From 8f21db55272226c215ceaf9f0669be52e1e109e7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 26 Aug 2023 16:40:29 +0200 Subject: [PATCH] Interim 808x fixes - just enough to fix the two most outstanding problems (Prehistorik 2 and Snatch-It! being broken). --- src/cpu/808x.c | 1084 +++++++++++++++++++++++++++++++----------------- 1 file changed, 699 insertions(+), 385 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 718469496..fd2aa52fb 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -92,6 +92,9 @@ static uint16_t mem_addr = 0; static int schedule_fetch = 1; static int pasv = 0; +static int pfq_idle = 1; +static int pfq_delay = 0; + #define BUS_OUT 1 #define BUS_HIGH 2 #define BUS_WIDE 4 @@ -135,7 +138,6 @@ enum { wait(val, 0); \ } -#if 0 # define CLOCK_CYCLES_FPU(val) \ { \ wait(val, 0); \ @@ -154,19 +156,6 @@ enum { } # define CONCURRENCY_CYCLES(c) fpu_cycles = (c) -#else -# define CLOCK_CYCLES(val) \ - { \ - wait(val, 0); \ - } - -# define CLOCK_CYCLES_FPU(val) \ - { \ - wait(val, 0); \ - } - -# define CONCURRENCY_CYCLES(c) -#endif typedef int (*OpFn)(uint32_t fetchdat); @@ -381,6 +370,20 @@ run_bus_cycle(int io_type) case BUS_T1: access_code = !!(io_type & BUS_CODE); break; + case BUS_T2: + switch (io_type & BUS_ACCESS_TYPE) { + case BUS_IO: + if (io_type & BUS_OUT) + bus_do_io(io_type); + break; + case BUS_MEM: + if (io_type & BUS_OUT) + bus_do_mem(io_type); + break; + default: + break; + } + break; case BUS_T3: switch (io_type & BUS_ACCESS_TYPE) { case BUS_CODE: @@ -388,10 +391,12 @@ run_bus_cycle(int io_type) last_was_code = 1; break; case BUS_IO: - bus_do_io(io_type); + if (!(io_type & BUS_OUT)) + bus_do_io(io_type); break; case BUS_MEM: - bus_do_mem(io_type); + if (!(io_type & BUS_OUT)) + bus_do_mem(io_type); break; case BUS_PIC: pic_data = pic_irq_ack(); @@ -441,6 +446,12 @@ cycles_idle(int c) } } +static void +pfq_schedule(int on) +{ + schedule_fetch = on && prefetching && (pfq_pos < pfq_size); +} + static void cycles_biu(int bus, int init) { @@ -467,7 +478,7 @@ cycles_biu(int bus, int init) break; } - schedule_fetch = 0; + pfq_schedule(0); access_code = 0; } } @@ -479,14 +490,22 @@ cycles_biu(int bus, int init) run_bus_cycle(BUS_CODE); } - if (BUS_CYCLE == BUS_T3) - schedule_fetch = prefetching && (pfq_pos < pfq_size); + if (BUS_CYCLE == BUS_T2) + pfq_schedule(1); run_dma_cycle(pasv); BUS_CYCLE_NEXT; } +static void +cycles_pasv(void) +{ + pfq_schedule(1); + + run_dma_cycle(1); +} + /* Bus: 0 CPU cycles without bus access. 1 CPU cycle T1-T4, bus access. @@ -503,7 +522,10 @@ wait(int c, int bus) for (int d = 0; d < c; d++) { x808x_log("[%04X:%04X] %02X cycle %i BIU\n", CS, cpu_state.pc, opcode, d); - cycles_biu(bus, !d); + if (!bus && !schedule_fetch && (BUS_CYCLE == BUS_T1)) + cycles_pasv(); + else + cycles_biu(bus, !d); x808x_log("[%04X:%04X] %02X cycle %i EU\n", CS, cpu_state.pc, opcode, d); cycles_forward(1); } @@ -554,7 +576,7 @@ cpu_io(int bits, int out, uint16_t port) } else { bus_request_type = BUS_IO | BUS_OUT; wait(4, 1); - schedule_fetch = 0; + pfq_schedule(0); bus_request_type = BUS_IO | BUS_OUT | BUS_HIGH; wait(4, 1); } @@ -570,7 +592,7 @@ cpu_io(int bits, int out, uint16_t port) } else { bus_request_type = BUS_IO; wait(4, 1); - schedule_fetch = 0; + pfq_schedule(0); bus_request_type = BUS_IO | BUS_HIGH; wait(4, 1); } @@ -627,7 +649,7 @@ readmemw(uint32_t s, uint16_t a) } else { bus_request_type = BUS_MEM | BUS_HIGH; wait(4, 1); - schedule_fetch = 0; + pfq_schedule(0); bus_request_type = BUS_MEM; wait(4, 1); } @@ -688,6 +710,9 @@ writememb(uint32_t s, uint32_t a, uint8_t v) { uint32_t addr = s + a; + // if (CS == DEBUG_SEG) + // fatal("writememb(%08X, %08X, %02X)\n", s, a, v); + mem_seg = s; mem_addr = a; mem_data = v; @@ -714,7 +739,7 @@ writememw(uint32_t s, uint32_t a, uint16_t v) } else { bus_request_type = BUS_MEM | BUS_OUT | BUS_HIGH; wait(4, 1); - schedule_fetch = 0; + pfq_schedule(0); bus_request_type = BUS_MEM | BUS_OUT; wait(4, 1); } @@ -761,12 +786,18 @@ pfq_write(void) *(uint16_t *) &(pfq[pfq_pos]) = tempw; pfq_ip = (pfq_ip + 2) & 0xffff; pfq_pos += 2; + + if (pfq_pos >= (pfq_size - 1)) + pfq_schedule(0); } else if (!fetch_word && (pfq_pos < pfq_size)) { /* The 8088 fetches 1 byte at a time, and only if there's at least 1 byte free in the queue. */ pfq[pfq_pos] = readmembf(pfq_ip); pfq_ip = (pfq_ip + 1) & 0xffff; pfq_pos++; + + if (pfq_pos >= pfq_size) + pfq_schedule(0); } if (pfq_pos >= pfq_size) @@ -859,17 +890,25 @@ static void pfq_clear(void) { pfq_pos = 0; - prefetching = 0; - schedule_fetch = 0; BUS_CYCLE_T1; } +static void +pfq_do_suspend(void) +{ + while (BUS_CYCLE != BUS_T1) + wait(1, 0); + wait(1, 0); + pfq_schedule(0); + prefetching = 0; +} + static void pfq_suspend(void) { + pfq_do_suspend(); pfq_clear(); - cycles_idle(3); } static void @@ -918,12 +957,9 @@ reset_808x(int hard) cpu_state.flags |= MD_FLAG; rammask = 0xfffff; - prefetching = 1; + pasv = 0; - schedule_fetch = 1; - pasv = 0; - - cpu_alu_op = 0; + cpu_alu_op = 0; use_custom_nmi_vector = 0x00; custom_nmi_vector = 0x00000000; @@ -937,6 +973,9 @@ reset_808x(int hard) mem_data = 0; mem_seg = 0; mem_addr = 0; + + prefetching = 1; + pfq_schedule(1); } static void @@ -944,7 +983,7 @@ set_ip(uint16_t new_ip) { pfq_ip = cpu_state.pc = new_ip; prefetching = 1; - schedule_fetch = prefetching && (pfq_pos < pfq_size); + pfq_schedule(1); } /* Memory refresh read - called by reads and writes on DMA channel 0. */ @@ -1115,8 +1154,10 @@ seteab(uint8_t val) { if (cpu_mod == 3) { setr8(cpu_rm, val); - } else + } else { + wait(1, 0); writememb(easeg, cpu_state.eaaddr, val); + } } /* Writes a word to the effective address. */ @@ -1125,8 +1166,10 @@ seteaw(uint16_t val) { if (cpu_mod == 3) cpu_state.regs[cpu_rm].w = val; - else + else { + wait(1, 0); writememw(easeg, cpu_state.eaaddr, val); + } } static void @@ -1181,78 +1224,170 @@ pop(void) return readmemw(ss, cpu_state.eaaddr); } -/* Calls an interrupt. */ static void -interrupt(uint16_t addr) +nearcall(uint16_t new_ip) { - uint16_t old_cs; - uint16_t old_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); +} + +/* 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 tempf; + uint16_t old_ip; - addr <<= 2; - cpu_state.eaaddr = addr; - old_cs = CS; + if (!skip_first) + wait(1, 0); + wait(2, 0); + + cpu_state.eaaddr = vector & 0xffff; new_ip = readmemw(0, cpu_state.eaaddr); wait(1, 0); cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; new_cs = readmemw(0, cpu_state.eaaddr); - prefetching = 0; - pfq_clear(); - ovr_seg = NULL; + + pfq_do_suspend(); wait(2, 0); - tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); - wait(5, 0); - push(&old_cs); - old_ip = cpu_state.pc; - load_cs(new_cs); - pfq_suspend(); - set_ip(new_ip); + wait(1, 0); + + 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; + + wait(3, 0); + cpu_state.eaaddr = vector & 0xffff; + new_ip = readmemw(0, cpu_state.eaaddr); + wait(1, 0); + cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; + new_cs = readmemw(0, cpu_state.eaaddr); + pfq_do_suspend(); wait(2, 0); + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + + /* FARCALL2 */ + wait(4, 0); + push(&CS); + load_cs(new_cs); + wait(1, 0); + + /* NEARCALL */ + old_ip = cpu_state.pc & 0xffff; + wait(2, 0); + set_ip(new_ip); + pfq_clear(); + wait(3, 0); push(&old_ip); } +static void +int1(void) +{ + wait(2, 0); + intr_routine(1, 1); +} + +static void +int2(void) +{ + wait(2, 0); + intr_routine(2, 1); +} + +static void +int3(void) +{ + wait(4, 0); + intr_routine(3, 0); +} + +static void +int_o(void) +{ + wait(4, 0); + + if (cpu_state.flags & V_FLAG) { + wait(2, 0); + intr_routine(4, 0); + } +} + void interrupt_808x(uint16_t addr) { - interrupt(addr); + intr_routine(addr, 0); } static void custom_nmi(void) { - uint16_t old_cs; - uint16_t old_ip; + uint16_t tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); uint16_t new_cs; uint16_t new_ip; - uint16_t tempf; + uint16_t old_ip; + + wait(1, 0); + wait(2, 0); cpu_state.eaaddr = 0x0002; - old_cs = CS; (void) readmemw(0, cpu_state.eaaddr); new_ip = custom_nmi_vector & 0xffff; wait(1, 0); cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; (void) readmemw(0, cpu_state.eaaddr); - new_cs = custom_nmi_vector >> 16; - prefetching = 0; - pfq_clear(); - ovr_seg = NULL; + new_cs = custom_nmi_vector >> 16; + + pfq_do_suspend(); wait(2, 0); - tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); - wait(5, 0); - push(&old_cs); - old_ip = cpu_state.pc; - load_cs(new_cs); - pfq_suspend(); - set_ip(new_ip); - wait(2, 0); - push(&old_ip); + wait(1, 0); + + farcall2(new_cs, new_ip); } static int @@ -1285,7 +1420,7 @@ check_interrupts(void) if (irq_pending()) { if ((cpu_state.flags & T_FLAG) && !noint) { wait(2, 0); - interrupt(1); + intr_routine(1, 0); return; } if (nmi && nmi_enable && nmi_mask) { @@ -1294,7 +1429,7 @@ check_interrupts(void) if (use_custom_nmi_vector) custom_nmi(); else - interrupt(2); + intr_routine(2, 0); #ifndef OLD_NMI_BEHAVIOR nmi = 0; #endif @@ -1318,76 +1453,52 @@ check_interrupts(void) wait(5, 0); /* Here is where temp should be filled, but we cheat. */ opcode = 0x00; - interrupt(temp); + intr_routine(temp, 0); } } } -static uint16_t tmpc; - -static int -rep_setup(void) +static void +rep_end(void) { - if (repeating) - return 0; - wait(2, 0); - if (in_rep == 0) - return 0; - wait(4, 0); - tmpc = CX; - if (tmpc == 0) - return 1; - wait(3, 0); - return 0; + repeating = 0; + in_rep = 0; + completed = 1; } static int -rep_interrupt(void) +rep_start(void) { - if (!irq_pending()) { - repeating = 1; - completed = 0; - return 0; + if (!repeating) { + wait(2, 0); + + if (in_rep != 0) { + if (CX == 0) { + wait(4, 0); + rep_end(); + return 0; + } else + wait(7, 0); + } } + completed = 1; - CX = tmpc; - pfq_clear(); - if (is_nec && (ovr_seg != NULL)) - set_ip(cpu_state.pc - 3); - else - set_ip(cpu_state.pc - 2); return 1; } -static int -rep_action(UNUSED(int bits)) +static void +rep_interrupt(void) { - uint16_t t; + pfq_do_suspend(); + wait(4, 0); + pfq_clear(); - if (in_rep == 0) - return 0; - wait(2, 0); - t = CX; - if (irq_pending() && (repeating != 0)) { - pfq_clear(); - if (is_nec && (ovr_seg != NULL)) - set_ip(cpu_state.pc - 3); - else - set_ip(cpu_state.pc - 2); - t = 0; - } - if (t == 0) { - wait(1, 0); - completed = 1; - repeating = 0; - return 1; - } - --CX; - completed = 0; - wait(2, 0); - if (!repeating) - wait(2, 0); - return 0; + if (is_nec && (ovr_seg != NULL)) + set_ip((cpu_state.pc - 3) & 0xffff); + else + set_ip((cpu_state.pc - 2) & 0xffff); + + rep_end(); } static uint16_t @@ -1747,7 +1858,7 @@ x86_div(uint16_t l, uint16_t h) if (h >= cpu_src) { if (opcode != 0xd4) wait(1, 0); - interrupt(0); + intr_routine(0, 0); return 0; } if (opcode != 0xd4) @@ -1783,7 +1894,7 @@ x86_div(uint16_t l, uint16_t h) if (top_bit(l, bit_count)) { if (cpu_mod == 3) wait(1, 0); - interrupt(0); + intr_routine(0, 0); return 0; } wait(7, 0); @@ -1829,6 +1940,17 @@ lods(int bits) 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) { @@ -1840,6 +1962,23 @@ stos(int bits) DI = string_increment(bits); } +static void +ins(int bits) +{ + cpu_state.eaaddr = SI; + cpu_io(bits, 0, cpu_state.eaaddr); + SI = string_increment(bits); +} + +static void +outs(int bits) +{ + cpu_state.eaaddr = DI; + cpu_data = (bits == 16) ? AX : AL; + cpu_io(bits, 1, cpu_state.eaaddr); + DI = string_increment(bits); +} + static void aa(void) { @@ -1933,6 +2072,51 @@ cpu_outw(uint16_t port, uint16_t val) return outw(port, val); } +/* The FARRET microcode routine. */ +static void +farret(int far) +{ + uint8_t far2 = !!(opcode & 0x08); + uint16_t new_cs; + uint16_t new_ip; + + wait(1, 0); + new_ip = pop(); + pfq_do_suspend(); + wait(2, 0); + + if ((!!far) != far2) + fatal("Far call distance mismatch (%i = %i)\n", !!far, far2); + + if (far) { + wait(1, 0); + new_cs = pop(); + + pfq_clear(); + wait(2, 0); + } else { + pfq_clear(); + wait(2, 0); + } + + wait(2, 0); + load_cs(new_cs); + set_ip(new_ip); +} + +/* The IRET microcode routine. */ +static void +iret_routine(void) +{ + wait(1, 0); + farret(1); + if (is_nec) + cpu_state.flags = pop() | 0x8002; + else + cpu_state.flags = pop() | 0x0002; + wait(1, 0); +} + /* Executes instructions up to the specified number of cycles. */ void execx86(int cycs) @@ -1985,9 +2169,6 @@ execx86(int cycs) if (!repeating) { cpu_state.oldpc = cpu_state.pc; -#if 0 - opcode = pfq_fetchb(); -#endif opcode = pfq_fetchb_common(); handled = 0; oldc = cpu_state.flags & C_FLAG; @@ -2039,7 +2220,7 @@ execx86(int cycs) regval = get_reg(cpu_reg); if (lowbound > regval || highbound < regval) { cpu_state.pc = cpu_state.oldpc; - interrupt(5); + intr_routine(5, 0); } handled = 1; break; @@ -2095,58 +2276,62 @@ execx86(int cycs) case 0x6c: case 0x6d: /* INM dst, DW/INS dst, DX */ - bits = 8 << (opcode & 1); handled = 1; - if (!repeating) - wait(2, 0); + bits = 8 << (opcode & 1); + if (rep_start()) { + ins(bits); + set_accum(bits, cpu_data); + wait(3, 0); - if (rep_action(bits)) - break; - else if (!repeating) - wait(7, 0); + if (in_rep != 0) { + completed = 0; + repeating = 1; - if (bits == 16) { - writememw(es, DI, cpu_inw(DX)); - DI += (cpu_state.flags & D_FLAG) ? -2 : 2; - } else { - wait(4, 0); - writememb(es, DI, inb(DX)); - DI += (cpu_state.flags & D_FLAG) ? -1 : 1; + wait(1, 0); + CX--; + + if (irq_pending()) { + wait(2, 0); + rep_interrupt(); + } else { + wait(2, 0); + + if (CX == 0) + rep_end(); + else + wait(1, 0); + } + } } - - if (in_rep == 0) - break; - - repeating = 1; - clock_end(); break; case 0x6e: case 0x6f: /* OUTM DW, src/OUTS DX, src */ - dest_seg = ovr_seg ? *ovr_seg : ds; - bits = 8 << (opcode & 1); - handled = 1; - if (!repeating) - wait(2, 0); + handled = 1; + bits = 8 << (opcode & 1); + if (rep_start()) { + cpu_data = AX; + wait(1, 0); + outs(bits); + if (in_rep != 0) { + completed = 0; + repeating = 1; - if (rep_action(bits)) - break; - else if (!repeating) - wait(7, 0); + wait(1, 0); + if (irq_pending()) { + wait(1, 0); + rep_interrupt(); + } - if (bits == 16) { - cpu_outw(DX, readmemw(dest_seg, SI)); - SI += (cpu_state.flags & D_FLAG) ? -2 : 2; - } else { - wait(4, 0); - outb(DX, readmemb(dest_seg, SI)); - SI += (cpu_state.flags & D_FLAG) ? -1 : 1; + wait(1, 0); + CX--; + if (CX == 0) + rep_end(); + else + wait(1, 0); + } else + wait(1, 0); } - if (in_rep == 0) - break; - - repeating = 1; - clock_end(); break; case 0xc8: /* ENTER/PREPARE */ @@ -2595,92 +2780,164 @@ execx86(int cycs) completed = 0; break; - case 0x00: - case 0x01: + case 0x00: /* ADD r/m8, r8; r8, r/m8; al, imm8 */ case 0x02: - case 0x03: - case 0x08: - case 0x09: + case 0x04: + case 0x08: /* OR r/m8, r8; r8, r/m8; al, imm8 */ case 0x0a: - case 0x0b: - case 0x10: - case 0x11: + case 0x0c: + case 0x10: /* ADC r/m8, r8; r8, r/m8; al, imm8 */ case 0x12: - case 0x13: - case 0x18: - case 0x19: + case 0x14: + case 0x18: /* SBB r/m8, r8; r8, r/m8; al, imm8 */ case 0x1a: - case 0x1b: - case 0x20: - case 0x21: + case 0x1c: + case 0x20: /* AND r/m8, r8; r8, r/m8; al, imm8 */ case 0x22: - case 0x23: - case 0x28: - case 0x29: + case 0x24: + case 0x28: /* SUB r/m8, r8; r8, r/m8; al, imm8 */ case 0x2a: - case 0x2b: - case 0x30: - case 0x31: + case 0x2c: + case 0x30: /* XOR r/m8, r8; r8, r/m8; al, imm8 */ case 0x32: - case 0x33: - case 0x38: - case 0x39: - case 0x3a: - case 0x3b: - /* alu rm, r / r, rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - tempw = get_ea(); - cpu_alu_op = (opcode >> 3) & 7; - if ((opcode & 2) == 0) { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); + case 0x34: + bits = 8; + wait(1, 0); + if (opcode & 0x04) { + cpu_data = pfq_fetch(); + cpu_dest = get_accum(bits); /* AX/AL */ + cpu_src = cpu_data; } else { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; + 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); + } } - wait(1, 0); - if (cpu_mod != 3) - wait(1, 0); + cpu_alu_op = (opcode >> 3) & 7; + wait(2, 0); + if (cpu_mod == 3) + wait(2, 0); + alu_op(bits); - wait(1, 0); - if (cpu_alu_op != 7) { - if ((opcode & 2) == 0) { - if (cpu_mod == 3) - wait(2, 0); - set_ea(cpu_data); - } else + 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 0x04: + case 0x01: /* ADD r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x03: case 0x05: - case 0x0c: + case 0x09: /* OR r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x0b: case 0x0d: - case 0x14: + case 0x11: /* ADC r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x13: case 0x15: - case 0x1c: + case 0x19: /* SBB r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x1b: case 0x1d: - case 0x24: + case 0x21: /* AND r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x23: case 0x25: - case 0x2c: + case 0x29: /* SUB r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x2b: case 0x2d: - case 0x34: + case 0x31: /* XOR r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x33: case 0x35: - case 0x3c: - case 0x3d: - /* alu A, imm */ - bits = 8 << (opcode & 1); + bits = 16; wait(1, 0); - cpu_data = pfq_fetch(); - cpu_dest = get_accum(bits); /* AX/AL */ - cpu_src = cpu_data; + 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); + } + } cpu_alu_op = (opcode >> 3) & 7; + wait(2, 0); + if (cpu_mod == 3) + wait(2, 0); + alu_op(bits); - if (cpu_alu_op != 7) + 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 0x38: /* CMP r/m8, r8; r8, r/m8; al, imm8 */ + case 0x3a: + case 0x3c: + bits = 8; wait(1, 0); + 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); + } + } + cpu_alu_op = (opcode >> 3) & 7; + wait(2, 0); + + alu_op(bits); + break; + + case 0x39: /* CMP r/m16, r16; r16, r/m16; ax, imm16 */ + case 0x3b: + case 0x3d: + bits = 16; + wait(1, 0); + 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); + } + } + cpu_alu_op = (opcode >> 3) & 7; + wait(2, 0); + + alu_op(bits); break; case 0x27: /*DAA*/ @@ -2934,7 +3191,7 @@ execx86(int cycs) do_mod_rm(); wait(1, 0); if (cpu_mod != 3) - wait(3, 0); + wait(2, 0); set_ea(get_reg(cpu_reg)); break; case 0x8A: @@ -2967,10 +3224,9 @@ execx86(int cycs) case 0x8E: /*MOV sreg,w*/ do_mod_rm(); tempw = geteaw(); - if ((rmdat & 0x18) == 0x08) { + if ((rmdat & 0x18) == 0x08) load_cs(tempw); - pfq_pos = 0; - } else + else load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); wait(1, 0); if (cpu_mod != 3) @@ -3100,35 +3356,32 @@ execx86(int cycs) case 0xA4: case 0xA5: /* MOVS */ - case 0xAC: - case 0xAD: /* LODS */ bits = 8 << (opcode & 1); - if (rep_setup()) - break; - if (in_rep != 0 && (BUS_CYCLE == BUS_T4)) - wait(1, 0); - lods(bits); - if ((opcode & 8) == 0) { + if (rep_start()) { + lods(bits); wait(1, 0); stos(bits); - } else - set_accum(bits, cpu_data); - wait(3, 0); - if (in_rep == 0) - break; - --tmpc; - if (rep_interrupt()) - break; - CX = tmpc; - if (tmpc == 0) { - completed = 1; wait(1, 0); - if ((opcode & 8) != 0) - wait(2, 0); - } else { - wait(2, 0); - if ((opcode & 8) != 0) - wait(2, 0); + + if (in_rep != 0) { + completed = 0; + repeating = 1; + + CX--; + + if (irq_pending()) { + wait(2, 0); + rep_interrupt(); + } else { + wait(2, 0); + + if (CX == 0) + rep_end(); + else + wait(1, 0); + } + } else + wait(1, 0); } break; @@ -3137,39 +3390,53 @@ execx86(int cycs) case 0xAE: case 0xAF: /* SCAS */ bits = 8 << (opcode & 1); - if (rep_setup()) - break; - tmpa = AX; - if ((opcode & 8) == 0) { - wait(1, 0); - lods(bits); - tmpa = cpu_data; - } - wait(2, 0); - cpu_state.eaaddr = DI; - cpu_data = readmem(es); - DI = string_increment(bits); - cpu_src = cpu_data; - cpu_dest = tmpa; - sub(bits); - wait(2, 0); - if (in_rep == 0) { + if (rep_start()) { + if ((opcode & 8) == 0) { + wait(1, 0); + lods(bits); + tmpa = cpu_data; + } else + tmpa = AX; wait(2, 0); - break; - } - --tmpc; - CX = tmpc; - if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { + lods_di(bits); + cpu_src = cpu_data; + cpu_dest = tmpa; wait(3, 0); - break; + sub(bits); + + if (in_rep) { + uint8_t end = 0; + + completed = 0; + repeating = 1; + + wait(1, 0); + + CX--; + + if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { + completed = 1; + wait(1, 0); + end = 1; + } + + if (!end) { + wait(1, 0); + + if (irq_pending()) { + wait(1, 0); + rep_interrupt(); + } + + wait(1, 0); + if (CX == 0) + rep_end(); + else + wait(1, 0); + } else + wait(1, 0); + } } - if (rep_interrupt()) - break; - wait(4, 0); - if (tmpc == 0) - completed = 1; - else - wait(1, 0); break; case 0xA8: @@ -3185,24 +3452,59 @@ execx86(int cycs) case 0xAA: case 0xAB: /* STOS */ bits = 8 << (opcode & 1); - if (rep_setup()) - break; - cpu_data = AX; - if (in_rep == 0 && (BUS_CYCLE == BUS_T4)) + if (rep_start()) { + cpu_data = AX; wait(1, 0); - stos(bits); - wait(3, 0); - if (in_rep == 0) - break; - --tmpc; - if (rep_interrupt()) - break; - CX = tmpc; - if (tmpc == 0) { - completed = 1; - wait(1, 0); - } else - wait(2, 0); + stos(bits); + if (in_rep != 0) { + completed = 0; + repeating = 1; + + wait(1, 0); + if (irq_pending()) { + wait(1, 0); + rep_interrupt(); + } + + wait(1, 0); + CX--; + if (CX == 0) + rep_end(); + else + wait(1, 0); + } else + wait(1, 0); + } + break; + + case 0xAC: + case 0xAD: /* LODS */ + bits = 8 << (opcode & 1); + if (rep_start()) { + lods(bits); + set_accum(bits, cpu_data); + wait(3, 0); + + if (in_rep != 0) { + completed = 0; + repeating = 1; + + wait(1, 0); + CX--; + + if (irq_pending()) { + wait(2, 0); + rep_interrupt(); + } else { + wait(2, 0); + + if (CX == 0) + rep_end(); + else + wait(1, 0); + } + } + } break; case 0xB0: @@ -3235,39 +3537,55 @@ execx86(int cycs) break; case 0xC0: - case 0xC1: case 0xC2: - case 0xC3: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - /* RET */ + /* RETN imm16 */ bits = 8 + (opcode & 0x08); wait(1, 0); - if (!(opcode & 1)) { - cpu_src = pfq_fetchw(); - wait(2, 0); - } - if ((opcode & 9) == 9) - wait(2, 0); - pfq_clear(); - new_ip = pop(); + cpu_src = pfq_fetchw(); wait(1, 0); - if ((opcode & 8) == 0) { - new_cs = CS; - if (opcode & 1) - wait(1, 0); - } else { - wait(2, 0); - new_cs = pop(); - } - if (!(opcode & 1)) - SP += cpu_src; - load_cs(new_cs); + new_ip = pop(); + pfq_do_suspend(); + wait(2, 0); + pfq_clear(); + wait(3, 0); + SP += cpu_src; set_ip(new_ip); break; + case 0xC1: + case 0xC3: + /* RETN */ + bits = 8 + (opcode & 0x08); + wait(1, 0); + cpu_src = pfq_fetchw(); + new_ip = pop(); + pfq_do_suspend(); + wait(1, 0); + pfq_clear(); + wait(2, 0); + set_ip(new_ip); + break; + + case 0xC8: + case 0xCA: + /* RETF imm16 */ + bits = 8 + (opcode & 0x08); + wait(1, 0); + cpu_src = pfq_fetchw(); + farret(1); + SP += cpu_src; + wait(1, 0); + break; + + case 0xC9: + case 0xCB: + /* RETF */ + bits = 8 + (opcode & 0x08); + wait(1, 0); + wait(1, 0); + farret(1); + break; + case 0xC4: case 0xC5: /* LsS rw, rmd */ @@ -3288,44 +3606,36 @@ execx86(int cycs) do_mod_rm(); wait(1, 0); cpu_data = pfq_fetch(); - wait(2, 0); + wait((opcode == 0xc6) ? 2 : 1, 0); set_ea(cpu_data); break; case 0xCC: /*INT 3*/ - wait(7, 0); - interrupt(3); + wait(1, 0); + wait(4, 0); + int3(); break; case 0xCD: /*INT*/ wait(1, 0); temp = pfq_fetchb(); wait(1, 0); - if (BUS_CYCLE != BUS_T4) - wait(1, 0); - wait(1, 0); - - interrupt(temp); + sw_int(temp); break; case 0xCE: /*INTO*/ - wait(3, 0); - if (cpu_state.flags & V_FLAG) { - wait(5, 0); - interrupt(4); - } + wait(1, 0); + if (cpu_state.flags & V_FLAG) + sw_int(4); break; case 0xCF: /*IRET*/ - wait(3, 0); - pfq_clear(); - new_ip = pop(); - new_cs = pop(); - load_cs(new_cs); - set_ip(new_ip); + wait(1, 0); + wait(1, 0); + farret(1); if (is_nec) cpu_state.flags = pop() | 0x8002; else cpu_state.flags = pop() | 0x0002; - wait(5, 0); + wait(1, 0); noint = 1; nmi_enable = 1; break; @@ -3628,12 +3938,13 @@ execx86(int cycs) case 0xEA: /*JMP far*/ wait(1, 0); addr = pfq_fetchw(); - wait(1, 0); tempw = pfq_fetchw(); load_cs(tempw); - pfq_clear(); - wait(4, 0); + pfq_do_suspend(); set_ip(addr); + wait(2, 0); + pfq_clear(); + wait(1, 0); break; case 0xEB: /*JMP rel*/ wait(1, 0); @@ -3658,21 +3969,21 @@ execx86(int cycs) break; case 0xF4: /*HLT*/ - if (!repeating) { - if ((BUS_CYCLE == BUS_T4) || !last_was_code) - cpu_data = 1; - else - cpu_data = 2; - wait(2, 0); - pfq_clear(); - } - wait(1, 0); - if (irq_pending()) { + if (repeating) { wait(1, 0); - if (cpu_data == 2) - wait(1, 0); - check_interrupts(); + wait(1, 0); + wait(1, 0); + if (irq_pending()) { + check_interrupts(); + wait(7, 0); + } else { + repeating = 1; + completed = 0; + } } else { + wait(1, 0); + pfq_do_suspend(); + wait(2, 0); repeating = 1; completed = 0; } @@ -3720,12 +4031,14 @@ execx86(int cycs) if (opcode & 1) { AX = cpu_data; DX = cpu_dest; - set_co_mul(bits, DX != ((AX & 0x8000) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); + set_co_mul(bits, DX != ((AX & 0x8000) == 0 || + (rmdat & 0x38) == 0x20 ? 0 : 0xffff)); cpu_data = DX; } else { AL = (uint8_t) cpu_data; AH = (uint8_t) cpu_dest; - set_co_mul(bits, AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); + set_co_mul(bits, AH != ((AL & 0x80) == 0 || + (rmdat & 0x38) == 0x20 ? 0 : 0xff)); if (!is_nec) cpu_data = AH; } @@ -3793,8 +4106,9 @@ execx86(int cycs) case 0x10: /* CALL rm */ cpu_data_opff_rm(); wait(2, 0); + pfq_do_suspend(); + wait(4, 0); pfq_clear(); - wait(5, 0); cpu_state.oldpc = cpu_state.pc; set_ip(cpu_data); wait(2, 0); @@ -3808,28 +4122,28 @@ execx86(int cycs) cpu_data |= 0xff00; new_cs = cpu_data; wait(1, 0); - pfq_clear(); + pfq_do_suspend(); + wait(3, 0); push(&(CS)); - wait(4, 0); - cpu_state.oldpc = cpu_state.pc; load_cs(new_cs); + wait(3, 0); + pfq_clear(); + wait(3, 0); + push((uint16_t *) &(cpu_state.pc)); set_ip(new_ip); - wait(1, 0); - push((uint16_t *) &(cpu_state.oldpc)); break; case 0x20: /* JMP rm */ cpu_data_opff_rm(); - wait(2, 0); + pfq_do_suspend(); + wait(4, 0); pfq_clear(); - if (BUS_CYCLE != BUS_T4) - wait(1, 0); set_ip(cpu_data); break; case 0x28: /* JMP rmd */ new_ip = cpu_data; - wait(3, 0); + pfq_do_suspend(); + wait(4, 0); pfq_clear(); - wait(1, 0); read_ea2(bits); if (!(opcode & 1)) cpu_data |= 0xff00;