--- /dev/null
+/*
+ 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;
+ }
+ }
+}
+
--- /dev/null
+/*
+* 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);
+}