From 2856eb091c972725bf681a9326b2cf16df1ac575 Mon Sep 17 00:00:00 2001 From: Toni Wilen Date: Wed, 22 Jul 2015 19:41:16 +0300 Subject: [PATCH] x86 bridgeboard emulation. --- disk.cpp | 82 +- expansion.cpp | 101 ++ fake86_cpu.cpp | 3577 ++++++++++++++++++++++++++++++++++++++++++ include/autoconf.h | 4 + include/disk.h | 14 +- include/rommgr.h | 3 + include/x86.h | 14 + od-win32/sysconfig.h | 1 + x86.cpp | 2033 ++++++++++++++++++++++++ 9 files changed, 5814 insertions(+), 15 deletions(-) create mode 100644 fake86_cpu.cpp create mode 100644 include/x86.h create mode 100644 x86.cpp diff --git a/disk.cpp b/disk.cpp index 6fdc719d..d6c0995a 100644 --- a/disk.cpp +++ b/disk.cpp @@ -92,8 +92,8 @@ static int longwritemode = 0; * L track length in bits */ -static int side, direction; -static uae_u8 selected = 15, disabled; +static int side, direction, reserved_side; +static uae_u8 selected = 15, disabled, reserved; static uae_u8 writebuffer[544 * MAX_SECTORS]; @@ -609,6 +609,7 @@ static void drive_settype_id (drive *drv) drv->drive_id = DRIVE_ID_525SD; break; case DRV_NONE: + case DRV_PC_ONLY: drv->drive_id = DRIVE_ID_NONE; break; } @@ -690,8 +691,11 @@ static void reset_drive (int num) drv->drive_id_scnt = 0; drv->lastdataacesstrack = -1; disabled &= ~(1 << num); - if (currprefs.floppyslots[num].dfxtype < 0) + reserved &= ~(1 << num); + if (currprefs.floppyslots[num].dfxtype < 0 || currprefs.floppyslots[num].dfxtype >= DRV_PC_ONLY) disabled |= 1 << num; + if (currprefs.floppyslots[num].dfxtype >= DRV_PC_ONLY) + reserved |= 1 << num; reset_drive_gui (num); /* most internal Amiga floppy drives won't enable * diskready until motor is running at full speed @@ -732,7 +736,10 @@ static void update_drive_gui (int num, bool force) gui_data.crc32[num] = drv->crc32; gui_data.drive_motor[num] = drv->state; gui_data.drive_track[num] = drv->cyl; - gui_data.drive_side = side; + if (reserved & (1 << num)) + gui_data.drive_side = reserved_side; + else + gui_data.drive_side = side; gui_data.drive_writing[num] = writ; gui_led (num + LED_DF0, (gui_data.drive_motor[num] ? 1 : 0) | (gui_data.drive_writing[num] ? 2 : 0)); } @@ -1226,6 +1233,11 @@ static int drive_insert (drive * drv, struct uae_prefs *p, int dnum, const TCHAR } else if (canauto && ( + // double sided + size == 9 * 40 * 2 * 512 || + // single sided + size == 9 * 40 * 1 * 512 || + // double sided size == 9 * 80 * 2 * 512 || size == 18 * 80 * 2 * 512 || size == 10 * 80 * 2 * 512 || size == 20 * 80 * 2 * 512 || size == 9 * 81 * 2 * 512 || size == 18 * 81 * 2 * 512 || size == 10 * 81 * 2 * 512 || size == 20 * 81 * 2 * 512 || @@ -1254,6 +1266,10 @@ static int drive_insert (drive * drv, struct uae_prefs *p, int dnum, const TCHAR drv->num_secs = 20; drv->ddhd = 2; break; + } else if (size == 9 * 40 * side * 512) { + drv->num_secs = 9; + drv->ddhd = 1; + break; } } drv->num_tracks = size / (drv->num_secs * 512); @@ -2879,7 +2895,7 @@ void DISK_select (uae_u8 data) if (!velvet) { if ((prev_data & 0x80) != (data & 0x80)) { for (dr = 0; dr < 4; dr++) { - if (floppy[dr].indexhackmode > 1 && !(selected & (1 << dr))) { + if (floppy[dr].indexhackmode > 1 && !((selected | disabled) & (1 << dr))) { floppy[dr].indexhack = 1; if (disk_debug_logging > 1) write_log (_T(" indexhack!")); @@ -2949,7 +2965,7 @@ void DISK_select (uae_u8 data) drive *drv = floppy + dr; /* motor on/off workings tested with small assembler code on real Amiga 1200. */ /* motor/id flipflop is set only when drive select goes from high to low */ - if (!(selected & (1 << dr)) && (prev_selected & (1 << dr)) ) { + if (!((selected | disabled) & (1 << dr)) && (prev_selected & (1 << dr)) ) { drv->drive_id_scnt++; drv->drive_id_scnt &= 31; drv->idbit = (drv->drive_id & (1L << (31 - drv->drive_id_scnt))) ? 1 : 0; @@ -3064,7 +3080,7 @@ uae_u8 DISK_status_ciaa(void) } else if (drv->dskchange && currprefs.floppyslots[dr].dfxtype != DRV_525_SD) { st &= ~4; } - } else if (!(selected & (1 << dr))) { + } else if (!((selected | disabled) & (1 << dr))) { if (drv->idbit) st &= ~0x20; } @@ -3215,7 +3231,7 @@ static void disk_doupdate_write (drive * drv, int floppybits) drives[dr] = 0; if (drv2->motoroff) continue; - if (selected & (1 << dr)) + if ((selected | disabled) & (1 << dr)) continue; drives[dr] = 1; } @@ -3261,7 +3277,7 @@ static void disk_doupdate_write (drive * drv, int floppybits) drv->writtento = 0; if (drv->motoroff) continue; - if (selected & (1 << dr)) + if ((selected | disabled) & (1 << dr)) continue; drive_write_data (drv); } @@ -3309,7 +3325,7 @@ static void disk_doupdate_predict (int startcycle) continue; if (!drv->trackspeed) continue; - if (selected & (1 << dr)) + if ((selected | disabled) & (1 << dr)) continue; int mfmpos = drv->mfmpos; if (drv->tracktiming[0]) @@ -3553,7 +3569,7 @@ uae_u16 DSKBYTR (int hpos) drive *drv = &floppy[dr]; if (drv->motoroff) continue; - if (!(selected & (1 << dr))) { + if (!((selected | disabled) & (1 << dr))) { drv->lastdataacesstrack = drv->cyl * 2 + side; #if REVOLUTION_DEBUG if (!drv->track_access_done) @@ -3583,7 +3599,7 @@ static void DISK_start (void) word = 0; for (dr = 0; dr < MAX_FLOPPY_DRIVES; dr++) { drive *drv = &floppy[dr]; - if (!(selected & (1 << dr))) { + if (!((selected | disabled) & (1 << dr))) { int tr = drv->cyl * 2 + side; trackid *ti = drv->trackdata + tr; @@ -3690,7 +3706,7 @@ void DISK_update (int tohpos) if (drv->motoroff || !drv->tracklen || !drv->trackspeed) continue; drv->floppybitcounter += cycles; - if (selected & (1 << dr)) { + if ((selected | disabled) & (1 << dr)) { drv->mfmpos += drv->floppybitcounter / drv->trackspeed; drv->mfmpos %= drv->tracklen; drv->floppybitcounter %= drv->trackspeed; @@ -3705,7 +3721,7 @@ void DISK_update (int tohpos) drive *drv = &floppy[dr]; if (drv->motoroff || !drv->trackspeed) continue; - if (selected & (1 << dr)) + if ((selected | disabled) & (1 << dr)) continue; /* write dma and wordsync enabled: read until wordsync match found */ if (dskdmaen == DSKDMA_WRITE && dma_enable) @@ -4651,3 +4667,41 @@ int getdebug(void) { return floppy[0].mfmpos; } + +void disk_reserved_setinfo(int num, int cyl, int head, int motor) +{ + for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) { + if (reserved & (1 << i)) { + if (num > 0) { + num--; + continue; + } + drive *drv = &floppy[i]; + reserved_side = head; + drv->cyl = cyl; + drv->state = motor; + update_drive_gui(i, false); + } + } +} + +bool disk_reserved_getinfo(int num, struct floppy_reserved *fr) +{ + for (int i = 0; i < MAX_FLOPPY_DRIVES; i++) { + if (reserved & (1 << i)) { + if (num > 0) { + num--; + continue; + } + drive *drv = &floppy[i]; + fr->img = drv->diskfile; + fr->wrprot = drv->wrprot; + fr->cyl = drv->cyl; + fr->cyls = drv->num_tracks / 2; + fr->secs = drv->num_secs; + fr->heads = 2; + return true; + } + } + return false; +} diff --git a/expansion.cpp b/expansion.cpp index f877877e..52ad06cc 100644 --- a/expansion.cpp +++ b/expansion.cpp @@ -39,6 +39,7 @@ #include "autoconf.h" #include "specialmonitors.h" #include "pci.h" +#include "x86.h" // More information in first revision HRM Appendix_G #define BOARD_PROTOAUTOCONFIG 1 @@ -2407,6 +2408,79 @@ static const struct expansionboardsettings bridge_settings[] = { } }; +static const struct expansionboardsettings x86_bridge_settings[] = { + { + // 2-3 + _T("Memory (SW1:3-4)\0""128K\0""256K\0""512K\0""640K\0"), + _T("memory\0""128k\0""256k\0""512k\0""640k\0"), + true, false, 2 + }, + { + // 4-5 + _T("Default video (J1)\0Monochrome\0Color 40x25\0Color 80x25\0None\0"), + _T("video\0mono\0color40\0color80\0none\0"), + true, false, 0 + }, + { + NULL + } +}; + +static const struct expansionboardsettings x86_bridge_sidecar_settings[] = { + { + // 0 + _T("System Diagnostics (SW1:1)"), + _T("diagnostics"), + }, + { + // 1 + _T("8037 installed (SW1:2)"), + _T("fpu"), + }, + { + // 2-3 + _T("Memory (SW1:3-4)\0""128K\0""256K\0""512K\0""640K\0"), + _T("memory\0""128k\0""256k\0""512k\0""640k\0"), + true + }, + { + // 4-5 + _T("Default video (SW1:5-6)\0Monochrome\0Color 40x25\0Color 80x25\0None\0"), + _T("video\0mono\0color40\0color80\0none\0"), + true + }, + { + // 6-7 + _T("Floppy drives (SW1:7-8)\0""1\0""2\0""3\0""4\0"), + _T("floppy\0""floppy1\0""floppy2\0""floppy3\0""floppy4\0"), + true + }, + { + // 8 + _T("Disable mono video emulation (SW2:1)"), + _T("mono_card") + }, + { + // 9 + _T("Disable color video emulation (SW2:2)"), + _T("color_card") + }, + { + // 10-11 + _T("Address sector (SW2:3-4)\0A0000-AFFFF\0A0000-AFFFF\0D0000-DFFFF\0E0000-EFFFF\0"), + _T("memory\0sector_a0000_1\0sector_a0000_2\0sector_d0000\0sector_e0000\0"), + true + }, + { + // 12 + _T("Disable parallel port emulation (J11)"), + _T("parport_card") + }, + { + NULL + } +}; + static void fastlane_memory_callback(struct romconfig *rc, uae_u8 *ac, int size) { struct zfile *z = read_device_from_romconfig(rc, NULL); @@ -2741,6 +2815,33 @@ const struct expansionromtype expansionroms[] = { _T("amax"), _T("AMAX ROM dongle"), _T("ReadySoft"), NULL, 0, NULL, NULL, NULL, ROMTYPE_AMAX | ROMTYPE_NONE, 0, 0, 0, false }, + { + _T("a1060"), _T("A1060 Sidecar"), _T("Commodore"), + a1060_init, NULL, NULL, ROMTYPE_A1060 | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false, + NULL, 0, + false, EXPANSIONTYPE_X86_BRIDGE, + 0, 0, 0, false, NULL, + false, + x86_bridge_sidecar_settings + }, + { + _T("a2088"), _T("A2088"), _T("Commodore"), + a2088xt_init, NULL, NULL, ROMTYPE_A2088XT | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false, + NULL, 0, + false, EXPANSIONTYPE_X86_BRIDGE, + 0, 0, 0, false, NULL, + false, + x86_bridge_settings + }, + { + _T("a2088t"), _T("A2088T"), _T("Commodore"), + a2088t_init, NULL, NULL, ROMTYPE_A2088T | ROMTYPE_NONE, 0, 0, BOARD_AUTOCONFIG_Z2, false, + NULL, 0, + false, EXPANSIONTYPE_X86_BRIDGE, + 0, 0, 0, false, NULL, + false, + x86_bridge_settings + }, { NULL } diff --git a/fake86_cpu.cpp b/fake86_cpu.cpp new file mode 100644 index 00000000..7074be56 --- /dev/null +++ b/fake86_cpu.cpp @@ -0,0 +1,3577 @@ +/* + 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. +*/ + +/* cpu.c: functions to emulate the 8086/V20 CPU in software. the heart of Fake86. */ + +#include +#include + +#define CPU_V20 +static int x86_cpu_v20; + +extern void write_log(const char*,...); + + +#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]; +}; + +#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) + +#if 0 +#include "config.h" +#include +#include +#include "cpu.h" +#include "i8259.h" +#include "i8253.h" + +extern struct i8253_s i8253; + +extern struct structpic i8259; +#endif + +uint64_t curtimer, lasttimer, timerfreq; + +static 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 +}; + +#if 0 +uint8_t RAM[0x100000], readonly[0x100000]; +#endif +static uint8_t opcode, segoverride, reptype, bootdrive = 0, hdcount = 0; +static uint16_t segregs[4], savecs, saveip, ip, useseg, oldsp; +static uint8_t tempcf, oldcf, cf, pf, af, zf, sf, tf, ifl, df, of, mode, reg, rm; +static uint16_t oper1, oper2, res16, disp16, temp16, dummy, stacksize, frametemp; +static uint8_t oper1b, oper2b, res8, disp8, temp8, nestlev, addrbyte; +static uint32_t temp1, temp2, temp3, temp4, temp5, temp32, tempaddr32, ea; +static int32_t result; +static uint64_t totalexec; + +#if 0 +extern uint16_t VGA_SC[0x100], VGA_CRTC[0x100], VGA_ATTR[0x100], VGA_GC[0x100]; +extern uint8_t updatedscreen; +#endif + +union _bytewordregs_ regs; + +#if 0 +uint8_t portram[0x10000]; +uint8_t running = 0, debugmode, showcsip, verbose; +uint8_t ethif; +#endif +static int verbose = 1; +static int running = 1; + +#if 0 +extern uint8_t vidmode; +extern uint8_t verbose; + +extern void vidinterrupt(); + +extern uint8_t readVGA (uint32_t addr32); +#endif + +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; \ + } + +#if 0 +extern void writeVGA (uint32_t addr32, uint8_t value); +#endif +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); +void writew86(uint32_t addr32, uint16_t value); +uint8_t read86(uint32_t addr32); +uint16_t readw86(uint32_t addr32); + +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); +} + +#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; \ + } \ + } + +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) { + putreg16 (regsp, getreg16 (regsp) - 2); + putmem16 (segregs[regss], getreg16 (regsp), pushval); +} + +uint16_t pop() { + + uint16_t tempval; + + tempval = getmem16 (segregs[regss], getreg16 (regsp) ); + putreg16 (regsp, getreg16 (regsp) + 2); + return tempval; +} + +void reset86(int v20) { + segregs[regcs] = 0xFFFF; + ip = 0x0000; + x86_cpu_v20 = v20; + //regs.wordregs[regsp] = 0xFFFE; +} + +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; + if (x86_cpu_v20) + cnt &= 0x1F; + 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); + } + 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; + if (x86_cpu_v20) + cnt &= 0x1F; + 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]; + putreg16 (regax, temp1 & 0xFFFF); + flag_szp8 ( (uint8_t) temp1); + if (regs.byteregs[regah]) { + cf = 1; + of = 1; + } + else { + cf = 0; + of = 0; + } + + if (!x86_cpu_v20) + zf = 0; + 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; + putreg16 (regax, temp3 & 0xFFFF); + if (regs.byteregs[regah]) { + cf = 1; + of = 1; + } + else { + cf = 0; + of = 0; + } + if (!x86_cpu_v20) + zf = 0; + break; + + case 6: /* DIV */ + op_div8 (getreg16 (regax), oper1b); + break; + + case 7: /* IDIV */ + op_idiv8 (getreg16 (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; + } + + putreg16 (regdx, valdiv % (uint32_t) divisor); + putreg16 (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; + } + + putreg16 (regax, d1); + putreg16 (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) getreg16 (regax); + putreg16 (regax, temp1 & 0xFFFF); + putreg16 (regdx, temp1 >> 16); + flag_szp16 ( (uint16_t) temp1); + if (getreg16 (regdx) ) { + cf = 1; + of = 1; + } + else { + cf = 0; + of = 0; + } + if (!x86_cpu_v20) + zf = 0; + break; + + case 5: /* IMUL */ + temp1 = getreg16 (regax); + temp2 = oper1; + if (temp1 & 0x8000) { + temp1 |= 0xFFFF0000; + } + + if (temp2 & 0x8000) { + temp2 |= 0xFFFF0000; + } + + temp3 = temp1 * temp2; + putreg16 (regax, temp3 & 0xFFFF); /* into register ax */ + putreg16 (regdx, temp3 >> 16); /* into register dx */ + if (getreg16 (regdx) ) { + cf = 1; + of = 1; + } + else { + cf = 0; + of = 0; + } + if (!x86_cpu_v20) + zf = 0; + break; + + case 6: /* DIV */ + op_div16 ( ( (uint32_t) getreg16 (regdx) << 16) + getreg16 (regax), oper1); + break; + + case 7: /* DIV */ + op_idiv16 ( ( (uint32_t) getreg16 (regdx) << 16) + getreg16 (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; + } +} + +#if 0 +uint8_t dolog = 0, didintr = 0; +FILE *logout; +uint8_t printops = 0; +#endif + +#ifdef NETWORKING_ENABLED +extern void nethandler(); +#endif +#if 0 +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); +#endif + +void intcall86(uint8_t intnum) +{ +#if 0 + static uint16_t lastint10ax; + uint16_t oldregax; + + didintr = 1; + + if (intnum == 0x19) didbootstrap = 1; + + switch (intnum) { + case 0x10: + updatedscreen = 1; + 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]; + break; +#ifndef DISK_CONTROLLER_ATA + case 0x19: //bootstrap + 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 + } +#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 +#if 0 +uint64_t frametimer = 0, didwhen = 0, didticks = 0; +uint32_t makeupticks = 0; +extern float timercomp; +uint64_t timerticks = 0, realticks = 0; +#endif +uint64_t lastcountertimer = 0, counterticks = 10000; +//extern uint8_t nextintr(); +//extern void timing(); + +extern void check_x86_irq(void); + +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 & 31) == 0) timing(); + + if (trap_toggle) { + intcall86 (1); + } + + if (tf) { + trap_toggle = 1; + } + else { + trap_toggle = 0; + } + + if (!trap_toggle && ifl) + check_x86_irq(); + + reptype = 0; + segoverride = 0; + useseg = segregs[regds]; + docontinue = 0; + firstip = ip; + +#if 0 + if ( (segregs[regcs] == 0xF000) && (ip == 0xE066) ) didbootstrap = 0; //detect if we hit the BIOS entry point to clear didbootstrap because we've rebooted +#endif + + while (!docontinue) { + segregs[regcs] = segregs[regcs] & 0xFFFF; + ip = ip & 0xFFFF; + savecs = segregs[regcs]; + saveip = ip; + opcode = getmem8 (segregs[regcs], ip); + 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++; + + /* + * if (printops == 1) { printf("%04X:%04X - %s\n", savecs, saveip, oplist[opcode]); + * } + */ + 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 = (getreg16 (regax) ); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + op_add16(); + putreg16 (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 = getreg16 (regax); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + op_or16(); + putreg16 (regax, res16); + break; + + case 0xE: /* 0E PUSH segregs[regcs] */ + push (segregs[regcs]); + break; + + case 0xF: //0F POP CS + if (!x86_cpu_v20) + segregs[regcs] = pop(); + break; + + 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 = getreg16 (regax); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + op_adc16(); + putreg16 (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 = getreg16 (regax); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + op_sbb16(); + putreg16 (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 = getreg16 (regax); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + op_and16(); + putreg16 (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] & 0xF0) > 0x90) || (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 = getreg16 (regax); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + op_sub16(); + putreg16 (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 = getreg16 (regax); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + op_xor16(); + putreg16 (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 = getreg16 (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 = getreg16 (regax); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regax, res16); + break; + + case 0x41: /* 41 INC eCX */ + oldcf = cf; + oper1 = getreg16 (regcx); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regcx, res16); + break; + + case 0x42: /* 42 INC eDX */ + oldcf = cf; + oper1 = getreg16 (regdx); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regdx, res16); + break; + + case 0x43: /* 43 INC eBX */ + oldcf = cf; + oper1 = getreg16 (regbx); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regbx, res16); + break; + + case 0x44: /* 44 INC eSP */ + oldcf = cf; + oper1 = getreg16 (regsp); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regsp, res16); + break; + + case 0x45: /* 45 INC eBP */ + oldcf = cf; + oper1 = getreg16 (regbp); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regbp, res16); + break; + + case 0x46: /* 46 INC eSI */ + oldcf = cf; + oper1 = getreg16 (regsi); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regsi, res16); + break; + + case 0x47: /* 47 INC eDI */ + oldcf = cf; + oper1 = getreg16 (regdi); + oper2 = 1; + op_add16(); + cf = oldcf; + putreg16 (regdi, res16); + break; + + case 0x48: /* 48 DEC eAX */ + oldcf = cf; + oper1 = getreg16 (regax); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regax, res16); + break; + + case 0x49: /* 49 DEC eCX */ + oldcf = cf; + oper1 = getreg16 (regcx); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regcx, res16); + break; + + case 0x4A: /* 4A DEC eDX */ + oldcf = cf; + oper1 = getreg16 (regdx); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regdx, res16); + break; + + case 0x4B: /* 4B DEC eBX */ + oldcf = cf; + oper1 = getreg16 (regbx); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regbx, res16); + break; + + case 0x4C: /* 4C DEC eSP */ + oldcf = cf; + oper1 = getreg16 (regsp); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regsp, res16); + break; + + case 0x4D: /* 4D DEC eBP */ + oldcf = cf; + oper1 = getreg16 (regbp); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regbp, res16); + break; + + case 0x4E: /* 4E DEC eSI */ + oldcf = cf; + oper1 = getreg16 (regsi); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regsi, res16); + break; + + case 0x4F: /* 4F DEC eDI */ + oldcf = cf; + oper1 = getreg16 (regdi); + oper2 = 1; + op_sub16(); + cf = oldcf; + putreg16 (regdi, res16); + break; + + case 0x50: /* 50 PUSH eAX */ + push (getreg16 (regax) ); + break; + + case 0x51: /* 51 PUSH eCX */ + push (getreg16 (regcx) ); + break; + + case 0x52: /* 52 PUSH eDX */ + push (getreg16 (regdx) ); + break; + + case 0x53: /* 53 PUSH eBX */ + push (getreg16 (regbx) ); + break; + + case 0x54: /* 54 PUSH eSP */ + push (getreg16 (regsp) - 2); + break; + + case 0x55: /* 55 PUSH eBP */ + push (getreg16 (regbp) ); + break; + + case 0x56: /* 56 PUSH eSI */ + push (getreg16 (regsi) ); + break; + + case 0x57: /* 57 PUSH eDI */ + push (getreg16 (regdi) ); + break; + + case 0x58: /* 58 POP eAX */ + putreg16 (regax, pop() ); + break; + + case 0x59: /* 59 POP eCX */ + putreg16 (regcx, pop() ); + break; + + case 0x5A: /* 5A POP eDX */ + putreg16 (regdx, pop() ); + break; + + case 0x5B: /* 5B POP eBX */ + putreg16 (regbx, pop() ); + break; + + case 0x5C: /* 5C POP eSP */ + putreg16 (regsp, pop() ); + break; + + case 0x5D: /* 5D POP eBP */ + putreg16 (regbp, pop() ); + break; + + case 0x5E: /* 5E POP eSI */ + putreg16 (regsi, pop() ); + break; + + case 0x5F: /* 5F POP eDI */ + putreg16 (regdi, pop() ); + break; + + case 0x60: /* 60 PUSHA (80186+) */ + if (!x86_cpu_v20) + goto nov20; + oldsp = getreg16 (regsp); + push (getreg16 (regax) ); + push (getreg16 (regcx) ); + push (getreg16 (regdx) ); + push (getreg16 (regbx) ); + push (oldsp); + push (getreg16 (regbp) ); + push (getreg16 (regsi) ); + push (getreg16 (regdi) ); + break; + + case 0x61: /* 61 POPA (80186+) */ + if (!x86_cpu_v20) + goto nov20; + putreg16 (regdi, pop() ); + putreg16 (regsi, pop() ); + putreg16 (regbp, pop() ); + dummy = pop(); + putreg16 (regbx, pop() ); + putreg16 (regdx, pop() ); + putreg16 (regcx, pop() ); + putreg16 (regax, pop() ); + break; + + case 0x62: /* 62 BOUND Gv, Ev (80186+) */ + if (!x86_cpu_v20) + goto nov20; + 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+) */ + if (!x86_cpu_v20) + goto nov20; + push (getmem16 (segregs[regcs], ip) ); + StepIP (2); + break; + + case 0x69: /* 69 IMUL Gv Ev Iv (80186+) */ + if (!x86_cpu_v20) + goto nov20; + 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+) */ + if (!x86_cpu_v20) + goto nov20; + push (getmem8 (segregs[regcs], ip) ); + StepIP (1); + break; + + case 0x6B: /* 6B IMUL Gv Eb Ib (80186+) */ + if (!x86_cpu_v20) + goto nov20; + 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 (!x86_cpu_v20) + goto nov20; + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + putmem8 (useseg, getreg16 (regsi) , portin (regs.wordregs[regdx]) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 1); + putreg16 (regdi, getreg16 (regdi) - 1); + } + else { + putreg16 (regsi, getreg16 (regsi) + 1); + putreg16 (regdi, getreg16 (regdi) + 1); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0x6D: /* 6F INSW */ + if (!x86_cpu_v20) + goto nov20; + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + putmem16 (useseg, getreg16 (regsi) , portin16 (regs.wordregs[regdx]) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 2); + putreg16 (regdi, getreg16 (regdi) - 2); + } + else { + putreg16 (regsi, getreg16 (regsi) + 2); + putreg16 (regdi, getreg16 (regdi) + 2); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0x6E: /* 6E OUTSB */ + if (!x86_cpu_v20) + goto nov20; + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + portout (regs.wordregs[regdx], getmem8 (useseg, getreg16 (regsi) ) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 1); + putreg16 (regdi, getreg16 (regdi) - 1); + } + else { + putreg16 (regsi, getreg16 (regsi) + 1); + putreg16 (regdi, getreg16 (regdi) + 1); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0x6F: /* 6F OUTSW */ + if (!x86_cpu_v20) + goto nov20; + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + portout16 (regs.wordregs[regdx], getmem16 (useseg, getreg16 (regsi) ) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 2); + putreg16 (regdi, getreg16 (regdi) - 2); + } + else { + putreg16 (regsi, getreg16 (regsi) + 2); + putreg16 (regdi, getreg16 (regdi) + 2); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + 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 = getreg16 (regcx); + putreg16 (regcx, getreg16 (regax) ); + putreg16 (regax, oper1); + break; + + case 0x92: /* 92 XCHG eDX eAX */ + oper1 = getreg16 (regdx); + putreg16 (regdx, getreg16 (regax) ); + putreg16 (regax, oper1); + break; + + case 0x93: /* 93 XCHG eBX eAX */ + oper1 = getreg16 (regbx); + putreg16 (regbx, getreg16 (regax) ); + putreg16 (regax, oper1); + break; + + case 0x94: /* 94 XCHG eSP eAX */ + oper1 = getreg16 (regsp); + putreg16 (regsp, getreg16 (regax) ); + putreg16 (regax, oper1); + break; + + case 0x95: /* 95 XCHG eBP eAX */ + oper1 = getreg16 (regbp); + putreg16 (regbp, getreg16 (regax) ); + putreg16 (regax, oper1); + break; + + case 0x96: /* 96 XCHG eSI eAX */ + oper1 = getreg16 (regsi); + putreg16 (regsi, getreg16 (regax) ); + putreg16 (regax, oper1); + break; + + case 0x97: /* 97 XCHG eDI eAX */ + oper1 = getreg16 (regdi); + putreg16 (regdi, getreg16 (regax) ); + putreg16 (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) { + putreg16 (regdx, 0xFFFF); + } + else { + putreg16 (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 */ + push (makeflagsword() | 0xF800); + 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); + putreg16 (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), getreg16 (regax) ); + StepIP (2); + break; + + case 0xA4: /* A4 MOVSB */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + putmem8 (segregs[reges], getreg16 (regdi), getmem8 (useseg, getreg16 (regsi) ) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 1); + putreg16 (regdi, getreg16 (regdi) - 1); + } + else { + putreg16 (regsi, getreg16 (regsi) + 1); + putreg16 (regdi, getreg16 (regdi) + 1); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0xA5: /* A5 MOVSW */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + putmem16 (segregs[reges], getreg16 (regdi), getmem16 (useseg, getreg16 (regsi) ) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 2); + putreg16 (regdi, getreg16 (regdi) - 2); + } + else { + putreg16 (regsi, getreg16 (regsi) + 2); + putreg16 (regdi, getreg16 (regdi) + 2); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0xA6: /* A6 CMPSB */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + oper1b = getmem8 (useseg, getreg16 (regsi) ); + oper2b = getmem8 (segregs[reges], getreg16 (regdi) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 1); + putreg16 (regdi, getreg16 (regdi) - 1); + } + else { + putreg16 (regsi, getreg16 (regsi) + 1); + putreg16 (regdi, getreg16 (regdi) + 1); + } + + flag_sub8 (oper1b, oper2b); + if (reptype) { + putreg16 (regcx, getreg16 (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 && (getreg16 (regcx) == 0) ) { + break; + } + + oper1 = getmem16 (useseg, getreg16 (regsi) ); + oper2 = getmem16 (segregs[reges], getreg16 (regdi) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 2); + putreg16 (regdi, getreg16 (regdi) - 2); + } + else { + putreg16 (regsi, getreg16 (regsi) + 2); + putreg16 (regdi, getreg16 (regdi) + 2); + } + + flag_sub16 (oper1, oper2); + if (reptype) { + putreg16 (regcx, getreg16 (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 = getreg16 (regax); + oper2 = getmem16 (segregs[regcs], ip); + StepIP (2); + flag_log16 (oper1 & oper2); + break; + + case 0xAA: /* AA STOSB */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + putmem8 (segregs[reges], getreg16 (regdi), regs.byteregs[regal]); + if (df) { + putreg16 (regdi, getreg16 (regdi) - 1); + } + else { + putreg16 (regdi, getreg16 (regdi) + 1); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0xAB: /* AB STOSW */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + putmem16 (segregs[reges], getreg16 (regdi), getreg16 (regax) ); + if (df) { + putreg16 (regdi, getreg16 (regdi) - 2); + } + else { + putreg16 (regdi, getreg16 (regdi) + 2); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0xAC: /* AC LODSB */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + regs.byteregs[regal] = getmem8 (useseg, getreg16 (regsi) ); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 1); + } + else { + putreg16 (regsi, getreg16 (regsi) + 1); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0xAD: /* AD LODSW */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + oper1 = getmem16 (useseg, getreg16 (regsi) ); + putreg16 (regax, oper1); + if (df) { + putreg16 (regsi, getreg16 (regsi) - 2); + } + else { + putreg16 (regsi, getreg16 (regsi) + 2); + } + + if (reptype) { + putreg16 (regcx, getreg16 (regcx) - 1); + } + + totalexec++; + loopcount++; + if (!reptype) { + break; + } + + ip = firstip; + break; + + case 0xAE: /* AE SCASB */ + if (reptype && (getreg16 (regcx) == 0) ) { + break; + } + + oper1b = getmem8 (segregs[reges], getreg16 (regdi) ); + oper2b = regs.byteregs[regal]; + flag_sub8 (oper1b, oper2b); + if (df) { + putreg16 (regdi, getreg16 (regdi) - 1); + } + else { + putreg16 (regdi, getreg16 (regdi) + 1); + } + + if (reptype) { + putreg16 (regcx, getreg16 (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 && (getreg16 (regcx) == 0) ) { + break; + } + + oper1 = getmem16 (segregs[reges], getreg16 (regdi) ); + oper2 = getreg16 (regax); + flag_sub16 (oper1, oper2); + if (df) { + putreg16 (regdi, getreg16 (regdi) - 2); + } + else { + putreg16 (regdi, getreg16 (regdi) + 2); + } + + if (reptype) { + putreg16 (regcx, getreg16 (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); + putreg16 (regax, oper1); + break; + + case 0xB9: /* B9 MOV eCX Iv */ + oper1 = getmem16 (segregs[regcs], ip); + StepIP (2); + putreg16 (regcx, oper1); + break; + + case 0xBA: /* BA MOV eDX Iv */ + oper1 = getmem16 (segregs[regcs], ip); + StepIP (2); + putreg16 (regdx, oper1); + break; + + case 0xBB: /* BB MOV eBX Iv */ + oper1 = getmem16 (segregs[regcs], ip); + StepIP (2); + putreg16 (regbx, oper1); + break; + + case 0xBC: /* BC MOV eSP Iv */ + putreg16 (regsp, getmem16 (segregs[regcs], ip) ); + StepIP (2); + break; + + case 0xBD: /* BD MOV eBP Iv */ + putreg16 (regbp, getmem16 (segregs[regcs], ip) ); + StepIP (2); + break; + + case 0xBE: /* BE MOV eSI Iv */ + putreg16 (regsi, getmem16 (segregs[regcs], ip) ); + StepIP (2); + break; + + case 0xBF: /* BF MOV eDI Iv */ + putreg16 (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(); + putreg16 (regsp, getreg16 (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 (getreg16 (regbp) ); + frametemp = getreg16 (regsp); + if (nestlev) { + for (temp16 = 1; temp16 < nestlev; temp16++) { + putreg16 (regbp, getreg16 (regbp) - 2); + push (getreg16 (regbp) ); + } + + push (getreg16 (regsp) ); + } + + putreg16 (regbp, frametemp); + putreg16 (regsp, getreg16 (regbp) - stacksize); + + break; + + case 0xC9: /* C9 LEAVE (80186+) */ + putreg16 (regsp, getreg16 (regbp) ); + putreg16 (regbp, pop() ); + + break; + + case 0xCA: /* CA RETF Iw */ + oper1 = getmem16 (segregs[regcs], ip); + ip = pop(); + segregs[regcs] = pop(); + putreg16 (regsp, getreg16 (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 (getreg16 (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 */ + + if (x86_cpu_v20) + regs.byteregs[regal] = read86(useseg * 16 + (regs.wordregs[regbx]) + regs.byteregs[regal]); + else + regs.byteregs[regal] = cf ? 0xFF : 0x00; + break; + + 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); + putreg16 (regcx, getreg16 (regcx) - 1); + if ( (getreg16 (regcx) ) && !zf) { + ip = ip + temp16; + } + break; + + case 0xE1: /* E1 LOOPZ Jb */ + temp16 = signext (getmem8 (segregs[regcs], ip) ); + StepIP (1); + putreg16 (regcx, (getreg16 (regcx) ) - 1); + if ( (getreg16 (regcx) ) && (zf == 1) ) { + ip = ip + temp16; + } + break; + + case 0xE2: /* E2 LOOP Jb */ + temp16 = signext (getmem8 (segregs[regcs], ip) ); + StepIP (1); + putreg16 (regcx, (getreg16 (regcx) ) - 1); + if (getreg16 (regcx) ) { + ip = ip + temp16; + } + break; + + case 0xE3: /* E3 JCXZ Jb */ + temp16 = signext (getmem8 (segregs[regcs], ip) ); + StepIP (1); + if (! (getreg16 (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); + putreg16 (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, (getreg16 (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 = (getreg16 (regdx) ); + regs.byteregs[regal] = (uint8_t) portin (oper1); + break; + + case 0xED: /* ED IN eAX regdx */ + oper1 = (getreg16 (regdx) ); + putreg16 (regax, portin16 (oper1) ); + break; + + case 0xEE: /* EE OUT regdx regs.byteregs[regal] */ + oper1 = (getreg16 (regdx) ); + portout (oper1, regs.byteregs[regal]); + break; + + case 0xEF: /* EF OUT regdx eAX */ + oper1 = (getreg16 (regdx) ); + portout16 (oper1, (getreg16 (regax) ) ); + break; + + case 0xF0: /* F0 LOCK */ + break; + + case 0xF4: /* F4 HLT */ + ip--; + 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: +nov20: + if (x86_cpu_v20) + 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. */ + + if (verbose) { + write_log ("Illegal opcode: %02X @ %04X:%04X\n", opcode, savecs, saveip); + } + break; + } + + if (!running) { + return; + } + } +} + diff --git a/include/autoconf.h b/include/autoconf.h index 7006991a..fd6966a8 100644 --- a/include/autoconf.h +++ b/include/autoconf.h @@ -115,10 +115,14 @@ typedef void(*DEVICE_MEMORY_CALLBACK)(struct romconfig*, uae_u8*, int); #define EXPANSIONTYPE_CUSTOM 32 #define EXPANSIONTYPE_PCI_BRIDGE 64 #define EXPANSIONTYPE_PARALLEL_ADAPTER 128 +#define EXPANSIONTYPE_X86_BRIDGE 256 struct expansionboardsettings { const TCHAR *name; const TCHAR *configname; + bool multiselect; + bool invert; + int bitshift; }; struct expansionsubromtype { diff --git a/include/disk.h b/include/disk.h index 038a867f..8d8bb342 100644 --- a/include/disk.h +++ b/include/disk.h @@ -6,7 +6,7 @@ * (c) 1995 Bernd Schmidt */ -typedef enum { DRV_NONE = -1, DRV_35_DD = 0, DRV_35_HD, DRV_525_SD, DRV_35_DD_ESCOM } drive_type; +typedef enum { DRV_NONE = -1, DRV_35_DD = 0, DRV_35_HD, DRV_525_SD, DRV_35_DD_ESCOM, DRV_PC_ONLY } drive_type; #define HISTORY_FLOPPY 0 #define HISTORY_CD 1 @@ -27,6 +27,18 @@ struct diskinfo TCHAR diskname[110]; }; +struct floppy_reserved +{ + struct zfile *img; + bool wrprot; + int cyl; + int cyls; + int heads; + int secs; +}; +void disk_reserved_setinfo(int num, int cyl, int head, int motor); +bool disk_reserved_getinfo(int num, struct floppy_reserved *fr); + extern void DISK_init (void); extern void DISK_free (void); extern void DISK_select (uae_u8 data); diff --git a/include/rommgr.h b/include/rommgr.h index 62093008..069c6f1d 100644 --- a/include/rommgr.h +++ b/include/rommgr.h @@ -85,6 +85,9 @@ extern int decode_cloanto_rom_do (uae_u8 *mem, int size, int real_size); #define ROMTYPE_ALF1 0x00100027 #define ROMTYPE_PROMIGOS 0x00100028 #define ROMTYPE_SYSTEM2000 0x00100029 +#define ROMTYPE_A1060 0x0010002a +#define ROMTYPE_A2088XT 0x0010002b +#define ROMTYPE_A2088T 0x0010002c #define ROMTYPE_NOT 0x00800000 #define ROMTYPE_QUAD 0x01000000 diff --git a/include/x86.h b/include/x86.h new file mode 100644 index 00000000..3bcd44fa --- /dev/null +++ b/include/x86.h @@ -0,0 +1,14 @@ + +extern addrbank *a1060_init(struct romconfig *rc); +extern addrbank *a2088xt_init(struct romconfig *rc); +extern addrbank *a2088t_init(struct romconfig *rc); +void x86_bridge_hsync(void); +void x86_bridge_reset(void); +void x86_bridge_free(void); +void x86_bridge_rethink(void); + +#define X86_STATE_INACTIVE 0 +#define X86_STATE_STOP 1 +#define X86_STATE_ACTIVE 2 + +int is_x86_cpu(struct uae_prefs*); diff --git a/od-win32/sysconfig.h b/od-win32/sysconfig.h index 30045dbb..acf3ece4 100644 --- a/od-win32/sysconfig.h +++ b/od-win32/sysconfig.h @@ -94,6 +94,7 @@ #define WITH_QEMU_CPU #define WITH_TOCCATA #define WITH_PCI +#define WITH_X86 #else diff --git a/x86.cpp b/x86.cpp new file mode 100644 index 00000000..4952d21b --- /dev/null +++ b/x86.cpp @@ -0,0 +1,2033 @@ +/* +* UAE - The Un*x Amiga Emulator +* +* X86 Bridge board emulation +* A1060, A2088, A2088T +* +* Copyright 2015 Toni Wilen +* x86 and PC support chip emulation from Fake86. +* +*/ + +#define X86_DEBUG_BRIDGE 1 +#define FLOPPY_IO_DEBUG 0 +#define X86_DEBUG_BRIDGE_IO 0 + +#include "sysconfig.h" +#include "sysdeps.h" + +#include "options.h" +#include "custom.h" +#include "memory.h" +#include "debug.h" +#include "x86.h" +#include "newcpu.h" +#include "uae.h" +#include "rommgr.h" +#include "autoconf.h" +#include "zfile.h" +#include "disk.h" + +#define TYPE_SIDECAR 0 +#define TYPE_2088 1 +#define TYPE_2088T 2 + +void x86_init(unsigned char *memp, unsigned char *iop); +void x86_reset(void); +int x86_execute(void); + +void exec86(uint32_t execloops); +void reset86(int v20); +void intcall86(uint8_t intnum); + +static void doirq(uint8_t irqnum); + +static frame_time_t last_cycles; + +struct x86_bridge +{ + uae_u8 acmemory[128]; + addrbank *bank; + int configured; + int type; + uaecptr baseaddress; + uae_u8 *pc_ram; + uae_u8 *io_ports; + uae_u8 *amiga_io; + bool x86_reset; + bool amiga_irq; + bool amiga_forced_interrupts; + bool pc_irq3a, pc_irq3b, pc_irq7; + uae_u8 pc_jumpers; + int pc_maxram; + int settings; +}; + +#define X86_BRIDGE_A1060 0 +#define X86_BRIDGE_MAX (X86_BRIDGE_A1060 + 1) + +#define ACCESS_MODE_BYTE 0 +#define ACCESS_MODE_WORD 1 +#define ACCESS_MODE_GFX 2 +#define ACCESS_MODE_IO 3 + +#define IO_AMIGA_INTERRUPT_STATUS 0x1ff1 +#define IO_PC_INTERRUPT_STATUS 0x1ff3 +#define IO_NEGATE_PC_RESET 0x1ff5 +#define IO_MODE_REGISTER 0x1ff7 +#define IO_INTERRUPT_MASK 0x1ff9 +#define IO_PC_INTERRUPT_CONTROL 0x1ffb +#define IO_CONTROL_REGISTER 0x1ffd +#define IO_KEYBOARD_REGISTER_A1000 0x61f +#define IO_KEYBOARD_REGISTER_A2000 0x1fff + +static struct x86_bridge *bridges[X86_BRIDGE_MAX]; + +static struct x86_bridge *x86_bridge_alloc(void) +{ + struct x86_bridge *xb = xcalloc(struct x86_bridge, 1); + return xb; +}; + +static uae_u8 get_mode_register(struct x86_bridge *xb, uae_u8 v) +{ + if (xb->type == TYPE_SIDECAR) { + v = 0x84; + if (!(xb->settings & (1 << 12))) + v |= 0x02; + if (!(xb->settings & (1 << 8))) + v |= 0x08; + if (!(xb->settings & (1 << 9))) + v |= 0x10; + if ((xb->settings & (1 << 10))) + v |= 0x20; + if ((xb->settings & (1 << 11))) + v |= 0x40; + } else { + v |= 0x80; + } + return v; +} + +static uae_u8 x86_bridge_put_io(struct x86_bridge *xb, uaecptr addr, uae_u8 v) +{ +#if X86_DEBUG_BRIDGE_IO + write_log(_T("IO write %08x %02x\n"), addr, v); +#endif + + switch (addr) + { + // read-only + case IO_AMIGA_INTERRUPT_STATUS: + v = xb->amiga_io[addr]; + break; + case IO_PC_INTERRUPT_STATUS: + v = xb->amiga_io[addr]; +#if X86_DEBUG_BRIDGE_IRQ + write_log(_T("IO_PC_INTERRUPT_STATUS %02x\n"), v); +#endif + break; + case IO_NEGATE_PC_RESET: + v = xb->amiga_io[addr]; + break; + case IO_PC_INTERRUPT_CONTROL: + if ((v & 1) || (v & (2 | 4 | 8)) != (2 | 4 | 8)) { +#if X86_DEBUG_BRIDGE_IRQ + write_log(_T("IO_PC_INTERRUPT_CONTROL %02x\n"), v); +#endif + if (xb->amiga_forced_interrupts) { + if (v & 1) + doirq(1); + if (xb->amiga_io[IO_CONTROL_REGISTER] & 8) { + if (!(v & 2) || !(v & 4)) + doirq(3); + if (!(v & 8)) + doirq(7); + } + } + } + break; + case IO_CONTROL_REGISTER: + if (!(v & 0x4)) { + xb->x86_reset = true; + } + if (!(v & 1)) + v |= 2; + else if (!(v & 2)) + v |= 1; +#if X86_DEBUG_BRIDGE_IO + write_log(_T("IO_CONTROL_REGISTER %02x\n"), v); +#endif + break; + case IO_KEYBOARD_REGISTER_A1000: + if (xb->type == TYPE_SIDECAR) { +#if X86_DEBUG_BRIDGE_IO + write_log(_T("IO_KEYBOARD_REGISTER %02x\n"), v); +#endif + xb->io_ports[0x60] = v; + } + break; + case IO_KEYBOARD_REGISTER_A2000: + if (xb->type >= TYPE_2088) { +#if X86_DEBUG_BRIDGE_IO + write_log(_T("IO_KEYBOARD_REGISTER %02x\n"), v); +#endif + xb->io_ports[0x60] = v; + } + break; + case IO_MODE_REGISTER: + v = get_mode_register(xb, v); +#if X86_DEBUG_BRIDGE_IO + write_log(_T("IO_MODE_REGISTER %02x\n"), v); +#endif + break; + } + + xb->amiga_io[addr] = v; + return v; +} +static uae_u8 x86_bridge_get_io(struct x86_bridge *xb, uaecptr addr) +{ + uae_u8 v = xb->amiga_io[addr]; + + v = xb->amiga_io[addr]; + + switch(addr) + { + case IO_AMIGA_INTERRUPT_STATUS: + xb->amiga_io[addr] = 0; +#if X86_DEBUG_BRIDGE_IRQ + if (v) + write_log(_T("IO_AMIGA_INTERRUPT_STATUS %02x. CLEARED.\n"), v); +#endif + break; + case IO_PC_INTERRUPT_STATUS: + v |= 0xf0; +#if X86_DEBUG_BRIDGE_IRQ + write_log(_T("IO_PC_INTERRUPT_STATUS %02x\n"), v); +#endif + break; + case IO_NEGATE_PC_RESET: + { + if (xb->x86_reset) { + write_log(_T("x86 CPU start!\n")); + reset86(xb->type == TYPE_2088T); + xb->x86_reset = false; + } + // because janus.library has stupid CPU loop wait + int vp = vpos; + while (vp == vpos) { + x_do_cycles(maxhpos * CYCLE_UNIT); + } + } + break; + case IO_MODE_REGISTER: + v = get_mode_register(xb, v); +#if X86_DEBUG_BRIDGE_IO + write_log(_T("IO_MODE_REGISTER %02x\n"), v); +#endif + break; + } + + return v; +} + +static void set_interrupt(struct x86_bridge *xb, int bit) +{ + if (xb->amiga_io[IO_AMIGA_INTERRUPT_STATUS] & (1 << bit)) + return; +#if X86_DEBUG_BRIDGE_IRQ + write_log(_T("IO_AMIGA_INTERRUPT_STATUS set bit %d\n"), bit); +#endif + xb->amiga_io[IO_AMIGA_INTERRUPT_STATUS] |= 1 << bit; + x86_bridge_rethink(); +} + +/* 8237 and 8253 from fake86 with small modifications */ + +#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]; +}; +static struct i8253_s i8253; +static uint16_t latched_val, latched; + +static uint64_t hostfreq; +static uint64_t tickgap, curtick, lasttick, lasti8253tick, i8253tickgap; + +static void inittiming() +{ +#ifdef _WIN32 + LARGE_INTEGER queryperf; + 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 = lasttick = curtick; + i8253tickgap = hostfreq / 119318; +} + +static void timing(void) +{ + struct x86_bridge *xb = bridges[0]; + +#ifdef _WIN32 + LARGE_INTEGER queryperf; + 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 (i8253.active[0]) { //timer interrupt channel on i8253 + if (curtick >= (lasttick + tickgap)) { + lasttick = curtick; + doirq(0); + } + } + + if (curtick >= (lasti8253tick + i8253tickgap)) { + for (int i8253chan = 0; i8253chan<3; i8253chan++) { + bool cantrun = (i8253chan == 2 && !(xb->io_ports[0x61] & 1)); + if (i8253.active[i8253chan] && !cantrun) { + if (i8253.counter[i8253chan] < 10) + i8253.counter[i8253chan] = i8253.chandata[i8253chan]; + i8253.counter[i8253chan] -= 10; + } + } + lasti8253tick = curtick; + } +} + +static 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.counter[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_LATCHCOUNT) { + latched_val = i8253.counter[value >> 6]; + latched = 2; + } else if (i8253.accessmode[value >> 6] == PIT_MODE_TOGGLE) + i8253.bytetoggle[value >> 6] = 0; + break; + } +} + +static uint8_t in8253(uint16_t portnum) +{ + uint8_t curbyte; + portnum &= 3; + switch (portnum) + { + case 0: + case 1: + case 2: //channel data + if (latched == 2) { + latched = 1; + return latched_val & 0xff; + } else if (latched == 1) { + latched = 0; + return latched_val >> 8; + } + 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); +} + +//#define DEBUG_DMA + +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 modeselect; + uint8_t masked; + uint8_t verifymode; +}; + +static struct dmachan_s dmachan[4]; +static uint8_t flipflop = 0; + +static int write8237(struct x86_bridge *xb, uint8_t channel, uint8_t data) +{ + if (dmachan[channel].masked) + return 0; + if (dmachan[channel].autoinit && (dmachan[channel].count > dmachan[channel].reload)) + dmachan[channel].count = 0; + if (dmachan[channel].count > dmachan[channel].reload) + return 0; + //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].verifymode) { + xb->pc_ram[dmachan[channel].page + dmachan[channel].addr] = data; + if (dmachan[channel].direction == 0) { + dmachan[channel].addr++; + } else { + dmachan[channel].addr--; + } + dmachan[channel].addr &= 0xffff; + } + dmachan[channel].count++; + if (dmachan[channel].count > dmachan[channel].reload) + return -1; + return 1; +} + +static uint8_t read8237(struct x86_bridge *xb, uint8_t channel, bool *end) +{ + uint8_t ret = 128; + *end = false; + if (dmachan[channel].masked) { + *end = true; + return ret; + } + if (dmachan[channel].autoinit && (dmachan[channel].count > dmachan[channel].reload)) + dmachan[channel].count = 0; + if (dmachan[channel].count > dmachan[channel].reload) { + *end = true; + return ret; + } + //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].verifymode) { + ret = xb->pc_ram[dmachan[channel].page + dmachan[channel].addr]; + if (dmachan[channel].direction == 0) { + dmachan[channel].addr++; + } else { + dmachan[channel].addr--; + } + dmachan[channel].addr &= 0xffff; + } + dmachan[channel].count++; + if (dmachan[channel].count > dmachan[channel].reload) + *end = true; + return ret; +} + +static void out8237(uint16_t addr, uint8_t value) +{ + uint8_t channel; +#ifdef DEBUG_DMA + write_log("out8237(0x%X, %X);\n", addr, value); +#endif + switch (addr) { + case 0x0: + case 0x2: //channel 1 address register + case 0x4: + case 0x6: + channel = addr / 2; + if (flipflop == 1) + dmachan[channel].addr = (dmachan[channel].addr & 0x00FF) | ((uint32_t)value << 8); + else + dmachan[channel].addr = (dmachan[channel].addr & 0xFF00) | value; +#ifdef DEBUG_DMA + if (flipflop == 1) write_log("[NOTICE] DMA channel %d address register = %04X\n", channel, dmachan[channel].addr); +#endif + flipflop = ~flipflop & 1; + break; + case 0x1: + case 0x3: //channel 1 count register + case 0x5: + case 0x7: + channel = addr / 2; + if (flipflop == 1) + dmachan[channel].reload = (dmachan[channel].reload & 0x00FF) | ((uint32_t)value << 8); + else + dmachan[channel].reload = (dmachan[channel].reload & 0xFF00) | value; + if (flipflop == 1) { + if (dmachan[channel].reload == 0) + dmachan[channel].reload = 65536; + dmachan[channel].count = 0; +#ifdef DEBUG_DMA + write_log("[NOTICE] DMA channel %d reload register = %04X\n", channel, dmachan[channel].reload); +#endif + } + flipflop = ~flipflop & 1; + break; + case 0xA: //write single mask register + channel = value & 3; + dmachan[channel].masked = (value >> 2) & 1; +#ifdef DEBUG_DMA + write_log("[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].modeselect = (value >> 6) & 3; + dmachan[channel].writemode = (value >> 2) & 1; //not quite accurate + dmachan[channel].verifymode = ((value >> 2) & 3) == 0; +#ifdef DEBUG_DMA + write_log("[NOTICE] DMA channel %u write mode reg: direction = %u, autoinit = %u, write mode = %u, verify mode = %u, mode select = %u\n", + channel, dmachan[channel].direction, dmachan[channel].autoinit, dmachan[channel].writemode, dmachan[channel].verifymode, dmachan[channel].modeselect); +#endif + break; + case 0xC: //clear byte pointer flip-flop +#ifdef DEBUG_DMA + write_log("[NOTICE] DMA cleared byte pointer flip-flop\n"); +#endif + flipflop = 0; + break; + case 0x81: // 2 + case 0x82: // 3 + case 0x83: // DMA channel 1 page register + // Original PC design. It can't get any more stupid. + if (addr == 0x81) + channel = 2; + else if (addr == 0x82) + channel = 3; + else + channel = 1; + dmachan[channel].page = (uint32_t)value << 16; +#ifdef DEBUG_DMA + write_log("[NOTICE] DMA channel %d page base = %05X\n", channel, dmachan[channel].page); +#endif + break; + } +} + +static uint8_t in8237(uint16_t addr) +{ + uint8_t channel; +#ifdef DEBUG_DMA + write_log("in8237(0x%X);\n", addr); +#endif + switch (addr) { + case 0x0: + case 0x2: //channel 1 address register + case 0x4: + case 0x6: + channel = addr / 2; + flipflop = ~flipflop & 1; + if (flipflop == 0) + return dmachan[channel].addr >> 8; + else + return dmachan[channel].addr; + break; + case 0x1: + case 0x3: //channel 1 count register + case 0x5: + case 0x7: + channel = addr / 2; + flipflop = ~flipflop & 1; + if (flipflop == 0) + return dmachan[channel].reload >> 8; + else + return dmachan[channel].reload; + break; + } + return (0); +} + +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; +}; + +static struct structpic i8259; + +static 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; +static int keyboardwaitack; + +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 + if (keyboardwaitack) { + keyboardwaitack = 0; + set_interrupt(bridges[0], 4); + } + for (i = 0; i < 8; i++) + if ((i8259.isr >> i) & 1) { + i8259.isr ^= (1 << i); +#if 0 + if ((i == 0) && (makeupticks>0)) { + makeupticks = 0; + i8259.irr |= 1; + } +#endif + 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; + } +} + +static void doirq(uint8_t irqnum) +{ + i8259.irr |= (1 << irqnum); + if (irqnum == 1) + keyboardwaitack = 1; +} + +static uint8_t nextintr(void) +{ + 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 check_x86_irq(void) +{ + if (i8259.irr & (~i8259.imr)) { + intcall86(nextintr()); /* get next interrupt from the i8259, if any */ + } +} + +struct pc_floppy +{ + uae_u8 phys_cyl; + uae_u8 cyl; + uae_u8 sector; + uae_u8 head; +}; + +static struct pc_floppy floppy_pc[4]; +static uae_u8 floppy_dpc; +static uae_s8 floppy_idx; +static uae_u8 floppy_dir; +static uae_u8 floppy_cmd_len; +static uae_u8 floppy_cmd[16]; +static uae_u8 floppy_result[16]; +static uae_u8 floppy_status[4]; +static uae_u8 floppy_num; +static int floppy_delay_hsync; +static bool floppy_irq; +static bool floppy_did_reset; +static bool floppy_high_density; + +static void floppy_reset(void) +{ + write_log(_T("Floppy reset\n")); + floppy_idx = 0; + floppy_dir = 0; + floppy_did_reset = true; +} + +static void do_floppy_irq(void) +{ + if (floppy_delay_hsync > 0) { + floppy_irq = true; + doirq(6); + } + floppy_delay_hsync = 0; +} + +static int floppy_exists(void) +{ + uae_u8 sel = floppy_dpc & 3; + if (sel == 0) + return 0; + if (sel == 1) + return 1; + return -1; +} + +static int floppy_selected(void) +{ + uae_u8 motormask = (floppy_dpc >> 4) & 15; + uae_u8 sel = floppy_dpc & 3; + if (floppy_exists() < 0) + return -1; + if (motormask & (1 << sel)) + return sel; + return -1; +} + +static void floppy_do_cmd(struct x86_bridge *xb) +{ + uae_u8 cmd = floppy_cmd[0]; + struct pc_floppy *pcf = &floppy_pc[floppy_num]; + struct floppy_reserved fr = { 0 }; + bool valid_floppy; + + valid_floppy = disk_reserved_getinfo(floppy_num, &fr); + + if (cmd == 8) { + write_log(_T("Floppy%d Sense Interrupt Status\n"), floppy_num); + floppy_cmd_len = 2; + if (!floppy_irq) { + floppy_status[0] = 0x80; + floppy_cmd_len = 1; + } else if (floppy_did_reset) { + floppy_did_reset = false; + floppy_status[0] = 0xc0; + } + floppy_irq = false; + floppy_result[0] = floppy_status[0]; + floppy_result[1] = pcf->cyl; + floppy_status[0] = 0; + goto end; + } + + memset(floppy_status, 0, sizeof floppy_status); + memset(floppy_result, 0, sizeof floppy_result); + if (floppy_exists()) { + if (pcf->head) + floppy_status[0] |= 4; + floppy_status[3] |= pcf->cyl == 0 ? 0x10 : 0x00; + floppy_status[3] |= pcf->head ? 4 : 0; + floppy_status[3] |= 8; // two side + if (fr.wrprot) + floppy_status[3] |= 0x40; // write protected + floppy_status[3] |= 0x20; // ready + } + floppy_status[3] |= floppy_dpc & 3; + floppy_status[0] |= floppy_dpc & 3; + floppy_cmd_len = 0; + + switch (cmd & 31) + { + case 3: + write_log(_T("Floppy%d Specify SRT=%d HUT=%d HLT=%d ND=%d\n"), floppy_num, floppy_cmd[1] >> 6, floppy_cmd[1] & 0x3f, floppy_cmd[2] >> 1, floppy_cmd[2] & 1); + floppy_delay_hsync = -5; + break; + + case 4: + write_log(_T("Floppy%d Sense Interrupt Status\n"), floppy_num); + floppy_delay_hsync = 5; + floppy_result[0] = floppy_status[3]; + floppy_cmd_len = 1; + break; + + case 5: + { + write_log(_T("Floppy%d write MT=%d MF=%d C=%d:H=%d:R=%d:N=%d:EOT=%d:GPL=%d:DTL=%d\n"), + (floppy_cmd[0] & 0x80) ? 1 : 0, (floppy_cmd[0] & 0x40) ? 1 : 0, + floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5], + floppy_cmd[6], floppy_cmd[7], floppy_cmd[8], floppy_cmd[9]); + write_log(_T("DMA addr %08x len %04x\n"), dmachan[2].page | dmachan[2].addr, dmachan[2].reload); + floppy_delay_hsync = 50; + if (valid_floppy) { + if (fr.img && pcf->cyl != floppy_cmd[2]) { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[2] |= 0x20; // wrong cylinder + } else if (fr.img) { + bool end = false; + pcf->sector = floppy_cmd[4] - 1; + pcf->head = (floppy_cmd[1] & 4) ? 1 : 0; + while (!end) { + int len = 128 << floppy_cmd[5]; + uae_u8 buf[512] = { 0 }; + for (int i = 0; i < 512 && i < len; i++) { + buf[i] = read8237(xb, 2, &end); + if (end) + break; + } + zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET); + zfile_fwrite(buf, 1, 512, fr.img); + pcf->sector++; + if (!(floppy_cmd[0] & 0x80)) + break; + if (pcf->sector >= fr.secs) { + pcf->sector = 0; + // todo: check limits + if (!pcf->head) { + pcf->head = 1; + } else { + break; + } + } + } + floppy_result[3] = pcf->cyl; + floppy_result[4] = pcf->head; + floppy_result[5] = pcf->sector + 1; + floppy_result[6] = floppy_cmd[5]; + } else { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[0] |= 0x10; // equipment check + } + } + floppy_cmd_len = 7; + if (fr.wrprot) { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[1] |= 0x02; // not writable + } + floppy_result[0] = floppy_status[0]; + floppy_result[1] = floppy_status[1]; + floppy_result[2] = floppy_status[2]; + floppy_delay_hsync = 10; + disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1); + } + break; + + case 6: + { + write_log(_T("Floppy%d read MT=%d MF=%d SK=%d C=%d:H=%d:R=%d:N=%d:EOT=%d:GPL=%d:DTL=%d\n"), + floppy_num, (floppy_cmd[0] & 0x80) ? 1 : 0, (floppy_cmd[0] & 0x40) ? 1 : 0, (floppy_cmd[0] & 0x20) ? 1 : 0, + floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5], + floppy_cmd[6], floppy_cmd[7], floppy_cmd[8], floppy_cmd[9]); + write_log(_T("DMA addr %08x len %04x\n"), dmachan[2].page | dmachan[2].addr, dmachan[2].reload); + floppy_delay_hsync = 50; + bool nodata = false; + if (valid_floppy) { + if (fr.img && pcf->cyl != floppy_cmd[2]) { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[2] |= 0x20; // wrong cylinder + } else if (fr.img) { + bool end = false; + pcf->sector = floppy_cmd[4] - 1; + pcf->head = (floppy_cmd[1] & 4) ? 1 : 0; + while (!end) { + int len = 128 << floppy_cmd[5]; + uae_u8 buf[512]; + zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET); + zfile_fread(buf, 1, 512, fr.img); + for (int i = 0; i < 512 && i < len; i++) { + if (write8237(xb, 2, buf[i]) <= 0) + end = true; + } + pcf->sector++; + if (!(floppy_cmd[0] & 0x80)) + break; + if (pcf->sector >= fr.secs) { + pcf->sector = 0; + // todo: check limits + if (!pcf->head) { + pcf->head = 1; + } + } + } + floppy_result[3] = pcf->cyl; + floppy_result[4] = pcf->head; + floppy_result[5] = pcf->sector + 1; + floppy_result[6] = floppy_cmd[5]; + } else { + nodata = true; + } + } + if (nodata) { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[1] |= 0x04; // no data + } + floppy_cmd_len = 7; + floppy_result[0] = floppy_status[0]; + floppy_result[1] = floppy_status[1]; + floppy_result[2] = floppy_status[2]; + floppy_delay_hsync = 10; + disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1); + } + break; + + case 7: + write_log(_T("Floppy%d recalibrate\n"), floppy_num); + if (floppy_selected() >= 0) { + pcf->cyl = 0; + pcf->phys_cyl = 0; + pcf->head = 0; + } else { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[0] |= 0x10; // equipment check + } + floppy_status[0] |= 0x20; // seek end + floppy_delay_hsync = 50; + disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1); + break; + + case 10: + write_log(_T("Floppy read ID\n")); + if (!valid_floppy && fr.img) { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[1] |= 0x04; // no data + } + floppy_cmd_len = 7; + floppy_result[0] = floppy_status[0]; + floppy_result[1] = floppy_status[1]; + floppy_result[2] = floppy_status[2]; + floppy_result[3] = pcf->cyl; + floppy_result[4] = pcf->head; + floppy_result[5] = pcf->sector + 1; + floppy_result[6] = 2; + + pcf->sector++; + pcf->sector %= fr.secs; + + floppy_delay_hsync = 10; + disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1); + break; + + case 13: + { + write_log(_T("Floppy%d format MF=%d N=%d:SC=%d:GPL=%d:D=%d\n"), + floppy_num, (floppy_cmd[0] & 0x40) ? 1 : 0, + floppy_cmd[2], floppy_cmd[3], floppy_cmd[4], floppy_cmd[5]); + write_log(_T("DMA addr %08x len %04x\n"), dmachan[2].page | dmachan[2].addr, dmachan[2].reload); + int secs = floppy_cmd[3]; + if (valid_floppy && fr.img) { + // TODO: CHRN values totally ignored + pcf->head = (floppy_cmd[1] & 4) ? 1 : 0; + uae_u8 buf[512]; + memset(buf, floppy_cmd[5], sizeof buf); + for (int i = 0; i < secs && i < fr.secs; i++) { + bool dmaend; + uae_u8 cx = read8237(xb, 2, &dmaend); + uae_u8 hx = read8237(xb, 2, &dmaend); + uae_u8 rx = read8237(xb, 2, &dmaend); + uae_u8 nx = read8237(xb, 2, &dmaend); + pcf->sector = rx - 1; + write_log(_T("Floppy%d %d/%d: C=%d H=%d R=%d N=%d\n"), floppy_num, i, fr.secs, cx, hx, rx, nx); + zfile_fseek(fr.img, (pcf->cyl * fr.secs * fr.heads + pcf->head * fr.secs + pcf->sector) * 512, SEEK_SET); + zfile_fwrite(buf, 1, 512, fr.img); + } + } else { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[0] |= 0x10; // equipment check + } + floppy_cmd_len = 7; + if (fr.wrprot) { + floppy_status[0] |= 0x40; // abnormal termination + floppy_status[1] |= 0x02; // not writable + } + floppy_result[0] = floppy_status[0]; + floppy_result[1] = floppy_status[1]; + floppy_result[2] = floppy_status[2]; + floppy_result[3] = pcf->cyl; + floppy_result[4] = pcf->head; + floppy_result[5] = pcf->sector + 1; + floppy_result[6] = floppy_cmd[2]; + floppy_delay_hsync = 10; + disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1); + } + break; + + case 15: + { + int newcyl = floppy_cmd[2]; + floppy_delay_hsync = abs(pcf->phys_cyl - newcyl) * 100 + 50; + pcf->phys_cyl = newcyl; + pcf->head = (floppy_cmd[1] & 4) ? 1 : 0; + floppy_status[0] |= 0x20; // seek end + if (fr.cyls < 80 && floppy_high_density) + pcf->cyl = pcf->phys_cyl / 2; + else + pcf->cyl = pcf->phys_cyl; + write_log(_T("Floppy%d seek to %d %d\n"), floppy_num, pcf->phys_cyl, pcf->head); + disk_reserved_setinfo(floppy_num, pcf->cyl, pcf->head, 1); + } + break; + + default: + floppy_status[0] = 0x80; + floppy_cmd_len = 1; + break; + } + +end: + if (floppy_cmd_len) { + floppy_idx = -1; + floppy_dir = 1; + write_log(_T("Status return: ")); + for (int i = 0; i < floppy_cmd_len; i++) { + write_log(_T("%02x "), floppy_result[i]); + } + write_log(_T("\n")); + } else { + floppy_idx = 0; + floppy_dir = 0; + } +} + +static void outfloppy(struct x86_bridge *xb, int portnum, uae_u8 v) +{ + switch (portnum) + { + case 0x3f2: // dpc + if ((v & 4) && !(floppy_dpc & 4)) { + floppy_reset(); + floppy_delay_hsync = 20; + } +#if FLOPPY_IO_DEBUG + write_log(_T("DPC: Motormask %02x sel=%d enable=%d dma=%d\n"), (v >> 4) & 15, v & 3, (v & 8) ? 1 : 0, (v & 4) ? 1 : 0); +#endif + floppy_dpc = v; + floppy_num = v & 3; + for (int i = 0; i < 2; i++) { + disk_reserved_setinfo(0, floppy_pc[i].cyl, floppy_pc[i].head, floppy_selected() == i); + } + break; + case 0x3f5: // data reg + floppy_cmd[floppy_idx] = v; + if (floppy_idx == 0) { + switch(v & 31) + { + case 3: // specify + floppy_cmd_len = 3; + break; + case 4: // sense drive status + floppy_cmd_len = 2; + break; + case 5: // write data + floppy_cmd_len = 9; + break; + case 6: // read data + floppy_cmd_len = 9; + break; + case 7: // recalibrate + floppy_cmd_len = 2; + break; + case 8: // sense interrupt status + floppy_cmd_len = 1; + break; + case 10: // read id + floppy_cmd_len = 2; + break; + case 13: // format track + floppy_cmd_len = 6; + break; + case 15: // seek + floppy_cmd_len = 3; + break; + default: + write_log(_T("Floppy unimplemented command %02x\n"), v); + floppy_cmd_len = 1; + break; + } + } + floppy_idx++; + if (floppy_idx >= floppy_cmd_len) { + floppy_do_cmd(xb); + } + break; + } +#if FLOPPY_IO_DEBUG + write_log(_T("out floppy port %04x %02x\n"), portnum, v); +#endif +} +static uae_u8 infloppy(struct x86_bridge *xb, int portnum) +{ + uae_u8 v = 0; + switch (portnum) + { + case 0x3f4: // main status + v = 0; + if (!floppy_delay_hsync) + v |= 0x80; + if (floppy_idx || floppy_delay_hsync) + v |= 0x10; + if ((v & 0x80) && floppy_dir) + v |= 0x40; + break; + case 0x3f5: // data reg + if (floppy_cmd_len && floppy_dir) { + int idx = (-floppy_idx) - 1; + if (idx < sizeof floppy_result) { + v = floppy_result[idx]; + idx++; + floppy_idx--; + if (idx >= floppy_cmd_len) { + floppy_cmd_len = 0; + floppy_dir = 0; + floppy_idx = 0; + } + } + } + break; + } +#if FLOPPY_IO_DEBUG + write_log(_T("in floppy port %04x %02x\n"), portnum, v); +#endif + return v; +} + +static void set_pc_address_access(struct x86_bridge *xb, uaecptr addr) +{ + if (addr >= 0xb0000 && addr < 0xb2000) { + // mono + set_interrupt(xb, 0); + } + if (addr >= 0xb8000 && addr < 0xc0000) { + // color + set_interrupt(xb, 1); + } +} + +static void set_pc_io_access(struct x86_bridge *xb, uaecptr portnum, bool write) +{ + if (write && portnum >= 0x3b0 && portnum < 0x3bf) { + // mono crt + set_interrupt(xb, 2); + } else if (write && portnum >= 0x3d0 && portnum < 0x3df) { + // color crt + set_interrupt(xb, 3); + } else if (portnum >= 0x37a && portnum < 0x37b) { + // LPT1 + set_interrupt(xb, 5); + } else if (portnum >= 0x2f8 && portnum < 0x2f9) { + // COM2 + set_interrupt(xb, 6); + } +} + +static bool is_port_enabled(struct x86_bridge *xb, uint16_t portnum) +{ + uae_u8 enables = xb->amiga_io[IO_MODE_REGISTER]; + // COM2 + if (portnum >= 0x2f8 && portnum < 0x300) { + if (!(enables & 1)) + return false; + } + // LPT1 + if (portnum >= 0x378 && portnum < 0x37f) { + if (!(enables & 2)) + return false; + } + // Keyboard + // ??? + // Mono video + if (portnum >= 0x3b0 && portnum < 0x3bf) { + if (!(enables & 8)) + return false; + } + // Color video + if (portnum >= 0x3d0 && portnum < 0x3df) { + if (!(enables & 16)) + return false; + } + return true; +} + +void portout(uint16_t portnum, uint8_t v) +{ + struct x86_bridge *xb = bridges[0]; + uae_u8 *io = xb->io_ports; + int aio = -1; + + if (portnum >= 0x400) + return; + + if (!is_port_enabled(xb, portnum)) + return; + + set_pc_io_access(xb, portnum, true); + + switch(portnum) + { + case 0x20: + case 0x21: + out8259(portnum, v); + break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + out8253(portnum, v); + break; + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + out8237(portnum, v); + break; + + case 0x60: + aio = 0x41f; + break; + case 0x61: + //write_log(_T("OUT Port B %02x\n"), v); + aio = 0x5f; + break; + case 0x62: + //write_log(_T("AMIGA SYSINT. %02x\n"), v); + set_interrupt(xb, 7); + aio = 0x3f; + if (xb->type > TYPE_SIDECAR) { + // default video mode bits 4-5 come from jumpers. + if (!(xb->io_ports[0x63] & 8)) { + xb->pc_jumpers &= ~0xcf; + xb->pc_jumpers |= v & 0xcf; + } + } + break; + case 0x63: + write_log(_T("OUT CONFIG %02x\n"), v); + if (xb->type > TYPE_SIDECAR) { + if (xb->io_ports[0x63] & 8) { + v |= 8; + } + if (xb->type == TYPE_2088T) { + int speed = v >> 6; + if (speed == 0) + write_log(_T("A2088T: 4.77MHz\n")); + if (speed == 1) + write_log(_T("A2088T: 7.15MHz\n")); + if (speed == 2) + write_log(_T("A2088T: 9.54MHz\n")); + } + } + break; + + case 0x2f8: + if (xb->amiga_io[0x13f] & 0x80) + aio = 0x7f; + else + aio = 0x7d; + break; + case 0x2f9: + if (xb->amiga_io[0x13f] & 0x80) + aio = 0x9f; + else + aio = 0xbd; + break; + case 0x2fb: + aio = 0x11f; + break; + case 0x2fc: + aio = 0x13f; + break; + case 0x2fa: + case 0x2fd: + case 0x2fe: + case 0x2ff: + aio = 0x1f; + break; + + // mono video + case 0x3b0: + case 0x3b2: + case 0x3b4: + case 0x3b6: + aio = 0x1ff; + break; + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + aio = 0x2a1 + (xb->amiga_io[0x1ff] & 15) * 2; + break; + case 0x3b8: + aio = 0x2ff; + break; + + // color video + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + aio = 0x21f; + break; + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + aio = 0x2c1 + (xb->amiga_io[0x21f] & 15) * 2; + break; + case 0x3d8: + aio = 0x23f; + break; + case 0x3d9: + aio = 0x25f; + break; + case 0x3dd: + aio = 0x29f; + break; + + case 0x378: + write_log(_T("BIOS DIAGNOSTICS CODE: %02x\n"), v); + aio = 0x19f; // ?? + break; + case 0x379: + if (xb->amiga_io[IO_MODE_REGISTER] & 2) { + xb->amiga_forced_interrupts = (v & 40) ? false : true; + } + aio = 0x19f; // ?? + break; + case 0x37a: + aio = 0x1df; + break; + + case 0x3ba: + case 0x3bb: + case 0x3bc: + case 0x3bd: + case 0x3be: + case 0x3bf: + case 0x3da: + case 0x3de: + case 0x3df: + aio = 0x1f; + break; + + // floppy + case 0x3f0: + case 0x3f1: + case 0x3f2: + case 0x3f3: + case 0x3f4: + case 0x3f5: + case 0x3f6: + case 0x3f7: + outfloppy(xb, portnum, v); + break; + } + + //write_log(_T("X86_OUT %08x %02X\n"), portnum, v); + + if (aio >= 0) + xb->amiga_io[aio] = v; + xb->io_ports[portnum] = v; +} +void portout16(uint16_t portnum, uint16_t value) +{ + write_log(_T("portout16 %08x\n"), portnum); +} +uint8_t portin(uint16_t portnum) +{ + struct x86_bridge *xb = bridges[0]; + int aio = -1; + + if (!is_port_enabled(xb, portnum)) + return 0; + + if (portnum >= 0x400) + return 0; + + set_pc_io_access(xb, portnum, false); + + uae_u8 v = xb->io_ports[portnum]; + switch (portnum) + { + case 0x20: + case 0x21: + v = in8259(portnum); + break; + case 0x40: + case 0x41: + case 0x42: + case 0x43: + v = in8253(portnum); + break; + case 0x80: + case 0x81: + case 0x82: + case 0x83: + case 0x84: + case 0x85: + case 0x86: + case 0x87: + case 0x88: + case 0x89: + case 0x8a: + case 0x8b: + case 0x8c: + case 0x8d: + case 0x8e: + case 0x8f: + case 0x00: + case 0x01: + case 0x02: + case 0x03: + case 0x04: + case 0x05: + case 0x06: + case 0x07: + case 0x08: + case 0x09: + case 0x0a: + case 0x0b: + case 0x0c: + case 0x0d: + case 0x0e: + case 0x0f: + v = in8237(portnum); + break; + + case 0x2f8: + if (xb->amiga_io[0x11f] & 0x80) + aio = 0x7f; + else + aio = 0x9d; + xb->pc_irq3b = false; + break; + case 0x2f9: + if (xb->amiga_io[0x11f] & 0x80) + aio = 0x9f; + else + aio = 0xdd; + break; + case 0x2fa: + aio = 0xff; + break; + case 0x2fd: + aio = 0x15f; + break; + case 0x2fe: + aio = 0x17f; + break; + case 0x2fb: + case 0x2fc: + case 0x2ff: + aio = 0x1f; + break; + + case 0x378: + aio = 0x19f; // ? + break; + case 0x379: + xb->pc_irq7 = false; + aio = 0x1bf; + break; + case 0x37a: + aio = 0x19f; // ? + break; + + // mono video + case 0x3b0: + xb->pc_irq3a = false; + aio = 0x1ff; + break; + case 0x3b2: + case 0x3b4: + case 0x3b6: + aio = 0x1ff; + break; + case 0x3b1: + case 0x3b3: + case 0x3b5: + case 0x3b7: + aio = 0x2a1 + (xb->amiga_io[0x1ff] & 15) * 2; + break; + case 0x3b8: + aio = 0x2ff; + break; + + // color video + case 0x3d0: + case 0x3d2: + case 0x3d4: + case 0x3d6: + aio = 0x21f; + break; + case 0x3d1: + case 0x3d3: + case 0x3d5: + case 0x3d7: + aio = 0x2c1 + (xb->amiga_io[0x21f] & 15) * 2; + break; + case 0x3d8: + aio = 0x23f; + break; + case 0x3d9: + aio = 0x25f; + break; + case 0x3ba: + case 0x3da: + v = 0; + // not really correct but easy. + if (vpos < 20) + v |= 8 | 1; + if (get_cycles() - last_cycles > maxhpos / 2) + v |= 1; + last_cycles = get_cycles(); + break; + case 0x3dd: + aio = 0x29f; + break; + + case 0x3bb: + case 0x3bc: + case 0x3bd: + case 0x3be: + case 0x3bf: + case 0x3de: + case 0x3df: + aio = 0x1f; + break; + + // floppy + case 0x3f0: + case 0x3f1: + case 0x3f2: + case 0x3f3: + case 0x3f4: + case 0x3f5: + case 0x3f6: + case 0x3f7: + v = infloppy(xb, portnum); + break; + + case 0x60: + //write_log(_T("PC read keycode %02x\n"), v); + break; + case 0x61: + v = xb->amiga_io[0x5f]; + //write_log(_T("IN Port B %02x\n"), v); + break; + case 0x62: + { + v = xb->amiga_io[0x3f]; + if (xb->type == TYPE_SIDECAR) { + // Sidecar has jumpers. + if (xb->amiga_io[0x5f] & 8) { + // bit 0-1: display (11=mono 80x25,10=01=color 80x25,00=no video) + // bit 2-3: number of drives (11=1..) + v &= 0xf0; + v |= (xb->pc_jumpers >> 4) & 0x0f; + } else { + v &= 0xf0; + // bit 0: 0=loop on POST + // bit 1: 0=8087 installed + // bit 2-3: (11=640k,10=256k,01=512k,00=128k) RAM size + v |= xb->pc_jumpers & 0xf; + } + } else { + // A2088+ are software configurable (Except default video mode) + if (!(xb->amiga_io[0x5f] & 4)) { + v &= 0xf0; + v |= (xb->pc_jumpers >> 4) & 0x0f; + } else { + v &= 0xf0; + v |= xb->pc_jumpers & 0xf; + } + } + v &= ~0x20; + if (!(xb->amiga_io[0x5f] & 1) && i8253.active[2]) + v |= 0x20; + //write_log(_T("IN Port C %02x\n"), v); + } + break; + case 0x63: + //write_log(_T("IN Control %02x\n"), v); + break; + default: + write_log(_T("X86_IN unknown %02x\n"), portnum); + return 0; + } + + if (aio >= 0) + v = xb->amiga_io[aio]; + //write_log(_T("X86_IN %08x %02X\n"), portnum, v); + return v; +} +uint16_t portin16(uint16_t portnum) +{ + write_log(_T("portin16 %08x\n"), portnum); + return 0; +} + +void write86(uint32_t addr32, uint8_t value) +{ + struct x86_bridge *xb = bridges[0]; + addr32 &= 0xFFFFF; + if (addr32 >= xb->pc_maxram && addr32 < 0xa0000) + return; + set_pc_address_access(xb, addr32); + xb->pc_ram[addr32] = value; +} +void writew86(uint32_t addr32, uint16_t value) +{ + struct x86_bridge *xb = bridges[0]; + addr32 &= 0xFFFFF; + if (addr32 >= xb->pc_maxram && addr32 < 0xa0000) + return; + set_pc_address_access(xb, addr32); + xb->pc_ram[addr32] = value & 0xff; + xb->pc_ram[addr32 + 1] = value >> 8; +} +uint8_t read86(uint32_t addr32) +{ + struct x86_bridge *xb = bridges[0]; + addr32 &= 0xFFFFF; + return xb->pc_ram[addr32]; +} +uint16_t readw86(uint32_t addr32) +{ + uint16_t v; + struct x86_bridge *xb = bridges[0]; + addr32 &= 0xFFFFF; + + v = xb->pc_ram[addr32]; + v |= xb->pc_ram[addr32 + 1] << 8; + return v; +} + +static uaecptr get_x86_address(struct x86_bridge *xb, uaecptr addr, int *mode) +{ + addr -= xb->baseaddress; + *mode = addr >> 17; + addr &= 0x1ffff; + if (addr < 0x10000) { + int opt = (xb->amiga_io[IO_MODE_REGISTER] >> 5) & 3; + // disk buffer + switch(opt) + { + case 1: + default: + return 0xa0000 + addr; + case 2: + return 0xd0000 + addr; + case 3: + return 0xe0000 + addr; + } + } + if (addr < 0x18000) { + // color video + addr -= 0x10000; + return 0xb8000 + addr; + } + if (addr < 0x1c000) { + addr -= 0x18000; + // parameter + return 0xf0000 + addr; + } + if (addr < 0x1e000) { + addr -= 0x1c000; + // mono video + return 0xb0000 + addr; + } + // IO + addr -= 0x1e000; + return addr; +} + +static struct x86_bridge *get_x86_bridge(uaecptr addr) +{ + return bridges[0]; +} + +static uae_u32 REGPARAM2 x86_bridge_wget(uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + uae_u16 v = 0; + struct x86_bridge *xb = get_x86_bridge(addr); + if (!xb) + return v; + int mode; + uaecptr a = get_x86_address(xb, addr, &mode); + if (mode == ACCESS_MODE_WORD) { + v = (xb->pc_ram[a + 1] << 8) | (xb->pc_ram[a + 0] << 0); + } else if (mode == ACCESS_MODE_GFX) { + write_log(_T("ACCESS_MODE_GFX\n")); + } else if (mode == ACCESS_MODE_IO) { + v = x86_bridge_get_io(xb, a); + v |= x86_bridge_get_io(xb, a + 1) << 8; + } else if (mode >= 0) { + v = (xb->pc_ram[a + 1] << 0) | (xb->pc_ram[a + 0] << 8); + } +#if X86_DEBUG_BRIDGE > 1 + write_log(_T("x86_bridge_wget %08x (%08x,%d) PC=%08x\n"), addr - xb->baseaddress, a, mode, M68K_GETPC); +#endif + return v; +} +static uae_u32 REGPARAM2 x86_bridge_lget(uaecptr addr) +{ + uae_u32 v; + v = x86_bridge_wget(addr) << 16; + v |= x86_bridge_wget(addr + 2); + return v; +} +static uae_u32 REGPARAM2 x86_bridge_bget(uaecptr addr) +{ +#ifdef JIT + special_mem |= S_READ; +#endif + uae_u8 v = 0; + struct x86_bridge *xb = get_x86_bridge(addr); + if (!xb) + return v; + if (!xb->configured) { + uaecptr offset = addr & 65535; + if (offset >= sizeof xb->acmemory) + return 0; + return xb->acmemory[offset]; + } + int mode; + uaecptr a = get_x86_address(xb, addr, &mode); + if (mode == ACCESS_MODE_WORD) { + v = xb->pc_ram[a ^ 1]; + } else if (mode == ACCESS_MODE_IO) { + v = x86_bridge_get_io(xb, a); + } else if (mode >= 0) { + v = xb->pc_ram[a]; + } +#if X86_DEBUG_BRIDGE > 1 + write_log(_T("x86_bridge_bget %08x (%08x,%d) %02x PC=%08x\n"), addr - xb->baseaddress, a, mode, v, M68K_GETPC); +#endif + return v; +} + +static void REGPARAM2 x86_bridge_wput(uaecptr addr, uae_u32 b) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + struct x86_bridge *xb = get_x86_bridge(addr); + if (!xb) + return; + int mode; + uaecptr a = get_x86_address(xb, addr, &mode); + +#if X86_DEBUG_BRIDGE > 1 + write_log(_T("pci_bridge_wput %08x (%08x,%d) %04x PC=%08x\n"), addr - xb->baseaddress, a, mode, b & 0xffff, M68K_GETPC); +#endif + + if (a >= 0xf8000 || mode < 0) + return; + + if (mode == ACCESS_MODE_IO) { + uae_u16 v = b; + x86_bridge_put_io(xb, a, v & 0xff); + x86_bridge_put_io(xb, a + 1, v >> 8); + } else if (mode == ACCESS_MODE_WORD) { + xb->pc_ram[a + 0] = b; + xb->pc_ram[a + 1] = b >> 8; + } else if (mode == ACCESS_MODE_GFX) { + write_log(_T("ACCESS_MODE_GFX\n")); + } else { + xb->pc_ram[a + 1] = b; + xb->pc_ram[a + 0] = b >> 8; + } +} +static void REGPARAM2 x86_bridge_lput(uaecptr addr, uae_u32 b) +{ + x86_bridge_wput(addr, b >> 16); + x86_bridge_wput(addr + 2, b); +} +static void REGPARAM2 x86_bridge_bput(uaecptr addr, uae_u32 b) +{ +#ifdef JIT + special_mem |= S_WRITE; +#endif + struct x86_bridge *xb = get_x86_bridge(addr); + if (!xb) + return; + if (!xb->configured) { + uaecptr offset = addr & 65535; + switch (offset) + { + case 0x48: + map_banks_z2(xb->bank, b, expamem_z2_size >> 16); + xb->baseaddress = b << 16; + xb->configured = 1; + expamem_next(xb->bank, NULL); + break; + case 0x4c: + xb->configured = -1; + expamem_shutup(xb->bank); + break; + } + } + + int mode; + uaecptr a = get_x86_address(xb, addr, &mode); + + if (a >= 0xf8000 || mode < 0) + return; + +#if X86_DEBUG_BRIDGE > 1 + write_log(_T("x86_bridge_bput %08x (%08x,%d) %02x PC=%08x\n"), addr - xb->baseaddress, a, mode, b & 0xff, M68K_GETPC); +#endif + + if (mode == ACCESS_MODE_IO) { + x86_bridge_put_io(xb, a, b); + } else if (mode == ACCESS_MODE_WORD) { + xb->pc_ram[a ^ 1] = b; + } else { + xb->pc_ram[a] = b; + } +} + +addrbank x86_bridge_bank = { + x86_bridge_lget, x86_bridge_wget, x86_bridge_bget, + x86_bridge_lput, x86_bridge_wput, x86_bridge_bput, + default_xlate, default_check, NULL, NULL, _T("X86 BRIDGE"), + x86_bridge_lget, x86_bridge_wget, ABFLAG_IO | ABFLAG_SAFE +}; + +void x86_bridge_rethink(void) +{ + struct x86_bridge *xb = bridges[0]; + if (!xb) + return; + if (!(xb->amiga_io[IO_CONTROL_REGISTER] & 1)) { + uae_u8 intreq = xb->amiga_io[IO_AMIGA_INTERRUPT_STATUS]; + uae_u8 intena = xb->amiga_io[IO_INTERRUPT_MASK]; + uae_u8 status = intreq & ~intena; + if (status) + INTREQ_0(0x8000 | 0x0008); + } +} + +void x86_bridge_free(void) +{ + for (int i = 0; i < X86_BRIDGE_MAX; i++) { + struct x86_bridge *xb = bridges[i]; + if (!xb) + continue; + xfree(xb->amiga_io); + xfree(xb->io_ports); + xfree(xb->pc_ram); + bridges[i] = NULL; + } +} + +void x86_bridge_reset(void) +{ +} + +void x86_bridge_hsync(void) +{ + struct x86_bridge *xb = bridges[0]; + if (!xb) + return; + + if (floppy_delay_hsync > 1 || floppy_delay_hsync < -1) { + if (floppy_delay_hsync > 0) + floppy_delay_hsync--; + else + floppy_delay_hsync++; + if (floppy_delay_hsync == 1 || floppy_delay_hsync == -1) + do_floppy_irq(); + } + + if (!xb->x86_reset) { + exec86(30); + timing(); + exec86(30); + timing(); + exec86(30); + timing(); + } +} + +static void ew(uae_u8 *acmemory, int addr, uae_u8 value) +{ + if (addr == 00 || addr == 02 || addr == 0x40 || addr == 0x42) { + acmemory[addr] = (value & 0xf0); + acmemory[addr + 2] = (value & 0x0f) << 4; + } else { + acmemory[addr] = ~(value & 0xf0); + acmemory[addr + 2] = ~((value & 0x0f) << 4); + } +} + +static void a1060_reset(struct x86_bridge *xb) +{ + xb->x86_reset = true; + xb->configured = 0; + xb->amiga_forced_interrupts = false; + xb->amiga_irq = false; + xb->pc_irq3a = xb->pc_irq3b = xb->pc_irq7 = false; + memset(xb->amiga_io, 0, 0x10000); + memset(xb->io_ports, 0, 0x10000); + memset(xb->pc_ram, 0, 0x100000 - 32768); + xb->amiga_io[IO_CONTROL_REGISTER] = 0xfe; + xb->amiga_io[IO_PC_INTERRUPT_CONTROL] = 0xff; + xb->amiga_io[IO_INTERRUPT_MASK] = 0xff; + xb->amiga_io[IO_MODE_REGISTER] = 0x00; + xb->amiga_io[IO_PC_INTERRUPT_STATUS] = 0xfe; + inittiming(); +} + +int is_x86_cpu(struct uae_prefs *p) +{ + struct x86_bridge *xb = bridges[0]; + if (!xb) { + if (is_device_rom(&currprefs, ROMTYPE_A1060, 0) < 0 && + is_device_rom(&currprefs, ROMTYPE_A2088XT, 0) < 0 && + is_device_rom(&currprefs, ROMTYPE_A2088T, 0) < 0) + return X86_STATE_INACTIVE; + } + if (!xb || xb->x86_reset) + return X86_STATE_STOP; + return X86_STATE_ACTIVE; +} + +static const uae_u8 a1060_autoconfig[16] = { 0xc4, 0x01, 0x80, 0x00, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +addrbank *x86_bridge_init(struct romconfig *rc, int type) +{ + struct x86_bridge *xb = x86_bridge_alloc(); + if (!xb) + return &expamem_null; + bridges[0] = xb; + + xb->pc_ram = xcalloc(uae_u8, 0x100000); + xb->io_ports = xcalloc(uae_u8, 0x10000); + xb->amiga_io = xcalloc(uae_u8, 0x10000); + xb->type = type; + xb->pc_jumpers = (rc->device_settings & 0xff) ^ ((0x80 | 0x40) | (0x20 | 0x10)); + xb->settings = rc->device_settings; + + int ramsize = (xb->settings >> 2) & 3; + switch(ramsize) { + case 0: + xb->pc_maxram = 128 * 1024; + break; + case 1: + xb->pc_maxram = 256 * 1024; + break; + case 2: + xb->pc_maxram = 512 * 1024; + break; + case 3: + xb->pc_maxram = 640 * 1024; + break; + } + + floppy_high_density = xb->type >= TYPE_2088T; + + a1060_reset(xb); + + // load bios + load_rom_rc(rc, NULL, 32768, 0, xb->pc_ram + 0xf8000, 32768, LOADROM_FILL); + + xb->bank = &x86_bridge_bank; + for (int i = 0; i < sizeof a1060_autoconfig; i++) { + ew(xb->acmemory, i * 4, a1060_autoconfig[i]); + } + + return xb->bank; +} + +addrbank *a1060_init(struct romconfig *rc) +{ + return x86_bridge_init(rc, TYPE_SIDECAR); +} +addrbank *a2088xt_init(struct romconfig *rc) +{ + return x86_bridge_init(rc, TYPE_2088); +} +addrbank *a2088t_init(struct romconfig *rc) +{ + return x86_bridge_init(rc, TYPE_2088T); +} -- 2.47.3