diff --git a/src/808x_tmp.txt b/src/808x_tmp.txt deleted file mode 100644 index 249bf9282..000000000 --- a/src/808x_tmp.txt +++ /dev/null @@ -1,3613 +0,0 @@ -/* - * 86Box A hypervisor and IBM PC system emulator that specializes in - * running old operating systems and software designed for IBM - * PC systems and compatibles from 1981 through fairly recent - * system designs based on the PCI bus. - * - * This file is part of the 86Box distribution. - * - * 808x CPU emulation, mostly ported from reenigne's XTCE, which - * is cycle-accurate. - * - * Authors: Andrew Jenner, - * Miran Grca, - * - * Copyright 2015-2020 Andrew Jenner. - * Copyright 2016-2020 Miran Grca. - */ -#include -#include -#include -#include -#include -#include - -#define HAVE_STDARG_H -#include <86box/86box.h> -#include "cpu.h" -#include "x86.h" -#include <86box/machine.h> -#include <86box/io.h> -#include <86box/mem.h> -#include <86box/rom.h> -#include <86box/nmi.h> -#include <86box/pic.h> -#include <86box/ppi.h> -#include <86box/timer.h> -#include <86box/gdbstub.h> -#include <86box/plat_fallthrough.h> -#include <86box/plat_unused.h> -#include "808x_biu.h" - -#define do_cycle() wait(1, 0) -#define do_cycle_i() do_cycle() -#define do_cycles(c) wait(c, 0) -#define do_cycles_i(c) do_cycles(c) -#define do_cycle_nx() nx = 1; \ - do_cycle() -#define do_cycle_nx_i() nx = 1; \ - do_cycle_i() -#define do_cycles_nx(c) nx = 1; \ - do_cycles(c) -#define do_cycles_nx_i(c) nx = 1; \ - do_cycles_i(c) -#define addr_mode_match() cpu_mod == 3 -#define math_op(o) cpu_alu_op = o; \ - alu_op(bits) - -/* Various things needed for 8087. */ -#define OP_TABLE(name) ops_##name - -#define CPU_BLOCK_END() -#define SEG_CHECK_READ(seg) -#define SEG_CHECK_WRITE(seg) -#define CHECK_READ(a, b, c) -#define CHECK_WRITE(a, b, c) -#define UN_USED(x) (void) (x) -#define fetch_ea_16(val) -#define fetch_ea_32(val) -#define PREFETCH_RUN(a, b, c, d, e, f, g, h) - -#define CYCLES(val) \ - { \ - wait(val, 0); \ - } - -#define CLOCK_CYCLES_ALWAYS(val) \ - { \ - wait(val, 0); \ - } - -#define CLOCK_CYCLES_FPU(val) \ - { \ - wait(val, 0); \ - } - -# define CLOCK_CYCLES(val) \ - { \ - if (fpu_cycles > 0) { \ - fpu_cycles -= (val); \ - if (fpu_cycles < 0) { \ - wait(val, 0); \ - } \ - } else { \ - wait(val, 0); \ - } \ - } - -#define CONCURRENCY_CYCLES(c) fpu_cycles = (c) - -typedef int (*OpFn)(uint32_t fetchdat); - -/* Is the CPU 8088 or 8086. */ -uint8_t use_custom_nmi_vector = 0; - -int is8086 = 0; - -static uint16_t last_addr = 0x0000; -static uint16_t mem_data = 0; -static uint16_t mem_addr = 0; - -static int oldc; -static int cycdiff; -static int pfq_size; -static int cpu_alu_op; -static int prefetching = 1; -static int completed = 1; -static int in_rep = 0; -static int repeating = 0; -static int rep_c_flag = 0; -static int clear_lock = 0; -static int refresh = 0; -static int pic_data = -1; -static int nx = 0; -static int noint = 0; -static int in_lock = 0; - -static uint32_t custom_nmi_vector = 0x00000000; -static uint32_t cpu_src = 0; -static uint32_t cpu_dest = 0; -static uint32_t cpu_data = 0; -static uint32_t mem_seg = 0; - -static uint32_t * ovr_seg = NULL; - -/* Pointer tables needed for segment overrides. */ -static uint32_t * opseg[4]; - -static x86seg * _opseg[4]; - -static void set_pzs(int bits); - -void -resub_cycles(int old_cycles) -{ - int cyc_diff = 0; - - if (old_cycles > cycles) { - cyc_diff = old_cycles - cycles; - - for (int i = 0; i < cyc_diff; i++) { - if (not_ready > 0) - not_ready--; - } - } - - process_timers(); -} - -/* This is for external subtraction of cycles, ie. wait states. */ -void -sub_cycles(int c) -{ - if (is286) - cycles -= c; - else { - if (c > 0) - cycles_idle(c); - } -} - -uint16_t -get_last_addr(void) -{ - return last_addr; -} - -static void -clock_start(void) -{ - cycdiff = cycles; -} - -static void -clock_end(void) -{ - int diff = cycdiff - cycles; - - /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ - tsc += ((uint64_t) diff * (xt_cpu_multi >> 32ULL)); /* Shift xt_cpu_multi by 32 bits to - the right and then multiply. */ - if (TIMER_VAL_LESS_THAN_VAL(timer_target, (uint32_t) tsc)) - timer_process(); -} - -static void -process_timers(void) -{ - clock_end(); - clock_start(); -} - -static void -cycles_forward(int c) -{ - cycles -= c; - - if (!is286) - process_timers(); -} - -static void -startx86(void) -{ - /* Reset takes 6 cycles before first fetch. */ - do_cycle(); - pfq_do_suspend(); - do_cycles_i(2); - pfq_clear(); - do_cycles_i(3); - set_ip(cpu_state.pc & 0xffff); -} - -static void -load_cs(uint16_t seg) -{ - // pclog("CS = %04X\n", seg); - cpu_state.seg_cs.base = seg << 4; - cpu_state.seg_cs.seg = seg & 0xffff; -} - -static void -load_seg(uint16_t seg, x86seg *s) -{ - s->base = seg << 4; - s->seg = seg & 0xffff; -} - -void -reset_808x(int hard) -{ - BUS_CYCLE_T1; - in_rep = 0; - in_lock = 0; - completed = 1; - repeating = 0; - clear_lock = 0; - refresh = 0; - ovr_seg = NULL; - - if (hard) { - opseg[0] = &es; - opseg[1] = &cs; - opseg[2] = &ss; - opseg[3] = &ds; - _opseg[0] = &cpu_state.seg_es; - _opseg[1] = &cpu_state.seg_cs; - _opseg[2] = &cpu_state.seg_ss; - _opseg[3] = &cpu_state.seg_ds; - - pfq_size = is8086 ? 6 : 4; - pfq_clear(); - } - - load_cs(0xFFFF); - cpu_state.pc = 0; - if (is_nec) - cpu_state.flags |= MD_FLAG; - rammask = 0xfffff; - - pasv = 0; - - cpu_alu_op = 0; - - use_custom_nmi_vector = 0x00; - custom_nmi_vector = 0x00000000; - - access_code = 0; - hlda = 0; - not_ready = 0; - bus_request_type = 0; - pic_data = -1; - last_was_code = 0; - mem_data = 0; - mem_seg = 0; - mem_addr = 0; - - prefetching = 1; - pfq_schedule(1); - if (CS == DEBUG_SEG) - pclog("reset_808x(): pfq_schedule(1, %i, %i): Fetch is now %sscheduled\n", prefetching, (pfq_pos < pfq_size), schedule_fetch ? "" : "not "); -} - -static void -set_ip(uint16_t new_ip) -{ - pfq_ip = cpu_state.pc = new_ip; - prefetching = 1; - pfq_schedule(1); - if (CS == DEBUG_SEG) - pclog("set_ip(): pfq_schedule(1, %i, %i): Fetch is now %sscheduled\n", prefetching, (pfq_pos < pfq_size), schedule_fetch ? "" : "not "); -} - -/* Memory refresh read - called by reads and writes on DMA channel 0. */ -void -refreshread(void) -{ - refresh++; -} - -static uint16_t -get_accum(int bits) -{ - return (bits == 16) ? AX : AL; -} - -static void -set_accum(int bits, uint16_t val) -{ - if (bits == 16) - AX = val; - else - AL = val; -} - -static uint16_t -sign_extend(uint8_t data) -{ - return data + (data < 0x80 ? 0 : 0xff00); -} - -/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ -static void -do_mod_rm(void) -{ - rmdat = pfq_fetchb(); - cpu_reg = (rmdat >> 3) & 7; - cpu_mod = (rmdat >> 6) & 3; - cpu_rm = rmdat & 7; - - if (cpu_mod == 3) - return; - - wait(2, 0); - if ((rmdat & 0xc7) == 0x06) { - cpu_state.eaaddr = pfq_fetchw(); - easeg = ovr_seg ? *ovr_seg : ds; - wait(2, 0); - return; - } else - switch (cpu_rm) { - case 0: - case 3: - wait(2, 0); - break; - case 1: - case 2: - wait(3, 0); - break; - - default: - break; - } - cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); - easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; - switch (rmdat & 0xc0) { - case 0x40: - wait(2, 0); - cpu_state.eaaddr += sign_extend(pfq_fetchb()); - wait(1, 0); - break; - case 0x80: - wait(2, 0); - cpu_state.eaaddr += pfq_fetchw(); - wait(1, 0); - break; - default: - break; - } - cpu_state.eaaddr &= 0xffff; - wait(2, 0); -} - -#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; - -/* Reads a byte from the effective address. */ -static uint8_t -geteab(void) -{ - if (cpu_mod == 3) - return (getr8(cpu_rm)); - - 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); -} - -/* Neede for 8087 - memory only. */ -static uint32_t -geteal(void) -{ - if (cpu_mod == 3) { - fatal("808x register geteal()\n"); - return 0xffffffff; - } - - return readmeml(easeg, cpu_state.eaaddr); -} - -/* Neede for 8087 - memory only. */ -static uint64_t -geteaq(void) -{ - if (cpu_mod == 3) { - fatal("808x register geteaq()\n"); - return 0xffffffff; - } - - return readmemq(easeg, cpu_state.eaaddr); -} - -static void -read_ea(int memory_only, int bits) -{ - if (cpu_mod != 3) { - if (bits == 16) - cpu_data = readmemw(easeg, cpu_state.eaaddr); - else - cpu_data = readmemb(easeg, cpu_state.eaaddr); - return; - } - if (!memory_only) { - if (bits == 8) { - cpu_data = getr8(cpu_rm); - } else - cpu_data = cpu_state.regs[cpu_rm].w; - } -} - -static void -read_ea_8to16(void) -{ - cpu_data = cpu_state.regs[cpu_rm & 3].w; -} - -static void -read_ea2(int bits) -{ - cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; - if (bits == 16) - cpu_data = readmemw(easeg, cpu_state.eaaddr); - else - cpu_data = readmemb(easeg, cpu_state.eaaddr); -} - -/* Writes a byte to the effective address. */ -static void -seteab(uint8_t val) -{ - if (cpu_mod == 3) { - setr8(cpu_rm, val); - } else { - wait(1, 0); - 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 { - wait(1, 0); - writememw(easeg, cpu_state.eaaddr, val); - } -} - -static void -seteal(uint32_t val) -{ - if (cpu_mod == 3) { - fatal("808x register seteal()\n"); - return; - } else - writememl(easeg, cpu_state.eaaddr, val); -} - -static void -seteaq(uint64_t val) -{ - if (cpu_mod == 3) { - fatal("808x register seteaq()\n"); - return; - } else - writememq(easeg, cpu_state.eaaddr, val); -} - -/* Leave out the 686 stuff as it's not needed and - complicates compiling. */ -#define FPU_8087 -#define tempc tempc_fpu -#include "x87.h" -#include "x87_ops.h" -#undef tempc -#undef FPU_8087 - -/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ -static void -do_mod_rm(void) -{ - rmdat = pfq_fetchb(); - cpu_reg = (rmdat >> 3) & 7; - cpu_mod = (rmdat >> 6) & 3; - cpu_rm = rmdat & 7; - - if (cpu_mod == 3) - return; - - wait(2, 0); - if ((rmdat & 0xc7) == 0x06) { - cpu_state.eaaddr = pfq_fetchw(); - easeg = ovr_seg ? *ovr_seg : ds; - wait(2, 0); - return; - } else - switch (cpu_rm) { - case 0: - case 3: - wait(2, 0); - break; - case 1: - case 2: - wait(3, 0); - break; - - default: - break; - } - cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); - easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; - switch (rmdat & 0xc0) { - case 0x40: - wait(2, 0); - cpu_state.eaaddr += sign_extend(pfq_fetchb()); - wait(1, 0); - break; - case 0x80: - wait(2, 0); - cpu_state.eaaddr += pfq_fetchw(); - wait(1, 0); - break; - default: - break; - } - cpu_state.eaaddr &= 0xffff; - wait(2, 0); -} - -static void -set_cf(int cond) -{ - cpu_state.flags = (cpu_state.flags & ~C_FLAG) | (cond ? C_FLAG : 0); -} - -static void -set_if(int cond) -{ - cpu_state.flags = (cpu_state.flags & ~I_FLAG) | (cond ? I_FLAG : 0); -} - -static void -set_df(int cond) -{ - cpu_state.flags = (cpu_state.flags & ~D_FLAG) | (cond ? D_FLAG : 0); -} - -static void -bitwise(int bits, uint16_t data) -{ - cpu_data = data; - cpu_state.flags &= ~(C_FLAG | A_FLAG | V_FLAG); - set_pzs(bits); -} - -static void -test(int bits, uint16_t dest, uint16_t src) -{ - cpu_dest = dest; - cpu_src = src; - bitwise(bits, (cpu_dest & cpu_src)); -} - -static void -set_of(int of) -{ - cpu_state.flags = (cpu_state.flags & ~0x800) | (of ? 0x800 : 0); -} - -static int -top_bit(uint16_t w, int bits) -{ - return (w & (1 << (bits - 1))); -} - -static void -set_of_add(int bits) -{ - set_of(top_bit((cpu_data ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); -} - -static void -set_of_sub(int bits) -{ - set_of(top_bit((cpu_dest ^ cpu_src) & (cpu_data ^ cpu_dest), bits)); -} - -static void -set_af(int af) -{ - cpu_state.flags = (cpu_state.flags & ~0x10) | (af ? 0x10 : 0); -} - -static void -do_af(void) -{ - set_af(((cpu_data ^ cpu_src ^ cpu_dest) & 0x10) != 0); -} - -static void -set_apzs(int bits) -{ - set_pzs(bits); - do_af(); -} - -static void -add(int bits) -{ - int size_mask = (1 << bits) - 1; - - cpu_data = cpu_dest + cpu_src; - set_apzs(bits); - set_of_add(bits); - - /* Anything - FF with carry on is basically anything + 0x100: value stays - unchanged but carry goes on. */ - if ((cpu_alu_op == 2) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) - cpu_state.flags |= C_FLAG; - else - set_cf((cpu_src & size_mask) > (cpu_data & size_mask)); -} - -static void -sub(int bits) -{ - int size_mask = (1 << bits) - 1; - - cpu_data = cpu_dest - cpu_src; - set_apzs(bits); - set_of_sub(bits); - - /* Anything - FF with carry on is basically anything - 0x100: value stays - unchanged but carry goes on. */ - if ((cpu_alu_op == 3) && !(cpu_src & size_mask) && (cpu_state.flags & C_FLAG)) - cpu_state.flags |= C_FLAG; - else - set_cf((cpu_src & size_mask) > (cpu_dest & size_mask)); -} - -static void -alu_op(int bits) -{ - switch (cpu_alu_op) { - case 1: - bitwise(bits, (cpu_dest | cpu_src)); - break; - case 2: - if (cpu_state.flags & C_FLAG) - cpu_src++; - fallthrough; - case 0: - add(bits); - break; - case 3: - if (cpu_state.flags & C_FLAG) - cpu_src++; - fallthrough; - case 5: - case 7: - sub(bits); - break; - case 4: - test(bits, cpu_dest, cpu_src); - break; - case 6: - bitwise(bits, (cpu_dest ^ cpu_src)); - break; - - default: - break; - } -} - -static void -set_sf(int bits) -{ - cpu_state.flags = (cpu_state.flags & ~0x80) | (top_bit(cpu_data, bits) ? 0x80 : 0); -} - -static void -set_pf(void) -{ - cpu_state.flags = (cpu_state.flags & ~4) | (!__builtin_parity(cpu_data & 0xFF) << 2); -} - -static void -mul(uint16_t a, uint16_t b) -{ - int negate = 0; - int bit_count = 8; - int carry; - uint16_t high_bit = 0x80; - uint16_t size_mask; - uint16_t c; - uint16_t r; - - size_mask = (1 << bit_count) - 1; - - if (opcode != 0xd5) { - if (opcode & 1) { - bit_count = 16; - high_bit = 0x8000; - } else - wait(8, 0); - - size_mask = (1 << bit_count) - 1; - - if ((rmdat & 0x38) == 0x28) { - if (!top_bit(a, bit_count)) { - if (top_bit(b, bit_count)) { - wait(1, 0); - if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) - wait(1, 0); - b = ~b + 1; - negate = 1; - } - } else { - wait(1, 0); - a = ~a + 1; - negate = 1; - if (top_bit(b, bit_count)) { - b = ~b + 1; - negate = 0; - } else - wait(4, 0); - } - wait(10, 0); - } - wait(3, 0); - } - - c = 0; - a &= size_mask; - carry = (a & 1) != 0; - a >>= 1; - for (int i = 0; i < bit_count; ++i) { - wait(7, 0); - if (carry) { - cpu_src = c; - cpu_dest = b; - add(bit_count); - c = cpu_data & size_mask; - wait(1, 0); - carry = !!(cpu_state.flags & C_FLAG); - } - r = (c >> 1) + (carry ? high_bit : 0); - carry = (c & 1) != 0; - c = r; - r = (a >> 1) + (carry ? high_bit : 0); - carry = (a & 1) != 0; - a = r; - } - if (negate) { - c = ~c; - a = (~a + 1) & size_mask; - if (a == 0) - ++c; - wait(9, 0); - } - cpu_data = a; - cpu_dest = c; - - set_sf(bit_count); - set_pf(); - set_af(0); -} - -static void -set_of_rotate(int bits) -{ - set_of(top_bit(cpu_data ^ cpu_dest, bits)); -} - -static void -set_zf_ex(int zf) -{ - cpu_state.flags = (cpu_state.flags & ~0x40) | (zf ? 0x40 : 0); -} - -static void -set_zf(int bits) -{ - int size_mask = (1 << bits) - 1; - - set_zf_ex((cpu_data & size_mask) == 0); -} - -static void -set_pzs(int bits) -{ - set_pf(); - set_zf(bits); - set_sf(bits); -} - -static void -set_co_mul(UNUSED(int bits), int carry) -{ - set_cf(carry); - set_of(carry); - set_zf_ex(!carry); - if (!carry) - wait(1, 0); -} - -/* Was div(), renamed to avoid conflicts with stdlib div(). */ -static int -x86_div(uint16_t l, uint16_t h) -{ - int bit_count = 8; - int negative = 0; - int dividend_negative = 0; - int size_mask; - int carry; - uint16_t r; - - if (opcode & 1) { - l = AX; - h = DX; - bit_count = 16; - } - - size_mask = (1 << bit_count) - 1; - - if (opcode != 0xd4) { - if ((rmdat & 0x38) == 0x38) { - if (top_bit(h, bit_count)) { - h = ~h; - l = (~l + 1) & size_mask; - if (l == 0) - ++h; - h &= size_mask; - negative = 1; - dividend_negative = 1; - wait(4, 0); - } - if (top_bit(cpu_src, bit_count)) { - cpu_src = ~cpu_src + 1; - negative = !negative; - } else - wait(1, 0); - wait(9, 0); - } - wait(3, 0); - } - wait(8, 0); - cpu_src &= size_mask; - if (h >= cpu_src) { - if (opcode != 0xd4) - wait(1, 0); - intr_routine(0, 0); - return 0; - } - if (opcode != 0xd4) - wait(1, 0); - wait(2, 0); - carry = 1; - for (int b = 0; b < bit_count; ++b) { - r = (l << 1) + (carry ? 1 : 0); - carry = top_bit(l, bit_count); - l = r; - r = (h << 1) + (carry ? 1 : 0); - carry = top_bit(h, bit_count); - h = r; - wait(8, 0); - if (carry) { - carry = 0; - h -= cpu_src; - if (b == bit_count - 1) - wait(2, 0); - } else { - carry = cpu_src > h; - if (!carry) { - h -= cpu_src; - wait(1, 0); - if (b == bit_count - 1) - wait(2, 0); - } - } - } - l = ~((l << 1) + (carry ? 1 : 0)); - if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { - wait(4, 0); - if (top_bit(l, bit_count)) { - if (cpu_mod == 3) - wait(1, 0); - intr_routine(0, 0); - return 0; - } - wait(7, 0); - if (negative) - l = ~l + 1; - if (dividend_negative) - h = ~h + 1; - } - if (opcode == 0xd4) { - AL = h & 0xff; - AH = l & 0xff; - } else { - AH = h & 0xff; - AL = l & 0xff; - if (opcode & 1) { - DX = h; - AX = l; - } - } - return 1; -} - -static uint16_t -string_increment(int bits) -{ - int d = bits >> 3; - if (cpu_state.flags & D_FLAG) - cpu_state.eaaddr -= d; - else - cpu_state.eaaddr += d; - cpu_state.eaaddr &= 0xffff; - return cpu_state.eaaddr; -} - -static void -lods(int bits) -{ - cpu_state.eaaddr = SI; - if (bits == 16) - cpu_data = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); - else - cpu_data = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); - SI = string_increment(bits); -} - -static void -lods_di(int bits) -{ - cpu_state.eaaddr = DI; - if (bits == 16) - cpu_data = readmemw(es, cpu_state.eaaddr); - else - cpu_data = readmemb(es, cpu_state.eaaddr); - DI = string_increment(bits); -} - -static void -stos(int bits) -{ - cpu_state.eaaddr = DI; - if (bits == 16) - writememw(es, cpu_state.eaaddr, cpu_data); - else - writememb(es, cpu_state.eaaddr, (uint8_t) (cpu_data & 0xff)); - DI = string_increment(bits); -} - -static void -set_ca(void) -{ - set_cf(1); - set_af(1); -} - -static void -clear_ca(void) -{ - set_cf(0); - set_af(0); -} - -static uint16_t -get_ea(void) -{ - if (opcode & 1) - return geteaw(); - else - return (uint16_t) geteab(); -} - -static uint16_t -get_reg(uint8_t reg) -{ - if (opcode & 1) - return cpu_state.regs[reg].w; - else - return (uint16_t) getr8(reg); -} - -static void -set_ea(uint16_t val) -{ - if (opcode & 1) - seteaw(val); - else - seteab((uint8_t) (val & 0xff)); -} - -static void -set_reg(uint8_t reg, uint16_t val) -{ - if (opcode & 1) - cpu_state.regs[reg].w = val; - else - setr8(reg, (uint8_t) (val & 0xff)); -} - -static void -cpu_data_opff_rm(void) -{ - if (!(opcode & 1)) { - if (cpu_mod != 3) - cpu_data |= 0xff00; - else - cpu_data = cpu_state.regs[cpu_rm].w; - } -} - -uint16_t -cpu_inw(uint16_t port) -{ - if (is8086 && !(port & 1)) { - wait(4, 0); - } else { - wait(8, 0); - } - - return inw(port); -} - -void -cpu_outw(uint16_t port, uint16_t val) -{ - if (is8086 && !(port & 1)) { - wait(4, 0); - } else { - wait(8, 0); - } - - return outw(port, val); -} - -/* Pushes a word to the stack. */ -static void -push(uint16_t *val) -{ - if ((is186 && !is_nec) && (SP == 1)) { - writememw(ss - 1, 0, *val); - SP = cpu_state.eaaddr = 0xFFFF; - return; - } - SP -= 2; - cpu_state.eaaddr = (SP & 0xffff); - writememw(ss, cpu_state.eaaddr, *val); -} - -/* Pops a word from the stack. */ -static uint16_t -pop(void) -{ - cpu_state.eaaddr = (SP & 0xffff); - SP += 2; - return readmemw(ss, cpu_state.eaaddr); -} - -static void -nearcall(uint16_t new_ip) -{ - uint16_t ret_ip = cpu_state.pc & 0xffff; - - wait(1, 0); - set_ip(new_ip); - pfq_clear(); - wait(3, 0); - push(&ret_ip); -} - -static void -farcall(uint16_t new_cs, uint16_t new_ip, int jump) -{ - if (jump) - wait(1, 0); - pfq_do_suspend(); - wait(3, 0); - push(&CS); - load_cs(new_cs); - wait(2, 0); - nearcall(new_ip); -} - -static void -farcall2(uint16_t new_cs, uint16_t new_ip) -{ - wait(3, 0); - push(&CS); - load_cs(new_cs); - wait(2, 0); - nearcall(new_ip); -} - -static void -handle_exception(uint16_t exception) -{ - uint16_t vector = exception * 4; - - push(&tempf); - push(&CS); - push(&cpu_state.old_pc); - - do_cycles_i(3); - cpu_state.eaaddr = vector & 0xffff; - new_ip = readmemw(0, cpu_state.eaaddr); - do_cycle_i(); - cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; - new_cs = readmemw(0, cpu_state.eaaddr); - - pfq_do_suspend(); - set_ip(new_ip); - set_cs(new_cs); - pfq_clear(); -} - -/* Calls an interrupt. */ -/* The INTR microcode routine. */ -static void -intr_routine(uint16_t intr, int skip_first) -{ - uint16_t vector = intr * 4; - uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); - uint16_t new_cs; - uint16_t new_ip; - uint16_t old_ip; - - if (!skip_first) - do_cycle_i(); - do_cycles_i(2); - - cpu_state.eaaddr = vector & 0xffff; - new_ip = readmemw(0, cpu_state.eaaddr); - do_cycle_i(); - cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; - new_cs = readmemw(0, cpu_state.eaaddr); - - pfq_do_suspend(); - do_cycles_i(2); - push(&tempf); - cpu_state.flags &= ~(I_FLAG | T_FLAG); - do_cycle_i(); - - farcall2(new_cs, new_ip); -} - -static void -sw_int(uint16_t intr) -{ - uint16_t vector = intr * 4; - uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); - uint16_t new_cs; - uint16_t new_ip; - uint16_t old_ip; - - do_cycles_i(3); - cpu_state.eaaddr = vector & 0xffff; - new_ip = readmemw(0, cpu_state.eaaddr); - do_cycle_i(); - cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; - new_cs = readmemw(0, cpu_state.eaaddr); - - pfq_do_suspend(); - do_cycles_i(2); - push(&tempf); - cpu_state.flags &= ~(I_FLAG | T_FLAG); - - /* FARCALL2 */ - do_cycles_i(4); - push(&CS); - load_cs(new_cs); - do_cycle_i(); - - /* NEARCALL */ - old_ip = cpu_state.pc & 0xffff; - do_cycles_i92); - set_ip(new_ip); - pfq_clear(); - do_cycles_i(3); - push(&old_ip); -} - -static void -int1(void) -{ - do_cycles_i(2); - intr_routine(1, 1); -} - -static void -int2(void) -{ - do_cycles_i(2); - intr_routine(2, 1); -} - -static void -int3(void) -{ - do_cycles_i(4); - intr_routine(3, 0); -} - -static void -int_o(void) -{ - do_cycles_i(4); - - if (cpu_state.flags & V_FLAG) { - do_cycles_i(2); - intr_routine(4, 0); - } -} - -void -interrupt_808x(uint16_t addr) -{ - intr_routine(addr, 0); -} - -static void -custom_nmi(void) -{ - uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); - uint16_t new_cs; - uint16_t new_ip; - uint16_t old_ip; - - do_cycle_i(); - do_cycles_i(2); - - cpu_state.eaaddr = 0x0002; - (void) readmemw(0, cpu_state.eaaddr); - new_ip = custom_nmi_vector & 0xffff; - do_cycle_i(); - cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; - (void) readmemw(0, cpu_state.eaaddr); - new_cs = custom_nmi_vector >> 16; - - pfq_do_suspend(); - do_cycles_i(2); - push(&tempf); - cpu_state.flags &= ~(I_FLAG | T_FLAG); - do_cycle_i(); - - farcall2(new_cs, new_ip); -} - -static int -irq_pending(void) -{ - uint8_t temp; - - temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint) || - ((cpu_state.flags & I_FLAG) && pic.int_pending && !noint); - - return temp; -} - -static int -bus_pic_ack(void) -{ - int old_in_lock = in_lock; - - in_lock = 1; - bus_request_type = BUS_PIC; - wait(4, 1); - in_lock = old_in_lock; - return pic_data; -} - -static void -hw_int(uint16_t vector) -{ - pfq_do_suspend(); - do_cycles_i(2); - - intr_routine(vector, 0); -} - -static void -check_interrupts(void) -{ - int temp; - - if (irq_pending()) { - if ((cpu_state.flags & T_FLAG) && !noint) { - wait(2, 0); - intr_routine(1, 0); - return; - } - if (nmi && nmi_enable && nmi_mask) { - nmi_enable = 0; - wait(2, 0); - if (use_custom_nmi_vector) - custom_nmi(); - else - intr_routine(2, 0); -#ifndef OLD_NMI_BEHAVIOR - nmi = 0; -#endif - return; - } - if ((cpu_state.flags & I_FLAG) && pic.int_pending && !noint) { - repeating = 0; - completed = 1; - ovr_seg = NULL; - wait(4, 0); - /* ACK to PIC */ - temp = bus_pic_ack(); - wait(1, 0); - /* ACK to PIC */ - temp = bus_pic_ack(); - in_lock = 0; - clear_lock = 0; - /* Here is where temp should be filled, but we cheat. */ - opcode = 0x00; - hw_int(temp); - } - } -} - -static int -iret_routine(void) -{ - do_cycle_i(); - farret(1); - /* pop_flags() */ - if (is_nec) - cpu_state.flags = pop() | 0x8002; - else - cpu_state.flags = pop() | 0x0002; - do_cycle_i(); - noint = 1; - nmi_enable = 1; -} - -static int -irq_pending(void) -{ - uint8_t temp; - - temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint) || - ((cpu_state.flags & I_FLAG) && pic.int_pending && !noint); - - return temp; -} - -static void -rep_end(void) -{ - repeating = 0; - in_rep = 0; - completed = 1; -} - -static int -rep_start(void) -{ - if (!repeating) { - if (in_rep != 0) { - if (CX == 0) { - do_cycles_i(4); - rep_end(); - return 0; - } else - do_cycles_i(7); - } - } - - completed = 1; - return 1; -} - -static void -rep_interrupt(void) -{ - pfq_do_suspend(); - do_cycles_i(4); - pfq_clear(); - - if (is_nec && (ovr_seg != NULL)) - set_ip((cpu_state.pc - 3) & 0xffff); - else - set_ip((cpu_state.pc - 2) & 0xffff); - - rep_end(); -} - -static void -sign_extend_al(void) -{ - if ((AL & 0x80) != 0) - AH = 0xff; - else - AH = 0x00; -} - -static void -sign_extend_ax(void) -{ - do_cycles(3); - if ((AX & 0x8000) == 0) - DX = 0x0000; - else { - do_cycle(); - DX = 0xffff; - } -} - -static void -reljmp(uint16_t new_ip, int jump) -{ - if (jump) - do_cycle_i(); - - pfq_do_suspend(); - do_cycles_i(3); - set_ip(new_ip); - pfq_clear(); - do_cycle_i(); -} - -static void -daa(void) -{ - uint16_t old_cf = cpu_state.flags & C_FLAG; - uint16_t old_af = cpu_state.flags & A_FLAG; - uint8_t old_al = AL; - uint8_t al_check; - - cpu_state.flags &= ~C_FLAG; - - al_check = (old_af ? 0x9f : 0x99); - - cpu_state.flags &= ~V_FLAG; - if (old_cf) { - if ((AL >= 0x1a) && (AL <= 0x7f)) - cpu_state.flags |= V_FLAG; - } else if ((AL >= 0x1a) && (AL <= 0x7f)) - cpu_state.flags |= V_FLAG; - - if (((AL & 0x0f) > 9) || (cpu_state.flags & A_FLAG)) { - AL += 6; - cpu_state.flags |= A_FLAG; - } else - cpu_state.flags &= ~A_FLAG; - - if ((old_al > al_check) || old_cf) { - AL += 0x60; - cpu_state.flags |= C_FLAG; - } else - cpu_state.flags &= ~C_FLAG; - - set_pzs(8); -} - -static void -das(void) -{ - uint8_t old_al = AL; - uint16_t old_af = cpu_stat.flags & A_FLAG; - uint16_t old_cf = cpu_stat.flags & C_FLAG; - uint8_t al_check = (old_af ? 0x9f : 0x99); - - cpu_state.flags &= ~V_FLAG; - - if (!old_af && !old_cf) { - if ((AL >= 0x9a) && (AL <= 0xdf)) - cpu_state.flags |= V_FLAG; - } else if (old_af && !old_cf) { - if (((AL >= 0x80) && (AL <= 0x85)) || ((AL >= ax80) && (AL <= 0xe5))) - cpu_state.flags |= V_FLAG; - } else if (!old_af && old_cf) { - if ((AL >= 0x80) && (AL <= 0xdf)) - cpu_state.flags |= V_FLAG; - } else if (old_af && old_cf) { - if ((AL >= 0x80) && (AL <= 0xe5)) - cpu_state.flags |= V_FLAG; - } - - cpu_state.flags &= ~C_FLAG; - if (((AL & 0x0f) > 9) || (cpu_state.flags & A_FLAG)) { - AL -= 6; - cpu_state.flags |= A_FLAG; - } else - cpu_state.flags &= ~A_FLAG; - - if ((old_al > al_check) || old_cf) { - AL -= 60; - cpu_state.flags |= C_FLAG; - } else - cpu_state.flags &= ~C_FLAG; - - set_pzs(8); -} - -static void -aaa(void) -{ - uint8_t old_al = AL; - uint8_t new_al; - - if (((AL & 0x0f) > 9) || (cpu_state.flags & A_FLAG)) { - AH += 1; - new_al = AL + 6; - AL = new_al & 0x0f; - cpu_state.flags |= A_FLAG; - cpu_state.flags |= C_FLAG; - } else { - new_al = AL; - AL &= 0x0f; - cpu_state.flags &= ~A_FLAG; - cpu_state.flags &= ~C_FLAG; - do_cycle_i(); - } - - cpu_state.flags &= ~(O_FLAG | Z_FLAG | N_FLAG); - if (new_al == 0x00) - cpu_state.flags |= Z_FLAG; - if ((old_al >= 0x7a) && (old_al <= 0x7f)) - cpu_state.flags |= O_FLAG; - if ((old_al >= 0x7a) && (old_al <= 0xf9)) - cpu_state.flags |= N_FLAG; - - cpu_data = new_al; - set_pf(); -} - -static void -aas(void) -{ - uint8_t old_al = AL; - uint16_t old_af = cpu_state.flags & A_FLAG; - uint8_t new_al; - - do_cycles_i(6); - - if (((AL & 0x0f) > 9) || old_af) { - new_al = AL - 6; - AH++; - AL = new_al & 0x0f; - cpu_state.flags |= (A_FLAG | C_FLAG); - } else { - new_al = AL; - AL &= 0x0f; - cpu_state.flags &= ~(C_FLAG | A_FLAG); - do_cycle_i(); - } - - cpu_state.flags &= ~(O_FLAG | Z_FLAG | N_FLAG); - if (new_al == 0x00) - cpu_state.flags |= Z_FLAG; - if (old_af && (old_al >= 0x80) && (old_al <= 0x85)) - cpu_state.flags |= O_FLAG; - if (!old_af && (old_al >= 0x80)) - cpu_state.flags |= N_FLAG; - if (old_af && ((old_al <= 0x05) || (old_al >= 0x86))) - cpu_state.flags |= N_FLAG; - - cpu_data = new_al; - set_pf(); -} - -static void -finalize(void) -{ - if (pfq_pos == 0) { - do { - if (nx) - nx = 0; - do_cycle(); - } while (pfq_pos == 0); - do_cycle(); - } else - do_cycle(); -} - -/* Executes instructions up to the specified number of cycles. */ -void -execx86(int cycs) -{ -#if 0 - uint8_t temp = 0; - uint8_t temp2; - uint8_t old_af; - uint8_t nests; - uint8_t temp_val; - uint8_t temp_al; - uint8_t bit; - uint8_t handled = 0; - uint8_t odd; - uint8_t zero; - uint8_t nibbles_count; - uint8_t destcmp; - uint8_t destbyte; - uint8_t srcbyte; - uint8_t nibble_result; - uint8_t bit_length; - uint8_t bit_offset; - int8_t nibble_result_s; - uint16_t addr; - uint16_t tempw; - uint16_t new_cs; - uint16_t new_ip; - uint16_t tempw_int; - uint16_t size; - uint16_t tempbp; - uint16_t lowbound; - uint16_t highbound; - uint16_t regval; - uint16_t orig_sp; - uint16_t wordtopush; - uint16_t immediate; - uint16_t old_flags; - uint16_t tmpa; - int bits; - uint32_t dest_seg; - uint32_t i; - uint32_t carry; - uint32_t nibble; - uint32_t srcseg; - uint32_t byteaddr; -#endif - - uint16_t jump; - int8_t rel8; - int16_t rel16; - uint16_t new_ip; - uint8_t tempb; - uint16_t tempw; - uint16_t zero_cond; - uint16_t old_cs; - uint16_t old_ip; - int negate; - uint16_t old_flags; - uint16_t prod16; - uint32_t prod32; - - cycles += cycs; - - while (cycles > 0) { - clock_start(); - - if (!repeating) { - cpu_state.oldpc = cpu_state.pc; - opcode = pfq_fetchb_common(); - handled = 0; - oldc = cpu_state.flags & C_FLAG; - if (clear_lock) { - in_lock = 0; - clear_lock = 0; - } - if (nx) { - wait(1, 0); - nx = 0; - } - wait(1, 0); - /* if (group_delay) { - wait(1, 0); - nx = 0; - } */ - } - - completed = 1; - x808x_log("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); - - switch (opcode) { - case 0x00: /* ADD r/m8, r8; r8, r/m8; al, imm8 */ - case 0x02: - case 0x04: - case 0x08: /* OR r/m8, r8; r8, r/m8; al, imm8 */ - case 0x0a: - case 0x0c: - case 0x10: /* ADC r/m8, r8; r8, r/m8; al, imm8 */ - case 0x12: - case 0x14: - case 0x18: /* SBB r/m8, r8; r8, r/m8; al, imm8 */ - case 0x1a: - case 0x1c: - case 0x20: /* AND r/m8, r8; r8, r/m8; al, imm8 */ - case 0x22: - case 0x24: - case 0x28: /* SUB r/m8, r8; r8, r/m8; al, imm8 */ - case 0x2a: - case 0x2c: - case 0x30: /* XOR r/m8, r8; r8, r/m8; al, imm8 */ - case 0x32: - case 0x34: - bits = 8; - /* read_operand8() */ - if (opcode & 0x04) { - cpu_data = pfq_fetch(); - cpu_dest = get_accum(bits); /* AX/AL */ - cpu_src = cpu_data; - } else { - do_mod_rm(); - tempw = get_ea(); - if (opcode & 2) { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; - } else { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); - } - } - do_cycles_nx_i(2); - if (addr_mode_match()) - do_cycles_i(2); - - /* math_op8() */ - math_op((opcode >> 3) & 7); - /* write_operand8() */ - if (opcode & 0x04) - set_accum(bits, cpu_data); - else { - if (opcode & 2) - set_reg(cpu_reg, cpu_data); - else - set_ea(cpu_data); - } - break; - - case 0x01: /* ADD r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x03: - case 0x05: - case 0x09: /* OR r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x0b: - case 0x0d: - case 0x11: /* ADC r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x13: - case 0x15: - case 0x19: /* SBB r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x1b: - case 0x1d: - case 0x21: /* AND r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x23: - case 0x25: - case 0x29: /* SUB r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x2b: - case 0x2d: - case 0x31: /* XOR r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x33: - case 0x35: - bits = 16; - nx = 1; - /* read_operand16() */ - if (opcode & 0x04) { - cpu_data = pfq_fetch(); - cpu_dest = get_accum(bits); /* AX/AL */ - cpu_src = cpu_data; - } else { - do_mod_rm(); - tempw = get_ea(); - if (opcode & 2) { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; - } else { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); - } - } - do_cycles_nx_i(2); - if (addr_mode_match()) - do_cycles_i(2); - - /* math_op16() */ - math_op((opcode >> 3) & 7); - /* write_operand16() */ - if (opcode & 0x04) - set_accum(bits, cpu_data); - else { - if (opcode & 2) - set_reg(cpu_reg, cpu_data); - else - set_ea(cpu_data); - } - break; - - case 0x06: - case 0x0e: - case 0x16: - case 0x1e: /* PUSH seg */ - wait(3, 0); - push(&(_opseg[(opcode >> 3) & 0x03]->seg)); - break; - - case 0x07: - case 0x17: - case 0x1f: /* POP seg */ - load_seg(pop(), _opseg[(opcode >> 3) & 0x03]); - /* All POP segment instructions suppress interrupts for one instruction. */ - noint = 1; - break; - - case 0x0f: - if (is_nec) { - // execvx0_0f(); - fatal("execvx0_0f() not yet implemented\n"); - } else { - load_cs(pop()); - /* All POP segment instructions suppress interrupts for one instruction. */ - noint = 1; - } - break; - - case 0x26: /* ES: */ - case 0x2e: /* CS: */ - case 0x36: /* SS: */ - case 0x3e: /* DS: */ - ovr_seg = opseg[(opcode >> 3) & 0x03]; - completed = 0; - break; - - case 0x27: /* DAA */ - do_cycles_nx_i(3); - daa(); - break; - - case 0x2f: /* DAS */ - do_cycles_nx_i(3); - das(); - break; - - case 0x37: /* AAA */ - aaa(); - break; - - case 0x38: /* CMP r/m8, r8; r8, r/m8; al, imm8 */ - case 0x3a: - case 0x3c: - bits = 8; - /* read_operand8() */ - if (opcode & 0x04) { - cpu_data = pfq_fetch(); - cpu_dest = get_accum(bits); /* AX/AL */ - cpu_src = cpu_data; - } else { - do_mod_rm(); - tempw = get_ea(); - if (opcode & 2) { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; - } else { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); - } - } - - do_cycles_nx_i(2); - - /* math_op8() */ - math_op(7); - break; - - case 0x39: /* CMP r/m16, r16; r16, r/m16; ax, imm16 */ - case 0x3b: - case 0x3d: - bits = 16; - /* read_operand16() */ - if (opcode & 0x04) { - cpu_data = pfq_fetch(); - cpu_dest = get_accum(bits); /* AX/AL */ - cpu_src = cpu_data; - } else { - do_mod_rm(); - tempw = get_ea(); - if (opcode & 2) { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; - } else { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); - } - } - - do_cycles_nx_i((opcode == 0x3d) ? 1 : 2); - - /* math_op16() */ - math_op(7); - break; - - case 0x3f: /*AAS*/ - aas(); - break; - - case 0x40 ... 0x47: /* INC r16 */ - /* read_operand16() */ - cpu_dest = cpu_state.regs[opcode & 7].w; - cpu_src = 1; - bits = 16; - /* math_op16() */ - cpu_data = cpu_dest + cpu_src; - set_of_add(bits); - do_af(); - set_pzs(16); - /* write_operand16() */ - cpu_state.regs[opcode & 7].w = cpu_data; - do_cycles_nx(1); - break; - - case 0x48 ... 0x4f: /* DEC r16 */ - /* read_operand16() */ - cpu_dest = cpu_state.regs[opcode & 7].w; - cpu_src = 1; - bits = 16; - /* math_op16() */ - cpu_data = cpu_dest - cpu_src; - set_of_sub(bits); - do_af(); - set_pzs(16); - /* write_operand16() */ - cpu_state.regs[opcode & 7].w = cpu_data; - do_cycles_nx(1); - break; - - case 0x50 ... 0x57: /* PUSH r16 */ - do_cycles_i(3); - push(&(cpu_state.regs[opcode & 0x07].w)); - break; - - case 0x58 ... 0x5f: /* POP r16 */ - cpu_state.regs[opcode & 0x07].w = pop(); - do_cycle_nx_i(); - break; - - case 0x60 ... 0x7f: /* JMP rel8 */ - if (is_nec && (opcode < 0x70)) { - // execvx0_6x(); - fatal("execvx0_6x() not yet implemented\n"); - } else { - switch ((opcode >> 1) & 0x07) { - case 0x00: - jump = cpu_state & V_FLAG; - break; - case 0x01: - jump = cpu_state & C_FLAG; - break; - case 0x02: - jump = cpu_state & Z_FLAG; - break; - case 0x03: - jump = cpu_state & (C_FLAG | Z_FLAG); - break; - case 0x04: - jump = cpu_state & N_FLAG; - break; - case 0x05: - jump = cpu_state & P_FLAG; - break; - case 0x06: - jump = (!!(cpu_state & N_FLAG)) != (!!(cpu_state & V_FLAG)); - break; - case 0x07: - jump = (cpu_state & Z_FLAG) || - ((!!(cpu_state & N_FLAG)) != (!!(cpu_state & V_FLAG)))); - break; - } - if (opcode & 1) - jump = !jump; - - new_ip = cpu_state.pc + ((int8_t) pfq_fetch()); - cpu_do_cycle_i(); - - if (jump) - reljmp(new_ip, 1); - } - break; - - case 0x80: /* ADD/OR/ADC/SBB/AND/SUB/XOR/CMP r/m8, imm8 */ - case 0x82: - bits = 8; - /* read_opreand8() */ - do_mod_rm(); - cpu_data = get_ea(); - cpu_dest = cpu_data; - cpu_src = pfq_fetchb() | 0xff00; - - do_cycle_nx(); - math_op((rmdat & 0x38) >> 3); - - if (addr_mode_match()) - do_cycles_i(2); - - /* write_operand8() */ - if (cpu_alu_op != 7) - set_ea(cpu_data); - break; - - case 0x81: /* ADD/OR/ADC/SBB/AND/SUB/XOR/CMP r/m16, imm16 */ - bits = 16; - /* read_opreand16() */ - do_mod_rm(); - cpu_data = get_ea(); - cpu_dest = cpu_data; - cpu_src = pfq_fetchw(); - - do_cycle_nx(); - math_op((rmdat & 0x38) >> 3); - - if (addr_mode_match()) { - if (cpu_alu_op != 7) - do_cycles_i(2); - else { - do_cycles_nx_i(2); - } - } - - /* write_operand16() */ - if (cpu_alu_op != 7) - set_ea(cpu_data); - break; - - case 0x83: /* ADD/OR/ADC/SBB/AND/SUB/XOR/CMP r/m16, imm8 (sign-extended) */ - bits = 16; - /* read_opreand16() */ - do_mod_rm(); - cpu_data = get_ea(); - cpu_dest = cpu_data; - cpu_src = sign_extend(pfq_fetchb()); - - do_cycle_nx(); - math_op((rmdat & 0x38) >> 3); - - if (addr_mode_match()) - do_cycles_i(2); - - /* write_operand16() */ - if (cpu_alu_op != 7) - set_ea(cpu_data); - break; - - case 0x84: /* TEST r/m8, r8 */ - bits = 8; - /* read_operand8() */ - do_mod_rm(); - cpu_data = get_ea(); - - /* math_op8() */ - test(bits, cpu_data, get_reg(cpu_reg)); - - do_cycles_nx_i(2); - break; - - case 0x85: /* TEST r/m16, r16 */ - bits = 16; - /* read_operand16() */ - do_mod_rm(); - cpu_data = get_ea(); - - /* math_op16() */ - test(bits, cpu_data, get_reg(cpu_reg)); - - do_cycles_nx_i(2); - break; - - case 0x86: /* XHG r8, r/m8 */ - bits = 8; - /* read_operand8() */ - do_mod_rm(); - cpu_data = get_ea(); - cpu_src = get_reg(cpu_reg); - - do_cycles_nx(3); - - if (addr_mode_match()) - do_cycles(2); - - /* write_operand8() */ - set_reg(cpu_reg, cpu_data); - set_ea(cpu_src); - break; - - case 0x87: /* XCHG r16, r/m16 */ - bits = 16; - /* read_operand16() */ - do_mod_rm(); - cpu_data = get_ea(); - cpu_src = get_reg(cpu_reg); - - do_cycles_nx(3); - - if (addr_mode_match()) - do_cycles(2); - - /* write_operand16() */ - set_reg(cpu_reg, cpu_data); - set_ea(cpu_src); - break; - - case 0x88: /* MOV r/m8, r8; MOV r8, r/m8 */ - case 0x8a: - bits = 8; - do_cycle_nx(); - /* read_operand8() */ - do_mod_rm(); - if (opcode == 0x88) - tempb = get_reg(cpu_reg); - else - tempb = get_ea(); - - if (addr_mode_match()) - do_cycles(2); - - /* write_operand8() */ - if (opcode == 0x88) - set_ea(tempb); - else - set_reg(cpu_reg, tempb); - break; - - case 0x89: /* MOV r/m16, r16; MOV r16, r/m16 */ - case 0x8b: - bits = 16; - do_cycle_nx(); - /* read_operand16() */ - do_mod_rm(); - if (opcode == 0x89) - tempw = get_reg(cpu_reg); - else - tempw = get_ea(); - - if (addr_mode_match()) - do_cycles(2); - - /* write_operand16() */ - if (opcode == 0x89) - set_ea(tempw); - else - set_reg(cpu_reg, tempw); - break; - - case 0x8c: /* MOV r/m16, SReg; MOV SReg, r/m16 */ - case 0x8e: - bits = 16; - do_mod_rm(); - if (addr_mode_match()) - do_cycle_i(); - /* read_operand16() */ - if (opcode == 0x8c) - tempw = _opseg[(rmdat & 0x18) >> 3]->seg; - else - tempw = geteaw(); - /* write_operand16() */ - if (opcode == 0x8c) - seteaw(tempw); - else { - if ((rmdat & 0x18) == 0x08) - load_cs(tempw); - else - load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); - if (((rmdat & 0x18) >> 3) == 2) - noint = 1; - } - break; - - case 0x8d: /* LEA */ - do_mod_rm(); - cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; - break; - - case 0x8f: /* POP r/m16 */ - do_cycle_i(); - /* pop_u16() */ - do_mod_rm(); - cpu_src = cpu_state.eaaddr; - cpu_data = pop(); - do_cycle_i(); - if (addr_mode_match()) - do_cycles_i(2); - /* write_operand16() */ - cpu_state.eaaddr = cpu_src; - seteaw(cpu_data); - break; - - case 0x90 ... 0x97: /* XCHG AX, r */ - cpu_data = cpu_state.regs[opcode & 7].w; - do_cycles_nx_i(2); - cpu_state.regs[opcode & 7].w = AX; - AX = cpu_data; - break; - - case 0x98: /* CBW */ - sign_extend_al(); - break; - - case 0x99: /* CWD */ - sign_extend_ax(); - break; - - case 0x9a: /* CALLF */ - /* read_operand_faraddr() */ - new_ip = pfq_fetchw(); - new_cs = pfq_fetchw(); - - do_cycle_i(); - pfq_do_suspend(); - do_cycles_i(3); - - push(&(CS)); - - do_cycles_i(3); - - load_cs(new_cs); - cpu_state.oldpc = cpu_state.pc; - set_ip(new_ip); - - pfq_clear(); - do_cycles_i(3); - push((uint16_t *) &(cpu_state.oldpc)); - break; - - case 0x9b: /* WAIT */ - do_cycles(3); - break; - - case 0x9c: /* PUSHF */ - do_cycles(3); - /* push_flags() */ - if (is_nec) - tempw = (cpu_state.flags & 0x8fd7) | 0x7000; - else - tempw = (cpu_state.flags & 0x0fd7) | 0xf000; - push(&tempw); - break; - - case 0x9d: /* POPF */ - /* pop_flags() */ - if (is_nec) - cpu_state.flags = pop() | 0x8002; - else - cpu_state.flags = pop() | 0x0002; - break; - - case 0x9e: /* SAHF */ - /* store_flags() */ - cpu_state.flags = (cpu_state.flags & 0xff02) | AH; - break; - - case 0x9f: /*LAHF*/ - /* load_flags() */ - /* set_register8() */ - AH = cpu_state.flags & 0xd7; - break; - - case 0xa0: /* MOV al, offset8 */ - bits = 8; - /* read_operand8() */ - cpu_state.eaaddr = pfq_fetchw(); - tempb = readmem(ovr_seg ? *ovr_seg : ds); - /* set_register8() */ - set_accum(bits, tempb); - break; - - case 0xa1: /* MOV al, offset16 */ - bits = 16; - /* read_operand16() */ - cpu_state.eaaddr = pfq_fetchw(); - tempbw = readmem(ovr_seg ? *ovr_seg : ds); - /* set_register16() */ - set_accum(bits, tempw); - break; - - case 0xa2: /* MOV offset8, Al */ - bits = 8; - tempb = get_accum(bits); - /* write_operand8() */ - cpu_state.eaaddr = pfq_fetchw(); - writemem((ovr_seg ? *ovr_seg : ds), tempb); - break; - - case 0xa3: /* MOV offset16, AX */ - bits = 16; - tempw = get_accum(bits); - /* write_operand16() */ - cpu_state.eaaddr = pfq_fetchw(); - writemem((ovr_seg ? *ovr_seg : ds), tempw); - break; - - case 0xa4: /* MOVSB & MOVSW */ - case 0xa5: - bits = 8 << (opcode & 1); - if (rep_start()) { - /* string_op() */ - lods(bits); - do_cycle_i(); - stos(bits); - do_cycle_i(); - - if (in_rep != 0) { - completed = 0; - repeating = 1; - - /* decrement_register16() */ - CX--; - - if (irq_pending()) { - do_cycles_i(2); - rep_interrupt(); - } else { - do_cycles_i(2); - - if (CX == 0) - rep_end(); - else - do_cycle_i(); - } - } else - do_cycle_i(); - } - break; - - case 0xa6: /* CMPSB, CMPSW, SCASB, SCASW */ - case 0xa7: - case 0xae: - case 0xaf: - bits = 8 << (opcode & 1); - if (rep_start()) { - /* string_op() */ - if (opcode & 8) { - tmpa = AX; - do_cycles_i(2); - lods_di(bits); - do_cycles_i(3); - - cpu_src = cpu_data; - cpu_dest = tmpa; - sub(bits); - } else { - do_cycle_i() - lods(bits); - tmpa = cpu_data; - do_cycles_i(2); - lods_di(bits); - do_cycles_i(3); - - cpu_src = cpu_data; - cpu_dest = tmpa; - sub(bits); - } - - if (in_rep) { - uint8_t end = 0; - - completed = 0; - repeating = 1; - - do_cycle_i(); - /* decrement_register16() */ - CX--; - - if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { - rep_end(); - do_cycle_i(); - end = 1; - } - - if (!end) { - do_cycle_i(); - - if (irq_pending()) { - do_cycle_i(); - rep_interrupt(); - } - - do_cycle_i(); - if (CX == 0) - rep_end(); - else - do_cycle_i(); - } else - do_cycle_i(); - } - } - break; - - case 0xa8: /* TEST al, imm8 */ - bits = 8; - /* read_operand8() */ - cpu_data = pfq_fetch(); - /* math_op8() */ - test(bits, get_accum(bits), cpu_data); - break; - - case 0xa9: /* TEST ax, imm16 */ - bits = 16; - /* read_operand16() */ - cpu_data = pfq_fetch(); - /* math_op16() */ - test(bits, get_accum(bits), cpu_data); - break; - - case 0xaa: /* STOSB & STOSW */ - case 0xab: - bits = 8 << (opcode & 1); - if (rep_start()) { - /* string_op() */ - cpu_data = AX; - /* This has to be here or Snatch-It! doesn't work. */ - wait(1, 0); - stos(bits); - - if (in_rep != 0) { - completed = 0; - repeating = 1; - - do_cycle_i(); - if (irq_pending()) { - do_cycle_i(); - rep_interrupt(); - } - - do_cycle_i(); - /* decrement_register16() */ - CX--; - if (CX == 0) - rep_end(); - else - do_cycle_i(); - } else - do_cycle_i(); - } - break; - - case 0xac: /* LODSB * LODSW */ - case 0xad: - bits = 8 << (opcode & 1); - if (rep_start()) { - /* string_op() */ - lods(bits); - set_accum(bits, cpu_data); - do_cycles_i(3); - - if (in_rep != 0) { - completed = 0; - repeating = 1; - - do_cycle_i(); - /* decrement_register16() */ - CX--; - - if (irq_pending()) { - do_cycles_i(2); - rep_interrupt(); - } else { - do_cycles_i(2); - - if (CX == 0) - rep_end(); - else - do_cycle_i(); - } - } - } - break; - - case 0xb0 ... 0xb7: /* MOV r8, imm8 */ - bits = 8; - /* read_operand8() */ - tempb = pfq_fetch(); - /* set_register8() */ - if (opcode & 0x04) - cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); - else - cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); - do_cycle_i(); - break; - - case 0xb8 ... 0xbf: /* MOV r16, imm16 */ - bits = 16; - /* read_operand16() */ - tempw = pfq_fetch(); - /* set_register16() */ - cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); - break; - - case 0xc0: /* RETN imm16 */ - case 0xc2: - bits = 8; - cpu_src = pfq_fetchw(); - do_cycle_i(); - new_ip = pop(); - set_ip(new_ip); - - pfq_do_suspend(); - do_cycles_i(2); - pfq_clear(); - do_cycles_i(3); - - /* release() */ - SP += cpu_src; - - jump = 1; - break; - - case 0xc1: /* RETN */ - case 0xc3: - bits = 8; - new_ip = pop(); - cpu_src = pfq_fetchw(); - pfq_do_suspend(); - set_ip(new_ip); - do_cycle_i(); - pfq_clear(); - do_cycles_i(2); - - jump = 1; - break; - - case 0xc4: /* LES */ - case 0xc5: /* LDS */ - do_mod_rm(); - bits = 16; - - do_cycles_i(2); - - /* read_operand_farptr() */ - read_ea(1, bits); - cpu_state.regs[cpu_reg].w = cpu_data; - read_ea2(bits); - - /* write_operand16() */ - load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); - break; - - case 0xc6: /* MOV r/m8, imm8 */ - bits = 8; - /* read_operand8() */ - do_mod_rm(); - cpu_data = pfq_fetch(); - do_cycles(2); - /* write_operand8() */ - set_ea(cpu_data); - break; - - case 0xc7: /* MOV r/m16, imm16 */ - bits = 16; - /* read_operand16() */ - do_mod_rm(); - cpu_data = pfq_fetch(); - do_cycle_i(); - /* write_operand16() */ - set_ea(cpu_data); - break; - - case 0xc8: /* RETF imm16 */ - case 0xca: - bits = 8 + (opcode & 0x08); - /* read_operand16() */ - cpu_src = pfq_fetchw(); - farret(1); - /* release() */ - SP += cpu_src; - do_cycle_i(); - jump = 1; - break; - - case 0xc9: /* RETF */ - case 0xcb: - bits = 8 + (opcode & 0x08); - do_cycle_i(); - farret(1); - jump = 1; - break; - - case 0xcc: /* INT 3 */ - do_cycles_i(4); - int3(); - jump = 1; - break; - - case 0xcd: /* INT imm8 */ - /* read_operand8() */ - temp = pfq_fetchb(); - do_cycle_i(); - sw_int(temp); - jump = 1; - break; - - case 0xce: /* INTO */ - if (cpu_state.flags & V_FLAG) { - sw_int(4); - jump = 1; - } - break; - - case 0xcf: /* IRET */ - iret_routine(); - jump = 1; - break; - - case 0xd0: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 8, 0x01 */ - case 0xd1: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 16, 0x01 */ - case 0xd2: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 8, cl */ - case 0xd3: /* ROL, ROR, RCL, RCR, SHL, SHR, SAR: r/m 16, cl */ - /* rot rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - /* read_operand() */ - cpu_data = get_ea(); - if ((opcode & 2) == 0) - cpu_src = 1; - else - cpu_src = CL; - if (is186 && !is_nec) - cpu_src &= 0x1F; - if (opcode >= 0xd2) { - do_cycles_i(6); - if (CL > 0) { - for (uint8_t i = 0; i < CL; i++) - do_cycles_i(4); - } - if (addr_mode_match()) - do_cycle_i(); - } - /* bitshift_op() */ - while (cpu_src != 0) { - cpu_dest = cpu_data; - oldc = cpu_state.flags & C_FLAG; - switch (rmdat & 0x38) { - case 0x00: /* ROL */ - set_cf(top_bit(cpu_data, bits)); - cpu_data <<= 1; - cpu_data |= ((cpu_state.flags & C_FLAG) ? 1 : 0); - set_of_rotate(bits); - set_af(0); - break; - case 0x08: /* ROR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - if (cpu_state.flags & C_FLAG) - cpu_data |= (!(opcode & 1) ? 0x80 : 0x8000); - set_of_rotate(bits); - set_af(0); - break; - case 0x10: /* RCL */ - set_cf(top_bit(cpu_data, bits)); - cpu_data = (cpu_data << 1) | (oldc ? 1 : 0); - set_of_rotate(bits); - set_af(0); - break; - case 0x18: /* RCR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - if (oldc) - cpu_data |= (!(opcode & 0x01) ? 0x80 : 0x8000); - set_cf((cpu_dest & 1) != 0); - set_of_rotate(bits); - set_af(0); - break; - case 0x20: /* SHL */ - set_cf(top_bit(cpu_data, bits)); - cpu_data <<= 1; - set_of_rotate(bits); - set_af((cpu_data & 0x10) != 0); - set_pzs(bits); - break; - case 0x28: /* SHR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - set_of_rotate(bits); - set_af(0); - set_pzs(bits); - break; - case 0x30: /* SETMO - undocumented? */ - bitwise(bits, 0xffff); - set_cf(0); - set_of_rotate(bits); - set_af(0); - set_pzs(bits); - break; - case 0x38: /* SAR */ - set_cf((cpu_data & 1) != 0); - cpu_data >>= 1; - if (!(opcode & 1)) - cpu_data |= (cpu_dest & 0x80); - else - cpu_data |= (cpu_dest & 0x8000); - set_of_rotate(bits); - set_af(0); - set_pzs(bits); - break; - - default: - break; - } - --cpu_src; - } - - if (opcode <= 0xd1) { - if (addr_mode_match()) - do_cycle_i(); - } - - /* write_operand() */ - set_ea(cpu_data); - break; - - case 0xD5: /*AAD*/ - wait(1, 0); - if (is_nec) { - (void) pfq_fetchb(); - mul(10, AH); - } else - mul(pfq_fetchb(), AH); - cpu_dest = AL; - cpu_src = cpu_data; - add(8); - AL = cpu_data; - AH = 0x00; - break; - - case 0xd4: /* AAM */ - /* read_operand8() */ - cpu_src = pfq_fetchb(); - /* Confirmed to be identical on V20/V30 to 808x, per - XTIDE working correctly on both (it uses AAM with - parameter other than 10. */ -#ifdef NO_VARIANT_ON_NEC - if (is_nec) - cpu_src = 10; -#endif - /* aam() */ - if (x86_div(AL, 0)) - set_pzs(16); - break; - - case 0xd5: /* AAD */ - /* read_operand8() */ - cpu_src = pfq_fetchb(); - if (is_nec) - cpu_src = 10; - /* aad() */ - mul(cpu_src, AH); - cpu_dest = AL; - cpu_src = cpu_data; - add(8); - AL = cpu_data; - AH = 0x00; - break; - - case 0xd6: /* SALC */ - AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; - break; - - case 0xd7: /* XLAT */ - do_cycles_i(3, 0); - /* biu_read_u8() */ - cpu_state.eaaddr = (BX + AL) & 0xffff; - tempb = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); - /* set_register8() */ - AL = tempb; - break; - - case 0xd8 ... 0xdf: /* ESC - FPU instructions. */ - /* read_operand16() */ - do_mod_rm(); - tempw = cpu_state.pc; - geteaw(); - /* fpu_op() */ - if (hasfpu) { - if (fpu_softfloat) { - switch (opcode) { - case 0xd8: - ops_sf_fpu_8087_d8[(rmdat >> 3) & 0x1f](rmdat); - break; - case 0xd9: - ops_sf_fpu_8087_d9[rmdat & 0xff](rmdat); - break; - case 0xda: - ops_sf_fpu_8087_da[rmdat & 0xff](rmdat); - break; - case 0xdb: - ops_sf_fpu_8087_db[rmdat & 0xff](rmdat); - break; - case 0xdc: - ops_sf_fpu_8087_dc[(rmdat >> 3) & 0x1f](rmdat); - break; - case 0xdd: - ops_sf_fpu_8087_dd[rmdat & 0xff](rmdat); - break; - case 0xde: - ops_sf_fpu_8087_de[rmdat & 0xff](rmdat); - break; - case 0xdf: - ops_sf_fpu_8087_df[rmdat & 0xff](rmdat); - break; - - default: - break; - } - } else { - switch (opcode) { - case 0xd8: - ops_fpu_8087_d8[(rmdat >> 3) & 0x1f](rmdat); - break; - case 0xd9: - ops_fpu_8087_d9[rmdat & 0xff](rmdat); - break; - case 0xdA: - ops_fpu_8087_da[rmdat & 0xff](rmdat); - break; - case 0xdb: - ops_fpu_8087_db[rmdat & 0xff](rmdat); - break; - case 0xdc: - ops_fpu_8087_dc[(rmdat >> 3) & 0x1f](rmdat); - break; - case 0xdd: - ops_fpu_8087_dd[rmdat & 0xff](rmdat); - break; - case 0xde: - ops_fpu_8087_de[rmdat & 0xff](rmdat); - break; - case 0xdf: - ops_fpu_8087_df[rmdat & 0xff](rmdat); - break; - - default: - break; - } - } - } - cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on - the 286+ core, but not here. */ - break; - - case 0xe0: /* LOOPNE & LOOPE */ - case 0xe1: - /* decrement_register16() */ - --CX; - do_cycles_i(2); - - zero_cond = !(cpu_state.flags & Z_FLAG); - if (opcode == 0xe1) - zero_cond = !zero_cond; - - /* read_operand8() */ - cpu_data = pfq_fetchb(); - - if ((CX != 0x0000) && zero_cond) { - new_ip = cpu_state.pc + ((int8_t) cpu_data); - reljmp(new_ip, 1); - jump = 1; - } else - do_cycle_i(); - break; - - case 0xe2: /* LOOP */ - /* decrement_register16() */ - --CX; - do_cycles_i(2); - - /* read_operand8() */ - cpu_data = pfq_fetchb(); - - if (CX != 0x0000) { - new_ip = cpu_state.pc + ((int8_t) cpu_data); - reljmp(new_ip, 1); - jump = 1; - } - if (!jump) - do_cycle(); - break; - - case 0xe3: /* JCXZ */ - do_cycles_i(2); - /* read_operand8() */ - cpu_data = pfq_fetchb(); - - do_cycle_i(); - - if (CX != 0x0000) { - new_ip = cpu_state.pc + ((int8_t) cpu_data); - reljmp(new_ip, 1); - jump = 1; - } else - do_cycle_i(); - break; - - case 0xe4: /* IN al, imm8 */ - bits = 8; - /* read_operand8() */ - cpu_data = pfq_fetchb(); - do_cycles_i(2); - - /* biu_io_read_u8() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 0, cpu_state.eaaddr); - /* set_register8() */ - break; - - case 0xe5: /* IN ax, imm8 */ - bits = 16; - /* read_operand16() */ - cpu_data = pfq_fetchb(); - do_cycles_i(2); - - /* biu_io_read_u16() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 0, cpu_state.eaaddr); - /* set_register16() */ - break; - - case 0xe6: /* OUT imm8, al */ - bits = 8; - /* read_operand8() */ - cpu_data = pfq_fetchb(); - /* read_operand8() */ - tempb = AL; - do_cycles_i(2); - - /* biu_io_write_u8() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 1, cpu_state.eaaddr); - break; - - case 0xe7: /* OUT imm8, ax */ - bits = 16; - /* read_operand8() */ - cpu_data = pfq_fetchb(); - /* read_operand16() */ - tempw = AX; - do_cycles_i(2); - - /* biu_io_write_u16() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 1, cpu_state.eaaddr); - break; - - case 0xe8: /* CALL rel16 */ - /* read_operand16() */ - rel16 = (int16_t) pfq_fetchw(); - - pfq_do_suspend(); - do_cycles_i(4); - - old_cs = CS; - old_ip = cpu_state.pc; - - new_ip = cpu_state.pc + rel16; - - set_ip(new_ip); - pfq_clear(); - do_cycles_i(3); - - push(&old_ip); - jump = 1; - break; - - case 0xe9: /* JMP rel16 */ - /* read_operand16() */ - rel16 = (int16_t) pfq_fetchw(); - new_ip = cpu_state.pc + rel16; - - reljmp(new_ip, 1); - jump = 1; - break; - - case 0xea: /* JMP far [addr16:16] */ - /* read_operand_faraddr() */ - addr = pfq_fetchw(); - tempw = pfq_fetchw(); - load_cs(tempw); - pfq_do_suspend(); - set_ip(addr); - - do_cycles_i(2); - pfq_clear(); - do_cycle_i(); - jump = 1; - break; - - case 0xeb: /* JMP rel8 */ - /* read_operand8() */ - rel8 = (int8_t) pfq_fetchb(); - new_ip = cpu_state.pc + rel8; - - reljmp(new_ip, 1); - jump = 1; - break; - - case 0xec: /* IN al, dx */ - bits = 8; - /* read_operand8() */ - cpu_data = DX; - /* biu_io_read_u8() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 0, cpu_state.eaaddr); - /* set_register8() */ - break; - - case 0xed: /* IN ax, dx */ - bits = 16; - /* read_operand16() */ - cpu_data = DX; - /* biu_io_read_u16() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 0, cpu_state.eaaddr); - /* set_register16() */ - break; - - case 0xee: /* OUT dx, al */ - bits = 8; - /* read_operand8() */ - cpu_data = DX; - /* read_operand8() */ - tempb = AL; - do_cycle_i(); - - /* biu_io_write_u8() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 1, cpu_state.eaaddr); - break; - - case 0xef: /* OUT dx, ax */ - bits = 16; - /* read_operand8() */ - cpu_data = DX; - /* read_operand16() */ - tempw = AX; - do_cycle_i(); - - /* biu_io_write_u16() */ - cpu_state.eaaddr = cpu_data; - cpu_io(bits, 1, cpu_state.eaaddr); - break; - - case 0xf0: - case 0xf1: /* LOCK - F1 is alias */ - in_lock = 1; - do_cycle(); - completed = 0; - break; - - case 0xf2: /* REPNE */ - case 0xf3: /* REPE */ - in_rep = (opcode == 0xf2 ? 1 : 2); - completed = 0; - rep_c_flag = 0; - break; - - case 0xf4: /* HLT */ - if (repeating) { - do_cycle(); - do_cycle(); - do_cycle(); - if (irq_pending()) { - check_interrupts(); - do_cycles(7); - } else { - repeating = 1; - completed = 0; - } - } else { - pfq_do_suspend(); - do_cycles(2); - repeating = 1; - completed = 0; - } - break; - - case 0xf5: /* CMC */ - cpu_state.flags ^= C_FLAG; - break; - - case 0xf6: /* Miscellaneuous Opcode Extensions, r/m8, imm8 */ - bits = 8; - do_mod_rm(); - negate = !!in_rep; - - switch (rmdat & 0x38) { - case 0x00: /* TEST */ - case 0x08: - /* read_operand8() */ - cpu_data = get_ea(); - /* read_operand8() */ - cpu_src = pfq_fetch(); - - do_cycles_i(2); - - /* math_op8() */ - test(bits, cpu_data, cpu_src); - break; - case 0x10: /* NOT */ - case 0x18: /* NEG */ - /* read_operand8() */ - cpu_data = get_ea(); - /* math_op8() */ - if ((rmdat & 0x38) == 0x10) - cpu_data = ~cpu_data; - else { - cpu_src = cpu_data; - cpu_dest = 0; - sub(bits); - } - - if (addr_mode_match()) - do_cycles_i(2); - - /* write_operand8() */ - set_ea(cpu_data); - break; - - case 0x20: /* MUL */ - case 0x28: /* IMUL */ - /* read_operand8() */ - cpu_data = get_ea(); - - /* mul8() */ - old_flags = cpu_state.flags; - mul(get_accum(bits), cpu_data); - prod16 = ((cpu_dest & 0xff) << 8) | (cpu_data & 0xff); - if (negate) - prod16 = -prod16; - cpu_dest = prod16 >> 8; - cpu_data = prod16 & 0xff; - AL = (uint8_t) cpu_data; - AH = (uint8_t) cpu_dest; - set_co_mul(bits, AH != ((AL & 0x80) == 0 || - (rmdat & 0x38) == 0x20 ? 0 : 0xff)); - if (!is_nec) - cpu_data = AH; - } - set_sf(bits); - set_pf(); - /* NOTE: When implementing the V20, care should be taken to not change - the zero flag. */ - if (is_nec) - cpu_state.flags = (cpu_state.flags & ~Z_FLAG) | (old_flags & Z_FLAG); - break; - - case 0x30: /* DIV */ - case 0x38: /* IDIV */ - /* read_operand8() */ - cpu_data = get_ea(); - - cpu_src = cpu_data; - if (x86_div(AL, AH)) { - if (negate) - AL = -AL; - do_cycle(i); - } - break; - } - break; - - case 0xf7: /* Miscellaneuous Opcode Extensions, r/m16, imm16 */ - bits = 16; - do_mod_rm(); - negate = !!in_rep; - - switch (rmdat & 0x38) { - case 0x00: /* TEST */ - case 0x08: - /* read_operand16() */ - cpu_data = get_ea(); - /* read_operand16() */ - cpu_src = pfq_fetch(); - - do_cycle_i(); - - /* math_op16() */ - test(bits, cpu_data, cpu_src); - break; - case 0x10: /* NOT */ - case 0x18: /* NEG */ - /* read_operand16() */ - cpu_data = get_ea(); - /* math_op16() */ - if ((rmdat & 0x38) == 0x10) - cpu_data = ~cpu_data; - else { - cpu_src = cpu_data; - cpu_dest = 0; - sub(bits); - } - - if (addr_mode_match()) - do_cycles_i(2); - - /* write_operand16() */ - set_ea(cpu_data); - break; - - case 0x20: /* MUL */ - case 0x28: /* IMUL */ - /* read_operand16() */ - cpu_data = get_ea(); - - /* mul8() */ - old_flags = cpu_state.flags; - mul(get_accum(bits), cpu_data); - prod32 = (((uint32_t) cpu_dest) << 16) | cpu_data; - if (negate) - prod32 = -prod32; - cpu_dest = prod32 >> 16; - cpu_data = prod32 & 0xffff; - AX = cpu_data; - DX = cpu_dest; - set_co_mul(bits, DX != ((AX & 0x8000) == 0 || - (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); - cpu_data = DX; - } - set_sf(bits); - set_pf(); - /* NOTE: When implementing the V20, care should be taken to not change - the zero flag. */ - if (is_nec) - cpu_state.flags = (cpu_state.flags & ~Z_FLAG) | (old_flags & Z_FLAG); - break; - - case 0x30: /* DIV */ - case 0x38: /* IDIV */ - /* read_operand16() */ - cpu_data = get_ea(); - - cpu_src = cpu_data; - if (x86_div(AX, DX)) { - if (negate) - AX = -AX; - do_cycle(i); - } - break; - } - break; - - case 0xf8: /* CLCSTC */ - case 0xf9: - set_cf(opcode & 1); - break; - - case 0xfa: /* CLISTI */ - case 0xfb: - set_if(opcode & 1); - break; - - case 0xfc: /* CLDSTD */ - case 0xfd: - set_df(opcode & 1); - break; - - case 0xfe: - bits = 8; - do_mod_rm(); - switch (rmdat & 0x38) { - case 0x00: /* INC rm */ - case 0x08: /* DEC rm */ - /* read_operand8() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - /* math_op8() */ - if ((rmdat & 0x38) == 0x00) { - cpu_data = cpu_dest + cpu_src; - set_of_add(bits); - } else { - cpu_data = cpu_dest - cpu_src; - set_of_sub(bits); - } - do_af(); - set_pzs(bits); - if (addr_mode_match()) - do_cycles_i(2); - /* write_operand8() */ - set_ea(cpu_data); - break; - case 0x10: /* CALL rm */ - /* read_operand8() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - cpu_data_opff_rm(); - - cpu_state.oldpc = cpu_state.pc; - push((uint16_t *) &(cpu_state.oldpc)); - - pfq_do_suspend(); - do_cycles(4); - pfq_clear(); - - set_ip(cpu_data | 0xff00); - jump = 1; - break; - case 0x18: /* CALL rmd */ - if (cpu_mod == 3) { - /* biu_read_u8() */ - cpu_state.eaaddr = 0x0004; - tempb = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); - - old_cs = CS & 0x00ff; - push(&old_cs); - old_ip = cpu_state.pc & 0x00ff; - push(&old_ip); - - pfq_do_suspend(); - do_cycles(4); - pfq_clear(); - - read_ea_8to16(); - set_ip(cpu_data); - } else { - /* read_operand8() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - new_ip = cpu_data | 0xff00; - - do_cycles_i(3); - - /* biu_read_u8() */ - read_ea2(bits); - cpu_data |= 0xff00; - new_cs = cpu_data; - - do_cycle_i(); - pfq_do_suspend(); - do_cycles_i(3); - - old_cs = CS & 0x00ff; - push(&old_cs); - old_ip = cpu_state.pc & 0x00ff; - - load_cs(new_cs); - set_ip(new_ip); - - do_cycles_i(3); - pfq_clear(); - do_cycles_i(3); - - push(&old_ip); - - jump = 1; - } - break; - case 0x20: /* JMP rm */ - /* read_operand8() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - cpu_data_opff_rm(); - - pfq_do_suspend(); - set_ip(cpu_data | 0xff00); - - do_cycles(4); - pfq_clear(); - jump = 1; - break; - case 0x28: /* JMP rmd */ - if (cpu_mod == 3) { - /* biu_read_u8() */ - cpu_state.eaaddr = 0x0004; - tempb = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); - - pfq_do_suspend(); - do_cycles(4); - pfq_clear(); - - read_ea_8to16(); - set_ip(cpu_data); - } else { - /* read_operand8() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - new_ip = cpu_data | 0xff00; - - do_cycles_i(3); - - /* biu_read_u8() */ - read_ea2(bits); - cpu_data |= 0xff00; - new_cs = cpu_data; - - pfq_do_suspend(); - do_cycles(4); - pfq_clear(); - - load_cs(new_cs); - set_ip(new_ip); - jump = 1; - } - break; - case 0x30: /* PUSH rm */ - case 0x38: - /* read_operand8() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - self_cycles_i(3); - cpu_data &= 0x00ff; - push((uint16_t *) &cpu_data); - break; - } - break; - - case 0xff: - bits = 16; - do_mod_rm(); - switch (rmdat & 0x38) { - case 0x00: /* INC rm */ - case 0x08: /* DEC rm */ - /* read_operand16() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - /* math_op16() */ - if ((rmdat & 0x38) == 0x00) { - cpu_data = cpu_dest + cpu_src; - set_of_add(bits); - } else { - cpu_data = cpu_dest - cpu_src; - set_of_sub(bits); - } - do_af(); - set_pzs(bits); - if (addr_mode_match()) - do_cycles_i(2); - /* write_operand16() */ - set_ea(cpu_data); - break; - case 0x10: /* CALL rm */ - /* read_operand16() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - cpu_data_opff_rm(); - - pfq_do_suspend(); - do_cycles(4); - - cpu_state.oldpc = cpu_state.pc; - - old_ip = cpu_state.pc; - set_ip(cpu_data); - pfq_clear(); - do_cycles_i(3); - - push((&old_ip); - - jump = 1; - break; - case 0x18: /* CALL rmd */ - if (cpu_mod == 3) { - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - new_ip = cpu_data; - - /* biu_read_u16() */ - cpu_state.eaaddr = 0x0004; - new_cs = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); - - do_cycle_i(); - pfq_do_suspend(); - do_cycles_i(3); - - push(&CS); - old_ip = cpu_state.pc; - set_ip(new_ip); - - load_cs(new_cs); - - do_cycles_i(3); - pfq_clear(); - do_cycles_i(3); - - push(&old_ip); - } else { - do_cycle_i(); - /* read_operand_farptr() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - new_ip = cpu_data; - read_ea2(bits); - new_cs = cpu_data; - - do_cycle_i(); - - pfq_do_suspend(); - do_cycles_i(3); - - push(&CS); - - load_cs(new_cs); - old_ip = cpu_state.pc; - set_ip(new_ip); - do_cycles_i(3); - pfq_flush(); - do_cycles_i(3); - push(&old_ip); - } - jump = 1; - break; - case 0x20: /* JMP rm */ - /* read_operand16() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - cpu_data_opff_rm(); - - pfq_do_suspend(); - do_cycle_i(); - set_ip(cpu_data); - pfq_clear(); - jump = 1; - break; - case 0x28: /* JMP rmd */ - if (cpu_mod == 3) { - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - new_ip = cpu_data; - - do_cycle(); - pfq_do_suspend(); - do_cycle(); - - /* biu_read_u16() */ - cpu_state.eaaddr = 0x0004; - new_cs = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); - - push(&CS); - pfq_clear(); - } else { - do_cycle_i(); - pfq_do_suspend(); - do_cycle_i(); - - /* read_operand_farptr() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - new_ip = cpu_data; - read_ea2(bits); - new_cs = cpu_data; - - load_cs(new_cs); - set_ip(new_ip); - pfq_clear(); - } - jump = 1; - break; - case 0x30: /* PUSH rm */ - case 0x38: - /* read_operand16() */ - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - self_cycles_i(3); - - if (cpu_rm == 4) - cpu_rm -= 2; - push((uint16_t *) &cpu_data); - break; - } - break; - - default: - x808x_log("Illegal opcode: %02X\n", opcode); - pfq_fetchb(); - wait(8, 0); - break; - } - - if (completed) { - finalize(); - - repeating = 0; - ovr_seg = NULL; - in_rep = 0; - rep_c_flag = 0; - if (in_lock) - clear_lock = 1; - clock_end(); - check_interrupts(); - - if (noint) - noint = 0; - - cpu_alu_op = 0; - } - -#ifdef USE_GDBSTUB - if (gdbstub_instruction()) - return; -#endif - } -}