diff options
author | Joseph Hunkeler <jhunkeler@gmail.com> | 2021-02-27 12:08:23 -0500 |
---|---|---|
committer | Joseph Hunkeler <jhunkeler@gmail.com> | 2021-02-27 12:08:23 -0500 |
commit | d49887486c772592c0e8ecc158c1cc3efb3f7709 (patch) | |
tree | ea5af335e7cee87f07de50082dd6ff66f3231353 /src | |
download | fake86-d49887486c772592c0e8ecc158c1cc3efb3f7709.tar.gz |
Initial commit 0.13.9.16
Diffstat (limited to 'src')
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 Binary files differnew file mode 100644 index 0000000..d6b04fe --- /dev/null +++ b/src/fake86/win32/resource.h 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); +} |