]> git.unchartedbackwaters.co.uk Git - francis/winuae.git/commitdiff
x86 bridgeboard emulation.
authorToni Wilen <twilen@winuae.net>
Wed, 22 Jul 2015 16:41:16 +0000 (19:41 +0300)
committerToni Wilen <twilen@winuae.net>
Wed, 22 Jul 2015 16:41:16 +0000 (19:41 +0300)
disk.cpp
expansion.cpp
fake86_cpu.cpp [new file with mode: 0644]
include/autoconf.h
include/disk.h
include/rommgr.h
include/x86.h [new file with mode: 0644]
od-win32/sysconfig.h
x86.cpp [new file with mode: 0644]

index 6fdc719d10b1b36cc7935ac43dee98b9d57f9cf6..d6c0995a9b48855581a07dbf686508d041f6b486 100644 (file)
--- 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;
+}
index f877877ee3f2fc4f0c1aef35ef15fad62785c822..52ad06cc2dea5f3eb0d9eb5e9e51d01f5f5691ba 100644 (file)
@@ -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 (file)
index 0000000..7074be5
--- /dev/null
@@ -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 <stdint.h>
+#include <stdio.h>
+
+#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 <stdint.h>
+#include <stdio.h>
+#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;
+                               }
+               }
+}
+
index 7006991a1737e90ed84c4ce76bf5a0f92244038f..fd6966a8acbfb7e6e5ef4405a1cb65a60b065166 100644 (file)
@@ -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
 {
index 038a867fcd9dda151219c9f9efb0794131e66b13..8d8bb342c2b81f9b419b2a80f4fa483a8f99d19b 100644 (file)
@@ -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);
index 62093008554dc06ad7a91f5dbb525499071ca15a..069c6f1dc11de5ae99dca0a304b8848ec6bdcbbd 100644 (file)
@@ -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 (file)
index 0000000..3bcd44f
--- /dev/null
@@ -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*);
index 30045dbb28eea45086d9f1615725344a7ed6b077..acf3ece4432cc1c368c134c562dd1ab15b1cd679 100644 (file)
@@ -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 (file)
index 0000000..4952d21
--- /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);
+}