diff --git a/src/cpu/808x.c b/src/cpu/808x.c index a02d144..8795ad7 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -8,7 +8,7 @@ * * 808x CPU emulation. * - * Version: @(#)808x.c 1.0.8 2019/02/08 + * Version: @(#)808x.c 1.0.9 2019/02/10 * * Authors: Miran Grca, * Andrew Jenner, @@ -1426,7 +1426,7 @@ stos(int bits) if (bits == 16) writememw(es, DI, cpu_data); else - writememb(es + DI, cpu_data); + writememb(es + DI, (uint8_t)(cpu_data & 0xff)); if (flags & D_FLAG) DI -= (bits >> 3); else @@ -1563,14 +1563,14 @@ opcodestart: if (opcode & 1) seteaw(cpu_data); else - seteab(cpu_data); + seteab((uint8_t) (cpu_data & 0xff)); if (cpu_mod == 3) wait(1, 0); } else { if (opcode & 1) cpu_state.regs[cpu_reg].w = cpu_data; else - setr8(cpu_reg, cpu_data); + setr8(cpu_reg, (uint8_t)(cpu_data & 0xff)); wait(1, 0); } } else @@ -1781,7 +1781,7 @@ opcodestart: if (opcode & 1) seteaw(cpu_data); else - seteab(cpu_data); + seteab((uint8_t)(cpu_data & 0xff)); } else { if (cpu_mod != 3) wait(1, 0); @@ -1816,14 +1816,14 @@ opcodestart: } else { cpu_data = geteab(); cpu_src = getr8(cpu_reg); - setr8(cpu_reg, cpu_data); + setr8(cpu_reg, (uint8_t)(cpu_data & 0xff)); } wait(3, 0); access(12, bits); if (opcode & 1) seteaw(cpu_src); else - seteab(cpu_src); + seteab((uint8_t)(cpu_src & 0xff)); break; case 0x88: case 0x89: @@ -2028,7 +2028,7 @@ opcodestart: if (opcode & 1) AX = cpu_data; else - AL = cpu_data; + AL = (uint8_t)(cpu_data & 0xff); if (in_rep != 0) wait(2, 0); } @@ -2203,7 +2203,7 @@ opcodestart: if (opcode & 1) seteaw(cpu_data); else - seteab(cpu_data); + seteab((uint8_t)(cpu_data & 0xff)); break; case 0xCC: /*INT 3*/ @@ -2326,7 +2326,7 @@ opcodestart: if (opcode & 1) seteaw(cpu_data); else - seteab(cpu_data); + seteab((uint8_t)(cpu_data & 0xff)); break; case 0xD4: /*AAM*/ @@ -2518,7 +2518,7 @@ opcodestart: if (opcode & 1) seteaw(cpu_data); else - seteab(cpu_data); + seteab((uint8_t)(cpu_data & 0xff)); break; case 0x20: /* MUL */ case 0x28: /* IMUL */ @@ -2591,7 +2591,7 @@ opcodestart: if (opcode & 1) seteaw(cpu_data); else - seteab(cpu_data); + seteab((uint8_t)(cpu_data & 0xff)); break; case 0x10: /* CALL rm */ if (!(opcode & 1)) { diff --git a/src/cpu/808x.c.orig b/src/cpu/808x.c.orig new file mode 100644 index 0000000..cbea8be --- /dev/null +++ b/src/cpu/808x.c.orig @@ -0,0 +1,3273 @@ +/* + * VARCem Virtual ARchaeological Computer EMulator. + * An emulator of (mostly) x86-based PC systems and devices, + * using the ISA,EISA,VLB,MCA and PCI system buses, roughly + * spanning the era between 1981 and 1995. + * + * This file is part of the VARCem Project. + * + * 808x CPU emulation. + * + * SHR AX,1 + * + * 4 clocks - fetch opcode + * 4 clocks - fetch mod/rm + * 2 clocks - execute 2 clocks - fetch opcode 1 + * 2 clocks - fetch opcode 2 + * 4 clocks - fetch mod/rm + * 2 clocks - fetch opcode 1 2 clocks - execute + * 2 clocks - fetch opcode 2 etc + * + * Version: @(#)808x.c 1.0.8 2019/02/08 + * + * Authors: Miran Grca, + * Sarah Walker, + * + * Copyright 2016-2019 Fred N. van Kempen. + * Copyright 2016-2019 Miran Grca. + * Copyright 2008-2018 Sarah Walker. + * + * 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. + * 59 Temple Place - Suite 330 + * Boston, MA 02111-1307 + * USA. + */ +#include +#include +#include +#include +#include +#include "../emu.h" +#include "cpu.h" +#include "x86.h" +#include "../io.h" +#include "../machines/machine.h" +#include "../devices/system/pic.h" +#include "../devices/system/nmi.h" +#include "../mem.h" +#include "../rom.h" +#include "../timer.h" +#include "../plat.h" + + +/* The opcode of the instruction currently being executed. */ +uint8_t opcode; + +/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ +uint8_t prefetchqueue[6]; + +/* Variables to aid with the prefetch queue operation. */ +int fetchcycles = 0; +int fetchclocks, prefetchw = 0; + +/* The prefetch queue CS buffer and things needed to handle it. */ +uint8_t pfq_csbuf[24]; +int pfq_csbuf_inited = 0, pfq_csbuf_start = 0; + +/* The tables to speed up the setting of the Z, N, and P flags. */ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +/* Mask for shift and rotate count - currently defaulting to 0xFF because + this code is currently only used for the 8088 and 8086. */ +int count_mask = 0xff; + +/* The previous value of the CS segment register. */ +uint16_t oldcs; + +/* The IP equivalent of the current prefetch queue position. */ +uint16_t prefetchpc; + +/* A 16-bit zero, needed because some speed-up arrays contain pointers to it. */ +uint16_t zero = 0; + +/* MOD and R/M stuff. */ +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; +int rmdat; +int slowrm[8]; + +/* XT CPU multiplier. */ +int xt_cpu_multi; + +/* Is the CPU 8088 or 8086. */ +int is8086 = 0; + +/* Variables for handling the non-maskable interrupts. */ +int nmi = 0, nmi_auto_clear = 0; +int nmi_enable = 1; + +/* Was the CPU ever reset? */ +int x86_was_reset = 0; + +/* Memory read/write cycles to subtract from prefetch queue adding. */ +int memcycs; + +/* Difference between cycles before and after instruction execution. */ +int cycdiff; + +/* Where is this even used?! */ +int nextcyc = 0; + +/* Variables used elsewhere in the emulator. */ +int tempc, output = 0; + +/* Amount of instructions executed - used to calculate the % shown in the title bar. */ +int ins = 0; + +/* Is the TRAP flag on? */ +int trap = 0; + +/* The current effective address's segment. */ +uint32_t easeg; + +/* Pointer tables needed for segment overrides. */ +uint32_t *opseg[4]; +x86seg *_opseg[4]; + +/* Misc */ +int use32, stack32; +int oldcpl; + + +/* Local variables. */ +static int takeint = 0, noint = 0; +static int in_lock = 0, halt = 0; +static uint32_t *override_seg = NULL; + + +enum { + OP_ROL = 0, + OP_ROR, + OP_RCL, + OP_RCR, + OP_SHL, + OP_SHR, + OP_SAL, + OP_SAR +}; + + +#define IRQTEST ((flags & I_FLAG) && (pic.pend & ~pic.mask) && !noint) + + +extern uint32_t oldcs2; +extern uint32_t oldpc2; + +int indump = 0; + + +void +dumpregs(int force) +{ + char *seg_names[4] = { "ES", "CS", "SS", "DS" }; + int c; + + /* Only dump when needed, and only once.. */ + if (indump || (!force && !dump_on_exit)) + return; + + INFO("EIP=%08X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n", + cpu_state.pc, CS, DS, ES, SS, flags); + INFO("Old CS:EIP's: %04X:%08X %04X:%08X; %i ins\n", + oldcs, cpu_state.oldpc, oldcs2, oldpc2, ins); + for (c = 0; c < 4; c++) { + INFO("%s : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_names[c], _opseg[c]->base, _opseg[c]->limit, + _opseg[c]->access, _opseg[c]->limit_low, _opseg[c]->limit_high); + } + if (is386) { + INFO("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + seg_fs, _fs.limit, _fs.access, _fs.limit_low, _fs.limit_high); + INFO("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n", + gs, _gs.limit, _gs.access, _gs.limit_low, _gs.limit_high); + INFO("GDT : base=%06X limit=%04X\n", gdt.base, gdt.limit); + INFO("LDT : base=%06X limit=%04X\n", ldt.base, ldt.limit); + INFO("IDT : base=%06X limit=%04X\n", idt.base, idt.limit); + INFO("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + INFO("386 in %s mode: %i-bit data, %-i-bit stack\n", + (msw & 1) ? ((eflags & VM_FLAG) ? "V86" : "protected") : "real", + (use32) ? 32 : 16, (stack32) ? 32 : 16); + INFO("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n", cr0, cr2, cr3, cr4); + INFO("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n", + EAX, EBX, ECX, EDX, EDI, ESI, EBP, ESP); + } else { + INFO("808x/286 in %s mode\n", (msw & 1) ? "protected" : "real"); + INFO("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n", + AX, BX, CX, DX, DI, SI, BP, SP); + } +#if 0 + INFO("Entries in readlookup : %i writelookup : %i\n", + readlnum, writelnum); +#endif + + x87_dumpregs(); + + indump = 0; +} + + +#undef readmemb +#undef readmemw + +/* Reads a byte from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +uint8_t +readmemb(uint32_t a) +{ + if (a != (cs + cpu_state.pc)) + memcycs += 4; + if (readlookup2 == NULL) + return readmembl(a); + if (readlookup2[(a) >> 12] == -1) + return readmembl(a); + else + return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + + +/* Reads a byte from the memory but does not accounts for memory transfer + cycles to subtract from the cycles to use for adding to the prefetch + queue. */ +uint8_t +readmembf(uint32_t a) +{ + if (readlookup2 == NULL) + return readmembl(a); + if (readlookup2[(a) >> 12] == -1) + return readmembl(a); + else + return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + + +/* Reads a word from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +uint16_t +readmemw(uint32_t s, uint16_t a) +{ + if (a != (cs + cpu_state.pc)) + memcycs += (8 >> is8086); + if (readlookup2 == NULL) + return readmemwl(s, a); + if ((readlookup2[((s) + (a)) >> 12] == -1 || (s) == 0xFFFFFFFF)) + return readmemwl(s, a); + else + return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); +} + + +/* Fetches the MOD and R/M data needed to calculate the effective address. */ +#undef fetchea +#define fetchea() { \ + rmdat = pfq_fetchb(); \ + cpu_reg = (rmdat >> 3) & 7; \ + cpu_mod = (rmdat >> 6) & 3; \ + cpu_rm = rmdat & 7; \ + if (cpu_mod != 3) \ + fetcheal(); \ + } + + +/* Writes a byte from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +void +writememb(uint32_t a, uint8_t v) +{ + memcycs += 4; + if (writelookup2 == NULL) + writemembl(a, v); + if (writelookup2[(a) >> 12] == -1) + writemembl(a, v); + else + *(uint8_t *)(writelookup2[a >> 12] + a) = v; +} + + +/* Writes a word from the memory and accounts for memory transfer cycles to + subtract from the cycles to use for adding to the prefetch queue. */ +void +writememw(uint32_t s, uint32_t a, uint16_t v) +{ + memcycs += (8 >> is8086); + if (writelookup2 == NULL) + writememwl(s, a, v); + if ((writelookup2[((s) + (a)) >> 12]== -1) || ((s) == 0xFFFFFFFF)) + writememwl(s, a, v); + else + *(uint16_t *) (writelookup2[(s + a) >> 12] + s + a) = v; +} + + +/* Buffers 24 bytes around prefetchpc so that pfq_fetch_add() will add to + the queue the bytes as they were before the current instruction executed. */ +static void +pfq_buffer_cs(uint32_t ip) +{ + int i, addr; + int oc = cycles; + + addr = ((ip & 0xfff8) - 0x08) & 0xffff; + for (i = 0; i < 24; i++) + pfq_csbuf[i] = readmembf(cs + ((addr + i) & 0xffff)); + pfq_csbuf_start = addr; + pfq_csbuf_inited = 1; + /* Readd any cycles that were subtracted, if any - this servers to avoid + excess wait state cycles. */ + if (oc != 0) + cycles += abs(cycles - oc); +} + + +/* Determines whether or not to read from the 24-byte CS buffer or directly + from memory, and then reads. */ +static uint8_t +pfq_buffer_read(uint32_t ip) +{ + int addr; + int add = 0; + uint8_t ret; + + /* Read this *ALWAYS* because of the wait states, if needed the value + will then be overrided with the one from the buffer. */ + ret = readmembf(cs + (ip & 0xffff)); + + /* This is one of those cases where our buffer goes across the segment + boundary, so if our IP is smaller than the backup start IP, we add + 0x10000 to it, so that IP - backup start IP will be above 0. */ + if ((pfq_csbuf_start > 0xffe8) && (ip < pfq_csbuf_start)) + add = 0x10000; + if (pfq_csbuf_inited) { + addr = ((ip & 0xffff) + add - pfq_csbuf_start); + if ((addr > 0) && (addr < 24)) + ret = pfq_csbuf[(addr & 0xffff) % 24]; + } + + return ret; +} + + +/* Fetches a byte from the prefetch queue, or from memory if the queue has + been drained. */ +static uint8_t +pfq_fetchb(void) +{ + uint8_t temp; + + if (prefetchw == 0) { + cycles -= (4 - (fetchcycles & 3)); + fetchclocks += (4 - (fetchcycles & 3)); + fetchcycles = 4; + temp = readmembf(cs + cpu_state.pc); + prefetchpc = cpu_state.pc = cpu_state.pc + 1; + if (is8086 && (cpu_state.pc & 1)) { + // prefetchqueue[0] = readmembf(cs + cpu_state.pc); + prefetchqueue[0] = pfq_buffer_read(cpu_state.pc); + prefetchpc++; + prefetchw++; + } + } else { + temp = prefetchqueue[0]; + prefetchqueue[0] = prefetchqueue[1]; + prefetchqueue[1] = prefetchqueue[2]; + prefetchqueue[2] = prefetchqueue[3]; + if (is8086) { + prefetchqueue[3] = prefetchqueue[4]; + prefetchqueue[4] = prefetchqueue[5]; + } + prefetchw--; + fetchcycles -= 4; + cpu_state.pc++; + } + return temp; +} + + +/* Fetches a word from the prefetch queue, or from memory if the queue has + been drained. */ +static uint16_t +pfq_fetchw(void) +{ + uint8_t temp = pfq_fetchb(); + return temp | (pfq_fetchb() << 8); +} + + +/* Adds bytes to the prefetch queue based on the instruction's cycle count. */ +static void +pfq_add(int c) +{ + int d; + if (c < 0) + return; + if (prefetchw > ((is8086) ? 5 : 3)) + return; + d = c + (fetchcycles & 3); + while ((d > 3) && (prefetchw < ((is8086) ? 6 : 4))) { + d -= 4; + if (is8086 && !(prefetchpc & 1)) { + prefetchqueue[prefetchw] = pfq_buffer_read(prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw < ((is8086) ? 6 : 4)) { + prefetchqueue[prefetchw] = pfq_buffer_read(prefetchpc); + prefetchpc++; + prefetchw++; + } + } + fetchcycles += c; + if (fetchcycles > 16) + fetchcycles = 16; +} + + +/* Completes a fetch (called by refreshread()). */ +static void +pfq_complete(void) +{ + if (!(fetchcycles & 3)) + return; + if (prefetchw > ((is8086) ? 5 : 3)) + return; + if (!prefetchw) + nextcyc = (4 - (fetchcycles & 3)); + cycles -= (4 - (fetchcycles & 3)); + fetchclocks += (4 - (fetchcycles & 3)); + if (is8086 && !(prefetchpc&1)) { + prefetchqueue[prefetchw] = pfq_buffer_read(prefetchpc); + prefetchpc++; + prefetchw++; + } + if (prefetchw < ((is8086) ? 6 : 4)) { + prefetchqueue[prefetchw] = pfq_buffer_read(prefetchpc); + prefetchpc++; + prefetchw++; + } + fetchcycles += (4 - (fetchcycles & 3)); +} + + +/* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ +static void +pfq_clear(void) +{ + prefetchpc = cpu_state.pc; + prefetchw = 0; + memcycs = cycdiff - cycles; + fetchclocks = 0; + pfq_csbuf_inited = 0; +} + + +/* Memory refresh read - called by reads and writes on DMA channel 0. */ +void +refreshread(void) +{ + pfq_complete(); + memcycs += 4; +} + + +/* Preparation of the various arrays needed to speed up the MOD and R/M work. */ +static void +makemod1table(void) +{ + mod1add[0][0] = &BX; + mod1add[0][1] = &BX; + mod1add[0][2] = &BP; + mod1add[0][3] = &BP; + mod1add[0][4] = &SI; + mod1add[0][5] = &DI; + mod1add[0][6] = &BP; + mod1add[0][7] = &BX; + mod1add[1][0] = &SI; + mod1add[1][1] = &DI; + mod1add[1][2] = &SI; + mod1add[1][3] = &DI; + mod1add[1][4] = &zero; + mod1add[1][5] = &zero; + mod1add[1][6] = &zero; + mod1add[1][7] = &zero; + slowrm[0] = 0; + slowrm[1] = 1; + slowrm[2] = 1; + slowrm[3] = 0; + mod1seg[0] = &ds; + mod1seg[1] = &ds; + mod1seg[2] = &ss; + mod1seg[3] = &ss; + mod1seg[4] = &ds; + mod1seg[5] = &ds; + mod1seg[6] = &ss; + mod1seg[7] = &ds; + opseg[0] = &es; + opseg[1] = &cs; + opseg[2] = &ss; + opseg[3] = &ds; + _opseg[0] = &_es; + _opseg[1] = &_cs; + _opseg[2] = &_ss; + _opseg[3] = &_ds; +} + + +/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ +static void +fetcheal(void) +{ + if (!cpu_mod && (cpu_rm == 6)) { + cpu_state.eaaddr = pfq_fetchw(); + easeg = ds; + pfq_add(6); + } else { + switch (cpu_mod) { + case 0: + cpu_state.eaaddr = 0; + if (cpu_rm & 4) + pfq_add(5); + else + pfq_add(7 + slowrm[cpu_rm]); + break; + case 1: + cpu_state.eaaddr = (uint16_t) (int8_t) pfq_fetchb(); + if (cpu_rm & 4) + pfq_add(9); + else + pfq_add(11 + slowrm[cpu_rm]); + break; + case 2: + cpu_state.eaaddr = pfq_fetchw(); + if (cpu_rm & 4) + pfq_add(9); + else + pfq_add(11 + slowrm[cpu_rm]); + break; + } + + cpu_state.eaaddr += (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = *mod1seg[cpu_rm]; + cpu_state.eaaddr &= 0xFFFF; + } + + if (override_seg) + easeg = *override_seg; + cpu_state.last_ea = cpu_state.eaaddr; +} + + +/* Reads a byte from the effective address. */ +static uint8_t +geteab(void) +{ + if (cpu_mod == 3) + return (cpu_rm & 4) ? cpu_state.regs[cpu_rm & 3].b.h : cpu_state.regs[cpu_rm & 3].b.l; + + return readmemb(easeg + cpu_state.eaaddr); +} + + +/* Reads a word from the effective address. */ +static uint16_t +geteaw(void) +{ + if (cpu_mod == 3) + return cpu_state.regs[cpu_rm].w; + return readmemw(easeg, cpu_state.eaaddr); +} + + +/* Writes a byte to the effective address. */ +static void +seteab(uint8_t val) +{ + if (cpu_mod == 3) { + if (cpu_rm & 4) + cpu_state.regs[cpu_rm & 3].b.h = val; + else + cpu_state.regs[cpu_rm & 3].b.l = val; + } else + writememb(easeg + cpu_state.eaaddr, val); +} + + +/* Writes a word to the effective address. */ +static void +seteaw(uint16_t val) +{ + if (cpu_mod == 3) + cpu_state.regs[cpu_rm].w = val; + else + writememw(easeg, cpu_state.eaaddr, val); +} + +#undef getr8 +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#undef setr8 +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/* Prepare the ZNP table needed to speed up the setting of the Z, N, and P flags. */ +static void +makeznptable(void) +{ + int c, d; + for (c = 0; c < 256; c++) { + d = 0; + if (c & 1) + d++; + if (c & 2) + d++; + if (c & 4) + d++; + if (c & 8) + d++; + if (c & 16) + d++; + if (c & 32) + d++; + if (c & 64) + d++; + if (c & 128) + d++; + if (d & 1) + znptable8[c] = 0; + else + znptable8[c] = P_FLAG; + if (c == 0xb1) + DEBUG("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) + znptable8[c] |= Z_FLAG; + if (c & 0x80) + znptable8[c] |= N_FLAG; + } + + for (c = 0; c < 65536; c++) { + d = 0; + if (c & 1) + d++; + if (c & 2) + d++; + if (c & 4) + d++; + if (c & 8) + d++; + if (c & 16) + d++; + if (c & 32) + d++; + if (c & 64) + d++; + if (c & 128) + d++; + if (d & 1) + znptable16[c] = 0; + else + znptable16[c] = P_FLAG; + if (c == 0xb1) + DEBUG("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) + DEBUG("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) + znptable16[c] |= Z_FLAG; + if (c & 0x8000) + znptable16[c] |= N_FLAG; + } +} + + +/* Common reset function. */ +static void +x86_reset_common(int hard) +{ + if (hard) { + INFO("x86 reset\n"); + ins = 0; + } + use32 = 0; + cpu_cur_status = 0; + stack32 = 0; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + msw = 0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cpu_cache_int_enabled = 0; + cpu_update_waitstates(); + cr4 = 0; + eflags = 0; + cgate32 = 0; + if (AT) { + loadcs(0xF000); + cpu_state.pc = 0xFFF0; + rammask = cpu_16bitbus ? 0xFFFFFF : 0xFFFFFFFF; + } else { + loadcs(0xFFFF); + cpu_state.pc=0; + rammask = 0xfffff; + } + idt.base = 0; + idt.limit = is386 ? 0x03FF : 0xFFFF; + flags = 2; + trap = 0; + override_seg = NULL; + in_lock = halt = 0; + + if (hard) { + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + pfq_clear(); + cpu_set_edx(); + EAX = 0; + ESP = 0; + mmu_perm = 4; + } + + x86seg_reset(); +#ifdef USE_DYNAREC + if (hard) + codegen_reset(); +#endif + x86_was_reset = 1; + port_92_clear_reset(); + + pfq_csbuf_inited = pfq_csbuf_start = 0; +} + + +/* Hard reset. */ +void +resetx86(void) +{ + x86_reset_common(1); +} + + +/* Soft reset. */ +void +softresetx86(void) +{ + x86_reset_common(0); +} + + +/* Sets the Z, N, and P flags according to the specified byte. */ +static void +setznp8(uint8_t val) +{ + flags &= ~0xC4; + flags |= znptable8[val]; +} + + +/* Sets the Z, N, and P flags according to the specified word. */ +static void +setznp16(uint16_t val) +{ + flags &= ~0xC4; + flags |= znptable16[val]; +} + + +static void +setadd8(uint8_t a, uint8_t b) +{ + uint16_t c = (uint16_t) a + (uint16_t) b; + + flags &= ~0x8D5; + flags |= znptable8[c & 0xFF]; + if (c & 0x100) + flags |= C_FLAG; + if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80)) + flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setadd8nc(uint8_t a, uint8_t b) +{ + uint16_t c = (uint16_t) a + (uint16_t) b; + + flags &= ~0x8D4; + flags |= znptable8[c & 0xFF]; + if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80)) + flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setadc8(uint8_t a, uint8_t b) +{ + uint16_t c = (uint16_t) a + (uint16_t) b + tempc; + + flags &= ~0x8D5; + flags |= znptable8[c & 0xFF]; + if (c & 0x100) + flags |= C_FLAG; + if (!((a ^ b) & 0x80) && ((a ^ c) & 0x80)) + flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setadd16(uint16_t a, uint16_t b) +{ + uint32_t c = (uint32_t) a + (uint32_t) b; + flags &= ~0x8D5; + flags |= znptable16[c & 0xFFFF]; + if (c & 0x10000) + flags |= C_FLAG; + if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000)) + flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setadd16nc(uint16_t a, uint16_t b) +{ + uint32_t c = (uint32_t) a + (uint32_t) b; + + flags &= ~0x8D4; + flags |= znptable16[c & 0xFFFF]; + if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000)) + flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setadc16(uint16_t a, uint16_t b) +{ + uint32_t c = (uint32_t) a + (uint32_t) b + tempc; + + flags &= ~0x8D5; + flags |= znptable16[c & 0xFFFF]; + if (c & 0x10000) + flags |= C_FLAG; + if (!((a ^ b) & 0x8000) && ((a ^ c) & 0x8000)) + flags |= V_FLAG; + if (((a & 0xF) + (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setsub8(uint8_t a, uint8_t b) +{ + uint16_t c = (uint16_t) a - (uint16_t) b; + + flags &= ~0x8D5; + flags |= znptable8[c & 0xFF]; + if (c & 0x100) + flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x80) + flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setsub8nc(uint8_t a, uint8_t b) +{ + uint16_t c = (uint16_t) a - (uint16_t) b; + + flags &= ~0x8D4; + flags |= znptable8[c & 0xFF]; + if ((a ^ b) & (a ^ c) & 0x80) + flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c = (uint16_t) a - (((uint16_t) b) + tempc); + + flags &= ~0x8D5; + flags |= znptable8[c & 0xFF]; + if (c & 0x100) + flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x80) + flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setsub16(uint16_t a, uint16_t b) +{ + uint32_t c = (uint32_t) a - (uint32_t) b; + + flags &= ~0x8D5; + flags |= znptable16[c & 0xFFFF]; + if (c & 0x10000) + flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x8000) + flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setsub16nc(uint16_t a, uint16_t b) +{ + uint32_t c = (uint32_t) a - (uint32_t) b; + + flags &= ~0x8D4; + flags |= (znptable16[c & 0xFFFF] & ~4); + flags |= (znptable8[c & 0xFF] & 4); + if ((a ^ b) & (a ^ c) & 0x8000) + flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +static void +setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c = (uint32_t) a - (((uint32_t) b) + tempc); + + flags &= ~0x8D5; + flags |= (znptable16[c & 0xFFFF] & ~4); + flags |= (znptable8[c & 0xFF] & 4); + if (c & 0x10000) + flags |= C_FLAG; + if ((a ^ b) & (a ^ c) & 0x8000) + flags |= V_FLAG; + if (((a & 0xF) - (b & 0xF)) & 0x10) + flags |= A_FLAG; +} + + +/* Ends the timer period. */ +static void +clockhardware(void) +{ + timer_end_period(cycles * xt_cpu_multi); +} + + +/* Performs a conditional jump. */ +static void +x86_jcc(uint8_t opcode, int cond) +{ + int8_t offset; + + offset = (int8_t) pfq_fetchb(); + if ((!cond) == (opcode & 0x01)) { + cpu_state.pc += offset; + cycles -= 12; + pfq_clear(); + } + cycles -= 4; +} + + +/* Pushes a word to the stack. */ +static void +x86_push_ex(uint16_t val) +{ + writememw(ss, (SP & 0xFFFF), val); + cpu_state.last_ea = SP; +} + + +static void +x86_push(uint16_t val) +{ + SP -= 2; + x86_push_ex(val); +} + + +/* Pops a word from the stack. */ +static uint16_t +x86_pop(void) +{ + uint16_t tempw; + + tempw = readmemw(ss, SP); + SP += 2; + cpu_state.last_ea = SP; + return tempw; +} + + +/* Calls an interrupt. */ +static void +x86_int(uint16_t addr, int cli) +{ + x86_push(flags | 0xF000); + x86_push(CS); + x86_push(cpu_state.pc); + if (cli) + flags &= ~I_FLAG; + flags &= ~T_FLAG; + addr <<= 2; + cpu_state.pc = readmemw(0, addr); + loadcs(readmemw(0, addr + 2)); + pfq_clear(); +} + + +static void +x86_post_process(void) +{ + uint8_t temp = 0; + + pfq_add(((cycdiff - cycles) - memcycs) - fetchclocks); + if ((cycdiff - cycles) < memcycs) + cycles -= (memcycs - (cycdiff - cycles)); + +#if 0 + /* FIXME: Find out why this is needed. */ + if (romset == ROM_IBMPC) { + if ((cs + cpu_state.pc) == 0xFE4A7) { + /* You didn't seriously think I was going to emulate the cassette, did you? */ + CX = 1; + BX = 0x500; + } + } +#endif + memcycs = 0; + + clockhardware(); + + if (trap && (flags & T_FLAG) && !noint) { + halt = 0; + x86_int(1, 1); + } else if (nmi && nmi_enable && nmi_mask) { + halt = 0; + x86_int(2, 1); + nmi_enable = 0; + } else if (takeint && !noint) { + temp = picinterrupt(); + if (temp != 0xFF) { + halt = 0; + x86_int(temp, 1); + } + } + takeint = (flags & I_FLAG) && (pic.pend &~ pic.mask); + + if (noint) + noint = 0; + ins++; +} + + +static void +x86_post_process_main(void) +{ + if (override_seg) + override_seg = NULL; + + if (in_lock) + in_lock = 0; + + x86_post_process(); +} + + +static void +x86_string(uint8_t op, int rep) { + uint8_t temp, temp2; + uint16_t tempw, tempw2; + + switch(op) { + case 0xA4: /*MOVSB*/ + temp = readmemb((override_seg ? *override_seg : ds) + SI); + writememb(es + DI, temp); + if (flags & D_FLAG) { + DI--; + SI--; + } else { + DI++; + SI++; + } + cycles -= 18; + break; + + case 0xA5: /*MOVSW*/ + tempw = readmemw((override_seg ? *override_seg : ds), SI); + writememw(es, DI, tempw); + if (flags & D_FLAG) { + DI -= 2; + SI -= 2; + } else { + DI += 2; + SI += 2; + } + cycles -= 18; + break; + + case 0xA6: /*CMPSB*/ + temp = readmemb((override_seg ? *override_seg : ds) + SI); + temp2 = readmemb(es + DI); + setsub8(temp, temp2); + if (flags & D_FLAG) { + DI--; + SI--; + } else { + DI++; + SI++; + } + cycles -= 30; + break; + + case 0xA7: /*CMPSW*/ + tempw = readmemw((override_seg ? *override_seg : ds), SI); + tempw2 = readmemw(es, DI); + setsub16(tempw, tempw2); + if (flags & D_FLAG) { + DI -= 2; + SI -= 2; + } else { + DI += 2; + SI += 2; + } + cycles -= 30; + break; + + case 0xAA: /*STOSB*/ + writememb(es + DI, AL); + if (flags & D_FLAG) + DI--; + else + DI++; + cycles -= 11; + break; + + case 0xAB: /*STOSW*/ + writememw(es, DI, AX); + if (flags & D_FLAG) + DI -= 2; + else + DI += 2; + cycles -= 11; + break; + + case 0xAC: /*LODSB*/ + temp2 = readmemb((override_seg ? *override_seg : ds) + SI); + if (!rep) + AL = temp2; + if (flags & D_FLAG) + SI--; + else + SI++; + cycles -= 16; + break; + + case 0xAD: /*LODSW*/ + tempw2 = readmemw((override_seg ? *override_seg : ds), SI); + if (!rep) + AX = tempw2; + if (flags & D_FLAG) + SI -= 2; + else + SI += 2; + cycles -= 16; + break; + + case 0xAE: /*SCASB*/ + temp = readmemb(es + DI); + setsub8(AL, temp); + if (flags & D_FLAG) + DI--; + else + DI++; + cycles -= 19; + break; + + case 0xAF: /*SCASW*/ + tempw = readmemw(es, DI); + setsub16(AX, tempw); + if (flags & D_FLAG) + DI -= 2; + else + DI += 2; + cycles -= 19; + break; + } +} + + +/* Performs a REP. */ +static void +x86_rep(int fv) +{ + uint8_t temp = 0; + int cond, c = CX; + uint16_t ipc = cpu_state.oldpc, ipc2 = 0; + + if (override_seg) + ipc2++; + if (in_lock) + ipc2++; + + cycles -= 2; + +startrep: + temp = pfq_fetchb(); + + switch (temp) { + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + override_seg = opseg[(temp >> 3) & 0x03]; + cycles -= 2; + goto startrep; + break; + + case 0xA4: /*REP MOVSB*/ + case 0xA5: /*REP MOVSW*/ + case 0xA6: /*REP CMPSB*/ + case 0xA7: /*REP CMPSW*/ + case 0xAA: /*REP STOSB*/ + case 0xAB: /*REP STOSW*/ + case 0xAC: /*REP LODSB*/ + case 0xAD: /*REP LODSW*/ + case 0xAE: /*REP SCASB*/ + case 0xAF: /*REP SCASW*/ + if ((temp & 0x17) != 0x17) + fv = 2; + + if (fv == 1) + flags |= Z_FLAG; + else if (fv == 0) + flags &= ~Z_FLAG; + + cond = !!c; + if (fv < 2) + cond = cond && (fv == ((flags & Z_FLAG) ? 1 : 0)); + if (cond) { + x86_string(temp, 1); + c--; + } + + cond = !!c; + if (fv < 2) + cond = cond && (fv == ((flags & Z_FLAG) ? 1 : 0)); + if (cond) { + cpu_state.pc = ipc; + pfq_clear(); + } + break; + + default: + cpu_state.pc = ipc + 1 + ipc2; + if (temp != 0x08) + cycles -= 18; + pfq_clear(); + + break; + } + + CX = c; + + if (IRQTEST) + takeint = 1; +} + + +/* Performs an 8-bit rotate. */ +static void +x86_rotate8(uint8_t *dst, uint8_t count) +{ + uint8_t temp_count; + uint16_t temp_cf; + uint8_t op = (rmdat & 0x38) >> 3; + + switch (op) { + case OP_RCL: + case OP_RCR: + /* RCL and RCR instructions */ + temp_count = (count & count_mask) % 9; + if (op == OP_RCL) { + /* RCL instruction operation */ + while (temp_count != 0) { + temp_cf = (*dst & 0x80) ? C_FLAG : 0; + *dst = (*dst << 1) + !!(flags & C_FLAG); + flags = (flags & ~C_FLAG) | temp_cf; + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x80) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } + } else { + /* RCR instruction operation */ + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x80) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } + + while (temp_count != 0) { + temp_cf = (*dst & 0x01) ? C_FLAG : 0; + *dst = (*dst >> 1) + (!!(flags & C_FLAG) << 7); + flags = (flags & ~C_FLAG) | temp_cf; + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + } + break; + + case OP_ROL: + case OP_ROR: + /* ROL and ROR instructions */ + temp_count = count % 8; + if (op == OP_ROL) { + /* ROL instruction operation */ + while (temp_count != 0) { + temp_cf = (*dst & 0x80) ? C_FLAG : 0; + *dst = (*dst << 1) + !!(temp_cf); + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + flags &= ~C_FLAG; + if (*dst & 0x01) + flags |= C_FLAG; + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x80) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } + } else { + /* ROR instruction operation */ + while (temp_count != 0) { + temp_cf = (*dst & 0x01) ? C_FLAG : 0; + *dst = (*dst >> 1) + (!!(temp_cf) << 7); + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + flags &= ~C_FLAG; + if (*dst & 0x80) + flags |= C_FLAG; + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x80) ^ !!(*dst & 0x40)) + flags |= V_FLAG; + } + } + break; + } + + seteab(*dst); +} + + +/* Performs a 16-bit rotate. */ +static void +x86_rotate16(uint16_t *dst, uint8_t count) +{ + uint8_t temp_count; + uint16_t temp_cf; + uint8_t op = (rmdat & 0x38) >> 3; + + switch (op) { + case OP_RCL: + case OP_RCR: + /* RCL and RCR instructions */ + temp_count = (count & count_mask) % 17; + if (op == OP_RCL) { + /* RCL instruction operation */ + while (temp_count != 0) { + temp_cf = (*dst & 0x8000) ? C_FLAG : 0; + *dst = (*dst << 1) + !!(flags & C_FLAG); + flags = (flags & ~C_FLAG) | temp_cf; + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x8000) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } + } else { + /* RCR instruction operation */ + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x8000) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } + + while (temp_count != 0) { + temp_cf = (*dst & 0x0001) ? C_FLAG : 0; + *dst = (*dst >> 1) + (!!(flags & C_FLAG) << 15); + flags = (flags & ~C_FLAG) | temp_cf; + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + } + break; + + case OP_ROL: + case OP_ROR: + /* ROL and ROR instructions */ + temp_count = count % 16; + if (op == OP_ROL) { + /* ROL instruction operation */ + while (temp_count != 0) { + temp_cf = (*dst & 0x8000) ? C_FLAG : 0; + *dst = (*dst << 1) + !!(temp_cf); + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + flags &= ~C_FLAG; + if (*dst & 0x0001) + flags |= C_FLAG; + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x8000) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } + } else { + /* ROR instruction operation */ + while (temp_count != 0) { + temp_cf = (*dst & 0x0001) ? C_FLAG : 0; + *dst = (*dst >> 1) + (!!(temp_cf) << 15); + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + flags &= ~C_FLAG; + if (*dst & 0x8000) + flags |= C_FLAG; + if (count == 1) { + flags &= ~V_FLAG; + if (!!(*dst & 0x8000) ^ !!(*dst & 0x4000)) + flags |= V_FLAG; + } + } + break; + } + + seteaw(*dst); +} + + +/* Performs an 8-bit shift. */ +static void +x86_shift8(uint8_t *dst, uint8_t count) +{ + uint8_t temp_count = count & count_mask; + uint8_t temp_dst = *dst; + int8_t signed_dst; + uint8_t op = (rmdat & 0x38) >> 3; + + if (!temp_count) + return; + + while (temp_count != 0) { + if ((op == OP_SAL) || (op == OP_SHL)) { + /* SAL, SHL */ + flags &= ~C_FLAG; + if (*dst & 0x80) + flags |= C_FLAG; + *dst = *dst << 1; + } else { + flags &= ~C_FLAG; + if (*dst & 0x01) + flags |= C_FLAG; + if (op == OP_SAR) { + signed_dst = (int8_t) *dst; + signed_dst = signed_dst >> 1; + *dst = (uint8_t) signed_dst; + } else + *dst = *dst >> 1; + } + + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + + if ((count & count_mask) == 1) { + flags &= ~V_FLAG; + if ((op == OP_SAL) || (op == OP_SHL)) { + if (!!(*dst & 0x80) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } else if (op == OP_SHR) { + if (temp_dst & 0x80) + flags |= V_FLAG; + } + } + + seteab(*dst); + + /* Set the SF, ZF, and PF flags. */ + setznp8(*dst); +} + + +/* Performs a 16-bit shift. */ +static void +x86_shift16(uint16_t *dst, uint8_t count) +{ + uint8_t temp_count = count & count_mask; + uint16_t temp_dst = *dst; + int16_t signed_dst; + uint8_t op = (rmdat & 0x38) >> 3; + + if (!temp_count) + return; + + while (temp_count != 0) { + if ((op == OP_SAL) || (op == OP_SHL)) { + /* SAL, SHL */ + flags &= ~C_FLAG; + if (*dst & 0x8000) + flags |= C_FLAG; + *dst = *dst << 1; + } else { + flags &= ~C_FLAG; + if (*dst & 0x0001) + flags |= C_FLAG; + if (op == OP_SAR) { + signed_dst = (int16_t) *dst; + signed_dst = signed_dst >> 1; + *dst = (uint16_t) signed_dst; + } else + *dst = *dst >> 1; + } + + if (opcode & 0x02) + cycles -= 4; + temp_count--; + } + + if ((count & count_mask) == 1) { + flags &= ~V_FLAG; + if ((op == OP_SAL) || (op == OP_SHL)) { + if (!!(*dst & 0x8000) ^ !!(flags & C_FLAG)) + flags |= V_FLAG; + } else if (op == OP_SHR) { + if (temp_dst & 0x8000) + flags |= V_FLAG; + } + } + + seteaw(*dst); + + /* Set the SF, ZF, and PF flags. */ + setznp16(*dst); +} + + +/* Executes instructions up to the specified number of cycles. */ +void +execx86(int cycs) +{ + int8_t offset; + uint8_t temp = 0, temp2; + uint16_t addr; + uint16_t tempw, tempw2; + int tempws, tempi; + uint32_t c, templ; + + cycles += cycs; + + while (cycles > 0) { + cycdiff = cycles; + timer_start_period(cycles * xt_cpu_multi); + cycles -= nextcyc; + nextcyc = 0; + fetchclocks = 0; + oldcs = CS; + cpu_state.oldpc = cpu_state.pc; + pfq_buffer_cs(prefetchpc); + +opcodestart: + if (halt) { + cycles -= 2; + x86_post_process_main(); + continue; + } + + opcode = pfq_fetchb(); + tempc = flags & C_FLAG; + trap = flags & T_FLAG; + cpu_state.pc--; + cpu_state.pc++; + + switch (opcode) { + case 0x00: /*ADD 8,reg*/ + fetchea(); + temp = geteab(); + setadd8(temp, getr8(cpu_reg)); + temp += getr8(cpu_reg); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 :24); + break; + + case 0x01: /*ADD 16,reg*/ + fetchea(); + tempw = geteaw(); + setadd16(tempw, cpu_state.regs[cpu_reg].w); + tempw += cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x02: /*ADD cpu_reg,8*/ + fetchea(); + temp = geteab(); + setadd8(getr8(cpu_reg), temp); + setr8(cpu_reg, getr8(cpu_reg) + temp); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x03: /*ADD cpu_reg,16*/ + fetchea(); + tempw = geteaw(); + setadd16(cpu_state.regs[cpu_reg].w, tempw); + cpu_state.regs[cpu_reg].w += tempw; + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x04: /*ADD AL,#8*/ + temp = pfq_fetchb(); + setadd8(AL, temp); + AL += temp; + cycles-=4; + break; + + case 0x05: /*ADD AX,#16*/ + tempw = pfq_fetchw(); + setadd16(AX, tempw); + AX += tempw; + cycles-=4; + break; + + case 0x06: case 0x0E: case 0x16: case 0x1E: /* PUSH seg */ + x86_push(_opseg[(opcode >> 3) & 0x03]->seg); + cycles -= 14; + break; + + case 0x07: case 0x0F: case 0x17: case 0x1F: /* POP seg */ + if (opcode == 0x0F) { + loadcs(x86_pop()); + pfq_clear(); + } else + loadseg(x86_pop(), _opseg[(opcode >> 3) & 0x03]); + cycles -= 12; + noint = 1; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + temp = geteab(); + temp |= getr8(cpu_reg); + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x09: /*OR 16,reg*/ + fetchea(); + tempw = geteaw(); + tempw |= cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x0A: /*OR cpu_reg,8*/ + fetchea(); + temp = geteab(); + temp |= getr8(cpu_reg); + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + setr8(cpu_reg, temp); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw = geteaw(); + tempw |= cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags &= ~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[cpu_reg].w = tempw; + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x0C: /*OR AL,#8*/ + AL |= pfq_fetchb(); + setznp8(AL); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= 4; + break; + + case 0x0D: /*OR AX,#16*/ + AX |= pfq_fetchw(); + setznp16(AX); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= 4; + break; + + case 0x10: /*ADC 8,reg*/ + fetchea(); + temp = geteab(); + temp2 = getr8(cpu_reg); + setadc8(temp, temp2); + temp += temp2 + tempc; + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x11: /*ADC 16,reg*/ + fetchea(); + tempw = geteaw(); + tempw2 = cpu_state.regs[cpu_reg].w; + setadc16(tempw,tempw2); + tempw += tempw2 + tempc; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x12: /*ADC cpu_reg,8*/ + fetchea(); + temp = geteab(); + setadc8(getr8(cpu_reg), temp); + setr8(cpu_reg, getr8(cpu_reg) + temp + tempc); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x13: /*ADC cpu_reg,16*/ + fetchea(); + tempw = geteaw(); + setadc16(cpu_state.regs[cpu_reg].w, tempw); + cpu_state.regs[cpu_reg].w += tempw + tempc; + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x14: /*ADC AL,#8*/ + tempw = pfq_fetchb(); + setadc8(AL, tempw & 0xff); + AL += tempw + tempc; + cycles -= 4; + break; + + case 0x15: /*ADC AX,#16*/ + tempw = pfq_fetchw(); + setadc16(AX, tempw); + AX += tempw + tempc; + cycles -= 4; + break; + + case 0x18: /*SBB 8,reg*/ + fetchea(); + temp = geteab(); + temp2 = getr8(cpu_reg); + setsbc8(temp, temp2); + temp -= (temp2 + tempc); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x19: /*SBB 16,reg*/ + fetchea(); + tempw = geteaw(); + tempw2 = cpu_state.regs[cpu_reg].w; + setsbc16(tempw, tempw2); + tempw -= (tempw2 + tempc); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x1A: /*SBB cpu_reg,8*/ + fetchea(); + temp = geteab(); + setsbc8(getr8(cpu_reg), temp); + setr8(cpu_reg, getr8(cpu_reg) - (temp + tempc)); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x1B: /*SBB cpu_reg,16*/ + fetchea(); + tempw = geteaw(); + tempw2 = cpu_state.regs[cpu_reg].w; + setsbc16(tempw2, tempw); + tempw2 -= (tempw + tempc); + cpu_state.regs[cpu_reg].w = tempw2; + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x1C: /*SBB AL,#8*/ + temp = pfq_fetchb(); + setsbc8(AL, temp); + AL -= (temp + tempc); + cycles -= 4; + break; + + case 0x1D: /*SBB AX,#16*/ + tempw = pfq_fetchw(); + setsbc16(AX, tempw); + AX -= (tempw + tempc); + cycles -= 4; + break; + + case 0x20: /*AND 8,reg*/ + fetchea(); + temp = geteab(); + temp &= getr8(cpu_reg); + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x21: /*AND 16,reg*/ + fetchea(); + tempw = geteaw(); + tempw &= cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x22: /*AND cpu_reg,8*/ + fetchea(); + temp = geteab(); + temp &= getr8(cpu_reg); + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + setr8(cpu_reg, temp); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x23: /*AND cpu_reg,16*/ + fetchea(); + tempw = geteaw(); + tempw &= cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cpu_state.regs[cpu_reg].w = tempw; + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x24: /*AND AL,#8*/ + AL &= pfq_fetchb(); + setznp8(AL); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= 4; + break; + + case 0x25: /*AND AX,#16*/ + AX &= pfq_fetchw(); + setznp16(AX); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= 4; + break; + + case 0x26: /*ES:*/ + case 0x2E: /*CS:*/ + case 0x36: /*SS:*/ + case 0x3E: /*DS:*/ + override_seg = opseg[(opcode >> 3) & 0x03]; + cycles -= 4; + goto opcodestart; + + case 0x27: /*DAA*/ + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) { + tempi = ((uint16_t) AL) + 6; + AL += 6; + flags |= A_FLAG; + if (tempi & 0x100) + flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9F)) { + AL += 0x60; + flags |= C_FLAG; + } + setznp8(AL); + cycles -= 4; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + temp = geteab(); + setsub8(temp, getr8(cpu_reg)); + temp -= getr8(cpu_reg); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 :24); + break; + + case 0x29: /*SUB 16,reg*/ + fetchea(); + tempw = geteaw(); + setsub16(tempw, cpu_state.regs[cpu_reg].w); + tempw -= cpu_state.regs[cpu_reg].w; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x2A: /*SUB cpu_reg,8*/ + fetchea(); + temp = geteab(); + setsub8(getr8(cpu_reg), temp); + setr8(cpu_reg, getr8(cpu_reg) - temp); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x2B: /*SUB cpu_reg,16*/ + fetchea(); + tempw = geteaw(); + setsub16(cpu_state.regs[cpu_reg].w, tempw); + cpu_state.regs[cpu_reg].w -= tempw; + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x2C: /*SUB AL,#8*/ + temp = pfq_fetchb(); + setsub8(AL, temp); + AL -= temp; + cycles -= 4; + break; + + case 0x2D: /*SUB AX,#16*/ + tempw = pfq_fetchw(); + setsub16(AX, tempw); + AX -= tempw; + cycles -= 4; + break; + + case 0x2F: /*DAS*/ + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) { + tempi = ((uint16_t) AL) - 6; + AL -= 6; + flags |= A_FLAG; + if (tempi & 0x100) + flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9F)) { + AL -= 0x60; + flags |= C_FLAG; + } + setznp8(AL); + cycles-=4; + break; + + case 0x30: /*XOR 8,reg*/ + fetchea(); + temp = geteab(); + temp ^= getr8(cpu_reg); + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x31: /*XOR 16,reg*/ + fetchea(); + tempw = geteaw(); + tempw ^= cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x32: /*XOR cpu_reg,8*/ + fetchea(); + temp = geteab(); + temp ^= getr8(cpu_reg); + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG); + setr8(cpu_reg, temp); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x33: /*XOR cpu_reg,16*/ + fetchea(); + tempw = geteaw(); + tempw ^= cpu_state.regs[cpu_reg].w; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[cpu_reg].w = tempw; + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x34: /*XOR AL,#8*/ + AL ^= pfq_fetchb(); + setznp8(AL); + flags &= ~(C_FLAG | V_FLAG); + cycles -= 4; + break; + + case 0x35: /*XOR AX,#16*/ + AX ^= pfq_fetchw(); + setznp16(AX); + flags &= ~(C_FLAG | V_FLAG); + cycles -= 4; + break; + + case 0x37: /*AAA*/ + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) { + AL += 6; + AH++; + flags |= (A_FLAG | C_FLAG); + } else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + cycles -= 8; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp = geteab(); + setsub8(temp, getr8(cpu_reg)); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw = geteaw(); + setsub16(tempw, cpu_state.regs[cpu_reg].w); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x3A: /*CMP cpu_reg,8*/ + fetchea(); + temp = geteab(); + setsub8(getr8(cpu_reg), temp); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x3B: /*CMP cpu_reg,16*/ + fetchea(); + tempw = geteaw(); + setsub16(cpu_state.regs[cpu_reg].w, tempw); + cycles -= ((cpu_mod == 3 ) ? 3 : 13); + break; + + case 0x3C: /*CMP AL,#8*/ + temp = pfq_fetchb(); + setsub8(AL, temp); + cycles -= 4; + break; + + case 0x3D: /*CMP AX,#16*/ + tempw = pfq_fetchw(); + setsub16(AX, tempw); + cycles -= 4; + break; + + case 0x3F: /*AAS*/ + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) { + AL -= 6; + AH--; + flags |= (A_FLAG | C_FLAG); + } else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + cycles -= 8; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(cpu_state.regs[opcode & 7].w, 1); + cpu_state.regs[opcode & 7].w++; + cycles -= 3; + break; + + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(cpu_state.regs[opcode & 7].w, 1); + cpu_state.regs[opcode & 7].w--; + cycles -= 3; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + SP -= 2; + x86_push_ex(cpu_state.regs[opcode & 0x07].w); + cycles -= 15; + break; + + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + cpu_state.regs[opcode & 0x07].w = x86_pop(); + cycles -= 12; + break; + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + x86_jcc(opcode, flags & V_FLAG); + break; + + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + x86_jcc(opcode, flags & C_FLAG); + break; + + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + x86_jcc(opcode, flags & Z_FLAG); + break; + + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + x86_jcc(opcode, flags & (C_FLAG | Z_FLAG)); + break; + + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + x86_jcc(opcode, flags & N_FLAG); + break; + + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + x86_jcc(opcode, flags & P_FLAG); + break; + + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + temp = (flags & N_FLAG) ? 1 : 0; + temp2 = (flags & V_FLAG) ? 1 : 0; + x86_jcc(opcode, temp ^ temp2); + break; + + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + temp = (flags & N_FLAG) ? 1 : 0; + temp2 = (flags & V_FLAG) ? 1 : 0; + x86_jcc(opcode, (flags & Z_FLAG) || (temp != temp2)); + cycles -= 4; + break; + + case 0x80: case 0x82: + fetchea(); + temp = geteab(); + temp2 = pfq_fetchb(); + switch (rmdat & 0x38) { + case 0x00: /*ADD b,#8*/ + setadd8(temp, temp2); + seteab(temp + temp2); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x08: /*OR b,#8*/ + temp |= temp2; + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x10: /*ADC b,#8*/ + setadc8(temp, temp2); + seteab(temp + temp2 + tempc); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x18: /*SBB b,#8*/ + setsbc8(temp, temp2); + seteab(temp - (temp2 + tempc)); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x20: /*AND b,#8*/ + temp &= temp2; + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x28: /*SUB b,#8*/ + setsub8(temp, temp2); + seteab(temp - temp2); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x30: /*XOR b,#8*/ + temp ^= temp2; + setznp8(temp); + flags &= ~(C_FLAG | V_FLAG); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x38: /*CMP b,#8*/ + setsub8(temp, temp2); + cycles -= ((cpu_mod == 3) ? 4 : 14); + break; + } + break; + + case 0x81: + fetchea(); + tempw = geteaw(); + tempw2 = pfq_fetchw(); + switch (rmdat & 0x38) { + case 0x00: /*ADD w,#16*/ + setadd16(tempw, tempw2); + tempw += tempw2; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x08: /*OR w,#16*/ + tempw |= tempw2; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x10: /*ADC w,#16*/ + setadc16(tempw, tempw2); + tempw += tempw2 + tempc; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x20: /*AND w,#16*/ + tempw &= tempw2; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x18: /*SBB w,#16*/ + setsbc16(tempw, tempw2); + seteaw(tempw - (tempw2 + tempc)); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x28: /*SUB w,#16*/ + setsub16(tempw, tempw2); + tempw -= tempw2; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x30: /*XOR w,#16*/ + tempw ^= tempw2; + setznp16(tempw); + flags &= ~(C_FLAG | V_FLAG); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x38: /*CMP w,#16*/ + setsub16(tempw, tempw2); + cycles -= ((cpu_mod == 3) ? 4 : 14); + break; + } + break; + + case 0x83: + fetchea(); + tempw = geteaw(); + tempw2 = pfq_fetchb(); + if (tempw2 & 0x80) + tempw2 |= 0xFF00; + switch (rmdat & 0x38) { + case 0x00: /*ADD w,#8*/ + setadd16(tempw, tempw2); + tempw += tempw2; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x08: /*OR w,#8*/ + tempw |= tempw2; + setznp16(tempw); + seteaw(tempw); + flags &= ~(C_FLAG | A_FLAG | V_FLAG); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x10: /*ADC w,#8*/ + setadc16(tempw, tempw2); + tempw += tempw2 + tempc; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x18: /*SBB w,#8*/ + setsbc16(tempw, tempw2); + tempw -= (tempw2 + tempc); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x20: /*AND w,#8*/ + tempw &= tempw2; + setznp16(tempw); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + flags &= ~(C_FLAG | A_FLAG | V_FLAG); + break; + + case 0x28: /*SUB w,#8*/ + setsub16(tempw, tempw2); + tempw -= tempw2; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + break; + + case 0x30: /*XOR w,#8*/ + tempw ^= tempw2; + setznp16(tempw); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 23); + flags &= ~(C_FLAG | V_FLAG); + break; + + case 0x38: /*CMP w,#8*/ + setsub16(tempw, tempw2); + cycles -= ((cpu_mod == 3) ? 4 : 14); + break; + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp = geteab(); + temp2 = getr8(cpu_reg); + setznp8(temp & temp2); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw = geteaw(); + tempw2 = cpu_state.regs[cpu_reg].w; + setznp16(tempw & tempw2); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= ((cpu_mod == 3) ? 3 : 13); + break; + + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp = geteab(); + seteab(getr8(cpu_reg)); + setr8(cpu_reg, temp); + cycles -= ((cpu_mod == 3) ? 4 : 25); + break; + + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw = geteaw(); + seteaw(cpu_state.regs[cpu_reg].w); + cpu_state.regs[cpu_reg].w = tempw; + cycles -= ((cpu_mod == 3) ? 4 : 25); + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(cpu_reg)); + cycles -= ((cpu_mod == 3) ? 2 : 13); + break; + + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(cpu_state.regs[cpu_reg].w); + cycles -= ((cpu_mod == 3) ? 2 : 13); + break; + + case 0x8A: /*MOV cpu_reg,b*/ + fetchea(); + temp = geteab(); + setr8(cpu_reg, temp); + cycles -= ((cpu_mod == 3) ? 2 : 12); + break; + + case 0x8B: /*MOV cpu_reg,w*/ + fetchea(); + tempw = geteaw(); + cpu_state.regs[cpu_reg].w = tempw; + cycles -= ((cpu_mod == 3) ? 2 : 12); + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat & 0x38) { + case 0x00: /*ES*/ + seteaw(ES); + break; + + case 0x08: /*CS*/ + seteaw(CS); + break; + + case 0x18: /*DS*/ + seteaw(DS); + break; + + case 0x10: /*SS*/ + seteaw(SS); + break; + } + cycles -= ((cpu_mod == 3) ? 2 : 13); + break; + + case 0x8D: /*LEA*/ + fetchea(); + cpu_state.regs[cpu_reg].w = (cpu_mod == 3) ? cpu_state.last_ea : cpu_state.eaaddr; + cycles -= 2; + break; + + case 0x8E: /*MOV sreg,w*/ + fetchea(); + switch (rmdat & 0x38) { + case 0x00: /*ES*/ + tempw = geteaw(); + loadseg(tempw, &_es); + break; + + case 0x08: /*CS - 8088/8086 only*/ + tempw = geteaw(); + // loadseg(tempw, &_cs); + loadcs(tempw); + pfq_clear(); + break; + + case 0x18: /*DS*/ + tempw = geteaw(); + loadseg(tempw, &_ds); + break; + + case 0x10: /*SS*/ + tempw = geteaw(); + loadseg(tempw, &_ss); + break; + } + cycles -= ((cpu_mod == 3) ? 2 : 12); + noint = 1; + break; + + case 0x8F: /*POPW*/ + fetchea(); + tempw = x86_pop(); + seteaw(tempw); + cycles -= 25; + break; + + case 0x90: /*NOP*/ + cycles-=3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw = AX; + AX = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = tempw; + cycles -= 3; + break; + + case 0x98: /*CBW*/ + AH = (AL & 0x80) ? 0xFF : 0; + cycles -= 2; + break; + + case 0x99: /*CWD*/ + DX = (AX & 0x8000) ? 0xFFFF : 0; + cycles -= 5; + break; + + case 0x9A: /*CALL FAR*/ + tempw = pfq_fetchw(); + tempw2 = pfq_fetchw(); + x86_push(CS); + x86_push(cpu_state.pc); + cpu_state.pc = tempw; + loadcs(tempw2); + cycles -= 36; + pfq_clear(); + break; + + case 0x9B: /*WAIT*/ + cycles -= 4; + break; + + case 0x9C: /*PUSHF*/ + x86_push(flags | 0xF000); + cycles -= 14; + break; + + case 0x9D: /*POPF*/ + flags = x86_pop() & 0xFFF; + cycles -= 12; + break; + + case 0x9E: /*SAHF*/ + flags = (flags & 0xFF00) | AH; + cycles -= 4; + break; + + case 0x9F: /*LAHF*/ + AH = flags & 0xFF; + cycles -= 4; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr = pfq_fetchw(); + AL = readmemb((override_seg ? *override_seg : ds) + addr); + cycles -= 14; + break; + + case 0xA1: /*MOV AX,(w)*/ + addr = pfq_fetchw(); + AX = readmemw((override_seg ? *override_seg : ds), addr); + cycles-=14; + break; + + case 0xA2: /*MOV (w),AL*/ + addr = pfq_fetchw(); + writememb((override_seg ? *override_seg : ds) + addr, AL); + cycles -= 14; + break; + + case 0xA3: /*MOV (w),AX*/ + addr = pfq_fetchw(); + writememw((override_seg ? *override_seg : ds), addr, AX); + cycles -= 14; + break; + + case 0xA4: /*MOVSB*/ + case 0xA5: /*MOVSW*/ + case 0xA6: /*CMPSB*/ + case 0xA7: /*CMPSW*/ + case 0xAA: /*STOSB*/ + case 0xAB: /*STOSW*/ + case 0xAC: /*LODSB*/ + case 0xAD: /*LODSW*/ + case 0xAE: /*SCASB*/ + case 0xAF: /*SCASW*/ + x86_string(opcode, 0); + break; + + case 0xA8: /*TEST AL,#8*/ + temp = pfq_fetchb(); + setznp8(AL & temp); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= 5; + break; + + case 0xA9: /*TEST AX,#16*/ + tempw = pfq_fetchw(); + setznp16(AX & tempw); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= 5; + break; + + case 0xB0: case 0xB1: case 0xB2: case 0xB3: /*MOV cpu_reg,#8*/ + case 0xB4: case 0xB5: case 0xB6: case 0xB7: + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + cycles -= 4; + break; + + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV cpu_reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + cycles -= 4; + break; + + case 0xC0: case 0xC2: /* RET - C0 is alias */ + tempw = pfq_fetchw(); + cpu_state.pc = x86_pop(); + SP += tempw; + cycles -= 24; + pfq_clear(); + break; + + case 0xC1: case 0xC3: /* RET - C1 is alias */ + cpu_state.pc = x86_pop(); + cycles -= 20; + pfq_clear(); + break; + + case 0xC4: /*LES*/ + case 0xC5: /*LDS*/ + fetchea(); + cpu_state.regs[cpu_reg].w = readmemw(easeg, cpu_state.eaaddr); + tempw = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xFFFF); + loadseg(tempw, (opcode & 0x01) ? &_ds : &_es); + cycles -= 24; + noint = 1; + break; + + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp = pfq_fetchb(); + seteab(temp); + cycles -= ((cpu_mod == 3) ? 4 : 14); + break; + + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw = pfq_fetchw(); + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 4 : 14); + break; + + case 0xC8: case 0xCA: /* RETF - C8 is alias */ + tempw = pfq_fetchw(); + cpu_state.pc = x86_pop(); + loadcs(x86_pop()); + SP += tempw; + cycles -= 33; + pfq_clear(); + break; + + case 0xC9: case 0xCB: /* RETF - C9 is alias */ + cpu_state.pc = x86_pop(); + loadcs(x86_pop()); + cycles -= 34; + pfq_clear(); + break; + + case 0xCC: /*INT 3*/ + x86_int(3, 1); + cycles -= 72; + break; + + case 0xCD: /*INT*/ + temp = pfq_fetchb(); + x86_int(temp, 0); + cycles -= 71; + break; + + case 0xCE: /*INTO*/ + if (flags & V_FLAG) + x86_int(4, 1); + cycles -= 3; + break; + + case 0xCF: /*IRET*/ + tempw = CS; + tempw2 = cpu_state.pc; + cpu_state.pc = x86_pop(); + loadcs(x86_pop()); + flags = x86_pop() & 0xFFF; + cycles -= 44; + noint = 1; + nmi_enable = 1; + pfq_clear(); + break; + + case 0xD0: + fetchea(); + temp = geteab(); + switch (rmdat & 0x38) { + case 0x00: /*ROL b,1*/ + case 0x08: /*ROR b,1*/ + case 0x10: /*RCL b,1*/ + case 0x18: /*RCR b,1*/ + x86_rotate8(&temp, 1); + cycles -= ((cpu_mod == 3) ? 2 : 23); + break; + + case 0x20: case 0x30: /*SHL b,1*/ + case 0x28: /*SHR b,1*/ + case 0x38: /*SAR b,1*/ + x86_shift8(&temp, 1); + cycles -= ((cpu_mod == 3) ? 2 : 23); + break; + } + break; + + case 0xD1: + fetchea(); + tempw = geteaw(); + switch (rmdat & 0x38) { + case 0x00: /*ROL w,1*/ + case 0x08: /*ROR w,1*/ + case 0x10: /*RCL w,1*/ + case 0x18: /*RCR w,1*/ + x86_rotate16(&tempw, 1); + cycles -= ((cpu_mod == 3) ? 2 : 23); + break; + + case 0x20: case 0x30: /*SHL w,1*/ + case 0x28: /*SHR w,1*/ + case 0x38: /*SAR b,1*/ + x86_shift16(&tempw, 1); + cycles -= ((cpu_mod == 3) ? 2 : 23); + break; + } + break; + + case 0xD2: + fetchea(); + temp = geteab(); + c = CL; + if (!c) + break; + switch (rmdat & 0x38) { + case 0x00: /*ROL b,CL*/ + case 0x08: /*ROR b,CL*/ + case 0x10: /*RCL b,CL*/ + case 0x18: /*RCR b,CL*/ + x86_rotate8(&temp, c); + cycles -= ((cpu_mod == 3) ? 8 : 28); + break; + + case 0x20: case 0x30: /*SHL b,CL*/ + case 0x28: /*SHR b,CL*/ + case 0x38: /*SAR b,CL*/ + x86_shift8(&temp, c); + cycles -= ((cpu_mod == 3) ? 8 : 28); + break; + } + break; + + case 0xD3: + fetchea(); + tempw = geteaw(); + c = CL; + if (!c) + break; + switch (rmdat & 0x38) { + case 0x00: /*ROL w,CL*/ + case 0x08: /*ROR w,CL*/ + case 0x10: /*RCL w,CL*/ + case 0x18: /*RCR w,CL*/ + x86_rotate16(&tempw, c); + cycles -= ((cpu_mod == 3) ? 8 : 28); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + case 0x28: /*SHR w,CL*/ + case 0x38: /*SAR w,CL*/ + x86_shift16(&tempw, c); + cycles -= ((cpu_mod == 3) ? 8 : 28); + break; + } + break; + + case 0xD4: /*AAM*/ + tempws = pfq_fetchb(); + AH = AL / tempws; + AL %= tempws; + setznp16(AX); + cycles -= 83; + break; + + case 0xD5: /*AAD*/ + tempws = pfq_fetchb(); + AL = (AH * tempws) + AL; + AH = 0; + setznp16(AX); + cycles -= 60; + break; + + case 0xD6: /*SETALC*/ + AL = (flags & C_FLAG) ? 0xff : 0; + cycles -= 4; + break; + + case 0xD7: /*XLAT*/ + addr = BX + AL; + cpu_state.last_ea = addr; + AL = readmemb((override_seg ? *override_seg : ds) + addr); + cycles -= 11; + break; + + case 0xD8: case 0xD9: case 0xDA: case 0xDB: /*ESCAPE*/ + case 0xDD: case 0xDC: case 0xDE: case 0xDF: + fetchea(); + geteab(); + break; + + case 0xE0: /*LOOPNE*/ + offset = (int8_t) pfq_fetchb(); + CX--; + if (CX && !(flags & Z_FLAG)) { + cpu_state.pc += offset; + cycles -= 12; + pfq_clear(); + } + cycles -= 6; + break; + + case 0xE1: /*LOOPE*/ + offset = (int8_t) pfq_fetchb(); + CX--; + if (CX && (flags & Z_FLAG)) { + cpu_state.pc += offset; + cycles -= 12; + pfq_clear(); + } + cycles -= 6; + break; + + case 0xE2: /*LOOP*/ + offset = (int8_t) pfq_fetchb(); + CX--; + if (CX) { + cpu_state.pc += offset; + cycles -= 12; + pfq_clear(); + } + cycles -= 5; + break; + + case 0xE3: /*JCXZ*/ + x86_jcc(opcode, CX); + cycles -= 2; + break; + + case 0xE4: /*IN AL*/ + temp = pfq_fetchb(); + AL = inb(temp); + cycles -= 14; + break; + + case 0xE5: /*IN AX*/ + temp = pfq_fetchb(); + AL = inb(temp); + AH = inb(temp + 1); + cycles -= 14; + break; + + case 0xE6: /*OUT AL*/ + temp = pfq_fetchb(); + outb(temp, AL); + cycles -= 14; + break; + + case 0xE7: /*OUT AX*/ + temp = pfq_fetchb(); + outb(temp, AL); + outb(temp + 1, AH); + cycles -= 14; + break; + + case 0xE8: /*CALL rel 16*/ + tempw = pfq_fetchw(); + x86_push(cpu_state.pc); + cpu_state.pc += tempw; + cycles -= 23; + pfq_clear(); + break; + + case 0xE9: /*JMP rel 16*/ + tempw = pfq_fetchw(); + cpu_state.pc += tempw; + cycles -= 15; + pfq_clear(); + break; + + case 0xEA: /*JMP far*/ + addr = pfq_fetchw(); + tempw = pfq_fetchw(); + cpu_state.pc = addr; + loadcs(tempw); + cycles -= 15; + pfq_clear(); + break; + + case 0xEB: /*JMP rel*/ + offset = (int8_t) pfq_fetchb(); + cpu_state.pc += offset; + cycles -= 15; + pfq_clear(); + break; + + case 0xEC: /*IN AL,DX*/ + AL = inb(DX); + cycles -= 12; + break; + + case 0xED: /*IN AX,DX*/ + AL = inb(DX); + AH = inb(DX + 1); + cycles -= 12; + break; + + case 0xEE: /*OUT DX,AL*/ + outb(DX, AL); + cycles -= 12; + break; + + case 0xEF: /*OUT DX,AX*/ + outb(DX, AL); + outb(DX+1, AH); + cycles -= 12; + break; + + case 0xF0: case 0xF1: /*LOCK - F1 is alias*/ + cycles -= 4; + in_lock = 1; + break; + + case 0xF2: /*REPNE*/ + case 0xF3: /*REPE*/ + x86_rep(opcode & 0x01); + break; + + case 0xF4: /*HLT*/ + halt = 1; + pfq_clear(); + cycles -= 2; + break; + + case 0xF5: /*CMC*/ + flags ^= C_FLAG; + cycles -= 2; + break; + + case 0xF6: + fetchea(); + temp = geteab(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: /*TEST b,#8*/ + temp2 = pfq_fetchb(); + temp &= temp2; + setznp8(temp); + flags &= ~(C_FLAG|V_FLAG|A_FLAG); + cycles -= ((cpu_mod==3)?5:11); + break; + + case 0x10: /*NOT b*/ + temp = ~temp; + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 :24); + break; + + case 0x18: /*NEG b*/ + setsub8(0, temp); + temp = 0 - temp; + seteab(temp); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x20: /*MUL AL,b*/ + setznp8(AL); + AX = AL * temp; + if (AX) + flags &= ~Z_FLAG; + else + flags |= Z_FLAG; + if (AH) + flags |= (C_FLAG | V_FLAG); + else + flags &= ~(C_FLAG | V_FLAG); + cycles-=70; + break; + + case 0x28: /*IMUL AL,b*/ + setznp8(AL); + tempws = (int) ((int8_t) AL) * (int) ((int8_t) temp); + AX = tempws & 0xFFFF; + if (AX) + flags &= ~Z_FLAG; + else + flags |= Z_FLAG; + if (AH) + flags |= (C_FLAG | V_FLAG); + else + flags &= ~(C_FLAG | V_FLAG); + cycles -= 80; + break; + + case 0x30: /*DIV AL,b*/ + tempw = AX; + if (temp) { + tempw2 = tempw % temp; + AH = tempw2 & 0xff; + tempw /= temp; + AL = tempw & 0xFF; + } else { + INFO("DIVb BY 0 %04X:%04X\n", cs >> 4, cpu_state.pc); + x86_int(0, 1); + } + cycles-=80; + break; + + case 0x38: /*IDIV AL,b*/ + tempws = (int) AX; + if (temp) { + tempw2 = tempws % (int) ((int8_t) temp); + AH = tempw2 & 0xFF; + tempws /= (int) ((int8_t) temp); + AL = tempws & 0xFF; + } else { + INFO("IDIVb BY 0 %04X:%04X\n", cs >> 4, cpu_state.pc); + x86_int(0, 1); + } + cycles -= 101; + break; + } + break; + + case 0xF7: + fetchea(); + tempw = geteaw(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: /*TEST w*/ + tempw2 = pfq_fetchw(); + setznp16(tempw & tempw2); + flags &= ~(C_FLAG | V_FLAG | A_FLAG); + cycles -= ((cpu_mod == 3) ? 5 : 11); + break; + + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x18: /*NEG w*/ + setsub16(0, tempw); + tempw = 0 - tempw; + seteaw(tempw); + cycles -= ((cpu_mod == 3) ? 3 : 24); + break; + + case 0x20: /*MUL AX,w*/ + setznp16(AX); + templ = AX * tempw; + AX = templ & 0xFFFF; + DX = templ >> 16; + if (AX | DX) + flags &= ~Z_FLAG; + else + flags |= Z_FLAG; + if (DX) + flags |= (C_FLAG | V_FLAG); + else + flags &= ~(C_FLAG|V_FLAG); + cycles -= 118; + break; + + case 0x28: /*IMUL AX,w*/ + setznp16(AX); + tempws = (int) ((int16_t) AX) * (int) ((int16_t) tempw); + if ((tempws >> 15) && ((tempws >> 15) != -1)) + flags |= (C_FLAG | V_FLAG); + else + flags &= ~(C_FLAG | V_FLAG); + AX = tempws & 0xFFFF; + tempws = (uint16_t) (tempws >> 16); + DX = tempws & 0xFFFF; + if (AX | DX) + flags &= ~Z_FLAG; + else + flags |= Z_FLAG; + cycles -= 128; + break; + + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (tempw) { + tempw2 = templ % tempw; + DX = tempw2; + templ /= tempw; + AX = templ & 0xFFFF; + } else { + INFO("DIVw BY 0 %04X:%04X\n", cs >> 4, cpu_state.pc); + x86_int(0, 1); + } + cycles -= 144; + break; + + case 0x38: /*IDIV AX,w*/ + tempws = (int) ((DX << 16) | AX); + if (tempw) { + tempw2 = tempws % (int) ((int16_t) tempw); + DX = tempw2; + tempws /= (int) ((int16_t) tempw); + AX = tempws & 0xFFFF; + } else { + INFO("IDIVw BY 0 %04X:%04X\n", cs >> 4, cpu_state.pc); + x86_int(0, 1); + } + cycles -= 165; + break; + } + break; + + case 0xF8: /*CLC*/ + flags &= ~C_FLAG; + cycles -= 2; + break; + + case 0xF9: /*STC*/ + flags |= C_FLAG; + cycles -= 2; + break; + + case 0xFA: /*CLI*/ + flags &= ~I_FLAG; + cycles -= 3; + break; + + case 0xFB: /*STI*/ + flags |= I_FLAG; + cycles -= 2; + break; + + case 0xFC: /*CLD*/ + flags &= ~D_FLAG; + cycles -= 2; + break; + + case 0xFD: /*STD*/ + flags |= D_FLAG; + cycles -= 2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp = geteab(); + flags &= ~V_FLAG; + if (rmdat & 0x38) { + setsub8nc(temp, 1); + temp2 = temp - 1; + if ((temp & 0x80) && !(temp2 & 0x80)) + flags |= V_FLAG; + } else { + setadd8nc(temp, 1); + temp2 = temp + 1; + if ((temp2 & 0x80) && !(temp & 0x80)) + flags |= V_FLAG; + } + seteab(temp2); + cycles -= ((cpu_mod == 3) ? 3 : 23); + break; + + case 0xFF: + fetchea(); + switch (rmdat & 0x38) { + case 0x00: /*INC w*/ + tempw = geteaw(); + setadd16nc(tempw, 1); + seteaw(tempw + 1); + cycles -= ((cpu_mod == 3) ? 3 : 23); + break; + + case 0x08: /*DEC w*/ + tempw = geteaw(); + setsub16nc(tempw, 1); + seteaw(tempw - 1); + cycles -= ((cpu_mod == 3) ? 3 : 23); + break; + + case 0x10: /*CALL*/ + tempw = geteaw(); + x86_push(cpu_state.pc); + cpu_state.pc = tempw; + cycles -= ((cpu_mod == 3) ? 20 : 29); + pfq_clear(); + break; + + case 0x18: /*CALL far*/ + tempw = readmemw(easeg, cpu_state.eaaddr); + tempw2 = readmemw(easeg, (cpu_state.eaaddr + 2) & 0xFFFF); + x86_push(CS); + x86_push(cpu_state.pc); + cpu_state.pc = tempw; + loadcs(tempw2); + cycles -= 53; + pfq_clear(); + break; + + case 0x20: /*JMP*/ + cpu_state.pc = geteaw(); + cycles -= ((cpu_mod == 3) ? 11 : 18); + pfq_clear(); + break; + + case 0x28: /*JMP far*/ + cpu_state.pc = readmemw(easeg, cpu_state.eaaddr); + loadcs(readmemw(easeg, (cpu_state.eaaddr + 2) & 0xFFFF)); + cycles -= 24; + pfq_clear(); + break; + + case 0x30: case 0x38: /*PUSH w - 0x38 is alias*/ + SP -= 2; + tempw = geteaw(); + x86_push_ex(tempw); + cycles -= ((cpu_mod == 3) ? 15 : 24); + break; + } + break; + + default: + INFO("CPU: Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + cycles -= 8; + break; + } + + cpu_state.pc &= 0xFFFF; + + x86_post_process_main(); + } +} diff --git a/src/devices/printer/prt_escp.c b/src/devices/printer/prt_escp.c index 5521463..186100a 100644 --- a/src/devices/printer/prt_escp.c +++ b/src/devices/printer/prt_escp.c @@ -8,7 +8,7 @@ * * Implementation of the Generic ESC/P Dot-Matrix printer. * - * Version: @(#)prt_escp.c 1.0.6 2019/01/11 + * Version: @(#)prt_escp.c 1.0.7 2019/02/10 * * Authors: Michael Drüing, * Fred N. van Kempen, @@ -607,7 +607,8 @@ printer_reset(escp_t *dev) dev->dpi = PAGE_DPI; dev->autofeed = 0; - dev->esc_seen = dev->esc_pending = dev->fss_seen = 0; + dev->esc_seen = dev->fss_seen = 0; + dev->esc_pending = 0; dev->esc_parms_req = dev->esc_parms_curr = 0; dev->hmi = -1;