├── bin └── .empty ├── win32 ├── bin │ └── .empty ├── intermediate │ └── .empty ├── fake86.rc ├── fake86.suo ├── resource.h ├── imagegen.vcxproj.filters ├── fake86.sln ├── fake86.vcxproj.filters ├── imagegen.vcxproj └── fake86.vcxproj ├── data ├── pcxtbios.bin ├── rombasic.bin └── videorom.bin ├── src ├── fake86 │ ├── win32 │ │ ├── resource.h │ │ └── menus.c │ ├── sermouse.h │ ├── i8237.h │ ├── disk.h │ ├── i8253.h │ ├── mutex.h │ ├── i8259.h │ ├── blaster.h │ ├── audio.h │ ├── speaker.c │ ├── config.h │ ├── sndsource.c │ ├── netcard.c │ ├── cpu.h │ ├── i8259.c │ ├── sermouse.c │ ├── ata.c │ ├── modregrm.h │ ├── ports.c │ ├── console.c │ ├── i8253.c │ ├── timing.c │ ├── audio.c │ ├── packet.c │ ├── i8237.c │ ├── disk.c │ ├── parsecl.c │ ├── main.c │ ├── blaster.c │ ├── adlib.c │ └── input.c └── imagegen │ └── imagegen.c ├── README.md ├── INSTALL.osx ├── INSTALL.haiku ├── INSTALL.linux ├── makefile.orig ├── makefile.pcap ├── makefile.haiku ├── makefile.osxuni ├── INSTALL.win ├── README ├── CHANGELOG ├── makefile └── LICENSE /bin/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /win32/bin/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /win32/intermediate/.empty: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /data/pcxtbios.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterfeizz/fake86/HEAD/data/pcxtbios.bin -------------------------------------------------------------------------------- /data/rombasic.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterfeizz/fake86/HEAD/data/rombasic.bin -------------------------------------------------------------------------------- /data/videorom.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterfeizz/fake86/HEAD/data/videorom.bin -------------------------------------------------------------------------------- /win32/fake86.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterfeizz/fake86/HEAD/win32/fake86.rc -------------------------------------------------------------------------------- /win32/fake86.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterfeizz/fake86/HEAD/win32/fake86.suo -------------------------------------------------------------------------------- /win32/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterfeizz/fake86/HEAD/win32/resource.h -------------------------------------------------------------------------------- /src/fake86/win32/resource.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/masterfeizz/fake86/HEAD/src/fake86/win32/resource.h -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This is a port of Fake86 for the Nintendo 3DS. 2 | 3 | All the launch parameters are hard coded and the only method of input at the moment is through the touchscreen. 4 | Sound is not implemented. 5 | -------------------------------------------------------------------------------- /INSTALL.osx: -------------------------------------------------------------------------------- 1 | For info on compiling for OS X, see the file INSTALL.linux as the instructions 2 | are identical if you are compiling only for your native CPU. 3 | 4 | If you would rather build a universal binary for OS X, the same instructions 5 | should still be followed, except you need to add " -f makefile.osxuni " as an 6 | option for all make commands. 7 | -------------------------------------------------------------------------------- /INSTALL.haiku: -------------------------------------------------------------------------------- 1 | Compilation and installation notes for Fake86 on Haiku OS: 2 | 3 | At the time of this writing, Haiku is still in Alpha stage. This means 4 | that everything I'm telling you here could be inaccurate as soon as 5 | tomorrow. I don't make any promises of correct functionaly in Haiku, 6 | and I can only say that this worked for me on Haiku R1 Alpha 3. Your 7 | mileage may vary. 8 | 9 | Required libraries: 10 | libSDL 1.2 11 | 12 | To compile and install Fake86 without ethernet emulation support: 13 | make -f makefile.haiku 14 | make -f makefile.haiku install 15 | 16 | Usage note: 17 | Just a reminder, Fake86 needs to be invoked via command line 18 | and requires some parameters to work. Run "fake86 -h" to get 19 | a listing of valid arguments. 20 | -------------------------------------------------------------------------------- /INSTALL.linux: -------------------------------------------------------------------------------- 1 | Compilation and installation notes for Fake86 on Linux: 2 | 3 | Sorry, but there is no configure script written for Fake86 yet. 4 | All my Linux-based testing has been done with Debian Squeeze 6.0, 5 | both 32 and 64 bit versions. It will use gcc. 6 | 7 | Required libraries: 8 | libSDL 1.2 9 | libpcap (Optional, only needed if using makefile.pcap) 10 | 11 | Debian users can install them all with this command: 12 | apt-get install libsdl1.2debian-all libsdl1.2-dev libpcap0.8 libpcap0.8-dev 13 | 14 | To compile and install Fake86 without ethernet emulation support: 15 | make 16 | sudo make install 17 | 18 | To compile and install Fake86 WITH ethernet emulation support: 19 | make -f makefile.pcap 20 | sudo make -f makefile.pcap install 21 | 22 | Usage note: 23 | Just a reminder, Fake86 needs to be invoked via command line 24 | and requires some parameters to work. Run "fake86 -h" to get 25 | a listing of valid arguments. 26 | -------------------------------------------------------------------------------- /src/fake86/sermouse.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | 22 | struct sermouse_s { 23 | uint8_t reg[8]; 24 | uint8_t buf[16]; 25 | int8_t bufptr; 26 | }; 27 | -------------------------------------------------------------------------------- /win32/imagegen.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | -------------------------------------------------------------------------------- /makefile.orig: -------------------------------------------------------------------------------- 1 | SRCFILES=src/fake86/*.c 2 | BINPATH=/usr/bin 3 | DATAPATH=/usr/share/fake86 4 | CFLAGS=-O2 -DPATH_DATAFILES=\"$(DATAPATH)/\" 5 | INCLUDE=-Isrc/fake86 6 | LIBS=-lpthread 7 | SDLFLAGS=`sdl-config --cflags --libs` 8 | 9 | all: fake86-src imagegen-src 10 | 11 | fake86-src: 12 | $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS) 13 | chmod a+x bin/fake86 14 | 15 | imagegen-src: 16 | $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS) 17 | chmod a+x bin/imagegen 18 | 19 | install: 20 | mkdir -p $(BINPATH) 21 | mkdir -p $(DATAPATH) 22 | chmod a-x data/* 23 | cp -p bin/fake86 $(BINPATH) 24 | cp -p bin/imagegen $(BINPATH) 25 | cp -p data/asciivga.dat $(DATAPATH) 26 | cp -p data/pcxtbios.bin $(DATAPATH) 27 | cp -p data/videorom.bin $(DATAPATH) 28 | cp -p data/rombasic.bin $(DATAPATH) 29 | 30 | clean: 31 | rm -f src/fake86/*.o 32 | rm -f src/fake86/*~ 33 | rm -f src/imagegen/*.o 34 | rm -f src/imagegen/*~ 35 | rm -f bin/fake86 36 | rm -f bin/imagegen 37 | 38 | uninstall: 39 | rm -f $(BINPATH)/fake86 40 | rm -f $(BINPATH)/imagegen 41 | -------------------------------------------------------------------------------- /makefile.pcap: -------------------------------------------------------------------------------- 1 | SRCFILES=src/fake86/*.c 2 | BINPATH=/usr/bin 3 | DATAPATH=/usr/share/fake86 4 | CFLAGS=-O2 -DPATH_DATAFILES=\"$(DATAPATH)/\" -DNETWORKING_ENABLED 5 | INCLUDE=-Isrc/fake86 6 | LIBS=-lpthread -lpcap 7 | SDLFLAGS=`sdl-config --cflags --libs` 8 | 9 | all: fake86-src imagegen-src 10 | 11 | fake86-src: 12 | $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS) 13 | chmod a+x bin/fake86 14 | 15 | imagegen-src: 16 | $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS) 17 | chmod a+x bin/imagegen 18 | 19 | install: 20 | mkdir -p $(BINPATH) 21 | mkdir -p $(DATAPATH) 22 | chmod a-x data/* 23 | cp -p bin/fake86 $(BINPATH) 24 | cp -p bin/imagegen $(BINPATH) 25 | cp -p data/asciivga.dat $(DATAPATH) 26 | cp -p data/pcxtbios.bin $(DATAPATH) 27 | cp -p data/videorom.bin $(DATAPATH) 28 | cp -p data/rombasic.bin $(DATAPATH) 29 | 30 | clean: 31 | rm -f src/fake86/*.o 32 | rm -f src/fake86/*~ 33 | rm -f src/imagegen/*.o 34 | rm -f src/imagegen/*~ 35 | rm -f bin/fake86 36 | rm -f bin/imagegen 37 | 38 | uninstall: 39 | rm -f $(BINPATH)/fake86 40 | rm -f $(BINPATH)/imagegen 41 | -------------------------------------------------------------------------------- /makefile.haiku: -------------------------------------------------------------------------------- 1 | SRCFILES=src/fake86/*.c 2 | BINPATH=/boot/system/bin 3 | DATAPATH=/boot/common/data/fake86 4 | CFLAGS=-O2 -DPATH_DATAFILES=\"$(DATAPATH)/\" 5 | INCLUDE=-Isrc/fake86 6 | LIBS= 7 | SDLFLAGS=`sdl-config --cflags --libs` 8 | 9 | all: fake86-src imagegen-src 10 | 11 | fake86-src: 12 | $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS) 13 | chmod a+x bin/fake86 14 | 15 | imagegen-src: 16 | $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS) 17 | chmod a+x bin/imagegen 18 | 19 | install: 20 | mkdir -p $(BINPATH) 21 | mkdir -p $(DATAPATH) 22 | cp bin/fake86 $(BINPATH) 23 | cp bin/imagegen $(BINPATH) 24 | cp data/asciivga.dat $(DATAPATH) 25 | cp data/pcxtbios.bin $(DATAPATH) 26 | cp data/videorom.bin $(DATAPATH) 27 | cp -p data/rombasic.bin $(DATAPATH) 28 | chmod a+x $(BINPATH)/fake86 29 | chmod a+x $(BINPATH)/imagegen 30 | 31 | clean: 32 | rm -f src/fake86/*.o 33 | rm -f src/fake86/*~ 34 | rm -f src/imagegen/*.o 35 | rm -f src/imagegen/*~ 36 | rm -f bin/fake86 37 | rm -f bin/imagegen 38 | 39 | uninstall: 40 | rm -f $(BINPATH)/fake86 41 | rm -f $(BINPATH)/imagegen 42 | -------------------------------------------------------------------------------- /makefile.osxuni: -------------------------------------------------------------------------------- 1 | SRCFILES=src/fake86/*.c 2 | BINPATH=/usr/bin 3 | DATAPATH=/usr/share/fake86 4 | CFLAGS=-force_cpusubtype_ALL -arch i386 -arch ppc -O2 -DPATH_DATAFILES=\"$(DATAPATH)/\" 5 | INCLUDE=-Isrc/fake86 6 | LIBS=-lpthread 7 | SDLFLAGS=`sdl-config --cflags --libs` 8 | 9 | all: fake86-src imagegen-src 10 | 11 | fake86-src: 12 | $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS) 13 | chmod a+x bin/fake86 14 | 15 | imagegen-src: 16 | $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS) 17 | chmod a+x bin/imagegen 18 | 19 | install: 20 | mkdir -p $(BINPATH) 21 | mkdir -p $(DATAPATH) 22 | chmod a-x data/* 23 | cp -p bin/fake86 $(BINPATH) 24 | cp -p bin/imagegen $(BINPATH) 25 | cp -p data/asciivga.dat $(DATAPATH) 26 | cp -p data/pcxtbios.bin $(DATAPATH) 27 | cp -p data/videorom.bin $(DATAPATH) 28 | cp -p data/rombasic.bin $(DATAPATH) 29 | 30 | clean: 31 | rm -f src/fake86/*.o 32 | rm -f src/fake86/*~ 33 | rm -f src/imagegen/*.o 34 | rm -f src/imagegen/*~ 35 | rm -f bin/fake86 36 | rm -f bin/imagegen 37 | 38 | uninstall: 39 | rm -f $(BINPATH)/fake86 40 | rm -f $(BINPATH)/imagegen 41 | -------------------------------------------------------------------------------- /src/fake86/i8237.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | 22 | struct dmachan_s { 23 | uint32_t page; 24 | uint32_t addr; 25 | uint32_t reload; 26 | uint32_t count; 27 | uint8_t direction; 28 | uint8_t autoinit; 29 | uint8_t writemode; 30 | uint8_t masked; 31 | }; 32 | -------------------------------------------------------------------------------- /src/fake86/disk.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | struct struct_drive { 24 | FILE *diskfile; 25 | uint32_t filesize; 26 | uint16_t cyls; 27 | uint16_t sects; 28 | uint16_t heads; 29 | uint8_t inserted; 30 | char *filename; 31 | }; 32 | -------------------------------------------------------------------------------- /src/fake86/i8253.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #define PIT_MODE_LATCHCOUNT 0 21 | #define PIT_MODE_LOBYTE 1 22 | #define PIT_MODE_HIBYTE 2 23 | #define PIT_MODE_TOGGLE 3 24 | 25 | struct i8253_s { 26 | uint16_t chandata[3]; 27 | uint8_t accessmode[3]; 28 | uint8_t bytetoggle[3]; 29 | uint32_t effectivedata[3]; 30 | float chanfreq[3]; 31 | uint8_t active[3]; 32 | uint16_t counter[3]; 33 | }; 34 | -------------------------------------------------------------------------------- /src/fake86/mutex.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #ifdef _WIN32 21 | #include 22 | #include 23 | #define MutexLock(mutex) EnterCriticalSection(&mutex) 24 | #define MutexUnlock(mutex) LeaveCriticalSection(&mutex) 25 | #else 26 | #include 27 | #define MutexLock(mutex) pthread_mutex_lock(&mutex) 28 | #define MutexUnlock(mutex) pthread_mutex_unlock(&mutex) 29 | #endif 30 | -------------------------------------------------------------------------------- /src/fake86/i8259.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | struct structpic { 21 | uint8_t imr; //mask register 22 | uint8_t irr; //request register 23 | uint8_t isr; //service register 24 | uint8_t icwstep; //used during initialization to keep track of which ICW we're at 25 | uint8_t icw[5]; 26 | uint8_t intoffset; //interrupt vector offset 27 | uint8_t priority; //which IRQ has highest priority 28 | uint8_t autoeoi; //automatic EOI mode 29 | uint8_t readmode; //remember what to return on read register from OCW3 30 | uint8_t enabled; 31 | }; 32 | -------------------------------------------------------------------------------- /src/fake86/blaster.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | 22 | struct blaster_s { 23 | uint8_t mem[1024]; 24 | uint16_t memptr; 25 | uint16_t samplerate; 26 | uint8_t dspmaj; 27 | uint8_t dspmin; 28 | uint8_t speakerstate; 29 | uint8_t lastresetval; 30 | uint8_t lastcmdval; 31 | uint8_t lasttestval; 32 | uint8_t waitforarg; 33 | uint8_t paused8; 34 | uint8_t paused16; 35 | uint8_t sample; 36 | uint8_t sbirq; 37 | uint8_t sbdma; 38 | uint8_t usingdma; 39 | uint8_t maskdma; 40 | uint8_t useautoinit; 41 | uint32_t blocksize; 42 | uint32_t blockstep; 43 | uint64_t sampleticks; 44 | struct mixer_s { 45 | uint8_t index; 46 | uint8_t reg[256]; 47 | } mixer; 48 | }; 49 | -------------------------------------------------------------------------------- /INSTALL.win: -------------------------------------------------------------------------------- 1 | Compilation and installation notes for Fake86 on Windows: 2 | 3 | If you do not plan to look at or modify the source code, you can 4 | just delete this archive and use the pre-compiled Win32 build of 5 | Fake86 instead! 6 | 7 | It is highly recommended that you use Visual Studio 2010 to compile 8 | Fake86. The solution file is included in the "win32\" folder. You should 9 | be able to compile with MinGW as well, but I have not tested it myself. 10 | It will require some minor modifications, and a custom makefile. 11 | 12 | Compiler requirements: 13 | - You will need libSDL 1.2.15 development library for Visual C++. 14 | You can download this from: 15 | http://www.libsdl.org/release/SDL-devel-1.2.15-VC.zip 16 | 17 | - To enable ethernet emulation, you will also need to install the 18 | WinPCap library and developer's pack. This is available at: 19 | http://www.winpcap.org 20 | 21 | - Create a directory named "SDL" in your Visual C++ include path, 22 | and then copy the contents of the "SDL-1.2.15\include\" folder 23 | from that archive into it. 24 | 25 | - Next, copy the two ".lib" files from the "SDL-1.2.15\lib\x86\" 26 | folder in that archive into it. Also copy "SDL.dll" into the 27 | folder "fake86-version\win32\bin\" from this source archive. 28 | 29 | This should allow you to compile successfully! After a successful 30 | compile, the final Fake86.exe and Imagegen.exe files will be in 31 | "fake86-version\win32\bin\". You will also need the files in "data\" 32 | as well as "SDL.dll" to be in the same folder as "Fake86.exe" for 33 | it to run properly. 34 | -------------------------------------------------------------------------------- /src/fake86/audio.h: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | 22 | struct wav_hdr_s { 23 | uint8_t RIFF[4]; /* RIFF Header */ //Magic header 24 | uint32_t ChunkSize; /* RIFF Chunk Size */ 25 | uint8_t WAVE[4]; /* WAVE Header */ 26 | uint8_t fmt[4]; /* FMT header */ 27 | uint32_t Subchunk1Size; /* Size of the fmt chunk */ 28 | uint16_t AudioFormat; /* Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM */ 29 | uint16_t NumOfChan; /* Number of channels 1=Mono 2=Sterio */ 30 | uint32_t SamplesPerSec; /* Sampling Frequency in Hz */ 31 | uint32_t bytesPerSec; /* bytes per second */ 32 | uint16_t blockAlign; /* 2=16-bit mono, 4=16-bit stereo */ 33 | uint16_t bitsPerSample; /* Number of bits per sample */ 34 | uint8_t Subchunk2ID[4]; /* "data" string */ 35 | uint32_t Subchunk2Size; /* Sampled data length */ 36 | }; 37 | -------------------------------------------------------------------------------- /src/fake86/speaker.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* speaker.c: function to generate output samples for PC speaker emulation. */ 21 | 22 | #include "config.h" 23 | #include 24 | #include "i8253.h" 25 | #include "mutex.h" 26 | 27 | extern struct i8253_s i8253; 28 | 29 | extern uint64_t gensamplerate; 30 | uint64_t speakerfullstep, speakerhalfstep, speakercurstep = 0; 31 | int16_t speakerpos = 0; 32 | 33 | int16_t speakergensample() { 34 | int16_t speakervalue; 35 | 36 | speakerfullstep = (uint64_t) ( (float) gensamplerate / (float) i8253.chanfreq[2]); 37 | if (speakerfullstep < 2) speakerfullstep = 2; 38 | speakerhalfstep = speakerfullstep >> 1; 39 | if (speakercurstep < speakerhalfstep) { 40 | speakervalue = 32; 41 | } 42 | else { 43 | speakervalue = -32; 44 | } 45 | speakercurstep = (speakercurstep + 1) % speakerfullstep; 46 | return (speakervalue); 47 | } 48 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | Fake86: A portable, open-source 8086 PC emulator. 2 | Copyright (C)2010-2013 Mike Chambers 3 | 4 | This program is free software; you can redistribute it and/or 5 | modify it under the terms of the GNU General Public License 6 | as published by the Free Software Foundation; either version 2 7 | of the License, or (at your option) any later version. 8 | 9 | This program is distributed in the hope that it will be useful, 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 | GNU General Public License for more details. 13 | 14 | You should have received a copy of the GNU General Public License 15 | along with this program; if not, write to the Free Software 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 17 | 18 | =============================================================================== 19 | 20 | The full terms of the GNU General Public License version 2, under which this 21 | software is release, are contained in the text file LICENSE 22 | 23 | =============================================================================== 24 | 25 | ** IMPORTANT ** 26 | Remember that Fake86 requires command line parameters to work. If you are just 27 | launching it by double-clicking on the .exe in Windows Explorer, it won't work. 28 | 29 | To contact the author of Fake86, Mike Chambers: 30 | Send an e-mail to miker00lz gmail com 31 | 32 | Official Fake86 homepage: 33 | http://fake86.rubbermallet.org 34 | 35 | Instructions for compiling and installing Fake86 are in 36 | the text files INSTALL.linux and INSTALL.win, please read 37 | whichever file is suited for your target platform if you 38 | are compiling from source. 39 | -------------------------------------------------------------------------------- /src/fake86/config.h: -------------------------------------------------------------------------------- 1 | #ifndef __CONFIG_H__ 2 | #define __CONFIG_H__ 3 | 4 | #define BUILD_STRING "Fake86 v0.13.9.16" 5 | 6 | //be sure to only define ONE of the CPU_* options at any given time, or 7 | //you will likely get some unexpected/bad results! 8 | //#define CPU_8086 9 | //#define CPU_186 10 | #define CPU_V20 11 | //#define CPU_286 12 | 13 | #if defined(CPU_8086) 14 | #define CPU_CLEAR_ZF_ON_MUL 15 | #define CPU_ALLOW_POP_CS 16 | #else 17 | #define CPU_ALLOW_ILLEGAL_OP_EXCEPTION 18 | #define CPU_LIMIT_SHIFT_COUNT 19 | #endif 20 | 21 | #if defined(CPU_V20) 22 | #define CPU_NO_SALC 23 | #endif 24 | 25 | #if defined(CPU_286) || defined(CPU_386) 26 | #define CPU_286_STYLE_PUSH_SP 27 | #else 28 | #define CPU_SET_HIGH_FLAGS 29 | #endif 30 | 31 | #define TIMING_INTERVAL 15 32 | 33 | //when USE_PREFETCH_QUEUE is defined, Fake86's CPU emulator uses a 6-byte 34 | //read-ahead cache for opcode fetches just as a real 8086/8088 does. 35 | //by default, i just leave this disabled because it wastes a very very 36 | //small amount of CPU power. however, for the sake of more accurate 37 | //emulation, it can be enabled by uncommenting the line below and recompiling. 38 | //#define USE_PREFETCH_QUEUE 39 | 40 | //#define CPU_ADDR_MODE_CACHE 41 | 42 | //when compiled with network support, fake86 needs libpcap/winpcap. 43 | //if it is disabled, the ethernet card is still emulated, but no actual 44 | //communication is possible -- as if the ethernet cable was unplugged. 45 | #define NETWORKING_OLDCARD //planning to support an NE2000 in the future 46 | 47 | //when DISK_CONTROLLER_ATA is defined, fake86 will emulate a true IDE/ATA1 controller 48 | //card. if it is disabled, emulated disk access is handled by directly intercepting 49 | //calls to interrupt 13h. 50 | //*WARNING* - the ATA controller is not currently complete. do not use! 51 | //#define DISK_CONTROLLER_ATA 52 | 53 | #define AUDIO_DEFAULT_SAMPLE_RATE 48000 54 | #define AUDIO_DEFAULT_LATENCY 100 55 | 56 | //#define DEBUG_BLASTER 57 | //#define DEBUG_DMA 58 | 59 | //#define BENCHMARK_BIOS 60 | #endif 61 | -------------------------------------------------------------------------------- /src/imagegen/imagegen.c: -------------------------------------------------------------------------------- 1 | /* 2 | Imagegen: A blank disk image generator for use with Fake86 3 | Copyright (C)2010-2012 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include 21 | #include 22 | 23 | const char *build = "Imagegen v1.1"; 24 | 25 | int main(int argc, char *argv[]) { 26 | FILE *image; 27 | char *blank; 28 | unsigned long i, size; 29 | 30 | printf("%s (c)2010-2012 Mike Chambers\n", build); 31 | printf("[Blank disk image generator for Fake86]\n\n"); 32 | 33 | if(argc < 3) { 34 | printf("Usage syntax:\n"); 35 | printf(" imagegen imagefile size\n\n"); 36 | printf("imagefile denotes the filename of the new disk image to create.\n"); 37 | printf("size denotes the size in megabytes that it should be.\n"); 38 | return(1); 39 | } 40 | 41 | size = atoi(argv[2]); 42 | if((size > 503) || !size) { 43 | printf("Invalid size specified! Valid range is 1 to 503 MB.\n"); 44 | return(1); 45 | } 46 | 47 | image = fopen(argv[1], "wb"); 48 | if(image == NULL) { 49 | printf("Unable to create new file: %s\n", argv[1]); 50 | return(1); 51 | } 52 | 53 | blank = (void *)malloc(1048576); 54 | if (blank == NULL) { 55 | printf("Unable to allocate enough memory!\n"); 56 | return(1); 57 | } 58 | 59 | printf("Please wait, generating new image...\n"); 60 | 61 | for(i = 0; i < size; i++) { 62 | fwrite(&blank[0], 1048576, 1, image); 63 | printf("\rWriting to file: %u MB", i); 64 | } 65 | 66 | printf(" complete.\n"); 67 | return(0); 68 | } 69 | -------------------------------------------------------------------------------- /win32/fake86.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fake86", "fake86.vcxproj", "{4C3260EB-396E-4017-AF95-E0FD33E87046}" 5 | EndProject 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imagegen", "imagegen.vcxproj", "{BE8FA015-E801-40C8-B35B-D477C540439F}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug (with WinPCap)|Win32 = Debug (with WinPCap)|Win32 11 | Debug|Win32 = Debug|Win32 12 | Release (with WinPCap)|Win32 = Release (with WinPCap)|Win32 13 | Release|Win32 = Release|Win32 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug (with WinPCap)|Win32.ActiveCfg = Debug (with WinPCap)|Win32 17 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug (with WinPCap)|Win32.Build.0 = Debug (with WinPCap)|Win32 18 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug|Win32.ActiveCfg = Debug|Win32 19 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug|Win32.Build.0 = Debug|Win32 20 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release (with WinPCap)|Win32.ActiveCfg = Release (with WinPCap)|Win32 21 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release (with WinPCap)|Win32.Build.0 = Release (with WinPCap)|Win32 22 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release|Win32.ActiveCfg = Release|Win32 23 | {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release|Win32.Build.0 = Release|Win32 24 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug (with WinPCap)|Win32.ActiveCfg = Release|Win32 25 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug (with WinPCap)|Win32.Build.0 = Release|Win32 26 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug|Win32.ActiveCfg = Debug|Win32 27 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug|Win32.Build.0 = Debug|Win32 28 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Release (with WinPCap)|Win32.ActiveCfg = Release (with WinPCap)|Win32 29 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Release (with WinPCap)|Win32.Build.0 = Release (with WinPCap)|Win32 30 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Release|Win32.ActiveCfg = Release|Win32 31 | {BE8FA015-E801-40C8-B35B-D477C540439F}.Release|Win32.Build.0 = Release|Win32 32 | EndGlobalSection 33 | GlobalSection(SolutionProperties) = preSolution 34 | HideSolutionNode = FALSE 35 | EndGlobalSection 36 | EndGlobal 37 | -------------------------------------------------------------------------------- /src/fake86/sndsource.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* ssource.c: functions to emulate the Disney Sound Source's 16-byte FIFO buffer. */ 21 | 22 | #include "config.h" 23 | #include 24 | 25 | extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback); 26 | extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback); 27 | 28 | extern uint8_t portram[0x10000]; 29 | uint8_t ssourcebuf[16], ssourceptr = 0, ssourceactive = 0; 30 | int16_t ssourcecursample = 0; 31 | 32 | int16_t getssourcebyte() { 33 | return (ssourcecursample); 34 | } 35 | 36 | void tickssource() { 37 | uint8_t rotatefifo; 38 | if ( (ssourceptr==0) || (!ssourceactive) ) { 39 | ssourcecursample = 0; 40 | return; 41 | } 42 | ssourcecursample = ssourcebuf[0]; 43 | for (rotatefifo=1; rotatefifo<16; rotatefifo++) 44 | ssourcebuf[rotatefifo-1] = ssourcebuf[rotatefifo]; 45 | ssourceptr--; 46 | portram[0x379] = 0; 47 | } 48 | 49 | void putssourcebyte (uint8_t value) { 50 | if (ssourceptr==16) return; 51 | ssourcebuf[ssourceptr++] = value; 52 | if (ssourceptr==16) portram[0x379] = 0x40; 53 | } 54 | 55 | uint8_t ssourcefull() { 56 | if (ssourceptr==16) return (0x40); 57 | else return (0x00); 58 | } 59 | 60 | void outsoundsource (uint16_t portnum, uint8_t value) { 61 | static uint8_t last37a = 0; 62 | switch (portnum) { 63 | case 0x378: 64 | putssourcebyte (value); 65 | break; 66 | case 0x37A: 67 | if ( (value & 4) && ! (last37a & 4) ) putssourcebyte (portram[0x378]); 68 | last37a = value; 69 | break; 70 | } 71 | } 72 | 73 | uint8_t insoundsource (uint16_t portnum) { 74 | return (ssourcefull() ); 75 | } 76 | 77 | void initsoundsource() { 78 | set_port_write_redirector (0x378, 0x378, &outsoundsource); 79 | set_port_write_redirector (0x37A, 0x37A, &outsoundsource); 80 | set_port_read_redirector (0x379, 0x379, &insoundsource); 81 | ssourceactive = 1; 82 | } 83 | -------------------------------------------------------------------------------- /src/fake86/netcard.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* netcard.c: this is a simple custom ethernet adapter interface for Fake86. 21 | it's not modeled after a real-world ethernet adapter, thus i had to create 22 | own DOS packet driver for programs to make use of it. this packet driver 23 | is included with this source code, in the data/ directory. the filename is 24 | pd.com - inject this file into any floppy or hard disk image if needed! */ 25 | 26 | #include "config.h" 27 | #ifdef NETWORKING_ENABLED 28 | #ifdef NETWORKING_OLDCARD 29 | #include 30 | #include 31 | #include 32 | #include "cpu.h" 33 | 34 | extern uint8_t verbose; 35 | extern union _bytewordregs_ regs; 36 | extern uint8_t RAM[0x100000], readonly[0x100000], ethif; 37 | extern uint16_t segregs[4]; 38 | extern void sendpkt (uint8_t *src, uint16_t len); 39 | 40 | struct netstruct { 41 | uint8_t enabled; 42 | uint8_t canrecv; 43 | uint16_t pktlen; 44 | } net; 45 | 46 | void nethandler() { 47 | uint32_t i; 48 | if (ethif==254) return; //networking not enabled 49 | switch (regs.byteregs[regah]) { //function number 50 | case 0x00: //enable packet reception 51 | net.enabled = 1; 52 | net.canrecv = 1; 53 | return; 54 | case 0x01: //send packet of CX at DS:SI 55 | if (verbose) { 56 | printf ("Sending packet of %u bytes.\n", regs.wordregs[regcx]); 57 | } 58 | sendpkt (&RAM[ ( (uint32_t) segregs[regds] << 4) + (uint32_t) regs.wordregs[regsi]], regs.wordregs[regcx]); 59 | return; 60 | case 0x02: //return packet info (packet buffer in DS:SI, length in CX) 61 | segregs[regds] = 0xD000; 62 | regs.wordregs[regsi] = 0x0000; 63 | regs.wordregs[regcx] = net.pktlen; 64 | return; 65 | case 0x03: //copy packet to final destination (given in ES:DI) 66 | memcpy (&RAM[ ( (uint32_t) segregs[reges] << 4) + (uint32_t) regs.wordregs[regdi]], &RAM[0xD0000], net.pktlen); 67 | return; 68 | case 0x04: //disable packets 69 | net.enabled = 0; 70 | net.canrecv = 0; 71 | return; 72 | case 0x05: //DEBUG: dump packet (DS:SI) of CX bytes to stdout 73 | for (i=0; i 22 | #else 23 | #include 24 | #endif 25 | 26 | #define regax 0 27 | #define regcx 1 28 | #define regdx 2 29 | #define regbx 3 30 | #define regsp 4 31 | #define regbp 5 32 | #define regsi 6 33 | #define regdi 7 34 | #define reges 0 35 | #define regcs 1 36 | #define regss 2 37 | #define regds 3 38 | 39 | #ifdef __BIG_ENDIAN__ 40 | #define regal 1 41 | #define regah 0 42 | #define regcl 3 43 | #define regch 2 44 | #define regdl 5 45 | #define regdh 4 46 | #define regbl 7 47 | #define regbh 6 48 | #else 49 | #define regal 0 50 | #define regah 1 51 | #define regcl 2 52 | #define regch 3 53 | #define regdl 4 54 | #define regdh 5 55 | #define regbl 6 56 | #define regbh 7 57 | #endif 58 | 59 | union _bytewordregs_ { 60 | uint16_t wordregs[8]; 61 | uint8_t byteregs[8]; 62 | }; 63 | 64 | #ifdef CPU_ADDR_MODE_CACHE 65 | struct addrmodecache_s { 66 | uint16_t exitcs; 67 | uint16_t exitip; 68 | uint16_t disp16; 69 | uint32_t len; 70 | uint8_t mode; 71 | uint8_t reg; 72 | uint8_t rm; 73 | uint8_t forcess; 74 | uint8_t valid; 75 | }; 76 | #endif 77 | 78 | #define StepIP(x) ip += x 79 | #define getmem8(x, y) read86(segbase(x) + y) 80 | #define getmem16(x, y) readw86(segbase(x) + y) 81 | #define putmem8(x, y, z) write86(segbase(x) + y, z) 82 | #define putmem16(x, y, z) writew86(segbase(x) + y, z) 83 | #define signext(value) (int16_t)(int8_t)(value) 84 | #define signext32(value) (int32_t)(int16_t)(value) 85 | #define getreg16(regid) regs.wordregs[regid] 86 | #define getreg8(regid) regs.byteregs[byteregtable[regid]] 87 | #define putreg16(regid, writeval) regs.wordregs[regid] = writeval 88 | #define putreg8(regid, writeval) regs.byteregs[byteregtable[regid]] = writeval 89 | #define getsegreg(regid) segregs[regid] 90 | #define putsegreg(regid, writeval) segregs[regid] = writeval 91 | #define segbase(x) ((uint32_t) x << 4) 92 | 93 | #define makeflagsword() \ 94 | ( \ 95 | 2 | (uint16_t) cf | ((uint16_t) pf << 2) | ((uint16_t) af << 4) | ((uint16_t) zf << 6) | ((uint16_t) sf << 7) | \ 96 | ((uint16_t) tf << 8) | ((uint16_t) ifl << 9) | ((uint16_t) df << 10) | ((uint16_t) of << 11) \ 97 | ) 98 | 99 | #define decodeflagsword(x) { \ 100 | temp16 = x; \ 101 | cf = temp16 & 1; \ 102 | pf = (temp16 >> 2) & 1; \ 103 | af = (temp16 >> 4) & 1; \ 104 | zf = (temp16 >> 6) & 1; \ 105 | sf = (temp16 >> 7) & 1; \ 106 | tf = (temp16 >> 8) & 1; \ 107 | ifl = (temp16 >> 9) & 1; \ 108 | df = (temp16 >> 10) & 1; \ 109 | of = (temp16 >> 11) & 1; \ 110 | } 111 | -------------------------------------------------------------------------------- /src/fake86/i8259.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* i8259.c: functions to emulate the Intel 8259 prioritized interrupt controller. 21 | note: this is not a very complete 8259 implementation, but for the purposes 22 | of a PC, it's all we need. */ 23 | 24 | #include 25 | #include 26 | #include "i8259.h" 27 | 28 | struct structpic i8259; 29 | 30 | extern uint8_t keyboardwaitack; 31 | 32 | extern void set_port_write_redirector(uint16_t startport, uint16_t endport, void *callback); 33 | extern void set_port_read_redirector(uint16_t startport, uint16_t endport, void *callback); 34 | 35 | uint8_t in8259(uint16_t portnum) { 36 | switch (portnum & 1) { 37 | case 0: 38 | if (i8259.readmode==0) return(i8259.irr); else return(i8259.isr); 39 | case 1: //read mask register 40 | return(i8259.imr); 41 | } 42 | return (0); 43 | } 44 | 45 | extern uint32_t makeupticks; 46 | void out8259(uint16_t portnum, uint8_t value) { 47 | uint8_t i; 48 | switch (portnum & 1) { 49 | case 0: 50 | if (value & 0x10) { //begin initialization sequence 51 | i8259.icwstep = 1; 52 | i8259.imr = 0; //clear interrupt mask register 53 | i8259.icw[i8259.icwstep++] = value; 54 | return; 55 | } 56 | if ((value & 0x98)==8) { //it's an OCW3 57 | if (value & 2) i8259.readmode = value & 2; 58 | } 59 | if (value & 0x20) { //EOI command 60 | keyboardwaitack = 0; 61 | for (i=0; i<8; i++) 62 | if ((i8259.isr >> i) & 1) { 63 | i8259.isr ^= (1 << i); 64 | if ((i==0) && (makeupticks>0)) { makeupticks = 0; i8259.irr |= 1; } 65 | return; 66 | } 67 | } 68 | break; 69 | case 1: 70 | if ((i8259.icwstep==3) && (i8259.icw[1] & 2)) i8259.icwstep = 4; //single mode, so don't read ICW3 71 | if (i8259.icwstep<5) { i8259.icw[i8259.icwstep++] = value; return; } 72 | //if we get to this point, this is just a new IMR value 73 | i8259.imr = value; 74 | break; 75 | } 76 | } 77 | 78 | uint8_t nextintr() { 79 | uint8_t i, tmpirr; 80 | tmpirr = i8259.irr & (~i8259.imr); //XOR request register with inverted mask register 81 | for (i=0; i<8; i++) 82 | if ((tmpirr >> i) & 1) { 83 | i8259.irr ^= (1 << i); 84 | i8259.isr |= (1 << i); 85 | return(i8259.icw[2] + i); 86 | } 87 | return(0); //this won't be reached, but without it the compiler gives a warning 88 | } 89 | 90 | void doirq(uint8_t irqnum) { 91 | i8259.irr |= (1 << irqnum); 92 | if (irqnum == 1) keyboardwaitack = 1; 93 | } 94 | 95 | void init8259() { 96 | memset((void *)&i8259, 0, sizeof(i8259)); 97 | set_port_write_redirector(0x20, 0x21, &out8259); 98 | set_port_read_redirector(0x20, 0x21, &in8259); 99 | } 100 | -------------------------------------------------------------------------------- /src/fake86/sermouse.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* sermouse.c: functions to emulate a standard Microsoft-compatible serial mouse. */ 21 | 22 | #include "config.h" 23 | #include 24 | #include 25 | #include 26 | #include "sermouse.h" 27 | 28 | extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback); 29 | extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback); 30 | extern void doirq (uint8_t irqnum); 31 | 32 | struct sermouse_s sermouse; 33 | 34 | void bufsermousedata (uint8_t value) { 35 | if (sermouse.bufptr == 16) return; 36 | if (sermouse.bufptr == 0 ) doirq (4); 37 | sermouse.buf[sermouse.bufptr++] = value; 38 | } 39 | 40 | void outsermouse (uint16_t portnum, uint8_t value) { 41 | uint8_t oldreg; 42 | //printf("[DEBUG] Serial mouse, port %X out: %02X\n", portnum, value); 43 | portnum &= 7; 44 | oldreg = sermouse.reg[portnum]; 45 | sermouse.reg[portnum] = value; 46 | switch (portnum) { 47 | case 4: //modem control register 48 | if ( (value & 1) != (oldreg & 1) ) { //software toggling of this register 49 | sermouse.bufptr = 0; //causes the mouse to reset and fill the buffer 50 | bufsermousedata ('M'); //with a bunch of ASCII 'M' characters. 51 | bufsermousedata ('M'); //this is intended to be a way for 52 | bufsermousedata ('M'); //drivers to verify that there is 53 | bufsermousedata ('M'); //actually a mouse connected to the port. 54 | bufsermousedata ('M'); 55 | bufsermousedata ('M'); 56 | } 57 | break; 58 | } 59 | } 60 | 61 | uint8_t insermouse (uint16_t portnum) { 62 | uint8_t temp; 63 | //printf("[DEBUG] Serial mouse, port %X in\n", portnum); 64 | portnum &= 7; 65 | switch (portnum) { 66 | case 0: //data receive 67 | temp = sermouse.buf[0]; 68 | memmove (sermouse.buf, &sermouse.buf[1], 15); 69 | sermouse.bufptr--; 70 | if (sermouse.bufptr < 0) sermouse.bufptr = 0; 71 | if (sermouse.bufptr > 0) doirq (4); 72 | sermouse.reg[4] = ~sermouse.reg[4] & 1; 73 | return (temp); 74 | case 5: //line status register (read-only) 75 | if (sermouse.bufptr > 0) temp = 1; 76 | else temp = 0; 77 | return (0x1); 78 | return (0x60 | temp); 79 | } 80 | return (sermouse.reg[portnum & 7]); 81 | } 82 | 83 | void initsermouse (uint16_t baseport, uint8_t irq) { 84 | sermouse.bufptr = 0; 85 | set_port_write_redirector (baseport, baseport + 7, &outsermouse); 86 | set_port_read_redirector (baseport, baseport + 7, &insermouse); 87 | } 88 | 89 | void sermouseevent (uint8_t buttons, int8_t xrel, int8_t yrel) { 90 | uint8_t highbits = 0; 91 | if (xrel < 0) highbits = 3; 92 | else highbits = 0; 93 | if (yrel < 0) highbits |= 12; 94 | bufsermousedata (0x40 | (buttons << 4) | highbits); 95 | bufsermousedata (xrel & 63); 96 | bufsermousedata (yrel & 63); 97 | } 98 | -------------------------------------------------------------------------------- /src/fake86/ata.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | #include "config.h" 21 | #ifdef DISK_CONTROLLER_ATA 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | uint8_t idATA[512]; 28 | 29 | #define ATA_STATUS_ERROR 0x01 30 | #define ATA_STATUS_DRQ 0x08 31 | #define ATA_STATUS_SRV 0x10 32 | #define ATA_STATUS_FAULT 0x20 33 | #define ATA_STATUS_READY 0x40 34 | #define ATA_STATUS_BUSY 0x80 35 | 36 | #define flip16(x) ((x&255) | (x>>8)) 37 | #define flip32(x) ((x>>24) | (((x>>16)&255)<<8) | (((x>>8)&255)<<16) | ((x&255)<<24)) 38 | 39 | uint8_t statusreg = 0, errorreg = 0, drivesel = 0, databuf[512]; 40 | uint16_t dataptr = 512; 41 | 42 | void bufclear() { 43 | memset (databuf, 0, 512); 44 | } 45 | 46 | void bufcook() { 47 | uint16_t i; 48 | uint8_t cc; 49 | for (i=0; i<512; i+=2) { 50 | cc = databuf[i]; 51 | databuf[i] = databuf[i+1]; 52 | databuf[i+1] = cc; 53 | } 54 | } 55 | 56 | void bufwrite8 (uint16_t bufpos, uint8_t value) { 57 | databuf[bufpos] = value; 58 | } 59 | 60 | void bufwrite16 (uint16_t bufpos, uint16_t value) { 61 | databuf[bufpos] = (uint8_t) value; 62 | databuf[bufpos+1] = (uint8_t) (value>>8); 63 | } 64 | 65 | void flipstring (uint8_t *dest, uint8_t *src) { 66 | uint16_t i; 67 | uint8_t cc; 68 | strcpy (dest, src); 69 | for (i=0; i> 4) & 1; 95 | break; 96 | case 0x1F7: //command register 97 | cmdATA (value); 98 | break; 99 | } 100 | } 101 | 102 | uint8_t inATA (uint16_t portnum) { 103 | //if (portnum != 0x1F0) printf("[DEBUG] ATA port %Xh read\n", portnum); 104 | //getch(); 105 | switch (portnum) { 106 | case 0x1F0: //data read 107 | if (dataptr < 512) { 108 | //printf("%c", databuf[dataptr]); 109 | return (databuf[dataptr++]); 110 | } 111 | else return (0); 112 | case 0x1F1: //error register 113 | if (drivesel == 1) return (1); 114 | else return (0); 115 | case 0x1F7: //status register 116 | statusreg = ATA_STATUS_READY; 117 | if (drivesel == 1) statusreg |= ATA_STATUS_ERROR; 118 | if (dataptr < 512) statusreg |= ATA_STATUS_DRQ; 119 | return (statusreg); 120 | } 121 | return (0); 122 | } 123 | #endif 124 | -------------------------------------------------------------------------------- /CHANGELOG: -------------------------------------------------------------------------------- 1 | Fake86 changelog for v0.13.9.13 2 | 3 | v0.13.9.16: 4 | - Fixed regression that caused Fake86 to not compile on at least some 5 | versions of Mac OS X. 6 | 7 | - Increased amount of processing time dedicated to timing and audio 8 | sample generation. Helps accuracy and helps prevent audio dropouts 9 | on slower systems. 10 | 11 | v0.13.9.13: 12 | - Major fix: Some games using the Sound Blaster used to go silent and some 13 | even would hang after playing the first sample chunk. It was due to them 14 | being unable to read the data count register from the DMA controller. 15 | This has been fixed. One example game that did this was Return to Zork. 16 | 17 | - Numerous big fixes and improvements. 18 | 19 | - Windows version now has a simple drop-down menu GUI, so on that platform 20 | it is no longer required to specify command-line options for the basics 21 | such as specifying disk images. These can be loaded from the menus. 22 | 23 | 24 | v0.12.9.19: 25 | - Fixed bug from v0.12.9.16 where the call to createscalemap() in the 26 | VideoThread() function was placed before the mutex lock, sometimes causing 27 | crashes when Fake86 first loads. (due to an uninitialized pointer) 28 | 29 | - Fixed bug in imagegen that made it crash on some Windows systems. 30 | 31 | 32 | v0.12.9.16: 33 | - Fixed bug from v0.12.9.12 that caused faulty CPU emulation on big-endian 34 | host CPUs, such as the PowerPC. 35 | 36 | - Fixed another bug from v0.12.9.12 that caused colors to be incorrect on 37 | big-endian host CPUs. 38 | 39 | - Added "-slowsys" command line option that can be used to fix audio dropout 40 | issues on very slow host CPUs by decreasing audio generation quality. 41 | 42 | - Added another stretching function that is used when the SDL window is 43 | exactly double of the width and height of the emulated video. Only active 44 | when no smoothing method has been specified. This saves the CPU a lot of 45 | work since we now only need to calculate the color to draw once for every 46 | four pixels, instead of recalculating the same color for every pixel 47 | This makes difference between smooth video and jerky, useless video on 48 | very old systems such as my 400 MHz PowerPC G3 iMac. 49 | 50 | - Added an obvious speed tweak which I should have had all along by 51 | generating a "scale map" lookup table once on every screen mode change. 52 | we no longer need to make expensive floating point scale calculations on 53 | every pixel in every frame. The speed boost is very noticeable on slower 54 | machines such as those with a Pentium 4 or older CPU. 55 | 56 | - No longer distributing IBM's ROM BASIC bundled with Fake86 out of legal 57 | concern. Is it very old? Yes. Does IBM care? Likely not, but they still 58 | hold the copyright. You can still use ROM BASIC by providing your own ROM 59 | dump. It should be 32,768 bytes in size, and must be named "rombasic.bin" 60 | without the quotes. After building and installing Fake86, you need to put 61 | the ROM dump in "/usr/share/fake86/" unless you explicitly changed the 62 | path in the makefile. In the case of running under Windows, the file 63 | should be placed in the same directory as the executable. 64 | 65 | - Created and included a new makefile, this one customized to work in 66 | Haiku OS. More information about Haiku at their website: 67 | http://www.haiku-os.org 68 | 69 | 70 | v0.12.9.12: 71 | - Around 80% of this version is a rewrite compared to all older versions of 72 | v0.11.7.22 and prior, and I am considering it a "fresh start". Older 73 | releases will no longer be officially available, and are to be considered 74 | obsolete. This fresh code base has far too many bugfixes, tweaks, design, 75 | layout, and speed improvements to even bother putting together a list of 76 | changes. 77 | -------------------------------------------------------------------------------- /src/fake86/modregrm.h: -------------------------------------------------------------------------------- 1 | #include "config.h" 2 | 3 | #ifdef CPU_ADDR_MODE_CACHE 4 | struct addrmodecache_s addrcache[0x100000]; 5 | uint8_t addrcachevalid[0x100000]; 6 | 7 | uint32_t addrdatalen, dataisvalid, setvalidptr; 8 | uint64_t cached_access_count = 0, uncached_access_count = 0; 9 | #define modregrm() { \ 10 | tempaddr32 = (((uint32_t)savecs << 4) + ip) & 0xFFFFF; \ 11 | if (addrcachevalid[tempaddr32]) { \ 12 | switch (addrcache[tempaddr32].len) { \ 13 | case 0: \ 14 | dataisvalid = 1; \ 15 | break; \ 16 | case 1: \ 17 | if (addrcachevalid[tempaddr32+1]) dataisvalid = 1; else dataisvalid = 0; \ 18 | break; \ 19 | case 2: \ 20 | if (addrcachevalid[tempaddr32+1] && addrcachevalid[tempaddr32+2]) dataisvalid = 1; else dataisvalid = 0; \ 21 | break; \ 22 | } \ 23 | } else dataisvalid = 0; \ 24 | if (dataisvalid) { \ 25 | cached_access_count++; \ 26 | disp16 = addrcache[tempaddr32].disp16; \ 27 | segregs[regcs] = addrcache[tempaddr32].exitcs; \ 28 | ip = addrcache[tempaddr32].exitip; \ 29 | mode = addrcache[tempaddr32].mode; \ 30 | reg = addrcache[tempaddr32].reg; \ 31 | rm = addrcache[tempaddr32].rm; \ 32 | if ((!segoverride) && addrcache[tempaddr32].forcess) useseg = segregs[regss]; \ 33 | } else { \ 34 | uncached_access_count++; \ 35 | addrbyte = getmem8(segregs[regcs], ip); \ 36 | StepIP(1); \ 37 | mode = addrbyte >> 6; \ 38 | reg = (addrbyte >> 3) & 7; \ 39 | rm = addrbyte & 7; \ 40 | addrdatalen = 0; \ 41 | addrcache[tempaddr32].forcess = 0; \ 42 | switch(mode) \ 43 | { \ 44 | case 0: \ 45 | if(rm == 6) { \ 46 | disp16 = getmem16(segregs[regcs], ip); \ 47 | addrdatalen = 2; \ 48 | StepIP(2); \ 49 | } \ 50 | if (((rm == 2) || (rm == 3))) { \ 51 | if (!segoverride) useseg = segregs[regss]; \ 52 | addrcache[tempaddr32].forcess = 1; \ 53 | } \ 54 | break; \ 55 | \ 56 | case 1: \ 57 | disp16 = signext(getmem8(segregs[regcs], ip)); \ 58 | addrdatalen = 1; \ 59 | StepIP(1); \ 60 | if (((rm == 2) || (rm == 3) || (rm == 6))) { \ 61 | if (!segoverride) useseg = segregs[regss]; \ 62 | addrcache[tempaddr32].forcess = 1; \ 63 | } \ 64 | break; \ 65 | \ 66 | case 2: \ 67 | disp16 = getmem16(segregs[regcs], ip); \ 68 | addrdatalen = 2; \ 69 | StepIP(2); \ 70 | if (((rm == 2) || (rm == 3) || (rm == 6))) { \ 71 | if (!segoverride) useseg = segregs[regss]; \ 72 | addrcache[tempaddr32].forcess = 1; \ 73 | } \ 74 | break; \ 75 | \ 76 | default: \ 77 | disp16 = 0; \ 78 | } \ 79 | addrcache[tempaddr32].disp16 = disp16; \ 80 | addrcache[tempaddr32].exitcs = segregs[regcs]; \ 81 | addrcache[tempaddr32].exitip = ip; \ 82 | addrcache[tempaddr32].mode = mode; \ 83 | addrcache[tempaddr32].reg = reg; \ 84 | addrcache[tempaddr32].rm = rm; \ 85 | addrcache[tempaddr32].len = addrdatalen; \ 86 | memset(&addrcachevalid[tempaddr32], 1, addrdatalen+1); \ 87 | } \ 88 | } 89 | #else 90 | #define modregrm() { \ 91 | addrbyte = getmem8(segregs[regcs], ip); \ 92 | StepIP(1); \ 93 | mode = addrbyte >> 6; \ 94 | reg = (addrbyte >> 3) & 7; \ 95 | rm = addrbyte & 7; \ 96 | switch(mode) \ 97 | { \ 98 | case 0: \ 99 | if(rm == 6) { \ 100 | disp16 = getmem16(segregs[regcs], ip); \ 101 | StepIP(2); \ 102 | } \ 103 | if(((rm == 2) || (rm == 3)) && !segoverride) { \ 104 | useseg = segregs[regss]; \ 105 | } \ 106 | break; \ 107 | \ 108 | case 1: \ 109 | disp16 = signext(getmem8(segregs[regcs], ip)); \ 110 | StepIP(1); \ 111 | if(((rm == 2) || (rm == 3) || (rm == 6)) && !segoverride) { \ 112 | useseg = segregs[regss]; \ 113 | } \ 114 | break; \ 115 | \ 116 | case 2: \ 117 | disp16 = getmem16(segregs[regcs], ip); \ 118 | StepIP(2); \ 119 | if(((rm == 2) || (rm == 3) || (rm == 6)) && !segoverride) { \ 120 | useseg = segregs[regss]; \ 121 | } \ 122 | break; \ 123 | \ 124 | default: \ 125 | disp8 = 0; \ 126 | disp16 = 0; \ 127 | } \ 128 | } 129 | #endif -------------------------------------------------------------------------------- /src/fake86/ports.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* ports.c: functions to handle port I/O from the CPU module, as well 21 | as functions for emulated hardware components to register their 22 | read/write callback functions across the port address range. */ 23 | 24 | #include 25 | #include 26 | #include "cpu.h" 27 | 28 | extern uint8_t portram[0x10000]; 29 | extern uint8_t speakerenabled; 30 | extern uint8_t keyboardwaitack; 31 | 32 | void (*do_callback_write) (uint16_t portnum, uint8_t value) = NULL; 33 | uint8_t (*do_callback_read) (uint16_t portnum) = NULL; 34 | void (*do_callback_write16) (uint16_t portnum, uint16_t value) = NULL; 35 | uint16_t (*do_callback_read16) (uint16_t portnum) = NULL; 36 | void * (port_write_callback[0x10000]); 37 | void * (port_read_callback[0x10000]); 38 | void * (port_write_callback16[0x10000]); 39 | void * (port_read_callback16[0x10000]); 40 | 41 | extern uint8_t verbose; 42 | void portout (uint16_t portnum, uint8_t value) { 43 | portram[portnum] = value; 44 | //if (verbose) printf("portout(0x%X, 0x%02X);\n", portnum, value); 45 | switch (portnum) { 46 | case 0x61: 47 | if ( (value & 3) == 3) speakerenabled = 1; 48 | else speakerenabled = 0; 49 | return; 50 | } 51 | do_callback_write = (void (*) (uint16_t portnum, uint8_t value) ) port_write_callback[portnum]; 52 | if (do_callback_write != (void *) 0) (*do_callback_write) (portnum, value); 53 | } 54 | 55 | uint8_t portin (uint16_t portnum) { 56 | //if (verbose) printf("portin(0x%X);\n", portnum); 57 | switch (portnum) { 58 | case 0x62: 59 | return (0x00); 60 | case 0x60: 61 | case 0x61: 62 | case 0x63: 63 | case 0x64: 64 | return (portram[portnum]); 65 | } 66 | do_callback_read = (uint8_t (*) (uint16_t portnum) ) port_read_callback[portnum]; 67 | if (do_callback_read != (void *) 0) return ( (*do_callback_read) (portnum) ); 68 | return (0xFF); 69 | } 70 | 71 | void portout16 (uint16_t portnum, uint16_t value) { 72 | do_callback_write16 = (void (*) (uint16_t portnum, uint16_t value) ) port_write_callback16[portnum]; 73 | if (do_callback_write16 != (void *) 0) { 74 | (*do_callback_write16) (portnum, value); 75 | return; 76 | } 77 | 78 | portout (portnum, (uint8_t) value); 79 | portout (portnum + 1, (uint8_t) (value >> 8) ); 80 | } 81 | 82 | uint16_t portin16 (uint16_t portnum) { 83 | uint16_t ret; 84 | 85 | do_callback_read16 = (uint16_t (*) (uint16_t portnum) ) port_read_callback16[portnum]; 86 | if (do_callback_read16 != (void *) 0) return ( (*do_callback_read16) (portnum) ); 87 | 88 | ret = (uint16_t) portin (portnum); 89 | ret |= (uint16_t) portin (portnum+1) << 8; 90 | return (ret); 91 | } 92 | 93 | void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback) { 94 | uint16_t i; 95 | for (i=startport; i<=endport; i++) { 96 | port_write_callback[i] = callback; 97 | } 98 | } 99 | 100 | void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback) { 101 | uint16_t i; 102 | for (i=startport; i<=endport; i++) { 103 | port_read_callback[i] = callback; 104 | } 105 | } 106 | 107 | void set_port_write_redirector_16 (uint16_t startport, uint16_t endport, void *callback) { 108 | uint16_t i; 109 | for (i=startport; i<=endport; i++) { 110 | port_write_callback16[i] = callback; 111 | } 112 | } 113 | 114 | void set_port_read_redirector_16 (uint16_t startport, uint16_t endport, void *callback) { 115 | uint16_t i; 116 | for (i=startport; i<=endport; i++) { 117 | port_read_callback16[i] = callback; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/fake86/console.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* console.c: functions for a simple interactive console on stdio. */ 21 | 22 | #include "config.h" 23 | //#include 24 | #include 25 | #include 26 | #include 27 | 28 | #ifdef _WIN32 29 | #include 30 | #define strcmpi _strcmpi 31 | #else 32 | #define strcmpi strcasecmp 33 | #endif 34 | 35 | uint8_t inputline[1024]; 36 | uint16_t inputptr = 0; 37 | extern uint8_t running; 38 | 39 | extern uint8_t insertdisk (uint8_t drivenum, char *filename); 40 | extern void ejectdisk (uint8_t drivenum); 41 | 42 | void waitforcmd (uint8_t *dst, uint16_t maxlen) { 43 | #ifdef _WIN32 44 | uint16_t inputptr; 45 | uint8_t cc; 46 | 47 | inputptr = 0; 48 | maxlen -= 2; 49 | inputline[0] = 0; 50 | while (running) { 51 | if (_kbhit () ) { 52 | cc = (uint8_t) _getch (); 53 | switch (cc) { 54 | case 0: 55 | case 9: 56 | case 10: 57 | break; 58 | case 8: //backspace 59 | if (inputptr > 0) { 60 | printf ("%c %c", 8, 8); 61 | inputline[--inputptr] = 0; 62 | } 63 | break; 64 | case 13: //enter 65 | printf ("\n"); 66 | return; 67 | default: 68 | if (inputptr < maxlen) { 69 | inputline[inputptr++] = cc; 70 | inputline[inputptr] = 0; 71 | printf ("%c",cc); 72 | } 73 | } 74 | } 75 | SDL_Delay(10); //don't waste CPU time while in the polling loop 76 | } 77 | #else 78 | gets (dst); 79 | #endif 80 | } 81 | 82 | void consolehelp () { 83 | printf ("\nConsole command summary:\n"); 84 | printf (" The console is not very robust yet. There are only a few commands:\n\n"); 85 | printf (" change fd0 Mount a new image file on first floppy drive.\n"); 86 | printf (" Entering a blank line just ejects any current image file.\n"); 87 | printf (" change fd1 Mount a new image file on first floppy drive.\n"); 88 | printf (" Entering a blank line just ejects any current image file.\n"); 89 | printf (" help This help display.\n"); 90 | printf (" quit Immediately abort emulation and close Fake86.\n"); 91 | } 92 | 93 | #ifdef _WIN32 94 | void runconsole (void *dummy) { 95 | #else 96 | void *runconsole (void *dummy) { 97 | #endif 98 | printf ("\nFake86 management console\n"); 99 | printf ("Type \"help\" for a summary of commands.\n"); 100 | while (running) { 101 | printf ("\n>"); 102 | waitforcmd (inputline, sizeof(inputline) ); 103 | if (strcmpi ( (const char *) inputline, "change fd0") == 0) { 104 | printf ("Path to new image file: "); 105 | waitforcmd (inputline, sizeof(inputline) ); 106 | if (strlen (inputline) > 0) { 107 | insertdisk (0, (char *) inputline); 108 | } 109 | else { 110 | ejectdisk (0); 111 | printf ("Floppy image ejected from first drive.\n"); 112 | } 113 | } 114 | else if (strcmpi ( (const char *) inputline, "change fd1") == 0) { 115 | printf ("Path to new image file: "); 116 | waitforcmd (inputline, sizeof(inputline) ); 117 | if (strlen (inputline) > 0) { 118 | insertdisk (1, (char *) inputline); 119 | } 120 | else { 121 | ejectdisk (1); 122 | printf ("Floppy image ejected from second drive.\n"); 123 | } 124 | } 125 | else if (strcmpi ( (const char *) inputline, "help") == 0) { 126 | consolehelp (); 127 | } 128 | else if (strcmpi ( (const char *) inputline, "quit") == 0) { 129 | running = 0; 130 | } 131 | else printf("Invalid command was entered.\n"); 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /src/fake86/i8253.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* i8253.c: functions to emulate the Intel 8253 programmable interval timer. 21 | these are required for the timer interrupt and PC speaker to be 22 | properly emulated! */ 23 | 24 | #include 25 | #include 26 | //#include 27 | #include "i8253.h" 28 | #include "mutex.h" 29 | 30 | extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback); 31 | extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback); 32 | 33 | struct i8253_s i8253; 34 | 35 | extern uint64_t hostfreq, lasttick, curtick, tickgap, totalexec; 36 | 37 | void out8253 (uint16_t portnum, uint8_t value) { 38 | uint8_t curbyte; 39 | portnum &= 3; 40 | switch (portnum) { 41 | case 0: 42 | case 1: 43 | case 2: //channel data 44 | if ( (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0; 45 | else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1; 46 | if (curbyte == 0) { //low byte 47 | i8253.chandata[portnum] = (i8253.chandata[portnum] & 0xFF00) | value; 48 | } 49 | else { //high byte 50 | i8253.chandata[portnum] = (i8253.chandata[portnum] & 0x00FF) | ( (uint16_t) value << 8); 51 | } 52 | if (i8253.chandata[portnum] == 0) i8253.effectivedata[portnum] = 65536; 53 | else i8253.effectivedata[portnum] = i8253.chandata[portnum]; 54 | i8253.active[portnum] = 1; 55 | tickgap = (uint64_t) ( (float) hostfreq / (float) ( (float) 1193182 / (float) i8253.effectivedata[0]) ); 56 | if (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1; 57 | i8253.chanfreq[portnum] = (float) ( (uint32_t) ( ( (float) 1193182.0 / (float) i8253.effectivedata[portnum]) * (float) 1000.0) ) / (float) 1000.0; 58 | //printf("[DEBUG] PIT channel %u counter changed to %u (%f Hz)\n", portnum, i8253.chandata[portnum], i8253.chanfreq[portnum]); 59 | break; 60 | case 3: //mode/command 61 | i8253.accessmode[value>>6] = (value >> 4) & 3; 62 | if (i8253.accessmode[value>>6] == PIT_MODE_TOGGLE) i8253.bytetoggle[value>>6] = 0; 63 | break; 64 | } 65 | } 66 | 67 | uint8_t in8253 (uint16_t portnum) { 68 | uint8_t curbyte; 69 | portnum &= 3; 70 | switch (portnum) { 71 | case 0: 72 | case 1: 73 | case 2: //channel data 74 | if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0; 75 | else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1; 76 | if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0; 77 | else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1; 78 | if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) ) i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1; 79 | if (curbyte == 0) { //low byte 80 | return ( (uint8_t) i8253.counter[portnum]); 81 | } 82 | else { //high byte 83 | return ( (uint8_t) (i8253.counter[portnum] >> 8) ); 84 | } 85 | break; 86 | } 87 | return (0); 88 | } 89 | 90 | void init8253() { 91 | memset (&i8253, 0, sizeof (i8253) ); 92 | set_port_write_redirector (0x40, 0x43, &out8253); 93 | set_port_read_redirector (0x40, 0x43, &in8253); 94 | } 95 | -------------------------------------------------------------------------------- /src/fake86/win32/menus.c: -------------------------------------------------------------------------------- 1 | #include "../config.h" 2 | #include "../../../win32/resource.h" 3 | #include 4 | #include 5 | #include 6 | 7 | HWND myWindow; 8 | HINSTANCE myInstance; 9 | HMENU myMenu; 10 | WNDPROC oldProc; 11 | HWND GetHwnd(); 12 | HICON myIcon; 13 | void SetWndProc(); 14 | void MenuItemClick(WPARAM wParam); 15 | 16 | void ShowMenu() { 17 | SetMenu(myWindow, myMenu); 18 | } 19 | 20 | void HideMenu() { 21 | SetMenu(myWindow, NULL); 22 | } 23 | 24 | void initmenus() { 25 | myWindow = GetHwnd(); 26 | myInstance = GetModuleHandle(NULL); 27 | myMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_MENU1)); 28 | ShowMenu(); 29 | SetWndProc(); 30 | //myIcon = LoadIcon(myInstance, MAKEINTRESOURCE(IDI_ICON1)); 31 | //SetClassLong(myWindow, GCLP_HICON, (LONG)(uint64_t)myIcon); 32 | //SetClassLong(myWindow, GCLP_HICONSM, (LONG)(uint64_t)myIcon); 33 | 34 | return; 35 | } 36 | 37 | HWND GetHwnd() { 38 | SDL_SysWMinfo wmi; 39 | SDL_VERSION(&wmi.version); 40 | 41 | if (!SDL_GetWMInfo(&wmi)) return(NULL); 42 | return(wmi.window); 43 | } 44 | 45 | LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { 46 | switch (msg) { 47 | case WM_COMMAND: 48 | MenuItemClick(wParam); 49 | return(TRUE); 50 | } 51 | 52 | return(CallWindowProc(oldProc, hwnd, msg, wParam, lParam)); 53 | } 54 | 55 | void SetWndProc() { 56 | oldProc = (WNDPROC)SetWindowLong(myWindow, GWL_WNDPROC, (LONG_PTR)WndProc); 57 | } 58 | 59 | extern uint8_t running, bootdrive, dohardreset, scrmodechange; 60 | extern uint16_t constantw, constanth; 61 | uint8_t insertdisk (uint8_t drivenum, char *filename); 62 | uint8_t ejectdisk (uint8_t drivenum); 63 | 64 | void MenuItemClick(WPARAM wParam) { 65 | OPENFILENAME of_dlg; 66 | uint8_t filename[MAX_PATH] = { 0 }; 67 | 68 | switch (LOWORD(wParam)) { 69 | //file menu 70 | case ID_FILE_EXIT: 71 | running = 0; 72 | break; 73 | 74 | //emulation menu 75 | case ID_EMULATION_HARDRESETEMULATOR: 76 | dohardreset = 1; 77 | break; 78 | 79 | case ID_FLOPPY0_INSERTDISK: 80 | case ID_FLOPPY1_INSERTDISK: 81 | memset(&of_dlg, 0, sizeof(of_dlg)); 82 | of_dlg.lStructSize = sizeof(of_dlg); 83 | of_dlg.lpstrTitle = "Open disk image"; 84 | of_dlg.hInstance = NULL; 85 | of_dlg.lpstrFile = filename; 86 | of_dlg.lpstrFilter = "Floppy disk images (*.img)\0*.img\0All files (*.*)\0*.*\0\0"; 87 | of_dlg.nMaxFile = MAX_PATH; 88 | of_dlg.Flags = OFN_FILEMUSTEXIST | OFN_LONGNAMES; 89 | if (GetOpenFileName(&of_dlg)) { 90 | if (LOWORD(wParam) == ID_FLOPPY0_INSERTDISK) { 91 | insertdisk(0, (char *)of_dlg.lpstrFile); 92 | if (bootdrive == 255) bootdrive = 0; 93 | } else insertdisk(1, (char *)of_dlg.lpstrFile); 94 | } 95 | break; 96 | case ID_FLOPPY0_EJECTDISK: 97 | ejectdisk(0); 98 | break; 99 | case ID_FLOPPY1_EJECTDISK: 100 | ejectdisk(1); 101 | break; 102 | 103 | case ID_HARDDRIVE0_INSERTDISK: 104 | case ID_HARDDRIVE1_INSERTDISK: 105 | memset(&of_dlg, 0, sizeof(of_dlg)); 106 | of_dlg.lStructSize = sizeof(of_dlg); 107 | of_dlg.lpstrTitle = "Open disk image"; 108 | of_dlg.hInstance = NULL; 109 | of_dlg.lpstrFile = filename; 110 | of_dlg.lpstrFilter = "Raw disk images (*.raw, *.img)\0*.raw;*.img\0All files (*.*)\0*.*\0\0"; 111 | of_dlg.nMaxFile = MAX_PATH; 112 | of_dlg.Flags = OFN_FILEMUSTEXIST | OFN_LONGNAMES; 113 | if (GetOpenFileName(&of_dlg)) { 114 | if (LOWORD(wParam) == ID_HARDDRIVE0_INSERTDISK) { 115 | insertdisk(128, (char *)of_dlg.lpstrFile); 116 | if (bootdrive == 255) bootdrive = 128; 117 | } else insertdisk(129, (char *)of_dlg.lpstrFile); 118 | } 119 | break; 120 | case ID_HARDDRIVE0_EJECTDISK: 121 | ejectdisk(128); 122 | break; 123 | case ID_HARDDRIVE1_EJECTDISK: 124 | ejectdisk(129); 125 | break; 126 | 127 | case ID_SETBOOTDRIVE_FLOPPY0: 128 | bootdrive = 0; 129 | break; 130 | case ID_SETBOOTDRIVE_HARDDRIVE0: 131 | bootdrive = 128; 132 | break; 133 | 134 | //video menu 135 | case ID_WINDOWRESOLUTION_AUTOMATIC: 136 | constantw = 0; 137 | constanth = 0; 138 | scrmodechange = 1; 139 | break; 140 | case ID_WINDOWRESOLUTION_320X200: 141 | constantw = 320; 142 | constanth = 200; 143 | scrmodechange = 1; 144 | break; 145 | case ID_WINDOWRESOLUTION_640X400: 146 | constantw = 640; 147 | constanth = 400; 148 | scrmodechange = 1; 149 | break; 150 | case ID_WINDOWRESOLUTION_960X600: 151 | constantw = 960; 152 | constanth = 600; 153 | scrmodechange = 1; 154 | break; 155 | case ID_WINDOWRESOLUTION_1280X800: 156 | constantw = 1280; 157 | constanth = 800; 158 | scrmodechange = 1; 159 | break; 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /src/fake86/timing.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* timing.c: critical functions to provide accurate timing for the 21 | system timer interrupt, and to generate new audio output samples. */ 22 | 23 | #include "config.h" 24 | //#include 25 | #include 26 | #include 27 | #ifdef _WIN32 28 | #include 29 | LARGE_INTEGER queryperf; 30 | #else 31 | #include 32 | struct timeval tv; 33 | #endif 34 | #include "i8253.h" 35 | #include "blaster.h" 36 | 37 | extern struct blaster_s blaster; 38 | extern struct i8253_s i8253; 39 | extern void doirq (uint8_t irqnum); 40 | extern void tickaudio(); 41 | extern void tickssource(); 42 | extern void tickadlib(); 43 | extern void tickBlaster(); 44 | 45 | uint64_t hostfreq = 1000000, lasttick = 0, curtick = 0, tickgap, i8253tickgap, lasti8253tick, scanlinetiming, lastscanlinetick, curscanline = 0; 46 | uint64_t sampleticks, lastsampletick, ssourceticks, lastssourcetick, adlibticks, lastadlibtick, lastblastertick, gensamplerate; 47 | 48 | uint16_t pit0counter = 65535; 49 | extern uint64_t totalexec; 50 | extern uint32_t speed; 51 | extern uint8_t port3da, doaudio, slowsystem; 52 | 53 | void inittiming() { 54 | #ifdef _WIN32 55 | QueryPerformanceFrequency (&queryperf); 56 | hostfreq = queryperf.QuadPart; 57 | QueryPerformanceCounter (&queryperf); 58 | curtick = queryperf.QuadPart; 59 | #else 60 | hostfreq = 1000000; 61 | gettimeofday (&tv, NULL); 62 | curtick = (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; 63 | #endif 64 | lasti8253tick = lastblastertick = lastadlibtick = lastssourcetick = lastsampletick = lastscanlinetick = lasttick = curtick; 65 | scanlinetiming = hostfreq / 31500; 66 | ssourceticks = hostfreq / 8000; 67 | adlibticks = hostfreq / 48000; 68 | if (doaudio) sampleticks = hostfreq / gensamplerate; 69 | else sampleticks = -1; 70 | i8253tickgap = hostfreq / 119318; 71 | } 72 | 73 | void timing() { 74 | uint8_t i8253chan; 75 | 76 | #ifdef _WIN32 77 | QueryPerformanceCounter (&queryperf); 78 | curtick = queryperf.QuadPart; 79 | #else 80 | gettimeofday (&tv, NULL); 81 | curtick = (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec; 82 | #endif 83 | 84 | if (curtick >= (lastscanlinetick + scanlinetiming) ) { 85 | curscanline = (curscanline + 1) % 525; 86 | if (curscanline > 479) port3da = 8; 87 | else port3da = 0; 88 | if (curscanline & 1) port3da |= 1; 89 | pit0counter++; 90 | lastscanlinetick = curtick; 91 | } 92 | 93 | if (i8253.active[0]) { //timer interrupt channel on i8253 94 | if (curtick >= (lasttick + tickgap) ) { 95 | lasttick = curtick; 96 | doirq (0); 97 | } 98 | } 99 | 100 | if (curtick >= (lasti8253tick + i8253tickgap) ) { 101 | for (i8253chan=0; i8253chan<3; i8253chan++) { 102 | if (i8253.active[i8253chan]) { 103 | if (i8253.counter[i8253chan] < 10) i8253.counter[i8253chan] = i8253.chandata[i8253chan]; 104 | i8253.counter[i8253chan] -= 10; 105 | } 106 | } 107 | lasti8253tick = curtick; 108 | } 109 | 110 | if (curtick >= (lastssourcetick + ssourceticks) ) { 111 | tickssource(); 112 | lastssourcetick = curtick - (curtick - (lastssourcetick + ssourceticks) ); 113 | } 114 | 115 | if (blaster.samplerate > 0) { 116 | if (curtick >= (lastblastertick + blaster.sampleticks) ) { 117 | tickBlaster(); 118 | lastblastertick = curtick - (curtick - (lastblastertick + blaster.sampleticks) ); 119 | } 120 | } 121 | 122 | if (curtick >= (lastsampletick + sampleticks) ) { 123 | tickaudio(); 124 | if (slowsystem) { 125 | tickaudio(); 126 | tickaudio(); 127 | tickaudio(); 128 | } 129 | lastsampletick = curtick - (curtick - (lastsampletick + sampleticks) ); 130 | } 131 | 132 | if (curtick >= (lastadlibtick + adlibticks) ) { 133 | tickadlib(); 134 | lastadlibtick = curtick - (curtick - (lastadlibtick + adlibticks) ); 135 | } 136 | } 137 | -------------------------------------------------------------------------------- /src/fake86/audio.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* audio.c: functions to mix the audio channels, and handle SDL's audio interface. */ 21 | 22 | #include "config.h" 23 | //#include 24 | #ifdef _WIN32 25 | #include 26 | #include 27 | #else 28 | #include 29 | #endif 30 | #include 31 | #include 32 | //#include 33 | #include "blaster.h" 34 | #include "audio.h" 35 | 36 | //extern SDL_Surface *screen; 37 | struct wav_hdr_s wav_hdr; 38 | FILE *wav_file = NULL; 39 | 40 | //SDL_AudioSpec wanted; 41 | int8_t audbuf[96000]; 42 | int32_t audbufptr, usebuffersize, usesamplerate = AUDIO_DEFAULT_SAMPLE_RATE, latency = AUDIO_DEFAULT_LATENCY; 43 | uint8_t speakerenabled = 0; 44 | 45 | extern uint64_t gensamplerate, sampleticks, hostfreq; 46 | extern int16_t adlibgensample(); 47 | extern int16_t speakergensample(); 48 | extern int16_t getssourcebyte(); 49 | extern int16_t getBlasterSample(); 50 | extern uint8_t usessource; 51 | 52 | void create_output_wav (uint8_t *filename) { 53 | printf ("Creating %s for audio logging... ", filename); 54 | wav_file = fopen (filename, "wb"); 55 | if (wav_file == NULL) { 56 | printf ("failed!\n"); 57 | return; 58 | } 59 | printf ("OK!\n"); 60 | 61 | wav_hdr.AudioFormat = 1; //PCM 62 | wav_hdr.bitsPerSample = 8; 63 | wav_hdr.blockAlign = 1; 64 | wav_hdr.ChunkSize = sizeof (wav_hdr) - 4; 65 | sprintf (&wav_hdr.WAVE[0], "WAVE"); 66 | sprintf (&wav_hdr.fmt[0], "fmt "); 67 | wav_hdr.NumOfChan = 1; 68 | wav_hdr.bytesPerSec = usesamplerate * (uint32_t) (wav_hdr.bitsPerSample >> 3) * (uint32_t) wav_hdr.NumOfChan; 69 | sprintf (&wav_hdr.RIFF[0], "RIFF"); 70 | wav_hdr.Subchunk1Size = 16; 71 | wav_hdr.SamplesPerSec = usesamplerate; 72 | sprintf (&wav_hdr.Subchunk2ID[0], "data"); 73 | wav_hdr.Subchunk2Size = 0; 74 | //fwrite((void *)&wav_hdr, 1, sizeof(wav_hdr), wav_file); 75 | } 76 | 77 | uint64_t doublesamplecount, cursampnum = 0, sampcount = 0, framecount = 0; 78 | uint8_t bmpfilename[256]; 79 | 80 | void savepic() { 81 | //SDL_SaveBMP (screen, &bmpfilename[0]); 82 | } 83 | 84 | int8_t samps[2400]; 85 | 86 | uint8_t audiobufferfilled() { 87 | if (audbufptr >= usebuffersize) return(1); 88 | return(0); 89 | } 90 | 91 | void tickaudio() { 92 | int16_t sample; 93 | if (audbufptr >= usebuffersize) return; 94 | sample = adlibgensample() >> 4; 95 | if (usessource) sample += getssourcebyte(); 96 | sample += getBlasterSample(); 97 | if (speakerenabled) sample += (speakergensample() >> 1); 98 | if (audbufptr < sizeof(audbuf) ) audbuf[audbufptr++] = (uint8_t) ((uint16_t) sample+128); 99 | } 100 | 101 | extern uint64_t timinginterval; 102 | extern void inittiming(); 103 | void fill_audio (void *udata, int8_t *stream, int len) { 104 | memcpy (stream, audbuf, len); 105 | memmove (audbuf, &audbuf[len], usebuffersize - len); 106 | 107 | audbufptr -= len; 108 | if (audbufptr < 0) audbufptr = 0; 109 | } 110 | 111 | void initaudio() { 112 | printf ("Initializing audio stream... "); 113 | 114 | if (usesamplerate < 4000) usesamplerate = 4000; 115 | else if (usesamplerate > 96000) usesamplerate = 96000; 116 | if (latency < 10) latency = 10; 117 | else if (latency > 1000) latency = 1000; 118 | audbufptr = usebuffersize = (usesamplerate / 1000) * latency; 119 | gensamplerate = usesamplerate; 120 | doublesamplecount = (uint32_t) ( (double) usesamplerate * (double) 0.01); 121 | 122 | /*wanted.freq = usesamplerate; 123 | wanted.format = AUDIO_U8; 124 | wanted.channels = 1; 125 | wanted.samples = (uint16_t) usebuffersize >> 1; 126 | wanted.callback = (void *) fill_audio; 127 | wanted.userdata = NULL;*/ 128 | 129 | //if (SDL_OpenAudio (&wanted, NULL) <0) { 130 | // printf ("Error: %s\n", SDL_GetError() ); 131 | // return; 132 | // } 133 | //else { 134 | // printf ("OK! (%lu Hz, %lu ms, %lu sample latency)\n", usesamplerate, latency, usebuffersize); 135 | // } 136 | 137 | memset (audbuf, 128, sizeof (audbuf) ); 138 | audbufptr = usebuffersize; 139 | //create_output_wav("fake86.wav"); 140 | //SDL_PauseAudio (0); 141 | return; 142 | } 143 | 144 | void killaudio() { 145 | //SDL_PauseAudio (1); 146 | 147 | if (wav_file == NULL) return; 148 | wav_hdr.ChunkSize = wav_hdr.Subchunk2Size + sizeof(wav_hdr) - 8; 149 | fseek(wav_file, 0, SEEK_SET); 150 | fwrite((void *)&wav_hdr, 1, sizeof(wav_hdr), wav_file); 151 | fclose (wav_file); 152 | } 153 | -------------------------------------------------------------------------------- /src/fake86/packet.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* packet.c: functions to interface with libpcap/winpcap for ethernet emulation. */ 21 | 22 | #include "config.h" 23 | 24 | #ifdef NETWORKING_ENABLED 25 | #define HAVE_REMOTE 26 | #define WPCAP 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | #ifndef _WIN32 33 | #define PCAP_OPENFLAG_PROMISCUOUS 1 34 | #endif 35 | 36 | extern uint8_t RAM[0x100000]; 37 | extern uint8_t verbose; 38 | uint8_t ethif, net_enabled = 0; 39 | uint8_t dopktrecv = 0; 40 | uint16_t rcvseg, rcvoff, hdrlen, handpkt; 41 | 42 | pcap_if_t *alldevs; 43 | pcap_if_t *d; 44 | pcap_t *adhandle; 45 | const u_char *pktdata; 46 | struct pcap_pkthdr *hdr; 47 | int inum; 48 | uint16_t curhandle = 0; 49 | char errbuf[PCAP_ERRBUF_SIZE]; 50 | uint8_t maclocal[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x13, 0x37 }; 51 | 52 | void initpcap() { 53 | int i=0; 54 | 55 | printf ("\nObtaining NIC list via libpcap...\n"); 56 | 57 | /* Retrieve the device list from the local machine */ 58 | #if defined(_WIN32) 59 | if (pcap_findalldevs_ex (PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1) 60 | #else 61 | if (pcap_findalldevs (&alldevs, errbuf) == -1) 62 | #endif 63 | { 64 | printf ("Error in pcap_findalldevs_ex: %s\n", errbuf); 65 | exit (1); 66 | } 67 | 68 | /* Print the list */ 69 | for (d= alldevs; d != NULL; d= d->next) { 70 | i++; 71 | if (ethif==255) { 72 | printf ("%d. %s", i, d->name); 73 | if (d->description) { 74 | printf (" (%s)\n", d->description); 75 | } 76 | else { 77 | printf (" (No description available)\n"); 78 | } 79 | } 80 | } 81 | 82 | if (i == 0) { 83 | printf ("\nNo interfaces found! Make sure WinPcap is installed.\n"); 84 | return; 85 | } 86 | 87 | printf ("\n"); 88 | 89 | if (ethif==255) exit (0); 90 | else inum = ethif; 91 | printf ("Using network interface %u.\n", ethif); 92 | 93 | 94 | if (inum < 1 || inum > i) { 95 | printf ("\nInterface number out of range.\n"); 96 | /* Free the device list */ 97 | pcap_freealldevs (alldevs); 98 | return; 99 | } 100 | 101 | /* Jump to the selected adapter */ 102 | for (d=alldevs, i=0; i< inum-1 ; d=d->next, i++); 103 | 104 | /* Open the device */ 105 | #ifdef _WIN32 106 | if ( (adhandle= pcap_open (d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, -1, NULL, errbuf) ) == NULL) 107 | #else 108 | if ( (adhandle= pcap_open_live (d->name, 65535, 1, -1, NULL) ) == NULL) 109 | #endif 110 | { 111 | printf ("\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); 112 | /* Free the device list */ 113 | pcap_freealldevs (alldevs); 114 | return; 115 | } 116 | 117 | printf ("\nEthernet bridge on %s...\n", d->description); 118 | 119 | /* At this point, we don't need any more the device list. Free it */ 120 | pcap_freealldevs (alldevs); 121 | net_enabled = 1; 122 | } 123 | 124 | void setmac() { 125 | memcpy (&RAM[0xE0000], &maclocal[0], 6); 126 | } 127 | 128 | #ifndef NETWORKING_OLDCARD 129 | extern int ne2000_can_receive(); 130 | extern void ne2000_receive (const uint8_t *buf, int size); 131 | 132 | uint8_t newrecv[5000]; 133 | 134 | void dispatch() { 135 | uint16_t i; 136 | 137 | if (pcap_next_ex (adhandle, &hdr, &pktdata) <=0) return; 138 | if (hdr->len==0) return; 139 | if (ne2000_can_receive() ) { 140 | for (i=0; ilen; i++) { 141 | newrecv[i<<1] = pktdata[i]; 142 | newrecv[ (i<<1) +1] = 0; 143 | } 144 | ne2000_receive (newrecv, hdr->len); 145 | } 146 | return; 147 | } 148 | 149 | void sendpkt (uint8_t *src, uint16_t len) { 150 | uint16_t i; 151 | for (i=0; ilen==0) return; 169 | 170 | net.canrecv = 0; 171 | memcpy (&RAM[0xD0000], &pktdata[0], hdr->len); 172 | net.pktlen = (uint16_t) hdr->len; 173 | if (verbose) { 174 | printf ("Received packet of %u bytes.\n", net.pktlen); 175 | } 176 | doirq (6); 177 | return; 178 | } 179 | 180 | void sendpkt (uint8_t *src, uint16_t len) { 181 | pcap_sendpacket (adhandle, src, len); 182 | } 183 | #endif 184 | 185 | #endif 186 | -------------------------------------------------------------------------------- /src/fake86/i8237.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* i8237.c: functions to emulate the Intel 8237 DMA controller. 21 | the Sound Blaster emulation functions rely on this! */ 22 | 23 | #include "config.h" 24 | #include 25 | #include 26 | //#include 27 | #include "blaster.h" 28 | #include "i8237.h" 29 | 30 | extern struct blaster_s blaster; 31 | 32 | struct dmachan_s dmachan[4]; 33 | uint8_t flipflop = 0; 34 | 35 | extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback); 36 | extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback); 37 | extern uint8_t read86 (uint32_t addr32); 38 | 39 | extern uint8_t RAM[0x100000]; 40 | uint8_t read8237 (uint8_t channel) { 41 | uint8_t ret; 42 | if (dmachan[channel].masked) return (128); 43 | if (dmachan[channel].autoinit && (dmachan[channel].count > dmachan[channel].reload) ) dmachan[channel].count = 0; 44 | if (dmachan[channel].count > dmachan[channel].reload) return (128); 45 | //if (dmachan[channel].direction) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count]; 46 | // else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count]; 47 | if (dmachan[channel].direction == 0) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count]; 48 | else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count]; 49 | dmachan[channel].count++; 50 | return (ret); 51 | } 52 | 53 | void out8237 (uint16_t addr, uint8_t value) { 54 | uint8_t channel; 55 | #ifdef DEBUG_DMA 56 | printf ("out8237(0x%X, %X);\n", addr, value); 57 | #endif 58 | switch (addr) { 59 | case 0x2: //channel 1 address register 60 | if (flipflop == 1) dmachan[1].addr = (dmachan[1].addr & 0x00FF) | ( (uint32_t) value << 8); 61 | else dmachan[1].addr = (dmachan[1].addr & 0xFF00) | value; 62 | #ifdef DEBUG_DMA 63 | if (flipflop == 1) printf ("[NOTICE] DMA channel 1 address register = %04X\n", dmachan[1].addr); 64 | #endif 65 | flipflop = ~flipflop & 1; 66 | break; 67 | case 0x3: //channel 1 count register 68 | if (flipflop == 1) dmachan[1].reload = (dmachan[1].reload & 0x00FF) | ( (uint32_t) value << 8); 69 | else dmachan[1].reload = (dmachan[1].reload & 0xFF00) | value; 70 | if (flipflop == 1) { 71 | if (dmachan[1].reload == 0) dmachan[1].reload = 65536; 72 | dmachan[1].count = 0; 73 | #ifdef DEBUG_DMA 74 | printf ("[NOTICE] DMA channel 1 reload register = %04X\n", dmachan[1].reload); 75 | #endif 76 | } 77 | flipflop = ~flipflop & 1; 78 | break; 79 | case 0xA: //write single mask register 80 | channel = value & 3; 81 | dmachan[channel].masked = (value >> 2) & 1; 82 | #ifdef DEBUG_DMA 83 | printf ("[NOTICE] DMA channel %u masking = %u\n", channel, dmachan[channel].masked); 84 | #endif 85 | break; 86 | case 0xB: //write mode register 87 | channel = value & 3; 88 | dmachan[channel].direction = (value >> 5) & 1; 89 | dmachan[channel].autoinit = (value >> 4) & 1; 90 | dmachan[channel].writemode = (value >> 2) & 1; //not quite accurate 91 | #ifdef DEBUG_DMA 92 | printf ("[NOTICE] DMA channel %u write mode reg: direction = %u, autoinit = %u, write mode = %u\n", 93 | channel, dmachan[channel].direction, dmachan[channel].autoinit, dmachan[channel].writemode); 94 | #endif 95 | break; 96 | case 0xC: //clear byte pointer flip-flop 97 | #ifdef DEBUG_DMA 98 | printf ("[NOTICE] DMA cleared byte pointer flip-flop\n"); 99 | #endif 100 | flipflop = 0; 101 | break; 102 | case 0x83: //DMA channel 1 page register 103 | dmachan[1].page = (uint32_t) value << 16; 104 | #ifdef DEBUG_DMA 105 | printf ("[NOTICE] DMA channel 1 page base = %05X\n", dmachan[1].page); 106 | #endif 107 | break; 108 | } 109 | } 110 | 111 | uint8_t in8237 (uint16_t addr) { 112 | #ifdef DEBUG_DMA 113 | printf ("in8237(0x%X);\n", addr); 114 | #endif 115 | switch (addr) { 116 | case 3: 117 | if (flipflop == 1) return(dmachan[1].reload >> 8); 118 | else return(dmachan[1].reload); 119 | flipflop = ~flipflop & 1; 120 | break; 121 | } 122 | return (0); 123 | } 124 | 125 | void init8237() { 126 | memset (dmachan, 0, sizeof (dmachan) ); 127 | 128 | set_port_write_redirector (0x00, 0x0F, &out8237); 129 | set_port_read_redirector (0x00, 0x0F, &in8237); 130 | 131 | set_port_write_redirector (0x80, 0x8F, &out8237); 132 | set_port_read_redirector (0x80, 0x8F, &in8237); 133 | } 134 | -------------------------------------------------------------------------------- /win32/fake86.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | {24282956-ada5-4a20-b289-9af8e28ff7c9} 18 | 19 | 20 | {91c547f5-4ef4-4a63-9ad1-3be02cf667ac} 21 | 22 | 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | Source Files 47 | 48 | 49 | Source Files 50 | 51 | 52 | Source Files 53 | 54 | 55 | Source Files 56 | 57 | 58 | Source Files 59 | 60 | 61 | Source Files 62 | 63 | 64 | Source Files 65 | 66 | 67 | Source Files 68 | 69 | 70 | Source Files 71 | 72 | 73 | Source Files 74 | 75 | 76 | Source Files 77 | 78 | 79 | Source Files 80 | 81 | 82 | Source Files 83 | 84 | 85 | Source Files 86 | 87 | 88 | Source Files 89 | 90 | 91 | Source Files\win32 92 | 93 | 94 | 95 | 96 | Header Files 97 | 98 | 99 | Header Files 100 | 101 | 102 | Header Files 103 | 104 | 105 | Header Files 106 | 107 | 108 | Header Files 109 | 110 | 111 | Header Files 112 | 113 | 114 | Header Files 115 | 116 | 117 | Header Files 118 | 119 | 120 | Header Files 121 | 122 | 123 | Header Files 124 | 125 | 126 | Header Files 127 | 128 | 129 | Header Files\win32 130 | 131 | 132 | 133 | 134 | Resource Files 135 | 136 | 137 | -------------------------------------------------------------------------------- /win32/imagegen.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release (with WinPCap) 10 | Win32 11 | 12 | 13 | Release 14 | Win32 15 | 16 | 17 | 18 | {BE8FA015-E801-40C8-B35B-D477C540439F} 19 | Win32Proj 20 | imagegen 21 | 22 | 23 | 24 | Application 25 | false 26 | true 27 | Unicode 28 | 29 | 30 | Application 31 | false 32 | true 33 | Unicode 34 | 35 | 36 | Application 37 | false 38 | true 39 | Unicode 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | false 56 | .\bin\ 57 | .\intermediate\ 58 | 59 | 60 | false 61 | .\bin\ 62 | .\intermediate\ 63 | 64 | 65 | false 66 | .\bin\ 67 | .\intermediate\ 68 | 69 | 70 | 71 | Level3 72 | 73 | 74 | MaxSpeed 75 | true 76 | true 77 | _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 78 | Fast 79 | MultiThreaded 80 | Default 81 | true 82 | 83 | 84 | Console 85 | false 86 | true 87 | true 88 | 1.1 89 | 90 | 91 | 92 | 93 | Level3 94 | 95 | 96 | MaxSpeed 97 | true 98 | true 99 | _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 100 | Fast 101 | MultiThreaded 102 | Default 103 | true 104 | 105 | 106 | Console 107 | false 108 | true 109 | true 110 | 1.1 111 | 112 | 113 | 114 | 115 | Level3 116 | 117 | 118 | MaxSpeed 119 | true 120 | true 121 | _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 122 | Fast 123 | MultiThreaded 124 | Default 125 | true 126 | 127 | 128 | Console 129 | false 130 | true 131 | true 132 | 1.1 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /src/fake86/disk.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* disk.c: disk emulation routines for Fake86. works at the BIOS interrupt 13h level. */ 21 | 22 | #include 23 | #include 24 | #include "disk.h" 25 | #include "cpu.h" 26 | 27 | extern uint8_t RAM[0x100000], cf, hdcount; 28 | extern uint16_t segregs[4]; 29 | extern union _bytewordregs_ regs; 30 | 31 | extern uint8_t read86 (uint32_t addr32); 32 | extern void write86 (uint32_t addr32, uint8_t value); 33 | 34 | struct struct_drive disk[256]; 35 | uint8_t sectorbuffer[512]; 36 | 37 | uint8_t insertdisk (uint8_t drivenum, char *filename) { 38 | if (disk[drivenum].inserted) fclose (disk[drivenum].diskfile); 39 | else disk[drivenum].inserted = 1; 40 | disk[drivenum].diskfile = fopen (filename, "r+b"); 41 | if (disk[drivenum].diskfile==NULL) { 42 | disk[drivenum].inserted = 0; 43 | return (1); 44 | } 45 | fseek (disk[drivenum].diskfile, 0L, SEEK_END); 46 | disk[drivenum].filesize = ftell (disk[drivenum].diskfile); 47 | fseek (disk[drivenum].diskfile, 0L, SEEK_SET); 48 | if (drivenum >= 0x80) { //it's a hard disk image 49 | disk[drivenum].sects = 63; 50 | disk[drivenum].heads = 16; 51 | disk[drivenum].cyls = disk[drivenum].filesize / (disk[drivenum].sects * disk[drivenum].heads * 512); 52 | hdcount++; 53 | } 54 | else { //it's a floppy image 55 | disk[drivenum].cyls = 80; 56 | disk[drivenum].sects = 18; 57 | disk[drivenum].heads = 2; 58 | if (disk[drivenum].filesize <= 1228800) disk[drivenum].sects = 15; 59 | if (disk[drivenum].filesize <= 737280) disk[drivenum].sects = 9; 60 | if (disk[drivenum].filesize <= 368640) { 61 | disk[drivenum].cyls = 40; 62 | disk[drivenum].sects = 9; 63 | } 64 | if (disk[drivenum].filesize <= 163840) { 65 | disk[drivenum].cyls = 40; 66 | disk[drivenum].sects = 8; 67 | disk[drivenum].heads = 1; 68 | } 69 | } 70 | return (0); 71 | } 72 | 73 | void ejectdisk (uint8_t drivenum) { 74 | disk[drivenum].inserted = 0; 75 | if (disk[drivenum].diskfile != NULL) fclose (disk[drivenum].diskfile); 76 | } 77 | 78 | void readdisk (uint8_t drivenum, uint16_t dstseg, uint16_t dstoff, uint16_t cyl, uint16_t sect, uint16_t head, uint16_t sectcount) { 79 | uint32_t memdest, lba, fileoffset, cursect, sectoffset; 80 | if (!sect || !disk[drivenum].inserted) return; 81 | lba = ( (uint32_t) cyl * (uint32_t) disk[drivenum].heads + (uint32_t) head) * (uint32_t) disk[drivenum].sects + (uint32_t) sect - 1; 82 | fileoffset = lba * 512; 83 | if (fileoffset>disk[drivenum].filesize) return; 84 | fseek (disk[drivenum].diskfile, fileoffset, SEEK_SET); 85 | memdest = ( (uint32_t) dstseg << 4) + (uint32_t) dstoff; 86 | //for the readdisk function, we need to use write86 instead of directly fread'ing into 87 | //the RAM array, so that read-only flags are honored. otherwise, a program could load 88 | //data from a disk over BIOS or other ROM code that it shouldn't be able to. 89 | for (cursect=0; cursectdisk[drivenum].filesize) return; 106 | fseek (disk[drivenum].diskfile, fileoffset, SEEK_SET); 107 | memdest = ( (uint32_t) dstseg << 4) + (uint32_t) dstoff; 108 | for (cursect=0; cursectdevkitARM") 7 | endif 8 | 9 | TOPDIR ?= $(CURDIR) 10 | include $(DEVKITARM)/3ds_rules 11 | 12 | #--------------------------------------------------------------------------------- 13 | # TARGET is the name of the output 14 | # BUILD is the directory where object files & intermediate files will be placed 15 | # SOURCES is a list of directories containing source code 16 | # DATA is a list of directories containing data files 17 | # INCLUDES is a list of directories containing header files 18 | # 19 | # NO_SMDH: if set to anything, no SMDH file is generated. 20 | # ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional) 21 | # APP_TITLE is the name of the app stored in the SMDH file (Optional) 22 | # APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) 23 | # APP_AUTHOR is the author of the app stored in the SMDH file (Optional) 24 | # ICON is the filename of the icon (.png), relative to the project folder. 25 | # If not set, it attempts to use one of the following (in this order): 26 | # - .png 27 | # - icon.png 28 | # - /default_icon.png 29 | #--------------------------------------------------------------------------------- 30 | TARGET := $(notdir $(CURDIR)) 31 | BUILD := build 32 | SOURCES := src/fake86 33 | DATA := 34 | INCLUDES := include 35 | DATAPATH = /3ds/fake86/data 36 | #ROMFS := romfs 37 | 38 | #--------------------------------------------------------------------------------- 39 | # options for code generation 40 | #--------------------------------------------------------------------------------- 41 | ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard 42 | 43 | CFLAGS := -g -Wall -O2 -mword-relocations -Wfatal-errors \ 44 | -fomit-frame-pointer -ffunction-sections\ 45 | $(ARCH) 46 | 47 | CFLAGS += $(INCLUDE) -DARM11 -D_3DS -DPATH_DATAFILES=\"$(DATAPATH)/\" 48 | 49 | CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 50 | 51 | ASFLAGS := -g $(ARCH) 52 | LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) -Wl,--gc-sections 53 | 54 | LIBS := -lctru -lm 55 | 56 | #--------------------------------------------------------------------------------- 57 | # list of directories containing libraries, this must be the top level containing 58 | # include and lib 59 | #--------------------------------------------------------------------------------- 60 | LIBDIRS := $(CTRULIB) 61 | 62 | 63 | #--------------------------------------------------------------------------------- 64 | # no real need to edit anything past this point unless you need to add additional 65 | # rules for different file extensions 66 | #--------------------------------------------------------------------------------- 67 | ifneq ($(BUILD),$(notdir $(CURDIR))) 68 | #--------------------------------------------------------------------------------- 69 | 70 | export OUTPUT := $(CURDIR)/$(TARGET) 71 | export TOPDIR := $(CURDIR) 72 | 73 | export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ 74 | $(foreach dir,$(DATA),$(CURDIR)/$(dir)) 75 | 76 | export DEPSDIR := $(CURDIR)/$(BUILD) 77 | 78 | CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) 79 | CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) 80 | SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) 81 | PICAFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.v.pica))) 82 | SHLISTFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.shlist))) 83 | BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*))) 84 | 85 | #--------------------------------------------------------------------------------- 86 | # use CXX for linking C++ projects, CC for standard C 87 | #--------------------------------------------------------------------------------- 88 | ifeq ($(strip $(CPPFILES)),) 89 | #--------------------------------------------------------------------------------- 90 | export LD := $(CC) 91 | #--------------------------------------------------------------------------------- 92 | else 93 | #--------------------------------------------------------------------------------- 94 | export LD := $(CXX) 95 | #--------------------------------------------------------------------------------- 96 | endif 97 | #--------------------------------------------------------------------------------- 98 | 99 | export OFILES := $(addsuffix .o,$(BINFILES)) \ 100 | $(PICAFILES:.v.pica=.shbin.o) $(SHLISTFILES:.shlist=.shbin.o) \ 101 | $(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o) 102 | 103 | export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ 104 | $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ 105 | -I$(CURDIR)/$(BUILD) 106 | 107 | export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib) 108 | 109 | ifeq ($(strip $(ICON)),) 110 | icons := $(wildcard *.png) 111 | ifneq (,$(findstring $(TARGET).png,$(icons))) 112 | export APP_ICON := $(TOPDIR)/$(TARGET).png 113 | else 114 | ifneq (,$(findstring icon.png,$(icons))) 115 | export APP_ICON := $(TOPDIR)/icon.png 116 | endif 117 | endif 118 | else 119 | export APP_ICON := $(TOPDIR)/$(ICON) 120 | endif 121 | 122 | ifeq ($(strip $(NO_SMDH)),) 123 | export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh 124 | endif 125 | 126 | ifneq ($(ROMFS),) 127 | export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS) 128 | endif 129 | 130 | .PHONY: $(BUILD) clean all 131 | 132 | #--------------------------------------------------------------------------------- 133 | all: $(BUILD) 134 | 135 | $(BUILD): 136 | @[ -d $@ ] || mkdir -p $@ 137 | @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile 138 | 139 | #--------------------------------------------------------------------------------- 140 | clean: 141 | @echo clean ... 142 | @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf 143 | 144 | 145 | #--------------------------------------------------------------------------------- 146 | else 147 | 148 | DEPENDS := $(OFILES:.o=.d) 149 | 150 | #--------------------------------------------------------------------------------- 151 | # main targets 152 | #--------------------------------------------------------------------------------- 153 | ifeq ($(strip $(NO_SMDH)),) 154 | $(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh 155 | else 156 | $(OUTPUT).3dsx : $(OUTPUT).elf 157 | endif 158 | 159 | $(OUTPUT).elf : $(OFILES) 160 | 161 | #--------------------------------------------------------------------------------- 162 | # you need a rule like this for each extension you use as binary data 163 | #--------------------------------------------------------------------------------- 164 | %.bin.o : %.bin 165 | #--------------------------------------------------------------------------------- 166 | @echo $(notdir $<) 167 | @$(bin2o) 168 | 169 | #--------------------------------------------------------------------------------- 170 | # rules for assembling GPU shaders 171 | #--------------------------------------------------------------------------------- 172 | define shader-as 173 | $(eval CURBIN := $(patsubst %.shbin.o,%.shbin,$(notdir $@))) 174 | picasso -o $(CURBIN) $1 175 | bin2s $(CURBIN) | $(AS) -o $@ 176 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h 177 | echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h 178 | echo "extern const u32" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(CURBIN) | tr . _)`.h 179 | endef 180 | 181 | %.shbin.o : %.v.pica %.g.pica 182 | @echo $(notdir $^) 183 | @$(call shader-as,$^) 184 | 185 | %.shbin.o : %.v.pica 186 | @echo $(notdir $<) 187 | @$(call shader-as,$<) 188 | 189 | %.shbin.o : %.shlist 190 | @echo $(notdir $<) 191 | @$(call shader-as,$(foreach file,$(shell cat $<),$(dir $<)/$(file))) 192 | 193 | -include $(DEPENDS) 194 | 195 | #--------------------------------------------------------------------------------------- 196 | endif 197 | #--------------------------------------------------------------------------------------- -------------------------------------------------------------------------------- /src/fake86/parsecl.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* parsecl.c: Fake86 command line parsing for runtime options. */ 21 | 22 | #include "config.h" 23 | //#include 24 | #include 25 | #include 26 | #include 27 | #include "disk.h" 28 | 29 | extern struct struct_drive disk[256]; 30 | #ifndef _WIN32 31 | #define strcmpi strcasecmp 32 | #else 33 | #define strcmpi _strcmpi 34 | #endif 35 | 36 | extern uint8_t bootdrive, ethif, verbose, cgaonly, *biosfile, usessource, noscale, nosmooth, renderbenchmark, useconsole, doaudio; 37 | extern uint32_t framedelay, textbase, usefullscreen, speed; 38 | extern int32_t usesamplerate, latency; 39 | uint16_t constantw = 0, constanth = 0; 40 | uint8_t slowsystem = 0; 41 | 42 | extern uint8_t insertdisk (uint8_t drivenum, char *filename); 43 | extern uint32_t loadrom (uint32_t addr32, uint8_t *filename, uint8_t failure_fatal); 44 | 45 | uint32_t hextouint(char *src) { 46 | uint32_t tempuint = 0, cc; 47 | uint16_t i; 48 | 49 | for (i=0; i= 'a') && (cc <= 'F')) cc = cc - 'a' + 10; 53 | else if ((cc >= 'A') && (cc <= 'F')) cc = cc - 'A' + 10; 54 | else if ((cc >= '0') && (cc <= '9')) cc = cc - '0'; 55 | else return(0); 56 | tempuint <<= 4; 57 | tempuint |= cc; 58 | } 59 | return(tempuint); 60 | } 61 | 62 | void showhelp () { 63 | printf ("Fake86 requires some command line parameters to run.\nValid options:\n"); 64 | 65 | printf (" -fd0 filename Specify a floppy disk image file to use as floppy 0.\n"); 66 | printf (" -fd1 filename Specify a floppy disk image file to use as floppy 1.\n"); 67 | printf (" -hd0 filename Specify a hard disk image file to use as hard drive 0.\n"); 68 | printf (" -hd1 filename Specify a hard disk image file to use as hard drive 1.\n"); 69 | printf (" -boot # Specify which BIOS drive ID should be the boot device in #.\n"); 70 | printf (" Examples: -boot 0 will boot from floppy 0.\n"); 71 | printf (" -boot 1 will boot from floppy 1.\n"); 72 | printf (" -boot 128 will boot from hard drive 0.\n"); 73 | printf (" -boot rom will boot to ROM BASIC if available.\n"); 74 | printf (" Default boot device is hard drive 0, if it exists.\n"); 75 | printf (" Otherwise, the default is floppy 0.\n"); 76 | printf (" -bios filename Specify alternate BIOS ROM image to use.\n"); 77 | #ifdef NETWORKING_ENABLED 78 | #ifdef _WIN32 79 | printf (" -net # Enable ethernet emulation via winpcap, where # is the\n"); 80 | #else 81 | printf (" -net # Enable ethernet emulation via libpcap, where # is the\n"); 82 | #endif 83 | printf (" numeric ID of your host's network interface to bridge.\n"); 84 | printf (" To get a list of possible interfaces, use -net list\n"); 85 | #endif 86 | printf (" -nosound Disable audio emulation and output.\n"); 87 | printf (" -fullscreen Start Fake86 in fullscreen mode.\n"); 88 | printf (" -verbose Verbose mode. Operation details will be written to stdout.\n"); 89 | printf (" -delay Specify how many milliseconds the render thread should idle\n"); 90 | printf (" between drawing each frame. Default is 20 ms. (~50 FPS)\n"); 91 | printf (" -slowsys If your machine is very slow and you have audio dropouts,\n"); 92 | printf (" use this option to sacrifice audio quality to compensate.\n"); 93 | printf (" If you still have dropouts, then also decrease sample rate\n"); 94 | printf (" and/or increase latency.\n"); 95 | printf (" -resw # -resh # Force a constant window size in pixels.\n"); 96 | printf (" -smooth Apply smoothing to screen rendering.\n"); 97 | printf (" -noscale Disable 2x scaling of low resolution video modes.\n"); 98 | printf (" -ssource Enable Disney Sound Source emulation on LPT1.\n"); 99 | printf (" -latency # Change audio buffering and output latency. (default: 100 ms)\n"); 100 | printf (" -samprate # Change audio emulation sample rate. (default: 48000 Hz)\n"); 101 | printf (" -console Enable console on stdio during emulation.\n"); 102 | printf (" -oprom addr rom Inject a custom option ROM binary at an address in hex.\n"); 103 | printf (" Example: -oprom F4000 monitor.bin\n"); 104 | printf (" This loads the data from monitor.bin at 0xF4000.\n"); 105 | 106 | printf ("\nThis program is free software; you can redistribute it and/or\n"); 107 | printf ("modify it under the terms of the GNU General Public License\n"); 108 | printf ("as published by the Free Software Foundation; either version 2\n"); 109 | printf ("of the License, or (at your option) any later version.\n\n"); 110 | 111 | printf ("This program is distributed in the hope that it will be useful,\n"); 112 | printf ("but WITHOUT ANY WARRANTY; without even the implied warranty of\n"); 113 | printf ("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"); 114 | printf ("GNU General Public License for more details.\n"); 115 | 116 | exit (0); 117 | } 118 | 119 | void parsecl (int argc, char *argv[]) { 120 | uint32_t tempuint; 121 | int i, abort = 0; 122 | 123 | if (argc<2) { 124 | printf ("Invoke Fake86 with the parameter -h for help and usage information.\n"); 125 | #ifndef _WIN32 126 | exit (0); 127 | #endif 128 | } 129 | 130 | bootdrive = 254; 131 | textbase = 0xB8000; 132 | ethif = 254; 133 | usefullscreen = 0; 134 | biosfile = "/3ds/fake86/data/pcxtbios.bin"; 135 | for (i=1; i 25 | #include 26 | #include 27 | #include 28 | 29 | #include "mutex.h" 30 | 31 | #define STACKSIZE (8 * 1024) 32 | 33 | const uint8_t *build = BUILD_STRING; 34 | 35 | extern uint8_t RAM[0x100000], readonly[0x100000]; 36 | extern uint8_t running, renderbenchmark; 37 | 38 | extern void reset86(); 39 | extern void exec86 (uint32_t execloops); 40 | extern uint8_t initscreen (uint8_t *ver); 41 | extern void VideoThread(); 42 | extern doscrmodechange(); 43 | extern void handleinput(); 44 | 45 | #ifdef CPU_ADDR_MODE_CACHE 46 | extern uint64_t cached_access_count, uncached_access_count; 47 | #endif 48 | 49 | extern uint8_t scrmodechange, doaudio; 50 | extern uint64_t totalexec, totalframes; 51 | uint64_t starttick, endtick, lasttick; 52 | 53 | uint8_t *biosfile = NULL, verbose = 0, cgaonly = 0, useconsole = 0; 54 | uint32_t speed = 0; 55 | 56 | 57 | uint32_t loadbinary (uint32_t addr32, uint8_t *filename, uint8_t roflag) { 58 | FILE *binfile = NULL; 59 | uint32_t readsize; 60 | 61 | binfile = fopen (filename, "rb"); 62 | if (binfile == NULL) { 63 | return (0); 64 | } 65 | 66 | fseek (binfile, 0, SEEK_END); 67 | readsize = ftell (binfile); 68 | fseek (binfile, 0, SEEK_SET); 69 | fread ( (void *) &RAM[addr32], 1, readsize, binfile); 70 | fclose (binfile); 71 | 72 | memset ( (void *) &readonly[addr32], roflag, readsize); 73 | return (readsize); 74 | } 75 | 76 | uint32_t loadrom (uint32_t addr32, uint8_t *filename, uint8_t failure_fatal) { 77 | uint32_t readsize; 78 | readsize = loadbinary (addr32, filename, 1); 79 | if (!readsize) { 80 | if (failure_fatal) printf("FATAL: "); 81 | else printf("WARNING: "); 82 | printf ("Unable to load %s\n", filename); 83 | return (0); 84 | } 85 | else { 86 | printf ("Loaded %s at 0x%05X (%lu KB)\n", filename, addr32, readsize >> 10); 87 | return (readsize); 88 | } 89 | } 90 | 91 | uint32_t loadbios (uint8_t *filename) { 92 | FILE *binfile = NULL; 93 | uint32_t readsize; 94 | 95 | binfile = fopen (filename, "rb"); 96 | if (binfile == NULL) { 97 | return (0); 98 | } 99 | 100 | fseek (binfile, 0, SEEK_END); 101 | readsize = ftell (binfile); 102 | fseek (binfile, 0, SEEK_SET); 103 | fread ( (void *) &RAM[0x100000 - readsize], 1, readsize, binfile); 104 | fclose (binfile); 105 | 106 | memset ( (void *) &readonly[0x100000 - readsize], 1, readsize); 107 | return (readsize); 108 | } 109 | 110 | extern uint32_t SDL_GetTicks(); 111 | extern uint8_t insertdisk (uint8_t drivenum, char *filename); 112 | extern void ejectdisk (uint8_t drivenum); 113 | extern uint8_t bootdrive, ethif, net_enabled; 114 | extern void doirq (uint8_t irqnum); 115 | //extern void isa_ne2000_init(int baseport, uint8_t irq); 116 | extern void parsecl (int argc, char *argv[]); 117 | void timing(); 118 | void tickaudio(); 119 | void inittiming(); 120 | void initaudio(); 121 | void init8253(); 122 | void init8259(); 123 | extern void init8237(); 124 | extern void initVideoPorts(); 125 | extern void killaudio(); 126 | extern void initsermouse (uint16_t baseport, uint8_t irq); 127 | extern void *port_write_callback[0x10000]; 128 | extern void *port_read_callback[0x10000]; 129 | extern void *port_write_callback16[0x10000]; 130 | extern void *port_read_callback16[0x10000]; 131 | extern void initadlib (uint16_t baseport); 132 | extern void initsoundsource(); 133 | extern void isa_ne2000_init (uint16_t baseport, uint8_t irq); 134 | extern void initBlaster (uint16_t baseport, uint8_t irq); 135 | 136 | #ifdef NETWORKING_ENABLED 137 | extern void initpcap(); 138 | extern void dispatch(); 139 | #endif 140 | 141 | void printbinary (uint8_t value) { 142 | int8_t curbit; 143 | 144 | for (curbit=7; curbit>=0; curbit--) { 145 | if ( (value >> curbit) & 1) printf ("1"); 146 | else printf ("0"); 147 | } 148 | } 149 | 150 | uint8_t usessource = 0; 151 | void inithardware() { 152 | #ifdef NETWORKING_ENABLED 153 | if (ethif != 254) initpcap(); 154 | #endif 155 | printf ("Initializing emulated hardware:\n"); 156 | memset (port_write_callback, 0, sizeof (port_write_callback) ); 157 | memset (port_read_callback, 0, sizeof (port_read_callback) ); 158 | memset (port_write_callback16, 0, sizeof (port_write_callback16) ); 159 | memset (port_read_callback16, 0, sizeof (port_read_callback16) ); 160 | printf (" - Intel 8253 timer: "); 161 | init8253(); 162 | printf ("OK\n"); 163 | printf (" - Intel 8259 interrupt controller: "); 164 | init8259(); 165 | printf ("OK\n"); 166 | printf (" - Intel 8237 DMA controller: "); 167 | init8237(); 168 | printf ("OK\n"); 169 | initVideoPorts(); 170 | if (usessource) { 171 | printf (" - Disney Sound Source: "); 172 | initsoundsource(); 173 | printf ("OK\n"); 174 | } 175 | #ifndef NETWORKING_OLDCARD 176 | printf (" - Novell NE2000 ethernet adapter: "); 177 | isa_ne2000_init (0x300, 6); 178 | printf ("OK\n"); 179 | #endif 180 | printf (" - Adlib FM music card: "); 181 | initadlib (0x388); 182 | printf ("OK\n"); 183 | printf (" - Creative Labs Sound Blaster 2.0: "); 184 | initBlaster (0x220, 7); 185 | printf ("OK\n"); 186 | printf (" - Serial mouse (Microsoft compatible): "); 187 | initsermouse (0x3F8, 4); 188 | printf ("OK\n"); 189 | if (doaudio) initaudio(); 190 | inittiming(); 191 | initscreen ( (uint8_t *) build); 192 | } 193 | 194 | uint8_t dohardreset = 0; 195 | uint8_t audiobufferfilled(); 196 | 197 | #ifdef _WIN32 198 | void initmenus(); 199 | void EmuThread (void *dummy) { 200 | #else 201 | Thread emuthread; 202 | void EmuThread (void *dummy) { 203 | #endif 204 | while (running) { 205 | if (!speed) exec86 (10000); 206 | else { 207 | exec86(speed / 100); 208 | while (!audiobufferfilled()) { 209 | timing(); 210 | tickaudio(); 211 | } 212 | #ifdef _WIN32 213 | Sleep(10); 214 | #else 215 | usleep(50); 216 | #endif 217 | } 218 | if (scrmodechange) doscrmodechange(); 219 | if (dohardreset) { 220 | reset86(); 221 | dohardreset = 0; 222 | } 223 | } 224 | } 225 | 226 | #ifdef _WIN32 227 | void runconsole (void *dummy); 228 | #else 229 | void *runconsole (void *dummy); 230 | #endif 231 | extern void bufsermousedata (uint8_t value); 232 | int main (int argc, char *argv[]) { 233 | uint32_t biossize; 234 | 235 | osSetSpeedupEnable(true); 236 | gfxInitDefault(); 237 | gfxSetDoubleBuffering(GFX_TOP, false); 238 | gfxSetDoubleBuffering(GFX_BOTTOM, false); 239 | gfxSet3D(false); 240 | consoleInit(GFX_BOTTOM, NULL); 241 | 242 | printf ("[A portable, open-source 8086 PC emulator]\n\n"); 243 | 244 | char *args[64]; 245 | args[0] = ""; 246 | args[1] = "-hd0"; 247 | args[2] = "test.raw"; 248 | args[3] = "-noaudio"; 249 | 250 | printf ("%s (c)2010-2013 Mike Chambers\n", build); 251 | printf ("[A portable, open-source 8086 PC emulator]\n\n"); 252 | 253 | parsecl (3, args); 254 | 255 | memset (readonly, 0, 0x100000); 256 | biossize = loadbios (biosfile); 257 | if (!biossize) return (-1); 258 | #ifdef DISK_CONTROLLER_ATA 259 | if (!loadrom (0xD0000UL, "/3ds/fake86/data/ide_xt.bin", 1) ) return (-1); 260 | #endif 261 | if (biossize <= 8192) { 262 | loadrom (0xF6000UL, "/3ds/fake86/data/rombasic.bin", 0); 263 | if (!loadrom (0xC0000UL, "/3ds/fake86/data/videorom.bin", 1) ) return (-1); 264 | } 265 | printf ("\nInitializing CPU... "); 266 | running = 1; 267 | reset86(); 268 | printf ("OK!\n"); 269 | 270 | Touch_Init(); 271 | Touch_DrawOverlay(); 272 | 273 | inithardware(); 274 | 275 | #ifdef _WIN32 276 | initmenus(); 277 | InitializeCriticalSection (&screenmutex); 278 | #endif 279 | if (useconsole) { 280 | #ifdef _WIN32 281 | _beginthread (runconsole, 0, NULL); 282 | #else 283 | //pthread_create (&consolethread, NULL, (void *) runconsole, NULL); 284 | #endif 285 | } 286 | 287 | #ifdef _WIN32 288 | _beginthread (EmuThread, 0, NULL); 289 | #else 290 | s32 prio = 0; 291 | svcGetThreadPriority(&prio, CUR_THREAD_HANDLE); 292 | emuthread = threadCreate(EmuThread, NULL, STACKSIZE, 0x32, -2, false); 293 | #endif 294 | 295 | lasttick = starttick = osGetTime(); 296 | while (running) { 297 | Touch_Update(); 298 | hidScanInput(); 299 | handleinput(); 300 | u32 kDown = hidKeysDown(); 301 | if (kDown & KEY_SELECT) 302 | running = false; 303 | #ifdef NETWORKING_ENABLED 304 | if (ethif < 254) dispatch(); 305 | #endif 306 | #ifdef _WIN32 307 | Sleep(1); 308 | #else 309 | usleep(1000); 310 | #endif 311 | } 312 | endtick = (osGetTime() - starttick) / 1000; 313 | if (endtick == 0) endtick = 1; //avoid divide-by-zero exception in the code below, if ran for less than 1 second 314 | 315 | killaudio(); 316 | 317 | if (renderbenchmark) { 318 | printf ("\n%llu frames rendered in %llu seconds.\n", totalframes, endtick); 319 | printf ("Average framerate: %llu FPS.\n", totalframes / endtick); 320 | } 321 | 322 | printf ("\n%llu instructions executed in %llu seconds.\n", totalexec, endtick); 323 | printf ("Average speed: %llu instructions/second.\n", totalexec / endtick); 324 | 325 | gfxExit(); 326 | 327 | #ifdef CPU_ADDR_MODE_CACHE 328 | printf ("\n Cached modregrm data access count: %llu\n", cached_access_count); 329 | printf ("Uncached modregrm data access count: %llu\n", uncached_access_count); 330 | #endif 331 | 332 | if (useconsole) exit (0); //makes sure console thread quits even if blocking 333 | 334 | return (0); 335 | } 336 | -------------------------------------------------------------------------------- /src/fake86/blaster.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* blaster.c: functions to emulate a Creative Labs Sound Blaster Pro. */ 21 | 22 | #include "config.h" 23 | #include 24 | #include 25 | #include 26 | #include "blaster.h" 27 | 28 | extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback); 29 | extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback); 30 | extern void doirq (uint8_t irqnum); 31 | extern uint8_t read8237 (uint8_t channel); 32 | 33 | extern void outadlib (uint16_t portnum, uint8_t value); //on the Sound Blaster Pro, ports (base+0) and (base+1) are for 34 | extern uint8_t inadlib (uint16_t portnum); //the OPL FM music chips, and are also mirrored at (base+8) (base+9) 35 | //as well as 0x388 and 0x389 to remain compatible with the older adlib cards 36 | 37 | struct blaster_s blaster; 38 | 39 | void bufNewData (uint8_t value) { 40 | if (blaster.memptr >= sizeof (blaster.mem) ) return; 41 | blaster.mem[blaster.memptr] = value; 42 | blaster.memptr++; 43 | } 44 | 45 | extern uint64_t hostfreq; 46 | void setsampleticks() { 47 | if (blaster.samplerate == 0) { 48 | blaster.sampleticks = 0; 49 | return; 50 | } 51 | blaster.sampleticks = hostfreq / (uint64_t) blaster.samplerate; 52 | } 53 | 54 | void cmdBlaster (uint8_t value) { 55 | uint8_t recognized = 1; 56 | if (blaster.waitforarg) { 57 | switch (blaster.lastcmdval) { 58 | case 0x10: //direct 8-bit sample output 59 | blaster.sample = value; 60 | break; 61 | case 0x14: //8-bit single block DMA output 62 | case 0x24: 63 | case 0x91: 64 | if (blaster.waitforarg == 2) { 65 | blaster.blocksize = (blaster.blocksize & 0xFF00) | (uint32_t) value; 66 | blaster.waitforarg = 3; 67 | return; 68 | } 69 | else { 70 | blaster.blocksize = (blaster.blocksize & 0x00FF) | ( (uint32_t) value << 8); 71 | #ifdef DEBUG_BLASTER 72 | printf ("[NOTICE] Sound Blaster DSP block transfer size set to %u\n", blaster.blocksize); 73 | #endif 74 | blaster.usingdma = 1; 75 | blaster.blockstep = 0; 76 | blaster.useautoinit = 0; 77 | blaster.paused8 = 0; 78 | blaster.speakerstate = 1; 79 | } 80 | break; 81 | case 0x40: //set time constant 82 | blaster.samplerate = (uint16_t) ( (uint32_t) 1000000 / (uint32_t) (256 - (uint32_t) value) ); 83 | setsampleticks(); 84 | #ifdef DEBUG_BLASTER 85 | printf ("[DEBUG] Sound Blaster time constant received, sample rate = %u\n", blaster.samplerate); 86 | #endif 87 | break; 88 | case 0x48: //set DSP block transfer size 89 | if (blaster.waitforarg == 2) { 90 | blaster.blocksize = (blaster.blocksize & 0xFF00) | (uint32_t) value; 91 | blaster.waitforarg = 3; 92 | return; 93 | } 94 | else { 95 | blaster.blocksize = (blaster.blocksize & 0x00FF) | ( (uint32_t) value << 8); 96 | //if (blaster.blocksize == 0) blaster.blocksize = 65536; 97 | blaster.blockstep = 0; 98 | #ifdef DEBUG_BLASTER 99 | printf ("[NOTICE] Sound Blaster DSP block transfer size set to %u\n", blaster.blocksize); 100 | #endif 101 | } 102 | break; 103 | case 0xE0: //DSP identification for Sound Blaster 2.0 and newer (invert each bit and put in read buffer) 104 | bufNewData (~value); 105 | break; 106 | case 0xE4: //DSP write test, put data value into read buffer 107 | bufNewData (value); 108 | blaster.lasttestval = value; 109 | break; 110 | default: 111 | recognized = 0; 112 | } 113 | //blaster.waitforarg--; // = 0; 114 | if (recognized) return; 115 | } 116 | 117 | switch (value) { 118 | case 0x10: 119 | case 0x40: 120 | case 0xE0: 121 | case 0xE4: 122 | blaster.waitforarg = 1; 123 | break; 124 | 125 | case 0x14: //8-bit single block DMA output 126 | case 0x24: 127 | case 0x48: 128 | case 0x91: 129 | blaster.waitforarg = 2; 130 | break; 131 | 132 | case 0x1C: //8-bit auto-init DMA output 133 | case 0x2C: 134 | blaster.usingdma = 1; 135 | blaster.blockstep = 0; 136 | blaster.useautoinit = 1; 137 | blaster.paused8 = 0; 138 | blaster.speakerstate = 1; 139 | break; 140 | 141 | case 0xD0: //pause 8-bit DMA I/O 142 | blaster.paused8 = 1; 143 | case 0xD1: //speaker output on 144 | blaster.speakerstate = 1; 145 | break; 146 | case 0xD3: //speaker output off 147 | blaster.speakerstate = 0; 148 | break; 149 | case 0xD4: //continue 8-bit DMA I/O 150 | blaster.paused8 = 0; 151 | break; 152 | case 0xD8: //get speaker status 153 | if (blaster.speakerstate) bufNewData (0xFF); 154 | else bufNewData (0x00); 155 | break; 156 | case 0xDA: //exit 8-bit auto-init DMA I/O mode 157 | blaster.usingdma = 0; 158 | break; 159 | case 0xE1: //get DSP version info 160 | blaster.memptr = 0; 161 | bufNewData (blaster.dspmaj); 162 | bufNewData (blaster.dspmin); 163 | break; 164 | case 0xE8: //DSP read test 165 | blaster.memptr = 0; 166 | bufNewData (blaster.lasttestval); 167 | break; 168 | case 0xF2: //force 8-bit IRQ 169 | doirq (blaster.sbirq); 170 | break; 171 | case 0xF8: //undocumented command, clears in-buffer and inserts a null byte 172 | blaster.memptr = 0; 173 | bufNewData (0); 174 | break; 175 | default: 176 | printf ("[NOTICE] Sound Blaster received unhandled command %02Xh\n", value); 177 | break; 178 | } 179 | } 180 | 181 | uint8_t mixer[256], mixerindex = 0; 182 | void outBlaster (uint16_t portnum, uint8_t value) { 183 | #ifdef DEBUG_BLASTER 184 | printf ("[DEBUG] outBlaster: port %Xh, value %02X\n", portnum, value); 185 | #endif 186 | portnum &= 0xF; 187 | switch (portnum) { 188 | case 0x0: 189 | case 0x8: 190 | outadlib (0x388, value); 191 | break; 192 | case 0x1: 193 | case 0x9: 194 | outadlib (0x389, value); 195 | break; 196 | case 0x4: //mixer address port 197 | mixerindex = value; 198 | break; 199 | case 0x5: //mixer data 200 | mixer[mixerindex] = value; 201 | break; 202 | case 0x6: //reset port 203 | if ( (value == 0x00) && (blaster.lastresetval == 0x01) ) { 204 | blaster.speakerstate = 0; 205 | blaster.sample = 128; 206 | blaster.waitforarg = 0; 207 | blaster.memptr = 0; 208 | blaster.usingdma = 0; 209 | blaster.blocksize = 65535; 210 | blaster.blockstep = 0; 211 | bufNewData (0xAA); 212 | memset (mixer, 0xEE, sizeof (mixer) ); 213 | #ifdef DEBUG_BLASTER 214 | printf ("[DEBUG] Sound Blaster received reset!\n"); 215 | #endif 216 | } 217 | blaster.lastresetval = value; 218 | break; 219 | case 0xC: //write command/data 220 | cmdBlaster (value); 221 | if (blaster.waitforarg != 3) blaster.lastcmdval = value; 222 | break; 223 | } 224 | } 225 | 226 | uint8_t inBlaster (uint16_t portnum) { 227 | uint8_t ret = 0; 228 | #ifdef DEBUG_BLASTER 229 | static uint16_t lastread = 0; 230 | #endif 231 | #ifdef DEBUG_BLASTER 232 | //if (lastread != portnum) printf ("[DEBUG] inBlaster: port %Xh, value ", portnum); 233 | #endif 234 | portnum &= 0xF; 235 | switch (portnum) { 236 | case 0x0: 237 | case 0x8: 238 | ret = inadlib (0x388); 239 | break; 240 | case 0x1: 241 | case 0x9: 242 | ret = inadlib (0x389); 243 | break; 244 | case 0x5: //mixer data 245 | ret = mixer[mixerindex]; 246 | break; 247 | case 0xA: //read data 248 | if (blaster.memptr == 0) { 249 | ret = 0; 250 | } 251 | else { 252 | ret = blaster.mem[0]; 253 | memmove (&blaster.mem[0], &blaster.mem[1], sizeof (blaster.mem) - 1); 254 | blaster.memptr--; 255 | } 256 | break; 257 | case 0xE: //read-buffer status 258 | if (blaster.memptr > 0) ret = 0x80; 259 | else ret = 0x00; 260 | break; 261 | default: 262 | ret = 0x00; 263 | } 264 | #ifdef DEBUG_BLASTER 265 | //if (lastread != portnum) printf ("%02X\n", ret); 266 | //lastread = portnum; 267 | #endif 268 | return (ret); 269 | } 270 | 271 | //FILE *sbout = NULL; 272 | void tickBlaster() { 273 | if (!blaster.usingdma) return; 274 | /*if (blaster.paused8) { 275 | blaster.sample = 128; 276 | return; 277 | }*/ 278 | //printf("tickBlaster();\n"); 279 | blaster.sample = read8237 (blaster.sbdma); 280 | //if (sbout != NULL) fwrite(&blaster.sample, 1, 1, sbout); 281 | blaster.blockstep++; 282 | if (blaster.blockstep > blaster.blocksize) { 283 | doirq (blaster.sbirq); 284 | #ifdef DEBUG_BLASTER 285 | printf ("[NOTICE] Sound Blaster did IRQ\n"); 286 | #endif 287 | if (blaster.useautoinit) { 288 | blaster.blockstep = 0; 289 | } 290 | else { 291 | blaster.usingdma = 0; 292 | } 293 | } 294 | } 295 | 296 | int16_t getBlasterSample() { 297 | if (blaster.speakerstate == 0) return (0); 298 | else return ( (int16_t) blaster.sample - 128); 299 | } 300 | 301 | void mixerReset() { 302 | memset (blaster.mixer.reg, 0, sizeof (blaster.mixer.reg) ); 303 | blaster.mixer.reg[0x22] = blaster.mixer.reg[0x26] = blaster.mixer.reg[0x04] = (4 << 5) | (4 << 1); 304 | } 305 | 306 | void initBlaster (uint16_t baseport, uint8_t irq) { 307 | //sbout = fopen("sbout.raw", "wb"); 308 | memset (&blaster, 0, sizeof (blaster) ); 309 | blaster.dspmaj = 2; //emulate a Sound Blaster 2.0 310 | blaster.dspmin = 0; 311 | blaster.sbirq = irq; 312 | blaster.sbdma = 1; 313 | mixerReset(); 314 | set_port_write_redirector (baseport, baseport + 0xE, &outBlaster); 315 | set_port_read_redirector (baseport, baseport + 0xE, &inBlaster); 316 | } 317 | -------------------------------------------------------------------------------- /src/fake86/adlib.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* adlib.c: very ugly Adlib OPL2 emulation for Fake86. very much a work in progress. :) */ 21 | 22 | #include "config.h" 23 | // #include 24 | #include 25 | #include 26 | 27 | extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback); 28 | extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback); 29 | 30 | extern int32_t usesamplerate; 31 | 32 | double samprateadjust = 1.0; 33 | uint8_t optable[0x16] = { 0, 0, 0, 1, 1, 1, 255, 255, 0, 0, 0, 1, 1, 1, 255, 255, 0, 0, 0, 1, 1, 1 }; 34 | uint16_t adlibregmem[0xFF], adlibaddr = 0; 35 | 36 | int8_t waveform[4][64] = { 37 | { 1, 8, 13, 20, 26, 31, 37, 41, 47, 49, 54, 58, 58, 62, 63, 63, 64, 63, 62, 61, 58, 55, 52, 47, 45, 38, 34, 27, 23, 17, 10, 4,-2,-8,-15,-21,-26,-34,-36,-42,-48,-51,-54,-59,-60,-62,-64,-65,-65,-63,-64,-61,-59,-56,-53,-48,-46,-39,-36,-28,-24,-17,-11,-6 }, 38 | { 1, 8, 13, 20, 25, 32, 36, 42, 46, 50, 54, 57, 60, 61, 62, 64, 63, 65, 61, 61, 58, 55, 51, 49, 44, 38, 34, 28, 23, 16, 11, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 39 | { 1, 8, 13, 21, 25, 31, 36, 43, 45, 50, 54, 57, 59, 62, 63, 63, 63, 64, 63, 59, 59, 55, 52, 48, 44, 38, 34, 28, 23, 16, 10, 4, 2, 7, 14, 20, 26, 31, 36, 42, 45, 51, 54, 56, 60, 62, 62, 63, 65, 63, 62, 60, 58, 55, 52, 48, 44, 38, 34, 28, 23, 17, 10, 3 }, 40 | { 1, 8, 13, 20, 26, 31, 36, 42, 46, 51, 53, 57, 60, 62, 61, 66, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 13, 21, 25, 32, 36, 41, 47, 50, 54, 56, 60, 62, 61, 67, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } 41 | }; 42 | 43 | int8_t oplwave[4][256] = { 44 | { 45 | 0, 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 40, 40, 42, 43, 44, 46, 46, 48, 49, 50, 51, 51, 53, 46 | 53, 54, 55, 56, 57, 57, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 116, 116, 116, 116, 116, 116, 116, 116, 116, 64, 64, 64, 63, 63, 63, 62, 62, 61, 61, 60, 47 | 59, 59, 58, 57, 57, 56, 55, 54, 53, 53, 51, 51, 50, 49, 48, 46, 46, 44, 43, 42, 40, 40, 38, 37, 36, 34, 33, 31, 30, 29, 27, 26, 24, 23, 22, 20, 18, 17, 15, 14, 48 | 12, 11, 9, 7, 6, 4, 3, 1, 0, -1, -3, -4, -6, -7, -9, -11, -12, -14, -15, -17, -18, -20, -22, -23, -24, -26, -27, -29, -30, -31, -33, -34, -36, -37, -38, -40, -40, -42, -43, -44, 49 | -46, -46, -48, -49, -50, -51, -51, -53, -53, -54, -55, -56, -57, -57, -58, -59, -59, -60, -61, -61, -62, -62, -63, -63, -63, -64, -64, -64, -116, -116, -116, -116, -116, -116, -116, -116, -116, -64, -64, -64, 50 | -63, -63, -63, -62, -62, -61, -61, -60, -59, -59, -58, -57, -57, -56, -55, -54, -53, -53, -51, -51, -50, -49, -48, -46, -46, -44, -43, -42, -40, -40, -38, -37, -36, -34, -33, -31, -30, -29, -27, -26, 51 | -24, -23, -22, -20, -18, -17, -15, -14, -12, -11, -9, -7, -6, -4, -3, -1 52 | }, 53 | 54 | { 55 | 0, 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20, 22, 23, 24, 26, 27, 29,30, 31, 33, 34, 36, 37, 38, 40, 40, 42, 43, 44, 46, 46, 48, 49, 50, 51, 51, 53, 56 | 53, 54, 55, 56, 57, 57, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 116, 116, 116, 116, 116, 116, 116, 116, 116, 64, 64, 64, 63, 63, 63, 62, 62, 61, 61, 60, 57 | 59, 59, 58, 57, 57, 56, 55, 54, 53, 53, 51, 51, 50, 49, 48, 46, 46, 44, 43, 42, 40, 40, 38, 37, 36, 34, 33, 31, 30, 29, 27, 26, 24, 23, 22, 20, 18, 17, 15, 14, 58 | 12, 11, 9, 7, 6, 4, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 61 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 62 | }, 63 | 64 | 65 | { 66 | 0, 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 40, 40, 42, 43, 44, 46, 46, 48, 49, 50, 51, 51, 53, 67 | 53, 54, 55, 56, 57, 57, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 116, 116, 116, 116, 116, 116, 116, 116, 116, 64, 64, 64, 63, 63, 63, 62, 62, 61, 61, 60, 68 | 59, 59, 58, 57, 57, 56, 55, 54, 53, 53, 51, 51, 50, 49, 48, 46, 46, 44, 43, 42, 40, 40, 38, 37, 36, 34, 33, 31, 30, 29, 27, 26, 24, 23, 22, 20, 18, 17, 15, 14, 69 | 12, 11, 9, 7, 6, 4, 3, 1, 0, 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 40, 40, 42, 43, 44, 70 | 46, 46, 48, 49, 50, 51, 51, 53, 53, 54, 55, 56, 57, 57, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 116, 116, 116, 116, 116, 116, 116, 116, 116, 64, 64, 64, 71 | 63, 63, 63, 62, 62, 61, 61, 60, 59, 59, 58, 57, 57, 56, 55, 54, 53, 53, 51, 51, 50, 49, 48, 46, 46, 44, 43, 42, 40, 40, 38, 37, 36, 34, 33, 31, 30, 29, 27, 26, 72 | 24, 23, 22, 20, 18, 17, 15, 14, 12, 11, 9, 7, 6, 4, 3, 1 73 | }, 74 | 75 | 76 | { 77 | 0, 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 40, 40, 42, 43, 44, 46, 46, 48, 49, 50, 51, 51, 53, 78 | 53, 54, 55, 56, 57, 57, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 116, 116, 116, 116, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 79 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 80 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 3, 4, 6, 7, 9, 11, 12, 14, 15, 17, 18, 20, 22, 23, 24, 26, 27, 29, 30, 31, 33, 34, 36, 37, 38, 40, 40, 42, 43, 44, 81 | 46, 46, 48, 49, 50, 51, 51, 53, 53, 54, 55, 56, 57, 57, 58, 59, 59, 60, 61, 61, 62, 62, 63, 63, 63, 64, 64, 64, 116, 116, 116, 116, 0, 0, 0, 0, 0, 0, 0, 0, 82 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 83 | 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 84 | } 85 | 86 | }; 87 | 88 | uint8_t oplstep[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 89 | 90 | struct structadlibop { 91 | uint8_t wave; 92 | } adlibop[9][2]; 93 | 94 | struct structadlibchan { 95 | uint16_t freq; 96 | double convfreq; 97 | uint8_t keyon; 98 | uint16_t octave; 99 | uint8_t wavesel; 100 | } adlibch[9]; 101 | 102 | double attacktable[16] = { 1.0003, 1.00025, 1.0002, 1.00015, 1.0001, 1.00009, 1.00008, 1.00007, 1.00006, 1.00005, 1.00004, 1.00003, 1.00002, 1.00001, 1.000005 }; //1.003, 1.05, 1.01, 1.015, 1.02, 1.025, 1.03, 1.035, 1.04, 1.045, 1.05, 1.055, 1.06, 1.065, 1.07, 1.075 }; 103 | double decaytable[16] = { 0.99999, 0.999985, 0.99998, 0.999975, 0.99997, 0.999965, 0.99996, 0.999955, 0.99995, 0.999945, 0.99994, 0.999935, 0.99994, 0.999925, 0.99992, 0.99991 }; 104 | double adlibenv[9], adlibdecay[9], adlibattack[9]; 105 | uint8_t adlibdidattack[9], adlibpercussion = 0, adlibstatus = 0; 106 | 107 | uint16_t adlibport = 0x388; 108 | 109 | void outadlib (uint16_t portnum, uint8_t value) { 110 | if (portnum==adlibport) { 111 | adlibaddr = value; 112 | return; 113 | } 114 | portnum = adlibaddr; 115 | adlibregmem[portnum] = value; 116 | switch (portnum) { 117 | case 4: //timer control 118 | if (value&0x80) { 119 | adlibstatus = 0; 120 | adlibregmem[4] = 0; 121 | } 122 | break; 123 | case 0xBD: 124 | if (value & 0x10) adlibpercussion = 1; 125 | else adlibpercussion = 0; 126 | break; 127 | } 128 | if ( (portnum >= 0x60) && (portnum <= 0x75) ) { //attack/decay 129 | portnum &= 15; 130 | adlibattack[portnum] = attacktable[15- (value>>4) ]*1.006; 131 | adlibdecay[portnum] = decaytable[value&15]; 132 | } 133 | else if ( (portnum >= 0xA0) && (portnum <= 0xB8) ) { //octave, freq, key on 134 | portnum &= 15; 135 | if (!adlibch[portnum].keyon && ( (adlibregmem[0xB0+portnum]>>5) &1) ) { 136 | adlibdidattack[portnum] = 0; 137 | adlibenv[portnum] = 0.0025; 138 | } 139 | adlibch[portnum].freq = adlibregmem[0xA0+portnum] | ( (adlibregmem[0xB0+portnum]&3) <<8); 140 | adlibch[portnum].convfreq = ( (double) adlibch[portnum].freq * 0.7626459); 141 | adlibch[portnum].keyon = (adlibregmem[0xB0+portnum]>>5) &1; 142 | adlibch[portnum].octave = (adlibregmem[0xB0+portnum]>>2) &7; 143 | } 144 | else if ( (portnum >= 0xE0) && (portnum <= 0xF5) ) { //waveform select 145 | portnum &= 15; 146 | if (portnum<9) adlibch[portnum].wavesel = value&3; 147 | } 148 | } 149 | 150 | uint8_t inadlib (uint16_t portnum) { 151 | if (!adlibregmem[4]) adlibstatus = 0; 152 | else adlibstatus = 0x80; 153 | adlibstatus = adlibstatus + (adlibregmem[4]&1) *0x40 + (adlibregmem[4]&2) *0x10; 154 | return (adlibstatus); 155 | } 156 | 157 | uint16_t adlibfreq (uint8_t chan) { 158 | uint16_t tmpfreq; 159 | if (!adlibch[chan].keyon) return (0); 160 | tmpfreq = (uint16_t) adlibch[chan].convfreq; 161 | switch (adlibch[chan].octave) { 162 | case 0: 163 | tmpfreq = tmpfreq >> 4; 164 | break; 165 | case 1: 166 | tmpfreq = tmpfreq >> 3; 167 | break; 168 | case 2: 169 | tmpfreq = tmpfreq >> 2; 170 | break; 171 | case 3: 172 | tmpfreq = tmpfreq >> 1; 173 | break; 174 | case 5: 175 | tmpfreq = tmpfreq << 1; 176 | break; 177 | case 6: 178 | tmpfreq = tmpfreq << 2; 179 | break; 180 | case 7: 181 | tmpfreq = tmpfreq << 3; 182 | } 183 | 184 | return (tmpfreq); 185 | } 186 | 187 | uint64_t fullstep, adlibstep[9]; 188 | double adlibenv[9], adlibdecay[9], adlibattack[9]; 189 | uint8_t adlibdidattack[9]; 190 | 191 | //extern SDL_AudioSpec wanted; 192 | 193 | int32_t adlibsample (uint8_t curchan) { 194 | int32_t tempsample; 195 | double tempstep; 196 | 197 | if (adlibpercussion && (curchan>=6) && (curchan<=8) ) return (0); 198 | 199 | fullstep = usesamplerate/adlibfreq (curchan); 200 | 201 | tempsample = (int32_t) oplwave[adlibch[curchan].wavesel][ (uint8_t) ( (double) adlibstep[curchan]/ ( (double) fullstep/ (double) 256) ) ]; 202 | tempstep = adlibenv[curchan]; 203 | if (tempstep>1.0) tempstep = 1; 204 | tempsample = (int32_t) ( (double) tempsample * tempstep * 2.0); 205 | 206 | adlibstep[curchan]++; 207 | if (adlibstep[curchan]>fullstep) adlibstep[curchan] = 0; 208 | return (tempsample); 209 | } 210 | 211 | int16_t adlibgensample() { 212 | uint8_t curchan; 213 | int16_t adlibaccum; 214 | adlibaccum = 0; 215 | for (curchan=0; curchan<9; curchan++) { 216 | if (adlibfreq (curchan) !=0) { 217 | adlibaccum += (int16_t) adlibsample (curchan); 218 | } 219 | } 220 | return (adlibaccum); 221 | } 222 | 223 | void tickadlib() { 224 | uint8_t curchan; 225 | for (curchan=0; curchan<9; curchan++) { 226 | if (adlibfreq (curchan) !=0) { 227 | if (adlibdidattack[curchan]) { 228 | adlibenv[curchan] *= adlibdecay[curchan]; 229 | } 230 | else { 231 | adlibenv[curchan] *= adlibattack[curchan]; 232 | if (adlibenv[curchan]>=1.0) adlibdidattack[curchan] = 1; 233 | } 234 | } 235 | } 236 | } 237 | 238 | void initadlib (uint16_t baseport) { 239 | set_port_write_redirector (baseport, baseport + 1, &outadlib); 240 | set_port_read_redirector (baseport, baseport + 1, &inadlib); 241 | } 242 | -------------------------------------------------------------------------------- /src/fake86/input.c: -------------------------------------------------------------------------------- 1 | /* 2 | Fake86: A portable, open-source 8086 PC emulator. 3 | Copyright (C)2010-2013 Mike Chambers 4 | 5 | This program is free software; you can redistribute it and/or 6 | modify it under the terms of the GNU General Public License 7 | as published by the Free Software Foundation; either version 2 8 | of the License, or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, write to the Free Software 17 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 18 | */ 19 | 20 | /* input.c: functions for translation of SDL scancodes to BIOS scancodes, 21 | and handling of SDL events in general. */ 22 | 23 | //#include 24 | #include 25 | #include "sermouse.h" 26 | 27 | #include <3ds.h> 28 | #include 29 | uint8_t keydown[0x100], keyboardwaitack = 0; 30 | extern uint32_t usegrabmode; 31 | 32 | extern void doirq (uint8_t irqnum); 33 | extern uint8_t running, portram[0x10000]; 34 | //extern SDL_Surface *screen; 35 | 36 | uint8_t translatescancode (uint16_t keyval) { 37 | switch (keyval) { 38 | case 0x1B: 39 | return (1); 40 | break; //Esc 41 | case 0x30: 42 | return (0xB); 43 | break; //zero 44 | case 0x31: 45 | case 0x32: 46 | case 0x33: 47 | case 0x34: 48 | case 0x35: 49 | case 0x36: 50 | case 0x37: 51 | case 0x38: 52 | case 0x39: 53 | return (keyval - 0x2F); 54 | break; //other number keys 55 | case 0x2D: 56 | return (0xC); 57 | break; //-_ 58 | case 0x3D: 59 | return (0xD); 60 | break; //=+ 61 | case 0x8: 62 | return (0xE); 63 | break; //backspace 64 | case 0x9: 65 | return (0xF); 66 | break; //tab 67 | case 0x71: 68 | return (0x10); 69 | break; 70 | case 0x77: 71 | return (0x11); 72 | break; 73 | case 0x65: 74 | return (0x12); 75 | break; 76 | case 0x72: 77 | return (0x13); 78 | break; 79 | case 0x74: 80 | return (0x14); 81 | break; 82 | case 0x79: 83 | return (0x15); 84 | break; 85 | case 0x75: 86 | return (0x16); 87 | break; 88 | case 0x69: 89 | return (0x17); 90 | break; 91 | case 0x6F: 92 | return (0x18); 93 | break; 94 | case 0x70: 95 | return (0x19); 96 | break; 97 | case 0x5B: 98 | return (0x1A); 99 | break; 100 | case 0x5D: 101 | return (0x1B); 102 | break; 103 | case 0xD: 104 | case 0x10F: 105 | return (0x1C); 106 | break; //enter 107 | case 0x131: 108 | case 0x132: 109 | return (0x1D); 110 | break; //ctrl 111 | case 0x61: 112 | return (0x1E); 113 | break; 114 | case 0x73: 115 | return (0x1F); 116 | break; 117 | case 0x64: 118 | return (0x20); 119 | break; 120 | case 0x66: 121 | return (0x21); 122 | break; 123 | case 0x67: 124 | return (0x22); 125 | break; 126 | case 0x68: 127 | return (0x23); 128 | break; 129 | case 0x6A: 130 | return (0x24); 131 | break; 132 | case 0x6B: 133 | return (0x25); 134 | break; 135 | case 0x6C: 136 | return (0x26); 137 | break; 138 | case 0x3B: 139 | return (0x27); 140 | break; 141 | case 0x27: 142 | return (0x28); 143 | break; 144 | case 0x60: 145 | return (0x29); 146 | break; 147 | case 0x130: 148 | return (0x2A); 149 | break; //left shift 150 | case 0x5C: 151 | return (0x2B); 152 | break; 153 | case 0x7A: 154 | return (0x2C); 155 | break; 156 | case 0x78: 157 | return (0x2D); 158 | break; 159 | case 0x63: 160 | return (0x2E); 161 | break; 162 | case 0x76: 163 | return (0x2F); 164 | break; 165 | case 0x62: 166 | return (0x30); 167 | break; 168 | case 0x6E: 169 | return (0x31); 170 | break; 171 | case 0x6D: 172 | return (0x32); 173 | break; 174 | case 0x2C: 175 | return (0x33); 176 | break; 177 | case 0x2E: 178 | return (0x34); 179 | break; 180 | case 0x2F: 181 | return (0x35); 182 | break; 183 | case 0x12F: 184 | return (0x36); 185 | break; //right shift 186 | case 0x13C: 187 | return (0x37); 188 | break; //print screen 189 | case 0x133: 190 | case 0x134: 191 | return (0x38); 192 | break; //alt 193 | case 0x20: 194 | return (0x39); 195 | break; //space 196 | case 0x12D: 197 | return (0x3A); 198 | break; //caps lock 199 | case 0x11A: 200 | case 0x11B: 201 | case 0x11C: 202 | case 0x11D: 203 | case 0x11E: 204 | case 0x11F: 205 | case 0x120: 206 | case 0x121: 207 | case 0x122: 208 | case 0x123: 209 | return (keyval - 0x11A + 0x3B); 210 | break; //F1 to F10 211 | case 0x12C: 212 | return (0x45); 213 | break; //num lock 214 | case 0x12E: 215 | return (0x46); 216 | break; //scroll lock 217 | case 0x116: 218 | case 0x107: 219 | return (0x47); 220 | break; //home 221 | case 0x111: 222 | case 0x108: 223 | return (0x48); 224 | break; //up 225 | case 0x118: 226 | case 0x109: 227 | return (0x49); 228 | break; //pgup 229 | case 0x10D: 230 | return (0x4A); 231 | break; //keypad - 232 | case 0x114: 233 | case 0x104: 234 | return (0x4B); 235 | break; //left 236 | case 0x105: 237 | return (0x4C); 238 | break; //center 239 | case 0x113: 240 | case 0x106: 241 | return (0x4D); 242 | break; //right 243 | case 0x10E: 244 | return (0x4E); 245 | break; //keypad + 246 | case 0x117: 247 | case 0x101: 248 | return (0x4F); 249 | break; //end 250 | case 0x112: 251 | case 0x102: 252 | return (0x50); 253 | break; //down 254 | case 0x119: 255 | case 0x103: 256 | return (0x51); 257 | break; //pgdn 258 | case 0x115: 259 | case 0x100: 260 | return (0x52); 261 | break; //ins 262 | case 0x7F: 263 | case 0x10A: 264 | return (0x53); 265 | break; //del 266 | default: 267 | return (0); 268 | } 269 | } 270 | 271 | uint8_t buttons = 0; 272 | extern void sermouseevent (uint8_t buttons, int8_t xrel, int8_t yrel); 273 | extern struct sermouse_s sermouse; 274 | extern void setwindowtitle (uint8_t *extra); 275 | 276 | void mousegrabtoggle() { 277 | /*if (usegrabmode == SDL_GRAB_ON) { 278 | usegrabmode = SDL_GRAB_OFF; 279 | SDL_WM_GrabInput (SDL_GRAB_OFF); 280 | SDL_ShowCursor (SDL_ENABLE); 281 | setwindowtitle (""); 282 | } 283 | else { 284 | usegrabmode = SDL_GRAB_ON; 285 | SDL_WM_GrabInput (SDL_GRAB_ON); 286 | SDL_ShowCursor (SDL_DISABLE); 287 | setwindowtitle (" (press Ctrl + Alt to release mouse)"); 288 | }*/ 289 | } 290 | 291 | extern uint8_t scrmodechange; 292 | extern uint32_t usefullscreen; 293 | void handleinput() { 294 | //SDL_Event event; 295 | int mx = 0, my = 0; 296 | uint8_t tempbuttons; 297 | uint32_t kDown = hidKeysDown(); 298 | /*if(kDown) 299 | { 300 | if(kDown & KEY_START) 301 | portram[0x60] = 0x1C; portram[0x64] |= 2; 302 | 303 | doirq (1); 304 | }*/ 305 | uint32_t kUp = hidKeysDown(); 306 | /*if(kUp) 307 | { 308 | if(kUp & KEY_START) 309 | portram[0x60] = 0x1C | 0x80; portram[0x64] |= 2; 310 | 311 | doirq (1); 312 | }*/ 313 | /*if (SDL_PollEvent (&event) ) { 314 | switch (event.type) { 315 | case SDL_KEYDOWN: 316 | portram[0x60] = translatescancode (event.key.keysym.sym); 317 | portram[0x64] |= 2; 318 | doirq (1); 319 | //printf("%02X\n", translatescancode(event.key.keysym.sym)); 320 | keydown[translatescancode (event.key.keysym.sym) ] = 1; 321 | if (keydown[0x38] && keydown[0x1D] && (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_ON) ) { 322 | keydown[0x1D] = 0; 323 | keydown[0x32] = 0; 324 | mousegrabtoggle(); 325 | break; 326 | } 327 | if (keydown[0x38] && keydown[0x1C]) { 328 | keydown[0x1D] = 0; 329 | keydown[0x38] = 0; 330 | if (usefullscreen) usefullscreen = 0; 331 | else usefullscreen = SDL_FULLSCREEN; 332 | scrmodechange = 1; 333 | break; 334 | } 335 | break; 336 | case SDL_KEYUP: 337 | portram[0x60] = translatescancode (event.key.keysym.sym) | 0x80; 338 | portram[0x64] |= 2; 339 | doirq (1); 340 | keydown[translatescancode (event.key.keysym.sym) ] = 0; 341 | break; 342 | case SDL_MOUSEBUTTONDOWN: 343 | if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF) { 344 | mousegrabtoggle(); 345 | break; 346 | } 347 | tempbuttons = SDL_GetMouseState (NULL, NULL); 348 | if (tempbuttons & 1) buttons = 2; 349 | else buttons = 0; 350 | if (tempbuttons & 4) buttons |= 1; 351 | sermouseevent (buttons, 0, 0); 352 | break; 353 | case SDL_MOUSEBUTTONUP: 354 | if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF) break; 355 | tempbuttons = SDL_GetMouseState (NULL, NULL); 356 | if (tempbuttons & 1) buttons = 2; 357 | else buttons = 0; 358 | if (tempbuttons & 4) buttons |= 1; 359 | sermouseevent (buttons, 0, 0); 360 | break; 361 | case SDL_MOUSEMOTION: 362 | if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF) break; 363 | SDL_GetRelativeMouseState (&mx, &my); 364 | sermouseevent (buttons, (int8_t) mx, (int8_t) my); 365 | SDL_WarpMouse (screen->w / 2, screen->h / 2); 366 | while (1) { 367 | SDL_PollEvent (&event); 368 | SDL_GetRelativeMouseState (&mx, &my); 369 | if ( (mx == 0) && (my == 0) ) break; 370 | } 371 | break; 372 | case SDL_QUIT: 373 | running = 0; 374 | break; 375 | default: 376 | break; 377 | } 378 | }*/ 379 | } 380 | 381 | 382 | u16* touchpadOverlay; 383 | u16* keyboardOverlay; 384 | char lastKey = 0; 385 | int tmode; 386 | u16* tfb; 387 | touchPosition oldtouch, touch; 388 | u64 tick; 389 | 390 | //Touchscreen mode identifiers 391 | #define TMODE_TOUCHPAD 1 392 | #define TMODE_KEYBOARD 2 393 | 394 | //Keyboard is currently laid out on a 14*4 grid of 20px*20px boxes for lazy implementation 395 | char keymap[14 * 6] = { 396 | 0x01, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 0, 397 | 41, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 398 | 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 43, 399 | 0, 30 , 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 28, 28, 400 | 42, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 0, 72, 0, 401 | 0, 0 , 0, 0, 57, 57, 57, 57, 57, 57, 0, 75, 80, 77 402 | }; 403 | 404 | void Touch_Init(){ 405 | tmode = TMODE_TOUCHPAD; //Start in touchpad Mode 406 | tfb = (u16*)gfxGetFramebuffer(GFX_BOTTOM, GFX_LEFT, NULL, NULL); 407 | 408 | //Load overlay files from sdmc for easier testing 409 | FILE *texture = fopen("touchpadOverlay.bin", "rb"); 410 | if(!texture){ 411 | printf("Could not open touchpadOverlay.bin\n"); 412 | goto ERROR; 413 | } 414 | fseek(texture, 0, SEEK_END); 415 | int size = ftell(texture); 416 | fseek(texture, 0, SEEK_SET); 417 | touchpadOverlay = malloc(size); 418 | fread(touchpadOverlay, 1, size, texture); 419 | fclose(texture); 420 | 421 | texture = fopen("keyboardOverlay.bin", "rb"); 422 | if(!texture){ 423 | printf("Could not open keyboardOverlay.bin\n"); 424 | goto ERROR; 425 | } 426 | fseek(texture, 0, SEEK_END); 427 | size = ftell(texture); 428 | fseek(texture, 0, SEEK_SET); 429 | keyboardOverlay = malloc(size); 430 | fread(keyboardOverlay, 1, size, texture); 431 | fclose(texture); 432 | 433 | return; 434 | 435 | ERROR: 436 | printf("Press START to exit\n"); 437 | while(1){ 438 | hidScanInput(); 439 | uint32_t kDown = hidKeysDown(); 440 | if (kDown & KEY_START) 441 | break; 442 | } 443 | gfxExit(); 444 | exit(1); 445 | } 446 | 447 | void Touch_TouchpadUpdate(){ 448 | if(hidKeysDown() & KEY_TOUCH){ 449 | hidTouchRead(&oldtouch); 450 | } 451 | 452 | if(hidKeysHeld() & KEY_TOUCH){ 453 | hidTouchRead(&touch); 454 | //mousex += (touch.px - oldtouch.px)*10; 455 | //mousey += (touch.py - oldtouch.py)*10; 456 | oldtouch = touch; 457 | } 458 | 459 | if(hidKeysUp() & KEY_TOUCH){ 460 | if(touch.py > 195 && touch.py < 240 && touch.px > 270 && touch.px < 320){ 461 | tmode = 2; 462 | Touch_DrawOverlay(); 463 | } 464 | } 465 | } 466 | 467 | int shiftToggle = 0; 468 | 469 | void Touch_KeyboardUpdate(){ 470 | 471 | if(hidKeysUp() & KEY_TOUCH){ 472 | if(touch.py > 195 && touch.py < 240 && touch.px > 270 && touch.px < 320){ 473 | tmode = 1; 474 | Touch_DrawOverlay(); 475 | } 476 | } 477 | 478 | char key = 0; 479 | if(hidKeysHeld() & KEY_TOUCH){ 480 | 481 | hidTouchRead(&touch); 482 | if(touch.py > 5 && touch.py < 138 && touch.px > 5 && touch.px < 315){ 483 | key = keymap[((touch.py - 6) / 22) * 14 + (touch.px - 6)/22]; 484 | } 485 | } 486 | 487 | if(lastKey != key && lastKey != 0){ 488 | portram[0x60] = lastKey | 0x80; portram[0x64] |= 2; 489 | lastKey = 0; 490 | doirq(1); 491 | return; 492 | } 493 | 494 | if(key == 42 && lastKey != key) 495 | { 496 | shiftToggle = !shiftToggle; 497 | if(shiftToggle){ 498 | portram[0x60] = key; portram[0x64] |= 2; 499 | } 500 | 501 | else{ 502 | portram[0x60] = key | 0x80; portram[0x64] |= 2; 503 | } 504 | } 505 | 506 | else if(key !=0 && lastKey != key){ 507 | portram[0x60] = key; portram[0x64] |= 2; 508 | lastKey = key; 509 | doirq(1); 510 | } 511 | } 512 | 513 | void Touch_Update(){ 514 | if(tmode == TMODE_TOUCHPAD) 515 | Touch_TouchpadUpdate(); 516 | else 517 | Touch_KeyboardUpdate(); 518 | } 519 | 520 | void Touch_DrawOverlay(){ 521 | u16* overlay = 0; 522 | if(tmode == TMODE_TOUCHPAD) 523 | overlay = touchpadOverlay; 524 | else 525 | overlay = keyboardOverlay; 526 | 527 | if(!overlay) return; 528 | 529 | int x,y; 530 | 531 | for(x=0; x<320; x++){ 532 | for(y=0; y<240;y++){ 533 | tfb[(x*240 + (239 - y))] = overlay[(y*320 + x)]; 534 | } 535 | } 536 | 537 | if(tmode == TMODE_KEYBOARD && shiftToggle == 1){ 538 | for(x=20; x<24; x++){ 539 | for(y=98; y<102;y++){ 540 | tfb[(x*240 + (239 - y))] = RGB8_to_565(0,255,0); 541 | } 542 | } 543 | } 544 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | GNU GENERAL PUBLIC LICENSE 2 | 3 | Version 2, June 1991 4 | 5 | Copyright (C) 1989, 1991 Free Software Foundation, Inc. 6 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA 7 | 8 | Everyone is permitted to copy and distribute verbatim copies 9 | of this license document, but changing it is not allowed. 10 | Preamble 11 | 12 | The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 13 | 14 | When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. 15 | 16 | To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. 17 | 18 | For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. 19 | 20 | We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. 21 | 22 | Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. 23 | 24 | Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. 25 | 26 | The precise terms and conditions for copying, distribution and modification follow. 27 | 28 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 29 | 30 | 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". 31 | 32 | Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 33 | 34 | 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. 35 | 36 | You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 37 | 38 | 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: 39 | 40 | a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. 41 | b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. 42 | c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) 43 | These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. 44 | 45 | Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. 46 | 47 | In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 48 | 49 | 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: 50 | 51 | a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, 52 | b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, 53 | c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) 54 | The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. 55 | 56 | If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 57 | 58 | 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 59 | 60 | 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 61 | 62 | 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 63 | 64 | 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. 65 | 66 | If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. 67 | 68 | It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. 69 | 70 | This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 71 | 72 | 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 73 | 74 | 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. 75 | 76 | Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 77 | 78 | 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. 79 | 80 | NO WARRANTY 81 | 82 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 83 | 84 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 85 | 86 | END OF TERMS AND CONDITIONS 87 | -------------------------------------------------------------------------------- /win32/fake86.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug (with WinPCap) 6 | Win32 7 | 8 | 9 | Debug 10 | Win32 11 | 12 | 13 | Release (with WinPCap) 14 | Win32 15 | 16 | 17 | Release 18 | Win32 19 | 20 | 21 | 22 | {4C3260EB-396E-4017-AF95-E0FD33E87046} 23 | Win32Proj 24 | fake86 25 | 26 | 27 | 28 | Application 29 | false 30 | true 31 | NotSet 32 | 33 | 34 | Application 35 | false 36 | true 37 | Unicode 38 | 39 | 40 | Application 41 | false 42 | true 43 | Unicode 44 | 45 | 46 | Application 47 | false 48 | true 49 | Unicode 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | false 69 | .\bin\ 70 | .\intermediate\ 71 | 72 | 73 | 74 | 75 | false 76 | .\bin\ 77 | .\intermediate\ 78 | 79 | 80 | 81 | 82 | false 83 | .\bin\ 84 | .\intermediate\ 85 | 86 | 87 | 88 | 89 | false 90 | .\bin\ 91 | .\intermediate\ 92 | 93 | 94 | 95 | 96 | 97 | Level3 98 | 99 | 100 | MaxSpeed 101 | true 102 | true 103 | PATH_DATAFILES="";_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 104 | MultiThreaded 105 | true 106 | Fast 107 | AnySuitable 108 | AssemblyAndSourceCode 109 | $(IntDir) 110 | 111 | 112 | Console 113 | false 114 | true 115 | true 116 | SDL.lib;SDLmain.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 117 | 0.12.9.19 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | copy ..\data\*.* bin\ /Y 129 | 130 | 131 | Copying ROM data files to bin folder... 132 | 133 | 134 | 135 | 136 | Level3 137 | 138 | 139 | Disabled 140 | true 141 | true 142 | PATH_DATAFILES="";_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 143 | MultiThreadedDebug 144 | true 145 | Fast 146 | Disabled 147 | EditAndContinue 148 | false 149 | 150 | 151 | Console 152 | true 153 | true 154 | true 155 | SDL.lib;SDLmain.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | copy ..\data\*.* bin\ /Y 167 | 168 | 169 | Copying ROM data files to bin folder... 170 | 171 | 172 | 173 | 174 | Level3 175 | 176 | 177 | MaxSpeed 178 | true 179 | true 180 | PATH_DATAFILES="";NETWORKING_ENABLED;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 181 | MultiThreaded 182 | true 183 | Fast 184 | AnySuitable 185 | 186 | 187 | Console 188 | false 189 | true 190 | true 191 | SDL.lib;SDLmain.lib;wpcap.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 192 | 0.12.9.19 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | copy ..\data\*.* bin\ /Y 204 | 205 | 206 | Copying ROM data files to bin folder... 207 | 208 | 209 | 210 | 211 | Level3 212 | 213 | 214 | MaxSpeed 215 | true 216 | true 217 | PATH_DATAFILES="";NETWORKING_ENABLED;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) 218 | MultiThreaded 219 | true 220 | Fast 221 | AnySuitable 222 | 223 | 224 | Console 225 | true 226 | true 227 | true 228 | SDL.lib;SDLmain.lib;wpcap.lib;ws2_32.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies) 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | copy ..\data\*.* bin\ /Y 240 | 241 | 242 | Copying ROM data files to bin folder... 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | --------------------------------------------------------------------------------