aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Hunkeler <jhunkeler@gmail.com>2021-02-27 12:08:23 -0500
committerJoseph Hunkeler <jhunkeler@gmail.com>2021-02-27 12:08:23 -0500
commitd49887486c772592c0e8ecc158c1cc3efb3f7709 (patch)
treeea5af335e7cee87f07de50082dd6ff66f3231353
downloadfake86-d49887486c772592c0e8ecc158c1cc3efb3f7709.tar.gz
Initial commit 0.13.9.16
-rwxr-xr-xCHANGELOG76
-rwxr-xr-xINSTALL.haiku19
-rwxr-xr-xINSTALL.linux25
-rwxr-xr-xINSTALL.osx6
-rwxr-xr-xINSTALL.win33
-rwxr-xr-xLICENSE86
-rwxr-xr-xREADME38
-rw-r--r--bin/.empty0
-rwxr-xr-xdata/asciivga.datbin0 -> 32768 bytes
-rwxr-xr-xdata/pcxtbios.binbin0 -> 8192 bytes
-rw-r--r--data/rombasic.binbin0 -> 32768 bytes
-rwxr-xr-xdata/videorom.binbin0 -> 32768 bytes
-rwxr-xr-xmakefile40
-rwxr-xr-xmakefile.haiku41
-rwxr-xr-xmakefile.osxuni40
-rwxr-xr-xmakefile.pcap40
-rwxr-xr-xsrc/fake86/adlib.c240
-rwxr-xr-xsrc/fake86/ata.c123
-rwxr-xr-xsrc/fake86/audio.c152
-rwxr-xr-xsrc/fake86/audio.h36
-rwxr-xr-xsrc/fake86/blaster.c316
-rwxr-xr-xsrc/fake86/blaster.h48
-rwxr-xr-xsrc/fake86/config.h60
-rwxr-xr-xsrc/fake86/console.c133
-rwxr-xr-xsrc/fake86/cpu.c3532
-rwxr-xr-xsrc/fake86/cpu.h110
-rwxr-xr-xsrc/fake86/disk.c182
-rwxr-xr-xsrc/fake86/disk.h31
-rwxr-xr-xsrc/fake86/i8237.c133
-rwxr-xr-xsrc/fake86/i8237.h31
-rwxr-xr-xsrc/fake86/i8253.c94
-rwxr-xr-xsrc/fake86/i8253.h33
-rwxr-xr-xsrc/fake86/i8259.c99
-rwxr-xr-xsrc/fake86/i8259.h31
-rwxr-xr-xsrc/fake86/input.c361
-rwxr-xr-xsrc/fake86/main.c321
-rw-r--r--src/fake86/modregrm.h129
-rwxr-xr-xsrc/fake86/mutex.h29
-rwxr-xr-xsrc/fake86/netcard.c83
-rwxr-xr-xsrc/fake86/packet.c185
-rwxr-xr-xsrc/fake86/parsecl.c228
-rwxr-xr-xsrc/fake86/ports.c119
-rwxr-xr-xsrc/fake86/render.c570
-rwxr-xr-xsrc/fake86/sermouse.c97
-rwxr-xr-xsrc/fake86/sermouse.h26
-rwxr-xr-xsrc/fake86/sndsource.c82
-rwxr-xr-xsrc/fake86/speaker.c47
-rwxr-xr-xsrc/fake86/timing.c136
-rwxr-xr-xsrc/fake86/video.c841
-rw-r--r--src/fake86/win32/menus.c161
-rw-r--r--src/fake86/win32/resource.hbin0 -> 900 bytes
-rwxr-xr-xsrc/imagegen/imagegen.c68
-rw-r--r--win32/bin/.empty0
-rw-r--r--win32/fake86.rcbin0 -> 6746 bytes
-rwxr-xr-xwin32/fake86.sln36
-rw-r--r--win32/fake86.suobin0 -> 21504 bytes
-rwxr-xr-xwin32/fake86.vcxproj290
-rwxr-xr-xwin32/fake86.vcxproj.filters137
-rwxr-xr-xwin32/imagegen.vcxproj141
-rwxr-xr-xwin32/imagegen.vcxproj.filters22
-rw-r--r--win32/intermediate/.empty0
-rw-r--r--win32/resource.hbin0 -> 3344 bytes
62 files changed, 9937 insertions, 0 deletions
diff --git a/CHANGELOG b/CHANGELOG
new file mode 100755
index 0000000..3d1dbd7
--- /dev/null
+++ b/CHANGELOG
@@ -0,0 +1,76 @@
+Fake86 changelog for v0.13.9.13
+
+v0.13.9.16:
+ - Fixed regression that caused Fake86 to not compile on at least some
+ versions of Mac OS X.
+
+ - Increased amount of processing time dedicated to timing and audio
+ sample generation. Helps accuracy and helps prevent audio dropouts
+ on slower systems.
+
+v0.13.9.13:
+ - Major fix: Some games using the Sound Blaster used to go silent and some
+ even would hang after playing the first sample chunk. It was due to them
+ being unable to read the data count register from the DMA controller.
+ This has been fixed. One example game that did this was Return to Zork.
+
+ - Numerous big fixes and improvements.
+
+ - Windows version now has a simple drop-down menu GUI, so on that platform
+ it is no longer required to specify command-line options for the basics
+ such as specifying disk images. These can be loaded from the menus.
+
+
+v0.12.9.19:
+ - Fixed bug from v0.12.9.16 where the call to createscalemap() in the
+ VideoThread() function was placed before the mutex lock, sometimes causing
+ crashes when Fake86 first loads. (due to an uninitialized pointer)
+
+ - Fixed bug in imagegen that made it crash on some Windows systems.
+
+
+v0.12.9.16:
+ - Fixed bug from v0.12.9.12 that caused faulty CPU emulation on big-endian
+ host CPUs, such as the PowerPC.
+
+ - Fixed another bug from v0.12.9.12 that caused colors to be incorrect on
+ big-endian host CPUs.
+
+ - Added "-slowsys" command line option that can be used to fix audio dropout
+ issues on very slow host CPUs by decreasing audio generation quality.
+
+ - Added another stretching function that is used when the SDL window is
+ exactly double of the width and height of the emulated video. Only active
+ when no smoothing method has been specified. This saves the CPU a lot of
+ work since we now only need to calculate the color to draw once for every
+ four pixels, instead of recalculating the same color for every pixel
+ This makes difference between smooth video and jerky, useless video on
+ very old systems such as my 400 MHz PowerPC G3 iMac.
+
+ - Added an obvious speed tweak which I should have had all along by
+ generating a "scale map" lookup table once on every screen mode change.
+ we no longer need to make expensive floating point scale calculations on
+ every pixel in every frame. The speed boost is very noticeable on slower
+ machines such as those with a Pentium 4 or older CPU.
+
+ - No longer distributing IBM's ROM BASIC bundled with Fake86 out of legal
+ concern. Is it very old? Yes. Does IBM care? Likely not, but they still
+ hold the copyright. You can still use ROM BASIC by providing your own ROM
+ dump. It should be 32,768 bytes in size, and must be named "rombasic.bin"
+ without the quotes. After building and installing Fake86, you need to put
+ the ROM dump in "/usr/share/fake86/" unless you explicitly changed the
+ path in the makefile. In the case of running under Windows, the file
+ should be placed in the same directory as the executable.
+
+ - Created and included a new makefile, this one customized to work in
+ Haiku OS. More information about Haiku at their website:
+ http://www.haiku-os.org
+
+
+v0.12.9.12:
+ - Around 80% of this version is a rewrite compared to all older versions of
+ v0.11.7.22 and prior, and I am considering it a "fresh start". Older
+ releases will no longer be officially available, and are to be considered
+ obsolete. This fresh code base has far too many bugfixes, tweaks, design,
+ layout, and speed improvements to even bother putting together a list of
+ changes.
diff --git a/INSTALL.haiku b/INSTALL.haiku
new file mode 100755
index 0000000..3021a8b
--- /dev/null
+++ b/INSTALL.haiku
@@ -0,0 +1,19 @@
+Compilation and installation notes for Fake86 on Haiku OS:
+
+At the time of this writing, Haiku is still in Alpha stage. This means
+that everything I'm telling you here could be inaccurate as soon as
+tomorrow. I don't make any promises of correct functionaly in Haiku,
+and I can only say that this worked for me on Haiku R1 Alpha 3. Your
+mileage may vary.
+
+Required libraries:
+libSDL 1.2
+
+To compile and install Fake86 without ethernet emulation support:
+make -f makefile.haiku
+make -f makefile.haiku install
+
+Usage note:
+Just a reminder, Fake86 needs to be invoked via command line
+and requires some parameters to work. Run "fake86 -h" to get
+a listing of valid arguments.
diff --git a/INSTALL.linux b/INSTALL.linux
new file mode 100755
index 0000000..91b85ab
--- /dev/null
+++ b/INSTALL.linux
@@ -0,0 +1,25 @@
+Compilation and installation notes for Fake86 on Linux:
+
+Sorry, but there is no configure script written for Fake86 yet.
+All my Linux-based testing has been done with Debian Squeeze 6.0,
+both 32 and 64 bit versions. It will use gcc.
+
+Required libraries:
+libSDL 1.2
+libpcap (Optional, only needed if using makefile.pcap)
+
+Debian users can install them all with this command:
+apt-get install libsdl1.2debian-all libsdl1.2-dev libpcap0.8 libpcap0.8-dev
+
+To compile and install Fake86 without ethernet emulation support:
+make
+sudo make install
+
+To compile and install Fake86 WITH ethernet emulation support:
+make -f makefile.pcap
+sudo make -f makefile.pcap install
+
+Usage note:
+Just a reminder, Fake86 needs to be invoked via command line
+and requires some parameters to work. Run "fake86 -h" to get
+a listing of valid arguments.
diff --git a/INSTALL.osx b/INSTALL.osx
new file mode 100755
index 0000000..af0aaeb
--- /dev/null
+++ b/INSTALL.osx
@@ -0,0 +1,6 @@
+For info on compiling for OS X, see the file INSTALL.linux as the instructions
+are identical if you are compiling only for your native CPU.
+
+If you would rather build a universal binary for OS X, the same instructions
+should still be followed, except you need to add " -f makefile.osxuni " as an
+option for all make commands.
diff --git a/INSTALL.win b/INSTALL.win
new file mode 100755
index 0000000..33be31c
--- /dev/null
+++ b/INSTALL.win
@@ -0,0 +1,33 @@
+Compilation and installation notes for Fake86 on Windows:
+
+If you do not plan to look at or modify the source code, you can
+just delete this archive and use the pre-compiled Win32 build of
+Fake86 instead!
+
+It is highly recommended that you use Visual Studio 2010 to compile
+Fake86. The solution file is included in the "win32\" folder. You should
+be able to compile with MinGW as well, but I have not tested it myself.
+It will require some minor modifications, and a custom makefile.
+
+Compiler requirements:
+ - You will need libSDL 1.2.15 development library for Visual C++.
+ You can download this from:
+ http://www.libsdl.org/release/SDL-devel-1.2.15-VC.zip
+
+ - To enable ethernet emulation, you will also need to install the
+ WinPCap library and developer's pack. This is available at:
+ http://www.winpcap.org
+
+ - Create a directory named "SDL" in your Visual C++ include path,
+ and then copy the contents of the "SDL-1.2.15\include\" folder
+ from that archive into it.
+
+ - Next, copy the two ".lib" files from the "SDL-1.2.15\lib\x86\"
+ folder in that archive into it. Also copy "SDL.dll" into the
+ folder "fake86-version\win32\bin\" from this source archive.
+
+This should allow you to compile successfully! After a successful
+compile, the final Fake86.exe and Imagegen.exe files will be in
+"fake86-version\win32\bin\". You will also need the files in "data\"
+as well as "SDL.dll" to be in the same folder as "Fake86.exe" for
+it to run properly.
diff --git a/LICENSE b/LICENSE
new file mode 100755
index 0000000..7747b44
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,86 @@
+GNU GENERAL PUBLIC LICENSE
+
+Version 2, June 1991
+
+Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+
+Everyone is permitted to copy and distribute verbatim copies
+of this license document, but changing it is not allowed.
+Preamble
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+The precise terms and conditions for copying, distribution and modification follow.
+
+TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+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".
+
+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.
+
+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.
+
+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.
+
+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:
+
+a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.
+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.
+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.)
+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.
+
+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.
+
+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.
+
+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:
+
+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,
+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,
+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.)
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+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.
+
+This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.
+
+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.
+
+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.
+
+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.
+
+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.
+
+NO WARRANTY
+
+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.
+
+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.
+
+END OF TERMS AND CONDITIONS
diff --git a/README b/README
new file mode 100755
index 0000000..b0cc74b
--- /dev/null
+++ b/README
@@ -0,0 +1,38 @@
+Fake86: A portable, open-source 8086 PC emulator.
+Copyright (C)2010-2013 Mike Chambers
+
+This program is free software; you can redistribute it and/or
+modify it under the terms of the GNU General Public License
+as published by the Free Software Foundation; either version 2
+of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+===============================================================================
+
+The full terms of the GNU General Public License version 2, under which this
+software is release, are contained in the text file LICENSE
+
+===============================================================================
+
+** IMPORTANT **
+Remember that Fake86 requires command line parameters to work. If you are just
+launching it by double-clicking on the .exe in Windows Explorer, it won't work.
+
+To contact the author of Fake86, Mike Chambers:
+Send an e-mail to miker00lz <at> gmail <dot> com
+
+Official Fake86 homepage:
+http://fake86.rubbermallet.org
+
+Instructions for compiling and installing Fake86 are in
+the text files INSTALL.linux and INSTALL.win, please read
+whichever file is suited for your target platform if you
+are compiling from source.
diff --git a/bin/.empty b/bin/.empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/bin/.empty
diff --git a/data/asciivga.dat b/data/asciivga.dat
new file mode 100755
index 0000000..a903092
--- /dev/null
+++ b/data/asciivga.dat
Binary files differ
diff --git a/data/pcxtbios.bin b/data/pcxtbios.bin
new file mode 100755
index 0000000..f862fd7
--- /dev/null
+++ b/data/pcxtbios.bin
Binary files differ
diff --git a/data/rombasic.bin b/data/rombasic.bin
new file mode 100644
index 0000000..897e689
--- /dev/null
+++ b/data/rombasic.bin
Binary files differ
diff --git a/data/videorom.bin b/data/videorom.bin
new file mode 100755
index 0000000..e94f41f
--- /dev/null
+++ b/data/videorom.bin
Binary files differ
diff --git a/makefile b/makefile
new file mode 100755
index 0000000..8e920b6
--- /dev/null
+++ b/makefile
@@ -0,0 +1,40 @@
+SRCFILES=src/fake86/*.c
+BINPATH=/usr/bin
+DATAPATH=/usr/share/fake86
+CFLAGS=-O2 -DPATH_DATAFILES=\"$(DATAPATH)/\"
+INCLUDE=-Isrc/fake86
+LIBS=-lpthread
+SDLFLAGS=`sdl-config --cflags --libs`
+
+all: fake86-src imagegen-src
+
+fake86-src:
+ $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS)
+ chmod a+x bin/fake86
+
+imagegen-src:
+ $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS)
+ chmod a+x bin/imagegen
+
+install:
+ mkdir -p $(BINPATH)
+ mkdir -p $(DATAPATH)
+ chmod a-x data/*
+ cp -p bin/fake86 $(BINPATH)
+ cp -p bin/imagegen $(BINPATH)
+ cp -p data/asciivga.dat $(DATAPATH)
+ cp -p data/pcxtbios.bin $(DATAPATH)
+ cp -p data/videorom.bin $(DATAPATH)
+ cp -p data/rombasic.bin $(DATAPATH)
+
+clean:
+ rm -f src/fake86/*.o
+ rm -f src/fake86/*~
+ rm -f src/imagegen/*.o
+ rm -f src/imagegen/*~
+ rm -f bin/fake86
+ rm -f bin/imagegen
+
+uninstall:
+ rm -f $(BINPATH)/fake86
+ rm -f $(BINPATH)/imagegen
diff --git a/makefile.haiku b/makefile.haiku
new file mode 100755
index 0000000..8db1873
--- /dev/null
+++ b/makefile.haiku
@@ -0,0 +1,41 @@
+SRCFILES=src/fake86/*.c
+BINPATH=/boot/system/bin
+DATAPATH=/boot/common/data/fake86
+CFLAGS=-O2 -DPATH_DATAFILES=\"$(DATAPATH)/\"
+INCLUDE=-Isrc/fake86
+LIBS=
+SDLFLAGS=`sdl-config --cflags --libs`
+
+all: fake86-src imagegen-src
+
+fake86-src:
+ $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS)
+ chmod a+x bin/fake86
+
+imagegen-src:
+ $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS)
+ chmod a+x bin/imagegen
+
+install:
+ mkdir -p $(BINPATH)
+ mkdir -p $(DATAPATH)
+ cp bin/fake86 $(BINPATH)
+ cp bin/imagegen $(BINPATH)
+ cp data/asciivga.dat $(DATAPATH)
+ cp data/pcxtbios.bin $(DATAPATH)
+ cp data/videorom.bin $(DATAPATH)
+ cp -p data/rombasic.bin $(DATAPATH)
+ chmod a+x $(BINPATH)/fake86
+ chmod a+x $(BINPATH)/imagegen
+
+clean:
+ rm -f src/fake86/*.o
+ rm -f src/fake86/*~
+ rm -f src/imagegen/*.o
+ rm -f src/imagegen/*~
+ rm -f bin/fake86
+ rm -f bin/imagegen
+
+uninstall:
+ rm -f $(BINPATH)/fake86
+ rm -f $(BINPATH)/imagegen
diff --git a/makefile.osxuni b/makefile.osxuni
new file mode 100755
index 0000000..9612851
--- /dev/null
+++ b/makefile.osxuni
@@ -0,0 +1,40 @@
+SRCFILES=src/fake86/*.c
+BINPATH=/usr/bin
+DATAPATH=/usr/share/fake86
+CFLAGS=-force_cpusubtype_ALL -arch i386 -arch ppc -O2 -DPATH_DATAFILES=\"$(DATAPATH)/\"
+INCLUDE=-Isrc/fake86
+LIBS=-lpthread
+SDLFLAGS=`sdl-config --cflags --libs`
+
+all: fake86-src imagegen-src
+
+fake86-src:
+ $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS)
+ chmod a+x bin/fake86
+
+imagegen-src:
+ $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS)
+ chmod a+x bin/imagegen
+
+install:
+ mkdir -p $(BINPATH)
+ mkdir -p $(DATAPATH)
+ chmod a-x data/*
+ cp -p bin/fake86 $(BINPATH)
+ cp -p bin/imagegen $(BINPATH)
+ cp -p data/asciivga.dat $(DATAPATH)
+ cp -p data/pcxtbios.bin $(DATAPATH)
+ cp -p data/videorom.bin $(DATAPATH)
+ cp -p data/rombasic.bin $(DATAPATH)
+
+clean:
+ rm -f src/fake86/*.o
+ rm -f src/fake86/*~
+ rm -f src/imagegen/*.o
+ rm -f src/imagegen/*~
+ rm -f bin/fake86
+ rm -f bin/imagegen
+
+uninstall:
+ rm -f $(BINPATH)/fake86
+ rm -f $(BINPATH)/imagegen
diff --git a/makefile.pcap b/makefile.pcap
new file mode 100755
index 0000000..dbc4f5c
--- /dev/null
+++ b/makefile.pcap
@@ -0,0 +1,40 @@
+SRCFILES=src/fake86/*.c
+BINPATH=/usr/bin
+DATAPATH=/usr/share/fake86
+CFLAGS=-O2 -DPATH_DATAFILES=\"$(DATAPATH)/\" -DNETWORKING_ENABLED
+INCLUDE=-Isrc/fake86
+LIBS=-lpthread -lpcap
+SDLFLAGS=`sdl-config --cflags --libs`
+
+all: fake86-src imagegen-src
+
+fake86-src:
+ $(CC) $(SRCFILES) -o bin/fake86 $(CFLAGS) $(INCLUDE) $(LIBS) $(SDLFLAGS)
+ chmod a+x bin/fake86
+
+imagegen-src:
+ $(CC) src/imagegen/imagegen.c -o bin/imagegen $(CFLAGS)
+ chmod a+x bin/imagegen
+
+install:
+ mkdir -p $(BINPATH)
+ mkdir -p $(DATAPATH)
+ chmod a-x data/*
+ cp -p bin/fake86 $(BINPATH)
+ cp -p bin/imagegen $(BINPATH)
+ cp -p data/asciivga.dat $(DATAPATH)
+ cp -p data/pcxtbios.bin $(DATAPATH)
+ cp -p data/videorom.bin $(DATAPATH)
+ cp -p data/rombasic.bin $(DATAPATH)
+
+clean:
+ rm -f src/fake86/*.o
+ rm -f src/fake86/*~
+ rm -f src/imagegen/*.o
+ rm -f src/imagegen/*~
+ rm -f bin/fake86
+ rm -f bin/imagegen
+
+uninstall:
+ rm -f $(BINPATH)/fake86
+ rm -f $(BINPATH)/imagegen
diff --git a/src/fake86/adlib.c b/src/fake86/adlib.c
new file mode 100755
index 0000000..cf17584
--- /dev/null
+++ b/src/fake86/adlib.c
@@ -0,0 +1,240 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* adlib.c: very ugly Adlib OPL2 emulation for Fake86. very much a work in progress. :) */
+
+#include "config.h"
+#include <SDL/SDL.h>
+#include <stdint.h>
+#include <stdio.h>
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+
+extern int32_t usesamplerate;
+
+double samprateadjust = 1.0;
+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 };
+uint16_t adlibregmem[0xFF], adlibaddr = 0;
+
+int8_t waveform[4][64] = {
+ { 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 },
+ { 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 },
+ { 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 },
+ { 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 }
+};
+
+int8_t oplwave[4][256] = {
+ {
+ 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,
+ 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,
+ 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,
+ 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,
+ -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,
+ -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,
+ -24, -23, -22, -20, -18, -17, -15, -14, -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, 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, 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, 24, 23, 22, 20, 18, 17, 15, 14,
+ 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,
+ 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,
+ 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 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, 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, 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, 24, 23, 22, 20, 18, 17, 15, 14,
+ 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,
+ 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,
+ 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,
+ 24, 23, 22, 20, 18, 17, 15, 14, 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, 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, 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, 0, 0, 0, 0, 0, 0, 0, 0,
+ 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,
+ 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,
+ 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,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ }
+
+};
+
+uint8_t oplstep[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+
+struct structadlibop {
+ uint8_t wave;
+} adlibop[9][2];
+
+struct structadlibchan {
+ uint16_t freq;
+ double convfreq;
+ uint8_t keyon;
+ uint16_t octave;
+ uint8_t wavesel;
+} adlibch[9];
+
+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 };
+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 };
+double adlibenv[9], adlibdecay[9], adlibattack[9];
+uint8_t adlibdidattack[9], adlibpercussion = 0, adlibstatus = 0;
+
+uint16_t adlibport = 0x388;
+
+void outadlib (uint16_t portnum, uint8_t value) {
+ if (portnum==adlibport) {
+ adlibaddr = value;
+ return;
+ }
+ portnum = adlibaddr;
+ adlibregmem[portnum] = value;
+ switch (portnum) {
+ case 4: //timer control
+ if (value&0x80) {
+ adlibstatus = 0;
+ adlibregmem[4] = 0;
+ }
+ break;
+ case 0xBD:
+ if (value & 0x10) adlibpercussion = 1;
+ else adlibpercussion = 0;
+ break;
+ }
+ if ( (portnum >= 0x60) && (portnum <= 0x75) ) { //attack/decay
+ portnum &= 15;
+ adlibattack[portnum] = attacktable[15- (value>>4) ]*1.006;
+ adlibdecay[portnum] = decaytable[value&15];
+ }
+ else if ( (portnum >= 0xA0) && (portnum <= 0xB8) ) { //octave, freq, key on
+ portnum &= 15;
+ if (!adlibch[portnum].keyon && ( (adlibregmem[0xB0+portnum]>>5) &1) ) {
+ adlibdidattack[portnum] = 0;
+ adlibenv[portnum] = 0.0025;
+ }
+ adlibch[portnum].freq = adlibregmem[0xA0+portnum] | ( (adlibregmem[0xB0+portnum]&3) <<8);
+ adlibch[portnum].convfreq = ( (double) adlibch[portnum].freq * 0.7626459);
+ adlibch[portnum].keyon = (adlibregmem[0xB0+portnum]>>5) &1;
+ adlibch[portnum].octave = (adlibregmem[0xB0+portnum]>>2) &7;
+ }
+ else if ( (portnum >= 0xE0) && (portnum <= 0xF5) ) { //waveform select
+ portnum &= 15;
+ if (portnum<9) adlibch[portnum].wavesel = value&3;
+ }
+}
+
+uint8_t inadlib (uint16_t portnum) {
+ if (!adlibregmem[4]) adlibstatus = 0;
+ else adlibstatus = 0x80;
+ adlibstatus = adlibstatus + (adlibregmem[4]&1) *0x40 + (adlibregmem[4]&2) *0x10;
+ return (adlibstatus);
+}
+
+uint16_t adlibfreq (uint8_t chan) {
+ uint16_t tmpfreq;
+ if (!adlibch[chan].keyon) return (0);
+ tmpfreq = (uint16_t) adlibch[chan].convfreq;
+ switch (adlibch[chan].octave) {
+ case 0:
+ tmpfreq = tmpfreq >> 4;
+ break;
+ case 1:
+ tmpfreq = tmpfreq >> 3;
+ break;
+ case 2:
+ tmpfreq = tmpfreq >> 2;
+ break;
+ case 3:
+ tmpfreq = tmpfreq >> 1;
+ break;
+ case 5:
+ tmpfreq = tmpfreq << 1;
+ break;
+ case 6:
+ tmpfreq = tmpfreq << 2;
+ break;
+ case 7:
+ tmpfreq = tmpfreq << 3;
+ }
+
+ return (tmpfreq);
+}
+
+uint64_t fullstep, adlibstep[9];
+double adlibenv[9], adlibdecay[9], adlibattack[9];
+uint8_t adlibdidattack[9];
+
+extern SDL_AudioSpec wanted;
+int32_t adlibsample (uint8_t curchan) {
+ int32_t tempsample;
+ double tempstep;
+
+ if (adlibpercussion && (curchan>=6) && (curchan<=8) ) return (0);
+
+ fullstep = usesamplerate/adlibfreq (curchan);
+
+ tempsample = (int32_t) oplwave[adlibch[curchan].wavesel][ (uint8_t) ( (double) adlibstep[curchan]/ ( (double) fullstep/ (double) 256) ) ];
+ tempstep = adlibenv[curchan];
+ if (tempstep>1.0) tempstep = 1;
+ tempsample = (int32_t) ( (double) tempsample * tempstep * 2.0);
+
+ adlibstep[curchan]++;
+ if (adlibstep[curchan]>fullstep) adlibstep[curchan] = 0;
+ return (tempsample);
+}
+
+int16_t adlibgensample() {
+ uint8_t curchan;
+ int16_t adlibaccum;
+ adlibaccum = 0;
+ for (curchan=0; curchan<9; curchan++) {
+ if (adlibfreq (curchan) !=0) {
+ adlibaccum += (int16_t) adlibsample (curchan);
+ }
+ }
+ return (adlibaccum);
+}
+
+void tickadlib() {
+ uint8_t curchan;
+ for (curchan=0; curchan<9; curchan++) {
+ if (adlibfreq (curchan) !=0) {
+ if (adlibdidattack[curchan]) {
+ adlibenv[curchan] *= adlibdecay[curchan];
+ }
+ else {
+ adlibenv[curchan] *= adlibattack[curchan];
+ if (adlibenv[curchan]>=1.0) adlibdidattack[curchan] = 1;
+ }
+ }
+ }
+}
+
+void initadlib (uint16_t baseport) {
+ set_port_write_redirector (baseport, baseport + 1, &outadlib);
+ set_port_read_redirector (baseport, baseport + 1, &inadlib);
+}
diff --git a/src/fake86/ata.c b/src/fake86/ata.c
new file mode 100755
index 0000000..df3b50a
--- /dev/null
+++ b/src/fake86/ata.c
@@ -0,0 +1,123 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include "config.h"
+#ifdef DISK_CONTROLLER_ATA
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+#include <string.h>
+
+uint8_t idATA[512];
+
+#define ATA_STATUS_ERROR 0x01
+#define ATA_STATUS_DRQ 0x08
+#define ATA_STATUS_SRV 0x10
+#define ATA_STATUS_FAULT 0x20
+#define ATA_STATUS_READY 0x40
+#define ATA_STATUS_BUSY 0x80
+
+#define flip16(x) ((x&255) | (x>>8))
+#define flip32(x) ((x>>24) | (((x>>16)&255)<<8) | (((x>>8)&255)<<16) | ((x&255)<<24))
+
+uint8_t statusreg = 0, errorreg = 0, drivesel = 0, databuf[512];
+uint16_t dataptr = 512;
+
+void bufclear() {
+ memset (databuf, 0, 512);
+}
+
+void bufcook() {
+ uint16_t i;
+ uint8_t cc;
+ for (i=0; i<512; i+=2) {
+ cc = databuf[i];
+ databuf[i] = databuf[i+1];
+ databuf[i+1] = cc;
+ }
+}
+
+void bufwrite8 (uint16_t bufpos, uint8_t value) {
+ databuf[bufpos] = value;
+}
+
+void bufwrite16 (uint16_t bufpos, uint16_t value) {
+ databuf[bufpos] = (uint8_t) value;
+ databuf[bufpos+1] = (uint8_t) (value>>8);
+}
+
+void flipstring (uint8_t *dest, uint8_t *src) {
+ uint16_t i;
+ uint8_t cc;
+ strcpy (dest, src);
+ for (i=0; i<strlen (dest); i+=2) {
+ cc = databuf[i];
+ databuf[i] = databuf[i+1];
+ databuf[i+1] = cc;
+ }
+}
+
+void cmdATA (uint8_t value) {
+ switch (value) {
+ case 0x91: //INITIALIZE DEVICE PARAMETERS
+ dataptr = 512;
+ break;
+ case 0xEC: //IDENTIFY
+ memset (&idATA, 0, sizeof (idATA) );
+ memcpy (databuf, &idATA, 512);
+ dataptr = 0;
+ break;
+ }
+}
+
+void outATA (uint16_t portnum, uint8_t value) {
+ //printf("[DEBUG] ATA port %Xh write: %02X\n", portnum, value);
+ //getch();
+ switch (portnum) {
+ case 0x1F6:
+ drivesel = (value >> 4) & 1;
+ break;
+ case 0x1F7: //command register
+ cmdATA (value);
+ break;
+ }
+}
+
+uint8_t inATA (uint16_t portnum) {
+ //if (portnum != 0x1F0) printf("[DEBUG] ATA port %Xh read\n", portnum);
+ //getch();
+ switch (portnum) {
+ case 0x1F0: //data read
+ if (dataptr < 512) {
+ //printf("%c", databuf[dataptr]);
+ return (databuf[dataptr++]);
+ }
+ else return (0);
+ case 0x1F1: //error register
+ if (drivesel == 1) return (1);
+ else return (0);
+ case 0x1F7: //status register
+ statusreg = ATA_STATUS_READY;
+ if (drivesel == 1) statusreg |= ATA_STATUS_ERROR;
+ if (dataptr < 512) statusreg |= ATA_STATUS_DRQ;
+ return (statusreg);
+ }
+ return (0);
+}
+#endif
diff --git a/src/fake86/audio.c b/src/fake86/audio.c
new file mode 100755
index 0000000..fb8c76b
--- /dev/null
+++ b/src/fake86/audio.c
@@ -0,0 +1,152 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* audio.c: functions to mix the audio channels, and handle SDL's audio interface. */
+
+#include "config.h"
+#include <SDL/SDL.h>
+#ifdef _WIN32
+#include <Windows.h>
+#include <process.h>
+#else
+#include <pthread.h>
+#endif
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+#include "blaster.h"
+#include "audio.h"
+
+extern SDL_Surface *screen;
+struct wav_hdr_s wav_hdr;
+FILE *wav_file = NULL;
+
+SDL_AudioSpec wanted;
+int8_t audbuf[96000];
+int32_t audbufptr, usebuffersize, usesamplerate = AUDIO_DEFAULT_SAMPLE_RATE, latency = AUDIO_DEFAULT_LATENCY;
+uint8_t speakerenabled = 0;
+
+extern uint64_t gensamplerate, sampleticks, hostfreq;
+extern int16_t adlibgensample();
+extern int16_t speakergensample();
+extern int16_t getssourcebyte();
+extern int16_t getBlasterSample();
+extern uint8_t usessource;
+
+void create_output_wav (uint8_t *filename) {
+ printf ("Creating %s for audio logging... ", filename);
+ wav_file = fopen (filename, "wb");
+ if (wav_file == NULL) {
+ printf ("failed!\n");
+ return;
+ }
+ printf ("OK!\n");
+
+ wav_hdr.AudioFormat = 1; //PCM
+ wav_hdr.bitsPerSample = 8;
+ wav_hdr.blockAlign = 1;
+ wav_hdr.ChunkSize = sizeof (wav_hdr) - 4;
+ sprintf (&wav_hdr.WAVE[0], "WAVE");
+ sprintf (&wav_hdr.fmt[0], "fmt ");
+ wav_hdr.NumOfChan = 1;
+ wav_hdr.bytesPerSec = usesamplerate * (uint32_t) (wav_hdr.bitsPerSample >> 3) * (uint32_t) wav_hdr.NumOfChan;
+ sprintf (&wav_hdr.RIFF[0], "RIFF");
+ wav_hdr.Subchunk1Size = 16;
+ wav_hdr.SamplesPerSec = usesamplerate;
+ sprintf (&wav_hdr.Subchunk2ID[0], "data");
+ wav_hdr.Subchunk2Size = 0;
+ //fwrite((void *)&wav_hdr, 1, sizeof(wav_hdr), wav_file);
+}
+
+uint64_t doublesamplecount, cursampnum = 0, sampcount = 0, framecount = 0;
+uint8_t bmpfilename[256];
+
+void savepic() {
+ SDL_SaveBMP (screen, &bmpfilename[0]);
+}
+
+int8_t samps[2400];
+
+uint8_t audiobufferfilled() {
+ if (audbufptr >= usebuffersize) return(1);
+ return(0);
+}
+
+void tickaudio() {
+ int16_t sample;
+ if (audbufptr >= usebuffersize) return;
+ sample = adlibgensample() >> 4;
+ if (usessource) sample += getssourcebyte();
+ sample += getBlasterSample();
+ if (speakerenabled) sample += (speakergensample() >> 1);
+ if (audbufptr < sizeof(audbuf) ) audbuf[audbufptr++] = (uint8_t) ((uint16_t) sample+128);
+}
+
+extern uint64_t timinginterval;
+extern void inittiming();
+void fill_audio (void *udata, int8_t *stream, int len) {
+ memcpy (stream, audbuf, len);
+ memmove (audbuf, &audbuf[len], usebuffersize - len);
+
+ audbufptr -= len;
+ if (audbufptr < 0) audbufptr = 0;
+}
+
+void initaudio() {
+ printf ("Initializing audio stream... ");
+
+ if (usesamplerate < 4000) usesamplerate = 4000;
+ else if (usesamplerate > 96000) usesamplerate = 96000;
+ if (latency < 10) latency = 10;
+ else if (latency > 1000) latency = 1000;
+ audbufptr = usebuffersize = (usesamplerate / 1000) * latency;
+ gensamplerate = usesamplerate;
+ doublesamplecount = (uint32_t) ( (double) usesamplerate * (double) 0.01);
+
+ wanted.freq = usesamplerate;
+ wanted.format = AUDIO_U8;
+ wanted.channels = 1;
+ wanted.samples = (uint16_t) usebuffersize >> 1;
+ wanted.callback = (void *) fill_audio;
+ wanted.userdata = NULL;
+
+ if (SDL_OpenAudio (&wanted, NULL) <0) {
+ printf ("Error: %s\n", SDL_GetError() );
+ return;
+ }
+ else {
+ printf ("OK! (%lu Hz, %lu ms, %lu sample latency)\n", usesamplerate, latency, usebuffersize);
+ }
+
+ memset (audbuf, 128, sizeof (audbuf) );
+ audbufptr = usebuffersize;
+ //create_output_wav("fake86.wav");
+ SDL_PauseAudio (0);
+ return;
+}
+
+void killaudio() {
+ SDL_PauseAudio (1);
+
+ if (wav_file == NULL) return;
+ wav_hdr.ChunkSize = wav_hdr.Subchunk2Size + sizeof(wav_hdr) - 8;
+ fseek(wav_file, 0, SEEK_SET);
+ fwrite((void *)&wav_hdr, 1, sizeof(wav_hdr), wav_file);
+ fclose (wav_file);
+}
diff --git a/src/fake86/audio.h b/src/fake86/audio.h
new file mode 100755
index 0000000..112d00c
--- /dev/null
+++ b/src/fake86/audio.h
@@ -0,0 +1,36 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdint.h>
+
+struct wav_hdr_s {
+ uint8_t RIFF[4]; /* RIFF Header */ //Magic header
+ uint32_t ChunkSize; /* RIFF Chunk Size */
+ uint8_t WAVE[4]; /* WAVE Header */
+ uint8_t fmt[4]; /* FMT header */
+ uint32_t Subchunk1Size; /* Size of the fmt chunk */
+ uint16_t AudioFormat; /* Audio format 1=PCM,6=mulaw,7=alaw, 257=IBM Mu-Law, 258=IBM A-Law, 259=ADPCM */
+ uint16_t NumOfChan; /* Number of channels 1=Mono 2=Sterio */
+ uint32_t SamplesPerSec; /* Sampling Frequency in Hz */
+ uint32_t bytesPerSec; /* bytes per second */
+ uint16_t blockAlign; /* 2=16-bit mono, 4=16-bit stereo */
+ uint16_t bitsPerSample; /* Number of bits per sample */
+ uint8_t Subchunk2ID[4]; /* "data" string */
+ uint32_t Subchunk2Size; /* Sampled data length */
+};
diff --git a/src/fake86/blaster.c b/src/fake86/blaster.c
new file mode 100755
index 0000000..33c95c6
--- /dev/null
+++ b/src/fake86/blaster.c
@@ -0,0 +1,316 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* blaster.c: functions to emulate a Creative Labs Sound Blaster Pro. */
+
+#include "config.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "blaster.h"
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void doirq (uint8_t irqnum);
+extern uint8_t read8237 (uint8_t channel);
+
+extern void outadlib (uint16_t portnum, uint8_t value); //on the Sound Blaster Pro, ports (base+0) and (base+1) are for
+extern uint8_t inadlib (uint16_t portnum); //the OPL FM music chips, and are also mirrored at (base+8) (base+9)
+//as well as 0x388 and 0x389 to remain compatible with the older adlib cards
+
+struct blaster_s blaster;
+
+void bufNewData (uint8_t value) {
+ if (blaster.memptr >= sizeof (blaster.mem) ) return;
+ blaster.mem[blaster.memptr] = value;
+ blaster.memptr++;
+}
+
+extern uint64_t hostfreq;
+void setsampleticks() {
+ if (blaster.samplerate == 0) {
+ blaster.sampleticks = 0;
+ return;
+ }
+ blaster.sampleticks = hostfreq / (uint64_t) blaster.samplerate;
+}
+
+void cmdBlaster (uint8_t value) {
+ uint8_t recognized = 1;
+ if (blaster.waitforarg) {
+ switch (blaster.lastcmdval) {
+ case 0x10: //direct 8-bit sample output
+ blaster.sample = value;
+ break;
+ case 0x14: //8-bit single block DMA output
+ case 0x24:
+ case 0x91:
+ if (blaster.waitforarg == 2) {
+ blaster.blocksize = (blaster.blocksize & 0xFF00) | (uint32_t) value;
+ blaster.waitforarg = 3;
+ return;
+ }
+ else {
+ blaster.blocksize = (blaster.blocksize & 0x00FF) | ( (uint32_t) value << 8);
+#ifdef DEBUG_BLASTER
+ printf ("[NOTICE] Sound Blaster DSP block transfer size set to %u\n", blaster.blocksize);
+#endif
+ blaster.usingdma = 1;
+ blaster.blockstep = 0;
+ blaster.useautoinit = 0;
+ blaster.paused8 = 0;
+ blaster.speakerstate = 1;
+ }
+ break;
+ case 0x40: //set time constant
+ blaster.samplerate = (uint16_t) ( (uint32_t) 1000000 / (uint32_t) (256 - (uint32_t) value) );
+ setsampleticks();
+#ifdef DEBUG_BLASTER
+ printf ("[DEBUG] Sound Blaster time constant received, sample rate = %u\n", blaster.samplerate);
+#endif
+ break;
+ case 0x48: //set DSP block transfer size
+ if (blaster.waitforarg == 2) {
+ blaster.blocksize = (blaster.blocksize & 0xFF00) | (uint32_t) value;
+ blaster.waitforarg = 3;
+ return;
+ }
+ else {
+ blaster.blocksize = (blaster.blocksize & 0x00FF) | ( (uint32_t) value << 8);
+ //if (blaster.blocksize == 0) blaster.blocksize = 65536;
+ blaster.blockstep = 0;
+#ifdef DEBUG_BLASTER
+ printf ("[NOTICE] Sound Blaster DSP block transfer size set to %u\n", blaster.blocksize);
+#endif
+ }
+ break;
+ case 0xE0: //DSP identification for Sound Blaster 2.0 and newer (invert each bit and put in read buffer)
+ bufNewData (~value);
+ break;
+ case 0xE4: //DSP write test, put data value into read buffer
+ bufNewData (value);
+ blaster.lasttestval = value;
+ break;
+ default:
+ recognized = 0;
+ }
+ //blaster.waitforarg--; // = 0;
+ if (recognized) return;
+ }
+
+ switch (value) {
+ case 0x10:
+ case 0x40:
+ case 0xE0:
+ case 0xE4:
+ blaster.waitforarg = 1;
+ break;
+
+ case 0x14: //8-bit single block DMA output
+ case 0x24:
+ case 0x48:
+ case 0x91:
+ blaster.waitforarg = 2;
+ break;
+
+ case 0x1C: //8-bit auto-init DMA output
+ case 0x2C:
+ blaster.usingdma = 1;
+ blaster.blockstep = 0;
+ blaster.useautoinit = 1;
+ blaster.paused8 = 0;
+ blaster.speakerstate = 1;
+ break;
+
+ case 0xD0: //pause 8-bit DMA I/O
+ blaster.paused8 = 1;
+ case 0xD1: //speaker output on
+ blaster.speakerstate = 1;
+ break;
+ case 0xD3: //speaker output off
+ blaster.speakerstate = 0;
+ break;
+ case 0xD4: //continue 8-bit DMA I/O
+ blaster.paused8 = 0;
+ break;
+ case 0xD8: //get speaker status
+ if (blaster.speakerstate) bufNewData (0xFF);
+ else bufNewData (0x00);
+ break;
+ case 0xDA: //exit 8-bit auto-init DMA I/O mode
+ blaster.usingdma = 0;
+ break;
+ case 0xE1: //get DSP version info
+ blaster.memptr = 0;
+ bufNewData (blaster.dspmaj);
+ bufNewData (blaster.dspmin);
+ break;
+ case 0xE8: //DSP read test
+ blaster.memptr = 0;
+ bufNewData (blaster.lasttestval);
+ break;
+ case 0xF2: //force 8-bit IRQ
+ doirq (blaster.sbirq);
+ break;
+ case 0xF8: //undocumented command, clears in-buffer and inserts a null byte
+ blaster.memptr = 0;
+ bufNewData (0);
+ break;
+ default:
+ printf ("[NOTICE] Sound Blaster received unhandled command %02Xh\n", value);
+ break;
+ }
+}
+
+uint8_t mixer[256], mixerindex = 0;
+void outBlaster (uint16_t portnum, uint8_t value) {
+#ifdef DEBUG_BLASTER
+ printf ("[DEBUG] outBlaster: port %Xh, value %02X\n", portnum, value);
+#endif
+ portnum &= 0xF;
+ switch (portnum) {
+ case 0x0:
+ case 0x8:
+ outadlib (0x388, value);
+ break;
+ case 0x1:
+ case 0x9:
+ outadlib (0x389, value);
+ break;
+ case 0x4: //mixer address port
+ mixerindex = value;
+ break;
+ case 0x5: //mixer data
+ mixer[mixerindex] = value;
+ break;
+ case 0x6: //reset port
+ if ( (value == 0x00) && (blaster.lastresetval == 0x01) ) {
+ blaster.speakerstate = 0;
+ blaster.sample = 128;
+ blaster.waitforarg = 0;
+ blaster.memptr = 0;
+ blaster.usingdma = 0;
+ blaster.blocksize = 65535;
+ blaster.blockstep = 0;
+ bufNewData (0xAA);
+ memset (mixer, 0xEE, sizeof (mixer) );
+#ifdef DEBUG_BLASTER
+ printf ("[DEBUG] Sound Blaster received reset!\n");
+#endif
+ }
+ blaster.lastresetval = value;
+ break;
+ case 0xC: //write command/data
+ cmdBlaster (value);
+ if (blaster.waitforarg != 3) blaster.lastcmdval = value;
+ break;
+ }
+}
+
+uint8_t inBlaster (uint16_t portnum) {
+ uint8_t ret = 0;
+#ifdef DEBUG_BLASTER
+ static uint16_t lastread = 0;
+#endif
+#ifdef DEBUG_BLASTER
+ //if (lastread != portnum) printf ("[DEBUG] inBlaster: port %Xh, value ", portnum);
+#endif
+ portnum &= 0xF;
+ switch (portnum) {
+ case 0x0:
+ case 0x8:
+ ret = inadlib (0x388);
+ break;
+ case 0x1:
+ case 0x9:
+ ret = inadlib (0x389);
+ break;
+ case 0x5: //mixer data
+ ret = mixer[mixerindex];
+ break;
+ case 0xA: //read data
+ if (blaster.memptr == 0) {
+ ret = 0;
+ }
+ else {
+ ret = blaster.mem[0];
+ memmove (&blaster.mem[0], &blaster.mem[1], sizeof (blaster.mem) - 1);
+ blaster.memptr--;
+ }
+ break;
+ case 0xE: //read-buffer status
+ if (blaster.memptr > 0) ret = 0x80;
+ else ret = 0x00;
+ break;
+ default:
+ ret = 0x00;
+ }
+#ifdef DEBUG_BLASTER
+ //if (lastread != portnum) printf ("%02X\n", ret);
+ //lastread = portnum;
+#endif
+ return (ret);
+}
+
+//FILE *sbout = NULL;
+void tickBlaster() {
+ if (!blaster.usingdma) return;
+ /*if (blaster.paused8) {
+ blaster.sample = 128;
+ return;
+ }*/
+ //printf("tickBlaster();\n");
+ blaster.sample = read8237 (blaster.sbdma);
+ //if (sbout != NULL) fwrite(&blaster.sample, 1, 1, sbout);
+ blaster.blockstep++;
+ if (blaster.blockstep > blaster.blocksize) {
+ doirq (blaster.sbirq);
+#ifdef DEBUG_BLASTER
+ printf ("[NOTICE] Sound Blaster did IRQ\n");
+#endif
+ if (blaster.useautoinit) {
+ blaster.blockstep = 0;
+ }
+ else {
+ blaster.usingdma = 0;
+ }
+ }
+}
+
+int16_t getBlasterSample() {
+ if (blaster.speakerstate == 0) return (0);
+ else return ( (int16_t) blaster.sample - 128);
+}
+
+void mixerReset() {
+ memset (blaster.mixer.reg, 0, sizeof (blaster.mixer.reg) );
+ blaster.mixer.reg[0x22] = blaster.mixer.reg[0x26] = blaster.mixer.reg[0x04] = (4 << 5) | (4 << 1);
+}
+
+void initBlaster (uint16_t baseport, uint8_t irq) {
+ //sbout = fopen("sbout.raw", "wb");
+ memset (&blaster, 0, sizeof (blaster) );
+ blaster.dspmaj = 2; //emulate a Sound Blaster 2.0
+ blaster.dspmin = 0;
+ blaster.sbirq = irq;
+ blaster.sbdma = 1;
+ mixerReset();
+ set_port_write_redirector (baseport, baseport + 0xE, &outBlaster);
+ set_port_read_redirector (baseport, baseport + 0xE, &inBlaster);
+}
diff --git a/src/fake86/blaster.h b/src/fake86/blaster.h
new file mode 100755
index 0000000..647dc1d
--- /dev/null
+++ b/src/fake86/blaster.h
@@ -0,0 +1,48 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdint.h>
+
+struct blaster_s {
+ uint8_t mem[1024];
+ uint16_t memptr;
+ uint16_t samplerate;
+ uint8_t dspmaj;
+ uint8_t dspmin;
+ uint8_t speakerstate;
+ uint8_t lastresetval;
+ uint8_t lastcmdval;
+ uint8_t lasttestval;
+ uint8_t waitforarg;
+ uint8_t paused8;
+ uint8_t paused16;
+ uint8_t sample;
+ uint8_t sbirq;
+ uint8_t sbdma;
+ uint8_t usingdma;
+ uint8_t maskdma;
+ uint8_t useautoinit;
+ uint32_t blocksize;
+ uint32_t blockstep;
+ uint64_t sampleticks;
+ struct mixer_s {
+ uint8_t index;
+ uint8_t reg[256];
+ } mixer;
+};
diff --git a/src/fake86/config.h b/src/fake86/config.h
new file mode 100755
index 0000000..359c1c0
--- /dev/null
+++ b/src/fake86/config.h
@@ -0,0 +1,60 @@
+#ifndef __CONFIG_H__
+#define __CONFIG_H__
+
+#define BUILD_STRING "Fake86 v0.13.9.16"
+
+//be sure to only define ONE of the CPU_* options at any given time, or
+//you will likely get some unexpected/bad results!
+//#define CPU_8086
+//#define CPU_186
+#define CPU_V20
+//#define CPU_286
+
+#if defined(CPU_8086)
+ #define CPU_CLEAR_ZF_ON_MUL
+ #define CPU_ALLOW_POP_CS
+#else
+ #define CPU_ALLOW_ILLEGAL_OP_EXCEPTION
+ #define CPU_LIMIT_SHIFT_COUNT
+#endif
+
+#if defined(CPU_V20)
+ #define CPU_NO_SALC
+#endif
+
+#if defined(CPU_286) || defined(CPU_386)
+ #define CPU_286_STYLE_PUSH_SP
+#else
+ #define CPU_SET_HIGH_FLAGS
+#endif
+
+#define TIMING_INTERVAL 15
+
+//when USE_PREFETCH_QUEUE is defined, Fake86's CPU emulator uses a 6-byte
+//read-ahead cache for opcode fetches just as a real 8086/8088 does.
+//by default, i just leave this disabled because it wastes a very very
+//small amount of CPU power. however, for the sake of more accurate
+//emulation, it can be enabled by uncommenting the line below and recompiling.
+//#define USE_PREFETCH_QUEUE
+
+//#define CPU_ADDR_MODE_CACHE
+
+//when compiled with network support, fake86 needs libpcap/winpcap.
+//if it is disabled, the ethernet card is still emulated, but no actual
+//communication is possible -- as if the ethernet cable was unplugged.
+#define NETWORKING_OLDCARD //planning to support an NE2000 in the future
+
+//when DISK_CONTROLLER_ATA is defined, fake86 will emulate a true IDE/ATA1 controller
+//card. if it is disabled, emulated disk access is handled by directly intercepting
+//calls to interrupt 13h.
+//*WARNING* - the ATA controller is not currently complete. do not use!
+//#define DISK_CONTROLLER_ATA
+
+#define AUDIO_DEFAULT_SAMPLE_RATE 48000
+#define AUDIO_DEFAULT_LATENCY 100
+
+//#define DEBUG_BLASTER
+//#define DEBUG_DMA
+
+//#define BENCHMARK_BIOS
+#endif
diff --git a/src/fake86/console.c b/src/fake86/console.c
new file mode 100755
index 0000000..03edebb
--- /dev/null
+++ b/src/fake86/console.c
@@ -0,0 +1,133 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* console.c: functions for a simple interactive console on stdio. */
+
+#include "config.h"
+#include <SDL/SDL.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+
+#ifdef _WIN32
+#include <conio.h>
+#define strcmpi _strcmpi
+#else
+#define strcmpi strcasecmp
+#endif
+
+uint8_t inputline[1024];
+uint16_t inputptr = 0;
+extern uint8_t running;
+
+extern uint8_t insertdisk (uint8_t drivenum, char *filename);
+extern void ejectdisk (uint8_t drivenum);
+
+void waitforcmd (uint8_t *dst, uint16_t maxlen) {
+#ifdef _WIN32
+ uint16_t inputptr;
+ uint8_t cc;
+
+ inputptr = 0;
+ maxlen -= 2;
+ inputline[0] = 0;
+ while (running) {
+ if (_kbhit () ) {
+ cc = (uint8_t) _getch ();
+ switch (cc) {
+ case 0:
+ case 9:
+ case 10:
+ break;
+ case 8: //backspace
+ if (inputptr > 0) {
+ printf ("%c %c", 8, 8);
+ inputline[--inputptr] = 0;
+ }
+ break;
+ case 13: //enter
+ printf ("\n");
+ return;
+ default:
+ if (inputptr < maxlen) {
+ inputline[inputptr++] = cc;
+ inputline[inputptr] = 0;
+ printf ("%c",cc);
+ }
+ }
+ }
+ SDL_Delay(10); //don't waste CPU time while in the polling loop
+ }
+#else
+ gets (dst);
+#endif
+}
+
+void consolehelp () {
+ printf ("\nConsole command summary:\n");
+ printf (" The console is not very robust yet. There are only a few commands:\n\n");
+ printf (" change fd0 Mount a new image file on first floppy drive.\n");
+ printf (" Entering a blank line just ejects any current image file.\n");
+ printf (" change fd1 Mount a new image file on first floppy drive.\n");
+ printf (" Entering a blank line just ejects any current image file.\n");
+ printf (" help This help display.\n");
+ printf (" quit Immediately abort emulation and close Fake86.\n");
+}
+
+#ifdef _WIN32
+void runconsole (void *dummy) {
+#else
+void *runconsole (void *dummy) {
+#endif
+ printf ("\nFake86 management console\n");
+ printf ("Type \"help\" for a summary of commands.\n");
+ while (running) {
+ printf ("\n>");
+ waitforcmd (inputline, sizeof(inputline) );
+ if (strcmpi ( (const char *) inputline, "change fd0") == 0) {
+ printf ("Path to new image file: ");
+ waitforcmd (inputline, sizeof(inputline) );
+ if (strlen (inputline) > 0) {
+ insertdisk (0, (char *) inputline);
+ }
+ else {
+ ejectdisk (0);
+ printf ("Floppy image ejected from first drive.\n");
+ }
+ }
+ else if (strcmpi ( (const char *) inputline, "change fd1") == 0) {
+ printf ("Path to new image file: ");
+ waitforcmd (inputline, sizeof(inputline) );
+ if (strlen (inputline) > 0) {
+ insertdisk (1, (char *) inputline);
+ }
+ else {
+ ejectdisk (1);
+ printf ("Floppy image ejected from second drive.\n");
+ }
+ }
+ else if (strcmpi ( (const char *) inputline, "help") == 0) {
+ consolehelp ();
+ }
+ else if (strcmpi ( (const char *) inputline, "quit") == 0) {
+ running = 0;
+ }
+ else printf("Invalid command was entered.\n");
+ }
+}
diff --git a/src/fake86/cpu.c b/src/fake86/cpu.c
new file mode 100755
index 0000000..828b4d7
--- /dev/null
+++ b/src/fake86/cpu.c
@@ -0,0 +1,3532 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* cpu.c: functions to emulate the 8086/V20 CPU in software. the heart of Fake86. */
+
+#include "config.h"
+#ifndef CPU_INSTRUCTION_FLOW_CACHE
+
+#include <stdint.h>
+#include <stdio.h>
+#include "cpu.h"
+#include "i8259.h"
+#include "i8253.h"
+#include "modregrm.h"
+
+extern struct i8253_s i8253;
+
+extern struct structpic i8259;
+uint64_t curtimer, lasttimer, timerfreq;
+
+uint8_t byteregtable[8] = { regal, regcl, regdl, regbl, regah, regch, regdh, regbh };
+
+static const uint8_t parity[0x100] = {
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0,
+ 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1
+};
+
+uint8_t RAM[0x100000], readonly[0x100000];
+uint8_t opcode, segoverride, reptype, bootdrive = 0, hdcount = 0, hltstate = 0;
+uint16_t segregs[4], savecs, saveip, ip, useseg, oldsp;
+uint8_t tempcf, oldcf, cf, pf, af, zf, sf, tf, ifl, df, of, mode, reg, rm;
+uint16_t oper1, oper2, res16, disp16, temp16, dummy, stacksize, frametemp;
+uint8_t oper1b, oper2b, res8, disp8, temp8, nestlev, addrbyte;
+uint32_t temp1, temp2, temp3, temp4, temp5, temp32, tempaddr32, ea;
+int32_t result;
+uint64_t totalexec;
+
+extern uint16_t VGA_SC[0x100], VGA_CRTC[0x100], VGA_ATTR[0x100], VGA_GC[0x100];
+extern uint8_t updatedscreen;
+union _bytewordregs_ regs;
+
+uint8_t portram[0x10000];
+uint8_t running = 0, debugmode, showcsip, verbose, mouseemu, didbootstrap = 0;
+uint8_t ethif;
+
+extern uint8_t vidmode;
+extern uint8_t verbose;
+
+extern void vidinterrupt();
+
+extern uint8_t readVGA (uint32_t addr32);
+
+void intcall86 (uint8_t intnum);
+
+#define makeflagsword() \
+ ( \
+ 2 | (uint16_t) cf | ((uint16_t) pf << 2) | ((uint16_t) af << 4) | ((uint16_t) zf << 6) | ((uint16_t) sf << 7) | \
+ ((uint16_t) tf << 8) | ((uint16_t) ifl << 9) | ((uint16_t) df << 10) | ((uint16_t) of << 11) \
+ )
+
+#define decodeflagsword(x) { \
+ temp16 = x; \
+ cf = temp16 & 1; \
+ pf = (temp16 >> 2) & 1; \
+ af = (temp16 >> 4) & 1; \
+ zf = (temp16 >> 6) & 1; \
+ sf = (temp16 >> 7) & 1; \
+ tf = (temp16 >> 8) & 1; \
+ ifl = (temp16 >> 9) & 1; \
+ df = (temp16 >> 10) & 1; \
+ of = (temp16 >> 11) & 1; \
+ }
+
+extern void writeVGA (uint32_t addr32, uint8_t value);
+extern void portout (uint16_t portnum, uint8_t value);
+extern void portout16 (uint16_t portnum, uint16_t value);
+extern uint8_t portin (uint16_t portnum);
+extern uint16_t portin16 (uint16_t portnum);
+
+void write86 (uint32_t addr32, uint8_t value) {
+ tempaddr32 = addr32 & 0xFFFFF;
+#ifdef CPU_ADDR_MODE_CACHE
+ if (!readonly[tempaddr32]) addrcachevalid[tempaddr32] = 0;
+#endif
+ if (readonly[tempaddr32] || (tempaddr32 >= 0xC0000) ) {
+ return;
+ }
+
+ if ( (tempaddr32 >= 0xA0000) && (tempaddr32 <= 0xBFFFF) ) {
+ if ( (vidmode != 0x13) && (vidmode != 0x12) && (vidmode != 0xD) && (vidmode != 0x10) ) {
+ RAM[tempaddr32] = value;
+ updatedscreen = 1;
+ }
+ else if ( ( (VGA_SC[4] & 6) == 0) && (vidmode != 0xD) && (vidmode != 0x10) && (vidmode != 0x12) ) {
+ RAM[tempaddr32] = value;
+ updatedscreen = 1;
+ }
+ else {
+ writeVGA (tempaddr32 - 0xA0000, value);
+ }
+
+ updatedscreen = 1;
+ }
+ else {
+ RAM[tempaddr32] = value;
+ }
+}
+
+void writew86 (uint32_t addr32, uint16_t value) {
+ write86 (addr32, (uint8_t) value);
+ write86 (addr32 + 1, (uint8_t) (value >> 8) );
+}
+
+uint8_t read86 (uint32_t addr32) {
+ addr32 &= 0xFFFFF;
+ if ( (addr32 >= 0xA0000) && (addr32 <= 0xBFFFF) ) {
+ if ( (vidmode == 0xD) || (vidmode == 0xE) || (vidmode == 0x10) || (vidmode == 0x12) ) return (readVGA (addr32 - 0xA0000) );
+ if ( (vidmode != 0x13) && (vidmode != 0x12) && (vidmode != 0xD) ) return (RAM[addr32]);
+ if ( (VGA_SC[4] & 6) == 0)
+ return (RAM[addr32]);
+ else
+ return (readVGA (addr32 - 0xA0000) );
+ }
+
+ if (!didbootstrap) {
+ RAM[0x410] = 0x41; //ugly hack to make BIOS always believe we have an EGA/VGA card installed
+ RAM[0x475] = hdcount; //the BIOS doesn't have any concept of hard drives, so here's another hack
+ }
+
+ return (RAM[addr32]);
+}
+
+uint16_t readw86 (uint32_t addr32) {
+ return ( (uint16_t) read86 (addr32) | (uint16_t) (read86 (addr32 + 1) << 8) );
+}
+
+void flag_szp8 (uint8_t value) {
+ if (!value) {
+ zf = 1;
+ }
+ else {
+ zf = 0; /* set or clear zero flag */
+ }
+
+ if (value & 0x80) {
+ sf = 1;
+ }
+ else {
+ sf = 0; /* set or clear sign flag */
+ }
+
+ pf = parity[value]; /* retrieve parity state from lookup table */
+}
+
+void flag_szp16 (uint16_t value) {
+ if (!value) {
+ zf = 1;
+ }
+ else {
+ zf = 0; /* set or clear zero flag */
+ }
+
+ if (value & 0x8000) {
+ sf = 1;
+ }
+ else {
+ sf = 0; /* set or clear sign flag */
+ }
+
+ pf = parity[value & 255]; /* retrieve parity state from lookup table */
+}
+
+void flag_log8 (uint8_t value) {
+ flag_szp8 (value);
+ cf = 0;
+ of = 0; /* bitwise logic ops always clear carry and overflow */
+}
+
+void flag_log16 (uint16_t value) {
+ flag_szp16 (value);
+ cf = 0;
+ of = 0; /* bitwise logic ops always clear carry and overflow */
+}
+
+void flag_adc8 (uint8_t v1, uint8_t v2, uint8_t v3) {
+
+ /* v1 = destination operand, v2 = source operand, v3 = carry flag */
+ uint16_t dst;
+
+ dst = (uint16_t) v1 + (uint16_t) v2 + (uint16_t) v3;
+ flag_szp8 ( (uint8_t) dst);
+ if ( ( (dst ^ v1) & (dst ^ v2) & 0x80) == 0x80) {
+ of = 1;
+ }
+ else {
+ of = 0; /* set or clear overflow flag */
+ }
+
+ if (dst & 0xFF00) {
+ cf = 1;
+ }
+ else {
+ cf = 0; /* set or clear carry flag */
+ }
+
+ if ( ( (v1 ^ v2 ^ dst) & 0x10) == 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0; /* set or clear auxilliary flag */
+ }
+}
+
+void flag_adc16 (uint16_t v1, uint16_t v2, uint16_t v3) {
+
+ uint32_t dst;
+
+ dst = (uint32_t) v1 + (uint32_t) v2 + (uint32_t) v3;
+ flag_szp16 ( (uint16_t) dst);
+ if ( ( ( (dst ^ v1) & (dst ^ v2) ) & 0x8000) == 0x8000) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ if (dst & 0xFFFF0000) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ if ( ( (v1 ^ v2 ^ dst) & 0x10) == 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+}
+
+void flag_add8 (uint8_t v1, uint8_t v2) {
+ /* v1 = destination operand, v2 = source operand */
+ uint16_t dst;
+
+ dst = (uint16_t) v1 + (uint16_t) v2;
+ flag_szp8 ( (uint8_t) dst);
+ if (dst & 0xFF00) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ if ( ( (dst ^ v1) & (dst ^ v2) & 0x80) == 0x80) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ if ( ( (v1 ^ v2 ^ dst) & 0x10) == 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+}
+
+void flag_add16 (uint16_t v1, uint16_t v2) {
+ /* v1 = destination operand, v2 = source operand */
+ uint32_t dst;
+
+ dst = (uint32_t) v1 + (uint32_t) v2;
+ flag_szp16 ( (uint16_t) dst);
+ if (dst & 0xFFFF0000) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ if ( ( (dst ^ v1) & (dst ^ v2) & 0x8000) == 0x8000) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ if ( ( (v1 ^ v2 ^ dst) & 0x10) == 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+}
+
+void flag_sbb8 (uint8_t v1, uint8_t v2, uint8_t v3) {
+
+ /* v1 = destination operand, v2 = source operand, v3 = carry flag */
+ uint16_t dst;
+
+ v2 += v3;
+ dst = (uint16_t) v1 - (uint16_t) v2;
+ flag_szp8 ( (uint8_t) dst);
+ if (dst & 0xFF00) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ if ( (dst ^ v1) & (v1 ^ v2) & 0x80) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ if ( (v1 ^ v2 ^ dst) & 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+}
+
+void flag_sbb16 (uint16_t v1, uint16_t v2, uint16_t v3) {
+
+ /* v1 = destination operand, v2 = source operand, v3 = carry flag */
+ uint32_t dst;
+
+ v2 += v3;
+ dst = (uint32_t) v1 - (uint32_t) v2;
+ flag_szp16 ( (uint16_t) dst);
+ if (dst & 0xFFFF0000) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ if ( (dst ^ v1) & (v1 ^ v2) & 0x8000) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ if ( (v1 ^ v2 ^ dst) & 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+}
+
+void flag_sub8 (uint8_t v1, uint8_t v2) {
+
+ /* v1 = destination operand, v2 = source operand */
+ uint16_t dst;
+
+ dst = (uint16_t) v1 - (uint16_t) v2;
+ flag_szp8 ( (uint8_t) dst);
+ if (dst & 0xFF00) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ if ( (dst ^ v1) & (v1 ^ v2) & 0x80) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ if ( (v1 ^ v2 ^ dst) & 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+}
+
+void flag_sub16 (uint16_t v1, uint16_t v2) {
+
+ /* v1 = destination operand, v2 = source operand */
+ uint32_t dst;
+
+ dst = (uint32_t) v1 - (uint32_t) v2;
+ flag_szp16 ( (uint16_t) dst);
+ if (dst & 0xFFFF0000) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ if ( (dst ^ v1) & (v1 ^ v2) & 0x8000) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ if ( (v1 ^ v2 ^ dst) & 0x10) {
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+}
+
+void op_adc8() {
+ res8 = oper1b + oper2b + cf;
+ flag_adc8 (oper1b, oper2b, cf);
+}
+
+void op_adc16() {
+ res16 = oper1 + oper2 + cf;
+ flag_adc16 (oper1, oper2, cf);
+}
+
+void op_add8() {
+ res8 = oper1b + oper2b;
+ flag_add8 (oper1b, oper2b);
+}
+
+void op_add16() {
+ res16 = oper1 + oper2;
+ flag_add16 (oper1, oper2);
+}
+
+void op_and8() {
+ res8 = oper1b & oper2b;
+ flag_log8 (res8);
+}
+
+void op_and16() {
+ res16 = oper1 & oper2;
+ flag_log16 (res16);
+}
+
+void op_or8() {
+ res8 = oper1b | oper2b;
+ flag_log8 (res8);
+}
+
+void op_or16() {
+ res16 = oper1 | oper2;
+ flag_log16 (res16);
+}
+
+void op_xor8() {
+ res8 = oper1b ^ oper2b;
+ flag_log8 (res8);
+}
+
+void op_xor16() {
+ res16 = oper1 ^ oper2;
+ flag_log16 (res16);
+}
+
+void op_sub8() {
+ res8 = oper1b - oper2b;
+ flag_sub8 (oper1b, oper2b);
+}
+
+void op_sub16() {
+ res16 = oper1 - oper2;
+ flag_sub16 (oper1, oper2);
+}
+
+void op_sbb8() {
+ res8 = oper1b - (oper2b + cf);
+ flag_sbb8 (oper1b, oper2b, cf);
+}
+
+void op_sbb16() {
+ res16 = oper1 - (oper2 + cf);
+ flag_sbb16 (oper1, oper2, cf);
+}
+
+void getea (uint8_t rmval) {
+ uint32_t tempea;
+
+ tempea = 0;
+ switch (mode) {
+ case 0:
+ switch (rmval) {
+ case 0:
+ tempea = regs.wordregs[regbx] + regs.wordregs[regsi];
+ break;
+ case 1:
+ tempea = regs.wordregs[regbx] + regs.wordregs[regdi];
+ break;
+ case 2:
+ tempea = regs.wordregs[regbp] + regs.wordregs[regsi];
+ break;
+ case 3:
+ tempea = regs.wordregs[regbp] + regs.wordregs[regdi];
+ break;
+ case 4:
+ tempea = regs.wordregs[regsi];
+ break;
+ case 5:
+ tempea = regs.wordregs[regdi];
+ break;
+ case 6:
+ tempea = disp16;
+ break;
+ case 7:
+ tempea = regs.wordregs[regbx];
+ break;
+ }
+ break;
+
+ case 1:
+ case 2:
+ switch (rmval) {
+ case 0:
+ tempea = regs.wordregs[regbx] + regs.wordregs[regsi] + disp16;
+ break;
+ case 1:
+ tempea = regs.wordregs[regbx] + regs.wordregs[regdi] + disp16;
+ break;
+ case 2:
+ tempea = regs.wordregs[regbp] + regs.wordregs[regsi] + disp16;
+ break;
+ case 3:
+ tempea = regs.wordregs[regbp] + regs.wordregs[regdi] + disp16;
+ break;
+ case 4:
+ tempea = regs.wordregs[regsi] + disp16;
+ break;
+ case 5:
+ tempea = regs.wordregs[regdi] + disp16;
+ break;
+ case 6:
+ tempea = regs.wordregs[regbp] + disp16;
+ break;
+ case 7:
+ tempea = regs.wordregs[regbx] + disp16;
+ break;
+ }
+ break;
+ }
+
+ ea = (tempea & 0xFFFF) + (useseg << 4);
+}
+
+void push (uint16_t pushval) {
+ regs.wordregs[regsp] = regs.wordregs[regsp] - 2;
+ putmem16 (segregs[regss], regs.wordregs[regsp], pushval);
+}
+
+uint16_t pop() {
+
+ uint16_t tempval;
+
+ tempval = getmem16 (segregs[regss], regs.wordregs[regsp]);
+ regs.wordregs[regsp] = regs.wordregs[regsp] + 2;
+ return tempval;
+}
+
+void reset86() {
+ segregs[regcs] = 0xFFFF;
+ ip = 0x0000;
+ hltstate = 0;
+}
+
+uint16_t readrm16 (uint8_t rmval) {
+ if (mode < 3) {
+ getea (rmval);
+ return read86 (ea) | ( (uint16_t) read86 (ea + 1) << 8);
+ }
+ else {
+ return getreg16 (rmval);
+ }
+}
+
+uint8_t readrm8 (uint8_t rmval) {
+ if (mode < 3) {
+ getea (rmval);
+ return read86 (ea);
+ }
+ else {
+ return getreg8 (rmval);
+ }
+}
+
+void writerm16 (uint8_t rmval, uint16_t value) {
+ if (mode < 3) {
+ getea (rmval);
+ write86 (ea, value & 0xFF);
+ write86 (ea + 1, value >> 8);
+ }
+ else {
+ putreg16 (rmval, value);
+ }
+}
+
+void writerm8 (uint8_t rmval, uint8_t value) {
+ if (mode < 3) {
+ getea (rmval);
+ write86 (ea, value);
+ }
+ else {
+ putreg8 (rmval, value);
+ }
+}
+
+uint8_t op_grp2_8 (uint8_t cnt) {
+
+ uint16_t s;
+ uint16_t shift;
+ uint16_t oldcf;
+ uint16_t msb;
+
+ s = oper1b;
+ oldcf = cf;
+#ifdef CPU_LIMIT_SHIFT_COUNT
+ cnt &= 0x1F;
+#endif
+ switch (reg) {
+ case 0: /* ROL r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ if (s & 0x80) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ s = s << 1;
+ s = s | cf;
+ }
+
+ if (cnt == 1) {
+ //of = cf ^ ( (s >> 7) & 1);
+ if ((s & 0x80) && cf) of = 1; else of = 0;
+ } else of = 0;
+ break;
+
+ case 1: /* ROR r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ cf = s & 1;
+ s = (s >> 1) | (cf << 7);
+ }
+
+ if (cnt == 1) {
+ of = (s >> 7) ^ ( (s >> 6) & 1);
+ }
+ break;
+
+ case 2: /* RCL r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ oldcf = cf;
+ if (s & 0x80) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ s = s << 1;
+ s = s | oldcf;
+ }
+
+ if (cnt == 1) {
+ of = cf ^ ( (s >> 7) & 1);
+ }
+ break;
+
+ case 3: /* RCR r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ oldcf = cf;
+ cf = s & 1;
+ s = (s >> 1) | (oldcf << 7);
+ }
+
+ if (cnt == 1) {
+ of = (s >> 7) ^ ( (s >> 6) & 1);
+ }
+ break;
+
+ case 4:
+ case 6: /* SHL r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ if (s & 0x80) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ s = (s << 1) & 0xFF;
+ }
+
+ if ( (cnt == 1) && (cf == (s >> 7) ) ) {
+ of = 0;
+ }
+ else {
+ of = 1;
+ }
+
+ flag_szp8 ( (uint8_t) s);
+ break;
+
+ case 5: /* SHR r/m8 */
+ if ( (cnt == 1) && (s & 0x80) ) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ for (shift = 1; shift <= cnt; shift++) {
+ cf = s & 1;
+ s = s >> 1;
+ }
+
+ flag_szp8 ( (uint8_t) s);
+ break;
+
+ case 7: /* SAR r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ msb = s & 0x80;
+ cf = s & 1;
+ s = (s >> 1) | msb;
+ }
+
+ of = 0;
+ flag_szp8 ( (uint8_t) s);
+ break;
+ }
+
+ return s & 0xFF;
+}
+
+uint16_t op_grp2_16 (uint8_t cnt) {
+
+ uint32_t s;
+ uint32_t shift;
+ uint32_t oldcf;
+ uint32_t msb;
+
+ s = oper1;
+ oldcf = cf;
+#ifdef CPU_LIMIT_SHIFT_COUNT
+ cnt &= 0x1F;
+#endif
+ switch (reg) {
+ case 0: /* ROL r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ if (s & 0x8000) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ s = s << 1;
+ s = s | cf;
+ }
+
+ if (cnt == 1) {
+ of = cf ^ ( (s >> 15) & 1);
+ }
+ break;
+
+ case 1: /* ROR r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ cf = s & 1;
+ s = (s >> 1) | (cf << 15);
+ }
+
+ if (cnt == 1) {
+ of = (s >> 15) ^ ( (s >> 14) & 1);
+ }
+ break;
+
+ case 2: /* RCL r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ oldcf = cf;
+ if (s & 0x8000) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ s = s << 1;
+ s = s | oldcf;
+ }
+
+ if (cnt == 1) {
+ of = cf ^ ( (s >> 15) & 1);
+ }
+ break;
+
+ case 3: /* RCR r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ oldcf = cf;
+ cf = s & 1;
+ s = (s >> 1) | (oldcf << 15);
+ }
+
+ if (cnt == 1) {
+ of = (s >> 15) ^ ( (s >> 14) & 1);
+ }
+ break;
+
+ case 4:
+ case 6: /* SHL r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ if (s & 0x8000) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ s = (s << 1) & 0xFFFF;
+ }
+
+ if ( (cnt == 1) && (cf == (s >> 15) ) ) {
+ of = 0;
+ }
+ else {
+ of = 1;
+ }
+
+ flag_szp16 ( (uint16_t) s);
+ break;
+
+ case 5: /* SHR r/m8 */
+ if ( (cnt == 1) && (s & 0x8000) ) {
+ of = 1;
+ }
+ else {
+ of = 0;
+ }
+
+ for (shift = 1; shift <= cnt; shift++) {
+ cf = s & 1;
+ s = s >> 1;
+ }
+
+ flag_szp16 ( (uint16_t) s);
+ break;
+
+ case 7: /* SAR r/m8 */
+ for (shift = 1; shift <= cnt; shift++) {
+ msb = s & 0x8000;
+ cf = s & 1;
+ s = (s >> 1) | msb;
+ }
+
+ of = 0;
+ flag_szp16 ( (uint16_t) s);
+ break;
+ }
+
+ return (uint16_t) s & 0xFFFF;
+}
+
+void op_div8 (uint16_t valdiv, uint8_t divisor) {
+ if (divisor == 0) {
+ intcall86 (0);
+ return;
+ }
+
+ if ( (valdiv / (uint16_t) divisor) > 0xFF) {
+ intcall86 (0);
+ return;
+ }
+
+ regs.byteregs[regah] = valdiv % (uint16_t) divisor;
+ regs.byteregs[regal] = valdiv / (uint16_t) divisor;
+}
+
+void op_idiv8 (uint16_t valdiv, uint8_t divisor) {
+
+ uint16_t s1;
+ uint16_t s2;
+ uint16_t d1;
+ uint16_t d2;
+ int sign;
+
+ if (divisor == 0) {
+ intcall86 (0);
+ return;
+ }
+
+ s1 = valdiv;
+ s2 = divisor;
+ sign = ( ( (s1 ^ s2) & 0x8000) != 0);
+ s1 = (s1 < 0x8000) ? s1 : ( (~s1 + 1) & 0xffff);
+ s2 = (s2 < 0x8000) ? s2 : ( (~s2 + 1) & 0xffff);
+ d1 = s1 / s2;
+ d2 = s1 % s2;
+ if (d1 & 0xFF00) {
+ intcall86 (0);
+ return;
+ }
+
+ if (sign) {
+ d1 = (~d1 + 1) & 0xff;
+ d2 = (~d2 + 1) & 0xff;
+ }
+
+ regs.byteregs[regah] = (uint8_t) d2;
+ regs.byteregs[regal] = (uint8_t) d1;
+}
+
+void op_grp3_8() {
+ oper1 = signext (oper1b);
+ oper2 = signext (oper2b);
+ switch (reg) {
+ case 0:
+ case 1: /* TEST */
+ flag_log8 (oper1b & getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ break;
+
+ case 2: /* NOT */
+ res8 = ~oper1b;
+ break;
+
+ case 3: /* NEG */
+ res8 = (~oper1b) + 1;
+ flag_sub8 (0, oper1b);
+ if (res8 == 0) {
+ cf = 0;
+ }
+ else {
+ cf = 1;
+ }
+ break;
+
+ case 4: /* MUL */
+ temp1 = (uint32_t) oper1b * (uint32_t) regs.byteregs[regal];
+ regs.wordregs[regax] = temp1 & 0xFFFF;
+ flag_szp8 ( (uint8_t) temp1);
+ if (regs.byteregs[regah]) {
+ cf = 1;
+ of = 1;
+ }
+ else {
+ cf = 0;
+ of = 0;
+ }
+#ifdef CPU_CLEAR_ZF_ON_MUL
+ zf = 0;
+#endif
+ break;
+
+ case 5: /* IMUL */
+ oper1 = signext (oper1b);
+ temp1 = signext (regs.byteregs[regal]);
+ temp2 = oper1;
+ if ( (temp1 & 0x80) == 0x80) {
+ temp1 = temp1 | 0xFFFFFF00;
+ }
+
+ if ( (temp2 & 0x80) == 0x80) {
+ temp2 = temp2 | 0xFFFFFF00;
+ }
+
+ temp3 = (temp1 * temp2) & 0xFFFF;
+ regs.wordregs[regax] = temp3 & 0xFFFF;
+ if (regs.byteregs[regah]) {
+ cf = 1;
+ of = 1;
+ }
+ else {
+ cf = 0;
+ of = 0;
+ }
+#ifdef CPU_CLEAR_ZF_ON_MUL
+ zf = 0;
+#endif
+ break;
+
+ case 6: /* DIV */
+ op_div8 (regs.wordregs[regax], oper1b);
+ break;
+
+ case 7: /* IDIV */
+ op_idiv8 (regs.wordregs[regax], oper1b);
+ break;
+ }
+}
+
+void op_div16 (uint32_t valdiv, uint16_t divisor) {
+ if (divisor == 0) {
+ intcall86 (0);
+ return;
+ }
+
+ if ( (valdiv / (uint32_t) divisor) > 0xFFFF) {
+ intcall86 (0);
+ return;
+ }
+
+ regs.wordregs[regdx] = valdiv % (uint32_t) divisor;
+ regs.wordregs[regax] = valdiv / (uint32_t) divisor;
+}
+
+void op_idiv16 (uint32_t valdiv, uint16_t divisor) {
+
+ uint32_t d1;
+ uint32_t d2;
+ uint32_t s1;
+ uint32_t s2;
+ int sign;
+
+ if (divisor == 0) {
+ intcall86 (0);
+ return;
+ }
+
+ s1 = valdiv;
+ s2 = divisor;
+ s2 = (s2 & 0x8000) ? (s2 | 0xffff0000) : s2;
+ sign = ( ( (s1 ^ s2) & 0x80000000) != 0);
+ s1 = (s1 < 0x80000000) ? s1 : ( (~s1 + 1) & 0xffffffff);
+ s2 = (s2 < 0x80000000) ? s2 : ( (~s2 + 1) & 0xffffffff);
+ d1 = s1 / s2;
+ d2 = s1 % s2;
+ if (d1 & 0xFFFF0000) {
+ intcall86 (0);
+ return;
+ }
+
+ if (sign) {
+ d1 = (~d1 + 1) & 0xffff;
+ d2 = (~d2 + 1) & 0xffff;
+ }
+
+ regs.wordregs[regax] = d1;
+ regs.wordregs[regdx] = d2;
+}
+
+void op_grp3_16() {
+ switch (reg) {
+ case 0:
+ case 1: /* TEST */
+ flag_log16 (oper1 & getmem16 (segregs[regcs], ip) );
+ StepIP (2);
+ break;
+
+ case 2: /* NOT */
+ res16 = ~oper1;
+ break;
+
+ case 3: /* NEG */
+ res16 = (~oper1) + 1;
+ flag_sub16 (0, oper1);
+ if (res16) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+ break;
+
+ case 4: /* MUL */
+ temp1 = (uint32_t) oper1 * (uint32_t) regs.wordregs[regax];
+ regs.wordregs[regax] = temp1 & 0xFFFF;
+ regs.wordregs[regdx] = temp1 >> 16;
+ flag_szp16 ( (uint16_t) temp1);
+ if (regs.wordregs[regdx]) {
+ cf = 1;
+ of = 1;
+ }
+ else {
+ cf = 0;
+ of = 0;
+ }
+#ifdef CPU_CLEAR_ZF_ON_MUL
+ zf = 0;
+#endif
+ break;
+
+ case 5: /* IMUL */
+ temp1 = regs.wordregs[regax];
+ temp2 = oper1;
+ if (temp1 & 0x8000) {
+ temp1 |= 0xFFFF0000;
+ }
+
+ if (temp2 & 0x8000) {
+ temp2 |= 0xFFFF0000;
+ }
+
+ temp3 = temp1 * temp2;
+ regs.wordregs[regax] = temp3 & 0xFFFF; /* into register ax */
+ regs.wordregs[regdx] = temp3 >> 16; /* into register dx */
+ if (regs.wordregs[regdx]) {
+ cf = 1;
+ of = 1;
+ }
+ else {
+ cf = 0;
+ of = 0;
+ }
+#ifdef CPU_CLEAR_ZF_ON_MUL
+ zf = 0;
+#endif
+ break;
+
+ case 6: /* DIV */
+ op_div16 ( ( (uint32_t) regs.wordregs[regdx] << 16) + regs.wordregs[regax], oper1);
+ break;
+
+ case 7: /* DIV */
+ op_idiv16 ( ( (uint32_t) regs.wordregs[regdx] << 16) + regs.wordregs[regax], oper1);
+ break;
+ }
+}
+
+void op_grp5() {
+ switch (reg) {
+ case 0: /* INC Ev */
+ oper2 = 1;
+ tempcf = cf;
+ op_add16();
+ cf = tempcf;
+ writerm16 (rm, res16);
+ break;
+
+ case 1: /* DEC Ev */
+ oper2 = 1;
+ tempcf = cf;
+ op_sub16();
+ cf = tempcf;
+ writerm16 (rm, res16);
+ break;
+
+ case 2: /* CALL Ev */
+ push (ip);
+ ip = oper1;
+ break;
+
+ case 3: /* CALL Mp */
+ push (segregs[regcs]);
+ push (ip);
+ getea (rm);
+ ip = (uint16_t) read86 (ea) + (uint16_t) read86 (ea + 1) * 256;
+ segregs[regcs] = (uint16_t) read86 (ea + 2) + (uint16_t) read86 (ea + 3) * 256;
+ break;
+
+ case 4: /* JMP Ev */
+ ip = oper1;
+ break;
+
+ case 5: /* JMP Mp */
+ getea (rm);
+ ip = (uint16_t) read86 (ea) + (uint16_t) read86 (ea + 1) * 256;
+ segregs[regcs] = (uint16_t) read86 (ea + 2) + (uint16_t) read86 (ea + 3) * 256;
+ break;
+
+ case 6: /* PUSH Ev */
+ push (oper1);
+ break;
+ }
+}
+
+uint8_t dolog = 0, didintr = 0;
+FILE *logout;
+uint8_t printops = 0;
+
+#ifdef NETWORKING_ENABLED
+extern void nethandler();
+#endif
+extern void diskhandler();
+extern void readdisk (uint8_t drivenum, uint16_t dstseg, uint16_t dstoff, uint16_t cyl, uint16_t sect, uint16_t head, uint16_t sectcount);
+
+void intcall86 (uint8_t intnum) {
+ static uint16_t lastint10ax;
+ uint16_t oldregax;
+ didintr = 1;
+
+ if (intnum == 0x19) didbootstrap = 1;
+
+ switch (intnum) {
+ case 0x10:
+ updatedscreen = 1;
+ /*if (regs.byteregs[regah]!=0x0E) {
+ printf("Int 10h AX = %04X\n", regs.wordregs[regax]);
+ }*/
+ if ( (regs.byteregs[regah]==0x00) || (regs.byteregs[regah]==0x10) ) {
+ oldregax = regs.wordregs[regax];
+ vidinterrupt();
+ regs.wordregs[regax] = oldregax;
+ if (regs.byteregs[regah]==0x10) return;
+ if (vidmode==9) return;
+ }
+ if ( (regs.byteregs[regah]==0x1A) && (lastint10ax!=0x0100) ) { //the 0x0100 is a cheap hack to make it not do this if DOS EDIT/QBASIC
+ regs.byteregs[regal] = 0x1A;
+ regs.byteregs[regbl] = 0x8;
+ return;
+ }
+ lastint10ax = regs.wordregs[regax];
+ if (regs.byteregs[regah]==0x1B) {
+ regs.byteregs[regal] = 0x1B;
+ segregs[reges] = 0xC800;
+ regs.wordregs[regdi] = 0x0000;
+ writew86(0xC8000, 0x0000);
+ writew86(0xC8002, 0xC900);
+ write86(0xC9000, 0x00);
+ write86(0xC9001, 0x00);
+ write86(0xC9002, 0x01);
+ return;
+ }
+ break;
+
+#ifndef DISK_CONTROLLER_ATA
+ case 0x19: //bootstrap
+#ifdef BENCHMARK_BIOS
+ running = 0;
+#endif
+ if (bootdrive<255) { //read first sector of boot drive into 07C0:0000 and execute it
+ regs.byteregs[regdl] = bootdrive;
+ readdisk (regs.byteregs[regdl], 0x07C0, 0x0000, 0, 1, 0, 1);
+ segregs[regcs] = 0x0000;
+ ip = 0x7C00;
+ }
+ else {
+ segregs[regcs] = 0xF600; //start ROM BASIC at bootstrap if requested
+ ip = 0x0000;
+ }
+ return;
+
+ case 0x13:
+ case 0xFD:
+ diskhandler();
+ return;
+#endif
+#ifdef NETWORKING_OLDCARD
+ case 0xFC:
+#ifdef NETWORKING_ENABLED
+ nethandler();
+#endif
+ return;
+#endif
+ }
+
+ push (makeflagsword() );
+ push (segregs[regcs]);
+ push (ip);
+ segregs[regcs] = getmem16 (0, (uint16_t) intnum * 4 + 2);
+ ip = getmem16 (0, (uint16_t) intnum * 4);
+ ifl = 0;
+ tf = 0;
+}
+
+#if defined(NETWORKING_ENABLED)
+extern struct netstruct {
+ uint8_t enabled;
+ uint8_t canrecv;
+ uint16_t pktlen;
+} net;
+#endif
+uint64_t frametimer = 0, didwhen = 0, didticks = 0;
+uint32_t makeupticks = 0;
+extern float timercomp;
+uint64_t timerticks = 0, realticks = 0;
+uint64_t lastcountertimer = 0, counterticks = 10000;
+extern uint8_t nextintr();
+extern void timing();
+
+#ifdef USE_PREFETCH_QUEUE
+uint8_t prefetch[6];
+uint32_t prefetch_base = 0;
+#endif
+
+void exec86 (uint32_t execloops) {
+
+ uint32_t loopcount;
+ uint8_t docontinue;
+ static uint16_t firstip;
+ static uint16_t trap_toggle = 0;
+
+ counterticks = (uint64_t) ( (double) timerfreq / (double) 65536.0);
+
+ for (loopcount = 0; loopcount < execloops; loopcount++) {
+
+ if ( (totalexec & TIMING_INTERVAL) == 0) timing();
+
+ if (trap_toggle) {
+ intcall86 (1);
+ }
+
+ if (tf) {
+ trap_toggle = 1;
+ }
+ else {
+ trap_toggle = 0;
+ }
+
+ if (!trap_toggle && (ifl && (i8259.irr & (~i8259.imr) ) ) ) {
+ hltstate = 0;
+ intcall86 (nextintr() ); /* get next interrupt from the i8259, if any */
+ }
+
+ if (hltstate) goto skipexecution;
+
+ /*if ((((uint32_t)segregs[regcs] << 4) + (uint32_t)ip) == 0xFEC59) {
+ //printf("Entered F000:EC59, returning to ");
+ ip = pop();
+ segregs[regcs] = pop();
+ decodeflagsword(pop());
+ //printf("%04X:%04X\n", segregs[regcs], ip);
+ diskhandler();
+ }*/
+
+ reptype = 0;
+ segoverride = 0;
+ useseg = segregs[regds];
+ docontinue = 0;
+ firstip = ip;
+
+ if ( (segregs[regcs] == 0xF000) && (ip == 0xE066) ) didbootstrap = 0; //detect if we hit the BIOS entry point to clear didbootstrap because we've rebooted
+
+ while (!docontinue) {
+ segregs[regcs] = segregs[regcs] & 0xFFFF;
+ ip = ip & 0xFFFF;
+ savecs = segregs[regcs];
+ saveip = ip;
+#ifdef USE_PREFETCH_QUEUE
+ ea = segbase(savecs) + (uint32_t)saveip;
+ if ( (ea < prefetch_base) || (ea > (prefetch_base + 5)) ) {
+ memcpy (&prefetch[0], &RAM[ea], 6);
+ prefetch_base = ea;
+ }
+ opcode = prefetch[ea - prefetch_base];
+#else
+ opcode = getmem8 (segregs[regcs], ip);
+#endif
+ StepIP (1);
+
+ switch (opcode) {
+ /* segment prefix check */
+ case 0x2E: /* segment segregs[regcs] */
+ useseg = segregs[regcs];
+ segoverride = 1;
+ break;
+
+ case 0x3E: /* segment segregs[regds] */
+ useseg = segregs[regds];
+ segoverride = 1;
+ break;
+
+ case 0x26: /* segment segregs[reges] */
+ useseg = segregs[reges];
+ segoverride = 1;
+ break;
+
+ case 0x36: /* segment segregs[regss] */
+ useseg = segregs[regss];
+ segoverride = 1;
+ break;
+
+ /* repetition prefix check */
+ case 0xF3: /* REP/REPE/REPZ */
+ reptype = 1;
+ break;
+
+ case 0xF2: /* REPNE/REPNZ */
+ reptype = 2;
+ break;
+
+ default:
+ docontinue = 1;
+ break;
+ }
+ }
+
+ totalexec++;
+
+ switch (opcode) {
+ case 0x0: /* 00 ADD Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ op_add8();
+ writerm8 (rm, res8);
+ break;
+
+ case 0x1: /* 01 ADD Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ op_add16();
+ writerm16 (rm, res16);
+ break;
+
+ case 0x2: /* 02 ADD Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ op_add8();
+ putreg8 (reg, res8);
+ break;
+
+ case 0x3: /* 03 ADD Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ op_add16();
+ putreg16 (reg, res16);
+ break;
+
+ case 0x4: /* 04 ADD regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ op_add8();
+ regs.byteregs[regal] = res8;
+ break;
+
+ case 0x5: /* 05 ADD eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ op_add16();
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x6: /* 06 PUSH segregs[reges] */
+ push (segregs[reges]);
+ break;
+
+ case 0x7: /* 07 POP segregs[reges] */
+ segregs[reges] = pop();
+ break;
+
+ case 0x8: /* 08 OR Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ op_or8();
+ writerm8 (rm, res8);
+ break;
+
+ case 0x9: /* 09 OR Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ op_or16();
+ writerm16 (rm, res16);
+ break;
+
+ case 0xA: /* 0A OR Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ op_or8();
+ putreg8 (reg, res8);
+ break;
+
+ case 0xB: /* 0B OR Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ op_or16();
+ if ( (oper1 == 0xF802) && (oper2 == 0xF802) ) {
+ sf = 0; /* cheap hack to make Wolf 3D think we're a 286 so it plays */
+ }
+
+ putreg16 (reg, res16);
+ break;
+
+ case 0xC: /* 0C OR regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ op_or8();
+ regs.byteregs[regal] = res8;
+ break;
+
+ case 0xD: /* 0D OR eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ op_or16();
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0xE: /* 0E PUSH segregs[regcs] */
+ push (segregs[regcs]);
+ break;
+
+#ifdef CPU_ALLOW_POP_CS //only the 8086/8088 does this.
+ case 0xF: //0F POP CS
+ segregs[regcs] = pop();
+ break;
+#endif
+
+ case 0x10: /* 10 ADC Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ op_adc8();
+ writerm8 (rm, res8);
+ break;
+
+ case 0x11: /* 11 ADC Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ op_adc16();
+ writerm16 (rm, res16);
+ break;
+
+ case 0x12: /* 12 ADC Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ op_adc8();
+ putreg8 (reg, res8);
+ break;
+
+ case 0x13: /* 13 ADC Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ op_adc16();
+ putreg16 (reg, res16);
+ break;
+
+ case 0x14: /* 14 ADC regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ op_adc8();
+ regs.byteregs[regal] = res8;
+ break;
+
+ case 0x15: /* 15 ADC eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ op_adc16();
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x16: /* 16 PUSH segregs[regss] */
+ push (segregs[regss]);
+ break;
+
+ case 0x17: /* 17 POP segregs[regss] */
+ segregs[regss] = pop();
+ break;
+
+ case 0x18: /* 18 SBB Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ op_sbb8();
+ writerm8 (rm, res8);
+ break;
+
+ case 0x19: /* 19 SBB Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ op_sbb16();
+ writerm16 (rm, res16);
+ break;
+
+ case 0x1A: /* 1A SBB Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ op_sbb8();
+ putreg8 (reg, res8);
+ break;
+
+ case 0x1B: /* 1B SBB Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ op_sbb16();
+ putreg16 (reg, res16);
+ break;
+
+ case 0x1C: /* 1C SBB regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ op_sbb8();
+ regs.byteregs[regal] = res8;
+ break;
+
+ case 0x1D: /* 1D SBB eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ op_sbb16();
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x1E: /* 1E PUSH segregs[regds] */
+ push (segregs[regds]);
+ break;
+
+ case 0x1F: /* 1F POP segregs[regds] */
+ segregs[regds] = pop();
+ break;
+
+ case 0x20: /* 20 AND Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ op_and8();
+ writerm8 (rm, res8);
+ break;
+
+ case 0x21: /* 21 AND Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ op_and16();
+ writerm16 (rm, res16);
+ break;
+
+ case 0x22: /* 22 AND Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ op_and8();
+ putreg8 (reg, res8);
+ break;
+
+ case 0x23: /* 23 AND Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ op_and16();
+ putreg16 (reg, res16);
+ break;
+
+ case 0x24: /* 24 AND regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ op_and8();
+ regs.byteregs[regal] = res8;
+ break;
+
+ case 0x25: /* 25 AND eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ op_and16();
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x27: /* 27 DAA */
+ if ( ( (regs.byteregs[regal] & 0xF) > 9) || (af == 1) ) {
+ oper1 = regs.byteregs[regal] + 6;
+ regs.byteregs[regal] = oper1 & 255;
+ if (oper1 & 0xFF00) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ af = 1;
+ }
+ else {
+ //af = 0;
+ }
+
+ if ( (regs.byteregs[regal] > 0x9F) || (cf == 1) ) {
+ regs.byteregs[regal] = regs.byteregs[regal] + 0x60;
+ cf = 1;
+ }
+ else {
+ //cf = 0;
+ }
+
+ regs.byteregs[regal] = regs.byteregs[regal] & 255;
+ flag_szp8 (regs.byteregs[regal]);
+ break;
+
+ case 0x28: /* 28 SUB Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ op_sub8();
+ writerm8 (rm, res8);
+ break;
+
+ case 0x29: /* 29 SUB Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ op_sub16();
+ writerm16 (rm, res16);
+ break;
+
+ case 0x2A: /* 2A SUB Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ op_sub8();
+ putreg8 (reg, res8);
+ break;
+
+ case 0x2B: /* 2B SUB Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ op_sub16();
+ putreg16 (reg, res16);
+ break;
+
+ case 0x2C: /* 2C SUB regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ op_sub8();
+ regs.byteregs[regal] = res8;
+ break;
+
+ case 0x2D: /* 2D SUB eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ op_sub16();
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x2F: /* 2F DAS */
+ if ( ( (regs.byteregs[regal] & 15) > 9) || (af == 1) ) {
+ oper1 = regs.byteregs[regal] - 6;
+ regs.byteregs[regal] = oper1 & 255;
+ if (oper1 & 0xFF00) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ af = 1;
+ }
+ else {
+ af = 0;
+ }
+
+ if ( ( (regs.byteregs[regal] & 0xF0) > 0x90) || (cf == 1) ) {
+ regs.byteregs[regal] = regs.byteregs[regal] - 0x60;
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+
+ flag_szp8 (regs.byteregs[regal]);
+ break;
+
+ case 0x30: /* 30 XOR Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ op_xor8();
+ writerm8 (rm, res8);
+ break;
+
+ case 0x31: /* 31 XOR Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ op_xor16();
+ writerm16 (rm, res16);
+ break;
+
+ case 0x32: /* 32 XOR Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ op_xor8();
+ putreg8 (reg, res8);
+ break;
+
+ case 0x33: /* 33 XOR Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ op_xor16();
+ putreg16 (reg, res16);
+ break;
+
+ case 0x34: /* 34 XOR regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ op_xor8();
+ regs.byteregs[regal] = res8;
+ break;
+
+ case 0x35: /* 35 XOR eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ op_xor16();
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x37: /* 37 AAA ASCII */
+ if ( ( (regs.byteregs[regal] & 0xF) > 9) || (af == 1) ) {
+ regs.byteregs[regal] = regs.byteregs[regal] + 6;
+ regs.byteregs[regah] = regs.byteregs[regah] + 1;
+ af = 1;
+ cf = 1;
+ }
+ else {
+ af = 0;
+ cf = 0;
+ }
+
+ regs.byteregs[regal] = regs.byteregs[regal] & 0xF;
+ break;
+
+ case 0x38: /* 38 CMP Eb Gb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getreg8 (reg);
+ flag_sub8 (oper1b, oper2b);
+ break;
+
+ case 0x39: /* 39 CMP Ev Gv */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getreg16 (reg);
+ flag_sub16 (oper1, oper2);
+ break;
+
+ case 0x3A: /* 3A CMP Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ flag_sub8 (oper1b, oper2b);
+ break;
+
+ case 0x3B: /* 3B CMP Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ flag_sub16 (oper1, oper2);
+ break;
+
+ case 0x3C: /* 3C CMP regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ flag_sub8 (oper1b, oper2b);
+ break;
+
+ case 0x3D: /* 3D CMP eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ flag_sub16 (oper1, oper2);
+ break;
+
+ case 0x3F: /* 3F AAS ASCII */
+ if ( ( (regs.byteregs[regal] & 0xF) > 9) || (af == 1) ) {
+ regs.byteregs[regal] = regs.byteregs[regal] - 6;
+ regs.byteregs[regah] = regs.byteregs[regah] - 1;
+ af = 1;
+ cf = 1;
+ }
+ else {
+ af = 0;
+ cf = 0;
+ }
+
+ regs.byteregs[regal] = regs.byteregs[regal] & 0xF;
+ break;
+
+ case 0x40: /* 40 INC eAX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regax];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x41: /* 41 INC eCX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regcx];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regcx] = res16;
+ break;
+
+ case 0x42: /* 42 INC eDX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regdx];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regdx] = res16;
+ break;
+
+ case 0x43: /* 43 INC eBX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regbx];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regbx] = res16;
+ break;
+
+ case 0x44: /* 44 INC eSP */
+ oldcf = cf;
+ oper1 = regs.wordregs[regsp];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regsp] = res16;
+ break;
+
+ case 0x45: /* 45 INC eBP */
+ oldcf = cf;
+ oper1 = regs.wordregs[regbp];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regbp] = res16;
+ break;
+
+ case 0x46: /* 46 INC eSI */
+ oldcf = cf;
+ oper1 = regs.wordregs[regsi];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regsi] = res16;
+ break;
+
+ case 0x47: /* 47 INC eDI */
+ oldcf = cf;
+ oper1 = regs.wordregs[regdi];
+ oper2 = 1;
+ op_add16();
+ cf = oldcf;
+ regs.wordregs[regdi] = res16;
+ break;
+
+ case 0x48: /* 48 DEC eAX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regax];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regax] = res16;
+ break;
+
+ case 0x49: /* 49 DEC eCX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regcx];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regcx] = res16;
+ break;
+
+ case 0x4A: /* 4A DEC eDX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regdx];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regdx] = res16;
+ break;
+
+ case 0x4B: /* 4B DEC eBX */
+ oldcf = cf;
+ oper1 = regs.wordregs[regbx];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regbx] = res16;
+ break;
+
+ case 0x4C: /* 4C DEC eSP */
+ oldcf = cf;
+ oper1 = regs.wordregs[regsp];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regsp] = res16;
+ break;
+
+ case 0x4D: /* 4D DEC eBP */
+ oldcf = cf;
+ oper1 = regs.wordregs[regbp];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regbp] = res16;
+ break;
+
+ case 0x4E: /* 4E DEC eSI */
+ oldcf = cf;
+ oper1 = regs.wordregs[regsi];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regsi] = res16;
+ break;
+
+ case 0x4F: /* 4F DEC eDI */
+ oldcf = cf;
+ oper1 = regs.wordregs[regdi];
+ oper2 = 1;
+ op_sub16();
+ cf = oldcf;
+ regs.wordregs[regdi] = res16;
+ break;
+
+ case 0x50: /* 50 PUSH eAX */
+ push (regs.wordregs[regax]);
+ break;
+
+ case 0x51: /* 51 PUSH eCX */
+ push (regs.wordregs[regcx]);
+ break;
+
+ case 0x52: /* 52 PUSH eDX */
+ push (regs.wordregs[regdx]);
+ break;
+
+ case 0x53: /* 53 PUSH eBX */
+ push (regs.wordregs[regbx]);
+ break;
+
+ case 0x54: /* 54 PUSH eSP */
+#ifdef USE_286_STYLE_PUSH_SP
+ push (regs.wordregs[regsp]);
+#else
+ push (regs.wordregs[regsp] - 2);
+#endif
+ break;
+
+ case 0x55: /* 55 PUSH eBP */
+ push (regs.wordregs[regbp]);
+ break;
+
+ case 0x56: /* 56 PUSH eSI */
+ push (regs.wordregs[regsi]);
+ break;
+
+ case 0x57: /* 57 PUSH eDI */
+ push (regs.wordregs[regdi]);
+ break;
+
+ case 0x58: /* 58 POP eAX */
+ regs.wordregs[regax] = pop();
+ break;
+
+ case 0x59: /* 59 POP eCX */
+ regs.wordregs[regcx] = pop();
+ break;
+
+ case 0x5A: /* 5A POP eDX */
+ regs.wordregs[regdx] = pop();
+ break;
+
+ case 0x5B: /* 5B POP eBX */
+ regs.wordregs[regbx] = pop();
+ break;
+
+ case 0x5C: /* 5C POP eSP */
+ regs.wordregs[regsp] = pop();
+ break;
+
+ case 0x5D: /* 5D POP eBP */
+ regs.wordregs[regbp] = pop();
+ break;
+
+ case 0x5E: /* 5E POP eSI */
+ regs.wordregs[regsi] = pop();
+ break;
+
+ case 0x5F: /* 5F POP eDI */
+ regs.wordregs[regdi] = pop();
+ break;
+
+#ifndef CPU_8086
+ case 0x60: /* 60 PUSHA (80186+) */
+ oldsp = regs.wordregs[regsp];
+ push (regs.wordregs[regax]);
+ push (regs.wordregs[regcx]);
+ push (regs.wordregs[regdx]);
+ push (regs.wordregs[regbx]);
+ push (oldsp);
+ push (regs.wordregs[regbp]);
+ push (regs.wordregs[regsi]);
+ push (regs.wordregs[regdi]);
+ break;
+
+ case 0x61: /* 61 POPA (80186+) */
+ regs.wordregs[regdi] = pop();
+ regs.wordregs[regsi] = pop();
+ regs.wordregs[regbp] = pop();
+ dummy = pop();
+ regs.wordregs[regbx] = pop();
+ regs.wordregs[regdx] = pop();
+ regs.wordregs[regcx] = pop();
+ regs.wordregs[regax] = pop();
+ break;
+
+ case 0x62: /* 62 BOUND Gv, Ev (80186+) */
+ modregrm();
+ getea (rm);
+ if (signext32 (getreg16 (reg) ) < signext32 ( getmem16 (ea >> 4, ea & 15) ) ) {
+ intcall86 (5); //bounds check exception
+ }
+ else {
+ ea += 2;
+ if (signext32 (getreg16 (reg) ) > signext32 ( getmem16 (ea >> 4, ea & 15) ) ) {
+ intcall86(5); //bounds check exception
+ }
+ }
+ break;
+
+ case 0x68: /* 68 PUSH Iv (80186+) */
+ push (getmem16 (segregs[regcs], ip) );
+ StepIP (2);
+ break;
+
+ case 0x69: /* 69 IMUL Gv Ev Iv (80186+) */
+ modregrm();
+ temp1 = readrm16 (rm);
+ temp2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ if ( (temp1 & 0x8000L) == 0x8000L) {
+ temp1 = temp1 | 0xFFFF0000L;
+ }
+
+ if ( (temp2 & 0x8000L) == 0x8000L) {
+ temp2 = temp2 | 0xFFFF0000L;
+ }
+
+ temp3 = temp1 * temp2;
+ putreg16 (reg, temp3 & 0xFFFFL);
+ if (temp3 & 0xFFFF0000L) {
+ cf = 1;
+ of = 1;
+ }
+ else {
+ cf = 0;
+ of = 0;
+ }
+ break;
+
+ case 0x6A: /* 6A PUSH Ib (80186+) */
+ push (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ break;
+
+ case 0x6B: /* 6B IMUL Gv Eb Ib (80186+) */
+ modregrm();
+ temp1 = readrm16 (rm);
+ temp2 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if ( (temp1 & 0x8000L) == 0x8000L) {
+ temp1 = temp1 | 0xFFFF0000L;
+ }
+
+ if ( (temp2 & 0x8000L) == 0x8000L) {
+ temp2 = temp2 | 0xFFFF0000L;
+ }
+
+ temp3 = temp1 * temp2;
+ putreg16 (reg, temp3 & 0xFFFFL);
+ if (temp3 & 0xFFFF0000L) {
+ cf = 1;
+ of = 1;
+ }
+ else {
+ cf = 0;
+ of = 0;
+ }
+ break;
+
+ case 0x6C: /* 6E INSB */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ putmem8 (useseg, regs.wordregs[regsi], portin (regs.wordregs[regdx]) );
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 1;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 1;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0x6D: /* 6F INSW */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ putmem16 (useseg, regs.wordregs[regsi], portin16 (regs.wordregs[regdx]) );
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 2;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 2;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0x6E: /* 6E OUTSB */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ portout (regs.wordregs[regdx], getmem8 (useseg, regs.wordregs[regsi]) );
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 1;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 1;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0x6F: /* 6F OUTSW */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ portout16 (regs.wordregs[regdx], getmem16 (useseg, regs.wordregs[regsi]) );
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 2;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 2;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+#endif
+
+ case 0x70: /* 70 JO Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (of) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x71: /* 71 JNO Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!of) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x72: /* 72 JB Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (cf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x73: /* 73 JNB Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!cf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x74: /* 74 JZ Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (zf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x75: /* 75 JNZ Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!zf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x76: /* 76 JBE Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (cf || zf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x77: /* 77 JA Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!cf && !zf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x78: /* 78 JS Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (sf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x79: /* 79 JNS Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!sf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x7A: /* 7A JPE Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (pf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x7B: /* 7B JPO Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!pf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x7C: /* 7C JL Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (sf != of) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x7D: /* 7D JGE Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (sf == of) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x7E: /* 7E JLE Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if ( (sf != of) || zf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x7F: /* 7F JG Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!zf && (sf == of) ) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0x80:
+ case 0x82: /* 80/82 GRP1 Eb Ib */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ switch (reg) {
+ case 0:
+ op_add8();
+ break;
+ case 1:
+ op_or8();
+ break;
+ case 2:
+ op_adc8();
+ break;
+ case 3:
+ op_sbb8();
+ break;
+ case 4:
+ op_and8();
+ break;
+ case 5:
+ op_sub8();
+ break;
+ case 6:
+ op_xor8();
+ break;
+ case 7:
+ flag_sub8 (oper1b, oper2b);
+ break;
+ default:
+ break; /* to avoid compiler warnings */
+ }
+
+ if (reg < 7) {
+ writerm8 (rm, res8);
+ }
+ break;
+
+ case 0x81: /* 81 GRP1 Ev Iv */
+ case 0x83: /* 83 GRP1 Ev Ib */
+ modregrm();
+ oper1 = readrm16 (rm);
+ if (opcode == 0x81) {
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ }
+ else {
+ oper2 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ }
+
+ switch (reg) {
+ case 0:
+ op_add16();
+ break;
+ case 1:
+ op_or16();
+ break;
+ case 2:
+ op_adc16();
+ break;
+ case 3:
+ op_sbb16();
+ break;
+ case 4:
+ op_and16();
+ break;
+ case 5:
+ op_sub16();
+ break;
+ case 6:
+ op_xor16();
+ break;
+ case 7:
+ flag_sub16 (oper1, oper2);
+ break;
+ default:
+ break; /* to avoid compiler warnings */
+ }
+
+ if (reg < 7) {
+ writerm16 (rm, res16);
+ }
+ break;
+
+ case 0x84: /* 84 TEST Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ oper2b = readrm8 (rm);
+ flag_log8 (oper1b & oper2b);
+ break;
+
+ case 0x85: /* 85 TEST Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ oper2 = readrm16 (rm);
+ flag_log16 (oper1 & oper2);
+ break;
+
+ case 0x86: /* 86 XCHG Gb Eb */
+ modregrm();
+ oper1b = getreg8 (reg);
+ putreg8 (reg, readrm8 (rm) );
+ writerm8 (rm, oper1b);
+ break;
+
+ case 0x87: /* 87 XCHG Gv Ev */
+ modregrm();
+ oper1 = getreg16 (reg);
+ putreg16 (reg, readrm16 (rm) );
+ writerm16 (rm, oper1);
+ break;
+
+ case 0x88: /* 88 MOV Eb Gb */
+ modregrm();
+ writerm8 (rm, getreg8 (reg) );
+ break;
+
+ case 0x89: /* 89 MOV Ev Gv */
+ modregrm();
+ writerm16 (rm, getreg16 (reg) );
+ break;
+
+ case 0x8A: /* 8A MOV Gb Eb */
+ modregrm();
+ putreg8 (reg, readrm8 (rm) );
+ break;
+
+ case 0x8B: /* 8B MOV Gv Ev */
+ modregrm();
+ putreg16 (reg, readrm16 (rm) );
+ break;
+
+ case 0x8C: /* 8C MOV Ew Sw */
+ modregrm();
+ writerm16 (rm, getsegreg (reg) );
+ break;
+
+ case 0x8D: /* 8D LEA Gv M */
+ modregrm();
+ getea (rm);
+ putreg16 (reg, ea - segbase (useseg) );
+ break;
+
+ case 0x8E: /* 8E MOV Sw Ew */
+ modregrm();
+ putsegreg (reg, readrm16 (rm) );
+ break;
+
+ case 0x8F: /* 8F POP Ev */
+ modregrm();
+ writerm16 (rm, pop() );
+ break;
+
+ case 0x90: /* 90 NOP */
+ break;
+
+ case 0x91: /* 91 XCHG eCX eAX */
+ oper1 = regs.wordregs[regcx];
+ regs.wordregs[regcx] = regs.wordregs[regax];
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0x92: /* 92 XCHG eDX eAX */
+ oper1 = regs.wordregs[regdx];
+ regs.wordregs[regdx] = regs.wordregs[regax];
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0x93: /* 93 XCHG eBX eAX */
+ oper1 = regs.wordregs[regbx];
+ regs.wordregs[regbx] = regs.wordregs[regax];
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0x94: /* 94 XCHG eSP eAX */
+ oper1 = regs.wordregs[regsp];
+ regs.wordregs[regsp] = regs.wordregs[regax];
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0x95: /* 95 XCHG eBP eAX */
+ oper1 = regs.wordregs[regbp];
+ regs.wordregs[regbp] = regs.wordregs[regax];
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0x96: /* 96 XCHG eSI eAX */
+ oper1 = regs.wordregs[regsi];
+ regs.wordregs[regsi] = regs.wordregs[regax];
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0x97: /* 97 XCHG eDI eAX */
+ oper1 = regs.wordregs[regdi];
+ regs.wordregs[regdi] = regs.wordregs[regax];
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0x98: /* 98 CBW */
+ if ( (regs.byteregs[regal] & 0x80) == 0x80) {
+ regs.byteregs[regah] = 0xFF;
+ }
+ else {
+ regs.byteregs[regah] = 0;
+ }
+ break;
+
+ case 0x99: /* 99 CWD */
+ if ( (regs.byteregs[regah] & 0x80) == 0x80) {
+ regs.wordregs[regdx] = 0xFFFF;
+ }
+ else {
+ regs.wordregs[regdx] = 0;
+ }
+ break;
+
+ case 0x9A: /* 9A CALL Ap */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ push (segregs[regcs]);
+ push (ip);
+ ip = oper1;
+ segregs[regcs] = oper2;
+ break;
+
+ case 0x9B: /* 9B WAIT */
+ break;
+
+ case 0x9C: /* 9C PUSHF */
+#ifdef CPU_SET_HIGH_FLAGS
+ push (makeflagsword() | 0xF800);
+#else
+ push (makeflagsword() | 0x0800);
+#endif
+ break;
+
+ case 0x9D: /* 9D POPF */
+ temp16 = pop();
+ decodeflagsword (temp16);
+ break;
+
+ case 0x9E: /* 9E SAHF */
+ decodeflagsword ( (makeflagsword() & 0xFF00) | regs.byteregs[regah]);
+ break;
+
+ case 0x9F: /* 9F LAHF */
+ regs.byteregs[regah] = makeflagsword() & 0xFF;
+ break;
+
+ case 0xA0: /* A0 MOV regs.byteregs[regal] Ob */
+ regs.byteregs[regal] = getmem8 (useseg, getmem16 (segregs[regcs], ip) );
+ StepIP (2);
+ break;
+
+ case 0xA1: /* A1 MOV eAX Ov */
+ oper1 = getmem16 (useseg, getmem16 (segregs[regcs], ip) );
+ StepIP (2);
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0xA2: /* A2 MOV Ob regs.byteregs[regal] */
+ putmem8 (useseg, getmem16 (segregs[regcs], ip), regs.byteregs[regal]);
+ StepIP (2);
+ break;
+
+ case 0xA3: /* A3 MOV Ov eAX */
+ putmem16 (useseg, getmem16 (segregs[regcs], ip), regs.wordregs[regax]);
+ StepIP (2);
+ break;
+
+ case 0xA4: /* A4 MOVSB */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ putmem8 (segregs[reges], regs.wordregs[regdi], getmem8 (useseg, regs.wordregs[regsi]) );
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 1;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 1;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xA5: /* A5 MOVSW */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ putmem16 (segregs[reges], regs.wordregs[regdi], getmem16 (useseg, regs.wordregs[regsi]) );
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 2;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 2;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xA6: /* A6 CMPSB */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ oper1b = getmem8 (useseg, regs.wordregs[regsi]);
+ oper2b = getmem8 (segregs[reges], regs.wordregs[regdi]);
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 1;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 1;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 1;
+ }
+
+ flag_sub8 (oper1b, oper2b);
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ if ( (reptype == 1) && !zf) {
+ break;
+ }
+ else if ( (reptype == 2) && (zf == 1) ) {
+ break;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xA7: /* A7 CMPSW */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ oper1 = getmem16 (useseg,regs.wordregs[regsi]);
+ oper2 = getmem16 (segregs[reges], regs.wordregs[regdi]);
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 2;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 2;
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 2;
+ }
+
+ flag_sub16 (oper1, oper2);
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ if ( (reptype == 1) && !zf) {
+ break;
+ }
+
+ if ( (reptype == 2) && (zf == 1) ) {
+ break;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xA8: /* A8 TEST regs.byteregs[regal] Ib */
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ flag_log8 (oper1b & oper2b);
+ break;
+
+ case 0xA9: /* A9 TEST eAX Iv */
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ flag_log16 (oper1 & oper2);
+ break;
+
+ case 0xAA: /* AA STOSB */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ putmem8 (segregs[reges], regs.wordregs[regdi], regs.byteregs[regal]);
+ if (df) {
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 1;
+ }
+ else {
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 1;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xAB: /* AB STOSW */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ putmem16 (segregs[reges], regs.wordregs[regdi], regs.wordregs[regax]);
+ if (df) {
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 2;
+ }
+ else {
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 2;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xAC: /* AC LODSB */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ regs.byteregs[regal] = getmem8 (useseg, regs.wordregs[regsi]);
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 1;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 1;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xAD: /* AD LODSW */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ oper1 = getmem16 (useseg, regs.wordregs[regsi]);
+ regs.wordregs[regax] = oper1;
+ if (df) {
+ regs.wordregs[regsi] = regs.wordregs[regsi] - 2;
+ }
+ else {
+ regs.wordregs[regsi] = regs.wordregs[regsi] + 2;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xAE: /* AE SCASB */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ oper1b = regs.byteregs[regal];
+ oper2b = getmem8 (segregs[reges], regs.wordregs[regdi]);
+ flag_sub8 (oper1b, oper2b);
+ if (df) {
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 1;
+ }
+ else {
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 1;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ if ( (reptype == 1) && !zf) {
+ break;
+ }
+ else if ( (reptype == 2) && (zf == 1) ) {
+ break;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xAF: /* AF SCASW */
+ if (reptype && (regs.wordregs[regcx] == 0) ) {
+ break;
+ }
+
+ oper1 = regs.wordregs[regax];
+ oper2 = getmem16 (segregs[reges], regs.wordregs[regdi]);
+ flag_sub16 (oper1, oper2);
+ if (df) {
+ regs.wordregs[regdi] = regs.wordregs[regdi] - 2;
+ }
+ else {
+ regs.wordregs[regdi] = regs.wordregs[regdi] + 2;
+ }
+
+ if (reptype) {
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ }
+
+ if ( (reptype == 1) && !zf) {
+ break;
+ }
+ else if ( (reptype == 2) & (zf == 1) ) {
+ break;
+ }
+
+ totalexec++;
+ loopcount++;
+ if (!reptype) {
+ break;
+ }
+
+ ip = firstip;
+ break;
+
+ case 0xB0: /* B0 MOV regs.byteregs[regal] Ib */
+ regs.byteregs[regal] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB1: /* B1 MOV regs.byteregs[regcl] Ib */
+ regs.byteregs[regcl] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB2: /* B2 MOV regs.byteregs[regdl] Ib */
+ regs.byteregs[regdl] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB3: /* B3 MOV regs.byteregs[regbl] Ib */
+ regs.byteregs[regbl] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB4: /* B4 MOV regs.byteregs[regah] Ib */
+ regs.byteregs[regah] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB5: /* B5 MOV regs.byteregs[regch] Ib */
+ regs.byteregs[regch] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB6: /* B6 MOV regs.byteregs[regdh] Ib */
+ regs.byteregs[regdh] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB7: /* B7 MOV regs.byteregs[regbh] Ib */
+ regs.byteregs[regbh] = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ break;
+
+ case 0xB8: /* B8 MOV eAX Iv */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ regs.wordregs[regax] = oper1;
+ break;
+
+ case 0xB9: /* B9 MOV eCX Iv */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ regs.wordregs[regcx] = oper1;
+ break;
+
+ case 0xBA: /* BA MOV eDX Iv */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ regs.wordregs[regdx] = oper1;
+ break;
+
+ case 0xBB: /* BB MOV eBX Iv */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ regs.wordregs[regbx] = oper1;
+ break;
+
+ case 0xBC: /* BC MOV eSP Iv */
+ regs.wordregs[regsp] = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ break;
+
+ case 0xBD: /* BD MOV eBP Iv */
+ regs.wordregs[regbp] = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ break;
+
+ case 0xBE: /* BE MOV eSI Iv */
+ regs.wordregs[regsi] = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ break;
+
+ case 0xBF: /* BF MOV eDI Iv */
+ regs.wordregs[regdi] = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ break;
+
+ case 0xC0: /* C0 GRP2 byte imm8 (80186+) */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ writerm8 (rm, op_grp2_8 (oper2b) );
+ break;
+
+ case 0xC1: /* C1 GRP2 word imm8 (80186+) */
+ modregrm();
+ oper1 = readrm16 (rm);
+ oper2 = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ writerm16 (rm, op_grp2_16 ( (uint8_t) oper2) );
+ break;
+
+ case 0xC2: /* C2 RET Iw */
+ oper1 = getmem16 (segregs[regcs], ip);
+ ip = pop();
+ regs.wordregs[regsp] = regs.wordregs[regsp] + oper1;
+ break;
+
+ case 0xC3: /* C3 RET */
+ ip = pop();
+ break;
+
+ case 0xC4: /* C4 LES Gv Mp */
+ modregrm();
+ getea (rm);
+ putreg16 (reg, read86 (ea) + read86 (ea + 1) * 256);
+ segregs[reges] = read86 (ea + 2) + read86 (ea + 3) * 256;
+ break;
+
+ case 0xC5: /* C5 LDS Gv Mp */
+ modregrm();
+ getea (rm);
+ putreg16 (reg, read86 (ea) + read86 (ea + 1) * 256);
+ segregs[regds] = read86 (ea + 2) + read86 (ea + 3) * 256;
+ break;
+
+ case 0xC6: /* C6 MOV Eb Ib */
+ modregrm();
+ writerm8 (rm, getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ break;
+
+ case 0xC7: /* C7 MOV Ev Iv */
+ modregrm();
+ writerm16 (rm, getmem16 (segregs[regcs], ip) );
+ StepIP (2);
+ break;
+
+ case 0xC8: /* C8 ENTER (80186+) */
+ stacksize = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ nestlev = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ push (regs.wordregs[regbp]);
+ frametemp = regs.wordregs[regsp];
+ if (nestlev) {
+ for (temp16 = 1; temp16 < nestlev; temp16++) {
+ regs.wordregs[regbp] = regs.wordregs[regbp] - 2;
+ push (regs.wordregs[regbp]);
+ }
+
+ push (regs.wordregs[regsp]);
+ }
+
+ regs.wordregs[regbp] = frametemp;
+ regs.wordregs[regsp] = regs.wordregs[regbp] - stacksize;
+
+ break;
+
+ case 0xC9: /* C9 LEAVE (80186+) */
+ regs.wordregs[regsp] = regs.wordregs[regbp];
+ regs.wordregs[regbp] = pop();
+ break;
+
+ case 0xCA: /* CA RETF Iw */
+ oper1 = getmem16 (segregs[regcs], ip);
+ ip = pop();
+ segregs[regcs] = pop();
+ regs.wordregs[regsp] = regs.wordregs[regsp] + oper1;
+ break;
+
+ case 0xCB: /* CB RETF */
+ ip = pop();;
+ segregs[regcs] = pop();
+ break;
+
+ case 0xCC: /* CC INT 3 */
+ intcall86 (3);
+ break;
+
+ case 0xCD: /* CD INT Ib */
+ oper1b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ intcall86 (oper1b);
+ break;
+
+ case 0xCE: /* CE INTO */
+ if (of) {
+ intcall86 (4);
+ }
+ break;
+
+ case 0xCF: /* CF IRET */
+ ip = pop();
+ segregs[regcs] = pop();
+ decodeflagsword (pop() );
+
+ /*
+ * if (net.enabled) net.canrecv = 1;
+ */
+ break;
+
+ case 0xD0: /* D0 GRP2 Eb 1 */
+ modregrm();
+ oper1b = readrm8 (rm);
+ writerm8 (rm, op_grp2_8 (1) );
+ break;
+
+ case 0xD1: /* D1 GRP2 Ev 1 */
+ modregrm();
+ oper1 = readrm16 (rm);
+ writerm16 (rm, op_grp2_16 (1) );
+ break;
+
+ case 0xD2: /* D2 GRP2 Eb regs.byteregs[regcl] */
+ modregrm();
+ oper1b = readrm8 (rm);
+ writerm8 (rm, op_grp2_8 (regs.byteregs[regcl]) );
+ break;
+
+ case 0xD3: /* D3 GRP2 Ev regs.byteregs[regcl] */
+ modregrm();
+ oper1 = readrm16 (rm);
+ writerm16 (rm, op_grp2_16 (regs.byteregs[regcl]) );
+ break;
+
+ case 0xD4: /* D4 AAM I0 */
+ oper1 = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ if (!oper1) {
+ intcall86 (0);
+ break;
+ } /* division by zero */
+
+ regs.byteregs[regah] = (regs.byteregs[regal] / oper1) & 255;
+ regs.byteregs[regal] = (regs.byteregs[regal] % oper1) & 255;
+ flag_szp16 (regs.wordregs[regax]);
+ break;
+
+ case 0xD5: /* D5 AAD I0 */
+ oper1 = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ regs.byteregs[regal] = (regs.byteregs[regah] * oper1 + regs.byteregs[regal]) & 255;
+ regs.byteregs[regah] = 0;
+ flag_szp16 (regs.byteregs[regah] * oper1 + regs.byteregs[regal]);
+ sf = 0;
+ break;
+
+ case 0xD6: /* D6 XLAT on V20/V30, SALC on 8086/8088 */
+#ifndef CPU_NO_SALC
+ regs.byteregs[regal] = cf ? 0xFF : 0x00;
+ break;
+#endif
+
+ case 0xD7: /* D7 XLAT */
+ regs.byteregs[regal] = read86(useseg * 16 + (regs.wordregs[regbx]) + regs.byteregs[regal]);
+ break;
+
+ case 0xD8:
+ case 0xD9:
+ case 0xDA:
+ case 0xDB:
+ case 0xDC:
+ case 0xDE:
+ case 0xDD:
+ case 0xDF: /* escape to x87 FPU (unsupported) */
+ modregrm();
+ break;
+
+ case 0xE0: /* E0 LOOPNZ Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ if ( (regs.wordregs[regcx]) && !zf) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0xE1: /* E1 LOOPZ Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ if (regs.wordregs[regcx] && (zf == 1) ) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0xE2: /* E2 LOOP Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ regs.wordregs[regcx] = regs.wordregs[regcx] - 1;
+ if (regs.wordregs[regcx]) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0xE3: /* E3 JCXZ Jb */
+ temp16 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ if (!regs.wordregs[regcx]) {
+ ip = ip + temp16;
+ }
+ break;
+
+ case 0xE4: /* E4 IN regs.byteregs[regal] Ib */
+ oper1b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ regs.byteregs[regal] = (uint8_t) portin (oper1b);
+ break;
+
+ case 0xE5: /* E5 IN eAX Ib */
+ oper1b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ regs.wordregs[regax] = portin16 (oper1b);
+ break;
+
+ case 0xE6: /* E6 OUT Ib regs.byteregs[regal] */
+ oper1b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ portout (oper1b, regs.byteregs[regal]);
+ break;
+
+ case 0xE7: /* E7 OUT Ib eAX */
+ oper1b = getmem8 (segregs[regcs], ip);
+ StepIP (1);
+ portout16 (oper1b, regs.wordregs[regax]);
+ break;
+
+ case 0xE8: /* E8 CALL Jv */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ push (ip);
+ ip = ip + oper1;
+ break;
+
+ case 0xE9: /* E9 JMP Jv */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ ip = ip + oper1;
+ break;
+
+ case 0xEA: /* EA JMP Ap */
+ oper1 = getmem16 (segregs[regcs], ip);
+ StepIP (2);
+ oper2 = getmem16 (segregs[regcs], ip);
+ ip = oper1;
+ segregs[regcs] = oper2;
+ break;
+
+ case 0xEB: /* EB JMP Jb */
+ oper1 = signext (getmem8 (segregs[regcs], ip) );
+ StepIP (1);
+ ip = ip + oper1;
+ break;
+
+ case 0xEC: /* EC IN regs.byteregs[regal] regdx */
+ oper1 = regs.wordregs[regdx];
+ regs.byteregs[regal] = (uint8_t) portin (oper1);
+ break;
+
+ case 0xED: /* ED IN eAX regdx */
+ oper1 = regs.wordregs[regdx];
+ regs.wordregs[regax] = portin16 (oper1);
+ break;
+
+ case 0xEE: /* EE OUT regdx regs.byteregs[regal] */
+ oper1 = regs.wordregs[regdx];
+ portout (oper1, regs.byteregs[regal]);
+ break;
+
+ case 0xEF: /* EF OUT regdx eAX */
+ oper1 = regs.wordregs[regdx];
+ portout16 (oper1, regs.wordregs[regax]);
+ break;
+
+ case 0xF0: /* F0 LOCK */
+ break;
+
+ case 0xF4: /* F4 HLT */
+ hltstate = 1;
+ break;
+
+ case 0xF5: /* F5 CMC */
+ if (!cf) {
+ cf = 1;
+ }
+ else {
+ cf = 0;
+ }
+ break;
+
+ case 0xF6: /* F6 GRP3a Eb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ op_grp3_8();
+ if ( (reg > 1) && (reg < 4) ) {
+ writerm8 (rm, res8);
+ }
+ break;
+
+ case 0xF7: /* F7 GRP3b Ev */
+ modregrm();
+ oper1 = readrm16 (rm);
+ op_grp3_16();
+ if ( (reg > 1) && (reg < 4) ) {
+ writerm16 (rm, res16);
+ }
+ break;
+
+ case 0xF8: /* F8 CLC */
+ cf = 0;
+ break;
+
+ case 0xF9: /* F9 STC */
+ cf = 1;
+ break;
+
+ case 0xFA: /* FA CLI */
+ ifl = 0;
+ break;
+
+ case 0xFB: /* FB STI */
+ ifl = 1;
+ break;
+
+ case 0xFC: /* FC CLD */
+ df = 0;
+ break;
+
+ case 0xFD: /* FD STD */
+ df = 1;
+ break;
+
+ case 0xFE: /* FE GRP4 Eb */
+ modregrm();
+ oper1b = readrm8 (rm);
+ oper2b = 1;
+ if (!reg) {
+ tempcf = cf;
+ res8 = oper1b + oper2b;
+ flag_add8 (oper1b, oper2b);
+ cf = tempcf;
+ writerm8 (rm, res8);
+ }
+ else {
+ tempcf = cf;
+ res8 = oper1b - oper2b;
+ flag_sub8 (oper1b, oper2b);
+ cf = tempcf;
+ writerm8 (rm, res8);
+ }
+ break;
+
+ case 0xFF: /* FF GRP5 Ev */
+ modregrm();
+ oper1 = readrm16 (rm);
+ op_grp5();
+ break;
+
+ default:
+#ifdef CPU_ALLOW_ILLEGAL_OP_EXCEPTION
+ intcall86 (6); /* trip invalid opcode exception (this occurs on the 80186+, 8086/8088 CPUs treat them as NOPs. */
+ /* technically they aren't exactly like NOPs in most cases, but for our pursoses, that's accurate enough. */
+#endif
+ if (verbose) {
+ printf ("Illegal opcode: %02X %02X /%X @ %04X:%04X\n", getmem8(savecs, saveip), getmem8(savecs, saveip+1), (getmem8(savecs, saveip+2) >> 3) & 7, savecs, saveip);
+ }
+ break;
+ }
+
+skipexecution:
+ if (!running) {
+ return;
+ }
+ }
+}
+#endif
diff --git a/src/fake86/cpu.h b/src/fake86/cpu.h
new file mode 100755
index 0000000..6b37f47
--- /dev/null
+++ b/src/fake86/cpu.h
@@ -0,0 +1,110 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <time.h>
+#endif
+
+#define regax 0
+#define regcx 1
+#define regdx 2
+#define regbx 3
+#define regsp 4
+#define regbp 5
+#define regsi 6
+#define regdi 7
+#define reges 0
+#define regcs 1
+#define regss 2
+#define regds 3
+
+#ifdef __BIG_ENDIAN__
+#define regal 1
+#define regah 0
+#define regcl 3
+#define regch 2
+#define regdl 5
+#define regdh 4
+#define regbl 7
+#define regbh 6
+#else
+#define regal 0
+#define regah 1
+#define regcl 2
+#define regch 3
+#define regdl 4
+#define regdh 5
+#define regbl 6
+#define regbh 7
+#endif
+
+union _bytewordregs_ {
+ uint16_t wordregs[8];
+ uint8_t byteregs[8];
+};
+
+#ifdef CPU_ADDR_MODE_CACHE
+struct addrmodecache_s {
+ uint16_t exitcs;
+ uint16_t exitip;
+ uint16_t disp16;
+ uint32_t len;
+ uint8_t mode;
+ uint8_t reg;
+ uint8_t rm;
+ uint8_t forcess;
+ uint8_t valid;
+};
+#endif
+
+#define StepIP(x) ip += x
+#define getmem8(x, y) read86(segbase(x) + y)
+#define getmem16(x, y) readw86(segbase(x) + y)
+#define putmem8(x, y, z) write86(segbase(x) + y, z)
+#define putmem16(x, y, z) writew86(segbase(x) + y, z)
+#define signext(value) (int16_t)(int8_t)(value)
+#define signext32(value) (int32_t)(int16_t)(value)
+#define getreg16(regid) regs.wordregs[regid]
+#define getreg8(regid) regs.byteregs[byteregtable[regid]]
+#define putreg16(regid, writeval) regs.wordregs[regid] = writeval
+#define putreg8(regid, writeval) regs.byteregs[byteregtable[regid]] = writeval
+#define getsegreg(regid) segregs[regid]
+#define putsegreg(regid, writeval) segregs[regid] = writeval
+#define segbase(x) ((uint32_t) x << 4)
+
+#define makeflagsword() \
+ ( \
+ 2 | (uint16_t) cf | ((uint16_t) pf << 2) | ((uint16_t) af << 4) | ((uint16_t) zf << 6) | ((uint16_t) sf << 7) | \
+ ((uint16_t) tf << 8) | ((uint16_t) ifl << 9) | ((uint16_t) df << 10) | ((uint16_t) of << 11) \
+ )
+
+#define decodeflagsword(x) { \
+ temp16 = x; \
+ cf = temp16 & 1; \
+ pf = (temp16 >> 2) & 1; \
+ af = (temp16 >> 4) & 1; \
+ zf = (temp16 >> 6) & 1; \
+ sf = (temp16 >> 7) & 1; \
+ tf = (temp16 >> 8) & 1; \
+ ifl = (temp16 >> 9) & 1; \
+ df = (temp16 >> 10) & 1; \
+ of = (temp16 >> 11) & 1; \
+ }
diff --git a/src/fake86/disk.c b/src/fake86/disk.c
new file mode 100755
index 0000000..b09c8e2
--- /dev/null
+++ b/src/fake86/disk.c
@@ -0,0 +1,182 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* disk.c: disk emulation routines for Fake86. works at the BIOS interrupt 13h level. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include "disk.h"
+#include "cpu.h"
+
+extern uint8_t RAM[0x100000], cf, hdcount;
+extern uint16_t segregs[4];
+extern union _bytewordregs_ regs;
+
+extern uint8_t read86 (uint32_t addr32);
+extern void write86 (uint32_t addr32, uint8_t value);
+
+struct struct_drive disk[256];
+uint8_t sectorbuffer[512];
+
+uint8_t insertdisk (uint8_t drivenum, char *filename) {
+ if (disk[drivenum].inserted) fclose (disk[drivenum].diskfile);
+ else disk[drivenum].inserted = 1;
+ disk[drivenum].diskfile = fopen (filename, "r+b");
+ if (disk[drivenum].diskfile==NULL) {
+ disk[drivenum].inserted = 0;
+ return (1);
+ }
+ fseek (disk[drivenum].diskfile, 0L, SEEK_END);
+ disk[drivenum].filesize = ftell (disk[drivenum].diskfile);
+ fseek (disk[drivenum].diskfile, 0L, SEEK_SET);
+ if (drivenum >= 0x80) { //it's a hard disk image
+ disk[drivenum].sects = 63;
+ disk[drivenum].heads = 16;
+ disk[drivenum].cyls = disk[drivenum].filesize / (disk[drivenum].sects * disk[drivenum].heads * 512);
+ hdcount++;
+ }
+ else { //it's a floppy image
+ disk[drivenum].cyls = 80;
+ disk[drivenum].sects = 18;
+ disk[drivenum].heads = 2;
+ if (disk[drivenum].filesize <= 1228800) disk[drivenum].sects = 15;
+ if (disk[drivenum].filesize <= 737280) disk[drivenum].sects = 9;
+ if (disk[drivenum].filesize <= 368640) {
+ disk[drivenum].cyls = 40;
+ disk[drivenum].sects = 9;
+ }
+ if (disk[drivenum].filesize <= 163840) {
+ disk[drivenum].cyls = 40;
+ disk[drivenum].sects = 8;
+ disk[drivenum].heads = 1;
+ }
+ }
+ return (0);
+}
+
+void ejectdisk (uint8_t drivenum) {
+ disk[drivenum].inserted = 0;
+ if (disk[drivenum].diskfile != NULL) fclose (disk[drivenum].diskfile);
+}
+
+void readdisk (uint8_t drivenum, uint16_t dstseg, uint16_t dstoff, uint16_t cyl, uint16_t sect, uint16_t head, uint16_t sectcount) {
+ uint32_t memdest, lba, fileoffset, cursect, sectoffset;
+ if (!sect || !disk[drivenum].inserted) return;
+ lba = ( (uint32_t) cyl * (uint32_t) disk[drivenum].heads + (uint32_t) head) * (uint32_t) disk[drivenum].sects + (uint32_t) sect - 1;
+ fileoffset = lba * 512;
+ if (fileoffset>disk[drivenum].filesize) return;
+ fseek (disk[drivenum].diskfile, fileoffset, SEEK_SET);
+ memdest = ( (uint32_t) dstseg << 4) + (uint32_t) dstoff;
+ //for the readdisk function, we need to use write86 instead of directly fread'ing into
+ //the RAM array, so that read-only flags are honored. otherwise, a program could load
+ //data from a disk over BIOS or other ROM code that it shouldn't be able to.
+ for (cursect=0; cursect<sectcount; cursect++) {
+ if (fread (sectorbuffer, 1, 512, disk[drivenum].diskfile) < 512) break;
+ for (sectoffset=0; sectoffset<512; sectoffset++) {
+ write86 (memdest++, sectorbuffer[sectoffset]);
+ }
+ }
+ regs.byteregs[regal] = cursect;
+ cf = 0;
+ regs.byteregs[regah] = 0;
+}
+
+void writedisk (uint8_t drivenum, uint16_t dstseg, uint16_t dstoff, uint16_t cyl, uint16_t sect, uint16_t head, uint16_t sectcount) {
+ uint32_t memdest, lba, fileoffset, cursect, sectoffset;
+ if (!sect || !disk[drivenum].inserted) return;
+ lba = ( (uint32_t) cyl * (uint32_t) disk[drivenum].heads + (uint32_t) head) * (uint32_t) disk[drivenum].sects + (uint32_t) sect - 1;
+ fileoffset = lba * 512;
+ if (fileoffset>disk[drivenum].filesize) return;
+ fseek (disk[drivenum].diskfile, fileoffset, SEEK_SET);
+ memdest = ( (uint32_t) dstseg << 4) + (uint32_t) dstoff;
+ for (cursect=0; cursect<sectcount; cursect++) {
+ for (sectoffset=0; sectoffset<512; sectoffset++) {
+ sectorbuffer[sectoffset] = read86 (memdest++);
+ }
+ fwrite (sectorbuffer, 1, 512, disk[drivenum].diskfile);
+ }
+ regs.byteregs[regal] = (uint8_t) sectcount;
+ cf = 0;
+ regs.byteregs[regah] = 0;
+}
+
+void diskhandler() {
+ static uint8_t lastdiskah[256], lastdiskcf[256];
+ switch (regs.byteregs[regah]) {
+ case 0: //reset disk system
+ regs.byteregs[regah] = 0;
+ cf = 0; //useless function in an emulator. say success and return.
+ break;
+ case 1: //return last status
+ regs.byteregs[regah] = lastdiskah[regs.byteregs[regdl]];
+ cf = lastdiskcf[regs.byteregs[regdl]];
+ return;
+ case 2: //read sector(s) into memory
+ if (disk[regs.byteregs[regdl]].inserted) {
+ readdisk (regs.byteregs[regdl], segregs[reges], getreg16 (regbx), regs.byteregs[regch] + (regs.byteregs[regcl]/64) *256, regs.byteregs[regcl] & 63, regs.byteregs[regdh], regs.byteregs[regal]);
+ cf = 0;
+ regs.byteregs[regah] = 0;
+ }
+ else {
+ cf = 1;
+ regs.byteregs[regah] = 1;
+ }
+ break;
+ case 3: //write sector(s) from memory
+ if (disk[regs.byteregs[regdl]].inserted) {
+ writedisk (regs.byteregs[regdl], segregs[reges], getreg16 (regbx), regs.byteregs[regch] + (regs.byteregs[regcl]/64) *256, regs.byteregs[regcl] & 63, regs.byteregs[regdh], regs.byteregs[regal]);
+ cf = 0;
+ regs.byteregs[regah] = 0;
+ }
+ else {
+ cf = 1;
+ regs.byteregs[regah] = 1;
+ }
+ break;
+ case 4:
+ case 5: //format track
+ cf = 0;
+ regs.byteregs[regah] = 0;
+ break;
+ case 8: //get drive parameters
+ if (disk[regs.byteregs[regdl]].inserted) {
+ cf = 0;
+ regs.byteregs[regah] = 0;
+ regs.byteregs[regch] = disk[regs.byteregs[regdl]].cyls - 1;
+ regs.byteregs[regcl] = disk[regs.byteregs[regdl]].sects & 63;
+ regs.byteregs[regcl] = regs.byteregs[regcl] + (disk[regs.byteregs[regdl]].cyls/256) *64;
+ regs.byteregs[regdh] = disk[regs.byteregs[regdl]].heads - 1;
+ if (regs.byteregs[regdl]<0x80) {
+ regs.byteregs[regbl] = 4; //else regs.byteregs[regbl] = 0;
+ regs.byteregs[regdl] = 2;
+ }
+ else regs.byteregs[regdl] = hdcount;
+ }
+ else {
+ cf = 1;
+ regs.byteregs[regah] = 0xAA;
+ }
+ break;
+ default:
+ cf = 1;
+ }
+ lastdiskah[regs.byteregs[regdl]] = regs.byteregs[regah];
+ lastdiskcf[regs.byteregs[regdl]] = cf;
+ if (regs.byteregs[regdl] & 0x80) RAM[0x474] = regs.byteregs[regah];
+}
diff --git a/src/fake86/disk.h b/src/fake86/disk.h
new file mode 100755
index 0000000..34f062a
--- /dev/null
+++ b/src/fake86/disk.h
@@ -0,0 +1,31 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdint.h>
+#include <stdio.h>
+
+struct struct_drive {
+ FILE *diskfile;
+ uint32_t filesize;
+ uint16_t cyls;
+ uint16_t sects;
+ uint16_t heads;
+ uint8_t inserted;
+ char *filename;
+};
diff --git a/src/fake86/i8237.c b/src/fake86/i8237.c
new file mode 100755
index 0000000..2ad9498
--- /dev/null
+++ b/src/fake86/i8237.c
@@ -0,0 +1,133 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* i8237.c: functions to emulate the Intel 8237 DMA controller.
+ the Sound Blaster emulation functions rely on this! */
+
+#include "config.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+#include "blaster.h"
+#include "i8237.h"
+
+extern struct blaster_s blaster;
+
+struct dmachan_s dmachan[4];
+uint8_t flipflop = 0;
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern uint8_t read86 (uint32_t addr32);
+
+extern uint8_t RAM[0x100000];
+uint8_t read8237 (uint8_t channel) {
+ uint8_t ret;
+ if (dmachan[channel].masked) return (128);
+ if (dmachan[channel].autoinit && (dmachan[channel].count > dmachan[channel].reload) ) dmachan[channel].count = 0;
+ if (dmachan[channel].count > dmachan[channel].reload) return (128);
+ //if (dmachan[channel].direction) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count];
+ // else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count];
+ if (dmachan[channel].direction == 0) ret = RAM[dmachan[channel].page + dmachan[channel].addr + dmachan[channel].count];
+ else ret = RAM[dmachan[channel].page + dmachan[channel].addr - dmachan[channel].count];
+ dmachan[channel].count++;
+ return (ret);
+}
+
+void out8237 (uint16_t addr, uint8_t value) {
+ uint8_t channel;
+#ifdef DEBUG_DMA
+ printf ("out8237(0x%X, %X);\n", addr, value);
+#endif
+ switch (addr) {
+ case 0x2: //channel 1 address register
+ if (flipflop == 1) dmachan[1].addr = (dmachan[1].addr & 0x00FF) | ( (uint32_t) value << 8);
+ else dmachan[1].addr = (dmachan[1].addr & 0xFF00) | value;
+#ifdef DEBUG_DMA
+ if (flipflop == 1) printf ("[NOTICE] DMA channel 1 address register = %04X\n", dmachan[1].addr);
+#endif
+ flipflop = ~flipflop & 1;
+ break;
+ case 0x3: //channel 1 count register
+ if (flipflop == 1) dmachan[1].reload = (dmachan[1].reload & 0x00FF) | ( (uint32_t) value << 8);
+ else dmachan[1].reload = (dmachan[1].reload & 0xFF00) | value;
+ if (flipflop == 1) {
+ if (dmachan[1].reload == 0) dmachan[1].reload = 65536;
+ dmachan[1].count = 0;
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel 1 reload register = %04X\n", dmachan[1].reload);
+#endif
+ }
+ flipflop = ~flipflop & 1;
+ break;
+ case 0xA: //write single mask register
+ channel = value & 3;
+ dmachan[channel].masked = (value >> 2) & 1;
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel %u masking = %u\n", channel, dmachan[channel].masked);
+#endif
+ break;
+ case 0xB: //write mode register
+ channel = value & 3;
+ dmachan[channel].direction = (value >> 5) & 1;
+ dmachan[channel].autoinit = (value >> 4) & 1;
+ dmachan[channel].writemode = (value >> 2) & 1; //not quite accurate
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel %u write mode reg: direction = %u, autoinit = %u, write mode = %u\n",
+ channel, dmachan[channel].direction, dmachan[channel].autoinit, dmachan[channel].writemode);
+#endif
+ break;
+ case 0xC: //clear byte pointer flip-flop
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA cleared byte pointer flip-flop\n");
+#endif
+ flipflop = 0;
+ break;
+ case 0x83: //DMA channel 1 page register
+ dmachan[1].page = (uint32_t) value << 16;
+#ifdef DEBUG_DMA
+ printf ("[NOTICE] DMA channel 1 page base = %05X\n", dmachan[1].page);
+#endif
+ break;
+ }
+}
+
+uint8_t in8237 (uint16_t addr) {
+#ifdef DEBUG_DMA
+ printf ("in8237(0x%X);\n", addr);
+#endif
+ switch (addr) {
+ case 3:
+ if (flipflop == 1) return(dmachan[1].reload >> 8);
+ else return(dmachan[1].reload);
+ flipflop = ~flipflop & 1;
+ break;
+ }
+ return (0);
+}
+
+void init8237() {
+ memset (dmachan, 0, sizeof (dmachan) );
+
+ set_port_write_redirector (0x00, 0x0F, &out8237);
+ set_port_read_redirector (0x00, 0x0F, &in8237);
+
+ set_port_write_redirector (0x80, 0x8F, &out8237);
+ set_port_read_redirector (0x80, 0x8F, &in8237);
+}
diff --git a/src/fake86/i8237.h b/src/fake86/i8237.h
new file mode 100755
index 0000000..ea2e24e
--- /dev/null
+++ b/src/fake86/i8237.h
@@ -0,0 +1,31 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdint.h>
+
+struct dmachan_s {
+ uint32_t page;
+ uint32_t addr;
+ uint32_t reload;
+ uint32_t count;
+ uint8_t direction;
+ uint8_t autoinit;
+ uint8_t writemode;
+ uint8_t masked;
+};
diff --git a/src/fake86/i8253.c b/src/fake86/i8253.c
new file mode 100755
index 0000000..49d30e1
--- /dev/null
+++ b/src/fake86/i8253.c
@@ -0,0 +1,94 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* i8253.c: functions to emulate the Intel 8253 programmable interval timer.
+ these are required for the timer interrupt and PC speaker to be
+ properly emulated! */
+
+#include <stdint.h>
+#include <stdio.h>
+#include <memory.h>
+#include "i8253.h"
+#include "mutex.h"
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+
+struct i8253_s i8253;
+
+extern uint64_t hostfreq, lasttick, curtick, tickgap, totalexec;
+
+void out8253 (uint16_t portnum, uint8_t value) {
+ uint8_t curbyte;
+ portnum &= 3;
+ switch (portnum) {
+ case 0:
+ case 1:
+ case 2: //channel data
+ if ( (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0;
+ else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1;
+ if (curbyte == 0) { //low byte
+ i8253.chandata[portnum] = (i8253.chandata[portnum] & 0xFF00) | value;
+ }
+ else { //high byte
+ i8253.chandata[portnum] = (i8253.chandata[portnum] & 0x00FF) | ( (uint16_t) value << 8);
+ }
+ if (i8253.chandata[portnum] == 0) i8253.effectivedata[portnum] = 65536;
+ else i8253.effectivedata[portnum] = i8253.chandata[portnum];
+ i8253.active[portnum] = 1;
+ tickgap = (uint64_t) ( (float) hostfreq / (float) ( (float) 1193182 / (float) i8253.effectivedata[0]) );
+ if (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1;
+ i8253.chanfreq[portnum] = (float) ( (uint32_t) ( ( (float) 1193182.0 / (float) i8253.effectivedata[portnum]) * (float) 1000.0) ) / (float) 1000.0;
+ //printf("[DEBUG] PIT channel %u counter changed to %u (%f Hz)\n", portnum, i8253.chandata[portnum], i8253.chanfreq[portnum]);
+ break;
+ case 3: //mode/command
+ i8253.accessmode[value>>6] = (value >> 4) & 3;
+ if (i8253.accessmode[value>>6] == PIT_MODE_TOGGLE) i8253.bytetoggle[value>>6] = 0;
+ break;
+ }
+}
+
+uint8_t in8253 (uint16_t portnum) {
+ uint8_t curbyte;
+ portnum &= 3;
+ switch (portnum) {
+ case 0:
+ case 1:
+ case 2: //channel data
+ if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0;
+ else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1;
+ if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_LOBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 0) ) ) curbyte = 0;
+ else if ( (i8253.accessmode[portnum] == PIT_MODE_HIBYTE) || ( (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) && (i8253.bytetoggle[portnum] == 1) ) ) curbyte = 1;
+ if ( (i8253.accessmode[portnum] == 0) || (i8253.accessmode[portnum] == PIT_MODE_TOGGLE) ) i8253.bytetoggle[portnum] = (~i8253.bytetoggle[portnum]) & 1;
+ if (curbyte == 0) { //low byte
+ return ( (uint8_t) i8253.counter[portnum]);
+ }
+ else { //high byte
+ return ( (uint8_t) (i8253.counter[portnum] >> 8) );
+ }
+ break;
+ }
+ return (0);
+}
+
+void init8253() {
+ memset (&i8253, 0, sizeof (i8253) );
+ set_port_write_redirector (0x40, 0x43, &out8253);
+ set_port_read_redirector (0x40, 0x43, &in8253);
+}
diff --git a/src/fake86/i8253.h b/src/fake86/i8253.h
new file mode 100755
index 0000000..de28ccd
--- /dev/null
+++ b/src/fake86/i8253.h
@@ -0,0 +1,33 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#define PIT_MODE_LATCHCOUNT 0
+#define PIT_MODE_LOBYTE 1
+#define PIT_MODE_HIBYTE 2
+#define PIT_MODE_TOGGLE 3
+
+struct i8253_s {
+ uint16_t chandata[3];
+ uint8_t accessmode[3];
+ uint8_t bytetoggle[3];
+ uint32_t effectivedata[3];
+ float chanfreq[3];
+ uint8_t active[3];
+ uint16_t counter[3];
+};
diff --git a/src/fake86/i8259.c b/src/fake86/i8259.c
new file mode 100755
index 0000000..97a297a
--- /dev/null
+++ b/src/fake86/i8259.c
@@ -0,0 +1,99 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* i8259.c: functions to emulate the Intel 8259 prioritized interrupt controller.
+ note: this is not a very complete 8259 implementation, but for the purposes
+ of a PC, it's all we need. */
+
+#include <stdint.h>
+#include <string.h>
+#include "i8259.h"
+
+struct structpic i8259;
+
+extern uint8_t keyboardwaitack;
+
+extern void set_port_write_redirector(uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector(uint16_t startport, uint16_t endport, void *callback);
+
+uint8_t in8259(uint16_t portnum) {
+ switch (portnum & 1) {
+ case 0:
+ if (i8259.readmode==0) return(i8259.irr); else return(i8259.isr);
+ case 1: //read mask register
+ return(i8259.imr);
+ }
+ return (0);
+}
+
+extern uint32_t makeupticks;
+void out8259(uint16_t portnum, uint8_t value) {
+ uint8_t i;
+ switch (portnum & 1) {
+ case 0:
+ if (value & 0x10) { //begin initialization sequence
+ i8259.icwstep = 1;
+ i8259.imr = 0; //clear interrupt mask register
+ i8259.icw[i8259.icwstep++] = value;
+ return;
+ }
+ if ((value & 0x98)==8) { //it's an OCW3
+ if (value & 2) i8259.readmode = value & 2;
+ }
+ if (value & 0x20) { //EOI command
+ keyboardwaitack = 0;
+ for (i=0; i<8; i++)
+ if ((i8259.isr >> i) & 1) {
+ i8259.isr ^= (1 << i);
+ if ((i==0) && (makeupticks>0)) { makeupticks = 0; i8259.irr |= 1; }
+ return;
+ }
+ }
+ break;
+ case 1:
+ if ((i8259.icwstep==3) && (i8259.icw[1] & 2)) i8259.icwstep = 4; //single mode, so don't read ICW3
+ if (i8259.icwstep<5) { i8259.icw[i8259.icwstep++] = value; return; }
+ //if we get to this point, this is just a new IMR value
+ i8259.imr = value;
+ break;
+ }
+}
+
+uint8_t nextintr() {
+ uint8_t i, tmpirr;
+ tmpirr = i8259.irr & (~i8259.imr); //XOR request register with inverted mask register
+ for (i=0; i<8; i++)
+ if ((tmpirr >> i) & 1) {
+ i8259.irr ^= (1 << i);
+ i8259.isr |= (1 << i);
+ return(i8259.icw[2] + i);
+ }
+ return(0); //this won't be reached, but without it the compiler gives a warning
+}
+
+void doirq(uint8_t irqnum) {
+ i8259.irr |= (1 << irqnum);
+ if (irqnum == 1) keyboardwaitack = 1;
+}
+
+void init8259() {
+ memset((void *)&i8259, 0, sizeof(i8259));
+ set_port_write_redirector(0x20, 0x21, &out8259);
+ set_port_read_redirector(0x20, 0x21, &in8259);
+}
diff --git a/src/fake86/i8259.h b/src/fake86/i8259.h
new file mode 100755
index 0000000..4056184
--- /dev/null
+++ b/src/fake86/i8259.h
@@ -0,0 +1,31 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+struct structpic {
+ uint8_t imr; //mask register
+ uint8_t irr; //request register
+ uint8_t isr; //service register
+ uint8_t icwstep; //used during initialization to keep track of which ICW we're at
+ uint8_t icw[5];
+ uint8_t intoffset; //interrupt vector offset
+ uint8_t priority; //which IRQ has highest priority
+ uint8_t autoeoi; //automatic EOI mode
+ uint8_t readmode; //remember what to return on read register from OCW3
+ uint8_t enabled;
+};
diff --git a/src/fake86/input.c b/src/fake86/input.c
new file mode 100755
index 0000000..f92428d
--- /dev/null
+++ b/src/fake86/input.c
@@ -0,0 +1,361 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* input.c: functions for translation of SDL scancodes to BIOS scancodes,
+ and handling of SDL events in general. */
+
+#include <SDL/SDL.h>
+#include <stdint.h>
+#include "sermouse.h"
+
+uint8_t keydown[0x100], keyboardwaitack = 0;
+extern uint32_t usegrabmode;
+
+extern void doirq (uint8_t irqnum);
+extern uint8_t running, portram[0x10000];
+extern SDL_Surface *screen;
+
+uint8_t translatescancode (uint16_t keyval) {
+ switch (keyval) {
+ case 0x1B:
+ return (1);
+ break; //Esc
+ case 0x30:
+ return (0xB);
+ break; //zero
+ case 0x31:
+ case 0x32:
+ case 0x33:
+ case 0x34:
+ case 0x35:
+ case 0x36:
+ case 0x37:
+ case 0x38:
+ case 0x39:
+ return (keyval - 0x2F);
+ break; //other number keys
+ case 0x2D:
+ return (0xC);
+ break; //-_
+ case 0x3D:
+ return (0xD);
+ break; //=+
+ case 0x8:
+ return (0xE);
+ break; //backspace
+ case 0x9:
+ return (0xF);
+ break; //tab
+ case 0x71:
+ return (0x10);
+ break;
+ case 0x77:
+ return (0x11);
+ break;
+ case 0x65:
+ return (0x12);
+ break;
+ case 0x72:
+ return (0x13);
+ break;
+ case 0x74:
+ return (0x14);
+ break;
+ case 0x79:
+ return (0x15);
+ break;
+ case 0x75:
+ return (0x16);
+ break;
+ case 0x69:
+ return (0x17);
+ break;
+ case 0x6F:
+ return (0x18);
+ break;
+ case 0x70:
+ return (0x19);
+ break;
+ case 0x5B:
+ return (0x1A);
+ break;
+ case 0x5D:
+ return (0x1B);
+ break;
+ case 0xD:
+ case 0x10F:
+ return (0x1C);
+ break; //enter
+ case 0x131:
+ case 0x132:
+ return (0x1D);
+ break; //ctrl
+ case 0x61:
+ return (0x1E);
+ break;
+ case 0x73:
+ return (0x1F);
+ break;
+ case 0x64:
+ return (0x20);
+ break;
+ case 0x66:
+ return (0x21);
+ break;
+ case 0x67:
+ return (0x22);
+ break;
+ case 0x68:
+ return (0x23);
+ break;
+ case 0x6A:
+ return (0x24);
+ break;
+ case 0x6B:
+ return (0x25);
+ break;
+ case 0x6C:
+ return (0x26);
+ break;
+ case 0x3B:
+ return (0x27);
+ break;
+ case 0x27:
+ return (0x28);
+ break;
+ case 0x60:
+ return (0x29);
+ break;
+ case 0x130:
+ return (0x2A);
+ break; //left shift
+ case 0x5C:
+ return (0x2B);
+ break;
+ case 0x7A:
+ return (0x2C);
+ break;
+ case 0x78:
+ return (0x2D);
+ break;
+ case 0x63:
+ return (0x2E);
+ break;
+ case 0x76:
+ return (0x2F);
+ break;
+ case 0x62:
+ return (0x30);
+ break;
+ case 0x6E:
+ return (0x31);
+ break;
+ case 0x6D:
+ return (0x32);
+ break;
+ case 0x2C:
+ return (0x33);
+ break;
+ case 0x2E:
+ return (0x34);
+ break;
+ case 0x2F:
+ return (0x35);
+ break;
+ case 0x12F:
+ return (0x36);
+ break; //right shift
+ case 0x13C:
+ return (0x37);
+ break; //print screen
+ case 0x133:
+ case 0x134:
+ return (0x38);
+ break; //alt
+ case 0x20:
+ return (0x39);
+ break; //space
+ case 0x12D:
+ return (0x3A);
+ break; //caps lock
+ case 0x11A:
+ case 0x11B:
+ case 0x11C:
+ case 0x11D:
+ case 0x11E:
+ case 0x11F:
+ case 0x120:
+ case 0x121:
+ case 0x122:
+ case 0x123:
+ return (keyval - 0x11A + 0x3B);
+ break; //F1 to F10
+ case 0x12C:
+ return (0x45);
+ break; //num lock
+ case 0x12E:
+ return (0x46);
+ break; //scroll lock
+ case 0x116:
+ case 0x107:
+ return (0x47);
+ break; //home
+ case 0x111:
+ case 0x108:
+ return (0x48);
+ break; //up
+ case 0x118:
+ case 0x109:
+ return (0x49);
+ break; //pgup
+ case 0x10D:
+ return (0x4A);
+ break; //keypad -
+ case 0x114:
+ case 0x104:
+ return (0x4B);
+ break; //left
+ case 0x105:
+ return (0x4C);
+ break; //center
+ case 0x113:
+ case 0x106:
+ return (0x4D);
+ break; //right
+ case 0x10E:
+ return (0x4E);
+ break; //keypad +
+ case 0x117:
+ case 0x101:
+ return (0x4F);
+ break; //end
+ case 0x112:
+ case 0x102:
+ return (0x50);
+ break; //down
+ case 0x119:
+ case 0x103:
+ return (0x51);
+ break; //pgdn
+ case 0x115:
+ case 0x100:
+ return (0x52);
+ break; //ins
+ case 0x7F:
+ case 0x10A:
+ return (0x53);
+ break; //del
+ default:
+ return (0);
+ }
+}
+
+uint8_t buttons = 0;
+extern void sermouseevent (uint8_t buttons, int8_t xrel, int8_t yrel);
+extern struct sermouse_s sermouse;
+extern void setwindowtitle (uint8_t *extra);
+
+void mousegrabtoggle() {
+ if (usegrabmode == SDL_GRAB_ON) {
+ usegrabmode = SDL_GRAB_OFF;
+ SDL_WM_GrabInput (SDL_GRAB_OFF);
+ SDL_ShowCursor (SDL_ENABLE);
+ setwindowtitle ("");
+ }
+ else {
+ usegrabmode = SDL_GRAB_ON;
+ SDL_WM_GrabInput (SDL_GRAB_ON);
+ SDL_ShowCursor (SDL_DISABLE);
+ setwindowtitle (" (press Ctrl + Alt to release mouse)");
+ }
+}
+
+extern uint8_t scrmodechange;
+extern uint32_t usefullscreen;
+void handleinput() {
+ SDL_Event event;
+ int mx = 0, my = 0;
+ uint8_t tempbuttons;
+ if (SDL_PollEvent (&event) ) {
+ switch (event.type) {
+ case SDL_KEYDOWN:
+ portram[0x60] = translatescancode (event.key.keysym.sym);
+ portram[0x64] |= 2;
+ doirq (1);
+ //printf("%02X\n", translatescancode(event.key.keysym.sym));
+ keydown[translatescancode (event.key.keysym.sym) ] = 1;
+ if (keydown[0x38] && keydown[0x1D] && (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_ON) ) {
+ keydown[0x1D] = 0;
+ keydown[0x32] = 0;
+ mousegrabtoggle();
+ break;
+ }
+ if (keydown[0x38] && keydown[0x1C]) {
+ keydown[0x1D] = 0;
+ keydown[0x38] = 0;
+ if (usefullscreen) usefullscreen = 0;
+ else usefullscreen = SDL_FULLSCREEN;
+ scrmodechange = 1;
+ break;
+ }
+ break;
+ case SDL_KEYUP:
+ portram[0x60] = translatescancode (event.key.keysym.sym) | 0x80;
+ portram[0x64] |= 2;
+ doirq (1);
+ keydown[translatescancode (event.key.keysym.sym) ] = 0;
+ break;
+ case SDL_MOUSEBUTTONDOWN:
+ if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF) {
+ mousegrabtoggle();
+ break;
+ }
+ tempbuttons = SDL_GetMouseState (NULL, NULL);
+ if (tempbuttons & 1) buttons = 2;
+ else buttons = 0;
+ if (tempbuttons & 4) buttons |= 1;
+ sermouseevent (buttons, 0, 0);
+ break;
+ case SDL_MOUSEBUTTONUP:
+ if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF) break;
+ tempbuttons = SDL_GetMouseState (NULL, NULL);
+ if (tempbuttons & 1) buttons = 2;
+ else buttons = 0;
+ if (tempbuttons & 4) buttons |= 1;
+ sermouseevent (buttons, 0, 0);
+ break;
+ case SDL_MOUSEMOTION:
+ if (SDL_WM_GrabInput (SDL_GRAB_QUERY) == SDL_GRAB_OFF) break;
+ SDL_GetRelativeMouseState (&mx, &my);
+ sermouseevent (buttons, (int8_t) mx, (int8_t) my);
+ SDL_WarpMouse (screen->w / 2, screen->h / 2);
+ while (1) {
+ SDL_PollEvent (&event);
+ SDL_GetRelativeMouseState (&mx, &my);
+ if ( (mx == 0) && (my == 0) ) break;
+ }
+ break;
+ case SDL_QUIT:
+ running = 0;
+ break;
+ default:
+ break;
+ }
+ }
+}
diff --git a/src/fake86/main.c b/src/fake86/main.c
new file mode 100755
index 0000000..78b3c43
--- /dev/null
+++ b/src/fake86/main.c
@@ -0,0 +1,321 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* main.c: functions to initialize the different components of Fake86,
+ load ROM binaries, and kickstart the CPU emulator. */
+
+#include "config.h"
+#ifdef __APPLE__ /* Memory leaks occur in OS X when the SDL window gets */
+#include <SDL/SDL.h> /* resized if SDL.h not included in file with main() */
+#endif
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <memory.h>
+#include "mutex.h"
+#ifdef _WIN32
+CRITICAL_SECTION screenmutex;
+#else
+#ifndef __APPLE__
+#include <X11/Xlib.h>
+#endif
+pthread_t consolethread;
+#endif
+
+const uint8_t *build = BUILD_STRING;
+
+extern uint8_t RAM[0x100000], readonly[0x100000];
+extern uint8_t running, renderbenchmark;
+
+extern void reset86();
+extern void exec86 (uint32_t execloops);
+extern uint8_t initscreen (uint8_t *ver);
+extern void VideoThread();
+extern doscrmodechange();
+extern void handleinput();
+
+#ifdef CPU_ADDR_MODE_CACHE
+extern uint64_t cached_access_count, uncached_access_count;
+#endif
+
+extern uint8_t scrmodechange, doaudio;
+extern uint64_t totalexec, totalframes;
+uint64_t starttick, endtick, lasttick;
+
+uint8_t *biosfile = NULL, verbose = 0, cgaonly = 0, useconsole = 0;
+uint32_t speed = 0;
+
+
+uint32_t loadbinary (uint32_t addr32, uint8_t *filename, uint8_t roflag) {
+ FILE *binfile = NULL;
+ uint32_t readsize;
+
+ binfile = fopen (filename, "rb");
+ if (binfile == NULL) {
+ return (0);
+ }
+
+ fseek (binfile, 0, SEEK_END);
+ readsize = ftell (binfile);
+ fseek (binfile, 0, SEEK_SET);
+ fread ( (void *) &RAM[addr32], 1, readsize, binfile);
+ fclose (binfile);
+
+ memset ( (void *) &readonly[addr32], roflag, readsize);
+ return (readsize);
+}
+
+uint32_t loadrom (uint32_t addr32, uint8_t *filename, uint8_t failure_fatal) {
+ uint32_t readsize;
+ readsize = loadbinary (addr32, filename, 1);
+ if (!readsize) {
+ if (failure_fatal) printf("FATAL: ");
+ else printf("WARNING: ");
+ printf ("Unable to load %s\n", filename);
+ return (0);
+ }
+ else {
+ printf ("Loaded %s at 0x%05X (%lu KB)\n", filename, addr32, readsize >> 10);
+ return (readsize);
+ }
+}
+
+uint32_t loadbios (uint8_t *filename) {
+ FILE *binfile = NULL;
+ uint32_t readsize;
+
+ binfile = fopen (filename, "rb");
+ if (binfile == NULL) {
+ return (0);
+ }
+
+ fseek (binfile, 0, SEEK_END);
+ readsize = ftell (binfile);
+ fseek (binfile, 0, SEEK_SET);
+ fread ( (void *) &RAM[0x100000 - readsize], 1, readsize, binfile);
+ fclose (binfile);
+
+ memset ( (void *) &readonly[0x100000 - readsize], 1, readsize);
+ return (readsize);
+}
+
+extern uint32_t SDL_GetTicks();
+extern uint8_t insertdisk (uint8_t drivenum, char *filename);
+extern void ejectdisk (uint8_t drivenum);
+extern uint8_t bootdrive, ethif, net_enabled;
+extern void doirq (uint8_t irqnum);
+//extern void isa_ne2000_init(int baseport, uint8_t irq);
+extern void parsecl (int argc, char *argv[]);
+void timing();
+void tickaudio();
+void inittiming();
+void initaudio();
+void init8253();
+void init8259();
+extern void init8237();
+extern void initVideoPorts();
+extern void killaudio();
+extern void initsermouse (uint16_t baseport, uint8_t irq);
+extern void *port_write_callback[0x10000];
+extern void *port_read_callback[0x10000];
+extern void *port_write_callback16[0x10000];
+extern void *port_read_callback16[0x10000];
+extern void initadlib (uint16_t baseport);
+extern void initsoundsource();
+extern void isa_ne2000_init (uint16_t baseport, uint8_t irq);
+extern void initBlaster (uint16_t baseport, uint8_t irq);
+
+#ifdef NETWORKING_ENABLED
+extern void initpcap();
+extern void dispatch();
+#endif
+
+void printbinary (uint8_t value) {
+ int8_t curbit;
+
+ for (curbit=7; curbit>=0; curbit--) {
+ if ( (value >> curbit) & 1) printf ("1");
+ else printf ("0");
+ }
+}
+
+uint8_t usessource = 0;
+void inithardware() {
+#ifdef NETWORKING_ENABLED
+ if (ethif != 254) initpcap();
+#endif
+ printf ("Initializing emulated hardware:\n");
+ memset (port_write_callback, 0, sizeof (port_write_callback) );
+ memset (port_read_callback, 0, sizeof (port_read_callback) );
+ memset (port_write_callback16, 0, sizeof (port_write_callback16) );
+ memset (port_read_callback16, 0, sizeof (port_read_callback16) );
+ printf (" - Intel 8253 timer: ");
+ init8253();
+ printf ("OK\n");
+ printf (" - Intel 8259 interrupt controller: ");
+ init8259();
+ printf ("OK\n");
+ printf (" - Intel 8237 DMA controller: ");
+ init8237();
+ printf ("OK\n");
+ initVideoPorts();
+ if (usessource) {
+ printf (" - Disney Sound Source: ");
+ initsoundsource();
+ printf ("OK\n");
+ }
+#ifndef NETWORKING_OLDCARD
+ printf (" - Novell NE2000 ethernet adapter: ");
+ isa_ne2000_init (0x300, 6);
+ printf ("OK\n");
+#endif
+ printf (" - Adlib FM music card: ");
+ initadlib (0x388);
+ printf ("OK\n");
+ printf (" - Creative Labs Sound Blaster 2.0: ");
+ initBlaster (0x220, 7);
+ printf ("OK\n");
+ printf (" - Serial mouse (Microsoft compatible): ");
+ initsermouse (0x3F8, 4);
+ printf ("OK\n");
+ if (doaudio) initaudio();
+ inittiming();
+ initscreen ( (uint8_t *) build);
+}
+
+uint8_t dohardreset = 0;
+uint8_t audiobufferfilled();
+
+#ifdef _WIN32
+void initmenus();
+void EmuThread (void *dummy) {
+#else
+pthread_t emuthread;
+void *EmuThread (void *dummy) {
+#endif
+ while (running) {
+ if (!speed) exec86 (10000);
+ else {
+ exec86(speed / 100);
+ while (!audiobufferfilled()) {
+ timing();
+ tickaudio();
+ }
+#ifdef _WIN32
+ Sleep(10);
+#else
+ usleep(10000);
+#endif
+ }
+ if (scrmodechange) doscrmodechange();
+ if (dohardreset) {
+ reset86();
+ dohardreset = 0;
+ }
+ }
+}
+
+#ifdef _WIN32
+void runconsole (void *dummy);
+#else
+void *runconsole (void *dummy);
+#endif
+extern void bufsermousedata (uint8_t value);
+int main (int argc, char *argv[]) {
+ uint32_t biossize;
+
+ printf ("%s (c)2010-2013 Mike Chambers\n", build);
+ printf ("[A portable, open-source 8086 PC emulator]\n\n");
+
+ parsecl (argc, argv);
+
+ memset (readonly, 0, 0x100000);
+ biossize = loadbios (biosfile);
+ if (!biossize) return (-1);
+#ifdef DISK_CONTROLLER_ATA
+ if (!loadrom (0xD0000UL, PATH_DATAFILES "ide_xt.bin", 1) ) return (-1);
+#endif
+ if (biossize <= 8192) {
+ loadrom (0xF6000UL, PATH_DATAFILES "rombasic.bin", 0);
+ if (!loadrom (0xC0000UL, PATH_DATAFILES "videorom.bin", 1) ) return (-1);
+ }
+ printf ("\nInitializing CPU... ");
+ running = 1;
+ reset86();
+ printf ("OK!\n");
+
+#ifndef _WIN32
+#ifndef __APPLE__
+ XInitThreads();
+#endif
+#endif
+ inithardware();
+
+#ifdef _WIN32
+ initmenus();
+ InitializeCriticalSection (&screenmutex);
+#endif
+ if (useconsole) {
+#ifdef _WIN32
+ _beginthread (runconsole, 0, NULL);
+#else
+ pthread_create (&consolethread, NULL, (void *) runconsole, NULL);
+#endif
+ }
+
+#ifdef _WIN32
+ _beginthread (EmuThread, 0, NULL);
+#else
+ pthread_create (&emuthread, NULL, (void *) EmuThread, NULL);
+#endif
+
+ lasttick = starttick = SDL_GetTicks();
+ while (running) {
+ handleinput();
+#ifdef NETWORKING_ENABLED
+ if (ethif < 254) dispatch();
+#endif
+#ifdef _WIN32
+ Sleep(1);
+#else
+ usleep(1000);
+#endif
+ }
+ endtick = (SDL_GetTicks() - starttick) / 1000;
+ if (endtick == 0) endtick = 1; //avoid divide-by-zero exception in the code below, if ran for less than 1 second
+
+ killaudio();
+
+ if (renderbenchmark) {
+ printf ("\n%llu frames rendered in %llu seconds.\n", totalframes, endtick);
+ printf ("Average framerate: %llu FPS.\n", totalframes / endtick);
+ }
+
+ printf ("\n%llu instructions executed in %llu seconds.\n", totalexec, endtick);
+ printf ("Average speed: %llu instructions/second.\n", totalexec / endtick);
+
+#ifdef CPU_ADDR_MODE_CACHE
+ printf ("\n Cached modregrm data access count: %llu\n", cached_access_count);
+ printf ("Uncached modregrm data access count: %llu\n", uncached_access_count);
+#endif
+
+ if (useconsole) exit (0); //makes sure console thread quits even if blocking
+
+ return (0);
+}
diff --git a/src/fake86/modregrm.h b/src/fake86/modregrm.h
new file mode 100644
index 0000000..026e030
--- /dev/null
+++ b/src/fake86/modregrm.h
@@ -0,0 +1,129 @@
+#include "config.h"
+
+#ifdef CPU_ADDR_MODE_CACHE
+struct addrmodecache_s addrcache[0x100000];
+uint8_t addrcachevalid[0x100000];
+
+uint32_t addrdatalen, dataisvalid, setvalidptr;
+uint64_t cached_access_count = 0, uncached_access_count = 0;
+#define modregrm() { \
+ tempaddr32 = (((uint32_t)savecs << 4) + ip) & 0xFFFFF; \
+ if (addrcachevalid[tempaddr32]) { \
+ switch (addrcache[tempaddr32].len) { \
+ case 0: \
+ dataisvalid = 1; \
+ break; \
+ case 1: \
+ if (addrcachevalid[tempaddr32+1]) dataisvalid = 1; else dataisvalid = 0; \
+ break; \
+ case 2: \
+ if (addrcachevalid[tempaddr32+1] && addrcachevalid[tempaddr32+2]) dataisvalid = 1; else dataisvalid = 0; \
+ break; \
+ } \
+ } else dataisvalid = 0; \
+ if (dataisvalid) { \
+ cached_access_count++; \
+ disp16 = addrcache[tempaddr32].disp16; \
+ segregs[regcs] = addrcache[tempaddr32].exitcs; \
+ ip = addrcache[tempaddr32].exitip; \
+ mode = addrcache[tempaddr32].mode; \
+ reg = addrcache[tempaddr32].reg; \
+ rm = addrcache[tempaddr32].rm; \
+ if ((!segoverride) && addrcache[tempaddr32].forcess) useseg = segregs[regss]; \
+ } else { \
+ uncached_access_count++; \
+ addrbyte = getmem8(segregs[regcs], ip); \
+ StepIP(1); \
+ mode = addrbyte >> 6; \
+ reg = (addrbyte >> 3) & 7; \
+ rm = addrbyte & 7; \
+ addrdatalen = 0; \
+ addrcache[tempaddr32].forcess = 0; \
+ switch(mode) \
+ { \
+ case 0: \
+ if(rm == 6) { \
+ disp16 = getmem16(segregs[regcs], ip); \
+ addrdatalen = 2; \
+ StepIP(2); \
+ } \
+ if (((rm == 2) || (rm == 3))) { \
+ if (!segoverride) useseg = segregs[regss]; \
+ addrcache[tempaddr32].forcess = 1; \
+ } \
+ break; \
+ \
+ case 1: \
+ disp16 = signext(getmem8(segregs[regcs], ip)); \
+ addrdatalen = 1; \
+ StepIP(1); \
+ if (((rm == 2) || (rm == 3) || (rm == 6))) { \
+ if (!segoverride) useseg = segregs[regss]; \
+ addrcache[tempaddr32].forcess = 1; \
+ } \
+ break; \
+ \
+ case 2: \
+ disp16 = getmem16(segregs[regcs], ip); \
+ addrdatalen = 2; \
+ StepIP(2); \
+ if (((rm == 2) || (rm == 3) || (rm == 6))) { \
+ if (!segoverride) useseg = segregs[regss]; \
+ addrcache[tempaddr32].forcess = 1; \
+ } \
+ break; \
+ \
+ default: \
+ disp16 = 0; \
+ } \
+ addrcache[tempaddr32].disp16 = disp16; \
+ addrcache[tempaddr32].exitcs = segregs[regcs]; \
+ addrcache[tempaddr32].exitip = ip; \
+ addrcache[tempaddr32].mode = mode; \
+ addrcache[tempaddr32].reg = reg; \
+ addrcache[tempaddr32].rm = rm; \
+ addrcache[tempaddr32].len = addrdatalen; \
+ memset(&addrcachevalid[tempaddr32], 1, addrdatalen+1); \
+ } \
+}
+#else
+#define modregrm() { \
+ addrbyte = getmem8(segregs[regcs], ip); \
+ StepIP(1); \
+ mode = addrbyte >> 6; \
+ reg = (addrbyte >> 3) & 7; \
+ rm = addrbyte & 7; \
+ switch(mode) \
+ { \
+ case 0: \
+ if(rm == 6) { \
+ disp16 = getmem16(segregs[regcs], ip); \
+ StepIP(2); \
+ } \
+ if(((rm == 2) || (rm == 3)) && !segoverride) { \
+ useseg = segregs[regss]; \
+ } \
+ break; \
+ \
+ case 1: \
+ disp16 = signext(getmem8(segregs[regcs], ip)); \
+ StepIP(1); \
+ if(((rm == 2) || (rm == 3) || (rm == 6)) && !segoverride) { \
+ useseg = segregs[regss]; \
+ } \
+ break; \
+ \
+ case 2: \
+ disp16 = getmem16(segregs[regcs], ip); \
+ StepIP(2); \
+ if(((rm == 2) || (rm == 3) || (rm == 6)) && !segoverride) { \
+ useseg = segregs[regss]; \
+ } \
+ break; \
+ \
+ default: \
+ disp8 = 0; \
+ disp16 = 0; \
+ } \
+}
+#endif \ No newline at end of file
diff --git a/src/fake86/mutex.h b/src/fake86/mutex.h
new file mode 100755
index 0000000..e0f665d
--- /dev/null
+++ b/src/fake86/mutex.h
@@ -0,0 +1,29 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#ifdef _WIN32
+ #include <Windows.h>
+ #include <process.h>
+ #define MutexLock(mutex) EnterCriticalSection(&mutex)
+ #define MutexUnlock(mutex) LeaveCriticalSection(&mutex)
+#else
+ #include <pthread.h>
+ #define MutexLock(mutex) pthread_mutex_lock(&mutex)
+ #define MutexUnlock(mutex) pthread_mutex_unlock(&mutex)
+#endif
diff --git a/src/fake86/netcard.c b/src/fake86/netcard.c
new file mode 100755
index 0000000..ab7d6d5
--- /dev/null
+++ b/src/fake86/netcard.c
@@ -0,0 +1,83 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* netcard.c: this is a simple custom ethernet adapter interface for Fake86.
+ it's not modeled after a real-world ethernet adapter, thus i had to create
+ own DOS packet driver for programs to make use of it. this packet driver
+ is included with this source code, in the data/ directory. the filename is
+ pd.com - inject this file into any floppy or hard disk image if needed! */
+
+#include "config.h"
+#ifdef NETWORKING_ENABLED
+#ifdef NETWORKING_OLDCARD
+#include <stdio.h>
+#include <string.h>
+#include <stdint.h>
+#include "cpu.h"
+
+extern uint8_t verbose;
+extern union _bytewordregs_ regs;
+extern uint8_t RAM[0x100000], readonly[0x100000], ethif;
+extern uint16_t segregs[4];
+extern void sendpkt (uint8_t *src, uint16_t len);
+
+struct netstruct {
+ uint8_t enabled;
+ uint8_t canrecv;
+ uint16_t pktlen;
+} net;
+
+void nethandler() {
+ uint32_t i;
+ if (ethif==254) return; //networking not enabled
+ switch (regs.byteregs[regah]) { //function number
+ case 0x00: //enable packet reception
+ net.enabled = 1;
+ net.canrecv = 1;
+ return;
+ case 0x01: //send packet of CX at DS:SI
+ if (verbose) {
+ printf ("Sending packet of %u bytes.\n", regs.wordregs[regcx]);
+ }
+ sendpkt (&RAM[ ( (uint32_t) segregs[regds] << 4) + (uint32_t) regs.wordregs[regsi]], regs.wordregs[regcx]);
+ return;
+ case 0x02: //return packet info (packet buffer in DS:SI, length in CX)
+ segregs[regds] = 0xD000;
+ regs.wordregs[regsi] = 0x0000;
+ regs.wordregs[regcx] = net.pktlen;
+ return;
+ case 0x03: //copy packet to final destination (given in ES:DI)
+ memcpy (&RAM[ ( (uint32_t) segregs[reges] << 4) + (uint32_t) regs.wordregs[regdi]], &RAM[0xD0000], net.pktlen);
+ return;
+ case 0x04: //disable packets
+ net.enabled = 0;
+ net.canrecv = 0;
+ return;
+ case 0x05: //DEBUG: dump packet (DS:SI) of CX bytes to stdout
+ for (i=0; i<regs.wordregs[regcx]; i++) {
+ printf ("%c", RAM[ ( (uint32_t) segregs[regds] << 4) + (uint32_t) regs.wordregs[regsi] + i]);
+ }
+ return;
+ case 0x06: //DEBUG: print milestone string
+ //print("PACKET DRIVER MILESTONE REACHED\n");
+ return;
+ }
+}
+#endif
+#endif
diff --git a/src/fake86/packet.c b/src/fake86/packet.c
new file mode 100755
index 0000000..38ce12e
--- /dev/null
+++ b/src/fake86/packet.c
@@ -0,0 +1,185 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* packet.c: functions to interface with libpcap/winpcap for ethernet emulation. */
+
+#include "config.h"
+
+#ifdef NETWORKING_ENABLED
+#define HAVE_REMOTE
+#define WPCAP
+#include <pcap.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <memory.h>
+
+#ifndef _WIN32
+#define PCAP_OPENFLAG_PROMISCUOUS 1
+#endif
+
+extern uint8_t RAM[0x100000];
+extern uint8_t verbose;
+uint8_t ethif, net_enabled = 0;
+uint8_t dopktrecv = 0;
+uint16_t rcvseg, rcvoff, hdrlen, handpkt;
+
+pcap_if_t *alldevs;
+pcap_if_t *d;
+pcap_t *adhandle;
+const u_char *pktdata;
+struct pcap_pkthdr *hdr;
+int inum;
+uint16_t curhandle = 0;
+char errbuf[PCAP_ERRBUF_SIZE];
+uint8_t maclocal[6] = { 0xDE, 0xAD, 0xBE, 0xEF, 0x13, 0x37 };
+
+void initpcap() {
+ int i=0;
+
+ printf ("\nObtaining NIC list via libpcap...\n");
+
+ /* Retrieve the device list from the local machine */
+#if defined(_WIN32)
+ if (pcap_findalldevs_ex (PCAP_SRC_IF_STRING, NULL /* auth is not needed */, &alldevs, errbuf) == -1)
+#else
+ if (pcap_findalldevs (&alldevs, errbuf) == -1)
+#endif
+ {
+ printf ("Error in pcap_findalldevs_ex: %s\n", errbuf);
+ exit (1);
+ }
+
+ /* Print the list */
+ for (d= alldevs; d != NULL; d= d->next) {
+ i++;
+ if (ethif==255) {
+ printf ("%d. %s", i, d->name);
+ if (d->description) {
+ printf (" (%s)\n", d->description);
+ }
+ else {
+ printf (" (No description available)\n");
+ }
+ }
+ }
+
+ if (i == 0) {
+ printf ("\nNo interfaces found! Make sure WinPcap is installed.\n");
+ return;
+ }
+
+ printf ("\n");
+
+ if (ethif==255) exit (0);
+ else inum = ethif;
+ printf ("Using network interface %u.\n", ethif);
+
+
+ if (inum < 1 || inum > i) {
+ printf ("\nInterface number out of range.\n");
+ /* Free the device list */
+ pcap_freealldevs (alldevs);
+ return;
+ }
+
+ /* Jump to the selected adapter */
+ for (d=alldevs, i=0; i< inum-1 ; d=d->next, i++);
+
+ /* Open the device */
+#ifdef _WIN32
+ if ( (adhandle= pcap_open (d->name, 65536, PCAP_OPENFLAG_PROMISCUOUS, -1, NULL, errbuf) ) == NULL)
+#else
+ if ( (adhandle= pcap_open_live (d->name, 65535, 1, -1, NULL) ) == NULL)
+#endif
+ {
+ printf ("\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
+ /* Free the device list */
+ pcap_freealldevs (alldevs);
+ return;
+ }
+
+ printf ("\nEthernet bridge on %s...\n", d->description);
+
+ /* At this point, we don't need any more the device list. Free it */
+ pcap_freealldevs (alldevs);
+ net_enabled = 1;
+}
+
+void setmac() {
+ memcpy (&RAM[0xE0000], &maclocal[0], 6);
+}
+
+#ifndef NETWORKING_OLDCARD
+extern int ne2000_can_receive();
+extern void ne2000_receive (const uint8_t *buf, int size);
+
+uint8_t newrecv[5000];
+
+void dispatch() {
+ uint16_t i;
+
+ if (pcap_next_ex (adhandle, &hdr, &pktdata) <=0) return;
+ if (hdr->len==0) return;
+ if (ne2000_can_receive() ) {
+ for (i=0; i<hdr->len; i++) {
+ newrecv[i<<1] = pktdata[i];
+ newrecv[ (i<<1) +1] = 0;
+ }
+ ne2000_receive (newrecv, hdr->len);
+ }
+ return;
+}
+
+void sendpkt (uint8_t *src, uint16_t len) {
+ uint16_t i;
+ for (i=0; i<len; i++) {
+ printf ("%02X ", src[i]);
+ }
+ printf ("\n");
+ pcap_sendpacket (adhandle, src, len);
+}
+#else
+extern struct netstruct {
+ uint8_t enabled;
+ uint8_t canrecv;
+ uint16_t pktlen;
+} net;
+
+extern void doirq (uint8_t irqnum);
+
+void dispatch() {
+ if (pcap_next_ex (adhandle, &hdr, &pktdata) <=0) return;
+ if (hdr->len==0) return;
+
+ net.canrecv = 0;
+ memcpy (&RAM[0xD0000], &pktdata[0], hdr->len);
+ net.pktlen = (uint16_t) hdr->len;
+ if (verbose) {
+ printf ("Received packet of %u bytes.\n", net.pktlen);
+ }
+ doirq (6);
+ return;
+}
+
+void sendpkt (uint8_t *src, uint16_t len) {
+ pcap_sendpacket (adhandle, src, len);
+}
+#endif
+
+#endif
diff --git a/src/fake86/parsecl.c b/src/fake86/parsecl.c
new file mode 100755
index 0000000..8751920
--- /dev/null
+++ b/src/fake86/parsecl.c
@@ -0,0 +1,228 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* parsecl.c: Fake86 command line parsing for runtime options. */
+
+#include "config.h"
+#include <SDL/SDL.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "disk.h"
+
+extern struct struct_drive disk[256];
+#ifndef _WIN32
+#define strcmpi strcasecmp
+#else
+#define strcmpi _strcmpi
+#endif
+
+extern uint8_t bootdrive, ethif, verbose, cgaonly, *biosfile, usessource, noscale, nosmooth, renderbenchmark, useconsole, doaudio;
+extern uint32_t framedelay, textbase, usefullscreen, speed;
+extern int32_t usesamplerate, latency;
+uint16_t constantw = 0, constanth = 0;
+uint8_t slowsystem = 0;
+
+extern uint8_t insertdisk (uint8_t drivenum, char *filename);
+extern uint32_t loadrom (uint32_t addr32, uint8_t *filename, uint8_t failure_fatal);
+
+uint32_t hextouint(char *src) {
+ uint32_t tempuint = 0, cc;
+ uint16_t i;
+
+ for (i=0; i<strlen(src); i++) {
+ cc = src[i];
+ if (cc == 0) break;
+ if ((cc >= 'a') && (cc <= 'F')) cc = cc - 'a' + 10;
+ else if ((cc >= 'A') && (cc <= 'F')) cc = cc - 'A' + 10;
+ else if ((cc >= '0') && (cc <= '9')) cc = cc - '0';
+ else return(0);
+ tempuint <<= 4;
+ tempuint |= cc;
+ }
+ return(tempuint);
+}
+
+void showhelp () {
+ printf ("Fake86 requires some command line parameters to run.\nValid options:\n");
+
+ printf (" -fd0 filename Specify a floppy disk image file to use as floppy 0.\n");
+ printf (" -fd1 filename Specify a floppy disk image file to use as floppy 1.\n");
+ printf (" -hd0 filename Specify a hard disk image file to use as hard drive 0.\n");
+ printf (" -hd1 filename Specify a hard disk image file to use as hard drive 1.\n");
+ printf (" -boot # Specify which BIOS drive ID should be the boot device in #.\n");
+ printf (" Examples: -boot 0 will boot from floppy 0.\n");
+ printf (" -boot 1 will boot from floppy 1.\n");
+ printf (" -boot 128 will boot from hard drive 0.\n");
+ printf (" -boot rom will boot to ROM BASIC if available.\n");
+ printf (" Default boot device is hard drive 0, if it exists.\n");
+ printf (" Otherwise, the default is floppy 0.\n");
+ printf (" -bios filename Specify alternate BIOS ROM image to use.\n");
+#ifdef NETWORKING_ENABLED
+#ifdef _WIN32
+ printf (" -net # Enable ethernet emulation via winpcap, where # is the\n");
+#else
+ printf (" -net # Enable ethernet emulation via libpcap, where # is the\n");
+#endif
+ printf (" numeric ID of your host's network interface to bridge.\n");
+ printf (" To get a list of possible interfaces, use -net list\n");
+#endif
+ printf (" -nosound Disable audio emulation and output.\n");
+ printf (" -fullscreen Start Fake86 in fullscreen mode.\n");
+ printf (" -verbose Verbose mode. Operation details will be written to stdout.\n");
+ printf (" -delay Specify how many milliseconds the render thread should idle\n");
+ printf (" between drawing each frame. Default is 20 ms. (~50 FPS)\n");
+ printf (" -slowsys If your machine is very slow and you have audio dropouts,\n");
+ printf (" use this option to sacrifice audio quality to compensate.\n");
+ printf (" If you still have dropouts, then also decrease sample rate\n");
+ printf (" and/or increase latency.\n");
+ printf (" -resw # -resh # Force a constant window size in pixels.\n");
+ printf (" -smooth Apply smoothing to screen rendering.\n");
+ printf (" -noscale Disable 2x scaling of low resolution video modes.\n");
+ printf (" -ssource Enable Disney Sound Source emulation on LPT1.\n");
+ printf (" -latency # Change audio buffering and output latency. (default: 100 ms)\n");
+ printf (" -samprate # Change audio emulation sample rate. (default: 48000 Hz)\n");
+ printf (" -console Enable console on stdio during emulation.\n");
+ printf (" -oprom addr rom Inject a custom option ROM binary at an address in hex.\n");
+ printf (" Example: -oprom F4000 monitor.bin\n");
+ printf (" This loads the data from monitor.bin at 0xF4000.\n");
+
+ printf ("\nThis program is free software; you can redistribute it and/or\n");
+ printf ("modify it under the terms of the GNU General Public License\n");
+ printf ("as published by the Free Software Foundation; either version 2\n");
+ printf ("of the License, or (at your option) any later version.\n\n");
+
+ printf ("This program is distributed in the hope that it will be useful,\n");
+ printf ("but WITHOUT ANY WARRANTY; without even the implied warranty of\n");
+ printf ("MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n");
+ printf ("GNU General Public License for more details.\n");
+
+ exit (0);
+}
+
+void parsecl (int argc, char *argv[]) {
+ uint32_t tempuint;
+ int i, abort = 0;
+
+ if (argc<2) {
+ printf ("Invoke Fake86 with the parameter -h for help and usage information.\n");
+#ifndef _WIN32
+ exit (0);
+#endif
+ }
+
+ bootdrive = 254;
+ textbase = 0xB8000;
+ ethif = 254;
+ usefullscreen = 0;
+ biosfile = PATH_DATAFILES "pcxtbios.bin";
+ for (i=1; i<argc; i++) {
+ if (strcmpi (argv[i], "-h") ==0) showhelp ();
+ else if (strcmpi (argv[i], "-?") ==0) showhelp ();
+ else if (strcmpi (argv[i], "-help") ==0) showhelp ();
+ else if (strcmpi (argv[i], "-fd0") ==0) {
+ i++;
+ if (insertdisk (0, argv[i]) ) {
+ printf ("ERROR: Unable to open image file %s\n", argv[i]);
+ }
+ }
+ else if (strcmpi (argv[i], "-fd1") ==0) {
+ i++;
+ if (insertdisk (1, argv[i]) ) {
+ printf ("ERROR: Unable to open image file %s\n", argv[i]);
+ }
+ }
+ else if (strcmpi (argv[i], "-hd0") ==0) {
+ i++;
+ if (insertdisk (0x80, argv[i]) ) {
+ printf ("ERROR: Unable to open image file %s\n", argv[i]);
+ }
+ }
+ else if (strcmpi (argv[i], "-hd1") ==0) {
+ i++;
+ if (insertdisk (0x81, argv[i]) ) {
+ printf ("ERROR: Unable to open image file %s\n", argv[i]);
+ }
+ }
+ else if (strcmpi (argv[i], "-net") ==0) {
+ i++;
+ if (strcmpi (argv[i], "list") ==0) ethif = 255;
+ else ethif = atoi (argv[i]);
+ }
+ else if (strcmpi (argv[i], "-boot") ==0) {
+ i++;
+ if (strcmpi (argv[i], "rom") ==0) bootdrive = 255;
+ else bootdrive = atoi (argv[i]);
+ }
+ else if (strcmpi (argv[i], "-ssource") ==0) {
+ i++;
+ usessource = 1;
+ }
+ else if (strcmpi (argv[i], "-latency") ==0) {
+ i++;
+ latency = atol (argv[i]);
+ }
+ else if (strcmpi (argv[i], "-samprate") ==0) {
+ i++;
+ usesamplerate = atol (argv[i]);
+ }
+ else if (strcmpi (argv[i], "-bios") ==0) {
+ i++;
+ biosfile = argv[i];
+ }
+ else if (strcmpi (argv[i], "-resw") ==0) {
+ i++;
+ constantw = (uint16_t) atoi (argv[i]);
+ }
+ else if (strcmpi (argv[i], "-resh") ==0) {
+ i++;
+ constanth = (uint16_t) atoi (argv[i]);
+ }
+ else if (strcmpi (argv[i], "-speed") ==0) {
+ i++;
+ speed= (uint32_t) atol (argv[i]);
+ }
+ else if (strcmpi (argv[i], "-noscale") ==0) noscale = 1;
+ else if (strcmpi (argv[i], "-verbose") ==0) verbose = 1;
+ else if (strcmpi (argv[i], "-smooth") ==0) nosmooth = 0;
+ else if (strcmpi (argv[i], "-fps") ==0) renderbenchmark = 1;
+ else if (strcmpi (argv[i], "-nosound") ==0) doaudio = 0;
+ else if (strcmpi (argv[i], "-fullscreen") ==0) usefullscreen = SDL_FULLSCREEN;
+ else if (strcmpi (argv[i], "-delay") ==0) framedelay = atol (argv[++i]);
+ else if (strcmpi (argv[i], "-console") ==0) useconsole = 1;
+ else if (strcmpi (argv[i], "-slowsys") ==0) slowsystem = 1;
+ else if (strcmpi (argv[i], "-oprom") ==0) {
+ i++;
+ tempuint = hextouint (argv[i++]);
+ loadrom (tempuint, argv[i], 0);
+ }
+ else {
+ printf ("Unrecognized parameter: %s\n", argv[i]);
+ exit (1);
+ }
+ }
+
+ if (bootdrive==254) {
+ if (disk[0x80].inserted) bootdrive = 0x80;
+ else if (disk[0x00].inserted) bootdrive = 0;
+ else bootdrive = 0xFF; //ROM BASIC fallback
+ }
+}
+
+
diff --git a/src/fake86/ports.c b/src/fake86/ports.c
new file mode 100755
index 0000000..88f047a
--- /dev/null
+++ b/src/fake86/ports.c
@@ -0,0 +1,119 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* ports.c: functions to handle port I/O from the CPU module, as well
+ as functions for emulated hardware components to register their
+ read/write callback functions across the port address range. */
+
+#include <stdint.h>
+#include <stdio.h>
+#include "cpu.h"
+
+extern uint8_t portram[0x10000];
+extern uint8_t speakerenabled;
+extern uint8_t keyboardwaitack;
+
+void (*do_callback_write) (uint16_t portnum, uint8_t value) = NULL;
+uint8_t (*do_callback_read) (uint16_t portnum) = NULL;
+void (*do_callback_write16) (uint16_t portnum, uint16_t value) = NULL;
+uint16_t (*do_callback_read16) (uint16_t portnum) = NULL;
+void * (port_write_callback[0x10000]);
+void * (port_read_callback[0x10000]);
+void * (port_write_callback16[0x10000]);
+void * (port_read_callback16[0x10000]);
+
+extern uint8_t verbose;
+void portout (uint16_t portnum, uint8_t value) {
+ portram[portnum] = value;
+ //if (verbose) printf("portout(0x%X, 0x%02X);\n", portnum, value);
+ switch (portnum) {
+ case 0x61:
+ if ( (value & 3) == 3) speakerenabled = 1;
+ else speakerenabled = 0;
+ return;
+ }
+ do_callback_write = (void (*) (uint16_t portnum, uint8_t value) ) port_write_callback[portnum];
+ if (do_callback_write != (void *) 0) (*do_callback_write) (portnum, value);
+}
+
+uint8_t portin (uint16_t portnum) {
+ //if (verbose) printf("portin(0x%X);\n", portnum);
+ switch (portnum) {
+ case 0x62:
+ return (0x00);
+ case 0x60:
+ case 0x61:
+ case 0x63:
+ case 0x64:
+ return (portram[portnum]);
+ }
+ do_callback_read = (uint8_t (*) (uint16_t portnum) ) port_read_callback[portnum];
+ if (do_callback_read != (void *) 0) return ( (*do_callback_read) (portnum) );
+ return (0xFF);
+}
+
+void portout16 (uint16_t portnum, uint16_t value) {
+ do_callback_write16 = (void (*) (uint16_t portnum, uint16_t value) ) port_write_callback16[portnum];
+ if (do_callback_write16 != (void *) 0) {
+ (*do_callback_write16) (portnum, value);
+ return;
+ }
+
+ portout (portnum, (uint8_t) value);
+ portout (portnum + 1, (uint8_t) (value >> 8) );
+}
+
+uint16_t portin16 (uint16_t portnum) {
+ uint16_t ret;
+
+ do_callback_read16 = (uint16_t (*) (uint16_t portnum) ) port_read_callback16[portnum];
+ if (do_callback_read16 != (void *) 0) return ( (*do_callback_read16) (portnum) );
+
+ ret = (uint16_t) portin (portnum);
+ ret |= (uint16_t) portin (portnum+1) << 8;
+ return (ret);
+}
+
+void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback) {
+ uint16_t i;
+ for (i=startport; i<=endport; i++) {
+ port_write_callback[i] = callback;
+ }
+}
+
+void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback) {
+ uint16_t i;
+ for (i=startport; i<=endport; i++) {
+ port_read_callback[i] = callback;
+ }
+}
+
+void set_port_write_redirector_16 (uint16_t startport, uint16_t endport, void *callback) {
+ uint16_t i;
+ for (i=startport; i<=endport; i++) {
+ port_write_callback16[i] = callback;
+ }
+}
+
+void set_port_read_redirector_16 (uint16_t startport, uint16_t endport, void *callback) {
+ uint16_t i;
+ for (i=startport; i<=endport; i++) {
+ port_read_callback16[i] = callback;
+ }
+}
diff --git a/src/fake86/render.c b/src/fake86/render.c
new file mode 100755
index 0000000..4f51639
--- /dev/null
+++ b/src/fake86/render.c
@@ -0,0 +1,570 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* render.c: functions for SDL initialization, as well as video scaling/rendering.
+ it is a bit messy. i plan to rework much of this in the future. i am also
+ going to add hardware accelerated scaling soon. */
+
+#include <SDL/SDL.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "mutex.h"
+
+#ifdef _WIN32
+CRITICAL_SECTION screenmutex;
+#else
+pthread_t vidthread;
+pthread_mutex_t screenmutex = PTHREAD_MUTEX_INITIALIZER;
+#endif
+
+SDL_Surface *screen = NULL;
+uint32_t *scalemap = NULL;
+uint8_t regenscalemap = 1;
+
+extern uint8_t RAM[0x100000], portram[0x10000];
+extern uint8_t VRAM[262144], vidmode, cgabg, blankattr, vidgfxmode, vidcolor, running;
+extern uint16_t cursx, cursy, cols, rows, vgapage, cursorposition, cursorvisible;
+extern uint8_t updatedscreen, clocksafe, port3da, port6, portout16;
+extern uint16_t VGA_SC[0x100], VGA_CRTC[0x100], VGA_ATTR[0x100], VGA_GC[0x100];
+extern uint32_t videobase, textbase, x, y;
+extern uint8_t fontcga[32768];
+extern uint32_t palettecga[16], palettevga[256];
+extern uint32_t usefullscreen, usegrabmode;
+
+uint64_t totalframes = 0;
+uint32_t framedelay = 20;
+uint8_t scrmodechange = 0, noscale = 0, nosmooth = 1, renderbenchmark = 0, doaudio = 1;
+char windowtitle[128];
+
+void initcga();
+#ifdef _WIN32
+void VideoThread (void *dummy);
+#else
+void *VideoThread (void *dummy);
+#endif
+
+void setwindowtitle (uint8_t *extra) {
+ char temptext[128];
+ sprintf (temptext, "%s%s", windowtitle, extra);
+ SDL_WM_SetCaption ( (const char *) temptext, NULL);
+}
+
+uint8_t initscreen (uint8_t *ver) {
+ if (doaudio) {
+ if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) ) return (0);
+ }
+ else {
+ if (SDL_Init (SDL_INIT_VIDEO | SDL_INIT_TIMER) ) return (0);
+ }
+ screen = SDL_SetVideoMode (640, 400, 32, SDL_HWSURFACE);
+ if (screen == NULL) return (0);
+ sprintf (windowtitle, "%s", ver);
+ setwindowtitle ("");
+ initcga();
+#ifdef _WIN32
+ InitializeCriticalSection (&screenmutex);
+ _beginthread (VideoThread, 0, NULL);
+#else
+ pthread_create (&vidthread, NULL, (void *) VideoThread, NULL);
+#endif
+
+ return (1);
+}
+
+uint32_t prestretch[1024][1024];
+uint32_t nw, nh; //native width and height, pre-stretching (i.e. 320x200 for mode 13h)
+void createscalemap() {
+ uint32_t srcx, srcy, dstx, dsty, scalemapptr;
+ double xscale, yscale;
+
+ xscale = (double) nw / (double) screen->w;
+ yscale = (double) nh / (double) screen->h;
+ if (scalemap != NULL) free(scalemap);
+ scalemap = (void *)malloc( ((uint32_t)screen->w + 1) * (uint32_t)screen->h * 4);
+ if (scalemap == NULL) {
+ printf("\nFATAL: Unable to allocate memory for scalemap!\n");
+ exit(1);
+ }
+ scalemapptr = 0;
+ for (dsty=0; dsty<(uint32_t)screen->h; dsty++) {
+ srcy = (uint32_t) ( (double) dsty * yscale);
+ scalemap[scalemapptr++] = srcy;
+ for (dstx=0; dstx<(uint32_t)screen->w; dstx++) {
+ srcx = (uint32_t) ( (double) dstx * xscale);
+ scalemap[scalemapptr++] = srcx;
+ }
+ }
+
+ regenscalemap = 0;
+}
+
+extern uint16_t oldw, oldh, constantw, constanth;
+void draw();
+extern void handleinput();
+#ifdef _WIN32
+void VideoThread (void *dummy) {
+#else
+void *VideoThread (void *dummy) {
+#endif
+ uint32_t cursorprevtick, cursorcurtick, delaycalc;
+ cursorprevtick = SDL_GetTicks();
+ cursorvisible = 0;
+
+ while (running) {
+ cursorcurtick = SDL_GetTicks();
+ if ( (cursorcurtick - cursorprevtick) >= 250) {
+ updatedscreen = 1;
+ cursorvisible = ~cursorvisible & 1;
+ cursorprevtick = cursorcurtick;
+ }
+
+ if (updatedscreen || renderbenchmark) {
+ updatedscreen = 0;
+ if (screen != NULL) {
+ MutexLock (screenmutex);
+ if (regenscalemap) createscalemap();
+ draw();
+ MutexUnlock (screenmutex);
+ }
+ totalframes++;
+ }
+ if (!renderbenchmark) {
+ delaycalc = framedelay - (SDL_GetTicks() - cursorcurtick);
+ if (delaycalc > framedelay) delaycalc = framedelay;
+ SDL_Delay (delaycalc);
+ }
+ }
+}
+
+#ifdef _WIN32
+void ShowMenu();
+void HideMenu();
+#endif
+
+void doscrmodechange() {
+ MutexLock (screenmutex);
+ if (scrmodechange) {
+ if (screen != NULL) SDL_FreeSurface (screen);
+#ifdef _WIN32
+ if (usefullscreen) HideMenu(); else ShowMenu();
+#endif
+ if (constantw && constanth) screen = SDL_SetVideoMode (constantw, constanth, 32, SDL_HWSURFACE | usefullscreen);
+ else if (noscale) screen = SDL_SetVideoMode (nw, nh, 32, SDL_HWSURFACE | usefullscreen);
+ else {
+ if ( (nw >= 640) || (nh >= 400) ) screen = SDL_SetVideoMode (nw, nh, 32, SDL_HWSURFACE | usefullscreen);
+ else screen = SDL_SetVideoMode (640, 400, 32, SDL_HWSURFACE | usefullscreen);
+ }
+ if (usefullscreen) SDL_WM_GrabInput (SDL_GRAB_ON); //always have mouse grab turned on for full screen mode
+ else SDL_WM_GrabInput (usegrabmode);
+ SDL_ShowCursor (SDL_DISABLE);
+ if (!usefullscreen) {
+ if (usegrabmode == SDL_GRAB_ON) setwindowtitle (" (press Ctrl + Alt to release mouse)");
+ else setwindowtitle ("");
+ }
+ regenscalemap = 1;
+ createscalemap();
+ }
+ MutexUnlock (screenmutex);
+ scrmodechange = 0;
+}
+
+void stretchblit (SDL_Surface *target) {
+ uint32_t srcx, srcy, dstx, dsty, lastx, lasty, r, g, b;
+ uint32_t consecutivex, consecutivey = 0, limitx, limity, scalemapptr;
+ uint32_t ofs;
+ uint8_t *pixelrgb;
+
+ limitx = (uint32_t)((double) nw / (double) target->w);
+ limity = (uint32_t)((double) nh / (double) target->h);
+
+ if (SDL_MUSTLOCK (target) )
+ if (SDL_LockSurface (target) < 0)
+ return;
+
+ lasty = 0;
+ scalemapptr = 0;
+ for (dsty=0; dsty<(uint32_t)target->h; dsty++) {
+ srcy = scalemap[scalemapptr++];
+ ofs = dsty*target->w;
+ consecutivex = 0;
+ lastx = 0;
+ if (srcy == lasty) consecutivey++;
+ else consecutivey = 0;
+ for (dstx=0; dstx<(uint32_t)target->w; dstx++) {
+ srcx = scalemap[scalemapptr++];
+ pixelrgb = (uint8_t *) &prestretch[srcy][srcx];
+ r = pixelrgb[0];
+ g = pixelrgb[1];
+ b = pixelrgb[2];
+ if (srcx == lastx) consecutivex++;
+ else consecutivex = 0;
+ if ( (consecutivex > limitx) && (consecutivey > limity) ) {
+ pixelrgb = (uint8_t *) &prestretch[srcy][srcx+1];
+ r += pixelrgb[0];
+ g += pixelrgb[1];
+ b += pixelrgb[2];
+ pixelrgb = (uint8_t *) &prestretch[srcy+1][srcx];
+ r += pixelrgb[0];
+ g += pixelrgb[1];
+ b += pixelrgb[2];
+ pixelrgb = (uint8_t *) &prestretch[srcy+1][srcx+1];
+ r += pixelrgb[0];
+ g += pixelrgb[1];
+ b += pixelrgb[2];
+ r = r >> 2;
+ g = g >> 2;
+ b = b >> 2;
+ //r = 255; g = 0; b = 0;
+ }
+ else if (consecutivex > limitx) {
+ pixelrgb = (uint8_t *) &prestretch[srcy][srcx+1];
+ r += pixelrgb[0];
+ r = r >> 1;
+ g += pixelrgb[1];
+ g = g >> 1;
+ b += pixelrgb[2];
+ b = b >> 1;
+ //r = 0; g = 255; b = 0;
+ }
+ else if (consecutivey > limity) {
+ pixelrgb = (uint8_t *) &prestretch[srcy+1][srcx];
+ r += pixelrgb[0];
+ r = r >> 1;
+ g += pixelrgb[1];
+ g = g >> 1;
+ b += pixelrgb[2];
+ b = b >> 1;
+ //r = 0; g = 0; b = 255;
+ }
+ ( (uint32_t *) target->pixels) [ofs++] = SDL_MapRGB (target->format, (uint8_t) r, (uint8_t) g, (uint8_t) b);
+ lastx = srcx;
+ }
+ lasty = srcy;
+ }
+
+ if (SDL_MUSTLOCK (target) )
+ SDL_UnlockSurface (target);
+ SDL_UpdateRect (target, 0, 0, target->w, target->h);
+}
+
+void roughblit (SDL_Surface *target) {
+ uint32_t srcx, srcy, dstx, dsty, scalemapptr;
+ int32_t ofs;
+ uint8_t *pixelrgb;
+
+ if (SDL_MUSTLOCK (target) )
+ if (SDL_LockSurface (target) < 0)
+ return;
+
+ scalemapptr = 0;
+ for (dsty=0; dsty<(uint32_t)target->h; dsty++) {
+ srcy = scalemap[scalemapptr++];
+ ofs = dsty*target->w;
+ for (dstx=0; dstx<(uint32_t)target->w; dstx++) {
+ srcx = scalemap[scalemapptr++];
+ pixelrgb = (uint8_t *) &prestretch[srcy][srcx];
+ ( (uint32_t *) target->pixels) [ofs++] = SDL_MapRGB (target->format, pixelrgb[0], pixelrgb[1], pixelrgb[2]);
+ }
+ }
+
+ if (SDL_MUSTLOCK (target) )
+ SDL_UnlockSurface (target);
+ SDL_UpdateRect (target, 0, 0, target->w, target->h);
+}
+
+/* NOTE: doubleblit is only used when smoothing is not enabled, and the SDL window size
+ is exactly double of native resolution for the current video mode. we can take
+ advantage of the fact that every pixel is simply doubled both horizontally and
+ vertically. this way, we do not need to waste mountains of CPU time doing
+ floating point multiplication for each and every on-screen pixel. it makes the
+ difference between games being smooth and playable, and being jerky on my old
+ 400 MHz PowerPC G3 iMac.
+*/
+void doubleblit (SDL_Surface *target) {
+ uint32_t srcx, srcy, dstx, dsty, curcolor;
+ int32_t ofs, startofs;
+ uint8_t *pixelrgb;
+
+ if (SDL_MUSTLOCK (target) )
+ if (SDL_LockSurface (target) < 0)
+ return;
+
+ for (dsty=0; dsty<(uint32_t)target->h; dsty += 2) {
+ srcy = (uint32_t) (dsty >> 1);
+ startofs = ofs = dsty*target->w;
+ for (dstx=0; dstx<(uint32_t)target->w; dstx += 2) {
+ srcx = (uint32_t) (dstx >> 1);
+ pixelrgb = (uint8_t *) &prestretch[srcy][srcx];
+ curcolor = SDL_MapRGB (target->format, pixelrgb[0], pixelrgb[1], pixelrgb[2]);
+ ( (uint32_t *) target->pixels) [ofs+target->w] = curcolor;
+ ( (uint32_t *) target->pixels) [ofs++] = curcolor;
+ ( (uint32_t *) target->pixels) [ofs+target->w] = curcolor;
+ ( (uint32_t *) target->pixels) [ofs++] = curcolor;
+ }
+ }
+
+ if (SDL_MUSTLOCK (target) )
+ SDL_UnlockSurface (target);
+ SDL_UpdateRect (target, 0, 0, target->w, target->h);
+}
+
+extern uint16_t vtotal;
+void draw () {
+ uint32_t planemode, vgapage, color, chary, charx, vidptr, divx, divy, curchar, curpixel, usepal, intensity, blockw, curheight, x1, y1;
+ switch (vidmode) {
+ case 0:
+ case 1:
+ case 2: //text modes
+ case 3:
+ case 7:
+ case 0x82:
+ nw = 640;
+ nh = 400;
+ vgapage = ( (uint32_t) VGA_CRTC[0xC]<<8) + (uint32_t) VGA_CRTC[0xD];
+ for (y=0; y<400; y++)
+ for (x=0; x<640; x++) {
+ if (cols==80) {
+ charx = x/8;
+ divx = 1;
+ }
+ else {
+ charx = x/16;
+ divx = 2;
+ }
+ if ( (portram[0x3D8]==9) && (portram[0x3D4]==9) ) {
+ chary = y/4;
+ vidptr = vgapage + videobase + chary*cols*2 + charx*2;
+ curchar = RAM[vidptr];
+ color = fontcga[curchar*128 + (y%4) *8 + ( (x/divx) %8) ];
+ }
+ else {
+ chary = y/16;
+ vidptr = videobase + chary*cols*2 + charx*2;
+ curchar = RAM[vidptr];
+ color = fontcga[curchar*128 + (y%16) *8 + ( (x/divx) %8) ];
+ }
+ if (vidcolor) {
+ /*if (!color) if (portram[0x3D8]&128) color = palettecga[ (RAM[vidptr+1]/16) &7];
+ else*/ if (!color) color = palettecga[RAM[vidptr+1]/16]; //high intensity background
+ else color = palettecga[RAM[vidptr+1]&15];
+ }
+ else {
+ if ( (RAM[vidptr+1] & 0x70) ) {
+ if (!color) color = palettecga[7];
+ else color = palettecga[0];
+ }
+ else {
+ if (!color) color = palettecga[0];
+ else color = palettecga[7];
+ }
+ }
+ prestretch[y][x] = color;
+ }
+ break;
+ case 4:
+ case 5:
+ nw = 320;
+ nh = 200;
+ usepal = (portram[0x3D9]>>5) & 1;
+ intensity = ( (portram[0x3D9]>>4) & 1) << 3;
+ for (y=0; y<200; y++) {
+ for (x=0; x<320; x++) {
+ charx = x;
+ chary = y;
+ vidptr = videobase + ( (chary>>1) * 80) + ( (chary & 1) * 8192) + (charx >> 2);
+ curpixel = RAM[vidptr];
+ switch (charx & 3) {
+ case 3:
+ curpixel = curpixel & 3;
+ break;
+ case 2:
+ curpixel = (curpixel>>2) & 3;
+ break;
+ case 1:
+ curpixel = (curpixel>>4) & 3;
+ break;
+ case 0:
+ curpixel = (curpixel>>6) & 3;
+ break;
+ }
+ if (vidmode==4) {
+ curpixel = curpixel * 2 + usepal + intensity;
+ if (curpixel == (usepal + intensity) ) curpixel = cgabg;
+ color = palettecga[curpixel];
+ prestretch[y][x] = color;
+ }
+ else {
+ curpixel = curpixel * 63;
+ color = palettecga[curpixel];
+ prestretch[y][x] = color;
+ }
+ }
+ }
+ break;
+ case 6:
+ nw = 640;
+ nh = 200;
+ for (y=0; y<400; y+=2) {
+ for (x=0; x<640; x++) {
+ charx = x;
+ chary = y >> 1;
+ vidptr = videobase + ( (chary>>1) * 80) + ( (chary&1) * 8192) + (charx>>3);
+ curpixel = (RAM[vidptr]>> (7- (charx&7) ) ) &1;
+ color = palettecga[curpixel*15];
+ prestretch[y][x] = color;
+ prestretch[y+1][x] = color;
+ }
+ }
+ break;
+ case 127:
+ nw = 720;
+ nh = 348;
+ for (y=0; y<348; y++) {
+ for (x=0; x<720; x++) {
+ charx = x;
+ chary = y>>1;
+ vidptr = videobase + ( (y & 3) << 13) + (y >> 2) *90 + (x >> 3);
+ curpixel = (RAM[vidptr]>> (7- (charx&7) ) ) &1;
+#ifdef __BIG_ENDIAN__
+ if (curpixel) color = 0xFFFFFF00;
+#else
+ if (curpixel) color = 0x00FFFFFF;
+#endif
+ else color = 0x00000000;
+ prestretch[y][x] = color;
+ }
+ }
+ break;
+ case 0x8: //160x200 16-color (PCjr)
+ nw = 640; //fix this
+ nh = 400; //part later
+ for (y=0; y<400; y++)
+ for (x=0; x<640; x++) {
+ vidptr = 0xB8000 + (y>>2) *80 + (x>>3) + ( (y>>1) &1) *8192;
+ if ( ( (x>>1) &1) ==0) color = palettecga[RAM[vidptr] >> 4];
+ else color = palettecga[RAM[vidptr] & 15];
+ prestretch[y][x] = color;
+ }
+ break;
+ case 0x9: //320x200 16-color (Tandy/PCjr)
+ nw = 640; //fix this
+ nh = 400; //part later
+ for (y=0; y<400; y++)
+ for (x=0; x<640; x++) {
+ vidptr = 0xB8000 + (y>>3) *160 + (x>>2) + ( (y>>1) &3) *8192;
+ if ( ( (x>>1) &1) ==0) color = palettecga[RAM[vidptr] >> 4];
+ else color = palettecga[RAM[vidptr] & 15];
+ prestretch[y][x] = color;
+ }
+ break;
+ case 0xD:
+ case 0xE:
+ nw = 640; //fix this
+ nh = 400; //part later
+ for (y=0; y<400; y++)
+ for (x=0; x<640; x++) {
+ divx = x>>1;
+ divy = y>>1;
+ vidptr = divy*40 + (divx>>3);
+ x1 = 7 - (divx & 7);
+ color = (VRAM[vidptr] >> x1) & 1;
+ color += ( ( (VRAM[0x10000 + vidptr] >> x1) & 1) << 1);
+ color += ( ( (VRAM[0x20000 + vidptr] >> x1) & 1) << 2);
+ color += ( ( (VRAM[0x30000 + vidptr] >> x1) & 1) << 3);
+ color = palettevga[color];
+ prestretch[y][x] = color;
+ }
+ break;
+ case 0x10:
+ nw = 640;
+ nh = 350;
+ for (y=0; y<350; y++)
+ for (x=0; x<640; x++) {
+ vidptr = y*80 + (x>>3);
+ x1 = 7 - (x & 7);
+ color = (VRAM[vidptr] >> x1) & 1;
+ color |= ( ( (VRAM[0x10000 + vidptr] >> x1) & 1) << 1);
+ color |= ( ( (VRAM[0x20000 + vidptr] >> x1) & 1) << 2);
+ color |= ( ( (VRAM[0x30000 + vidptr] >> x1) & 1) << 3);
+ color = palettevga[color];
+ prestretch[y][x] = color;
+ }
+ break;
+ case 0x12:
+ nw = 640;
+ nh = 480;
+ vgapage = ( (uint32_t) VGA_CRTC[0xC]<<8) + (uint32_t) VGA_CRTC[0xD];
+ for (y=0; y<nh; y++)
+ for (x=0; x<nw; x++) {
+ vidptr = y*80 + (x/8);
+ color = (VRAM[vidptr] >> (~x & 7) ) & 1;
+ color |= ( (VRAM[vidptr+0x10000] >> (~x & 7) ) & 1) << 1;
+ color |= ( (VRAM[vidptr+0x20000] >> (~x & 7) ) & 1) << 2;
+ color |= ( (VRAM[vidptr+0x30000] >> (~x & 7) ) & 1) << 3;
+ prestretch[y][x] = palettevga[color];
+ }
+ break;
+ case 0x13:
+ if (vtotal == 11) { //ugly hack to show Flashback at the proper resolution
+ nw = 256;
+ nh = 224;
+ }
+ else {
+ nw = 320;
+ nh = 200;
+ }
+ if (VGA_SC[4] & 6) planemode = 1;
+ else planemode = 0;
+ //vgapage = ( (uint32_t) VGA_CRTC[0xC]<<8) + (uint32_t) VGA_CRTC[0xD];
+ vgapage = (( (uint32_t) VGA_CRTC[0xC]<<8) + (uint32_t) VGA_CRTC[0xD]) << 2;
+ for (y=0; y<nh; y++)
+ for (x=0; x<nw; x++) {
+ if (!planemode) color = palettevga[RAM[videobase + ((vgapage + y*nw + x) & 0xFFFF) ]];
+ //if (!planemode) color = palettevga[RAM[videobase + y*nw + x]];
+ else {
+ vidptr = y*nw + x;
+ vidptr = vidptr/4 + (x & 3) *0x10000;
+ vidptr = vidptr + vgapage - (VGA_ATTR[0x13] & 15);
+ color = palettevga[VRAM[vidptr]];
+ }
+ prestretch[y][x] = color;
+ }
+ }
+
+ if (vidgfxmode==0) {
+ if (cursorvisible) {
+ curheight = 2;
+ if (cols==80) blockw = 8;
+ else blockw = 16;
+ x1 = cursx * blockw;
+ y1 = cursy * 8 + 8 - curheight;
+ for (y=y1*2; y<=y1*2+curheight-1; y++)
+ for (x=x1; x<=x1+blockw-1; x++) {
+ color = palettecga[RAM[videobase+cursy*cols*2+cursx*2+1]&15];
+ prestretch[y&1023][x&1023] = color;
+ }
+ }
+ }
+ if (nosmooth) {
+ if ( ((nw << 1) == screen->w) && ((nh << 1) == screen->h) ) doubleblit (screen);
+ else roughblit (screen);
+ }
+ else stretchblit (screen);
+}
+
diff --git a/src/fake86/sermouse.c b/src/fake86/sermouse.c
new file mode 100755
index 0000000..98e25ab
--- /dev/null
+++ b/src/fake86/sermouse.c
@@ -0,0 +1,97 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* sermouse.c: functions to emulate a standard Microsoft-compatible serial mouse. */
+
+#include "config.h"
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include "sermouse.h"
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void doirq (uint8_t irqnum);
+
+struct sermouse_s sermouse;
+
+void bufsermousedata (uint8_t value) {
+ if (sermouse.bufptr == 16) return;
+ if (sermouse.bufptr == 0 ) doirq (4);
+ sermouse.buf[sermouse.bufptr++] = value;
+}
+
+void outsermouse (uint16_t portnum, uint8_t value) {
+ uint8_t oldreg;
+ //printf("[DEBUG] Serial mouse, port %X out: %02X\n", portnum, value);
+ portnum &= 7;
+ oldreg = sermouse.reg[portnum];
+ sermouse.reg[portnum] = value;
+ switch (portnum) {
+ case 4: //modem control register
+ if ( (value & 1) != (oldreg & 1) ) { //software toggling of this register
+ sermouse.bufptr = 0; //causes the mouse to reset and fill the buffer
+ bufsermousedata ('M'); //with a bunch of ASCII 'M' characters.
+ bufsermousedata ('M'); //this is intended to be a way for
+ bufsermousedata ('M'); //drivers to verify that there is
+ bufsermousedata ('M'); //actually a mouse connected to the port.
+ bufsermousedata ('M');
+ bufsermousedata ('M');
+ }
+ break;
+ }
+}
+
+uint8_t insermouse (uint16_t portnum) {
+ uint8_t temp;
+ //printf("[DEBUG] Serial mouse, port %X in\n", portnum);
+ portnum &= 7;
+ switch (portnum) {
+ case 0: //data receive
+ temp = sermouse.buf[0];
+ memmove (sermouse.buf, &sermouse.buf[1], 15);
+ sermouse.bufptr--;
+ if (sermouse.bufptr < 0) sermouse.bufptr = 0;
+ if (sermouse.bufptr > 0) doirq (4);
+ sermouse.reg[4] = ~sermouse.reg[4] & 1;
+ return (temp);
+ case 5: //line status register (read-only)
+ if (sermouse.bufptr > 0) temp = 1;
+ else temp = 0;
+ return (0x1);
+ return (0x60 | temp);
+ }
+ return (sermouse.reg[portnum & 7]);
+}
+
+void initsermouse (uint16_t baseport, uint8_t irq) {
+ sermouse.bufptr = 0;
+ set_port_write_redirector (baseport, baseport + 7, &outsermouse);
+ set_port_read_redirector (baseport, baseport + 7, &insermouse);
+}
+
+void sermouseevent (uint8_t buttons, int8_t xrel, int8_t yrel) {
+ uint8_t highbits = 0;
+ if (xrel < 0) highbits = 3;
+ else highbits = 0;
+ if (yrel < 0) highbits |= 12;
+ bufsermousedata (0x40 | (buttons << 4) | highbits);
+ bufsermousedata (xrel & 63);
+ bufsermousedata (yrel & 63);
+}
diff --git a/src/fake86/sermouse.h b/src/fake86/sermouse.h
new file mode 100755
index 0000000..d9d71ba
--- /dev/null
+++ b/src/fake86/sermouse.h
@@ -0,0 +1,26 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdint.h>
+
+struct sermouse_s {
+ uint8_t reg[8];
+ uint8_t buf[16];
+ int8_t bufptr;
+};
diff --git a/src/fake86/sndsource.c b/src/fake86/sndsource.c
new file mode 100755
index 0000000..515d1c7
--- /dev/null
+++ b/src/fake86/sndsource.c
@@ -0,0 +1,82 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* ssource.c: functions to emulate the Disney Sound Source's 16-byte FIFO buffer. */
+
+#include "config.h"
+#include <stdint.h>
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+
+extern uint8_t portram[0x10000];
+uint8_t ssourcebuf[16], ssourceptr = 0, ssourceactive = 0;
+int16_t ssourcecursample = 0;
+
+int16_t getssourcebyte() {
+ return (ssourcecursample);
+}
+
+void tickssource() {
+ uint8_t rotatefifo;
+ if ( (ssourceptr==0) || (!ssourceactive) ) {
+ ssourcecursample = 0;
+ return;
+ }
+ ssourcecursample = ssourcebuf[0];
+ for (rotatefifo=1; rotatefifo<16; rotatefifo++)
+ ssourcebuf[rotatefifo-1] = ssourcebuf[rotatefifo];
+ ssourceptr--;
+ portram[0x379] = 0;
+}
+
+void putssourcebyte (uint8_t value) {
+ if (ssourceptr==16) return;
+ ssourcebuf[ssourceptr++] = value;
+ if (ssourceptr==16) portram[0x379] = 0x40;
+}
+
+uint8_t ssourcefull() {
+ if (ssourceptr==16) return (0x40);
+ else return (0x00);
+}
+
+void outsoundsource (uint16_t portnum, uint8_t value) {
+ static uint8_t last37a = 0;
+ switch (portnum) {
+ case 0x378:
+ putssourcebyte (value);
+ break;
+ case 0x37A:
+ if ( (value & 4) && ! (last37a & 4) ) putssourcebyte (portram[0x378]);
+ last37a = value;
+ break;
+ }
+}
+
+uint8_t insoundsource (uint16_t portnum) {
+ return (ssourcefull() );
+}
+
+void initsoundsource() {
+ set_port_write_redirector (0x378, 0x378, &outsoundsource);
+ set_port_write_redirector (0x37A, 0x37A, &outsoundsource);
+ set_port_read_redirector (0x379, 0x379, &insoundsource);
+ ssourceactive = 1;
+}
diff --git a/src/fake86/speaker.c b/src/fake86/speaker.c
new file mode 100755
index 0000000..df3e651
--- /dev/null
+++ b/src/fake86/speaker.c
@@ -0,0 +1,47 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* speaker.c: function to generate output samples for PC speaker emulation. */
+
+#include "config.h"
+#include <stdint.h>
+#include "i8253.h"
+#include "mutex.h"
+
+extern struct i8253_s i8253;
+
+extern uint64_t gensamplerate;
+uint64_t speakerfullstep, speakerhalfstep, speakercurstep = 0;
+int16_t speakerpos = 0;
+
+int16_t speakergensample() {
+ int16_t speakervalue;
+
+ speakerfullstep = (uint64_t) ( (float) gensamplerate / (float) i8253.chanfreq[2]);
+ if (speakerfullstep < 2) speakerfullstep = 2;
+ speakerhalfstep = speakerfullstep >> 1;
+ if (speakercurstep < speakerhalfstep) {
+ speakervalue = 32;
+ }
+ else {
+ speakervalue = -32;
+ }
+ speakercurstep = (speakercurstep + 1) % speakerfullstep;
+ return (speakervalue);
+}
diff --git a/src/fake86/timing.c b/src/fake86/timing.c
new file mode 100755
index 0000000..b3c4b23
--- /dev/null
+++ b/src/fake86/timing.c
@@ -0,0 +1,136 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* timing.c: critical functions to provide accurate timing for the
+ system timer interrupt, and to generate new audio output samples. */
+
+#include "config.h"
+#include <SDL/SDL.h>
+#include <stdint.h>
+#include <stdio.h>
+#ifdef _WIN32
+#include <Windows.h>
+LARGE_INTEGER queryperf;
+#else
+#include <sys/time.h>
+struct timeval tv;
+#endif
+#include "i8253.h"
+#include "blaster.h"
+
+extern struct blaster_s blaster;
+extern struct i8253_s i8253;
+extern void doirq (uint8_t irqnum);
+extern void tickaudio();
+extern void tickssource();
+extern void tickadlib();
+extern void tickBlaster();
+
+uint64_t hostfreq = 1000000, lasttick = 0, curtick = 0, tickgap, i8253tickgap, lasti8253tick, scanlinetiming, lastscanlinetick, curscanline = 0;
+uint64_t sampleticks, lastsampletick, ssourceticks, lastssourcetick, adlibticks, lastadlibtick, lastblastertick, gensamplerate;
+
+uint16_t pit0counter = 65535;
+extern uint64_t totalexec;
+extern uint32_t speed;
+extern uint8_t port3da, doaudio, slowsystem;
+
+void inittiming() {
+#ifdef _WIN32
+ QueryPerformanceFrequency (&queryperf);
+ hostfreq = queryperf.QuadPart;
+ QueryPerformanceCounter (&queryperf);
+ curtick = queryperf.QuadPart;
+#else
+ hostfreq = 1000000;
+ gettimeofday (&tv, NULL);
+ curtick = (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
+#endif
+ lasti8253tick = lastblastertick = lastadlibtick = lastssourcetick = lastsampletick = lastscanlinetick = lasttick = curtick;
+ scanlinetiming = hostfreq / 31500;
+ ssourceticks = hostfreq / 8000;
+ adlibticks = hostfreq / 48000;
+ if (doaudio) sampleticks = hostfreq / gensamplerate;
+ else sampleticks = -1;
+ i8253tickgap = hostfreq / 119318;
+}
+
+void timing() {
+ uint8_t i8253chan;
+
+#ifdef _WIN32
+ QueryPerformanceCounter (&queryperf);
+ curtick = queryperf.QuadPart;
+#else
+ gettimeofday (&tv, NULL);
+ curtick = (uint64_t) tv.tv_sec * (uint64_t) 1000000 + (uint64_t) tv.tv_usec;
+#endif
+
+ if (curtick >= (lastscanlinetick + scanlinetiming) ) {
+ curscanline = (curscanline + 1) % 525;
+ if (curscanline > 479) port3da = 8;
+ else port3da = 0;
+ if (curscanline & 1) port3da |= 1;
+ pit0counter++;
+ lastscanlinetick = curtick;
+ }
+
+ if (i8253.active[0]) { //timer interrupt channel on i8253
+ if (curtick >= (lasttick + tickgap) ) {
+ lasttick = curtick;
+ doirq (0);
+ }
+ }
+
+ if (curtick >= (lasti8253tick + i8253tickgap) ) {
+ for (i8253chan=0; i8253chan<3; i8253chan++) {
+ if (i8253.active[i8253chan]) {
+ if (i8253.counter[i8253chan] < 10) i8253.counter[i8253chan] = i8253.chandata[i8253chan];
+ i8253.counter[i8253chan] -= 10;
+ }
+ }
+ lasti8253tick = curtick;
+ }
+
+ if (curtick >= (lastssourcetick + ssourceticks) ) {
+ tickssource();
+ lastssourcetick = curtick - (curtick - (lastssourcetick + ssourceticks) );
+ }
+
+ if (blaster.samplerate > 0) {
+ if (curtick >= (lastblastertick + blaster.sampleticks) ) {
+ tickBlaster();
+ lastblastertick = curtick - (curtick - (lastblastertick + blaster.sampleticks) );
+ }
+ }
+
+ if (curtick >= (lastsampletick + sampleticks) ) {
+ tickaudio();
+ if (slowsystem) {
+ tickaudio();
+ tickaudio();
+ tickaudio();
+ }
+ lastsampletick = curtick - (curtick - (lastsampletick + sampleticks) );
+ }
+
+ if (curtick >= (lastadlibtick + adlibticks) ) {
+ tickadlib();
+ lastadlibtick = curtick - (curtick - (lastadlibtick + adlibticks) );
+ }
+}
diff --git a/src/fake86/video.c b/src/fake86/video.c
new file mode 100755
index 0000000..95c9c61
--- /dev/null
+++ b/src/fake86/video.c
@@ -0,0 +1,841 @@
+/*
+ Fake86: A portable, open-source 8086 PC emulator.
+ Copyright (C)2010-2013 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+/* video.c: many various functions to emulate bits of the video controller.
+ a lot of this code is inefficient, and just plain ugly. i plan to rework
+ large sections of it soon. */
+
+#include <SDL/SDL.h>
+#include <stdint.h>
+#include <stdio.h>
+#include "mutex.h"
+#include "cpu.h"
+
+extern void set_port_write_redirector (uint16_t startport, uint16_t endport, void *callback);
+extern void set_port_read_redirector (uint16_t startport, uint16_t endport, void *callback);
+
+extern SDL_Surface *screen;
+extern uint8_t verbose;
+extern union _bytewordregs_ regs;
+extern uint8_t RAM[0x100000], readonly[0x100000];
+extern uint8_t portram[0x10000];
+extern uint16_t segregs[4];
+
+extern uint8_t read86 (uint32_t addr32);
+extern uint8_t write86 (uint32_t addr32, uint8_t value);
+extern uint8_t scrmodechange;
+
+uint8_t VRAM[262144], vidmode, cgabg, blankattr, vidgfxmode, vidcolor;
+uint16_t cursx, cursy, cols = 80, rows = 25, vgapage, cursorposition, cursorvisible;
+uint8_t updatedscreen, clocksafe, port3da, port6, portout16;
+uint16_t VGA_SC[0x100], VGA_CRTC[0x100], VGA_ATTR[0x100], VGA_GC[0x100];
+uint32_t videobase= 0xB8000, textbase = 0xB8000, x, y;
+uint8_t fontcga[32768];
+uint32_t palettecga[16], palettevga[256];
+uint32_t usefullscreen = 0, usegrabmode = SDL_GRAB_OFF;
+
+uint8_t latchRGB = 0, latchPal = 0, VGA_latch[4], stateDAC = 0;
+uint8_t latchReadRGB = 0, latchReadPal = 0;
+uint32_t tempRGB;
+uint16_t oldw, oldh; //used when restoring screen mode
+
+uint32_t rgb(uint32_t r, uint32_t g, uint32_t b) {
+#ifdef __BIG_ENDIAN__
+ return ( (r<<24) | (g<<16) | (b<<8) );
+#else
+ return (r | (g<<8) | (b<<16) );
+#endif
+}
+
+extern uint32_t nw, nh;
+void vidinterrupt() {
+ uint32_t tempcalc, memloc, n;
+ updatedscreen = 1;
+ switch (regs.byteregs[regah]) { //what video interrupt function?
+ case 0: //set video mode
+ if (verbose) {
+ printf ("Set video mode %02Xh\n", regs.byteregs[regal]);
+ }
+ VGA_SC[0x4] = 0; //VGA modes are in chained mode by default after a mode switch
+ //regs.byteregs[regal] = 3;
+ switch (regs.byteregs[regal] & 0x7F) {
+ case 0: //40x25 mono text
+ videobase = textbase;
+ cols = 40;
+ rows = 25;
+ vidcolor = 0;
+ vidgfxmode = 0;
+ blankattr = 7;
+ for (tempcalc = videobase; tempcalc<videobase+16384; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ break;
+ case 1: //40x25 color text
+ videobase = textbase;
+ cols = 40;
+ rows = 25;
+ vidcolor = 1;
+ vidgfxmode = 0;
+ blankattr = 7;
+ for (tempcalc = videobase; tempcalc<videobase+16384; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ portram[0x3D8] = portram[0x3D8] & 0xFE;
+ break;
+ case 2: //80x25 mono text
+ videobase = textbase;
+ cols = 80;
+ rows = 25;
+ vidcolor = 1;
+ vidgfxmode = 0;
+ blankattr = 7;
+ for (tempcalc = videobase; tempcalc<videobase+16384; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ portram[0x3D8] = portram[0x3D8] & 0xFE;
+ break;
+ case 3: //80x25 color text
+ videobase = textbase;
+ cols = 80;
+ rows = 25;
+ vidcolor = 1;
+ vidgfxmode = 0;
+ blankattr = 7;
+ for (tempcalc = videobase; tempcalc<videobase+16384; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ portram[0x3D8] = portram[0x3D8] & 0xFE;
+ break;
+ case 4:
+ case 5: //80x25 color text
+ videobase = textbase;
+ cols = 40;
+ rows = 25;
+ vidcolor = 1;
+ vidgfxmode = 1;
+ blankattr = 7;
+ for (tempcalc = videobase; tempcalc<videobase+16384; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ if (regs.byteregs[regal]==4) portram[0x3D9] = 48;
+ else portram[0x3D9] = 0;
+ break;
+ case 6:
+ videobase = textbase;
+ cols = 80;
+ rows = 25;
+ vidcolor = 0;
+ vidgfxmode = 1;
+ blankattr = 7;
+ for (tempcalc = videobase; tempcalc<videobase+16384; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ portram[0x3D8] = portram[0x3D8] & 0xFE;
+ break;
+ case 127:
+ videobase = 0xB8000;
+ cols = 90;
+ rows = 25;
+ vidcolor = 0;
+ vidgfxmode = 1;
+ for (tempcalc = videobase; tempcalc<videobase+16384; tempcalc++) {
+ RAM[tempcalc] = 0;
+ }
+ portram[0x3D8] = portram[0x3D8] & 0xFE;
+ break;
+ case 0x9: //320x200 16-color
+ videobase = 0xB8000;
+ cols = 40;
+ rows = 25;
+ vidcolor = 1;
+ vidgfxmode = 1;
+ blankattr = 0;
+ if ( (regs.byteregs[regal]&0x80) ==0) for (tempcalc = videobase; tempcalc<videobase+65535; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ portram[0x3D8] = portram[0x3D8] & 0xFE;
+ break;
+ case 0xD: //320x200 16-color
+ case 0x12: //640x480 16-color
+ case 0x13: //320x200 256-color
+ videobase = 0xA0000;
+ cols = 40;
+ rows = 25;
+ vidcolor = 1;
+ vidgfxmode = 1;
+ blankattr = 0;
+ for (tempcalc = videobase; tempcalc<videobase+65535; tempcalc+=2) {
+ RAM[tempcalc] = 0;
+ RAM[tempcalc+1] = blankattr;
+ }
+ portram[0x3D8] = portram[0x3D8] & 0xFE;
+ break;
+ }
+ vidmode = regs.byteregs[regal] & 0x7F;
+ RAM[0x449] = vidmode;
+ RAM[0x44A] = (uint8_t) cols;
+ RAM[0x44B] = 0;
+ RAM[0x484] = (uint8_t) (rows - 1);
+ cursx = 0;
+ cursy = 0;
+ if ( (regs.byteregs[regal] & 0x80) == 0x00) {
+ memset (&RAM[0xA0000], 0, 0x1FFFF);
+ memset (VRAM, 0, 262144);
+ }
+ switch (vidmode) {
+ case 127: //hercules
+ nw = oldw = 720;
+ nh = oldh = 348;
+ scrmodechange = 1;
+ break;
+ case 0x12:
+ nw = oldw = 640;
+ nh = oldh = 480;
+ scrmodechange = 1;
+ break;
+ case 0x13:
+ oldw = 640;
+ oldh = 400;
+ nw = 320;
+ nh = 200;
+ scrmodechange = 1;
+ break;
+ default:
+ nw = oldw = 640;
+ nh = oldh = 400;
+ scrmodechange = 1;
+ break;
+ }
+ break;
+ case 0x10: //VGA DAC functions
+ switch (regs.byteregs[regal]) {
+ case 0x10: //set individual DAC register
+ palettevga[getreg16 (regbx) ] = rgb((regs.byteregs[regdh] & 63) << 2, (regs.byteregs[regch] & 63) << 2, (regs.byteregs[regcl] & 63) << 2);
+ break;
+ case 0x12: //set block of DAC registers
+ memloc = segregs[reges]*16+getreg16 (regdx);
+ for (n=getreg16 (regbx); n< (uint32_t) (getreg16 (regbx) +getreg16 (regcx) ); n++) {
+ palettevga[n] = rgb(read86(memloc) << 2, read86(memloc + 1) << 2, read86(memloc + 2) << 2);
+ memloc += 3;
+ }
+ }
+ break;
+ case 0x1A: //get display combination code (ps, vga/mcga)
+ regs.byteregs[regal] = 0x1A;
+ regs.byteregs[regbl] = 0x8;
+ break;
+ }
+}
+
+void initcga() {
+ FILE *fontfile;
+ fontfile = fopen (PATH_DATAFILES "asciivga.dat", "rb");
+ if (fontfile==NULL) {
+ printf ("FATAL: Cannot open " PATH_DATAFILES "asciivga!\n");
+ exit (1);
+ }
+ fread (&fontcga[0], 32768, 1, fontfile);
+ fclose (fontfile);
+
+ palettecga[0] = 0;
+ palettecga[1] = rgb (0, 0, 0xAA);
+ palettecga[2] = rgb (0, 0xAA, 0);
+ palettecga[3] = rgb (0, 0xAA, 0xAA);
+ palettecga[4] = rgb (0xAA, 0, 0);
+ palettecga[5] = rgb (0xAA, 0, 0xAA);
+ palettecga[6] = rgb (0xAA, 0x55, 0);
+ palettecga[7] = rgb (0xAA, 0xAA, 0xAA);
+ palettecga[8] = rgb (0x55, 0x55, 0x55);
+ palettecga[9] = rgb (0x55, 0x55, 0xFF);
+ palettecga[10] = rgb (0x55, 0xFF, 0x55);
+ palettecga[11] = rgb (0x55, 0xFF, 0xFF);
+ palettecga[12] = rgb (0xFF, 0x55, 0x55);
+ palettecga[13] = rgb (0xFF, 0x55, 0xFF);
+ palettecga[14] = rgb (0xFF, 0xFF, 0x55);
+ palettecga[15] = rgb (0xFF, 0xFF, 0xFF);
+ palettevga[0] = rgb (0, 0, 0);
+ palettevga[1] = rgb (0, 0, 169);
+ palettevga[2] = rgb (0, 169, 0);
+ palettevga[3] = rgb (0, 169, 169);
+ palettevga[4] = rgb (169, 0, 0);
+ palettevga[5] = rgb (169, 0, 169);
+ palettevga[6] = rgb (169, 169, 0);
+ palettevga[7] = rgb (169, 169, 169);
+ palettevga[8] = rgb (0, 0, 84);
+ palettevga[9] = rgb (0, 0, 255);
+ palettevga[10] = rgb (0, 169, 84);
+ palettevga[11] = rgb (0, 169, 255);
+ palettevga[12] = rgb (169, 0, 84);
+ palettevga[13] = rgb (169, 0, 255);
+ palettevga[14] = rgb (169, 169, 84);
+ palettevga[15] = rgb (169, 169, 255);
+ palettevga[16] = rgb (0, 84, 0);
+ palettevga[17] = rgb (0, 84, 169);
+ palettevga[18] = rgb (0, 255, 0);
+ palettevga[19] = rgb (0, 255, 169);
+ palettevga[20] = rgb (169, 84, 0);
+ palettevga[21] = rgb (169, 84, 169);
+ palettevga[22] = rgb (169, 255, 0);
+ palettevga[23] = rgb (169, 255, 169);
+ palettevga[24] = rgb (0, 84, 84);
+ palettevga[25] = rgb (0, 84, 255);
+ palettevga[26] = rgb (0, 255, 84);
+ palettevga[27] = rgb (0, 255, 255);
+ palettevga[28] = rgb (169, 84, 84);
+ palettevga[29] = rgb (169, 84, 255);
+ palettevga[30] = rgb (169, 255, 84);
+ palettevga[31] = rgb (169, 255, 255);
+ palettevga[32] = rgb (84, 0, 0);
+ palettevga[33] = rgb (84, 0, 169);
+ palettevga[34] = rgb (84, 169, 0);
+ palettevga[35] = rgb (84, 169, 169);
+ palettevga[36] = rgb (255, 0, 0);
+ palettevga[37] = rgb (255, 0, 169);
+ palettevga[38] = rgb (255, 169, 0);
+ palettevga[39] = rgb (255, 169, 169);
+ palettevga[40] = rgb (84, 0, 84);
+ palettevga[41] = rgb (84, 0, 255);
+ palettevga[42] = rgb (84, 169, 84);
+ palettevga[43] = rgb (84, 169, 255);
+ palettevga[44] = rgb (255, 0, 84);
+ palettevga[45] = rgb (255, 0, 255);
+ palettevga[46] = rgb (255, 169, 84);
+ palettevga[47] = rgb (255, 169, 255);
+ palettevga[48] = rgb (84, 84, 0);
+ palettevga[49] = rgb (84, 84, 169);
+ palettevga[50] = rgb (84, 255, 0);
+ palettevga[51] = rgb (84, 255, 169);
+ palettevga[52] = rgb (255, 84, 0);
+ palettevga[53] = rgb (255, 84, 169);
+ palettevga[54] = rgb (255, 255, 0);
+ palettevga[55] = rgb (255, 255, 169);
+ palettevga[56] = rgb (84, 84, 84);
+ palettevga[57] = rgb (84, 84, 255);
+ palettevga[58] = rgb (84, 255, 84);
+ palettevga[59] = rgb (84, 255, 255);
+ palettevga[60] = rgb (255, 84, 84);
+ palettevga[61] = rgb (255, 84, 255);
+ palettevga[62] = rgb (255, 255, 84);
+ palettevga[63] = rgb (255, 255, 255);
+ palettevga[64] = rgb (255, 125, 125);
+ palettevga[65] = rgb (255, 157, 125);
+ palettevga[66] = rgb (255, 190, 125);
+ palettevga[67] = rgb (255, 222, 125);
+ palettevga[68] = rgb (255, 255, 125);
+ palettevga[69] = rgb (222, 255, 125);
+ palettevga[70] = rgb (190, 255, 125);
+ palettevga[71] = rgb (157, 255, 125);
+ palettevga[72] = rgb (125, 255, 125);
+ palettevga[73] = rgb (125, 255, 157);
+ palettevga[74] = rgb (125, 255, 190);
+ palettevga[75] = rgb (125, 255, 222);
+ palettevga[76] = rgb (125, 255, 255);
+ palettevga[77] = rgb (125, 222, 255);
+ palettevga[78] = rgb (125, 190, 255);
+ palettevga[79] = rgb (125, 157, 255);
+ palettevga[80] = rgb (182, 182, 255);
+ palettevga[81] = rgb (198, 182, 255);
+ palettevga[82] = rgb (218, 182, 255);
+ palettevga[83] = rgb (234, 182, 255);
+ palettevga[84] = rgb (255, 182, 255);
+ palettevga[85] = rgb (255, 182, 234);
+ palettevga[86] = rgb (255, 182, 218);
+ palettevga[87] = rgb (255, 182, 198);
+ palettevga[88] = rgb (255, 182, 182);
+ palettevga[89] = rgb (255, 198, 182);
+ palettevga[90] = rgb (255, 218, 182);
+ palettevga[91] = rgb (255, 234, 182);
+ palettevga[92] = rgb (255, 255, 182);
+ palettevga[93] = rgb (234, 255, 182);
+ palettevga[94] = rgb (218, 255, 182);
+ palettevga[95] = rgb (198, 255, 182);
+ palettevga[96] = rgb (182, 255, 182);
+ palettevga[97] = rgb (182, 255, 198);
+ palettevga[98] = rgb (182, 255, 218);
+ palettevga[99] = rgb (182, 255, 234);
+ palettevga[100] = rgb (182, 255, 255);
+ palettevga[101] = rgb (182, 234, 255);
+ palettevga[102] = rgb (182, 218, 255);
+ palettevga[103] = rgb (182, 198, 255);
+ palettevga[104] = rgb (0, 0, 113);
+ palettevga[105] = rgb (28, 0, 113);
+ palettevga[106] = rgb (56, 0, 113);
+ palettevga[107] = rgb (84, 0, 113);
+ palettevga[108] = rgb (113, 0, 113);
+ palettevga[109] = rgb (113, 0, 84);
+ palettevga[110] = rgb (113, 0, 56);
+ palettevga[111] = rgb (113, 0, 28);
+ palettevga[112] = rgb (113, 0, 0);
+ palettevga[113] = rgb (113, 28, 0);
+ palettevga[114] = rgb (113, 56, 0);
+ palettevga[115] = rgb (113, 84, 0);
+ palettevga[116] = rgb (113, 113, 0);
+ palettevga[117] = rgb (84, 113, 0);
+ palettevga[118] = rgb (56, 113, 0);
+ palettevga[119] = rgb (28, 113, 0);
+ palettevga[120] = rgb (0, 113, 0);
+ palettevga[121] = rgb (0, 113, 28);
+ palettevga[122] = rgb (0, 113, 56);
+ palettevga[123] = rgb (0, 113, 84);
+ palettevga[124] = rgb (0, 113, 113);
+ palettevga[125] = rgb (0, 84, 113);
+ palettevga[126] = rgb (0, 56, 113);
+ palettevga[127] = rgb (0, 28, 113);
+ palettevga[128] = rgb (56, 56, 113);
+ palettevga[129] = rgb (68, 56, 113);
+ palettevga[130] = rgb (84, 56, 113);
+ palettevga[131] = rgb (97, 56, 113);
+ palettevga[132] = rgb (113, 56, 113);
+ palettevga[133] = rgb (113, 56, 97);
+ palettevga[134] = rgb (113, 56, 84);
+ palettevga[135] = rgb (113, 56, 68);
+ palettevga[136] = rgb (113, 56, 56);
+ palettevga[137] = rgb (113, 68, 56);
+ palettevga[138] = rgb (113, 84, 56);
+ palettevga[139] = rgb (113, 97, 56);
+ palettevga[140] = rgb (113, 113, 56);
+ palettevga[141] = rgb (97, 113, 56);
+ palettevga[142] = rgb (84, 113, 56);
+ palettevga[143] = rgb (68, 113, 56);
+ palettevga[144] = rgb (56, 113, 56);
+ palettevga[145] = rgb (56, 113, 68);
+ palettevga[146] = rgb (56, 113, 84);
+ palettevga[147] = rgb (56, 113, 97);
+ palettevga[148] = rgb (56, 113, 113);
+ palettevga[149] = rgb (56, 97, 113);
+ palettevga[150] = rgb (56, 84, 113);
+ palettevga[151] = rgb (56, 68, 113);
+ palettevga[152] = rgb (80, 80, 113);
+ palettevga[153] = rgb (89, 80, 113);
+ palettevga[154] = rgb (97, 80, 113);
+ palettevga[155] = rgb (105, 80, 113);
+ palettevga[156] = rgb (113, 80, 113);
+ palettevga[157] = rgb (113, 80, 105);
+ palettevga[158] = rgb (113, 80, 97);
+ palettevga[159] = rgb (113, 80, 89);
+ palettevga[160] = rgb (113, 80, 80);
+ palettevga[161] = rgb (113, 89, 80);
+ palettevga[162] = rgb (113, 97, 80);
+ palettevga[163] = rgb (113, 105, 80);
+ palettevga[164] = rgb (113, 113, 80);
+ palettevga[165] = rgb (105, 113, 80);
+ palettevga[166] = rgb (97, 113, 80);
+ palettevga[167] = rgb (89, 113, 80);
+ palettevga[168] = rgb (80, 113, 80);
+ palettevga[169] = rgb (80, 113, 89);
+ palettevga[170] = rgb (80, 113, 97);
+ palettevga[171] = rgb (80, 113, 105);
+ palettevga[172] = rgb (80, 113, 113);
+ palettevga[173] = rgb (80, 105, 113);
+ palettevga[174] = rgb (80, 97, 113);
+ palettevga[175] = rgb (80, 89, 113);
+ palettevga[176] = rgb (0, 0, 64);
+ palettevga[177] = rgb (16, 0, 64);
+ palettevga[178] = rgb (32, 0, 64);
+ palettevga[179] = rgb (48, 0, 64);
+ palettevga[180] = rgb (64, 0, 64);
+ palettevga[181] = rgb (64, 0, 48);
+ palettevga[182] = rgb (64, 0, 32);
+ palettevga[183] = rgb (64, 0, 16);
+ palettevga[184] = rgb (64, 0, 0);
+ palettevga[185] = rgb (64, 16, 0);
+ palettevga[186] = rgb (64, 32, 0);
+ palettevga[187] = rgb (64, 48, 0);
+ palettevga[188] = rgb (64, 64, 0);
+ palettevga[189] = rgb (48, 64, 0);
+ palettevga[190] = rgb (32, 64, 0);
+ palettevga[191] = rgb (16, 64, 0);
+ palettevga[192] = rgb (0, 64, 0);
+ palettevga[193] = rgb (0, 64, 16);
+ palettevga[194] = rgb (0, 64, 32);
+ palettevga[195] = rgb (0, 64, 48);
+ palettevga[196] = rgb (0, 64, 64);
+ palettevga[197] = rgb (0, 48, 64);
+ palettevga[198] = rgb (0, 32, 64);
+ palettevga[199] = rgb (0, 16, 64);
+ palettevga[200] = rgb (32, 32, 64);
+ palettevga[201] = rgb (40, 32, 64);
+ palettevga[202] = rgb (48, 32, 64);
+ palettevga[203] = rgb (56, 32, 64);
+ palettevga[204] = rgb (64, 32, 64);
+ palettevga[205] = rgb (64, 32, 56);
+ palettevga[206] = rgb (64, 32, 48);
+ palettevga[207] = rgb (64, 32, 40);
+ palettevga[208] = rgb (64, 32, 32);
+ palettevga[209] = rgb (64, 40, 32);
+ palettevga[210] = rgb (64, 48, 32);
+ palettevga[211] = rgb (64, 56, 32);
+ palettevga[212] = rgb (64, 64, 32);
+ palettevga[213] = rgb (56, 64, 32);
+ palettevga[214] = rgb (48, 64, 32);
+ palettevga[215] = rgb (40, 64, 32);
+ palettevga[216] = rgb (32, 64, 32);
+ palettevga[217] = rgb (32, 64, 40);
+ palettevga[218] = rgb (32, 64, 48);
+ palettevga[219] = rgb (32, 64, 56);
+ palettevga[220] = rgb (32, 64, 64);
+ palettevga[221] = rgb (32, 56, 64);
+ palettevga[222] = rgb (32, 48, 64);
+ palettevga[223] = rgb (32, 40, 64);
+ palettevga[224] = rgb (44, 44, 64);
+ palettevga[225] = rgb (48, 44, 64);
+ palettevga[226] = rgb (52, 44, 64);
+ palettevga[227] = rgb (60, 44, 64);
+ palettevga[228] = rgb (64, 44, 64);
+ palettevga[229] = rgb (64, 44, 60);
+ palettevga[230] = rgb (64, 44, 52);
+ palettevga[231] = rgb (64, 44, 48);
+ palettevga[232] = rgb (64, 44, 44);
+ palettevga[233] = rgb (64, 48, 44);
+ palettevga[234] = rgb (64, 52, 44);
+ palettevga[235] = rgb (64, 60, 44);
+ palettevga[236] = rgb (64, 64, 44);
+ palettevga[237] = rgb (60, 64, 44);
+ palettevga[238] = rgb (52, 64, 44);
+ palettevga[239] = rgb (48, 64, 44);
+ palettevga[240] = rgb (44, 64, 44);
+ palettevga[241] = rgb (44, 64, 48);
+ palettevga[242] = rgb (44, 64, 52);
+ palettevga[243] = rgb (44, 64, 60);
+ palettevga[244] = rgb (44, 64, 64);
+ palettevga[245] = rgb (44, 60, 64);
+ palettevga[246] = rgb (44, 52, 64);
+ palettevga[247] = rgb (44, 48, 64);
+ palettevga[248] = rgb (0, 0, 0);
+ palettevga[249] = rgb (0, 0, 0);
+ palettevga[250] = rgb (0, 0, 0);
+ palettevga[251] = rgb (0, 0, 0);
+ palettevga[252] = rgb (0, 0, 0);
+ palettevga[253] = rgb (0, 0, 0);
+ palettevga[254] = rgb (0, 0, 0);
+ palettevga[255] = rgb (0, 0, 0);
+}
+
+uint16_t vtotal = 0;
+void outVGA (uint16_t portnum, uint8_t value) {
+ static uint8_t oldah, oldal;
+ uint8_t flip3c0 = 0;
+ updatedscreen = 1;
+ switch (portnum) {
+ case 0x3B8: //hercules support
+ if ( ( (value & 2) == 2) && (vidmode != 127) ) {
+ oldah = regs.byteregs[regah];
+ oldal = regs.byteregs[regal];
+ regs.byteregs[regah] = 0;
+ regs.byteregs[regal] = 127;
+ vidinterrupt();
+ regs.byteregs[regah] = oldah;
+ regs.byteregs[regal] = oldal;
+ }
+ if (value & 0x80) videobase = 0xB8000;
+ else videobase = 0xB0000;
+ break;
+ case 0x3C0:
+ if (flip3c0) {
+ flip3c0 = 0;
+ portram[0x3C0] = value & 255;
+ return;
+ }
+ else {
+ flip3c0 = 1;
+ VGA_ATTR[portram[0x3C0]] = value & 255;
+ return;
+ }
+ case 0x3C4: //sequence controller index
+ portram[0x3C4] = value & 255;
+ //if (portout16) VGA_SC[value & 255] = value >> 8;
+ break;
+ case 0x3C5: //sequence controller data
+ VGA_SC[portram[0x3C4]] = value & 255;
+ /*if (portram[0x3C4] == 2) {
+ printf("VGA_SC[2] = %02X\n", value);
+ }*/
+ break;
+ case 0x3D4: //CRT controller index
+ portram[0x3D4] = value & 255;
+ //if (portout16) VGA_CRTC[value & 255] = value >> 8;
+ break;
+ case 0x3C7: //color index register (read operations)
+ latchReadPal = value & 255;
+ latchReadRGB = 0;
+ stateDAC = 0;
+ break;
+ case 0x3C8: //color index register (write operations)
+ latchPal = value & 255;
+ latchRGB = 0;
+ tempRGB = 0;
+ stateDAC = 3;
+ break;
+ case 0x3C9: //RGB data register
+ value = value & 63;
+ switch (latchRGB) {
+#ifdef __BIG_ENDIAN__
+ case 0: //red
+ tempRGB = value << 26;
+ break;
+ case 1: //green
+ tempRGB |= value << 18;
+ break;
+ case 2: //blue
+ tempRGB |= value << 10;
+ palettevga[latchPal] = tempRGB;
+ latchPal = latchPal + 1;
+ break;
+#else
+ case 0: //red
+ tempRGB = value << 2;
+ break;
+ case 1: //green
+ tempRGB |= value << 10;
+ break;
+ case 2: //blue
+ tempRGB |= value << 18;
+ palettevga[latchPal] = tempRGB;
+ latchPal = latchPal + 1;
+ break;
+#endif
+ }
+ latchRGB = (latchRGB + 1) % 3;
+ break;
+ case 0x3D5: //cursor position latch
+ VGA_CRTC[portram[0x3D4]] = value & 255;
+ if (portram[0x3D4]==0xE) cursorposition = (cursorposition&0xFF) | (value<<8);
+ else if (portram[0x3D4]==0xF) cursorposition = (cursorposition&0xFF00) |value;
+ cursy = cursorposition/cols;
+ cursx = cursorposition%cols;
+ if (portram[0x3D4] == 6) {
+ vtotal = value | ( ( (uint16_t) VGA_GC[7] & 1) << 8) | ( ( (VGA_GC[7] & 32) ? 1 : 0) << 9);
+ //printf("Vertical total: %u\n", vtotal);
+ }
+ break;
+ case 0x3CF:
+ VGA_GC[portram[0x3CE]] = value;
+ break;
+ default:
+ portram[portnum] = value;
+ }
+}
+
+uint8_t inVGA (uint16_t portnum) {
+ switch (portnum) {
+ case 0x3C1:
+ return ( (uint8_t) VGA_ATTR[portram[0x3C0]]);
+ case 0x3C5:
+ return ( (uint8_t) VGA_SC[portram[0x3C4]]);
+ case 0x3D5:
+ return ( (uint8_t) VGA_CRTC[portram[0x3D4]]);
+ case 0x3C7: //DAC state
+ return (stateDAC);
+ case 0x3C8: //palette index
+ return (latchReadPal);
+ case 0x3C9: //RGB data register
+ switch (latchReadRGB++) {
+#ifdef __BIG_ENDIAN__
+ case 0: //blue
+ return ( (palettevga[latchReadPal] >> 26) & 63);
+ case 1: //green
+ return ( (palettevga[latchReadPal] >> 18) & 63);
+ case 2: //red
+ latchReadRGB = 0;
+ return ( (palettevga[latchReadPal++] >> 10) & 63);
+#else
+ case 0: //blue
+ return ( (palettevga[latchReadPal] >> 2) & 63);
+ case 1: //green
+ return ( (palettevga[latchReadPal] >> 10) & 63);
+ case 2: //red
+ latchReadRGB = 0;
+ return ( (palettevga[latchReadPal++] >> 18) & 63);
+#endif
+ }
+ case 0x3DA:
+ return (port3da);
+ }
+ return (portram[portnum]); //this won't be reached, but without it the compiler gives a warning
+}
+
+#define shiftVGA(value) {\
+ for (cnt=0; cnt<(VGA_GC[3] & 7); cnt++) {\
+ value = (value >> 1) | ((value & 1) << 7);\
+ }\
+}
+
+#define logicVGA(curval, latchval) {\
+ switch ((VGA_GC[3]>>3) & 3) {\
+ case 1: curval &= latchval; break;\
+ case 2: curval |= latchval; break;\
+ case 3: curval ^= latchval; break;\
+ }\
+}
+
+uint8_t lastmode = 0, tempvalue;
+void writeVGA (uint32_t addr32, uint8_t value) {
+ uint32_t planesize;
+ uint8_t curval, tempand, cnt;
+ updatedscreen = 1;
+ planesize = 0x10000;
+ //if (lastmode != VGA_GC[5] & 3) printf("write mode %u\n", VGA_GC[5] & 3);
+ //lastmode = VGA_GC[5] & 3;
+ switch (VGA_GC[5] & 3) { //get write mode
+ case 0:
+ shiftVGA (value);
+ if (VGA_SC[2] & 1) {
+ if (VGA_GC[1] & 1)
+ if (VGA_GC[0] & 1) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[0]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[0]);
+ VRAM[addr32] = curval;
+ }
+ if (VGA_SC[2] & 2) {
+ if (VGA_GC[1] & 2)
+ if (VGA_GC[0] & 2) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[1]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[1]);
+ VRAM[addr32+planesize] = curval;
+ }
+ if (VGA_SC[2] & 4) {
+ if (VGA_GC[1] & 4)
+ if (VGA_GC[0] & 4) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[2]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[2]);
+ VRAM[addr32+planesize*2] = curval;
+ }
+ if (VGA_SC[2] & 8) {
+ if (VGA_GC[1] & 8)
+ if (VGA_GC[0] & 8) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[3]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[3]);
+ VRAM[addr32+planesize*3] = curval;
+ }
+ break;
+ case 1:
+ if (VGA_SC[2] & 1) VRAM[addr32] = VGA_latch[0];
+ if (VGA_SC[2] & 2) VRAM[addr32+planesize] = VGA_latch[1];
+ if (VGA_SC[2] & 4) VRAM[addr32+planesize*2] = VGA_latch[2];
+ if (VGA_SC[2] & 8) VRAM[addr32+planesize*3] = VGA_latch[3];
+ break;
+ case 2:
+ if (VGA_SC[2] & 1) {
+ if (VGA_GC[1] & 1)
+ if (value & 1) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[0]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[0]);
+ VRAM[addr32] = curval;
+ }
+ if (VGA_SC[2] & 2) {
+ if (VGA_GC[1] & 2)
+ if (value & 2) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[1]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[1]);
+ VRAM[addr32+planesize] = curval;
+ }
+ if (VGA_SC[2] & 4) {
+ if (VGA_GC[1] & 4)
+ if (value & 4) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[2]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[2]);
+ VRAM[addr32+planesize*2] = curval;
+ }
+ if (VGA_SC[2] & 8) {
+ if (VGA_GC[1] & 8)
+ if (value & 8) curval = 255;
+ else curval = 0;
+ else curval = value;
+ logicVGA (curval, VGA_latch[3]);
+ curval = (~VGA_GC[8] & curval) | (VGA_GC[8] & VGA_latch[3]);
+ VRAM[addr32+planesize*3] = curval;
+ }
+ break;
+ case 3:
+ tempand = value & VGA_GC[8];
+ shiftVGA (value);
+ if (VGA_SC[2] & 1) {
+ if (VGA_GC[0] & 1) curval = 255;
+ else curval = 0;
+ //logicVGA (curval, VGA_latch[0]);
+ curval = (~tempand & curval) | (tempand & VGA_latch[0]);
+ VRAM[addr32] = curval;
+ }
+ if (VGA_SC[2] & 2) {
+ if (VGA_GC[0] & 2) curval = 255;
+ else curval = 0;
+ //logicVGA (curval, VGA_latch[1]);
+ curval = (~tempand & curval) | (tempand & VGA_latch[1]);
+ VRAM[addr32+planesize] = curval;
+ }
+ if (VGA_SC[2] & 4) {
+ if (VGA_GC[0] & 4) curval = 255;
+ else curval = 0;
+ //logicVGA (curval, VGA_latch[2]);
+ curval = (~tempand & curval) | (tempand & VGA_latch[2]);
+ VRAM[addr32+planesize*2] = curval;
+ }
+ if (VGA_SC[2] & 8) {
+ if (VGA_GC[0] & 8) curval = 255;
+ else curval = 0;
+ //logicVGA (curval, VGA_latch[3]);
+ curval = (~tempand & curval) | (tempand & VGA_latch[3]);
+ VRAM[addr32+planesize*3] = curval;
+ }
+ break;
+ }
+}
+
+uint8_t readmode;
+uint32_t readmap;
+uint8_t readVGA (uint32_t addr32) {
+ uint32_t planesize;
+ planesize = 0x10000;
+
+ VGA_latch[0] = VRAM[addr32];
+ VGA_latch[1] = VRAM[addr32+planesize];
+ VGA_latch[2] = VRAM[addr32+planesize*2];
+ VGA_latch[3] = VRAM[addr32+planesize*3];
+ if (VGA_SC[2] & 1) return (VRAM[addr32]);
+ if (VGA_SC[2] & 2) return (VRAM[addr32+planesize]);
+ if (VGA_SC[2] & 4) return (VRAM[addr32+planesize*2]);
+ if (VGA_SC[2] & 8) return (VRAM[addr32+planesize*3]);
+ return (0); //this won't be reached, but without it some compilers give a warning
+}
+
+void initVideoPorts() {
+ set_port_write_redirector (0x3B0, 0x3DA, &outVGA);
+ set_port_read_redirector (0x3B0, 0x3DA, &inVGA);
+}
diff --git a/src/fake86/win32/menus.c b/src/fake86/win32/menus.c
new file mode 100644
index 0000000..738798a
--- /dev/null
+++ b/src/fake86/win32/menus.c
@@ -0,0 +1,161 @@
+#include "../config.h"
+#include "../../../win32/resource.h"
+#include <Windows.h>
+#include <SDL/SDL.h>
+#include <SDL/SDL_syswm.h>
+
+HWND myWindow;
+HINSTANCE myInstance;
+HMENU myMenu;
+WNDPROC oldProc;
+HWND GetHwnd();
+HICON myIcon;
+void SetWndProc();
+void MenuItemClick(WPARAM wParam);
+
+void ShowMenu() {
+ SetMenu(myWindow, myMenu);
+}
+
+void HideMenu() {
+ SetMenu(myWindow, NULL);
+}
+
+void initmenus() {
+ myWindow = GetHwnd();
+ myInstance = GetModuleHandle(NULL);
+ myMenu = LoadMenu(NULL, MAKEINTRESOURCE(IDR_MENU1));
+ ShowMenu();
+ SetWndProc();
+ //myIcon = LoadIcon(myInstance, MAKEINTRESOURCE(IDI_ICON1));
+ //SetClassLong(myWindow, GCLP_HICON, (LONG)(uint64_t)myIcon);
+ //SetClassLong(myWindow, GCLP_HICONSM, (LONG)(uint64_t)myIcon);
+
+ return;
+}
+
+HWND GetHwnd() {
+ SDL_SysWMinfo wmi;
+ SDL_VERSION(&wmi.version);
+
+ if (!SDL_GetWMInfo(&wmi)) return(NULL);
+ return(wmi.window);
+}
+
+LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
+ switch (msg) {
+ case WM_COMMAND:
+ MenuItemClick(wParam);
+ return(TRUE);
+ }
+
+ return(CallWindowProc(oldProc, hwnd, msg, wParam, lParam));
+}
+
+void SetWndProc() {
+ oldProc = (WNDPROC)SetWindowLong(myWindow, GWL_WNDPROC, (LONG_PTR)WndProc);
+}
+
+extern uint8_t running, bootdrive, dohardreset, scrmodechange;
+extern uint16_t constantw, constanth;
+uint8_t insertdisk (uint8_t drivenum, char *filename);
+uint8_t ejectdisk (uint8_t drivenum);
+
+void MenuItemClick(WPARAM wParam) {
+ OPENFILENAME of_dlg;
+ uint8_t filename[MAX_PATH] = { 0 };
+
+ switch (LOWORD(wParam)) {
+ //file menu
+ case ID_FILE_EXIT:
+ running = 0;
+ break;
+
+ //emulation menu
+ case ID_EMULATION_HARDRESETEMULATOR:
+ dohardreset = 1;
+ break;
+
+ case ID_FLOPPY0_INSERTDISK:
+ case ID_FLOPPY1_INSERTDISK:
+ memset(&of_dlg, 0, sizeof(of_dlg));
+ of_dlg.lStructSize = sizeof(of_dlg);
+ of_dlg.lpstrTitle = "Open disk image";
+ of_dlg.hInstance = NULL;
+ of_dlg.lpstrFile = filename;
+ of_dlg.lpstrFilter = "Floppy disk images (*.img)\0*.img\0All files (*.*)\0*.*\0\0";
+ of_dlg.nMaxFile = MAX_PATH;
+ of_dlg.Flags = OFN_FILEMUSTEXIST | OFN_LONGNAMES;
+ if (GetOpenFileName(&of_dlg)) {
+ if (LOWORD(wParam) == ID_FLOPPY0_INSERTDISK) {
+ insertdisk(0, (char *)of_dlg.lpstrFile);
+ if (bootdrive == 255) bootdrive = 0;
+ } else insertdisk(1, (char *)of_dlg.lpstrFile);
+ }
+ break;
+ case ID_FLOPPY0_EJECTDISK:
+ ejectdisk(0);
+ break;
+ case ID_FLOPPY1_EJECTDISK:
+ ejectdisk(1);
+ break;
+
+ case ID_HARDDRIVE0_INSERTDISK:
+ case ID_HARDDRIVE1_INSERTDISK:
+ memset(&of_dlg, 0, sizeof(of_dlg));
+ of_dlg.lStructSize = sizeof(of_dlg);
+ of_dlg.lpstrTitle = "Open disk image";
+ of_dlg.hInstance = NULL;
+ of_dlg.lpstrFile = filename;
+ of_dlg.lpstrFilter = "Raw disk images (*.raw, *.img)\0*.raw;*.img\0All files (*.*)\0*.*\0\0";
+ of_dlg.nMaxFile = MAX_PATH;
+ of_dlg.Flags = OFN_FILEMUSTEXIST | OFN_LONGNAMES;
+ if (GetOpenFileName(&of_dlg)) {
+ if (LOWORD(wParam) == ID_HARDDRIVE0_INSERTDISK) {
+ insertdisk(128, (char *)of_dlg.lpstrFile);
+ if (bootdrive == 255) bootdrive = 128;
+ } else insertdisk(129, (char *)of_dlg.lpstrFile);
+ }
+ break;
+ case ID_HARDDRIVE0_EJECTDISK:
+ ejectdisk(128);
+ break;
+ case ID_HARDDRIVE1_EJECTDISK:
+ ejectdisk(129);
+ break;
+
+ case ID_SETBOOTDRIVE_FLOPPY0:
+ bootdrive = 0;
+ break;
+ case ID_SETBOOTDRIVE_HARDDRIVE0:
+ bootdrive = 128;
+ break;
+
+ //video menu
+ case ID_WINDOWRESOLUTION_AUTOMATIC:
+ constantw = 0;
+ constanth = 0;
+ scrmodechange = 1;
+ break;
+ case ID_WINDOWRESOLUTION_320X200:
+ constantw = 320;
+ constanth = 200;
+ scrmodechange = 1;
+ break;
+ case ID_WINDOWRESOLUTION_640X400:
+ constantw = 640;
+ constanth = 400;
+ scrmodechange = 1;
+ break;
+ case ID_WINDOWRESOLUTION_960X600:
+ constantw = 960;
+ constanth = 600;
+ scrmodechange = 1;
+ break;
+ case ID_WINDOWRESOLUTION_1280X800:
+ constantw = 1280;
+ constanth = 800;
+ scrmodechange = 1;
+ break;
+ }
+}
diff --git a/src/fake86/win32/resource.h b/src/fake86/win32/resource.h
new file mode 100644
index 0000000..d6b04fe
--- /dev/null
+++ b/src/fake86/win32/resource.h
Binary files differ
diff --git a/src/imagegen/imagegen.c b/src/imagegen/imagegen.c
new file mode 100755
index 0000000..5a5cafb
--- /dev/null
+++ b/src/imagegen/imagegen.c
@@ -0,0 +1,68 @@
+/*
+ Imagegen: A blank disk image generator for use with Fake86
+ Copyright (C)2010-2012 Mike Chambers
+
+ This program is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License
+ as published by the Free Software Foundation; either version 2
+ of the License, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+
+const char *build = "Imagegen v1.1";
+
+int main(int argc, char *argv[]) {
+ FILE *image;
+ char *blank;
+ unsigned long i, size;
+
+ printf("%s (c)2010-2012 Mike Chambers\n", build);
+ printf("[Blank disk image generator for Fake86]\n\n");
+
+ if(argc < 3) {
+ printf("Usage syntax:\n");
+ printf(" imagegen imagefile size\n\n");
+ printf("imagefile denotes the filename of the new disk image to create.\n");
+ printf("size denotes the size in megabytes that it should be.\n");
+ return(1);
+ }
+
+ size = atoi(argv[2]);
+ if((size > 503) || !size) {
+ printf("Invalid size specified! Valid range is 1 to 503 MB.\n");
+ return(1);
+ }
+
+ image = fopen(argv[1], "wb");
+ if(image == NULL) {
+ printf("Unable to create new file: %s\n", argv[1]);
+ return(1);
+ }
+
+ blank = (void *)malloc(1048576);
+ if (blank == NULL) {
+ printf("Unable to allocate enough memory!\n");
+ return(1);
+ }
+
+ printf("Please wait, generating new image...\n");
+
+ for(i = 0; i < size; i++) {
+ fwrite(&blank[0], 1048576, 1, image);
+ printf("\rWriting to file: %u MB", i);
+ }
+
+ printf(" complete.\n");
+ return(0);
+}
diff --git a/win32/bin/.empty b/win32/bin/.empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/win32/bin/.empty
diff --git a/win32/fake86.rc b/win32/fake86.rc
new file mode 100644
index 0000000..112f87c
--- /dev/null
+++ b/win32/fake86.rc
Binary files differ
diff --git a/win32/fake86.sln b/win32/fake86.sln
new file mode 100755
index 0000000..abcbdf8
--- /dev/null
+++ b/win32/fake86.sln
@@ -0,0 +1,36 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual Studio 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "fake86", "fake86.vcxproj", "{4C3260EB-396E-4017-AF95-E0FD33E87046}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "imagegen", "imagegen.vcxproj", "{BE8FA015-E801-40C8-B35B-D477C540439F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug (with WinPCap)|Win32 = Debug (with WinPCap)|Win32
+ Debug|Win32 = Debug|Win32
+ Release (with WinPCap)|Win32 = Release (with WinPCap)|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug (with WinPCap)|Win32.ActiveCfg = Debug (with WinPCap)|Win32
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug (with WinPCap)|Win32.Build.0 = Debug (with WinPCap)|Win32
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Debug|Win32.Build.0 = Debug|Win32
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release (with WinPCap)|Win32.ActiveCfg = Release (with WinPCap)|Win32
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release (with WinPCap)|Win32.Build.0 = Release (with WinPCap)|Win32
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release|Win32.ActiveCfg = Release|Win32
+ {4C3260EB-396E-4017-AF95-E0FD33E87046}.Release|Win32.Build.0 = Release|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug (with WinPCap)|Win32.ActiveCfg = Release|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug (with WinPCap)|Win32.Build.0 = Release|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Debug|Win32.Build.0 = Debug|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Release (with WinPCap)|Win32.ActiveCfg = Release (with WinPCap)|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Release (with WinPCap)|Win32.Build.0 = Release (with WinPCap)|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Release|Win32.ActiveCfg = Release|Win32
+ {BE8FA015-E801-40C8-B35B-D477C540439F}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/win32/fake86.suo b/win32/fake86.suo
new file mode 100644
index 0000000..cad7663
--- /dev/null
+++ b/win32/fake86.suo
Binary files differ
diff --git a/win32/fake86.vcxproj b/win32/fake86.vcxproj
new file mode 100755
index 0000000..40136ec
--- /dev/null
+++ b/win32/fake86.vcxproj
@@ -0,0 +1,290 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug (with WinPCap)|Win32">
+ <Configuration>Debug (with WinPCap)</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release (with WinPCap)|Win32">
+ <Configuration>Release (with WinPCap)</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{4C3260EB-396E-4017-AF95-E0FD33E87046}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>fake86</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>NotSet</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug (with WinPCap)|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug (with WinPCap)|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>.\bin\</OutDir>
+ <IntDir>.\intermediate\</IntDir>
+ <CustomBuildAfterTargets>
+ </CustomBuildAfterTargets>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>.\bin\</OutDir>
+ <IntDir>.\intermediate\</IntDir>
+ <CustomBuildAfterTargets>
+ </CustomBuildAfterTargets>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>.\bin\</OutDir>
+ <IntDir>.\intermediate\</IntDir>
+ <CustomBuildAfterTargets>
+ </CustomBuildAfterTargets>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug (with WinPCap)|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>.\bin\</OutDir>
+ <IntDir>.\intermediate\</IntDir>
+ <CustomBuildAfterTargets>
+ </CustomBuildAfterTargets>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>PATH_DATAFILES="";_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <OmitFramePointers>true</OmitFramePointers>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ <AssemblerOutput>AssemblyAndSourceCode</AssemblerOutput>
+ <AssemblerListingLocation>$(IntDir)</AssemblerListingLocation>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>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)</AdditionalDependencies>
+ <Version>0.12.9.19</Version>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>
+ </Message>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>copy ..\data\*.* bin\ /Y</Command>
+ </PostBuildEvent>
+ <PostBuildEvent>
+ <Message>Copying ROM data files to bin folder...</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>Disabled</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>PATH_DATAFILES="";_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>
+ <OmitFramePointers>true</OmitFramePointers>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <InlineFunctionExpansion>Disabled</InlineFunctionExpansion>
+ <DebugInformationFormat>EditAndContinue</DebugInformationFormat>
+ <WholeProgramOptimization>false</WholeProgramOptimization>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>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)</AdditionalDependencies>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>
+ </Message>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>copy ..\data\*.* bin\ /Y</Command>
+ </PostBuildEvent>
+ <PostBuildEvent>
+ <Message>Copying ROM data files to bin folder...</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>PATH_DATAFILES="";NETWORKING_ENABLED;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <OmitFramePointers>true</OmitFramePointers>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>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)</AdditionalDependencies>
+ <Version>0.12.9.19</Version>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>
+ </Message>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>copy ..\data\*.* bin\ /Y</Command>
+ </PostBuildEvent>
+ <PostBuildEvent>
+ <Message>Copying ROM data files to bin folder...</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug (with WinPCap)|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>PATH_DATAFILES="";NETWORKING_ENABLED;_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <OmitFramePointers>true</OmitFramePointers>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <InlineFunctionExpansion>AnySuitable</InlineFunctionExpansion>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>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)</AdditionalDependencies>
+ </Link>
+ <CustomBuildStep>
+ <Command>
+ </Command>
+ </CustomBuildStep>
+ <CustomBuildStep>
+ <Message>
+ </Message>
+ </CustomBuildStep>
+ <PostBuildEvent>
+ <Command>copy ..\data\*.* bin\ /Y</Command>
+ </PostBuildEvent>
+ <PostBuildEvent>
+ <Message>Copying ROM data files to bin folder...</Message>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\fake86\adlib.c" />
+ <ClCompile Include="..\src\fake86\ata.c" />
+ <ClCompile Include="..\src\fake86\audio.c" />
+ <ClCompile Include="..\src\fake86\blaster.c" />
+ <ClCompile Include="..\src\fake86\console.c" />
+ <ClCompile Include="..\src\fake86\cpu.c" />
+ <ClCompile Include="..\src\fake86\disk.c" />
+ <ClCompile Include="..\src\fake86\i8237.c" />
+ <ClCompile Include="..\src\fake86\i8253.c" />
+ <ClCompile Include="..\src\fake86\i8259.c" />
+ <ClCompile Include="..\src\fake86\input.c" />
+ <ClCompile Include="..\src\fake86\main.c" />
+ <ClCompile Include="..\src\fake86\netcard.c" />
+ <ClCompile Include="..\src\fake86\packet.c" />
+ <ClCompile Include="..\src\fake86\parsecl.c" />
+ <ClCompile Include="..\src\fake86\ports.c" />
+ <ClCompile Include="..\src\fake86\render.c" />
+ <ClCompile Include="..\src\fake86\sermouse.c" />
+ <ClCompile Include="..\src\fake86\sndsource.c" />
+ <ClCompile Include="..\src\fake86\speaker.c" />
+ <ClCompile Include="..\src\fake86\timing.c" />
+ <ClCompile Include="..\src\fake86\video.c" />
+ <ClCompile Include="..\src\fake86\win32\menus.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\src\fake86\audio.h" />
+ <ClInclude Include="..\src\fake86\blaster.h" />
+ <ClInclude Include="..\src\fake86\config.h" />
+ <ClInclude Include="..\src\fake86\cpu.h" />
+ <ClInclude Include="..\src\fake86\disk.h" />
+ <ClInclude Include="..\src\fake86\i8237.h" />
+ <ClInclude Include="..\src\fake86\i8253.h" />
+ <ClInclude Include="..\src\fake86\i8259.h" />
+ <ClInclude Include="..\src\fake86\modregrm.h" />
+ <ClInclude Include="..\src\fake86\mutex.h" />
+ <ClInclude Include="..\src\fake86\sermouse.h" />
+ <ClInclude Include="resource.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="fake86.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/win32/fake86.vcxproj.filters b/win32/fake86.vcxproj.filters
new file mode 100755
index 0000000..16214c3
--- /dev/null
+++ b/win32/fake86.vcxproj.filters
@@ -0,0 +1,137 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Source Files\win32">
+ <UniqueIdentifier>{24282956-ada5-4a20-b289-9af8e28ff7c9}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Header Files\win32">
+ <UniqueIdentifier>{91c547f5-4ef4-4a63-9ad1-3be02cf667ac}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\fake86\adlib.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\video.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\ata.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\audio.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\blaster.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\console.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\cpu.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\disk.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\i8237.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\i8253.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\i8259.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\input.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\main.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\netcard.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\packet.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\parsecl.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\ports.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\render.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\sermouse.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\sndsource.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\speaker.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\timing.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="..\src\fake86\win32\menus.c">
+ <Filter>Source Files\win32</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="..\src\fake86\audio.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\blaster.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\config.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\cpu.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\disk.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\i8237.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\i8253.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\i8259.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\mutex.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\sermouse.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="..\src\fake86\modregrm.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files\win32</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="fake86.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/win32/imagegen.vcxproj b/win32/imagegen.vcxproj
new file mode 100755
index 0000000..4b2f333
--- /dev/null
+++ b/win32/imagegen.vcxproj
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release (with WinPCap)|Win32">
+ <Configuration>Release (with WinPCap)</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{BE8FA015-E801-40C8-B35B-D477C540439F}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>imagegen</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'" Label="Configuration">
+ <ConfigurationType>Application</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>.\bin\</OutDir>
+ <IntDir>.\intermediate\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>.\bin\</OutDir>
+ <IntDir>.\intermediate\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>.\bin\</OutDir>
+ <IntDir>.\intermediate\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+ <OmitFramePointers>true</OmitFramePointers>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <Version>1.1</Version>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+ <OmitFramePointers>true</OmitFramePointers>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <Version>1.1</Version>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release (with WinPCap)|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>
+ </PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <FloatingPointModel>Fast</FloatingPointModel>
+ <RuntimeLibrary>MultiThreaded</RuntimeLibrary>
+ <InlineFunctionExpansion>Default</InlineFunctionExpansion>
+ <OmitFramePointers>true</OmitFramePointers>
+ </ClCompile>
+ <Link>
+ <SubSystem>Console</SubSystem>
+ <GenerateDebugInformation>false</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <Version>1.1</Version>
+ </Link>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\imagegen\imagegen.c" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/win32/imagegen.vcxproj.filters b/win32/imagegen.vcxproj.filters
new file mode 100755
index 0000000..a228731
--- /dev/null
+++ b/win32/imagegen.vcxproj.filters
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="..\src\imagegen\imagegen.c">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/win32/intermediate/.empty b/win32/intermediate/.empty
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/win32/intermediate/.empty
diff --git a/win32/resource.h b/win32/resource.h
new file mode 100644
index 0000000..c9076c0
--- /dev/null
+++ b/win32/resource.h
Binary files differ