aboutsummaryrefslogtreecommitdiff
path: root/src
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 /src
downloadfake86-d49887486c772592c0e8ecc158c1cc3efb3f7709.tar.gz
Initial commit 0.13.9.16
Diffstat (limited to 'src')
-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
36 files changed, 8867 insertions, 0 deletions
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);
+}