diff --git a/.ci/Jenkinsfile b/.ci/Jenkinsfile index cc3e415cd..9084b80f3 100644 --- a/.ci/Jenkinsfile +++ b/.ci/Jenkinsfile @@ -147,7 +147,7 @@ def runBuild(args) { if (isUnix()) return sh(returnStatus: true, script: "chmod u+x '$WORKSPACE/.ci/build.sh' && exec '$WORKSPACE/.ci/build.sh' $args") else - return bat(returnStatus: true, script: "C:\\msys64\\msys2_shell.cmd -msys2 -defterm -here -no-start -c 'exec \"\$(cygpath -u \\'%WORKSPACE%\\')/.ci/build.sh\" $args'") + return bat(returnStatus: true, script: "C:\\msys64\\msys2_shell.cmd -ucrt64 -defterm -here -no-start -c 'exec \"\$(cygpath -u \\'%WORKSPACE%\\')/.ci/build.sh\" $args'") } def failStage() { diff --git a/CMakeLists.txt b/CMakeLists.txt index 667df5221..b503b3e39 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -36,7 +36,7 @@ if(MUNT_EXTERNAL) endif() project(86Box - VERSION 5.4 + VERSION 6.0 DESCRIPTION "Emulator of x86-based systems" HOMEPAGE_URL "https://86box.net" LANGUAGES C CXX) @@ -180,7 +180,6 @@ cmake_dependent_option(ISAMEM_RAMPAGE "AST Rampage" cmake_dependent_option(ISAMEM_IAB "Intel Above Board" ON "DEV_BRANCH" OFF) cmake_dependent_option(ISAMEM_BRAT "BocaRAM/AT" ON "DEV_BRANCH" OFF) cmake_dependent_option(OPL4ML "OPL4-ML daughterboard" ON "DEV_BRANCH" OFF) -cmake_dependent_option(PCL "Generic PCL5e Printer" ON "DEV_BRANCH" OFF) cmake_dependent_option(SIO_DETECT "Super I/O Detection Helper" ON "DEV_BRANCH" OFF) cmake_dependent_option(WACOM "Wacom Input Devices" ON "DEV_BRANCH" OFF) cmake_dependent_option(XL24 "ATI VGA Wonder XL24 (ATI-28800-6)" ON "DEV_BRANCH" OFF) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f4f32b2e..de6541e36 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,7 +2,7 @@ The 86Box project welcomes contributions from anyone, as long as some basic guidelines are followed. ## Emulated hardware -In order to accept new emulated hardware, the following criteria must be met: +In order to accept new emulated hardware or a request thereof, the following criteria must be met: * A ROM must be available and be added to [our ROM repository](https://github.com/86Box/roms) * Documentation must be available or it must be feasible to reverse engineer with a reasonable amount of time and effort diff --git a/debian/changelog b/debian/changelog index c0c4bf945..72e246145 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,5 +1,5 @@ -86box (5.4) UNRELEASED; urgency=medium +86box (6.0) UNRELEASED; urgency=medium * Bump release. - -- Jasmine Iwanek Tue, 23 Dec 2025 00:27:45 +0100 + -- Jasmine Iwanek Wed, 28 Jan 2026 08:45:23 +0100 diff --git a/src/86box.c b/src/86box.c index 80244dc8b..24e8be26a 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1704,6 +1704,8 @@ pc_reset_hard_init(void) ide_hard_reset(); + lpt_ports_reset(); + /* Initialize the actual machine and its basic modules. */ machine_init(); diff --git a/src/chipset/laserxt.c b/src/chipset/laserxt.c index a5308e2f0..bf2636b91 100644 --- a/src/chipset/laserxt.c +++ b/src/chipset/laserxt.c @@ -296,6 +296,37 @@ lxt_init(const device_t *info) } static const device_config_t laserxt_config[] = { + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "laserxt_126", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "1.08", + .internal_name = "laserxt_108", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { "roms/machines/ltxt/ltxt-v1.08.bin", "" } + }, + { + .name = "1.26", + .internal_name = "laserxt_126", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 8192, + .files = { "roms/machines/ltxt/27c64.bin", "" } + }, + { .files_no = 0 } + } + }, { .name = "ems_1_base", .description = "EMS 1 Address", diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 4e2e830d0..8cb153cd2 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -40,6 +40,7 @@ #include <86box/gdbstub.h> #include <86box/plat_fallthrough.h> #include <86box/plat_unused.h> +#include "vx0_biu.h" /* Is the CPU 8088 or 8086. */ int is8086 = 0; @@ -51,27 +52,39 @@ uint32_t custom_nmi_vector = 0x00000000; static uint8_t pfq[6]; /* Variables to aid with the prefetch queue operation. */ -static int biu_cycles = 0, pfq_pos = 0; +static int biu_cycles = 0; +int pfq_pos = 0; + +int oldc; +int cpu_alu_op; +int completed = 1; +int in_rep = 0; +int repeating = 0; +int rep_c_flag = 0; +int noint = 0; +int tempc_fpu = 0; +int clear_lock = 0; +int is_new_biu = 0; + +uint32_t cpu_src = 0; +uint32_t cpu_dest = 0; + +uint32_t cpu_data = 0; + +uint32_t * ovr_seg = NULL; + +/* Pointer tables needed for segment overrides. */ +uint32_t * opseg[4]; +x86seg * _opseg[4]; /* The IP equivalent of the current prefetch queue position. */ static uint16_t pfq_ip; -/* Pointer tables needed for segment overrides. */ -static uint32_t *opseg[4]; -static x86seg *_opseg[4]; +static int pfq_size; -static int noint = 0; -static int cpu_alu_op, pfq_size; +uint16_t last_addr = 0x0000; -static uint32_t cpu_src = 0, cpu_dest = 0; -static uint32_t cpu_data = 0; - -static uint16_t last_addr = 0x0000; - -static uint32_t *ovr_seg = NULL; -static int prefetching = 1, completed = 1; -static int in_rep = 0, repeating = 0, rep_c_flag = 0; -static int oldc, clear_lock = 0; +static int prefetching = 1; static int refresh = 0, cycdiff; static i8080 emulated_processor; @@ -135,8 +148,6 @@ static bool cpu_md_write_disable = 1; typedef int (*OpFn)(uint32_t fetchdat); -static int tempc_fpu = 0; - #ifdef ENABLE_808X_LOG #if 0 void dumpregs(int); @@ -204,67 +215,12 @@ prefetch_queue_get_size(void) } static void set_if(int cond); -void -sync_from_i8080(void) -{ - AL = emulated_processor.a; - BH = emulated_processor.h; - BL = emulated_processor.l; - CH = emulated_processor.b; - CL = emulated_processor.c; - DH = emulated_processor.d; - DL = emulated_processor.e; - BP = emulated_processor.sp; - - cpu_state.pc = emulated_processor.pc; - cpu_state.flags &= 0xFF00; - cpu_state.flags |= emulated_processor.sf << 7; - cpu_state.flags |= emulated_processor.zf << 6; - cpu_state.flags |= emulated_processor.hf << 4; - cpu_state.flags |= emulated_processor.pf << 2; - cpu_state.flags |= 1 << 1; - cpu_state.flags |= emulated_processor.cf << 0; - set_if(emulated_processor.iff); -} - -void -sync_to_i8080(void) -{ - if (!is_nec) - return; - emulated_processor.a = AL; - emulated_processor.h = BH; - emulated_processor.l = BL; - emulated_processor.b = CH; - emulated_processor.c = CL; - emulated_processor.d = DH; - emulated_processor.e = DL; - emulated_processor.sp = BP; - emulated_processor.pc = cpu_state.pc; - emulated_processor.iff = !!(cpu_state.flags & I_FLAG); - - emulated_processor.sf = (cpu_state.flags >> 7) & 1; - emulated_processor.zf = (cpu_state.flags >> 6) & 1; - emulated_processor.hf = (cpu_state.flags >> 4) & 1; - emulated_processor.pf = (cpu_state.flags >> 2) & 1; - emulated_processor.cf = (cpu_state.flags >> 0) & 1; - - emulated_processor.interrupt_delay = noint; -} - - uint16_t get_last_addr(void) { return last_addr; } -static void -clock_start(void) -{ - cycdiff = cycles; -} - static void clock_end(void) { @@ -293,15 +249,19 @@ fetch_and_bus(int c, int bus) pfq_add(c, !bus); if (bus < 2) { clock_end(); - clock_start(); + cycdiff = cycles; } } static void wait_cycs(int c, int bus) { - cycles -= c; - fetch_and_bus(c, bus); + if (is_new_biu) + wait_vx0(c); + else { + cycles -= c; + fetch_and_bus(c, bus); + } } /* This is for external subtraction of cycles. */ @@ -337,55 +297,63 @@ resub_cycles(int old_cycles) static void cpu_io(int bits, int out, uint16_t port) { - int old_cycles = cycles; + if (is_new_biu) + cpu_io_vx0(bits, out, port); + else { + int old_cycles = cycles; - if (out) { - wait_cycs(is_mazovia ? 5 : 4, 1); - if (bits == 16) { - if (is8086 && !(port & 1)) { - old_cycles = cycles; - outw(port, AX); + if (out) { + wait_cycs(is_mazovia ? 5 : 4, 1); + if (bits == 16) { + if (is8086 && !(port & 1)) { + old_cycles = cycles; + outw(port, AX); + } else { + wait_cycs(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + outb(port++, AL); + outb(port, AH); + } } else { - wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; - outb(port++, AL); - outb(port, AH); + outb(port, AL); } } else { - old_cycles = cycles; - outb(port, AL); - } - } else { - wait_cycs(is_mazovia ? 5 : 4, 1); - if (bits == 16) { - if (is8086 && !(port & 1)) { - old_cycles = cycles; - AX = inw(port); + wait_cycs(is_mazovia ? 5 : 4, 1); + if (bits == 16) { + if (is8086 && !(port & 1)) { + old_cycles = cycles; + AX = inw(port); + } else { + wait_cycs(is_mazovia ? 5 : 4, 1); + old_cycles = cycles; + AL = inb(port++); + AH = inb(port); + } } else { - wait_cycs(is_mazovia ? 5 : 4, 1); old_cycles = cycles; - AL = inb(port++); - AH = inb(port); + AL = inb(port); } - } else { - old_cycles = cycles; - AL = inb(port); } + + resub_cycles(old_cycles); } - - resub_cycles(old_cycles); } /* Reads a byte from the memory and advances the BIU. */ static uint8_t -readmemb(uint32_t a) +readmemb(uint32_t s, uint32_t a) { - uint8_t ret; + if (is_new_biu) + return readmemb_vx0(s, a); + else { + uint8_t ret; - wait_cycs(4, 1); - ret = read_mem_b(a); + wait_cycs(4, 1); + ret = read_mem_b(s + a); - return ret; + return ret; + } } /* Reads a byte from the memory but does not advance the BIU. */ @@ -404,18 +372,22 @@ readmembf(uint32_t a) static uint16_t readmemw(uint32_t s, uint16_t a) { - uint16_t ret; - - wait_cycs(4, 1); - if (is8086 && !(a & 1)) - ret = read_mem_w(s + a); + if (is_new_biu) + return readmemw_vx0(s, a); else { - wait_cycs(4, 1); - ret = read_mem_b(s + a); - ret |= read_mem_b(s + ((is186 && !is_nec) ? (a + 1) : (a + 1) & 0xffff)) << 8; - } + uint16_t ret; - return ret; + wait_cycs(4, 1); + if (is8086 && !(a & 1)) + ret = read_mem_w(s + a); + else { + wait_cycs(4, 1); + ret = read_mem_b(s + a); + ret |= read_mem_b(s + ((is186 && !is_nec) ? (a + 1) : (a + 1) & 0xffff)) << 8; + } + + return ret; + } } static uint16_t @@ -431,88 +403,120 @@ readmemwf(uint16_t a) static uint16_t readmem(uint32_t s) { - if (opcode & 1) - return readmemw(s, cpu_state.eaaddr); - else - return (uint16_t) readmemb(s + cpu_state.eaaddr); + if (is_new_biu) + return readmem_vx0(s); + else { + if (opcode & 1) + return readmemw(s, cpu_state.eaaddr); + else + return (uint16_t) readmemb(s, cpu_state.eaaddr); + } } static uint32_t readmeml(uint32_t s, uint16_t a) { - uint32_t temp; + if (is_new_biu) + return readmeml_vx0(s, a); + else { + uint32_t temp; - temp = (uint32_t) (readmemw(s, a + 2)) << 16; - temp |= readmemw(s, a); + temp = (uint32_t) (readmemw(s, a + 2)) << 16; + temp |= readmemw(s, a); - return temp; + return temp; + } } static uint64_t readmemq(uint32_t s, uint16_t a) { - uint64_t temp; + if (is_new_biu) + return readmemq_vx0(s, a); + else { + uint64_t temp; - temp = (uint64_t) (readmeml(s, a + 4)) << 32; - temp |= readmeml(s, a); + temp = (uint64_t) (readmeml(s, a + 4)) << 32; + temp |= readmeml(s, a); - return temp; + return temp; + } } /* Writes a byte to the memory and advances the BIU. */ static void writememb(uint32_t s, uint32_t a, uint8_t v) { - uint32_t addr = s + a; + if (is_new_biu) + writememb_vx0(s, a, v); + else { + uint32_t addr = s + a; - wait_cycs(4, 1); - write_mem_b(addr, v); + wait_cycs(4, 1); + write_mem_b(addr, v); - if ((addr >= 0xf0000) && (addr <= 0xfffff)) - last_addr = addr & 0xffff; + if ((addr >= 0xf0000) && (addr <= 0xfffff)) + last_addr = addr & 0xffff; + } } /* Writes a word to the memory and advances the BIU. */ static void writememw(uint32_t s, uint32_t a, uint16_t v) { - uint32_t addr = s + a; - - wait_cycs(4, 1); - if (is8086 && !(a & 1)) - write_mem_w(addr, v); + if (is_new_biu) + writememw_vx0(s, a, v); else { - write_mem_b(addr, v & 0xff); - wait_cycs(4, 1); - addr = s + ((is186 && !is_nec) ? (a + 1) : ((a + 1) & 0xffff)); - write_mem_b(addr, v >> 8); - } + uint32_t addr = s + a; - if ((addr >= 0xf0000) && (addr <= 0xfffff)) - last_addr = addr & 0xffff; + wait_cycs(4, 1); + if (is8086 && !(a & 1)) + write_mem_w(addr, v); + else { + write_mem_b(addr, v & 0xff); + wait_cycs(4, 1); + addr = s + ((is186 && !is_nec) ? (a + 1) : ((a + 1) & 0xffff)); + write_mem_b(addr, v >> 8); + } + + if ((addr >= 0xf0000) && (addr <= 0xfffff)) + last_addr = addr & 0xffff; + } } static void writemem(uint32_t s, uint16_t v) { - if (opcode & 1) - writememw(s, cpu_state.eaaddr, v); - else - writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); + if (is_new_biu) + writemem_vx0(s, v); + else { + if (opcode & 1) + writememw(s, cpu_state.eaaddr, v); + else + writememb(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); + } } static void writememl(uint32_t s, uint32_t a, uint32_t v) { - writememw(s, a, v & 0xffff); - writememw(s, a + 2, v >> 16); + if (is_new_biu) + writememl_vx0(s, a, v); + else { + writememw(s, a, v & 0xffff); + writememw(s, a + 2, v >> 16); + } } static void writememq(uint32_t s, uint32_t a, uint64_t v) { - writememl(s, a, v & 0xffffffff); - writememl(s, a + 4, v >> 32); + if (is_new_biu) + writememl_vx0(s, a, v); + else { + writememl(s, a, v & 0xffffffff); + writememl(s, a + 4, v >> 32); + } } static void @@ -539,13 +543,17 @@ pfq_write(void) static uint8_t pfq_read(void) { - uint8_t temp = pfq[0]; + if (is_new_biu) + return biu_pfq_read(); + else { + uint8_t temp = pfq[0]; - for (int i = 0; i < (pfq_size - 1); i++) - pfq[i] = pfq[i + 1]; - pfq_pos--; - cpu_state.pc = (cpu_state.pc + 1) & 0xffff; - return temp; + for (int i = 0; i < (pfq_size - 1); i++) + pfq[i] = pfq[i + 1]; + pfq_pos--; + cpu_state.pc = (cpu_state.pc + 1) & 0xffff; + return temp; + } } /* Fetches a byte from the prefetch queue, or from memory if the queue has @@ -553,28 +561,36 @@ pfq_read(void) static uint8_t pfq_fetchb_common(void) { - uint8_t temp; + if (is_new_biu) + return biu_pfq_fetchb_common(); + else { + uint8_t temp; - if (pfq_pos == 0) { - /* Reset prefetch queue internal position. */ - pfq_ip = cpu_state.pc; - /* Fill the queue. */ - wait_cycs(4 - (biu_cycles & 3), 0); + if (pfq_pos == 0) { + /* Reset prefetch queue internal position. */ + pfq_ip = cpu_state.pc; + /* Fill the queue. */ + wait_cycs(4 - (biu_cycles & 3), 0); + } + + /* Fetch. */ + temp = pfq_read(); + return temp; } - - /* Fetch. */ - temp = pfq_read(); - return temp; } static uint8_t pfq_fetchb(void) { - uint8_t ret; + if (is_new_biu) + return biu_pfq_fetchb(); + else { + uint8_t ret; - ret = pfq_fetchb_common(); - wait_cycs(1, 0); - return ret; + ret = pfq_fetchb_common(); + wait_cycs(1, 0); + return ret; + } } /* Fetches a word from the prefetch queue, or from memory if the queue has @@ -582,22 +598,30 @@ pfq_fetchb(void) static uint16_t pfq_fetchw(void) { - uint16_t temp; + if (is_new_biu) + return biu_pfq_fetchw(); + else { + uint16_t temp; - temp = pfq_fetchb_common(); - wait_cycs(1, 0); - temp |= (pfq_fetchb_common() << 8); + temp = pfq_fetchb_common(); + wait_cycs(1, 0); + temp |= (pfq_fetchb_common() << 8); - return temp; + return temp; + } } static uint16_t pfq_fetch(void) { - if (opcode & 1) - return pfq_fetchw(); - else - return (uint16_t) pfq_fetchb(); + if (is_new_biu) + return biu_pfq_fetch(); + else { + if (opcode & 1) + return pfq_fetchw(); + else + return (uint16_t) pfq_fetchb(); + } } /* Adds bytes to the prefetch queue based on the instruction's cycle count. */ @@ -616,12 +640,26 @@ pfq_add(int c, int add) } } +static void +pfq_clear_pos(void) +{ + if (is_new_biu) + biu_queue_flush(); + else + pfq_pos = 0; +} + /* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ static void pfq_clear(void) { - pfq_pos = 0; - prefetching = 0; + if (is_new_biu) { + biu_suspend_fetch(); + biu_queue_flush(); + } else { + pfq_pos = 0; + prefetching = 0; + } } static void @@ -640,12 +678,12 @@ load_seg(uint16_t seg, x86seg *s) uint8_t fetch_i8080_opcode(UNUSED(void* priv), uint16_t addr) { - return readmemb(cs + addr); + return readmemb(cs, addr); } uint8_t fetch_i8080_data(UNUSED(void* priv), uint16_t addr) { - return readmemb(ds + addr); + return readmemb(ds, addr); } void put_i8080_data(UNUSED(void* priv), uint16_t addr, uint8_t val) @@ -668,6 +706,7 @@ static void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val) void reset_808x(int hard) { + is_new_biu = 0; biu_cycles = 0; in_rep = 0; completed = 1; @@ -715,8 +754,12 @@ reset_808x(int hard) static void set_ip(uint16_t new_ip) { - pfq_ip = cpu_state.pc = new_ip; - prefetching = 1; + if (is_new_biu) + cpu_state.pc = new_ip; + else { + pfq_ip = cpu_state.pc = new_ip; + prefetching = 1; + } } /* Memory refresh read - called by reads and writes on DMA channel 0. */ @@ -810,7 +853,7 @@ geteab(void) if (cpu_mod == 3) return (getr8(cpu_rm)); - return readmemb(easeg + cpu_state.eaaddr); + return readmemb(easeg, cpu_state.eaaddr); } /* Reads a word from the effective address. */ @@ -854,7 +897,7 @@ read_ea(int memory_only, int bits) if (bits == 16) cpu_data = readmemw(easeg, cpu_state.eaaddr); else - cpu_data = readmemb(easeg + cpu_state.eaaddr); + cpu_data = readmemb(easeg, cpu_state.eaaddr); return; } if (!memory_only) { @@ -872,7 +915,7 @@ read_ea2(int bits) if (bits == 16) cpu_data = readmemw(easeg, cpu_state.eaaddr); else - cpu_data = readmemb(easeg + cpu_state.eaaddr); + cpu_data = readmemb(easeg, cpu_state.eaaddr); } /* Writes a byte to the effective address. */ @@ -952,57 +995,39 @@ static void access(int num, UNUSED(int bits)) { switch (num) { - case 0: + case 0: case 61: - case 63: - case 64: + case 63 ... 64: case 67: case 69: - case 71: - case 72: + case 71 ... 72: default: break; - case 1: - case 6: - case 7: - case 8: - case 9: + case 1: + case 6 ... 9: case 17: - case 20: - case 21: + case 20 ... 21: case 24: case 28: - case 47: - case 48: - case 49: - case 50: - case 51: - case 55: - case 56: + case 47 ... 51: + case 55 ... 56: case 62: case 66: case 68: wait_cycs(1, 0); break; - case 3: + case 3: case 11: case 15: - case 22: - case 23: - case 25: - case 26: + case 22 ... 23: + case 25 ... 26: case 35: - case 44: - case 45: - case 46: - case 52: - case 53: - case 54: + case 44 ... 46: + case 52 ... 54: wait_cycs(2, 0); break; case 16: - case 18: - case 19: + case 18 ... 19: case 27: case 32: case 37: @@ -1010,19 +1035,15 @@ access(int num, UNUSED(int bits)) wait_cycs(3, 0); break; case 10: - case 12: - case 13: - case 14: - case 29: - case 30: - case 33: - case 34: + case 12 ... 14: + case 29 ... 30: + case 33 ... 34: case 39: case 41: case 60: wait_cycs(4, 0); break; - case 4: + case 4: case 70: wait_cycs(5, 0); break; @@ -1039,7 +1060,10 @@ access(int num, UNUSED(int bits)) break; case 36: wait_cycs(1, 0); - pfq_clear(); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); wait_cycs(1, 0); if (cpu_mod != 3) wait_cycs(1, 0); @@ -1047,7 +1071,10 @@ access(int num, UNUSED(int bits)) break; case 43: wait_cycs(2, 0); - pfq_clear(); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); wait_cycs(1, 0); break; case 57: @@ -1062,14 +1089,20 @@ access(int num, UNUSED(int bits)) break; case 59: wait_cycs(2, 0); - pfq_clear(); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); if (cpu_mod != 3) wait_cycs(1, 0); wait_cycs(3, 0); break; case 65: wait_cycs(1, 0); - pfq_clear(); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); wait_cycs(2, 0); if (cpu_mod != 3) wait_cycs(1, 0); @@ -1085,11 +1118,6 @@ interrupt(uint16_t addr) uint16_t new_cs, new_ip; uint16_t tempf; - if (!(cpu_state.flags & MD_FLAG) && is_nec) { - sync_from_i8080(); - x808x_log("CALLN/INT#/NMI#\n"); - } - addr <<= 2; cpu_state.eaaddr = addr; old_cs = CS; @@ -1099,90 +1127,42 @@ interrupt(uint16_t addr) cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; access(6, 16); new_cs = readmemw(0, cpu_state.eaaddr); - prefetching = 0; - pfq_clear(); + if (is_new_biu) + biu_suspend_fetch(); + else { + prefetching = 0; + pfq_clear(); + } ovr_seg = NULL; - access(39, 16); + if (is_new_biu) + wait_cycs(2, 0); + else + access(39, 16); tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); push(&tempf); cpu_state.flags &= ~(I_FLAG | T_FLAG); if (is_nec) cpu_state.flags |= MD_FLAG; - access(40, 16); + if (is_new_biu) + wait_cycs(4, 0); + else + access(40, 16); push(&old_cs); old_ip = cpu_state.pc; load_cs(new_cs); - access(68, 16); + if (is_new_biu) + wait_cycs(3, 0); + else + access(68, 16); set_ip(new_ip); - access(41, 16); + if (is_new_biu) { + biu_queue_flush(); + wait_cycs(4, 0); + } else + access(41, 16); push(&old_ip); } -/* Ditto, but for breaking into emulation mode. */ -static void -interrupt_brkem(uint16_t addr) -{ - uint16_t old_cs, old_ip; - uint16_t new_cs, new_ip; - uint16_t tempf; - - addr <<= 2; - cpu_state.eaaddr = addr; - old_cs = CS; - access(5, 16); - new_ip = readmemw(0, cpu_state.eaaddr); - wait_cycs(1, 0); - cpu_state.eaaddr = (cpu_state.eaaddr + 2) & 0xffff; - access(6, 16); - new_cs = readmemw(0, cpu_state.eaaddr); - prefetching = 0; - pfq_clear(); - ovr_seg = NULL; - access(39, 16); - tempf = cpu_state.flags & (is_nec ? 0x8fd7 : 0x0fd7); - push(&tempf); - cpu_state.flags &= ~(MD_FLAG); - cpu_md_write_disable = 0; - access(40, 16); - push(&old_cs); - old_ip = cpu_state.pc; - load_cs(new_cs); - access(68, 16); - set_ip(new_ip); - access(41, 16); - push(&old_ip); - sync_to_i8080(); - x808x_log("BRKEM mode\n"); -} - -void -retem_i8080(void) -{ - sync_from_i8080(); - - prefetching = 0; - pfq_clear(); - - set_ip(pop()); - load_cs(pop()); - cpu_state.flags = pop(); - - emulated_processor.iff = !!(cpu_state.flags & I_FLAG); - - cpu_md_write_disable = 1; - - noint = 1; - nmi_enable = 1; - - x808x_log("RETEM mode\n"); -} - -void -interrupt_808x(uint16_t addr) -{ - interrupt(addr); -} - static void custom_nmi(void) { @@ -1190,11 +1170,6 @@ custom_nmi(void) uint16_t new_cs, new_ip; uint16_t tempf; - if (!(cpu_state.flags & MD_FLAG) && is_nec) { - sync_from_i8080(); - pclog("NMI# (CUTSOM)\n"); - } - cpu_state.eaaddr = 0x0002; old_cs = CS; access(5, 16); @@ -1318,10 +1293,15 @@ jump(uint16_t delta) { uint16_t old_ip; access(67, 8); - pfq_clear(); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); wait_cycs(5, 0); old_ip = cpu_state.pc; set_ip((cpu_state.pc + delta) & 0xffff); + if (is_new_biu) + biu_queue_flush(); return old_ip; } @@ -1759,7 +1739,7 @@ lods(int bits) 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); + cpu_data = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); SI = string_increment(bits); } @@ -1914,42 +1894,1468 @@ cpu_outw(uint16_t port, uint16_t val) resub_cycles(old_cycles); } +void +execx86_instruction(void) +{ + uint8_t temp = 0, temp2, old_af, nests; + uint16_t addr, tempw, new_cs, new_ip, handled = 0; + uint16_t tempw_int, size, tempbp, lowbound, old_flags; + uint16_t highbound, regval, orig_sp, wordtopush, immediate; + int bits; + uint32_t dest_seg; + + if (!repeating) + handled = 0; + + completed = 1; + // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); + + if (is186) { + switch (opcode) { + case 0x60: /* PUSHA/PUSH R */ + orig_sp = SP; + wait_cycs(1, 0); + push(&AX); + push(&CX); + push(&DX); + push(&BX); + push(&orig_sp); + push(&BP); + push(&SI); + push(&DI); + handled = 1; + break; + case 0x61: /* POPA/POP R */ + wait_cycs(9, 0); + DI = pop(); + SI = pop(); + BP = pop(); + (void) pop(); /* former orig_sp */ + BX = pop(); + DX = pop(); + CX = pop(); + AX = pop(); + handled = 1; + break; + + case 0x62: /* BOUND r/m */ + lowbound = 0; + highbound = 0; + regval = 0; + do_mod_rm(); + + lowbound = readmemw(easeg, cpu_state.eaaddr); + highbound = readmemw(easeg, cpu_state.eaaddr + 2); + regval = get_reg(cpu_reg); + if (lowbound > regval || highbound < regval) { + cpu_state.pc = cpu_state.oldpc; + interrupt(5); + } + handled = 1; + break; + + case 0x64: + case 0x65: + if (is_nec) { + /* REPC/REPNC */ + wait_cycs(1, 0); + in_rep = (opcode == 0x64 ? 1 : 2); + rep_c_flag = 1; + completed = 0; + handled = 1; + } + break; + + case 0x68: + wordtopush = pfq_fetchw(); + wait_cycs(1, 0); + push(&wordtopush); + handled = 1; + break; + + case 0x69: + immediate = 0; + bits = 16; + do_mod_rm(); + read_ea(0, 16); + immediate = pfq_fetchw(); + mul(cpu_data & 0xFFFF, immediate); + set_reg(cpu_reg, cpu_data); + set_co_mul(16, cpu_dest != 0); + handled = 1; + break; + + case 0x6a: + wordtopush = sign_extend(pfq_fetchb()); + push(&wordtopush); + handled = 1; + break; + + case 0x6b: /* IMUL reg16,reg16/mem16,imm8 */ + immediate = 0; + bits = 16; + do_mod_rm(); + read_ea(0, 16); + immediate = pfq_fetchb(); + mul(cpu_data & 0xFFFF, immediate); + set_reg(cpu_reg, cpu_data); + set_co_mul(16, cpu_dest != 0); + handled = 1; + break; + + case 0x6c ... 0x6d: /* INM dst, DW/INS dst, DX */ + bits = 8 << (opcode & 1); + handled = 1; + if (!repeating) + wait_cycs(2, 0); + + if (rep_action(bits)) + break; + else if (!repeating) + wait_cycs(7, 0); + + if (bits == 16) { + writememw(es, DI, cpu_inw(DX)); + DI += (cpu_state.flags & D_FLAG) ? -2 : 2; + } else { + writememb(es, DI, cpu_inb(DX)); + DI += (cpu_state.flags & D_FLAG) ? -1 : 1; + } + + if (in_rep == 0) + break; + + repeating = 1; + clock_end(); + break; + + case 0x6e ... 0x6f: /* OUTM DW, src/OUTS DX, src */ + dest_seg = ovr_seg ? *ovr_seg : ds; + bits = 8 << (opcode & 1); + handled = 1; + if (!repeating) + wait_cycs(2, 0); + + if (rep_action(bits)) + break; + else if (!repeating) + wait_cycs(7, 0); + + if (bits == 16) { + cpu_outw(DX, readmemw(dest_seg, SI)); + SI += (cpu_state.flags & D_FLAG) ? -2 : 2; + } else { + cpu_outb(DX, readmemb(dest_seg, SI)); + SI += (cpu_state.flags & D_FLAG) ? -1 : 1; + } + if (in_rep == 0) + break; + + repeating = 1; + clock_end(); + break; + + case 0xc8: /* ENTER/PREPARE */ + tempw_int = 0; + size = pfq_fetchw(); + nests = pfq_fetchb(); + + push(&BP); + tempw_int = SP; + if (nests > 0) { + while (--nests) { + tempbp = 0; + BP -= 2; + tempbp = readmemw(ss, BP); + push(&tempbp); + } + push(&tempw_int); + } + BP = tempw_int; + SP -= size; + handled = 1; + break; + + case 0xc0 ... 0xc1: /* rot imm8 */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait_cycs(1, 0); + access(53, bits); + cpu_data = get_ea(); + cpu_src = pfq_fetchb(); + + wait_cycs((cpu_mod != 3) ? 9 : 6, 0); + + if (!is_nec) + cpu_src &= 0x1f; + + 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; + } + if ((opcode & 2) != 0) + wait_cycs(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + handled = 1; + break; + + case 0xc9: /* LEAVE/DISPOSE */ + SP = BP; + BP = pop(); + handled = 1; + break; + } + } + if (!handled) { + if (!is186 && !is_nec && (opcode >= 0x60) && (opcode <= 0x6f)) + opcode |= 0x10; + + switch (opcode) { + case 0x06: + case 0x0e: + case 0x16: + case 0x1e: /* PUSH seg */ + access(29, 16); + push(&(_opseg[(opcode >> 3) & 0x03]->seg)); + break; + case 0x07: + case 0x0f: + case 0x17: + case 0x1f: /* POP seg */ + access(22, 16); + if (opcode == 0x0f) { + load_cs(pop()); + pfq_pos = 0; + } else + load_seg(pop(), _opseg[(opcode >> 3) & 0x03]); + wait_cycs(1, 0); + /* All POP segment instructions suppress interrupts for one instruction. */ + noint = 1; + break; + + case 0x26: /* ES: */ + case 0x2e: /* CS: */ + case 0x36: /* SS: */ + case 0x3e: /* DS: */ + wait_cycs(1, 0); + ovr_seg = opseg[(opcode >> 3) & 0x03]; + completed = 0; + break; + + case 0x00 ... 0x03: /* alu rm, r / r, rm */ + case 0x08 ... 0x0b: + case 0x10 ... 0x13: + case 0x18 ... 0x1b: + case 0x20 ... 0x23: + case 0x28 ... 0x2b: + case 0x30 ... 0x33: + case 0x38 ... 0x3b: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(46, bits); + tempw = get_ea(); + cpu_alu_op = (opcode >> 3) & 7; + if ((opcode & 2) == 0) { + cpu_dest = tempw; + cpu_src = get_reg(cpu_reg); + } else { + cpu_dest = get_reg(cpu_reg); + cpu_src = tempw; + } + if (cpu_mod != 3) + wait_cycs(2, 0); + wait_cycs(1, 0); + alu_op(bits); + if (cpu_alu_op != 7) { + if ((opcode & 2) == 0) { + access(10, bits); + set_ea(cpu_data); + if (cpu_mod == 3) + wait_cycs(1, 0); + } else { + set_reg(cpu_reg, cpu_data); + wait_cycs(1, 0); + } + } else + wait_cycs(1, 0); + break; + + case 0x04 ... 0x05: /* alu A, imm */ + case 0x0c ... 0x0d: + case 0x14 ... 0x15: + case 0x1c ... 0x1d: + case 0x24 ... 0x25: + case 0x2c ... 0x2d: + case 0x34 ... 0x35: + case 0x3c ... 0x3d: + bits = 8 << (opcode & 1); + wait_cycs(1, 0); + cpu_data = pfq_fetch(); + cpu_dest = get_accum(bits); /* AX/AL */ + cpu_src = cpu_data; + cpu_alu_op = (opcode >> 3) & 7; + alu_op(bits); + if (cpu_alu_op != 7) + set_accum(bits, cpu_data); + wait_cycs(1, 0); + break; + + case 0x27: /* DAA */ + cpu_dest = AL; + set_of(0); + old_af = !!(cpu_state.flags & A_FLAG); + if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { + cpu_src = 6; + cpu_data = cpu_dest + cpu_src; + set_of_add(8); + cpu_dest = cpu_data; + set_af(1); + } + if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { + cpu_src = 0x60; + cpu_data = cpu_dest + cpu_src; + set_of_add(8); + cpu_dest = cpu_data; + set_cf(1); + } + AL = cpu_dest; + set_pzs(8); + wait_cycs(3, 0); + break; + case 0x2f: /* DAS */ + cpu_dest = AL; + set_of(0); + old_af = !!(cpu_state.flags & A_FLAG); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_src = 6; + cpu_data = cpu_dest - cpu_src; + set_of_sub(8); + cpu_dest = cpu_data; + set_af(1); + } + if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { + cpu_src = 0x60; + cpu_data = cpu_dest - cpu_src; + set_of_sub(8); + cpu_dest = cpu_data; + set_cf(1); + } + AL = cpu_dest; + set_pzs(8); + wait_cycs(3, 0); + break; + case 0x37: /* AAA */ + wait_cycs(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_src = 6; + ++AH; + set_ca(); + } else { + cpu_src = 0; + clear_ca(); + wait_cycs(1, 0); + } + cpu_dest = AL; + cpu_data = cpu_dest + cpu_src; + set_of_add(8); + aa(); + break; + case 0x3f: /* AAS */ + wait_cycs(1, 0); + if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { + cpu_src = 6; + --AH; + set_ca(); + } else { + cpu_src = 0; + clear_ca(); + wait_cycs(1, 0); + } + cpu_dest = AL; + cpu_data = cpu_dest - cpu_src; + set_of_sub(8); + aa(); + break; + + case 0x40 ... 0x4f: /* INCDEC rw */ + wait_cycs(1, 0); + cpu_dest = cpu_state.regs[opcode & 7].w; + cpu_src = 1; + bits = 16; + if ((opcode & 8) == 0) { + 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(16); + cpu_state.regs[opcode & 7].w = cpu_data; + break; + + case 0x50 ... 0x57: /* PUSH r16 */ + access(30, 16); + push(&(cpu_state.regs[opcode & 0x07].w)); + break; + case 0x58 ... 0x5f: /* POP r16 */ + access(23, 16); + cpu_state.regs[opcode & 0x07].w = pop(); + wait_cycs(1, 0); + break; + + case 0x70 ... 0x71: /* JO, JNO */ + jcc(opcode, cpu_state.flags & V_FLAG); + break; + case 0x72 ... 0x73: /* JB, JNB */ + jcc(opcode, cpu_state.flags & C_FLAG); + break; + case 0x74 ... 0x75: /* JE, JNE */ + jcc(opcode, cpu_state.flags & Z_FLAG); + break; + case 0x76 ... 0x77: /* JBE, JBBE */ + jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); + break; + case 0x78 ... 0x79: /* JS, JNS */ + jcc(opcode, cpu_state.flags & N_FLAG); + break; + case 0x7a ... 0x7b: /* JP, JNP */ + jcc(opcode, cpu_state.flags & P_FLAG); + break; + case 0x7c ... 0x7d: /* JL, JNL */ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, temp ^ temp2); + break; + case 0x7e ... 0x7f: /* JLE, JNLE */ + temp = (cpu_state.flags & N_FLAG) ? 1 : 0; + temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; + jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); + break; + + case 0x80 ... 0x83: /* alu rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(47, bits); + cpu_data = get_ea(); + cpu_dest = cpu_data; + if (cpu_mod != 3) + wait_cycs(3, 0); + if (opcode == 0x81) { + if (cpu_mod == 3) + wait_cycs(1, 0); + cpu_src = pfq_fetchw(); + } else { + if (cpu_mod == 3) + wait_cycs(1, 0); + if (opcode == 0x83) + cpu_src = sign_extend(pfq_fetchb()); + else + cpu_src = pfq_fetchb() | 0xff00; + } + wait_cycs(1, 0); + cpu_alu_op = (rmdat & 0x38) >> 3; + alu_op(bits); + if (cpu_alu_op != 7) { + access(11, bits); + set_ea(cpu_data); + } else { + if (cpu_mod != 3) + wait_cycs(1, 0); + } + break; + + case 0x84 ... 0x85: + /* TEST rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(48, bits); + cpu_data = get_ea(); + test(bits, cpu_data, get_reg(cpu_reg)); + if (cpu_mod == 3) + wait_cycs(2, 0); + wait_cycs(2, 0); + break; + case 0x86 ... 0x87: + /* XCHG rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(49, bits); + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + set_reg(cpu_reg, cpu_data); + wait_cycs(3, 0); + access(12, bits); + set_ea(cpu_src); + break; + + case 0x88 ... 0x89: + /* MOV rm, reg */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait_cycs(1, 0); + access(13, bits); + set_ea(get_reg(cpu_reg)); + break; + case 0x8a ... 0x8b: + /* MOV reg, rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(50, bits); + set_reg(cpu_reg, get_ea()); + wait_cycs(1, 0); + if (cpu_mod != 3) + wait_cycs(2, 0); + break; + + case 0x8c: /* MOV w,sreg */ + do_mod_rm(); + if (cpu_mod == 3) + wait_cycs(1, 0); + access(14, 16); + seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); + break; + + case 0x8d: /* LEA */ + do_mod_rm(); + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + wait_cycs(1, 0); + if (cpu_mod != 3) + wait_cycs(2, 0); + break; + + case 0x8e: /* MOV sreg,w */ + do_mod_rm(); + access(51, 16); + tempw = geteaw(); + if ((rmdat & 0x18) == 0x08) { + load_cs(tempw); + pfq_clear_pos(); + } else + load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); + wait_cycs(1, 0); + if (cpu_mod != 3) + wait_cycs(2, 0); + if (((rmdat & 0x18) >> 3) == 2) + noint = 1; + break; + + case 0x8f: /* POPW */ + do_mod_rm(); + wait_cycs(1, 0); + cpu_src = cpu_state.eaaddr; + access(24, 16); + if (cpu_mod != 3) + wait_cycs(2, 0); + cpu_data = pop(); + cpu_state.eaaddr = cpu_src; + wait_cycs(2, 0); + access(15, 16); + seteaw(cpu_data); + break; + + case 0x90 ... 0x97: /* XCHG AX, rw */ + wait_cycs(1, 0); + cpu_data = cpu_state.regs[opcode & 7].w; + cpu_state.regs[opcode & 7].w = AX; + AX = cpu_data; + wait_cycs(1, 0); + break; + + case 0x98: /* CBW */ + wait_cycs(1, 0); + AX = sign_extend(AL); + break; + case 0x99: /* CWD */ + wait_cycs(4, 0); + if (!top_bit(AX, 16)) + DX = 0; + else { + wait_cycs(1, 0); + DX = 0xffff; + } + break; + case 0x9a: /* CALL FAR */ + wait_cycs(1, 0); + new_ip = pfq_fetchw(); + wait_cycs(1, 0); + new_cs = pfq_fetchw(); + if (is_new_biu) + biu_suspend_fetch(); + else { + pfq_clear(); + access(31, 16); + } + push(&(CS)); + if (!is_new_biu) + access(60, 16); + cpu_state.oldpc = cpu_state.pc; + load_cs(new_cs); + set_ip(new_ip); + if (is_new_biu) { + wait_cycs(3, 0); + biu_queue_flush(); + } + access(32, 16); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x9b: /* WAIT */ + if (!repeating) + wait_cycs(2, 0); + wait_cycs(5, 0); +#ifdef NO_HACK + if (irq_pending(0)) { + wait_cycs(7, 0); + check_interrupts(0); + } else { + repeating = 1; + completed = 0; + if (!is_new_biu) + clock_end(); + } +#else + wait_cycs(7, 0); + check_interrupts(0); +#endif + break; + case 0x9c: /* PUSHF */ + access(33, 16); + if (is_nec) + tempw = (cpu_state.flags & 0x8fd7) | 0x7000; + else + tempw = (cpu_state.flags & 0x0fd7) | 0xf000; + push(&tempw); + break; + case 0x9d: { /* POPF */ + uint16_t old_flags = cpu_state.flags; + access(25, 16); + if (is_nec && cpu_md_write_disable) + cpu_state.flags = pop() | 0x8002; + else + cpu_state.flags = pop() | 0x0002; + wait_cycs(1, 0); + if ((old_flags ^ cpu_state.flags) & T_FLAG) + noint = 1; + break; + } case 0x9e: /* SAHF */ + wait_cycs(1, 0); + cpu_state.flags = (cpu_state.flags & 0xff02) | AH; + wait_cycs(2, 0); + break; + case 0x9f: /* LAHF */ + wait_cycs(1, 0); + AH = cpu_state.flags & 0xd7; + break; + + case 0xa0 ... 0xa1: /* MOV A, [iw] */ + bits = 8 << (opcode & 1); + wait_cycs(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(1, bits); + set_accum(bits, readmem((ovr_seg ? *ovr_seg : ds))); + wait_cycs(1, 0); + break; + case 0xa2 ... 0xa3: /* MOV [iw], A */ + bits = 8 << (opcode & 1); + wait_cycs(1, 0); + cpu_state.eaaddr = pfq_fetchw(); + access(7, bits); + writemem((ovr_seg ? *ovr_seg : ds), get_accum(bits)); + break; + + case 0xa4 ... 0xa5: /* MOVS */ + case 0xac ... 0xad: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait_cycs(1, 0); + if ((opcode & 8) == 0 && in_rep != 0) + wait_cycs(1, 0); + } + if (rep_action(bits)) { + wait_cycs(1, 0); + if ((opcode & 8) != 0) + wait_cycs(1, 0); + break; + } + if (in_rep != 0 && (opcode & 8) != 0) + wait_cycs(1, 0); + access(20, bits); + lods(bits); + if ((opcode & 8) == 0) { + access(27, bits); + stos(bits); + } else { + set_accum(bits, cpu_data); + if (in_rep != 0) + wait_cycs(2, 0); + } + if (in_rep == 0) { + wait_cycs(3, 0); + if ((opcode & 8) != 0) + wait_cycs(1, 0); + break; + } + repeating = 1; + if (!is_new_biu) + clock_end(); + break; + + case 0xa6 ... 0xa7: /* CMPS */ + case 0xae ... 0xaf: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) + wait_cycs(1, 0); + if (rep_action(bits)) { + wait_cycs(2, 0); + break; + } + if (in_rep != 0) + wait_cycs(1, 0); + wait_cycs(1, 0); + cpu_dest = get_accum(bits); + if ((opcode & 8) == 0) { + access(21, bits); + lods(bits); + wait_cycs(1, 0); + cpu_dest = cpu_data; + } + access(2, bits); + cpu_state.eaaddr = DI; + cpu_data = readmem(es); + DI = string_increment(bits); + cpu_src = cpu_data; + sub(bits); + wait_cycs(2, 0); + if (in_rep == 0) { + wait_cycs(3, 0); + break; + } + if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { + completed = 1; + wait_cycs(4, 0); + break; + } + repeating = 1; + if (!is_new_biu) + clock_end(); + break; + + case 0xa8 ... 0xa9: /* TEST A, imm */ + bits = 8 << (opcode & 1); + wait_cycs(1, 0); + cpu_data = pfq_fetch(); + test(bits, get_accum(bits), cpu_data); + wait_cycs(1, 0); + break; + + case 0xaa ... 0xab: /* STOS */ + bits = 8 << (opcode & 1); + if (!repeating) { + wait_cycs(1, 0); + if (in_rep != 0) + wait_cycs(1, 0); + } + if (rep_action(bits)) { + wait_cycs(1, 0); + break; + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait_cycs(3, 0); + break; + } + repeating = 1; + if (!is_new_biu) + clock_end(); + break; + + case 0xb0 ... 0xb7: /* MOV cpu_reg,#8 */ + wait_cycs(1, 0); + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); + else + cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + wait_cycs(1, 0); + break; + + case 0xb8 ... 0xbf: /* MOV cpu_reg,#16 */ + wait_cycs(1, 0); + cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + wait_cycs(1, 0); + break; + + case 0xc0 ... 0xc3: /* RET */ + case 0xc8 ... 0xcb: + bits = 8 + (opcode & 0x08); + if ((opcode & 9) != 1) + wait_cycs(1, 0); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); + wait_cycs(1, 0); + } + if ((opcode & 9) == 9) + wait_cycs(1, 0); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); + access(26, bits); + new_ip = pop(); + wait_cycs(2, 0); + if ((opcode & 8) == 0) + new_cs = CS; + else { + access(42, bits); + new_cs = pop(); + if (opcode & 1) + wait_cycs(1, 0); + } + if (!(opcode & 1)) { + SP += cpu_src; + wait_cycs(1, 0); + } + load_cs(new_cs); + access(72, bits); + set_ip(new_ip); + if (is_new_biu) + biu_queue_flush(); + break; + + case 0xc4 ... 0xc5: /* LsS rw, rmd */ + do_mod_rm(); + bits = 16; + access(52, bits); + read_ea(1, bits); + cpu_state.regs[cpu_reg].w = cpu_data; + access(57, bits); + read_ea2(bits); + load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); + wait_cycs(1, 0); + break; + + case 0xc6 ... 0xc7: /* MOV rm, imm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + wait_cycs(1, 0); + if (cpu_mod != 3) + wait_cycs(2, 0); + cpu_data = pfq_fetch(); + if (cpu_mod == 3) + wait_cycs(1, 0); + access(16, bits); + set_ea(cpu_data); + break; + + case 0xcc: /* INT 3 */ + interrupt(3); + break; + case 0xcd: /* INT */ + wait_cycs(1, 0); + interrupt(pfq_fetchb()); + break; + case 0xce: /* INTO */ + wait_cycs(3, 0); + if (cpu_state.flags & V_FLAG) { + wait_cycs(2, 0); + interrupt(4); + } + break; + case 0xcf: /* IRET */ + access(43, 8); + new_ip = pop(); + wait_cycs(3, 0); + access(44, 8); + new_cs = pop(); + load_cs(new_cs); + access(62, 8); + set_ip(new_ip); + if (is_new_biu) + biu_queue_flush(); + access(45, 8); + if (is_nec && cpu_md_write_disable) + cpu_state.flags = pop() | 0x8002; + else + cpu_state.flags = pop() | 0x0002; + wait_cycs(5, 0); + noint = 2; + nmi_enable = 1; + break; + + case 0xd0 ... 0xd3: /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) + wait_cycs(1, 0); + access(53, bits); + cpu_data = get_ea(); + if ((opcode & 2) == 0) { + cpu_src = 1; + wait_cycs((cpu_mod != 3) ? 4 : 0, 0); + } else { + cpu_src = CL; + wait_cycs((cpu_mod != 3) ? 9 : 6, 0); + } + if (is186 && !is_nec) + cpu_src &= 0x1f; + 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; + } + if ((opcode & 2) != 0) + wait_cycs(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + break; + + case 0xd4: /* AAM */ + wait_cycs(1, 0); + cpu_src = pfq_fetchb(); + if (x86_div(AL, 0)) { + cpu_data = AL; + set_pzs(8); + } + break; + case 0xd5: /* AAD */ + wait_cycs(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; + set_pzs(8); + break; + case 0xd6: /* SALC */ + if (!is_nec) { + wait_cycs(1, 0); + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + wait_cycs(1, 0); + break; + } + fallthrough; + case 0xd7: /* XLATB */ + cpu_state.eaaddr = (BX + AL) & 0xffff; + access(4, 8); + AL = readmemb((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); + wait_cycs(1, 0); + break; + + case 0xd8 ... 0xdf: /* esc i, r, rm */ + do_mod_rm(); + access(54, 16); + tempw = cpu_state.pc; + if (!hasfpu) + geteaw(); + else 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. */ + wait_cycs(1, 0); + if (cpu_mod != 3) + wait_cycs(2, 0); + break; + + case 0xe0 ... 0xe3: /* LOOP */ + wait_cycs(3, 0); + cpu_data = pfq_fetchb(); + if (opcode != 0xe2) + wait_cycs(1, 0); + if (opcode != 0xe3) { + --CX; + oldc = (CX != 0); + switch (opcode) { + case 0xe0: + if (cpu_state.flags & Z_FLAG) + oldc = 0; + break; + case 0xe1: + if (!(cpu_state.flags & Z_FLAG)) + oldc = 0; + break; + } + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + break; + + case 0xe4 ... 0xe7: + case 0xec ... 0xef: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) + wait_cycs(1, 0); + if ((opcode & 8) == 0) + cpu_data = pfq_fetchb(); + else + cpu_data = DX; + cpu_state.eaaddr = cpu_data; + if ((opcode & 2) == 0) { + access(3, bits); + if (opcode & 1) + cpu_io(16, 0, cpu_data); + else + cpu_io(8, 0, cpu_data); + wait_cycs(1, 0); + } else { + if ((opcode & 8) == 0) + access(8, bits); + else + access(9, bits); + if (opcode & 1) + cpu_io(16, 1, cpu_data); + else + cpu_io(8, 1, cpu_data); + } + break; + + case 0xe8: /* CALL rel 16 */ + wait_cycs(1, 0); + cpu_state.oldpc = jump_near(); + access(34, 8); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0xe9: /* JMP rel 16 */ + wait_cycs(1, 0); + jump_near(); + break; + case 0xea: /* JMP far */ + wait_cycs(1, 0); + addr = pfq_fetchw(); + wait_cycs(1, 0); + tempw = pfq_fetchw(); + load_cs(tempw); + access(70, 8); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); + set_ip(addr); + if (is_new_biu) + biu_queue_flush(); + break; + case 0xeb: /* JMP rel */ + wait_cycs(1, 0); + cpu_data = (int8_t) pfq_fetchb(); + jump_short(); + wait_cycs(1, 0); + break; + + case 0xf0 ... 0xf1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait_cycs(1, 0); + completed = 0; + break; + + case 0xf2 ... 0xf3: /* REPNE, REPE */ + wait_cycs(1, 0); + in_rep = (opcode == 0xf2 ? 1 : 2); + completed = 0; + rep_c_flag = 0; + break; + + case 0xf4: /* HLT */ + if (!repeating) { + wait_cycs(1, 0); + pfq_clear(); + } + wait_cycs(1, 0); + if (irq_pending(is_nec)) { + wait_cycs(cycles & 1, 0); + check_interrupts(is_nec); + } else { + repeating = 1; + completed = 0; + clock_end(); + } + break; + case 0xf5: /* CMC */ + wait_cycs(1, 0); + cpu_state.flags ^= C_FLAG; + break; + + case 0xf6 ... 0xf7: + bits = 8 << (opcode & 1); + do_mod_rm(); + access(55, bits); + cpu_data = get_ea(); + switch (rmdat & 0x38) { + case 0x00: case 0x08: /* TEST */ + wait_cycs(2, 0); + if (cpu_mod != 3) + wait_cycs(1, 0); + cpu_src = pfq_fetch(); + wait_cycs(1, 0); + test(bits, cpu_data, cpu_src); + if (cpu_mod != 3) + wait_cycs(1, 0); + break; + case 0x10: case 0x18: /* NOT, NEG */ + wait_cycs(2, 0); + if ((rmdat & 0x38) == 0x10) + cpu_data = ~cpu_data; + else { + cpu_src = cpu_data; + cpu_dest = 0; + sub(bits); + } + access(18, bits); + set_ea(cpu_data); + break; + case 0x20: case 0x28: /* MUL, IMUL */ + old_flags = cpu_state.flags; + wait_cycs(1, 0); + mul(get_accum(bits), cpu_data); + if (opcode & 1) { + AX = cpu_data; + DX = cpu_dest; + 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)); + if (!is_nec) + cpu_data = AH; + } + set_sf(bits); + set_pf(); + if (cpu_mod != 3) + wait_cycs(1, 0); + /* 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: case 0x38: /* DIV, IDIV */ + if (cpu_mod != 3) + wait_cycs(1, 0); + cpu_src = cpu_data; + if (x86_div(AL, AH)) + wait_cycs(1, 0); + break; + } + break; + + case 0xf8 ... 0xf9: /* CLCSTC */ + wait_cycs(1, 0); + set_cf(opcode & 1); + break; + case 0xfa ... 0xfb: /* CLISTI */ + wait_cycs(1, 0); + set_if(opcode & 1); + break; + case 0xfc ... 0xfd: /* CLDSTD */ + wait_cycs(1, 0); + set_df(opcode & 1); + break; + + case 0xfe ... 0xff: /* misc */ + bits = 8 << (opcode & 1); + do_mod_rm(); + access(56, bits); + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: case 0x08: /* INC rm, DEC rm */ + cpu_dest = cpu_data; + cpu_src = 1; + 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); + wait_cycs(2, 0); + access(19, bits); + set_ea(cpu_data); + break; + case 0x10: /* CALL rm */ + cpu_data_opff_rm(); + access(63, bits); + wait_cycs(1, 0); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); + wait_cycs(4, 0); + if (cpu_mod != 3) + wait_cycs(1, 0); + wait_cycs(1, 0); /* Wait. */ + cpu_state.oldpc = cpu_state.pc; + set_ip(cpu_data); + if (is_new_biu) + biu_queue_flush(); + wait_cycs(2, 0); + access(35, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x18: /* CALL rmd */ + new_ip = cpu_data; + access(58, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + access(36, bits); + push(&(CS)); + access(64, bits); + if (!is_new_biu) + wait_cycs(4, 0); + cpu_state.oldpc = cpu_state.pc; + load_cs(new_cs); + set_ip(new_ip); + if (is_new_biu) { + wait_cycs(3, 0); + biu_queue_flush(); + } + access(37, bits); + push((uint16_t *) &(cpu_state.oldpc)); + break; + case 0x20: /* JMP rm */ + cpu_data_opff_rm(); + access(65, bits); + set_ip(cpu_data); + if (is_new_biu) + biu_queue_flush(); + break; + case 0x28: /* JMP rmd */ + new_ip = cpu_data; + access(59, bits); + read_ea2(bits); + if (!(opcode & 1)) + cpu_data |= 0xff00; + new_cs = cpu_data; + load_cs(new_cs); + access(66, bits); + set_ip(new_ip); + if (is_new_biu) + biu_queue_flush(); + break; + case 0x30: case 0x38: /* PUSH rm */ + if (cpu_mod != 3) + wait_cycs(1, 0); + access(38, bits); + push((uint16_t *) &(cpu_data)); + break; + } + break; + + default: + x808x_log("Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait_cycs(8, 0); + break; + } + } +} + /* Executes instructions up to the specified number of cycles. */ void execx86(int cycs) { - uint8_t temp = 0, temp2, old_af, nests; - uint8_t temp_val, temp_al, bit, handled = 0; - uint8_t odd, zero, nibbles_count, destcmp; - uint8_t destbyte, srcbyte, nibble_result, bit_length; - uint8_t bit_offset; - int8_t nibble_result_s; - uint16_t addr, tempw, new_cs, new_ip; - uint16_t tempw_int, size, tempbp, lowbound; - uint16_t highbound, regval, orig_sp, wordtopush; - uint16_t immediate, old_flags; - int bits; - uint32_t dest_seg, i, carry, nibble; - uint32_t srcseg, byteaddr; - cycles += cycs; while (cycles > 0) { - clock_start(); - - if (is_nec && !(cpu_state.flags & MD_FLAG)) { - i8080_step(&emulated_processor); - set_if(emulated_processor.iff); - cycles -= emulated_processor.cyc; - emulated_processor.cyc = 0; - completed = 1; - goto exec_completed; - } + cycdiff = cycles; if (!repeating) { cpu_state.oldpc = cpu_state.pc; opcode = pfq_fetchb(); - handled = 0; oldc = cpu_state.flags & C_FLAG; if (clear_lock) { in_lock = 0; @@ -1958,1892 +3364,8 @@ execx86(int cycs) wait_cycs(1, 0); } - completed = 1; - // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); - if (is186) { - switch (opcode) { - case 0x60: /*PUSHA/PUSH R*/ - orig_sp = SP; - wait_cycs(1, 0); - push(&AX); - push(&CX); - push(&DX); - push(&BX); - push(&orig_sp); - push(&BP); - push(&SI); - push(&DI); - handled = 1; - break; - case 0x61: /*POPA/POP R*/ - wait_cycs(9, 0); - DI = pop(); - SI = pop(); - BP = pop(); - (void) pop(); /* former orig_sp */ - BX = pop(); - DX = pop(); - CX = pop(); - AX = pop(); - handled = 1; - break; + execx86_instruction(); - case 0x62: /* BOUND r/m */ - lowbound = 0; - highbound = 0; - regval = 0; - do_mod_rm(); - - lowbound = readmemw(easeg, cpu_state.eaaddr); - highbound = readmemw(easeg, cpu_state.eaaddr + 2); - regval = get_reg(cpu_reg); - if (lowbound > regval || highbound < regval) { - cpu_state.pc = cpu_state.oldpc; - interrupt(5); - } - handled = 1; - break; - - case 0x64: - case 0x65: - if (is_nec) { - /* REPC/REPNC */ - wait_cycs(1, 0); - in_rep = (opcode == 0x64 ? 1 : 2); - rep_c_flag = 1; - completed = 0; - handled = 1; - } - break; - - case 0x68: - wordtopush = pfq_fetchw(); - wait_cycs(1, 0); - push(&wordtopush); - handled = 1; - break; - - case 0x69: - immediate = 0; - bits = 16; - do_mod_rm(); - read_ea(0, 16); - immediate = pfq_fetchw(); - mul(cpu_data & 0xFFFF, immediate); - set_reg(cpu_reg, cpu_data); - set_co_mul(16, cpu_dest != 0); - handled = 1; - break; - - case 0x6a: - wordtopush = sign_extend(pfq_fetchb()); - push(&wordtopush); - handled = 1; - break; - - case 0x6b: /* IMUL reg16,reg16/mem16,imm8 */ - immediate = 0; - bits = 16; - do_mod_rm(); - read_ea(0, 16); - immediate = pfq_fetchb(); - mul(cpu_data & 0xFFFF, immediate); - set_reg(cpu_reg, cpu_data); - set_co_mul(16, cpu_dest != 0); - handled = 1; - break; - - case 0x6c: - case 0x6d: /* INM dst, DW/INS dst, DX */ - bits = 8 << (opcode & 1); - handled = 1; - if (!repeating) - wait_cycs(2, 0); - - if (rep_action(bits)) - break; - else if (!repeating) - wait_cycs(7, 0); - - if (bits == 16) { - writememw(es, DI, cpu_inw(DX)); - DI += (cpu_state.flags & D_FLAG) ? -2 : 2; - } else { - writememb(es, DI, cpu_inb(DX)); - DI += (cpu_state.flags & D_FLAG) ? -1 : 1; - } - - 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_cycs(2, 0); - - if (rep_action(bits)) - break; - else if (!repeating) - wait_cycs(7, 0); - - if (bits == 16) { - cpu_outw(DX, readmemw(dest_seg, SI)); - SI += (cpu_state.flags & D_FLAG) ? -2 : 2; - } else { - cpu_outb(DX, readmemb(dest_seg + SI)); - SI += (cpu_state.flags & D_FLAG) ? -1 : 1; - } - if (in_rep == 0) - break; - - repeating = 1; - clock_end(); - break; - - case 0xc8: /* ENTER/PREPARE */ - tempw_int = 0; - size = pfq_fetchw(); - nests = pfq_fetchb(); - i = 0; - - push(&BP); - tempw_int = SP; - if (nests > 0) { - while (--nests) { - tempbp = 0; - BP -= 2; - tempbp = readmemw(ss, BP); - push(&tempbp); - } - push(&tempw_int); - } - BP = tempw_int; - SP -= size; - handled = 1; - break; - - case 0xc0: - case 0xc1: /*rot imm8 */ - bits = 8 << (opcode & 1); - do_mod_rm(); - if (cpu_mod == 3) - wait_cycs(1, 0); - access(53, bits); - cpu_data = get_ea(); - cpu_src = pfq_fetchb(); - - wait_cycs((cpu_mod != 3) ? 9 : 6, 0); - - if (!is_nec) - cpu_src &= 0x1F; - 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; - } - if ((opcode & 2) != 0) - wait_cycs(4, 0); - --cpu_src; - } - access(17, bits); - set_ea(cpu_data); - handled = 1; - break; - - case 0xc9: /* LEAVE/DISPOSE */ - SP = BP; - BP = pop(); - handled = 1; - break; - } - } - if (!handled) { - switch (opcode) { - case 0x06: - case 0x0E: - case 0x16: - case 0x1E: /* PUSH seg */ - access(29, 16); - push(&(_opseg[(opcode >> 3) & 0x03]->seg)); - break; - case 0x07: - case 0x0F: - case 0x17: - case 0x1F: /* POP seg */ - if (is_nec && (opcode == 0x0F)) { - uint8_t orig_opcode = opcode; - opcode = pfq_fetchb(); - switch (opcode) { - case 0x28: /* ROL4 r/m */ - do_mod_rm(); - wait_cycs(21, 0); - - temp_val = geteab(); - temp_al = AL; - - temp_al &= 0xF; - temp_al |= (temp_val & 0xF0); - temp_val = (temp_al & 0xF) | ((temp_val & 0xF) << 4); - temp_al >>= 4; - temp_al &= 0xF; - seteab(temp_val); - AL = temp_al; - - handled = 1; - break; - - case 0x2a: /* ROR4 r/m */ - do_mod_rm(); - wait_cycs(21, 0); - - temp_val = geteab(); - temp_al = AL; - - AL = temp_val & 0xF; - temp_val = (temp_val >> 4) | ((temp_al & 0xF) << 4); - - seteab(temp_val); - - handled = 1; - break; - - case 0x10: /* TEST1 r8/m8, CL*/ - case 0x11: /* TEST1 r16/m16, CL*/ - case 0x18: /* TEST1 r8/m8, imm3 */ - case 0x19: /* TEST1 r16/m16, imm4 */ - bits = 8 << (opcode & 0x1); - do_mod_rm(); - wait_cycs(3, 0); - - bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); - bit &= ((1 << (3 + (opcode & 0x1))) - 1); - read_ea(0, bits); - - set_zf_ex(!(cpu_data & (1 << bit))); - cpu_state.flags &= ~(V_FLAG | C_FLAG); - - handled = 1; - break; - - case 0x16: /* NOT1 r8/m8, CL*/ - case 0x17: /* NOT1 r16/m16, CL*/ - case 0x1e: /* NOT1 r8/m8, imm3 */ - case 0x1f: /* NOT1 r16/m16, imm4 */ - bits = 8 << (opcode & 0x1); - do_mod_rm(); - wait_cycs(3, 0); - - bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); - bit &= ((1 << (3 + (opcode & 0x1))) - 1); - read_ea(0, bits); - - if (bits == 8) - seteab((cpu_data & 0xFF) ^ (1 << bit)); - else - seteaw((cpu_data & 0xFFFF) ^ (1 << bit)); - - handled = 1; - break; - - case 0x14: /* SET1 r8/m8, CL*/ - case 0x15: /* SET1 r16/m16, CL*/ - case 0x1c: /* SET1 r8/m8, imm3 */ - case 0x1d: /* SET1 r16/m16, imm4 */ - bits = 8 << (opcode & 0x1); - do_mod_rm(); - wait_cycs(3, 0); - - bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); - bit &= ((1 << (3 + (opcode & 0x1))) - 1); - read_ea(0, bits); - - if (bits == 8) - seteab((cpu_data & 0xFF) | (1 << bit)); - else - seteaw((cpu_data & 0xFFFF) | (1 << bit)); - - handled = 1; - break; - - case 0x12: /* CLR1 r8/m8, CL*/ - case 0x13: /* CLR1 r16/m16, CL*/ - case 0x1a: /* CLR1 r8/m8, imm3 */ - case 0x1b: /* CLR1 r16/m16, imm4 */ - bits = 8 << (opcode & 0x1); - do_mod_rm(); - wait_cycs(3, 0); - - bit = (opcode & 0x8) ? (pfq_fetchb()) : (CL); - bit &= ((1 << (3 + (opcode & 0x1))) - 1); - read_ea(0, bits); - - if (bits == 8) - seteab((cpu_data & 0xFF) & ~(1 << bit)); - else - seteaw((cpu_data & 0xFFFF) & ~(1 << bit)); - - handled = 1; - break; - - case 0x20: /* ADD4S */ - odd = !!(CL % 2); - zero = 1; - nibbles_count = CL - odd; - i = 0; - carry = 0; - nibble = 0; - srcseg = ovr_seg ? *ovr_seg : ds; - - wait_cycs(5, 0); - for (i = 0; i < ((nibbles_count / 2) + odd); i++) { - wait_cycs(19, 0); - destcmp = read_mem_b((es) + DI + i); - for (nibble = 0; nibble < 2; nibble++) { - destbyte = destcmp >> (nibble ? 4 : 0); - srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); - destbyte &= 0xF; - srcbyte &= 0xF; - nibble_result = (i == (nibbles_count / 2) && nibble == 1) ? (destbyte + carry) : ((uint8_t) (destbyte)) + ((uint8_t) (srcbyte)) + ((uint32_t) carry); - carry = 0; - while (nibble_result >= 10) { - nibble_result -= 10; - carry++; - } - if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) - zero = (nibble_result == 0); - destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble))); - } - write_mem_b(es + DI + i, destcmp); - } - set_cf(!!carry); - set_zf(!!zero); - handled = 1; - break; - - case 0x22: /* SUB4S */ - odd = !!(CL % 2); - zero = 1; - nibbles_count = CL - odd; - i = 0; - carry = 0; - nibble = 0; - srcseg = ovr_seg ? *ovr_seg : ds; - - wait_cycs(5, 0); - for (i = 0; i < ((nibbles_count / 2) + odd); i++) { - wait_cycs(19, 0); - destcmp = read_mem_b((es) + DI + i); - for (nibble = 0; nibble < 2; nibble++) { - destbyte = destcmp >> (nibble ? 4 : 0); - srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); - destbyte &= 0xF; - srcbyte &= 0xF; - nibble_result_s = (i == (nibbles_count / 2) && nibble == 1) ? ((int8_t) destbyte - (int8_t) carry) : ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry); - carry = 0; - while (nibble_result_s < 0) { - nibble_result_s += 10; - carry++; - } - if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) - zero = (nibble_result_s == 0); - destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (4 * nibble))); - } - write_mem_b(es + DI + i, destcmp); - } - set_cf(!!carry); - set_zf(!!zero); - handled = 1; - break; - - case 0x26: /* CMP4S */ - odd = !!(CL % 2); - zero = 1; - nibbles_count = CL - odd; - i = 0; - carry = 0; - nibble = 0; - srcseg = ovr_seg ? *ovr_seg : ds; - - wait_cycs(5, 0); - for (i = 0; i < ((nibbles_count / 2) + odd); i++) { - wait_cycs(19, 0); - destcmp = read_mem_b((es) + DI + i); - for (nibble = 0; nibble < 2; nibble++) { - destbyte = destcmp >> (nibble ? 4 : 0); - srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); - destbyte &= 0xF; - srcbyte &= 0xF; - nibble_result_s = ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry); - carry = 0; - while (nibble_result_s < 0) { - nibble_result_s += 10; - carry++; - } - if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) - zero = (nibble_result_s == 0); - destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (4 * nibble))); - } - } - set_cf(!!carry); - set_zf(!!zero); - handled = 1; - break; - - case 0x31: /* INS reg1, reg2 */ - case 0x39: /* INS reg8, imm4 */ - do_mod_rm(); - wait_cycs(1, 0); - - bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; - bit_offset = getr8(cpu_rm) & 0xF; - byteaddr = (es) + DI; - i = 0; - - if (bit_offset >= 8) { - DI++; - byteaddr++; - bit_offset -= 8; - } - for (i = 0; i < bit_length; i++) { - byteaddr = (es) + DI; - writememb(es, DI, (read_mem_b(byteaddr) & ~(1 << (bit_offset))) | ((!!(AX & (1 << i))) << bit_offset)); - bit_offset++; - if (bit_offset == 8) { - DI++; - bit_offset = 0; - } - } - setr8(cpu_rm, bit_offset); - - handled = 1; - break; - - case 0x33: /* EXT reg1, reg2 */ - case 0x3b: /* EXT reg8, imm4 */ - do_mod_rm(); - wait_cycs(1, 0); - - bit_length = ((opcode & 0x8) ? (pfq_fetchb() & 0xF) : (getr8(cpu_reg) & 0xF)) + 1; - bit_offset = getr8(cpu_rm) & 0xF; - byteaddr = (ds) + SI; - i = 0; - - if (bit_offset >= 8) { - SI++; - byteaddr++; - bit_offset -= 8; - } - - AX = 0; - for (i = 0; i < bit_length; i++) { - byteaddr = (ds) + SI; - AX |= (!!(readmemb(byteaddr) & (1 << bit_offset))) << i; - bit_offset++; - if (bit_offset == 8) { - SI++; - bit_offset = 0; - } - } - setr8(cpu_rm, bit_offset); - - handled = 1; - break; - - case 0xFF: /* BRKEM */ - interrupt_brkem(pfq_fetchb()); - handled = 1; - break; - - default: - opcode = orig_opcode; - cpu_state.pc--; - break; - } - } else - handled = 0; - if (handled) - break; - access(22, 16); - if (opcode == 0x0F) { - load_cs(pop()); - pfq_pos = 0; - } else - load_seg(pop(), _opseg[(opcode >> 3) & 0x03]); - wait_cycs(1, 0); - /* All POP segment instructions suppress interrupts for one instruction. */ - noint = 1; - break; - - case 0x26: /*ES:*/ - case 0x2E: /*CS:*/ - case 0x36: /*SS:*/ - case 0x3E: /*DS:*/ - wait_cycs(1, 0); - ovr_seg = opseg[(opcode >> 3) & 0x03]; - completed = 0; - break; - - case 0x00: - case 0x01: - case 0x02: - case 0x03: - case 0x08: - case 0x09: - case 0x0a: - case 0x0b: - case 0x10: - case 0x11: - case 0x12: - case 0x13: - case 0x18: - case 0x19: - case 0x1a: - case 0x1b: - case 0x20: - case 0x21: - case 0x22: - case 0x23: - case 0x28: - case 0x29: - case 0x2a: - case 0x2b: - case 0x30: - case 0x31: - case 0x32: - case 0x33: - case 0x38: - case 0x39: - case 0x3a: - case 0x3b: - /* alu rm, r / r, rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(46, bits); - tempw = get_ea(); - cpu_alu_op = (opcode >> 3) & 7; - if ((opcode & 2) == 0) { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); - } else { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; - } - if (cpu_mod != 3) - wait_cycs(2, 0); - wait_cycs(1, 0); - alu_op(bits); - if (cpu_alu_op != 7) { - if ((opcode & 2) == 0) { - access(10, bits); - set_ea(cpu_data); - if (cpu_mod == 3) - wait_cycs(1, 0); - } else { - set_reg(cpu_reg, cpu_data); - wait_cycs(1, 0); - } - } else - wait_cycs(1, 0); - break; - - case 0x04: - case 0x05: - case 0x0c: - case 0x0d: - case 0x14: - case 0x15: - case 0x1c: - case 0x1d: - case 0x24: - case 0x25: - case 0x2c: - case 0x2d: - case 0x34: - case 0x35: - case 0x3c: - case 0x3d: - /* alu A, imm */ - bits = 8 << (opcode & 1); - wait_cycs(1, 0); - cpu_data = pfq_fetch(); - cpu_dest = get_accum(bits); /* AX/AL */ - cpu_src = cpu_data; - cpu_alu_op = (opcode >> 3) & 7; - alu_op(bits); - if (cpu_alu_op != 7) - set_accum(bits, cpu_data); - wait_cycs(1, 0); - break; - - case 0x27: /*DAA*/ - cpu_dest = AL; - set_of(0); - old_af = !!(cpu_state.flags & A_FLAG); - if ((cpu_state.flags & A_FLAG) || (AL & 0x0f) > 9) { - cpu_src = 6; - cpu_data = cpu_dest + cpu_src; - set_of_add(8); - cpu_dest = cpu_data; - set_af(1); - } - if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { - cpu_src = 0x60; - cpu_data = cpu_dest + cpu_src; - set_of_add(8); - cpu_dest = cpu_data; - set_cf(1); - } - AL = cpu_dest; - set_pzs(8); - wait_cycs(3, 0); - break; - case 0x2F: /*DAS*/ - cpu_dest = AL; - set_of(0); - old_af = !!(cpu_state.flags & A_FLAG); - if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { - cpu_src = 6; - cpu_data = cpu_dest - cpu_src; - set_of_sub(8); - cpu_dest = cpu_data; - set_af(1); - } - if ((cpu_state.flags & C_FLAG) || AL > (old_af ? 0x9f : 0x99)) { - cpu_src = 0x60; - cpu_data = cpu_dest - cpu_src; - set_of_sub(8); - cpu_dest = cpu_data; - set_cf(1); - } - AL = cpu_dest; - set_pzs(8); - wait_cycs(3, 0); - break; - case 0x37: /*AAA*/ - wait_cycs(1, 0); - if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { - cpu_src = 6; - ++AH; - set_ca(); - } else { - cpu_src = 0; - clear_ca(); - wait_cycs(1, 0); - } - cpu_dest = AL; - cpu_data = cpu_dest + cpu_src; - set_of_add(8); - aa(); - break; - case 0x3F: /*AAS*/ - wait_cycs(1, 0); - if ((cpu_state.flags & A_FLAG) || ((AL & 0xf) > 9)) { - cpu_src = 6; - --AH; - set_ca(); - } else { - cpu_src = 0; - clear_ca(); - wait_cycs(1, 0); - } - cpu_dest = AL; - cpu_data = cpu_dest - cpu_src; - set_of_sub(8); - aa(); - break; - - case 0x40: - case 0x41: - case 0x42: - case 0x43: - case 0x44: - case 0x45: - case 0x46: - case 0x47: - case 0x48: - case 0x49: - case 0x4A: - case 0x4B: - case 0x4C: - case 0x4D: - case 0x4E: - case 0x4F: - /* INCDEC rw */ - wait_cycs(1, 0); - cpu_dest = cpu_state.regs[opcode & 7].w; - cpu_src = 1; - bits = 16; - if ((opcode & 8) == 0) { - 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(16); - cpu_state.regs[opcode & 7].w = cpu_data; - break; - - case 0x50: - case 0x51: - case 0x52: - case 0x53: /*PUSH r16*/ - case 0x54: - case 0x55: - case 0x56: - case 0x57: - access(30, 16); - push(&(cpu_state.regs[opcode & 0x07].w)); - break; - case 0x58: - case 0x59: - case 0x5A: - case 0x5B: /*POP r16*/ - case 0x5C: - case 0x5D: - case 0x5E: - case 0x5F: - access(23, 16); - cpu_state.regs[opcode & 0x07].w = pop(); - wait_cycs(1, 0); - break; - - case 0x60: /*JO alias*/ - case 0x70: /*JO*/ - case 0x61: /*JNO alias*/ - case 0x71: /*JNO*/ - jcc(opcode, cpu_state.flags & V_FLAG); - break; - case 0x62: /*JB alias*/ - case 0x72: /*JB*/ - case 0x63: /*JNB alias*/ - case 0x73: /*JNB*/ - jcc(opcode, cpu_state.flags & C_FLAG); - break; - case 0x64: /*JE alias*/ - case 0x74: /*JE*/ - case 0x65: /*JNE alias*/ - case 0x75: /*JNE*/ - jcc(opcode, cpu_state.flags & Z_FLAG); - break; - case 0x66: /*JBE alias*/ - case 0x76: /*JBE*/ - case 0x67: /*JNBE alias*/ - case 0x77: /*JNBE*/ - jcc(opcode, cpu_state.flags & (C_FLAG | Z_FLAG)); - break; - case 0x68: /*JS alias*/ - case 0x78: /*JS*/ - case 0x69: /*JNS alias*/ - case 0x79: /*JNS*/ - jcc(opcode, cpu_state.flags & N_FLAG); - break; - case 0x6A: /*JP alias*/ - case 0x7A: /*JP*/ - case 0x6B: /*JNP alias*/ - case 0x7B: /*JNP*/ - jcc(opcode, cpu_state.flags & P_FLAG); - break; - case 0x6C: /*JL alias*/ - case 0x7C: /*JL*/ - case 0x6D: /*JNL alias*/ - case 0x7D: /*JNL*/ - temp = (cpu_state.flags & N_FLAG) ? 1 : 0; - temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; - jcc(opcode, temp ^ temp2); - break; - case 0x6E: /*JLE alias*/ - case 0x7E: /*JLE*/ - case 0x6F: /*JNLE alias*/ - case 0x7F: /*JNLE*/ - temp = (cpu_state.flags & N_FLAG) ? 1 : 0; - temp2 = (cpu_state.flags & V_FLAG) ? 1 : 0; - jcc(opcode, (cpu_state.flags & Z_FLAG) || (temp != temp2)); - break; - - case 0x80: - case 0x81: - case 0x82: - case 0x83: - /* alu rm, imm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(47, bits); - cpu_data = get_ea(); - cpu_dest = cpu_data; - if (cpu_mod != 3) - wait_cycs(3, 0); - if (opcode == 0x81) { - if (cpu_mod == 3) - wait_cycs(1, 0); - cpu_src = pfq_fetchw(); - } else { - if (cpu_mod == 3) - wait_cycs(1, 0); - if (opcode == 0x83) - cpu_src = sign_extend(pfq_fetchb()); - else - cpu_src = pfq_fetchb() | 0xff00; - } - wait_cycs(1, 0); - cpu_alu_op = (rmdat & 0x38) >> 3; - alu_op(bits); - if (cpu_alu_op != 7) { - access(11, bits); - set_ea(cpu_data); - } else { - if (cpu_mod != 3) - wait_cycs(1, 0); - } - break; - - case 0x84: - case 0x85: - /* TEST rm, reg */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(48, bits); - cpu_data = get_ea(); - test(bits, cpu_data, get_reg(cpu_reg)); - if (cpu_mod == 3) - wait_cycs(2, 0); - wait_cycs(2, 0); - break; - case 0x86: - case 0x87: - /* XCHG rm, reg */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(49, bits); - cpu_data = get_ea(); - cpu_src = get_reg(cpu_reg); - set_reg(cpu_reg, cpu_data); - wait_cycs(3, 0); - access(12, bits); - set_ea(cpu_src); - break; - - case 0x88: - case 0x89: - /* MOV rm, reg */ - bits = 8 << (opcode & 1); - do_mod_rm(); - wait_cycs(1, 0); - access(13, bits); - set_ea(get_reg(cpu_reg)); - break; - case 0x8A: - case 0x8B: - /* MOV reg, rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(50, bits); - set_reg(cpu_reg, get_ea()); - wait_cycs(1, 0); - if (cpu_mod != 3) - wait_cycs(2, 0); - break; - - case 0x8C: /*MOV w,sreg*/ - do_mod_rm(); - if (cpu_mod == 3) - wait_cycs(1, 0); - access(14, 16); - seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); - break; - - case 0x8D: /*LEA*/ - do_mod_rm(); - cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; - wait_cycs(1, 0); - if (cpu_mod != 3) - wait_cycs(2, 0); - break; - - case 0x8E: /*MOV sreg,w*/ - do_mod_rm(); - access(51, 16); - tempw = geteaw(); - if ((rmdat & 0x18) == 0x08) { - load_cs(tempw); - pfq_pos = 0; - } else - load_seg(tempw, _opseg[(rmdat & 0x18) >> 3]); - wait_cycs(1, 0); - if (cpu_mod != 3) - wait_cycs(2, 0); - if (((rmdat & 0x18) >> 3) == 2) - noint = 1; - break; - - case 0x8F: /*POPW*/ - do_mod_rm(); - wait_cycs(1, 0); - cpu_src = cpu_state.eaaddr; - access(24, 16); - if (cpu_mod != 3) - wait_cycs(2, 0); - cpu_data = pop(); - cpu_state.eaaddr = cpu_src; - wait_cycs(2, 0); - access(15, 16); - seteaw(cpu_data); - break; - - case 0x90: - case 0x91: - case 0x92: - case 0x93: - case 0x94: - case 0x95: - case 0x96: - case 0x97: - /* XCHG AX, rw */ - wait_cycs(1, 0); - cpu_data = cpu_state.regs[opcode & 7].w; - cpu_state.regs[opcode & 7].w = AX; - AX = cpu_data; - wait_cycs(1, 0); - break; - - case 0x98: /*CBW*/ - wait_cycs(1, 0); - AX = sign_extend(AL); - break; - case 0x99: /*CWD*/ - wait_cycs(4, 0); - if (!top_bit(AX, 16)) - DX = 0; - else { - wait_cycs(1, 0); - DX = 0xffff; - } - break; - case 0x9A: /*CALL FAR*/ - wait_cycs(1, 0); - new_ip = pfq_fetchw(); - wait_cycs(1, 0); - new_cs = pfq_fetchw(); - pfq_clear(); - access(31, 16); - push(&(CS)); - access(60, 16); - cpu_state.oldpc = cpu_state.pc; - load_cs(new_cs); - set_ip(new_ip); - access(32, 16); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0x9B: /*WAIT*/ - if (!repeating) - wait_cycs(2, 0); - wait_cycs(5, 0); -#ifdef NO_HACK - if (irq_pending(0)) { - wait_cycs(7, 0); - check_interrupts(0); - } else { - repeating = 1; - completed = 0; - clock_end(); - } -#else - wait_cycs(7, 0); - check_interrupts(0); -#endif - break; - case 0x9C: /*PUSHF*/ - access(33, 16); - if (is_nec) - tempw = (cpu_state.flags & 0x8fd7) | 0x7000; - else - tempw = (cpu_state.flags & 0x0fd7) | 0xf000; - push(&tempw); - break; - case 0x9D: { /*POPF*/ - uint16_t old_flags = cpu_state.flags; - access(25, 16); - if (is_nec && cpu_md_write_disable) - cpu_state.flags = pop() | 0x8002; - else - cpu_state.flags = pop() | 0x0002; - wait_cycs(1, 0); - if ((old_flags ^ cpu_state.flags) & T_FLAG) - noint = 1; - sync_to_i8080(); - break; - } case 0x9E: /*SAHF*/ - wait_cycs(1, 0); - cpu_state.flags = (cpu_state.flags & 0xff02) | AH; - wait_cycs(2, 0); - break; - case 0x9F: /*LAHF*/ - wait_cycs(1, 0); - AH = cpu_state.flags & 0xd7; - break; - - case 0xA0: - case 0xA1: - /* MOV A, [iw] */ - bits = 8 << (opcode & 1); - wait_cycs(1, 0); - cpu_state.eaaddr = pfq_fetchw(); - access(1, bits); - set_accum(bits, readmem((ovr_seg ? *ovr_seg : ds))); - wait_cycs(1, 0); - break; - case 0xA2: - case 0xA3: - /* MOV [iw], A */ - bits = 8 << (opcode & 1); - wait_cycs(1, 0); - cpu_state.eaaddr = pfq_fetchw(); - access(7, bits); - writemem((ovr_seg ? *ovr_seg : ds), get_accum(bits)); - break; - - case 0xA4: - case 0xA5: /* MOVS */ - case 0xAC: - case 0xAD: /* LODS */ - bits = 8 << (opcode & 1); - if (!repeating) { - wait_cycs(1, 0); - if ((opcode & 8) == 0 && in_rep != 0) - wait_cycs(1, 0); - } - if (rep_action(bits)) { - wait_cycs(1, 0); - if ((opcode & 8) != 0) - wait_cycs(1, 0); - break; - } - if (in_rep != 0 && (opcode & 8) != 0) - wait_cycs(1, 0); - access(20, bits); - lods(bits); - if ((opcode & 8) == 0) { - access(27, bits); - stos(bits); - } else { - set_accum(bits, cpu_data); - if (in_rep != 0) - wait_cycs(2, 0); - } - if (in_rep == 0) { - wait_cycs(3, 0); - if ((opcode & 8) != 0) - wait_cycs(1, 0); - break; - } - repeating = 1; - clock_end(); - break; - - case 0xA6: - case 0xA7: /* CMPS */ - case 0xAE: - case 0xAF: /* SCAS */ - bits = 8 << (opcode & 1); - if (!repeating) - wait_cycs(1, 0); - if (rep_action(bits)) { - wait_cycs(2, 0); - break; - } - if (in_rep != 0) - wait_cycs(1, 0); - wait_cycs(1, 0); - cpu_dest = get_accum(bits); - if ((opcode & 8) == 0) { - access(21, bits); - lods(bits); - wait_cycs(1, 0); - cpu_dest = cpu_data; - } - access(2, bits); - cpu_state.eaaddr = DI; - cpu_data = readmem(es); - DI = string_increment(bits); - cpu_src = cpu_data; - sub(bits); - wait_cycs(2, 0); - if (in_rep == 0) { - wait_cycs(3, 0); - break; - } - if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { - completed = 1; - wait_cycs(4, 0); - break; - } - repeating = 1; - clock_end(); - break; - - case 0xA8: - case 0xA9: - /* TEST A, imm */ - bits = 8 << (opcode & 1); - wait_cycs(1, 0); - cpu_data = pfq_fetch(); - test(bits, get_accum(bits), cpu_data); - wait_cycs(1, 0); - break; - - case 0xAA: - case 0xAB: /* STOS */ - bits = 8 << (opcode & 1); - if (!repeating) { - wait_cycs(1, 0); - if (in_rep != 0) - wait_cycs(1, 0); - } - if (rep_action(bits)) { - wait_cycs(1, 0); - break; - } - cpu_data = AX; - access(28, bits); - stos(bits); - if (in_rep == 0) { - wait_cycs(3, 0); - break; - } - repeating = 1; - clock_end(); - break; - - case 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: /*MOV cpu_reg,#8*/ - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: - wait_cycs(1, 0); - if (opcode & 0x04) - cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); - else - cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); - wait_cycs(1, 0); - break; - - case 0xB8: - case 0xB9: - case 0xBA: - case 0xBB: /*MOV cpu_reg,#16*/ - case 0xBC: - case 0xBD: - case 0xBE: - case 0xBF: - wait_cycs(1, 0); - cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); - wait_cycs(1, 0); - break; - - case 0xC0: - case 0xC1: - case 0xC2: - case 0xC3: - case 0xC8: - case 0xC9: - case 0xCA: - case 0xCB: - /* RET */ - bits = 8 + (opcode & 0x08); - if ((opcode & 9) != 1) - wait_cycs(1, 0); - if (!(opcode & 1)) { - cpu_src = pfq_fetchw(); - wait_cycs(1, 0); - } - if ((opcode & 9) == 9) - wait_cycs(1, 0); - pfq_clear(); - access(26, bits); - new_ip = pop(); - wait_cycs(2, 0); - if ((opcode & 8) == 0) - new_cs = CS; - else { - access(42, bits); - new_cs = pop(); - if (opcode & 1) - wait_cycs(1, 0); - } - if (!(opcode & 1)) { - SP += cpu_src; - wait_cycs(1, 0); - } - load_cs(new_cs); - access(72, bits); - set_ip(new_ip); - break; - - case 0xC4: - case 0xC5: - /* LsS rw, rmd */ - do_mod_rm(); - bits = 16; - access(52, bits); - read_ea(1, bits); - cpu_state.regs[cpu_reg].w = cpu_data; - access(57, bits); - read_ea2(bits); - load_seg(cpu_data, (opcode & 0x01) ? &cpu_state.seg_ds : &cpu_state.seg_es); - wait_cycs(1, 0); - break; - - case 0xC6: - case 0xC7: - /* MOV rm, imm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - wait_cycs(1, 0); - if (cpu_mod != 3) - wait_cycs(2, 0); - cpu_data = pfq_fetch(); - if (cpu_mod == 3) - wait_cycs(1, 0); - access(16, bits); - set_ea(cpu_data); - break; - - case 0xCC: /*INT 3*/ - interrupt(3); - break; - case 0xCD: /*INT*/ - wait_cycs(1, 0); - interrupt(pfq_fetchb()); - break; - case 0xCE: /*INTO*/ - wait_cycs(3, 0); - if (cpu_state.flags & V_FLAG) { - wait_cycs(2, 0); - interrupt(4); - } - break; - - case 0xCF: /*IRET*/ - access(43, 8); - new_ip = pop(); - wait_cycs(3, 0); - access(44, 8); - new_cs = pop(); - load_cs(new_cs); - access(62, 8); - set_ip(new_ip); - access(45, 8); - if (is_nec && cpu_md_write_disable) - cpu_state.flags = pop() | 0x8002; - else - cpu_state.flags = pop() | 0x0002; - wait_cycs(5, 0); - noint = 2; - nmi_enable = 1; - if (is_nec && !(cpu_state.flags & MD_FLAG)) - sync_to_i8080(); - break; - - case 0xD0: - case 0xD1: - case 0xD2: - case 0xD3: - /* rot rm */ - bits = 8 << (opcode & 1); - do_mod_rm(); - if (cpu_mod == 3) - wait_cycs(1, 0); - access(53, bits); - cpu_data = get_ea(); - if ((opcode & 2) == 0) { - cpu_src = 1; - wait_cycs((cpu_mod != 3) ? 4 : 0, 0); - } else { - cpu_src = CL; - wait_cycs((cpu_mod != 3) ? 9 : 6, 0); - } - if (is186 && !is_nec) - cpu_src &= 0x1F; - 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; - } - if ((opcode & 2) != 0) - wait_cycs(4, 0); - --cpu_src; - } - access(17, bits); - set_ea(cpu_data); - break; - - case 0xD4: /*AAM*/ - wait_cycs(1, 0); -#ifdef NO_VARIANT_ON_NEC - if (is_nec) { - (void) pfq_fetchb(); - cpu_src = 10; - } else - cpu_src = pfq_fetchb(); -#else - cpu_src = pfq_fetchb(); -#endif - if (x86_div(AL, 0)) { - cpu_data = AL; - set_pzs(8); - } - break; - case 0xD5: /*AAD*/ - wait_cycs(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; - set_pzs(8); - break; - case 0xD6: /*SALC*/ - if (!is_nec) { - wait_cycs(1, 0); - AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; - wait_cycs(1, 0); - break; - } - fallthrough; - case 0xD7: /*XLATB*/ - cpu_state.eaaddr = (BX + AL) & 0xffff; - access(4, 8); - AL = readmemb((ovr_seg ? *ovr_seg : ds) + cpu_state.eaaddr); - wait_cycs(1, 0); - break; - - case 0xD8: - case 0xD9: - case 0xDA: - case 0xDB: - case 0xDD: - case 0xDC: - case 0xDE: - case 0xDF: - /* esc i, r, rm */ - do_mod_rm(); - access(54, 16); - tempw = cpu_state.pc; - if (!hasfpu) - geteaw(); - else - 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. */ - wait_cycs(1, 0); - if (cpu_mod != 3) - wait_cycs(2, 0); - break; - - case 0xE0: - case 0xE1: - case 0xE2: - case 0xE3: - /* LOOP */ - wait_cycs(3, 0); - cpu_data = pfq_fetchb(); - if (opcode != 0xe2) - wait_cycs(1, 0); - if (opcode != 0xe3) { - --CX; - oldc = (CX != 0); - switch (opcode) { - case 0xE0: - if (cpu_state.flags & Z_FLAG) - oldc = 0; - break; - case 0xE1: - if (!(cpu_state.flags & Z_FLAG)) - oldc = 0; - break; - } - } else - oldc = (CX == 0); - if (oldc) - jump_short(); - break; - - case 0xE4: - case 0xE5: - case 0xE6: - case 0xE7: - case 0xEC: - case 0xED: - case 0xEE: - case 0xEF: - bits = 8 << (opcode & 1); - if ((opcode & 0x0e) != 0x0c) - wait_cycs(1, 0); - if ((opcode & 8) == 0) - cpu_data = pfq_fetchb(); - else - cpu_data = DX; - cpu_state.eaaddr = cpu_data; - if ((opcode & 2) == 0) { - access(3, bits); - if (opcode & 1) - cpu_io(16, 0, cpu_data); - else - cpu_io(8, 0, cpu_data); - wait_cycs(1, 0); - } else { - if ((opcode & 8) == 0) - access(8, bits); - else - access(9, bits); - if (opcode & 1) - cpu_io(16, 1, cpu_data); - else - cpu_io(8, 1, cpu_data); - } - break; - - case 0xE8: /*CALL rel 16*/ - wait_cycs(1, 0); - cpu_state.oldpc = jump_near(); - access(34, 8); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0xE9: /*JMP rel 16*/ - wait_cycs(1, 0); - jump_near(); - break; - case 0xEA: /*JMP far*/ - wait_cycs(1, 0); - addr = pfq_fetchw(); - wait_cycs(1, 0); - tempw = pfq_fetchw(); - load_cs(tempw); - access(70, 8); - pfq_clear(); - set_ip(addr); - break; - case 0xEB: /*JMP rel*/ - wait_cycs(1, 0); - cpu_data = (int8_t) pfq_fetchb(); - jump_short(); - wait_cycs(1, 0); - break; - - case 0xF0: - case 0xF1: /*LOCK - F1 is alias*/ - in_lock = 1; - wait_cycs(1, 0); - completed = 0; - break; - - case 0xF2: /*REPNE*/ - case 0xF3: /*REPE*/ - wait_cycs(1, 0); - in_rep = (opcode == 0xf2 ? 1 : 2); - completed = 0; - rep_c_flag = 0; - break; - - case 0xF4: /*HLT*/ - if (!repeating) { - wait_cycs(1, 0); - pfq_clear(); - } - wait_cycs(1, 0); - if (irq_pending(is_nec)) { - wait_cycs(cycles & 1, 0); - check_interrupts(is_nec); - } else { - repeating = 1; - completed = 0; - clock_end(); - } - break; - case 0xF5: /*CMC*/ - wait_cycs(1, 0); - cpu_state.flags ^= C_FLAG; - break; - - case 0xF6: - case 0xF7: - bits = 8 << (opcode & 1); - do_mod_rm(); - access(55, bits); - cpu_data = get_ea(); - switch (rmdat & 0x38) { - case 0x00: - case 0x08: - /* TEST */ - wait_cycs(2, 0); - if (cpu_mod != 3) - wait_cycs(1, 0); - cpu_src = pfq_fetch(); - wait_cycs(1, 0); - test(bits, cpu_data, cpu_src); - if (cpu_mod != 3) - wait_cycs(1, 0); - break; - case 0x10: /* NOT */ - case 0x18: /* NEG */ - wait_cycs(2, 0); - if ((rmdat & 0x38) == 0x10) - cpu_data = ~cpu_data; - else { - cpu_src = cpu_data; - cpu_dest = 0; - sub(bits); - } - access(18, bits); - set_ea(cpu_data); - break; - case 0x20: /* MUL */ - case 0x28: /* IMUL */ - old_flags = cpu_state.flags; - wait_cycs(1, 0); - mul(get_accum(bits), cpu_data); - if (opcode & 1) { - AX = cpu_data; - DX = cpu_dest; - 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)); - if (!is_nec) - cpu_data = AH; - } - set_sf(bits); - set_pf(); - if (cpu_mod != 3) - wait_cycs(1, 0); - /* 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 */ - if (cpu_mod != 3) - wait_cycs(1, 0); - cpu_src = cpu_data; - if (x86_div(AL, AH)) - wait_cycs(1, 0); - break; - } - break; - - case 0xF8: - case 0xF9: - /* CLCSTC */ - wait_cycs(1, 0); - set_cf(opcode & 1); - break; - case 0xFA: - case 0xFB: - /* CLISTI */ - wait_cycs(1, 0); - set_if(opcode & 1); - break; - case 0xFC: - case 0xFD: - /* CLDSTD */ - wait_cycs(1, 0); - set_df(opcode & 1); - break; - - case 0xFE: - case 0xFF: - /* misc */ - bits = 8 << (opcode & 1); - do_mod_rm(); - access(56, bits); - read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); - switch (rmdat & 0x38) { - case 0x00: /* INC rm */ - case 0x08: /* DEC rm */ - cpu_dest = cpu_data; - cpu_src = 1; - 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); - wait_cycs(2, 0); - access(19, bits); - set_ea(cpu_data); - break; - case 0x10: /* CALL rm */ - cpu_data_opff_rm(); - access(63, bits); - wait_cycs(1, 0); - pfq_clear(); - wait_cycs(4, 0); - if (cpu_mod != 3) - wait_cycs(1, 0); - wait_cycs(1, 0); /* Wait. */ - cpu_state.oldpc = cpu_state.pc; - set_ip(cpu_data); - wait_cycs(2, 0); - access(35, bits); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0x18: /* CALL rmd */ - new_ip = cpu_data; - access(58, bits); - read_ea2(bits); - if (!(opcode & 1)) - cpu_data |= 0xff00; - new_cs = cpu_data; - access(36, bits); - push(&(CS)); - access(64, bits); - wait_cycs(4, 0); - cpu_state.oldpc = cpu_state.pc; - load_cs(new_cs); - set_ip(new_ip); - access(37, bits); - push((uint16_t *) &(cpu_state.oldpc)); - break; - case 0x20: /* JMP rm */ - cpu_data_opff_rm(); - access(65, bits); - set_ip(cpu_data); - break; - case 0x28: /* JMP rmd */ - new_ip = cpu_data; - access(59, bits); - read_ea2(bits); - if (!(opcode & 1)) - cpu_data |= 0xff00; - new_cs = cpu_data; - load_cs(new_cs); - access(66, bits); - set_ip(new_ip); - break; - case 0x30: /* PUSH rm */ - case 0x38: - if (cpu_mod != 3) - wait_cycs(1, 0); - access(38, bits); - push((uint16_t *) &(cpu_data)); - break; - } - break; - - default: - x808x_log("Illegal opcode: %02X\n", opcode); - pfq_fetchb(); - wait_cycs(8, 0); - break; - } - } -exec_completed: if (completed) { repeating = 0; ovr_seg = NULL; diff --git a/src/cpu/CMakeLists.txt b/src/cpu/CMakeLists.txt index dc7f5ac11..7eadb94fa 100644 --- a/src/cpu/CMakeLists.txt +++ b/src/cpu/CMakeLists.txt @@ -20,6 +20,8 @@ add_library(cpu OBJECT cpu_table.c fpu.c x86.c 808x.c + vx0.c + vx0_biu.c 386.c 386_common.c 386_dynarec.c diff --git a/src/cpu/cpu.c b/src/cpu/cpu.c index 6e675acc8..e0868861d 100644 --- a/src/cpu/cpu.c +++ b/src/cpu/cpu.c @@ -1865,6 +1865,8 @@ cpu_set(void) cpu_exec = exec386_2386; } else if (cpu_s->cpu_type >= CPU_286) cpu_exec = exec386_2386; + else if (is_nec) + cpu_exec = execvx0; else cpu_exec = execx86; mmx_init(); diff --git a/src/cpu/cpu.h b/src/cpu/cpu.h index 865e76ffb..92d60f708 100644 --- a/src/cpu/cpu.h +++ b/src/cpu/cpu.h @@ -718,6 +718,7 @@ extern void codegen_reset(void); extern void cpu_set_edx(void); extern int divl(uint32_t val); extern void execx86(int32_t cycs); +extern void execvx0(int32_t cycs); extern void enter_smm(int in_hlt); extern void enter_smm_check(int in_hlt); extern void leave_smm(void); @@ -728,6 +729,7 @@ extern int idivl(int32_t val); extern void resetmcr(void); extern void resetx86(void); extern void refreshread(void); +extern void refreshread_vx0(void); extern void resetreadlookup(void); extern void softresetx86(void); extern void hardresetx86(void); @@ -809,6 +811,8 @@ extern void SF_FPU_reset(void); extern void reset_808x(int hard); extern void interrupt_808x(uint16_t addr); +extern void reset_vx0(int hard); + extern void cpu_register_fast_off_handler(void *timer); extern void cpu_fast_off_advance(void); extern void cpu_fast_off_period_set(uint16_t vla, double period); diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index cb337b405..91808299a 100644 --- a/src/cpu/cpu_table.c +++ b/src/cpu/cpu_table.c @@ -3616,7 +3616,7 @@ const cpu_family_t cpu_families[] = { { .package = CPU_PKG_SOCKET4, .manufacturer = "Intel", - .name = "Pentium", + .name = "Pentium (P5)", .internal_name = "pentium_p5", .cpus = (const CPU[]) { { @@ -3736,7 +3736,7 @@ const cpu_family_t cpu_families[] = { { .package = CPU_PKG_SOCKET5_7, .manufacturer = "Intel", - .name = "Pentium", + .name = "Pentium (P54C)", .internal_name = "pentium_p54c", .cpus = (const CPU[]) { { diff --git a/src/cpu/vx0.c b/src/cpu/vx0.c new file mode 100644 index 000000000..20924ea04 --- /dev/null +++ b/src/cpu/vx0.c @@ -0,0 +1,4784 @@ +/* + * 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. + * + * Vx0 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 + +#include "i8080.h" + +#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 "vx0_biu.h" + +#define do_cycle() wait_vx0(1) +#define do_cycle_no_modrm() if (!nx) \ + do_cycle() +#define do_cycle_i() do_cycle() +#define do_cycles(c) wait_vx0(c) +#define do_cycles_i(c) do_cycles(c) +#define do_cycle_nx() nx = 1 +#define do_cycle_nx_i() nx = 1 +#define do_cycles_nx(c) nx = 1; \ + if (c > 1) \ + do_cycles(c - 1) +#define do_cycles_nx_i(c) nx = 1; \ + if (c > 1) \ + do_cycles(c - 1) +#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) \ + { \ + do_cycles(val); \ + } + +#define CLOCK_CYCLES_ALWAYS(val) \ + { \ + do_cycles(val); \ + } + +#define CLOCK_CYCLES_FPU(val) \ + { \ + do_cycles(val); \ + } + +# define CLOCK_CYCLES(val) \ + { \ + if (fpu_cycles > 0) { \ + fpu_cycles -= (val); \ + if (fpu_cycles < 0) { \ + do_cycles(val); \ + } \ + } else { \ + do_cycles(val); \ + } \ + } + +#define CONCURRENCY_CYCLES(c) fpu_cycles = (c) + +#define OP_MRM 1 +#define OP_EA 2 +#define OP_MEA (OP_MRM | OP_EA) +#define OP_GRP 4 +#define OP_DELAY 8 +#define OP_PRE 16 + +#define readmemb readmemb_vx0 +#define readmemw readmemw_vx0 +#define readmem readmem_vx0 +#define readmeml readmeml_vx0 +#define readmemq readmemq_vx0 +#define writememb writememb_vx0 +#define writememw writememw_vx0 +#define writemem writemem_vx0 +#define writememl writememl_vx0 +#define writememq writememq_vx0 + +typedef int (*OpFn)(uint32_t fetchdat); + +static void farret(int far); + +const uint8_t opf[256] = { OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 00 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 08 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 10 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 18 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 20 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 28 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 30 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 38 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 48 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 50 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 58 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 60 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 68 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 78 */ + OP_GRP, OP_GRP, OP_GRP, OP_GRP, OP_MEA, OP_MEA, OP_MEA, OP_MEA, /* 80 */ + OP_MRM, OP_MRM, OP_MEA, OP_MEA, OP_MRM, OP_MRM, OP_MEA, OP_MRM, /* 88 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 98 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* A0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* A8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* B0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* B8 */ + 0, 0, 0, 0, OP_MEA, OP_MEA, OP_MRM, OP_MRM, /* C0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* C8 */ + OP_GRP, OP_GRP, OP_GRP, OP_GRP, 0, 0, 0, 0, /* D0 */ + OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* D8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* E0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* E8 */ + OP_PRE, OP_PRE, OP_PRE, OP_PRE, 0, 0, OP_GRP, OP_GRP, /* F0 */ + 0, 0, 0, 0, 0, 0, OP_GRP, OP_GRP }; /* F8 */ + +const uint8_t opf_nec[256] = { OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 00 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, OP_PRE, /* 08 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 10 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, 0, 0, /* 18 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 20 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 28 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 30 */ + OP_MEA, OP_MEA, OP_MEA, OP_MEA, 0, 0, OP_PRE, 0, /* 38 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 48 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 50 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 58 */ + 0, 0, OP_MRM, OP_MRM, OP_PRE, OP_PRE, OP_MRM, OP_MRM, /* 60 */ + 0, OP_MRM, 0, OP_MEA, 0, 0, 0, 0, /* 68 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 78 */ + OP_GRP, OP_GRP, OP_GRP, OP_GRP, OP_MEA, OP_MEA, OP_MEA, OP_MEA, /* 80 */ + OP_MRM, OP_MRM, OP_MEA, OP_MEA, OP_MRM, OP_MRM, OP_MEA, OP_MRM, /* 88 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 98 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* A0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* A8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* B0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* B8 */ + OP_GRP, OP_GRP, 0, 0, OP_MEA, OP_MEA, OP_MRM, OP_MRM, /* C0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* C8 */ + OP_GRP, OP_GRP, OP_GRP, OP_GRP, 0, 0, 0, 0, /* D0 */ + OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* D8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* E0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* E8 */ + OP_PRE, OP_PRE, OP_PRE, OP_PRE, 0, 0, OP_GRP, OP_GRP, /* F0 */ + 0, 0, 0, 0, 0, 0, OP_GRP, OP_GRP }; /* F8 */ + +const uint8_t opf_0f[256] = { 0, 0, 0, 0, 0, 0, 0, 0, /* 00 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 08 */ + OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* 10 */ + OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, OP_MRM, /* 18 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 20 */ + OP_MRM, 0, OP_MRM, 0, 0, 0, 0, 0, /* 28 */ + OP_MRM, 0, OP_MRM, 0, 0, 0, 0, 0, /* 30 */ + OP_MRM, 0, OP_MRM, 0, 0, 0, 0, 0, /* 38 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 40 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 48 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 50 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 58 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 60 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 68 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 70 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 78 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 88 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* 98 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* A0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* A8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* B0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* B8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* C0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* C8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* D0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* D8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* E0 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* E8 */ + 0, 0, 0, 0, 0, 0, 0, 0, /* F0 */ + 0, 0, 0, 0, 0, 0, 0, 0 }; /* F8 */ + +int nx = 0; + +static int started = 0; +static int group_delay = 0; +static int modrm_loaded = 0; +static int in_0f = 0; +static int in_hlt = 0; +static int retem = 0; +static int halted = 0; + +enum { + MODRM_ADDR_BX_SI = 0x00, + MODRM_ADDR_BX_DI, + MODRM_ADDR_BP_SI, + MODRM_ADDR_BP_DI, + MODRM_ADDR_SI, + MODRM_ADDR_DI, + MODRM_ADDR_DISP16, + MODRM_ADDR_BX, + + MODRM_ADDR_BX_SI_DISP8 = 0x40, + MODRM_ADDR_BX_DI_DISP8, + MODRM_ADDR_BP_SI_DISP8, + MODRM_ADDR_BP_DI_DISP8, + MODRM_ADDR_SI_DISP8, + MODRM_ADDR_DI_DISP8, + MODRM_ADDR_BP_DISP8, + MODRM_ADDR_BX_DISP8, + + MODRM_ADDR_BX_SI_DISP16 = 0x80, + MODRM_ADDR_BX_DI_DISP16, + MODRM_ADDR_BP_SI_DISP16, + MODRM_ADDR_BP_DI_DISP16, + MODRM_ADDR_SI_DISP16, + MODRM_ADDR_DI_DISP16, + MODRM_ADDR_BP_DISP16, + MODRM_ADDR_BX_DISP16 +}; + +static uint8_t modrm_cycs_pre[256] = { [MODRM_ADDR_BX_SI] = 4, + [MODRM_ADDR_BX_DI] = 5, + [MODRM_ADDR_BP_SI] = 5, + [MODRM_ADDR_BP_DI] = 4, + [MODRM_ADDR_SI] = 2, + [MODRM_ADDR_DI] = 2, + [MODRM_ADDR_DISP16] = 0, + [MODRM_ADDR_BX] = 2, + [0x08 ... 0x3f] = 0, + [MODRM_ADDR_BX_SI_DISP8] = 4, + [MODRM_ADDR_BX_DI_DISP8] = 5, + [MODRM_ADDR_BP_SI_DISP8] = 5, + [MODRM_ADDR_BP_DI_DISP8] = 4, + [MODRM_ADDR_SI_DISP8] = 2, + [MODRM_ADDR_DI_DISP8] = 2, + [MODRM_ADDR_BP_DISP8] = 2, + [MODRM_ADDR_BX_DISP8] = 2, + [0x48 ... 0x7f] = 0, + [MODRM_ADDR_BX_SI_DISP16] = 4, + [MODRM_ADDR_BX_DI_DISP16] = 5, + [MODRM_ADDR_BP_SI_DISP16] = 5, + [MODRM_ADDR_BP_DI_DISP16] = 4, + [MODRM_ADDR_SI_DISP16] = 2, + [MODRM_ADDR_DI_DISP16] = 2, + [MODRM_ADDR_BP_DISP16] = 2, + [MODRM_ADDR_BX_DISP16] = 2, + [0x88 ... 0xff] = 0 }; + +static uint8_t modrm_cycs_post[256] = { [MODRM_ADDR_BX_SI] = 0, + [MODRM_ADDR_BX_DI] = 0, + [MODRM_ADDR_BP_SI] = 0, + [MODRM_ADDR_BP_DI] = 0, + [MODRM_ADDR_SI] = 0, + [MODRM_ADDR_DI] = 0, + [MODRM_ADDR_DISP16] = 1, + [MODRM_ADDR_BX] = 0, + [0x08 ... 0x3f] = 0, + [MODRM_ADDR_BX_SI_DISP8] = 3, + [MODRM_ADDR_BX_DI_DISP8] = 3, + [MODRM_ADDR_BP_SI_DISP8] = 3, + [MODRM_ADDR_BP_DI_DISP8] = 3, + [MODRM_ADDR_SI_DISP8] = 3, + [MODRM_ADDR_DI_DISP8] = 3, + [MODRM_ADDR_BP_DISP8] = 3, + [MODRM_ADDR_BX_DISP8] = 3, + [0x48 ... 0x7f] = 0, + [MODRM_ADDR_BX_SI_DISP16] = 2, + [MODRM_ADDR_BX_DI_DISP16] = 2, + [MODRM_ADDR_BP_SI_DISP16] = 2, + [MODRM_ADDR_BP_DI_DISP16] = 2, + [MODRM_ADDR_SI_DISP16] = 2, + [MODRM_ADDR_DI_DISP16] = 2, + [MODRM_ADDR_BP_DISP16] = 2, + [MODRM_ADDR_BX_DISP16] = 2, + [0x88 ... 0xff] = 0 }; + +#ifdef ENABLE_VX0_LOG +#if 0 +void dumpregs(int); +#endif +int vx0_do_log = ENABLE_VX0_LOG; + +static void +vx0_log(const char *fmt, ...) +{ + va_list ap; + + if (vx0_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define vx0_log(fmt, ...) +#endif + +static i8080 emulated_processor; +static bool cpu_md_write_disable = 1; + +static void +set_if(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~I_FLAG) | (cond ? I_FLAG : 0); +} + +void +sync_from_i8080(void) +{ + AL = emulated_processor.a; + BH = emulated_processor.h; + BL = emulated_processor.l; + CH = emulated_processor.b; + CL = emulated_processor.c; + DH = emulated_processor.d; + DL = emulated_processor.e; + BP = emulated_processor.sp; + + cpu_state.pc = emulated_processor.pc; + cpu_state.flags &= 0xFF00; + cpu_state.flags |= emulated_processor.sf << 7; + cpu_state.flags |= emulated_processor.zf << 6; + cpu_state.flags |= emulated_processor.hf << 4; + cpu_state.flags |= emulated_processor.pf << 2; + cpu_state.flags |= 1 << 1; + cpu_state.flags |= emulated_processor.cf << 0; + set_if(emulated_processor.iff); +} + +void +sync_to_i8080(void) +{ + if (!is_nec) + return; + emulated_processor.a = AL; + emulated_processor.h = BH; + emulated_processor.l = BL; + emulated_processor.b = CH; + emulated_processor.c = CL; + emulated_processor.d = DH; + emulated_processor.e = DL; + emulated_processor.sp = BP; + emulated_processor.pc = cpu_state.pc; + emulated_processor.iff = !!(cpu_state.flags & I_FLAG); + + emulated_processor.sf = (cpu_state.flags >> 7) & 1; + emulated_processor.zf = (cpu_state.flags >> 6) & 1; + emulated_processor.hf = (cpu_state.flags >> 4) & 1; + emulated_processor.pf = (cpu_state.flags >> 2) & 1; + emulated_processor.cf = (cpu_state.flags >> 0) & 1; + + emulated_processor.interrupt_delay = noint; +} + +static void +set_ip(uint16_t new_ip) +{ + cpu_state.pc = new_ip; +} + +static void +startx86(void) +{ + /* Reset takes 6 cycles before first fetch. */ + do_cycle(); + biu_suspend_fetch(); + do_cycles_i(2); + biu_queue_flush(); + do_cycles_i(3); +} + +static void +load_cs(uint16_t 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; +} + +static uint8_t +fetch_i8080_opcode(UNUSED(void* priv), uint16_t addr) +{ + return readmemb(cs, addr); +} + +static uint8_t +fetch_i8080_data(UNUSED(void* priv), uint16_t addr) +{ + return readmemb(ds, addr); +} + +static void +put_i8080_data(UNUSED(void* priv), uint16_t addr, uint8_t val) +{ + writememb(ds, addr, val); +} + +static +uint8_t i8080_port_in(UNUSED(void* priv), uint8_t port) +{ + cpu_data = port; + cpu_state.eaaddr = cpu_data; + cpu_io_vx0(8, 0, cpu_state.eaaddr); + return AL; +} + +static +void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val) +{ + cpu_data = DX; + AL = val; + do_cycle_i(); + + cpu_state.eaaddr = cpu_data; + cpu_data = AL; + cpu_io_vx0(8, 1, port); +} + +void +reset_vx0(int hard) +{ + is_new_biu = 1; + halted = 0; + in_hlt = 0; + in_0f = 0; + in_rep = 0; + in_lock = 0; + completed = 1; + repeating = 0; + clear_lock = 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; + } + + load_cs(0xFFFF); + cpu_state.pc = 0; + + if (is_nec) + cpu_state.flags |= MD_FLAG; + rammask = 0xfffff; + + cpu_alu_op = 0; + + nx = 0; + + use_custom_nmi_vector = 0x00; + custom_nmi_vector = 0x00000000; + + biu_reset(); + + started = 1; + modrm_loaded = 0; + + cpu_md_write_disable = 1; + i8080_init(&emulated_processor); + emulated_processor.write_byte = put_i8080_data; + emulated_processor.read_byte = fetch_i8080_data; + emulated_processor.read_byte_seg = fetch_i8080_opcode; + emulated_processor.port_in = i8080_port_in; + emulated_processor.port_out = i8080_port_out; +} + +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); +} + +#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) +{ + uint8_t ret; + + if (cpu_mod == 3) + ret = (getr8(cpu_rm)); + else + ret = readmemb(easeg, cpu_state.eaaddr); + + return ret; +} + +/* Reads a word from the effective address. */ +static uint16_t +geteaw(void) +{ + uint16_t ret; + + if (cpu_mod == 3) + ret = cpu_state.regs[cpu_rm].w; + else + ret = readmemw(easeg, cpu_state.eaaddr); + + return ret; +} + +/* Neede for 8087 - memory only. */ +static uint32_t +geteal(void) +{ + uint32_t ret; + + if (cpu_mod == 3) { + fatal("Vx0 register geteal()\n"); + ret = 0xffffffff; + } else + ret = readmeml(easeg, cpu_state.eaaddr); + + return ret; +} + +/* Neede for 8087 - memory only. */ +static uint64_t +geteaq(void) +{ + uint32_t ret; + + if (cpu_mod == 3) { + fatal("Vx0 register geteaq()\n"); + ret = 0xffffffff; + } else + ret = readmemq(easeg, cpu_state.eaaddr); + + return ret; +} + +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 { + do_cycle(); + 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 { + do_cycle(); + writememw(easeg, cpu_state.eaaddr, val); + } +} + +static void +seteal(uint32_t val) +{ + if (cpu_mod == 3) { + fatal("Vx0 register seteal()\n"); + return; + } else + writememl(easeg, cpu_state.eaaddr, val); +} + +static void +seteaq(uint64_t val) +{ + if (cpu_mod == 3) { + fatal("Vx0 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 FPU_NEC +#define tempc tempc_fpu +#include "x87_sf.h" +#include "x87.h" +#include "x87_ops.h" +#undef tempc +#undef FPU_8087 + +static void +set_cf(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~C_FLAG) | (cond ? C_FLAG : 0); +} + +static void +set_df(int cond) +{ + cpu_state.flags = (cpu_state.flags & ~D_FLAG) | (cond ? D_FLAG : 0); +} + +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_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 +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_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 +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 +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 +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 + do_cycles(8); + + size_mask = (1 << bit_count) - 1; + + if ((rmdat & 0x38) == 0x28) { + if (!top_bit(a, bit_count)) { + if (top_bit(b, bit_count)) { + do_cycle(); + if ((b & size_mask) != ((opcode & 1) ? 0x8000 : 0x80)) + do_cycle(); + b = ~b + 1; + negate = 1; + } + } else { + do_cycle(); + a = ~a + 1; + negate = 1; + if (top_bit(b, bit_count)) { + b = ~b + 1; + negate = 0; + } else + do_cycles(4); + } + do_cycles(10); + } + do_cycles(3); + } + + c = 0; + a &= size_mask; + carry = (a & 1) != 0; + a >>= 1; + for (int i = 0; i < bit_count; ++i) { + do_cycles(7); + if (carry) { + cpu_src = c; + cpu_dest = b; + add(bit_count); + c = cpu_data & size_mask; + do_cycles(1); + 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; + do_cycles(9); + } + cpu_data = a; + cpu_dest = c; + + set_sf(bit_count); + set_pf(); + set_af(0); +} + +static void +set_co_mul(UNUSED(int bits), int carry) +{ + set_cf(carry); + set_of(carry); + set_zf_ex(!carry); + if (!carry) + do_cycle(); +} + +/* 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; + + do_cycle_i(); + set_ip(new_ip); + biu_queue_flush(); + do_cycles_i(3); + push(&ret_ip); +} + +static void +farcall2(uint16_t new_cs, uint16_t new_ip) +{ + do_cycles_i(3); + push(&CS); + load_cs(new_cs); + do_cycles_i(2); + nearcall(new_ip); +} + +/* 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; + + if (!(cpu_state.flags & MD_FLAG) && is_nec) { + sync_from_i8080(); + vx0_log("CALLN/INT#/NMI#\n"); + } + + 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); + + biu_suspend_fetch(); + do_cycles_i(2); + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + if (is_nec) + cpu_state.flags |= MD_FLAG; + do_cycle_i(); + + farcall2(new_cs, new_ip); +} + +/* 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; + do_cycles(4); + } + if (top_bit(cpu_src, bit_count)) { + cpu_src = ~cpu_src + 1; + negative = !negative; + } else + do_cycle(); + do_cycles(9); + } + do_cycles(3); + } + do_cycles(8); + cpu_src &= size_mask; + if (h >= cpu_src) { + if (opcode != 0xd4) + do_cycle(); + intr_routine(0, 0); + return 0; + } + if (opcode != 0xd4) + do_cycle(); + do_cycles(2); + 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; + do_cycles(8); + if (carry) { + carry = 0; + h -= cpu_src; + if (b == bit_count - 1) + do_cycles(2); + } else { + carry = cpu_src > h; + if (!carry) { + h -= cpu_src; + do_cycle(); + if (b == bit_count - 1) + do_cycles(2); + } + } + } + l = ~((l << 1) + (carry ? 1 : 0)); + if (opcode != 0xd4 && (rmdat & 0x38) == 0x38) { + do_cycles(4); + if (top_bit(l, bit_count)) { + if (cpu_mod == 3) + do_cycle(); + intr_routine(0, 0); + return 0; + } + do_cycles(7); + 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 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; + } +} + +static void +farcall(uint16_t new_cs, uint16_t new_ip, int jump) +{ + if (jump) + do_cycle_i(); + biu_suspend_fetch(); + do_cycles_i(2); + push(&CS); + load_cs(new_cs); + do_cycles_i(2); + nearcall(new_ip); +} + +/* Calls an interrupt. */ +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; + + if (!(cpu_state.flags & MD_FLAG) && is_nec) { + sync_from_i8080(); + vx0_log("CALLN/INT#/NMI#\n"); + } + + 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); + + biu_suspend_fetch(); + do_cycles_i(2); + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + if (is_nec) + cpu_state.flags |= MD_FLAG; + + /* FARCALL2 */ + do_cycles_i(4); + push(&CS); + load_cs(new_cs); + do_cycle_i(); + + /* NEARCALL */ + old_ip = cpu_state.pc & 0xffff; + do_cycles_i(2); + set_ip(new_ip); + biu_queue_flush(); + do_cycles_i(3); + push(&old_ip); +} + +static void +int3(void) +{ + do_cycles_i(4); + intr_routine(3, 0); +} + +/* Ditto, but for breaking into emulation mode. */ +static void +interrupt_brkem(uint16_t addr) +{ + 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 = addr << 2; + 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); + + biu_suspend_fetch(); + do_cycles_i(2); + push(&tempf); + cpu_state.flags &= ~(MD_FLAG); + cpu_md_write_disable = 0; + + /* FARCALL2 */ + do_cycles_i(4); + push(&CS); + load_cs(new_cs); + do_cycle_i(); + + /* NEARCALL */ + old_ip = cpu_state.pc & 0xffff; + do_cycles_i(2); + set_ip(new_ip); + biu_queue_flush(); + do_cycles_i(3); + push(&old_ip); + + sync_to_i8080(); + vx0_log("BRKEM mode\n"); +} + +void +retem_i8080(void) +{ + sync_from_i8080(); + + do_cycle_i(); + farret(1); + /* pop_flags() */ + cpu_state.flags = pop(); + do_cycle_i(); + + noint = 1; + nmi_enable = 1; + + emulated_processor.iff = !!(cpu_state.flags & I_FLAG); + + cpu_md_write_disable = 1; + + retem = 1; + + vx0_log("RETEM mode\n"); +} + +void +interrupt_808x(uint16_t addr) +{ + biu_suspend_fetch(); + do_cycles_i(2); + + 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; + + if (!(cpu_state.flags & MD_FLAG) && is_nec) { + sync_from_i8080(); + vx0_log("CALLN/INT#/NMI#\n"); + } + + 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; + + biu_suspend_fetch(); + do_cycles_i(2); + push(&tempf); + cpu_state.flags &= ~(I_FLAG | T_FLAG); + if (is_nec) + cpu_state.flags |= MD_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) || + ((in_hlt || (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; + biu_begin_eu(); + biu_wait_for_read_finish(); + in_lock = old_in_lock; + return pic_data; +} + +static void +hw_int(uint16_t vector) +{ + biu_suspend_fetch(); + do_cycles_i(2); + + intr_routine(vector, 0); +} + +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 +check_interrupts(void) +{ + int temp; + + if (irq_pending()) { + if ((cpu_state.flags & T_FLAG) && !noint) { + int1(); + return; + } + if (nmi && nmi_enable && nmi_mask) { + nmi_enable = 0; + if (use_custom_nmi_vector) { + do_cycles(2); + custom_nmi(); + } else + int2(); + return; + } + if ((in_hlt || (cpu_state.flags & I_FLAG)) && pic.int_pending && !noint) { + repeating = 0; + completed = 1; + ovr_seg = NULL; + do_cycles(4); + /* ACK to PIC */ + biu_begin_eu(); + temp = bus_pic_ack(); + do_cycle(); + /* 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); + } + } +} + +/* The FARRET microcode routine. */ +static void +farret(int far) +{ + uint8_t far2 = !!(opcode & 0x08); + + do_cycle_i(); + set_ip(pop()); + biu_suspend_fetch(); + do_cycles_i(2); + + if ((!!far) != far2) + fatal("Far call distance mismatch (%i = %i)\n", !!far, far2); + + if (far) { + do_cycle_i(); + load_cs(pop()); + + biu_queue_flush(); + do_cycles_i(2); + } else { + biu_queue_flush(); + do_cycles_i(2); + } + + do_cycles_i(2); +} + +static void +iret_routine(void) +{ + do_cycle_i(); + farret(1); + /* pop_flags() */ + if (is_nec && cpu_md_write_disable) + cpu_state.flags = pop() | 0x8002; + else + cpu_state.flags = pop() | 0x0002; + do_cycle_i(); + noint = 1; + nmi_enable = 1; +} + +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(is_nec ? 1 : 4); + rep_end(); + return 0; + } else + do_cycles_i(is_nec ? 1 : 7); + } + } + + completed = 1; + return 1; +} + +static void +rep_interrupt(void) +{ + biu_suspend_fetch(); + do_cycles_i(4); + biu_queue_flush(); + + 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 (!is_nec && jump) + do_cycle_i(); + + biu_suspend_fetch(); + if (!is_nec) + do_cycles_i(3); + set_ip(new_ip); + biu_queue_flush(); + 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 >= 0x7a) && (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_state.flags & A_FLAG; + uint16_t old_cf = cpu_state.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 >= 0xa0) && (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 -= 0x60; + 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 &= ~(V_FLAG | Z_FLAG | N_FLAG); + if (new_al == 0x00) + cpu_state.flags |= Z_FLAG; + if ((old_al >= 0x7a) && (old_al <= 0x7f)) + cpu_state.flags |= V_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 &= ~(V_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 |= V_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) +{ + in_0f = 0; + repeating = 0; + ovr_seg = NULL; + in_rep = 0; + rep_c_flag = 0; + if (in_lock) + clear_lock = 1; + cpu_alu_op = 0; + + if (pfq_pos == 0) { + do { + if (nx) + nx = 0; + do_cycle(); + } while (pfq_pos == 0); + biu_preload_byte = biu_pfq_read(); + biu_queue_preload = 1; + do_cycle(); + } else { + biu_queue_preload = 1; + biu_preload_byte = biu_pfq_read(); + + biu_resume_on_queue_read(); + + do_cycle(); + } + + if (irq_pending()) + cpu_state.pc--; +} + +/* Fetches the effective address from the prefetch queue according to MOD and R/M. */ +static void +do_mod_rm(void) +{ + rmdat = biu_pfq_fetchb(); + cpu_reg = (rmdat >> 3) & 7; + cpu_mod = (rmdat >> 6) & 3; + cpu_rm = rmdat & 7; + + if (cpu_mod != 3) { + do_cycle(); + if (is_nec) + do_cycle(); + else if (modrm_cycs_pre[rmdat & 0xc7]) + do_cycles(modrm_cycs_pre[rmdat & 0xc7]); + + if ((rmdat & 0xc7) == 0x06) { + cpu_state.eaaddr = biu_pfq_fetchw(); + easeg = ovr_seg ? *ovr_seg : ds; + } else { + cpu_state.eaaddr = (*mod1add[0][cpu_rm]) + (*mod1add[1][cpu_rm]); + easeg = ovr_seg ? *ovr_seg : *mod1seg[cpu_rm]; + switch (rmdat & 0xc0) { + default: + break; + case 0x40: + cpu_state.eaaddr += sign_extend(biu_pfq_fetchb()); + break; + case 0x80: + cpu_state.eaaddr += biu_pfq_fetchw(); + break; + } + cpu_state.eaaddr &= 0xffff; + } + + if (!is_nec && modrm_cycs_post[rmdat & 0xc7]) + do_cycles(modrm_cycs_post[rmdat & 0xc7]); + } +} + +static void +decode_modrm(void) +{ + uint8_t op_f; + + modrm_loaded = 0; + + if (is_nec) { + if (in_0f) + op_f = (uint8_t) opf_0f[opcode]; + else + op_f = (uint8_t) opf_nec[opcode]; + } else + op_f = (uint8_t) opf[opcode]; + + if (op_f & OP_GRP) { + do_mod_rm(); + modrm_loaded = 1; + + op_f |= (OP_MRM | OP_EA); + + if (opcode >= 0xf0) { + op_f |= OP_DELAY; + group_delay = 1; + } + } + + if (!modrm_loaded && (op_f & OP_MRM)) { + do_mod_rm(); + modrm_loaded = 1; + } + + if (modrm_loaded && !(op_f & OP_EA)) { + if (is_nec) + do_cycle(); + else { + if (opcode == 0x8f) { + if (cpu_mod == 3) + do_cycles_i(2); + } else + do_cycles_i(2); + } + } +} + +static void +decode(void) +{ + uint8_t prefix = 0; + + if (halted) + opcode = 0xf4; + else + opcode = biu_pfq_fetchb_common(); + + while (1) { + prefix = 0; + + switch (opcode) { + case 0x0f: /* NEC/186 */ + if (is_nec) { + in_0f = 1; + prefix = 1; + } + break; + case 0x26: /* ES: */ + case 0x2e: /* CS: */ + case 0x36: /* SS: */ + case 0x3e: /* DS: */ + ovr_seg = opseg[(opcode >> 3) & 0x03]; + prefix = 1; + break; + case 0x64: /* REPNC */ + case 0x65: /* REPC */ + if (is_nec) { + in_rep = (opcode == 0x64 ? 1 : 2); + rep_c_flag = 1; + prefix = 1; + } + break; + case 0xf0: + case 0xf1: /* LOCK - F1 is alias */ + in_lock = 1; + prefix = 1; + break; + case 0xf2: /* REPNE */ + case 0xf3: /* REPE */ + in_rep = (opcode == 0xf2 ? 1 : 2); + rep_c_flag = 0; + prefix = 1; + break; + default: + break; + } + + if (prefix == 0) + break; + + do_cycle(); + + opcode = biu_pfq_fetchb_common(); + } +} + +static void +string_op(int bits) +{ + uint16_t tmpa; + uint16_t old_ax; + + if ((opcode & 0xf0) == 0x60) switch (opcode & 0x0e) { + case 0x0c: + old_ax = AX; + cpu_data = DX; + cpu_state.eaaddr = cpu_data; + cpu_io_vx0(bits, 0, cpu_state.eaaddr); + cpu_data = AX; + stos(bits); + AX = old_ax; + break; + case 0x0e: + old_ax = AX; + lods(bits); + set_accum(bits, cpu_data); + cpu_data = DX; + do_cycle_i(); + /* biu_io_write_u16() */ + cpu_state.eaaddr = cpu_data; + cpu_io_vx0(bits, 1, cpu_state.eaaddr); + AX = old_ax; + break; + } else switch (opcode & 0x0e) { + case 0x04: + lods(bits); + do_cycle_i(); + stos(bits); + break; + case 0x06: + do_cycle_i(); + if (is_nec) { + if (in_rep) { + lods_di(bits); + tmpa = cpu_data; + lods(bits); + /* Swap them or else the operation goes wrong. */ + uint32_t tmpa2 = tmpa; + tmpa = cpu_data; + cpu_data = tmpa2; + } else { + lods(bits); + tmpa = cpu_data; + lods_di(bits); + } + } else { + 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); + break; + case 0x0e: + tmpa = AX; + do_cycles_i(2); + lods_di(bits); + do_cycles_i(3); + + cpu_src = cpu_data; + cpu_dest = tmpa; + sub(bits); + break; + case 0x0a: + cpu_data = AX; + stos(bits); + break; + case 0x0c: + lods(bits); + set_accum(bits, cpu_data); + break; + } +} + +static int do_print = 1; + +static void +execvx0_0f(void) +{ + uint8_t bit; + uint8_t odd; + uint8_t nibbles_count; + uint8_t destcmp; + uint8_t destbyte; + uint8_t srcbyte; + uint8_t nibble_result; + uint8_t temp_val; + uint8_t temp_al; + uint8_t bit_length; + uint8_t bit_offset; + int8_t nibble_result_s; + int bits; + uint32_t i; + uint32_t carry; + uint32_t nibble; + uint32_t srcseg; + uint32_t byteaddr; + + switch (opcode) { + case 0x10: /* TEST1 r8/m8, CL*/ + case 0x11: /* TEST1 r16/m16, CL*/ + case 0x18: /* TEST1 r8/m8, imm3 */ + case 0x19: /* TEST1 r16/m16, imm4 */ + bits = 8 << (opcode & 0x1); + do_cycles(2); + + bit = (opcode & 0x8) ? biu_pfq_fetchb() : CL; + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + set_zf_ex(!(cpu_data & (1 << bit))); + cpu_state.flags &= ~(V_FLAG | C_FLAG); + break; + + case 0x12: /* CLR1 r8/m8, CL*/ + case 0x13: /* CLR1 r16/m16, CL*/ + case 0x1a: /* CLR1 r8/m8, imm3 */ + case 0x1b: /* CLR1 r16/m16, imm4 */ + bits = 8 << (opcode & 0x1); + do_cycles(2); + + bit = (opcode & 0x8) ? biu_pfq_fetchb() : CL; + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + if (bits == 8) + seteab((cpu_data & 0xff) & ~(1 << bit)); + else + seteaw((cpu_data & 0xffff) & ~(1 << bit)); + break; + + case 0x14: /* SET1 r8/m8, CL*/ + case 0x15: /* SET1 r16/m16, CL*/ + case 0x1c: /* SET1 r8/m8, imm3 */ + case 0x1d: /* SET1 r16/m16, imm4 */ + bits = 8 << (opcode & 0x1); + do_cycles(2); + + bit = (opcode & 0x8) ? biu_pfq_fetchb() : CL; + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + if (bits == 8) + seteab((cpu_data & 0xff) | (1 << bit)); + else + seteaw((cpu_data & 0xffff) | (1 << bit)); + break; + + case 0x16: /* NOT1 r8/m8, CL*/ + case 0x17: /* NOT1 r16/m16, CL*/ + case 0x1e: /* NOT1 r8/m8, imm3 */ + case 0x1f: /* NOT1 r16/m16, imm4 */ + bits = 8 << (opcode & 0x1); + do_cycles(2); + + bit = (opcode & 0x8) ? (biu_pfq_fetchb()) : (CL); + bit &= ((1 << (3 + (opcode & 0x1))) - 1); + read_ea(0, bits); + + if (bits == 8) + seteab((cpu_data & 0xff) ^ (1 << bit)); + else + seteaw((cpu_data & 0xffff) ^ (1 << bit)); + break; + + case 0x20: /* ADD4S */ + odd = !!(CL % 2); + zero = 1; + nibbles_count = CL - odd; + i = 0; + carry = 0; + nibble = 0; + srcseg = ovr_seg ? *ovr_seg : ds; + + do_cycles(4); + + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + do_cycles(19); + destcmp = read_mem_b((es) + DI + i); + + for (nibble = 0; nibble < 2; nibble++) { + destbyte = destcmp >> (nibble ? 4 : 0); + srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + nibble_result = (i == (nibbles_count / 2) && nibble == 1) ? (destbyte + carry) : + ((uint8_t) (destbyte)) + ((uint8_t) (srcbyte)) + ((uint32_t) carry); + carry = 0; + + while (nibble_result >= 10) { + nibble_result -= 10; + carry++; + } + + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result == 0); + + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result << (4 * nibble))); + } + + write_mem_b(es + DI + i, destcmp); + } + + set_cf(!!carry); + set_zf(!!zero); + break; + + case 0x22: /* SUB4S */ + odd = !!(CL % 2); + zero = 1; + nibbles_count = CL - odd; + i = 0; + carry = 0; + nibble = 0; + srcseg = ovr_seg ? *ovr_seg : ds; + + do_cycles(4); + + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + do_cycles(19); + destcmp = read_mem_b((es) + DI + i); + + for (nibble = 0; nibble < 2; nibble++) { + destbyte = destcmp >> (nibble ? 4 : 0); + srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + nibble_result_s = (i == (nibbles_count / 2) && nibble == 1) ? ((int8_t) destbyte - (int8_t) carry) : + ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry); + carry = 0; + + while (nibble_result_s < 0) { + nibble_result_s += 10; + carry++; + } + + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result_s == 0); + + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (4 * nibble))); + } + + write_mem_b(es + DI + i, destcmp); + } + + set_cf(!!carry); + set_zf(!!zero); + break; + + case 0x26: /* CMP4S */ + odd = !!(CL % 2); + zero = 1; + nibbles_count = CL - odd; + i = 0; + carry = 0; + nibble = 0; + srcseg = ovr_seg ? *ovr_seg : ds; + + do_cycles(4); + + for (i = 0; i < ((nibbles_count / 2) + odd); i++) { + do_cycles(19); + destcmp = read_mem_b((es) + DI + i); + + for (nibble = 0; nibble < 2; nibble++) { + destbyte = destcmp >> (nibble ? 4 : 0); + srcbyte = read_mem_b(srcseg + SI + i) >> (nibble ? 4 : 0); + destbyte &= 0xF; + srcbyte &= 0xF; + nibble_result_s = ((int8_t) (destbyte)) - ((int8_t) (srcbyte)) - ((int8_t) carry); + carry = 0; + + while (nibble_result_s < 0) { + nibble_result_s += 10; + carry++; + } + + if (zero != 0 || (i == (nibbles_count / 2) && nibble == 1)) + zero = (nibble_result_s == 0); + + destcmp = ((destcmp & (nibble ? 0x0F : 0xF0)) | (nibble_result_s << (4 * nibble))); + } + } + + set_cf(!!carry); + set_zf(!!zero); + break; + + case 0x28: /* ROL4 r/m */ + do_cycles(20); + + temp_val = geteab(); + temp_al = AL; + + temp_al &= 0x0f; + temp_al |= (temp_val & 0xf0); + temp_val = (temp_al & 0x0f) | ((temp_val & 0x0f) << 4); + temp_al >>= 4; + temp_al &= 0x0f; + seteab(temp_val); + AL = temp_al; + break; + + case 0x2a: /* ROR4 r/m */ + do_cycles(20); + + temp_val = geteab(); + temp_al = AL; + + AL = temp_val & 0x0f; + temp_val = (temp_val >> 4) | ((temp_al & 0x0f) << 4); + + seteab(temp_val); + break; + + case 0x31: /* INS reg1, reg2 */ + case 0x39: /* INS reg8, imm4 */ + bit_length = ((opcode & 0x8) ? (biu_pfq_fetchb() & 0x0f) : (getr8(cpu_reg) & 0x0f)) + 1; + bit_offset = getr8(cpu_rm) & 0x0f; + byteaddr = (es) + DI; + i = 0; + + if (bit_offset >= 8) { + DI++; + byteaddr++; + bit_offset -= 8; + } + + for (i = 0; i < bit_length; i++) { + byteaddr = (es) + DI; + writememb(es, DI, (read_mem_b(byteaddr) & ~(1 << (bit_offset))) | ((!!(AX & (1 << i))) << bit_offset)); + bit_offset++; + + if (bit_offset == 8) { + DI++; + bit_offset = 0; + } + } + + setr8(cpu_rm, bit_offset); + break; + + case 0x33: /* EXT reg1, reg2 */ + case 0x3b: /* EXT reg8, imm4 */ + bit_length = ((opcode & 0x8) ? (biu_pfq_fetchb() & 0x0f) : (getr8(cpu_reg) & 0x0f)) + 1; + bit_offset = getr8(cpu_rm) & 0x0f; + byteaddr = (ds) + SI; + i = 0; + + if (bit_offset >= 8) { + SI++; + byteaddr++; + bit_offset -= 8; + } + + AX = 0; + + for (i = 0; i < bit_length; i++) { + byteaddr = (ds) + SI; + AX |= (!!(readmemb(ds, SI) & (1 << bit_offset))) << i; + bit_offset++; + + if (bit_offset == 8) { + SI++; + bit_offset = 0; + } + } + + setr8(cpu_rm, bit_offset); + break; + + case 0xff: /* BRKEM */ + interrupt_brkem(biu_pfq_fetchb()); + break; + + default: + do_cycles_nx_i(2); /* Guess, based on NOP. */ + break; + } +} + +static void +execvx0_6x(uint16_t *jump) +{ + uint16_t lowbound; + uint16_t highbound; + uint16_t regval; + uint16_t wordtopush; + uint16_t immediate; + uint16_t tempw; + int bits; + int32_t templ; + + switch (opcode) { + case 0x60: /* PUSHA/PUSH R */ + writememw(ss, ((SP - 2) & 0xffff), AX); + biu_state_set_eu(); + writememw(ss, ((SP - 4) & 0xffff), CX); + biu_state_set_eu(); + writememw(ss, ((SP - 6) & 0xffff), DX); + biu_state_set_eu(); + writememw(ss, ((SP - 8) & 0xffff), BX); + biu_state_set_eu(); + writememw(ss, ((SP - 10) & 0xffff), SP); + biu_state_set_eu(); + writememw(ss, ((SP - 12) & 0xffff), BP); + biu_state_set_eu(); + writememw(ss, ((SP - 14) & 0xffff), SI); + biu_state_set_eu(); + writememw(ss, ((SP - 16) & 0xffff), DI); + SP -= 16; + break; + + case 0x61: /* POPA/POP R */ + DI = readmemw(ss, ((SP) & 0xffff)); + biu_state_set_eu(); + SI = readmemw(ss, ((SP + 2) & 0xffff)); + biu_state_set_eu(); + BP = readmemw(ss, ((SP + 4) & 0xffff)); + biu_state_set_eu(); + BX = readmemw(ss, ((SP + 8) & 0xffff)); + biu_state_set_eu(); + DX = readmemw(ss, ((SP + 10) & 0xffff)); + biu_state_set_eu(); + CX = readmemw(ss, ((SP + 12) & 0xffff)); + biu_state_set_eu(); + AX = readmemw(ss, ((SP + 14) & 0xffff)); + SP += 16; + break; + + case 0x62: /* BOUND r/m */ + lowbound = 0; + highbound = 0; + regval = 0; + + lowbound = readmemw(easeg, cpu_state.eaaddr); + highbound = readmemw(easeg, cpu_state.eaaddr + 2); + regval = get_reg(cpu_reg); + + if ((lowbound > regval) || (highbound < regval)) { + sw_int(5); + *jump = 1; + } + break; + + case 0x63: + if (is_nec) { + /* read_operand16() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + tempw = cpu_state.pc; + geteaw(); + do_cycles(60); + } + break; + + case 0x64: + case 0x65: + if (!is_nec) { + do_cycles_nx_i(2); /* Guess, based on NOP. */ + } + break; + + case 0x66 ... 0x67: /* FPO2 - NEC FPU instructions. */ + /* read_operand16() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + tempw = cpu_state.pc; + geteaw(); + /* fpu_op() */ + cpu_state.pc = tempw; /* Do this as the x87 code advances it, which is needed on + the 286+ core, but not here. */ + break; + + case 0x68: + wordtopush = biu_pfq_fetchw(); + push(&wordtopush); + break; + + case 0x69: + bits = 16; + read_ea(0, 16); + immediate = biu_pfq_fetchw(); + + templ = ((int) cpu_data) * ((int) immediate); + if ((templ >> 15) != 0 && (templ >> 15) != -1) + cpu_state.flags |= C_FLAG | V_FLAG; + else + cpu_state.flags &= ~(C_FLAG | V_FLAG); + set_reg(cpu_reg, templ & 0xffff); + do_cycles((cpu_mod == 3) ? 20 : 26); + break; + + case 0x6a: + wordtopush = sign_extend(biu_pfq_fetchb()); + push(&wordtopush); + break; + + case 0x6b: /* IMUL reg16,reg16/mem16,imm8 */ + read_ea(0, 16); + immediate = biu_pfq_fetchb(); + immediate = geteaw(); + if (immediate & 0x80) + immediate |= 0xff00; + + templ = ((int) cpu_data) * ((int) immediate); + if ((templ >> 15) != 0 && (templ >> 15) != -1) + cpu_state.flags |= C_FLAG | V_FLAG; + else + cpu_state.flags &= ~(C_FLAG | V_FLAG); + set_reg(cpu_reg, templ & 0xffff); + do_cycles((cpu_mod == 3) ? 24 : 30); + break; + + case 0x6c: + case 0x6d: /* INM dst, DW/INS dst, DX */ + bits = 8 << (opcode & 1); + if (rep_start()) { + string_op(bits); + do_cycle_i(); + + 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 0x6e: + case 0x6f: /* OUTM DW, src/OUTS DX, src */ + bits = 8 << (opcode & 1); + if (rep_start()) { + string_op(bits); + 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; + + default: + do_cycles_nx_i(2); /* Guess, based on NOP. */ + break; + } +} + +/* Executes a single instruction. */ +void +execute_instruction(void) +{ + uint8_t temp = 0; + uint8_t tempb; + uint8_t nests; + + int8_t rel8; + int8_t temps; + + uint16_t addr; + uint16_t jump = 0; + uint16_t new_cs; + uint16_t new_ip; + uint16_t tempw; + uint16_t zero_cond; + uint16_t old_cs; + uint16_t old_ip; + uint16_t old_flags; + uint16_t prod16; + uint16_t tempw_int; + uint16_t size; + uint16_t tempbp; + uint16_t src16; + + int16_t rel16; + int16_t temps16; + + uint32_t prod32; + uint32_t templ; + uint32_t templ2 = 0; + + int bits; + int negate; + int tempws = 0; + int tempws2 = 0; + + completed = 1; + + if (nx) { + do_cycle(); + nx = 0; + } else if (!modrm_loaded) + do_cycle(); + + if (group_delay) { + group_delay = 0; + do_cycle(); + nx = 0; + } + + if (!is_nec && (opcode >= 0xc0) && (opcode <= 0xc1)) + opcode |= 0x02; + + if (is_nec && !(cpu_state.flags & MD_FLAG)) { + i8080_step(&emulated_processor); + set_if(emulated_processor.iff); + if (retem) + jump = 1; + retem = 0; + do_cycles(emulated_processor.cyc); + emulated_processor.cyc = 0; + } else if (is_nec && in_0f) + execvx0_0f(); + else if (is_nec && ((opcode & 0xf0) == 0x60)) + execvx0_6x(&jump); + else 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 = biu_pfq_fetch(); + cpu_dest = get_accum(bits); /* AX/AL */ + cpu_src = cpu_data; + } else { + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + 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 (!(opcode & 0x06) && (cpu_mod != 3)) + 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 = biu_pfq_fetch(); + cpu_dest = get_accum(bits); /* AX/AL */ + cpu_src = cpu_data; + } else { + if (cpu_mod != 3) + do_cycles_i(is_nec ? 1 : 2); /* load_operand() */ + 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 (!(opcode & 0x06) && (cpu_mod != 3)) + do_cycles_i(2); + + /* math_op16() */ + math_op((opcode >> 3) & 7); + /* write_operand16() */ + if (opcode & 0x04) + set_accum(bits, cpu_data); + else { + if (opcode & 0x02) + set_reg(cpu_reg, cpu_data); + else + set_ea(cpu_data); + } + break; + + case 0x06: + case 0x0e: + case 0x16: + case 0x1e: /* PUSH seg */ + do_cycles_i(3); + 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) { + 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: */ + 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 = biu_pfq_fetch(); + cpu_dest = get_accum(bits); /* AX/AL */ + cpu_src = cpu_data; + } else { + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + 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 = biu_pfq_fetch(); + cpu_dest = get_accum(bits); /* AX/AL */ + cpu_src = cpu_data; + } else { + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + 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 */ + switch ((opcode >> 1) & 0x07) { + case 0x00: + jump = cpu_state.flags & V_FLAG; + break; + case 0x01: + jump = cpu_state.flags & C_FLAG; + break; + case 0x02: + jump = cpu_state.flags & Z_FLAG; + break; + case 0x03: + jump = cpu_state.flags & (C_FLAG | Z_FLAG); + break; + case 0x04: + jump = cpu_state.flags & N_FLAG; + break; + case 0x05: + jump = cpu_state.flags & P_FLAG; + break; + case 0x06: + jump = (!!(cpu_state.flags & N_FLAG)) != (!!(cpu_state.flags & V_FLAG)); + break; + case 0x07: + jump = (cpu_state.flags & Z_FLAG) || + ((!!(cpu_state.flags & N_FLAG)) != (!!(cpu_state.flags & V_FLAG))); + break; + } + if (opcode & 1) + jump = !jump; + + rel8 = (int8_t) biu_pfq_fetchb(); + new_ip = cpu_state.pc + rel8; + if (!is_nec) + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_data = get_ea(); + cpu_dest = cpu_data; + cpu_src = biu_pfq_fetchb() | 0xff00; + + do_cycle_nx(); + math_op((rmdat & 0x38) >> 3); + + if (cpu_mod != 3) + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_data = get_ea(); + cpu_dest = cpu_data; + cpu_src = biu_pfq_fetchw(); + + do_cycle_nx(); + math_op((rmdat & 0x38) >> 3); + + if (cpu_mod != 3) { + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_data = get_ea(); + cpu_dest = cpu_data; + cpu_src = sign_extend(biu_pfq_fetchb()); + + do_cycle_nx(); + math_op((rmdat & 0x38) >> 3); + + if (cpu_mod != 3) + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + + do_cycles_nx(3); + + if (cpu_mod != 3) + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_data = get_ea(); + cpu_src = get_reg(cpu_reg); + + do_cycles_nx(3); + + if (cpu_mod != 3) + 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; + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + do_cycle_nx(); + /* read_operand8() */ + if (opcode == 0x88) + tempb = get_reg(cpu_reg); + else + tempb = get_ea(); + + if ((opcode == 0x88) && (cpu_mod != 3)) + do_cycles_i(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; + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + do_cycle_nx(); + /* read_operand16() */ + if (opcode == 0x89) + tempw = get_reg(cpu_reg); + else + tempw = get_ea(); + + if ((opcode == 0x89) && (cpu_mod != 3)) + do_cycles_i(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; + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + if ((opcode == 0x8c) && (cpu_mod != 3)) + 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 */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_state.regs[cpu_reg].w = cpu_state.eaaddr; + break; + + case 0x8f: /* POP r/m16 */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + do_cycle_i(); + /* pop_u16() */ + cpu_src = cpu_state.eaaddr; + cpu_data = pop(); + do_cycle_i(); + if (cpu_mod != 3) + 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 = biu_pfq_fetchw(); + new_cs = biu_pfq_fetchw(); + + farcall(new_cs, new_ip, 1); + + jump = 1; + 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_md_write_disable) + cpu_state.flags = pop() | 0x8002; + else + cpu_state.flags = pop() | 0x0002; + sync_to_i8080(); + 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 = biu_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 = biu_pfq_fetchw(); + tempw = 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 = biu_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 = biu_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(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(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 = biu_pfq_fetch(); + /* math_op8() */ + test(bits, get_accum(bits), cpu_data); + break; + + case 0xa9: /* TEST ax, imm16 */ + bits = 16; + /* read_operand16() */ + cpu_data = biu_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(bits); + do_cycle_i(); + + 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(bits); + 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 = biu_pfq_fetchb(); + /* set_register8() */ + if (opcode & 0x04) + cpu_state.regs[opcode & 0x03].b.h = tempb; + else + cpu_state.regs[opcode & 0x03].b.l = tempb; + do_cycle_i(); + break; + + case 0xb8 ... 0xbf: /* MOV r16, imm16 */ + bits = 16; + /* read_operand16() */ + tempw = biu_pfq_fetchw(); + /* set_register16() */ + cpu_state.regs[opcode & 0x07].w = tempw; + break; + + case 0xc0: /* rot imm8 */ + case 0xc1: + /* rot rm */ + bits = 8 << (opcode & 1); + if (cpu_mod != 3) + do_cycles_i(is_nec ? 1 : 2); /* load_operand() */ + /* read_operand() */ + cpu_data = get_ea(); + cpu_src = biu_pfq_fetchb(); + if (is186 && !is_nec) + cpu_src &= 0x1F; + do_cycles_i(6); + if (cpu_src > 0) { + for (uint8_t i = 0; i < cpu_src; i++) + do_cycles_i(4); + } + if (cpu_mod != 3) + 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 (cpu_mod != 3) + do_cycle_i(); + } + + /* write_operand() */ + set_ea(cpu_data); + break; + + case 0xc2: /* RETN imm16 */ + bits = 8; + cpu_src = biu_pfq_fetchw(); + do_cycle_i(); + new_ip = pop(); + biu_suspend_fetch(); + set_ip(new_ip); + + do_cycles_i(2); + biu_queue_flush(); + do_cycles_i(3); + + /* release() */ + SP += cpu_src; + + jump = 1; + break; + + case 0xc3: /* RETN */ + bits = 8; + new_ip = pop(); + biu_suspend_fetch(); + set_ip(new_ip); + do_cycle_i(); + biu_queue_flush(); + do_cycles_i(2); + + jump = 1; + break; + + case 0xc4: /* LES */ + case 0xc5: /* LDS */ + bits = 16; + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + + 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_data = biu_pfq_fetch(); + do_cycles(2); + /* write_operand8() */ + set_ea(cpu_data); + break; + + case 0xc7: /* MOV r/m16, imm16 */ + bits = 16; + /* read_operand16() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + cpu_data = biu_pfq_fetch(); + do_cycle_i(); + /* write_operand16() */ + set_ea(cpu_data); + break; + + case 0xc8: /* RETF imm16 */ + if (is_nec) { + /* ENTER/PREPARE */ + tempw_int = 0; + size = biu_pfq_fetchw(); + nests = biu_pfq_fetchb(); + + push(&BP); + tempw_int = SP; + if (nests > 0) { + while (--nests) { + tempbp = 0; + BP -= 2; + tempbp = readmemw(ss, BP); + push(&tempbp); + } + push(&tempw_int); + } + BP = tempw_int; + SP -= size; + break; + } else + fallthrough; + case 0xca: + bits = 16; + /* read_operand16() */ + cpu_src = biu_pfq_fetchw(); + farret(1); + /* release() */ + SP += cpu_src; + do_cycle_i(); + jump = 1; + break; + + case 0xc9: /* RETF */ + if (is_nec) { + /* LEAVE/DISPOSE */ + SP = BP; + BP = pop(); + break; + } else + fallthrough; + case 0xcb: + bits = 16; + 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 = biu_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(); + if (is_nec && !(cpu_state.flags & MD_FLAG)) + sync_to_i8080(); + 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); + if (cpu_mod != 3) + do_cycles_i(is_nec ? 1 : 2); /* load_operand() */ + /* 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 (cpu_mod != 3) + do_cycle_i(); + } + /* bitshift_op() */ + while (cpu_src != 0) { + cpu_dest = cpu_data; + oldc = cpu_state.flags & C_FLAG; + if (is_nec && ((rmdat & 0x38) == 0x30)) + rmdat &= 0xef; /* Make it 0x20, so it aliases to SHL. */ + 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 (cpu_mod != 3) + do_cycle_i(); + } + + /* write_operand() */ + set_ea(cpu_data); + break; + + case 0xd4: /* AAM */ + /* read_operand8() */ + cpu_src = biu_pfq_fetchb(); + + if (is_nec) { + if (!cpu_src) + cpu_src = 10; + AH = AL / cpu_src; + AL %= cpu_src; + cpu_data = AL; + set_pzs(8); + do_cycles(12); + } else { + /* Confirmed to be identical on V20/V30 to 808x, per + XTIDE working correctly on both (it uses AAM with + parameter other than 10. */ + /* aam() */ + if (x86_div(AL, 0)) { + cpu_data = AL; + set_pzs(8); + } + } + break; + + case 0xd5: /* AAD */ + /* read_operand8() */ + cpu_src = biu_pfq_fetchb(); + + if (is_nec) { + cpu_src = 10; + AL = (AH * cpu_src) + AL; + AH = 0; + cpu_data = AL; + set_pzs(8); + do_cycles(4); + } else { + 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; + set_pzs(8); + } + break; + + case 0xd6: /* SALC */ + if (is_nec) { + do_cycles(14); + fallthrough; + } else { + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + break; + } + case 0xd7: /* XLAT */ + do_cycles_i(3); + /* 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() */ + if (cpu_mod != 3) + do_cycles_i(2); /* load_operand() */ + 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 = biu_pfq_fetchb(); + + if ((CX != 0x0000) && zero_cond) { + rel8 = (int8_t) cpu_data; + new_ip = (cpu_state.pc + rel8) & 0xffff; + reljmp(new_ip, 1); + jump = 1; + do_print = 0; + } else { + do_cycle_i(); + do_print = 1; + } + break; + + case 0xe2: /* LOOP */ + /* decrement_register16() */ + --CX; + do_cycles_i(2); + + /* read_operand8() */ + cpu_data = biu_pfq_fetchb(); + + if (CX != 0x0000) { + rel8 = (int8_t) cpu_data; + new_ip = (cpu_state.pc + rel8) & 0xffff; + reljmp(new_ip, 1); + jump = 1; + do_print = 0; + } + if (!jump) { + do_cycle(); + do_print = 1; + } + break; + + case 0xe3: /* JCXZ */ + do_cycles_i(2); + /* read_operand8() */ + cpu_data = biu_pfq_fetchb(); + + do_cycle_i(); + + if (CX == 0x0000) { + rel8 = (int8_t) cpu_data; + new_ip = (cpu_state.pc + rel8) & 0xffff; + reljmp(new_ip, 1); + jump = 1; + } else + do_cycle_i(); + break; + + case 0xe4: /* IN al, imm8 */ + bits = 8; + /* read_operand8() */ + cpu_data = biu_pfq_fetchb(); + do_cycles_i(2); + + /* biu_io_read_u8() */ + cpu_state.eaaddr = cpu_data; + cpu_io_vx0(bits, 0, cpu_state.eaaddr); + /* set_register8() */ + break; + + case 0xe5: /* IN ax, imm8 */ + bits = 16; + /* read_operand16() */ + cpu_data = biu_pfq_fetchb(); + do_cycles_i(2); + + /* biu_io_read_u16() */ + cpu_state.eaaddr = cpu_data; + cpu_io_vx0(bits, 0, cpu_state.eaaddr); + /* set_register16() */ + break; + + case 0xe6: /* OUT imm8, al */ + bits = 8; + /* read_operand8() */ + cpu_data = biu_pfq_fetchb(); + /* read_operand8() */ + tempb = AL; + do_cycles_i(2); + + /* biu_io_write_u8() */ + cpu_state.eaaddr = cpu_data; + cpu_data = tempb; + cpu_io_vx0(bits, 1, cpu_state.eaaddr); + break; + + case 0xe7: /* OUT imm8, ax */ + bits = 16; + /* read_operand8() */ + cpu_data = biu_pfq_fetchb(); + /* read_operand16() */ + tempw = AX; + do_cycles_i(2); + + /* biu_io_write_u16() */ + cpu_state.eaaddr = cpu_data; + cpu_data = tempw; + cpu_io_vx0(bits, 1, cpu_state.eaaddr); + break; + + case 0xe8: /* CALL rel16 */ + /* read_operand16() */ + rel16 = (int16_t) biu_pfq_fetchw(); + + biu_suspend_fetch(); + do_cycles_i(4); + + old_ip = cpu_state.pc; + new_ip = cpu_state.pc + rel16; + + set_ip(new_ip); + biu_queue_flush(); + do_cycles_i(3); + + push(&old_ip); + jump = 1; + break; + + case 0xe9: /* JMP rel16 */ + /* read_operand16() */ + rel16 = (int16_t) biu_pfq_fetchw(); + new_ip = (cpu_state.pc + rel16) & 0xffff; + + reljmp(new_ip, 1); + jump = 1; + break; + + case 0xea: /* JMP far [addr16:16] */ + /* read_operand_faraddr() */ + addr = biu_pfq_fetchw(); + tempw = biu_pfq_fetchw(); + load_cs(tempw); + set_ip(addr); + + biu_suspend_fetch(); + do_cycles_i(2); + biu_queue_flush(); + do_cycle_i(); + jump = 1; + break; + + case 0xeb: /* JMP rel8 */ + /* read_operand8() */ + rel8 = (int8_t) biu_pfq_fetchb(); + new_ip = (cpu_state.pc + rel8) & 0xffff; + + 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_vx0(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_vx0(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_data = tempb; + cpu_io_vx0(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_data = tempw; + cpu_io_vx0(bits, 1, cpu_state.eaaddr); + break; + + case 0xf0: + case 0xf1: /* LOCK - F1 is alias */ + break; + + case 0xf2: /* REPNE */ + case 0xf3: /* REPE */ + break; + + case 0xf4: /* HLT */ + if (is_nec) + in_hlt = 1; + + if (!repeating) { + biu_suspend_fetch(); + // biu_queue_flush(); + do_cycles(2); + /* TODO: biu_halt(); */ + do_cycle(); + } + + do_cycle_i(); + do_cycle_i(); + do_cycle_i(); + if (irq_pending()) { + halted = 0; + check_interrupts(); + } else { + repeating = 1; + completed = 0; + + halted = 1; + } + + if (is_nec) + in_hlt = 0; + break; + + case 0xf5: /* CMC */ + cpu_state.flags ^= C_FLAG; + break; + + case 0xf6: /* Miscellaneuous Opcode Extensions, r/m8, imm8 */ + bits = 8; + if (cpu_mod != 3) + do_cycles_i(is_nec ? 1 : 2); /* load_operand() */ + negate = !!in_rep; + + if (is_nec && ((rmdat & 0x38) >= 0x20)) switch (rmdat & 0x38) { + case 0x20: /* MUL */ + /* read_operand8() */ + cpu_data = get_ea(); + + AX = AL * cpu_data; + if (AH) + cpu_state.flags |= (C_FLAG | V_FLAG); + else + cpu_state.flags &= ~(C_FLAG | V_FLAG); + + do_cycles((cpu_mod == 3) ? 24 : 30); + break; + case 0x28: /* IMUL */ + /* read_operand8() */ + cpu_data = get_ea(); + + tempws = (int) ((int8_t) AL) * (int) ((int8_t) cpu_data); + AX = tempws & 0xffff; + if (((int16_t) AX >> 7) != 0 && ((int16_t) AX >> 7) != -1) + cpu_state.flags |= (C_FLAG | V_FLAG); + else + cpu_state.flags &= ~(C_FLAG | V_FLAG); + + do_cycles((cpu_mod == 3) ? 13 : 19); + break; + case 0x30: /* DIV */ + /* read_operand8() */ + cpu_data = get_ea(); + + src16 = AX; + if (cpu_data) + tempw = src16 / cpu_data; + if (cpu_data && !(tempw & 0xff00)) { + AH = src16 % cpu_data; + AL = (src16 / cpu_data) & 0xff; + cpu_state.flags |= 0x8D5; + cpu_state.flags &= ~1; + } else { + intr_routine(0, 0); + break; + } + + do_cycles((cpu_mod == 3) ? 21 : 27); + break; + case 0x38: /* IDIV */ + /* read_operand8() */ + cpu_data = get_ea(); + + tempws = (int) (int16_t) AX; + if (cpu_data != 0) + tempws2 = tempws / (int) ((int8_t) cpu_data); + temps = tempws2 & 0xff; + if (cpu_data && ((int) temps == tempws2)) { + AH = (tempws % (int) ((int8_t) cpu_data)) & 0xff; + AL = tempws2 & 0xff; + cpu_state.flags |= 0x8D5; + cpu_state.flags &= ~1; + } else { + intr_routine(0, 0); + break; + } + + do_cycles((cpu_mod == 3) ? 11 : 17); + break; + } else switch (rmdat & 0x38) { + case 0x00: /* TEST */ + case 0x08: + /* read_operand8() */ + cpu_data = get_ea(); + /* read_operand8() */ + cpu_src = biu_pfq_fetch(); + + do_cycles_i(is_nec ? 1 : 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 (cpu_mod != 3) + 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 (!is_nec && negate) + AL = -AL; + do_cycle(); + } + break; + } + break; + + case 0xf7: /* Miscellaneuous Opcode Extensions, r/m16, imm16 */ + bits = 16; + if (cpu_mod != 3) + do_cycles_i(is_nec ? 1 : 2); /* load_operand() */ + negate = !!in_rep; + + if (is_nec && ((rmdat & 0x38) >= 0x20)) switch (rmdat & 0x38) { + case 0x20: /* MUL */ + /* read_operand16() */ + cpu_data = get_ea(); + + templ = AX * cpu_data; + AX = templ & 0xFFFF; + DX = templ >> 16; + if (DX) + cpu_state.flags |= (C_FLAG | V_FLAG); + else + cpu_state.flags &= ~(C_FLAG | V_FLAG); + + do_cycles((cpu_mod == 3) ? 29 : 35); + break; + case 0x28: /* IMUL */ + /* read_operand16() */ + cpu_data = get_ea(); + + templ = (int) ((int16_t) AX) * (int) ((int16_t) cpu_data); + AX = templ & 0xFFFF; + DX = templ >> 16; + if (((int32_t) templ >> 15) != 0 && ((int32_t) templ >> 15) != -1) + cpu_state.flags |= (C_FLAG | V_FLAG); + else + cpu_state.flags &= ~(C_FLAG | V_FLAG); + + do_cycles((cpu_mod == 3) ? 17 : 27); + break; + case 0x30: /* DIV */ + /* read_operand16() */ + cpu_data = get_ea(); + + templ = (DX << 16) | AX; + if (cpu_data) + templ2 = templ / cpu_data; + if (cpu_data && !(templ2 & 0xffff0000)) { + DX = templ % cpu_data; + AX = (templ / cpu_data) & 0xffff; + cpu_data = AX; + set_pzs(16); + } else { + intr_routine(0, 0); + break; + } + + do_cycles((cpu_mod == 3) ? 26 : 36); + break; + case 0x38: /* IDIV */ + /* read_operand16() */ + cpu_data = get_ea(); + + tempws = (int) ((DX << 16) | AX); + if (cpu_data) + tempws2 = tempws / (int) ((int16_t) cpu_data); + temps16 = tempws2 & 0xffff; + if ((cpu_data != 0) && ((int) temps16 == tempws2)) { + DX = tempws % (int) ((int16_t) cpu_data); + AX = tempws2 & 0xffff; + cpu_data = AX; + set_pzs(16); + } else { + intr_routine(0, 0); + break; + } + + do_cycles((cpu_mod == 3) ? 13 : 23); + break; + } else switch (rmdat & 0x38) { + case 0x00: /* TEST */ + case 0x08: + /* read_operand16() */ + cpu_data = get_ea(); + /* read_operand16() */ + cpu_src = biu_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 (cpu_mod != 3) + 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 (!is_nec && negate) + AX = -AX; + do_cycle(); + } + 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; + if (cpu_mod != 3) + do_cycles_i(is_nec ? 1 : 2); /* load_operand() */ + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + /* read_operand8() */ + /* math_op8() */ + cpu_dest = cpu_data; + cpu_src = 1; + 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 (cpu_mod != 3) + do_cycles_i(2); + /* write_operand8() */ + set_ea(cpu_data); + break; + case 0x10: /* CALL rm */ + /* read_operand8() */ + cpu_data_opff_rm(); + + cpu_state.oldpc = cpu_state.pc; + push((uint16_t *) &(cpu_state.oldpc)); + + biu_suspend_fetch(); + do_cycles(4); + biu_queue_flush(); + + set_ip(cpu_data | 0xff00); + 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); + + biu_suspend_fetch(); + do_cycles(4); + biu_queue_flush(); + + read_ea_8to16(); + set_ip(cpu_data); + } else { + /* read_operand8() */ + 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(); + biu_suspend_fetch(); + 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); + biu_queue_flush(); + do_cycles_i(3); + + push(&old_ip); + } + break; + case 0x20: /* JMP rm */ + /* read_operand8() */ + cpu_data_opff_rm(); + + set_ip(cpu_data | 0xff00); + + biu_suspend_fetch(); + do_cycles(4); + biu_queue_flush(); + 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); + + biu_suspend_fetch(); + do_cycles(4); + biu_queue_flush(); + + read_ea_8to16(); + set_ip(cpu_data); + } else { + /* read_operand8() */ + new_ip = cpu_data | 0xff00; + + /* biu_read_u8() */ + read_ea2(bits); + cpu_data |= 0xff00; + new_cs = cpu_data; + + biu_suspend_fetch(); + do_cycles(4); + biu_queue_flush(); + + load_cs(new_cs); + set_ip(new_ip); + } + break; + case 0x30: /* PUSH rm */ + case 0x38: + /* read_operand8() */ + do_cycles_i(3); + cpu_data &= 0x00ff; + push((uint16_t *) &cpu_data); + break; + } + break; + + case 0xff: + bits = 16; + if (cpu_mod != 3) + do_cycles_i(is_nec ? 1 : 2); /* load_operand() */ + read_ea(((rmdat & 0x38) == 0x18) || ((rmdat & 0x38) == 0x28), bits); + switch (rmdat & 0x38) { + case 0x00: /* INC rm */ + case 0x08: /* DEC rm */ + /* read_operand16() */ + /* math_op16() */ + cpu_dest = cpu_data; + cpu_src = 1; + 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 (cpu_mod != 3) + do_cycles_i(2); + /* write_operand16() */ + set_ea(cpu_data); + break; + case 0x10: /* CALL rm */ + /* read_operand16() */ + cpu_data_opff_rm(); + + biu_suspend_fetch(); + do_cycles(4); + + cpu_state.oldpc = cpu_state.pc; + + old_ip = cpu_state.pc; + set_ip(cpu_data); + biu_queue_flush(); + do_cycles_i(3); + + push(&old_ip); + break; + case 0x18: /* CALL rmd */ + if (cpu_mod == 3) { + 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(); + biu_suspend_fetch(); + do_cycles_i(3); + + push(&CS); + old_ip = cpu_state.pc; + set_ip(new_ip); + + load_cs(new_cs); + + do_cycles_i(3); + biu_queue_flush(); + do_cycles_i(3); + + push(&old_ip); + } else { + do_cycle_i(); + /* read_operand_farptr() */ + new_ip = cpu_data; + read_ea2(bits); + new_cs = cpu_data; + + do_cycle_i(); + + biu_suspend_fetch(); + do_cycles_i(3); + + push(&CS); + + load_cs(new_cs); + old_ip = cpu_state.pc; + set_ip(new_ip); + do_cycles_i(3); + biu_queue_flush(); + do_cycles_i(3); + push(&old_ip); + } + break; + case 0x20: /* JMP rm */ + /* read_operand16() */ + cpu_data_opff_rm(); + + biu_suspend_fetch(); + do_cycle_i(); + set_ip(cpu_data); + biu_queue_flush(); + break; + case 0x28: /* JMP rmd */ + if (cpu_mod == 3) { + new_ip = cpu_data; + + do_cycle(); + biu_suspend_fetch(); + do_cycle(); + + /* biu_read_u16() */ + cpu_state.eaaddr = 0x0004; + new_cs = readmemw((ovr_seg ? *ovr_seg : ds), cpu_state.eaaddr); + + push(&CS); + biu_queue_flush(); + } else { + do_cycle_i(); + biu_suspend_fetch(); + do_cycle_i(); + + /* read_operand_farptr() */ + new_ip = cpu_data; + read_ea2(bits); + new_cs = cpu_data; + + load_cs(new_cs); + set_ip(new_ip); + biu_queue_flush(); + } + break; + case 0x30: /* PUSH rm */ + case 0x38: + /* read_operand16() */ + do_cycles_i(3); + + if (cpu_rm == 4) + cpu_rm -= 2; + push((uint16_t *) &cpu_data); + break; + } + break; + + default: + vx0_log("Illegal opcode: %02X\n", opcode); + biu_pfq_fetchb(); + do_cycles(8); + break; + } +} + +/* Executes instructions up to the specified number of cycles. */ +void +execvx0(int cycs) +{ + cycles += cycs; + + while (cycles > 0) { + if (started) { + started = 0; + startx86(); + } + +#ifdef DEBUG_INSTRUCTIONS + if (repeating) { + if ((opcode >= MIN_INS) && (opcode <= MAX_INS) && (opcode != SKIP_INS)) { + execx86_instruction(); + goto check_completed; + } + } else { +#else + if (!repeating) { +#endif + cpu_state.oldpc = cpu_state.pc; + + if (clear_lock) { + in_lock = 0; + clear_lock = 0; + } + + if (!is_nec || (cpu_state.flags & MD_FLAG)) { + decode(); + +#ifdef DEBUG_INSTRUCTIONS + if ((opcode >= MIN_INS) && (opcode <= MAX_INS) && (opcode != SKIP_INS)) { + oldc = cpu_state.flags & C_FLAG; + + execx86_instruction(); + goto check_completed; + } +#endif + + decode_modrm(); + } + + oldc = cpu_state.flags & C_FLAG; + } + + vx0_log("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); + + execute_instruction(); + +#ifdef DEBUG_INSTRUCTIONS +check_completed: +#endif + if (completed) { + if (opcode != 0xf4) + finalize(); + + check_interrupts(); + + if (noint) + noint = 0; + } + +#ifdef USE_GDBSTUB + if (gdbstub_instruction()) + return; +#endif + } +} diff --git a/src/cpu/vx0_biu.c b/src/cpu/vx0_biu.c new file mode 100644 index 000000000..92f1909a6 --- /dev/null +++ b/src/cpu/vx0_biu.c @@ -0,0 +1,1152 @@ +/* + * 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. + * + * Vx0 BIU emulation. + * + * 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 "vx0_biu.h" + +#define do_cycle() wait_vx0(1) +#define do_cycle_i() do_cycle() + +uint8_t biu_preload_byte = 0x00; + +int bus_request_type = 0; + +int pic_data = -1; +int biu_queue_preload = 0; + +/* The IP equivalent of the current prefetch queue position. */ +static uint16_t pfq_ip = 0x0000; +static uint16_t pfq_in = 0x0000; + +/* Variables to aid with the prefetch queue operation. */ +static int pfq_size = 0; + +static int cycles_ex = 0; + +/* The prefetch queue (4 bytes for 8088, 6 bytes for 8086). */ +static uint8_t pfq[6]; + +static int biu_cycles = 0; +static int biu_wait = 0; +static int biu_wait_length = 0; +static int refresh = 0; +static uint16_t mem_data = 0; +static uint32_t mem_seg = 0; +static uint16_t mem_addr = 0; +static int biu_state = 0; +static int biu_next_state = 0; +static int biu_scheduled_state = 0; +static int biu_state_length = 0; +static int biu_state_total_len = 0; +static int dma_state = 0; +static int dma_state_length = 0; +static int wait_states = 0; +static int fetch_suspended = 0; +static int ready = 1; +static int dma_wait_states = 0; + +#define BUS_CYCLE (biu_cycles & 3) +#define BUS_CYCLE_T1 biu_cycles = 0 +#define BUS_CYCLE_NEXT biu_cycles = (biu_cycles + 1) & 3 + +/* DEBUG stuff. */ +const char *lpBiuStates[7] = { "Ti ", "Ti S ", "Ti D ", "Ti R ", "Tw ", "T%i PF", "T%i EU" }; + +#ifdef ENABLE_VX0_BIU_LOG +int vx0_biu_do_log = ENABLE_VX0_BIU_LOG; + +static void +vx0_biu_log(const char *fmt, ...) +{ + va_list ap; + + if (vx0_biu_do_log) { + va_start(ap, fmt); + pclog_ex(fmt, ap); + va_end(ap); + } +} +#else +# define vx0_biu_log(fmt, ...) +#endif + +void +biu_set_bus_cycle(int bus_cycle) +{ + biu_cycles = bus_cycle; +} + +void +biu_set_bus_state(int bus_state) +{ + biu_state = bus_state; +} + +void +biu_set_bus_next_state(int bus_next_state) +{ + biu_state = bus_next_state; +} + +void +biu_set_cycle_t1(void) +{ + BUS_CYCLE_T1; +} + +void +biu_set_next_cycle(void) +{ + BUS_CYCLE_NEXT; +} + +int +biu_get_bus_cycle(void) +{ + return BUS_CYCLE; +} + +int +biu_get_bus_state(void) +{ + return biu_state; +} + +int +biu_get_bus_next_state(void) +{ + return biu_next_state; +} + +static void pfq_add(void); + +static void +pfq_resume(int delay) +{ + if (is_nec) + biu_state = BIU_STATE_PF; + else { + biu_state = BIU_STATE_RESUME; + biu_state_length = delay; + biu_state_total_len = delay; + } +} + +static void +pfq_switch_to_pf(int delay) +{ + if (is_nec) + biu_next_state = BIU_STATE_PF; + else { + biu_next_state = BIU_STATE_RESUME; + biu_state_length = delay; + biu_state_total_len = delay; + } +} + +static uint8_t +biu_queue_delay(void) +{ + if (is8086) + return pfq_pos == 4; + else + return pfq_pos == 3; +} + +static void +pfq_schedule(void) +{ + if (biu_state == BIU_STATE_EU) { + if (!is_nec && biu_queue_delay()) { + biu_next_state = BIU_STATE_DELAY; + biu_state_length = 3; + biu_state_total_len = 3; + } else if ((is_nec || !fetch_suspended) && (pfq_pos < 4)) + biu_next_state = BIU_STATE_PF; + else + biu_next_state = BIU_STATE_IDLE; + } else { + if (!is_nec && biu_queue_delay()) { + biu_next_state = BIU_STATE_DELAY; + biu_state_length = 3; + biu_state_total_len = 3; + } else + biu_next_state = BIU_STATE_PF; + } +} + +void +biu_reset(void) +{ + BUS_CYCLE_T1; + biu_cycles = 0; + biu_wait = 0; + refresh = 0; + bus_request_type = 0; + biu_queue_preload = 0; + pic_data = -1; + mem_data = 0; + mem_seg = 0; + mem_addr = 0; + wait_states = 0; + dma_state = DMA_STATE_IDLE; + dma_state_length = 0; + biu_state = BIU_STATE_IDLE; + biu_next_state = BIU_STATE_IDLE; + biu_scheduled_state = BIU_STATE_IDLE; + biu_state_length = 0; + pfq_size = is8086 ? 6 : 4; + pfq_in = 0x0000; +} + +static void +process_timers(void) +{ + /* On 808x systems, clock speed is usually crystal frequency divided by an integer. */ + tsc += ((uint64_t) 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, (uint64_t) tsc)) + timer_process(); +} + +static void +cycles_forward(int c) +{ + for (int i = 0; i < c; i++) { + cycles--; + if (!is286) + process_timers(); + } + + cycles_ex++; +} + +static void +bus_outb(uint16_t port, uint8_t val) +{ + outb(port, val); +} + +static void +bus_outw(uint16_t port, uint16_t val) +{ + outw(port, val); +} + +static uint8_t +bus_inb(uint16_t port) +{ + uint8_t ret; + + ret = inb(port); + + return ret; +} + +static uint16_t +bus_inw(uint16_t port) +{ + uint16_t ret; + + ret = inw(port); + + return ret; +} + +void +resub_cycles_vx0(int old_cycles) +{ + if (old_cycles > cycles) + wait_states = old_cycles - cycles; + + cycles = old_cycles; +} + +static void +bus_do_io(int io_type) +{ + int old_cycles = cycles; + + vx0_biu_log("(%02X) bus_do_io(%02X): %04X\n", opcode, io_type, cpu_state.eaaddr); + + if (io_type & BUS_OUT) { + if (io_type & BUS_WIDE) + bus_outw((uint16_t) cpu_state.eaaddr, AX); + else if (io_type & BUS_HIGH) + bus_outb(((uint16_t) cpu_state.eaaddr + 1) & 0xffff, AH); + else + bus_outb((uint16_t) cpu_state.eaaddr, AL); + } else { + if (io_type & BUS_WIDE) + AX = bus_inw((uint16_t) cpu_state.eaaddr); + else if (io_type & BUS_HIGH) + AH = bus_inb(((uint16_t) cpu_state.eaaddr + 1) & 0xffff); + else + AL = bus_inb((uint16_t) cpu_state.eaaddr); + } + + resub_cycles_vx0(old_cycles); +} + +static void +bus_writeb(uint32_t seg, uint32_t addr, uint8_t val) +{ + write_mem_b(seg + addr, val); +} + +static void +bus_writew(uint32_t seg, uint32_t addr, uint16_t val) +{ + write_mem_w(seg + addr, val); +} + +static uint8_t +bus_readb(uint32_t seg, uint32_t addr) +{ + uint8_t ret = read_mem_b(seg + addr); + + return ret; +} + +static uint16_t +bus_readw(uint32_t seg, uint32_t addr) +{ + uint16_t ret = read_mem_w(seg + addr); + + return ret; +} + +static void +bus_do_mem(int io_type) +{ + int old_cycles = cycles; + + if (io_type & BUS_OUT) { + if (io_type & BUS_WIDE) + bus_writew(mem_seg, (uint32_t) mem_addr, mem_data); + else if (io_type & BUS_HIGH) { + if (is186 && !is_nec) + bus_writeb(mem_seg, ((uint32_t) mem_addr) + 1, mem_data >> 8); + else + bus_writeb(mem_seg, (uint32_t) ((mem_addr + 1) & 0xffff), mem_data >> 8); + } else + bus_writeb(mem_seg, (uint32_t) mem_addr, mem_data & 0xff); + } else { + if (io_type & BUS_WIDE) + mem_data = bus_readw(mem_seg, (uint32_t) mem_addr); + else if (io_type & BUS_HIGH) { + if (is186 && !is_nec) + mem_data = (mem_data & 0x00ff) | + (((uint16_t) bus_readb(mem_seg, ((uint32_t) mem_addr) + 1)) << 8); + else + mem_data = (mem_data & 0x00ff) | + (((uint16_t) bus_readb(mem_seg, (uint32_t) ((mem_addr + 1) & 0xffff))) << 8); + } else + mem_data = (mem_data & 0xff00) | ((uint16_t) bus_readb(mem_seg, (uint32_t) mem_addr)); + } + + resub_cycles_vx0(old_cycles); +} + +static void +biu_print_cycle(void) +{ + if ((CS == DEBUG_SEG) && (cpu_state.pc >= DEBUG_OFF_L) && (cpu_state.pc <= DEBUG_OFF_H)) { + if (biu_state >= BIU_STATE_PF) { + if (biu_wait) { + vx0_biu_log("[%04X:%04X] [%i, %i] (%i) %s (%i)\n", CS, cpu_state.pc, dma_state, dma_wait_states, + pfq_pos, lpBiuStates[BIU_STATE_WAIT], wait_states); + } else { + char temp[16] = { 0 }; + + sprintf(temp, lpBiuStates[biu_state], biu_cycles + 1); + vx0_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, + pfq_pos, temp); + } + } else { + vx0_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, + pfq_pos, lpBiuStates[biu_state]); + } + } +} + +static void +do_wait(void) +{ + if (wait_states > 0) + wait_states--; + + if (dma_wait_states > 0) + dma_wait_states--; +} + +static void +run_dma_cycle(void) +{ + int bus_cycle_check = ((biu_state < BIU_STATE_PF) || (BUS_CYCLE == BUS_T3) || + (BUS_CYCLE == BUS_T4) || biu_wait) && !in_lock; + + switch (dma_state) { + case DMA_STATE_TIMER: + dma_state = DMA_STATE_DREQ; + dma_state_length = 1; + break; + case DMA_STATE_DREQ: + dma_state = DMA_STATE_HRQ; + dma_state_length = 1; + break; + case DMA_STATE_HRQ: + if (!in_lock && bus_cycle_check) { + dma_state = DMA_STATE_HLDA; + dma_state_length = 1; + } + break; + case DMA_STATE_HLDA: + dma_state = DMA_STATE_OPERATING; + dma_state_length = 4; + break; + case DMA_STATE_OPERATING: + dma_state_length--; + if (dma_state_length == 3) { + dma_wait_states = 7; + ready = 0; + } else if (dma_state_length == 0) { + dma_state = DMA_STATE_IDLE; + dma_state_length = 1; + } + break; + } +} + +static void +biu_cycle_idle(int type) +{ + if ((CS == DEBUG_SEG) && (cpu_state.pc >= DEBUG_OFF_L) && (cpu_state.pc <= DEBUG_OFF_H)) { + vx0_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, + pfq_pos, lpBiuStates[type]); + } + + run_dma_cycle(); + cycles_forward(1); + + do_wait(); +} + +/* Reads a byte from the memory but does not advance the BIU. */ +static uint8_t +readmembf(uint32_t a) +{ + uint8_t ret; + + a = cs + (a & 0xffff); + ret = read_mem_b(a); + + return ret; +} + +static uint16_t +readmemwf(uint16_t a) +{ + uint16_t ret; + + ret = read_mem_w(cs + (a & 0xffff)); + + return ret; +} + +static void +do_bus_access(void) +{ + int io_type = (biu_state == BIU_STATE_EU) ? bus_request_type : BUS_CODE; + + vx0_biu_log("[%04X:%04X] %02X bus access %02X\n", CS, cpu_state.pc, opcode, io_type); + + if (io_type != 0) { + wait_states = 0; + switch (io_type & BUS_ACCESS_TYPE) { + case BUS_CODE: + if (is8086) + pfq_in = readmemwf(pfq_ip); + else + pfq_in = readmembf(pfq_ip); + break; + case BUS_IO: + bus_do_io(io_type); + break; + case BUS_MEM: + bus_do_mem(io_type); + break; + case BUS_PIC: + pic_data = pic_irq_ack(); + break; + default: + break; + } + } +} + +static uint8_t +biu_queue_has_room(void) +{ + if (is8086) + return pfq_pos < 5; + else + return pfq_pos < 4; +} + +static int bus_access_done = 0; + +static void +biu_do_cycle(void) +{ + int biu_old_state = biu_state; + + biu_print_cycle(); + + switch (biu_state) { + default: + fatal("Invalid BIU state: %02X\n", biu_state); + break; + case BIU_STATE_RESUME: + if (biu_state_length > 0) { + biu_state_length--; + if (biu_state_length == 0) { + biu_state = BIU_STATE_PF; + biu_next_state = BIU_STATE_PF; + } + } else { + biu_state = BIU_STATE_PF; + biu_next_state = BIU_STATE_PF; + } + break; + case BIU_STATE_IDLE: + case BIU_STATE_SUSP: + biu_state = biu_next_state; + break; + case BIU_STATE_DELAY: + if (biu_state_length > 0) { + biu_state_length--; + if (biu_state_length == 0) { + if (biu_queue_has_room()) { + biu_state = BIU_STATE_PF; + biu_next_state = BIU_STATE_PF; + } else { + biu_state = BIU_STATE_IDLE; + biu_next_state = BIU_STATE_IDLE; + } + } + } else { + if (biu_queue_has_room()) { + biu_state = BIU_STATE_PF; + biu_next_state = BIU_STATE_PF; + } else { + biu_state = BIU_STATE_IDLE; + biu_next_state = BIU_STATE_IDLE; + } + } + break; + case BIU_STATE_PF: + case BIU_STATE_EU: + if (biu_wait) { + if ((wait_states == 0) && (dma_wait_states == 0)) { + biu_wait = 0; + BUS_CYCLE_NEXT; + } + } else { + if (BUS_CYCLE == BUS_T4) { + if (biu_state == BIU_STATE_PF) + pfq_add(); + biu_state = biu_next_state; + } + + if ((BUS_CYCLE == BUS_T3) && (biu_state == BIU_STATE_EU)) { + if ((bus_request_type != 0) && ((bus_request_type & BUS_ACCESS_TYPE) == BUS_IO)) + wait_states++; + } + + if ((BUS_CYCLE == BUS_T3) && ((wait_states != 0) || (dma_wait_states != 0))) + biu_wait = 1; + else { + biu_wait = 0; + BUS_CYCLE_NEXT; + } + + if ((BUS_CYCLE == BUS_T1) && (biu_state == BIU_STATE_IDLE) && biu_queue_delay()) { + if (biu_old_state == BIU_STATE_EU) + pfq_resume(2); + else + biu_state = BIU_STATE_PF; + } + } + + if (bus_access_done && !biu_wait) + bus_access_done = 0; + break; + } +} + +static int +biu_is_last_tw(void) +{ + return ((biu_state >= BIU_STATE_PF) && biu_wait && ((wait_states + dma_wait_states) == 1)); +} + +static void +biu_cycle(void) +{ + if (biu_state >= BIU_STATE_PF) { + if (BUS_CYCLE == BUS_T2) + pfq_schedule(); + else if (((BUS_CYCLE == BUS_T3) && !biu_wait) || biu_is_last_tw()) { + if (!bus_access_done) { + do_bus_access(); + bus_access_done = 1; + } + } + } + + run_dma_cycle(); + + biu_do_cycle(); + + cycles_forward(1); + + do_wait(); +} + +static void +biu_eu_request(void) +{ + switch (biu_state) { + default: + fatal("Invalid BIU state: %02X\n", biu_state); + break; + case BIU_STATE_RESUME: + /* Resume it - leftover cycles. */ + if (!is_nec) for (uint8_t i = 0; i < (biu_state_total_len - biu_state_length); i++) + biu_cycle_idle(biu_state); + break; + case BIU_STATE_IDLE: + case BIU_STATE_SUSP: + /* Resume it - 3 cycles. */ + if (!is_nec) for (uint8_t i = 0; i < 3; i++) + biu_cycle_idle(biu_state); + break; + case BIU_STATE_DELAY: + case BIU_STATE_EU: + /* Do the request immediately (needs hardware testing). */ + biu_state_length = 0; + break; + case BIU_STATE_PF: + /* Transition the state. */ + switch (BUS_CYCLE) { + case BUS_T1: + case BUS_T2: + /* Leftover BIU cycles. */ + do + biu_cycle(); + while (BUS_CYCLE != BUS_T1); + break; + case BUS_T3: + case BUS_T4: + /* Leftover BIU cycles. */ + do + biu_cycle(); + while (BUS_CYCLE != BUS_T1); + /* The two abort cycles. */ + if (!is_nec) for (uint8_t i = 0; i < 2; i++) + biu_cycle_idle(BIU_STATE_IDLE); + break; + + default: + break; + } + break; + } + + biu_state = BIU_STATE_EU; + biu_next_state = BIU_STATE_EU; + + biu_state_length = 0; +} + +void +wait_vx0(int c) +{ + vx0_biu_log("[%04X:%04X] %02X %i cycles\n", CS, cpu_state.pc, opcode, c); + + for (uint8_t i = 0; i < c; i++) + biu_cycle(); +} + +/* This is for external subtraction of cycles, ie. wait states. */ +void +sub_cycles_vx0(int c) +{ + cycles -= c; +} + +void +biu_begin_eu(void) +{ + biu_eu_request(); +} + +static void +biu_wait_for_write_finish(void) +{ + while (BUS_CYCLE != BUS_T4) { + biu_cycle(); + if (biu_wait_length == 1) + break; + } +} + +void +biu_wait_for_read_finish(void) +{ + biu_wait_for_write_finish(); + biu_cycle(); +} + +void +cpu_io_vx0(int bits, int out, uint16_t port) +{ + /* Do this, otherwise, the first half of the operation never happens. */ + if ((BUS_CYCLE == BUS_T4) && (biu_state == BIU_STATE_EU)) + BUS_CYCLE_T1; + + if (out) { + if (bits == 16) { + if (is8086 && !(port & 1)) { + bus_request_type = BUS_IO | BUS_OUT | BUS_WIDE; + biu_begin_eu(); + biu_wait_for_write_finish(); + } else { + bus_request_type = BUS_IO | BUS_OUT; + biu_begin_eu(); + biu_wait_for_write_finish(); + biu_cycle(); + biu_state = BIU_STATE_EU; + biu_state_length = 0; + bus_request_type = BUS_IO | BUS_OUT | BUS_HIGH; + biu_wait_for_write_finish(); + } + } else { + bus_request_type = BUS_IO | BUS_OUT; + biu_begin_eu(); + biu_wait_for_write_finish(); + } + } else { + if (bits == 16) { + if (is8086 && !(port & 1)) { + bus_request_type = BUS_IO | BUS_WIDE; + biu_begin_eu(); + biu_wait_for_read_finish(); + } else { + bus_request_type = BUS_IO; + biu_begin_eu(); + biu_wait_for_read_finish(); + biu_state = BIU_STATE_EU; + biu_state_length = 0; + bus_request_type = BUS_IO | BUS_HIGH; + biu_wait_for_read_finish(); + } + } else { + bus_request_type = BUS_IO; + biu_begin_eu(); + biu_wait_for_read_finish(); + } + } + + bus_request_type = 0; +} + +void +biu_state_set_eu(void) +{ + biu_state = BIU_STATE_EU; + biu_state_length = 0; +} + +/* Reads a byte from the memory and advances the BIU. */ +uint8_t +readmemb_vx0(uint32_t s, uint16_t a) +{ + uint8_t ret; + + mem_seg = s; + mem_addr = a; + /* Do this, otherwise, the first half of the operation never happens. */ + if ((BUS_CYCLE == BUS_T4) && (biu_state == BIU_STATE_EU)) + BUS_CYCLE_T1; + bus_request_type = BUS_MEM; + biu_begin_eu(); + biu_wait_for_read_finish(); + ret = mem_data & 0xff; + bus_request_type = 0; + + return ret; +} + +/* Reads a word from the memory and advances the BIU. */ +uint16_t +readmemw_vx0(uint32_t s, uint16_t a) +{ + uint16_t ret; + + mem_seg = s; + mem_addr = a; + /* Do this, otherwise, the first half of the operation never happens. */ + if ((BUS_CYCLE == BUS_T4) && (biu_state == BIU_STATE_EU)) + BUS_CYCLE_T1; + if (is8086 && !(a & 1)) { + bus_request_type = BUS_MEM | BUS_WIDE; + biu_begin_eu(); + biu_wait_for_read_finish(); + } else { + bus_request_type = BUS_MEM | BUS_HIGH; + biu_begin_eu(); + biu_wait_for_read_finish(); + biu_state = BIU_STATE_EU; + biu_state_length = 0; + bus_request_type = BUS_MEM; + biu_wait_for_read_finish(); + } + ret = mem_data; + bus_request_type = 0; + + return ret; +} + +uint16_t +readmem_vx0(uint32_t s) +{ + if (opcode & 1) + return readmemw_vx0(s, cpu_state.eaaddr); + else + return (uint16_t) readmemb_vx0(s, cpu_state.eaaddr); +} + +uint32_t +readmeml_vx0(uint32_t s, uint16_t a) +{ + uint32_t temp; + + temp = (uint32_t) (readmemw_vx0(s, a + 2)) << 16; + temp |= readmemw_vx0(s, a); + + return temp; +} + +uint64_t +readmemq_vx0(uint32_t s, uint16_t a) +{ + uint64_t temp; + + temp = (uint64_t) (readmeml_vx0(s, a + 4)) << 32; + temp |= readmeml_vx0(s, a); + + return temp; +} + +/* Writes a byte to the memory and advances the BIU. */ +void +writememb_vx0(uint32_t s, uint32_t a, uint8_t v) +{ + uint32_t addr = s + a; + + mem_seg = s; + mem_addr = a; + mem_data = v; + /* Do this, otherwise, the first half of the operation never happens. */ + if ((BUS_CYCLE == BUS_T4) && (biu_state == BIU_STATE_EU)) + BUS_CYCLE_T1; + bus_request_type = BUS_MEM | BUS_OUT; + biu_begin_eu(); + biu_wait_for_write_finish(); + bus_request_type = 0; + + if ((addr >= 0xf0000) && (addr <= 0xfffff)) + last_addr = addr & 0xffff; +} + +/* Writes a word to the memory and advances the BIU. */ +void +writememw_vx0(uint32_t s, uint32_t a, uint16_t v) +{ + uint32_t addr = s + a; + + mem_seg = s; + mem_addr = a; + mem_data = v; + /* Do this, otherwise, the first half of the operation never happens. */ + if ((BUS_CYCLE == BUS_T4) && (biu_state == BIU_STATE_EU)) + BUS_CYCLE_T1; + if (is8086 && !(a & 1)) { + bus_request_type = BUS_MEM | BUS_OUT | BUS_WIDE; + biu_begin_eu(); + biu_wait_for_write_finish(); + } else { + bus_request_type = BUS_MEM | BUS_OUT | BUS_HIGH; + biu_begin_eu(); + biu_wait_for_write_finish(); + biu_cycle(); + biu_state = BIU_STATE_EU; + biu_state_length = 0; + bus_request_type = BUS_MEM | BUS_OUT; + biu_wait_for_write_finish(); + } + bus_request_type = 0; + + if ((addr >= 0xf0000) && (addr <= 0xfffff)) + last_addr = addr & 0xffff; +} + +void +writemem_vx0(uint32_t s, uint16_t v) +{ + if (opcode & 1) + writememw_vx0(s, cpu_state.eaaddr, v); + else + writememb_vx0(s, cpu_state.eaaddr, (uint8_t) (v & 0xff)); +} + +void +writememl_vx0(uint32_t s, uint32_t a, uint32_t v) +{ + writememw_vx0(s, a, v & 0xffff); + writememw_vx0(s, a + 2, v >> 16); +} + +void +writememq_vx0(uint32_t s, uint32_t a, uint64_t v) +{ + writememl_vx0(s, a, v & 0xffffffff); + writememl_vx0(s, a + 4, v >> 32); +} + +static void +pfq_write(void) +{ + uint16_t tempw; + /* Byte fetch on odd addres on 8086 to simulate the HL toggle. */ + int fetch_word = is8086 && !(pfq_ip & 1); + + if (fetch_word && (pfq_pos < (pfq_size - 1))) { + /* The 8086 fetches 2 bytes at a time, and only if there's at least 2 bytes + free in the queue. */ + tempw = pfq_in; + *(uint16_t *) &(pfq[pfq_pos]) = tempw; + pfq_ip = (pfq_ip + 2) & 0xffff; + pfq_pos += 2; + } 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. */ + if (pfq_pos >= 0) + pfq[pfq_pos] = pfq_in & 0xff; + pfq_ip = (pfq_ip + 1) & 0xffff; + pfq_pos++; + } + + if (pfq_pos >= pfq_size) + pfq_pos = pfq_size; +} + +uint8_t +biu_pfq_read(void) +{ + uint8_t temp; + + temp = pfq[0]; + for (int i = 0; i < (pfq_size - 1); i++) + pfq[i] = pfq[i + 1]; + pfq_pos--; + if (pfq_pos < 0) + pfq_pos = 0; + cpu_state.pc = (cpu_state.pc + 1) & 0xffff; + return temp; +} + +void +biu_resume_on_queue_read(void) +{ + if ((biu_next_state == BIU_STATE_IDLE) && (pfq_pos == 3)) + // pfq_switch_to_pf(is_nec ? 0 : ((biu_state == BIU_STATE_IDLE) ? 3 : 0)); + pfq_switch_to_pf(is_nec ? 0 : 3); +} + +/* Fetches a byte from the prefetch queue, or from memory if the queue has + been drained. + + Cycles: 1 If fetching from the queue; + (4 - (biu_cycles & 3)) If fetching from the bus - fetch into the queue; + 1 If fetching from the bus - delay. */ +uint8_t +biu_pfq_fetchb_common(void) +{ + uint8_t temp; + + if (biu_queue_preload) { + if (nx) + nx = 0; + + biu_queue_preload = 0; + return biu_preload_byte; + } + + if (pfq_pos > 0) { + if (biu_state == BIU_STATE_DELAY) { + while (biu_state == BIU_STATE_DELAY) + biu_cycle(); + } + + temp = biu_pfq_read(); + biu_resume_on_queue_read(); + } else { + /* Fill the queue. */ + while (pfq_pos == 0) + biu_cycle(); + + /* Fetch. */ + temp = biu_pfq_read(); + } + + do_cycle(); + return temp; +} + +/* The timings are above. */ +uint8_t +biu_pfq_fetchb(void) +{ + uint8_t ret; + + ret = biu_pfq_fetchb_common(); + return ret; +} + +/* Fetches a word from the prefetch queue, or from memory if the queue has + been drained. */ +uint16_t +biu_pfq_fetchw(void) +{ + uint16_t temp; + + temp = biu_pfq_fetchb_common(); + temp |= (biu_pfq_fetchb_common() << 8); + + return temp; +} + +uint16_t +biu_pfq_fetch(void) +{ + if (opcode & 1) + return biu_pfq_fetchw(); + else + return (uint16_t) biu_pfq_fetchb(); +} + +/* Adds bytes to the prefetch queue based on the instruction's cycle count. */ +static void +pfq_add(void) +{ + if ((biu_state == BIU_STATE_PF) && (pfq_pos < pfq_size)) + pfq_write(); +} + +void +biu_update_pc(void) +{ + pfq_ip = cpu_state.pc; + biu_queue_preload = 0; +} + +/* Clear the prefetch queue - called on reset and on anything that affects either CS or IP. */ +void +biu_queue_flush(void) +{ + pfq_pos = 0; + biu_update_pc(); + + fetch_suspended = 0; + + /* FLUSH command. */ + if ((biu_state == BIU_STATE_SUSP) || (biu_state == BIU_STATE_IDLE)) + pfq_resume(3); +} + +static void +biu_bus_wait_finish(void) +{ + while (BUS_CYCLE != BUS_T4) + biu_cycle(); +} + +void +biu_suspend_fetch(void) +{ + biu_state_length = 0; + fetch_suspended = 1; + + if (biu_state == BIU_STATE_PF) { + if (is_nec) + BUS_CYCLE_T1; + else { + biu_bus_wait_finish(); + biu_cycle(); + } + biu_state = BIU_STATE_IDLE; + biu_next_state = BIU_STATE_IDLE; + } else { + if (biu_state == BIU_STATE_EU) + BUS_CYCLE_T1; + biu_state = BIU_STATE_IDLE; + biu_next_state = BIU_STATE_IDLE; + } +} + +/* Memory refresh read - called by reads and writes on DMA channel 0. */ +void +refreshread_vx0(void) +{ + if (dma_state == DMA_STATE_IDLE) { + dma_state = DMA_STATE_TIMER; + dma_state_length = 1; + } +} diff --git a/src/cpu/vx0_biu.h b/src/cpu/vx0_biu.h new file mode 100644 index 000000000..173a6947b --- /dev/null +++ b/src/cpu/vx0_biu.h @@ -0,0 +1,138 @@ +/* + * 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 BIU emulation header. + * + * Authors: Andrew Jenner, + * Miran Grca, + * + * Copyright 2015-2020 Andrew Jenner. + * Copyright 2016-2020 Miran Grca. + */ +#ifndef EMU_808X_BIU_H +#define EMU_808X_BIU_H + +#define DEBUG_SEG 0xf000 +// #define DEBUG_SEG 0x0f3c +// #define DEBUG_SEG 0x1e1f +// #define DEBUG_SEG 0xf000 +// #define DEBUG_SEG 0xc800 +// #define DEBUG_SEG 0x0070 +// #define DEBUG_SEG 0x0291 +// #define DEBUG_SEG 0xefff +// #define DEBUG_SEG 0x15a2 + +// #define DEBUG_OFF_L 0x2c3b +// #define DEBUG_OFF_L 0xe182 +// #define DEBUG_OFF_L 0xf000 +// #define DEBUG_OFF_H 0xefff +// #define DEBUG_OFF_L 0x0000 +// #define DEBUG_OFF_H 0xffff +#define DEBUG_OFF_L 0xf300 +#define DEBUG_OFF_H 0xf3ff + +#define BUS_OUT 1 +#define BUS_HIGH 2 +#define BUS_WIDE 4 +#define BUS_CODE 8 +#define BUS_IO 16 +#define BUS_MEM 32 +#define BUS_PIC 64 +#define BUS_ACCESS_TYPE (BUS_CODE | BUS_IO | BUS_MEM | BUS_PIC) + +#undef readmemb +#undef readmemw +#undef readmeml +#undef readmemq + +enum { + BUS_T1 = 0, + BUS_T2, + BUS_T3, + BUS_T4 +}; + +enum { + BIU_STATE_IDLE, + BIU_STATE_SUSP, + BIU_STATE_DELAY, + BIU_STATE_RESUME, + BIU_STATE_WAIT, + BIU_STATE_PF, + BIU_STATE_EU +}; + +enum { + DMA_STATE_IDLE, + DMA_STATE_TIMER, + DMA_STATE_DREQ, + DMA_STATE_HRQ, + DMA_STATE_HLDA, + DMA_STATE_OPERATING +}; + +extern void execx86_instruction(void); + +extern void biu_resume_on_queue_read(void); +extern void wait_vx0(int c); +extern void biu_reset(void); +extern void cpu_io_vx0(int bits, int out, uint16_t port); +extern void biu_state_set_eu(void); +extern uint8_t readmemb_vx0(uint32_t s, uint16_t a); +extern uint16_t readmemw_vx0(uint32_t s, uint16_t a); +extern uint16_t readmem_vx0(uint32_t s); +extern uint32_t readmeml_vx0(uint32_t s, uint16_t a); +extern uint64_t readmemq_vx0(uint32_t s, uint16_t a); +extern void writememb_vx0(uint32_t s, uint32_t a, uint8_t v); +extern void writememw_vx0(uint32_t s, uint32_t a, uint16_t v); +extern void writemem_vx0(uint32_t s, uint16_t v); +extern void writememl_vx0(uint32_t s, uint32_t a, uint32_t v); +extern void writememq_vx0(uint32_t s, uint32_t a, uint64_t v); +extern uint8_t biu_pfq_read(void); +extern uint8_t biu_pfq_fetchb_common(void); +extern uint8_t biu_pfq_fetchb(void); +extern uint16_t biu_pfq_fetchw(void); +extern uint16_t biu_pfq_fetch(void); +extern void biu_update_pc(void); +extern void biu_queue_flush(void); +extern void biu_suspend_fetch(void); +extern void biu_begin_eu(void); +extern void biu_wait_for_read_finish(void); + +extern uint8_t biu_preload_byte; + +extern int nx; +extern int oldc; +extern int cpu_alu_op; +extern int completed; +extern int in_rep; +extern int repeating; +extern int rep_c_flag; +extern int noint; +extern int tempc_fpu; +extern int clear_lock; +extern int is_new_biu; + +extern int schedule_fetch; +extern int in_lock; +extern int bus_request_type; +extern int pic_data; +extern int biu_queue_preload; + +extern uint32_t cpu_src; +extern uint32_t cpu_dest; + +extern uint32_t cpu_data; + +extern uint32_t *ovr_seg; + +/* Pointer tables needed for segment overrides. */ +extern uint32_t * opseg[4]; +extern x86seg * _opseg[4]; + +#endif /*EMU_808X_BIU_H*/ diff --git a/src/cpu/x86.c b/src/cpu/x86.c index 38e50a488..a19ac440a 100644 --- a/src/cpu/x86.c +++ b/src/cpu/x86.c @@ -367,8 +367,12 @@ reset_common(int hard) } else device_reset_all(DEVICE_SOFTRESET); - if (!is286) - reset_808x(hard); + if (!is286) { + if (is_nec) + reset_vx0(hard); + else + reset_808x(hard); + } in_lock = 0; diff --git a/src/cpu/x86.h b/src/cpu/x86.h index ccfeadea0..c0140520f 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -37,6 +37,7 @@ extern uint8_t opcode; extern uint8_t flags_p; extern uint8_t znptable8[256]; +extern uint16_t last_addr; extern uint16_t zero; extern uint16_t oldcs; extern uint16_t lastcs; @@ -44,6 +45,7 @@ extern uint16_t lastpc; extern uint16_t *mod1add[2][8]; extern uint16_t znptable16[65536]; +extern int pfq_pos; extern int x86_was_reset; extern int trap; extern int codegen_flat_ss; diff --git a/src/cpu/x87_ops.h b/src/cpu/x87_ops.h index 4d099885a..49b5c2378 100644 --- a/src/cpu/x87_ops.h +++ b/src/cpu/x87_ops.h @@ -551,7 +551,11 @@ static int FPU_ILLEGAL_a16(UNUSED(uint32_t fetchdat)) { geteaw(); +#ifdef FPU_NEC + do_cycles(timing_rr); +#else wait_cycs(timing_rr, 0); +#endif return 0; } #else @@ -577,7 +581,7 @@ FPU_ILLEGAL_a32(uint32_t fetchdat) #define ILLEGAL_a16 FPU_ILLEGAL_a16 #ifdef FPU_8087 -const OpFn OP_TABLE(sf_fpu_8087_d8)[32] = { +static const OpFn OP_TABLE(sf_fpu_8087_d8)[32] = { // clang-format off sf_FADDs_a16, sf_FMULs_a16, sf_FCOMs_a16, sf_FCOMPs_a16, sf_FSUBs_a16, sf_FSUBRs_a16, sf_FDIVs_a16, sf_FDIVRs_a16, sf_FADDs_a16, sf_FMULs_a16, sf_FCOMs_a16, sf_FCOMPs_a16, sf_FSUBs_a16, sf_FSUBRs_a16, sf_FDIVs_a16, sf_FDIVRs_a16, @@ -586,7 +590,7 @@ const OpFn OP_TABLE(sf_fpu_8087_d8)[32] = { // clang-format on }; -const OpFn OP_TABLE(sf_fpu_8087_d9)[256] = { +static const OpFn OP_TABLE(sf_fpu_8087_d9)[256] = { // clang-format off sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, sf_FLDs_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, @@ -626,7 +630,7 @@ const OpFn OP_TABLE(sf_fpu_8087_d9)[256] = { // clang-format on }; -const OpFn OP_TABLE(sf_fpu_8087_da)[256] = { +static const OpFn OP_TABLE(sf_fpu_8087_da)[256] = { // clang-format off sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FADDil_a16, sf_FMULil_a16, sf_FMULil_a16, sf_FMULil_a16, sf_FMULil_a16, sf_FMULil_a16, sf_FMULil_a16, sf_FMULil_a16, sf_FMULil_a16, @@ -666,7 +670,7 @@ const OpFn OP_TABLE(sf_fpu_8087_da)[256] = { // clang-format on }; -const OpFn OP_TABLE(sf_fpu_8087_db)[256] = { +static const OpFn OP_TABLE(sf_fpu_8087_db)[256] = { // clang-format off sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, sf_FILDil_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, @@ -706,7 +710,7 @@ const OpFn OP_TABLE(sf_fpu_8087_db)[256] = { // clang-format on }; -const OpFn OP_TABLE(sf_fpu_8087_dc)[32] = { +static const OpFn OP_TABLE(sf_fpu_8087_dc)[32] = { // clang-format off sf_FADDd_a16, sf_FMULd_a16, sf_FCOMd_a16, sf_FCOMPd_a16, sf_FSUBd_a16, sf_FSUBRd_a16, sf_FDIVd_a16, sf_FDIVRd_a16, sf_FADDd_a16, sf_FMULd_a16, sf_FCOMd_a16, sf_FCOMPd_a16, sf_FSUBd_a16, sf_FSUBRd_a16, sf_FDIVd_a16, sf_FDIVRd_a16, @@ -715,7 +719,7 @@ const OpFn OP_TABLE(sf_fpu_8087_dc)[32] = { // clang-format on }; -const OpFn OP_TABLE(sf_fpu_8087_dd)[256] = { +static const OpFn OP_TABLE(sf_fpu_8087_dd)[256] = { // clang-format off sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, sf_FLDd_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, @@ -755,7 +759,7 @@ const OpFn OP_TABLE(sf_fpu_8087_dd)[256] = { // clang-format on }; -const OpFn OP_TABLE(sf_fpu_8087_de)[256] = { +static const OpFn OP_TABLE(sf_fpu_8087_de)[256] = { // clang-format off sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FADDiw_a16, sf_FMULiw_a16, sf_FMULiw_a16, sf_FMULiw_a16, sf_FMULiw_a16, sf_FMULiw_a16, sf_FMULiw_a16, sf_FMULiw_a16, sf_FMULiw_a16, @@ -795,7 +799,7 @@ const OpFn OP_TABLE(sf_fpu_8087_de)[256] = { // clang-format on }; -const OpFn OP_TABLE(sf_fpu_8087_df)[256] = { +static const OpFn OP_TABLE(sf_fpu_8087_df)[256] = { // clang-format off sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, sf_FILDiw_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, @@ -835,7 +839,7 @@ const OpFn OP_TABLE(sf_fpu_8087_df)[256] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_d8)[32] = { +static const OpFn OP_TABLE(fpu_8087_d8)[32] = { // clang-format off opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, @@ -844,7 +848,7 @@ const OpFn OP_TABLE(fpu_8087_d8)[32] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_d9)[256] = { +static const OpFn OP_TABLE(fpu_8087_d9)[256] = { // clang-format off opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, @@ -884,7 +888,7 @@ const OpFn OP_TABLE(fpu_8087_d9)[256] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_da)[256] = { +static const OpFn OP_TABLE(fpu_8087_da)[256] = { // clang-format off opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, @@ -924,7 +928,7 @@ const OpFn OP_TABLE(fpu_8087_da)[256] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_db)[256] = { +static const OpFn OP_TABLE(fpu_8087_db)[256] = { // clang-format off opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, @@ -964,7 +968,7 @@ const OpFn OP_TABLE(fpu_8087_db)[256] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_dc)[32] = { +static const OpFn OP_TABLE(fpu_8087_dc)[32] = { // clang-format off opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, @@ -973,7 +977,7 @@ const OpFn OP_TABLE(fpu_8087_dc)[32] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_dd)[256] = { +static const OpFn OP_TABLE(fpu_8087_dd)[256] = { // clang-format off opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, @@ -1013,7 +1017,7 @@ const OpFn OP_TABLE(fpu_8087_dd)[256] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_de)[256] = { +static const OpFn OP_TABLE(fpu_8087_de)[256] = { // clang-format off opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, @@ -1053,7 +1057,7 @@ const OpFn OP_TABLE(fpu_8087_de)[256] = { // clang-format on }; -const OpFn OP_TABLE(fpu_8087_df)[256] = { +static const OpFn OP_TABLE(fpu_8087_df)[256] = { // clang-format off opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, ILLEGAL_a16, diff --git a/src/cpu/x87_ops_misc.h b/src/cpu/x87_ops_misc.h index 417beea62..68955e07d 100644 --- a/src/cpu/x87_ops_misc.h +++ b/src/cpu/x87_ops_misc.h @@ -7,7 +7,11 @@ opFI(uint32_t fetchdat) cpu_state.npxc &= ~0x80; if (rmdat == 0xe1) cpu_state.npxc |= 0x80; +#ifdef FPU_NEC + do_cycles(3); +#else wait_cycs(3, 0); +#endif return 0; } #else diff --git a/src/cpu/x87_ops_sf.h b/src/cpu/x87_ops_sf.h index adbaa2003..722d86435 100644 --- a/src/cpu/x87_ops_sf.h +++ b/src/cpu/x87_ops_sf.h @@ -354,7 +354,11 @@ sf_FI(uint32_t fetchdat) fpu_state.cwd &= ~FPU_SW_Summary; if (rmdat == 0xe1) fpu_state.cwd |= FPU_SW_Summary; +#ifdef FPU_NEC + do_cycles(3); +#else wait_cycs(3, 0); +#endif return 0; } #else diff --git a/src/device/hasp.c b/src/device/hasp.c index ea8b9b413..f4b6bc0ad 100644 --- a/src/device/hasp.c +++ b/src/device/hasp.c @@ -302,13 +302,13 @@ hasp_read_status(void *priv) } static void * -hasp_init(void *lpt, int type) +hasp_init(const device_t *info, int type) { hasp_t *dev = calloc(1, sizeof(hasp_t)); hasp_log("HASP: init(%d)\n", type); - dev->lpt = lpt; + dev->lpt = lpt_attach(hasp_write_data, NULL, NULL, hasp_read_status, NULL, NULL, NULL, dev); dev->type = &hasp_types[type]; dev->status = 0x80; @@ -317,9 +317,9 @@ hasp_init(void *lpt, int type) } static void * -hasp_init_savquest(void *lpt) +hasp_init_savquest(const device_t *info) { - return hasp_init(lpt, HASP_TYPE_SAVQUEST); + return hasp_init(info, HASP_TYPE_SAVQUEST); } static void @@ -332,16 +332,16 @@ hasp_close(void *priv) free(dev); } -const lpt_device_t lpt_hasp_savquest_device = { - .name = "Protection Dongle for Savage Quest", - .internal_name = "dongle_savquest", - .init = hasp_init_savquest, - .close = hasp_close, - .write_data = hasp_write_data, - .write_ctrl = NULL, - .strobe = NULL, - .read_status = hasp_read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL +const device_t lpt_hasp_savquest_device = { + .name = "Protection Dongle for Savage Quest", + .internal_name = "dongle_savquest", + .flags = DEVICE_LPT, + .local = 0, + .init = hasp_init_savquest, + .close = hasp_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/device/lpt.c b/src/device/lpt.c index f7cc6eda0..a7fb5ac2d 100644 --- a/src/device/lpt.c +++ b/src/device/lpt.c @@ -34,19 +34,22 @@ lpt_port_t lpt_ports[PARALLEL_MAX]; lpt_device_t lpt_devs[PARALLEL_MAX]; -const lpt_device_t lpt_none_device = { +const device_t lpt_none_device = { .name = "None", .internal_name = "none", + .flags = DEVICE_LPT, + .local = 0, .init = NULL, .close = NULL, - .write_data = NULL, - .write_ctrl = NULL, - .read_status = NULL, - .read_ctrl = NULL + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; static const struct { - const lpt_device_t *device; + const device_t *device; } lpt_devices[] = { // clang-format off { &lpt_none_device }, @@ -56,9 +59,7 @@ static const struct { { &lpt_prt_text_device }, { &lpt_prt_escp_device }, { &lpt_prt_ps_device }, -#ifdef USE_PCL { &lpt_prt_pcl_device }, -#endif { &lpt_plip_device }, { &lpt_hasp_savquest_device }, { NULL } @@ -83,50 +84,41 @@ lpt_log(const char *fmt, ...) # define lpt_log(fmt, ...) #endif +int +lpt_device_available(int id) +{ + if (lpt_devices[id].device) + return device_available(lpt_devices[id].device); + + return 1; +} + const device_t * lpt_device_getdevice(const int id) { - return (device_t *) lpt_devices[id].device->cfgdevice; + return lpt_devices[id].device; } int lpt_device_has_config(const int id) { - int c = 0; - const device_t *dev = (device_t *) lpt_devices[id].device->cfgdevice; - const device_config_t *config; - if (dev == NULL) + if (lpt_devices[id].device == NULL) return 0; - - if (dev->config == NULL) - return 0; - - config = dev->config; - - while (config->type != CONFIG_END) { - c++; - config++; - } - - return (c > 0) ? 1 : 0; + return device_has_config(lpt_devices[id].device); } const char * lpt_device_get_name(const int id) { if (lpt_devices[id].device == NULL) - return NULL; - + return 0; return lpt_devices[id].device->name; } const char * lpt_device_get_internal_name(const int id) { - if (lpt_devices[id].device == NULL) - return NULL; - - return lpt_devices[id].device->internal_name; + return device_get_internal_name(lpt_devices[id].device); } int @@ -147,29 +139,43 @@ void lpt_devices_init(void) { for (uint8_t i = 0; i < PARALLEL_MAX; i++) { - lpt_t *dev = lpt_devs[i].lpt; + memset(&(lpt_devs[i]), 0x00, sizeof(lpt_device_t)); - if (lpt_devices[lpt_ports[i].device].device != NULL) { - memcpy(&(lpt_devs[i]), (lpt_device_t *) lpt_devices[lpt_ports[i].device].device, sizeof(lpt_device_t)); - - if (lpt_devs[i].init) - lpt_devs[i].priv = lpt_devs[i].init(dev); - } else - memset(&(lpt_devs[i]), 0x00, sizeof(lpt_device_t)); - - lpt_devs[i].lpt = dev; + if ((lpt_devices[lpt_ports[i].device].device != NULL) && + (lpt_devices[lpt_ports[i].device].device != &lpt_none_device)) + device_add_inst((device_t *) lpt_devices[lpt_ports[i].device].device, i + 1); } } +void * +lpt_attach(void (*write_data)(uint8_t val, void *priv), + void (*write_ctrl)(uint8_t val, void *priv), + void (*strobe)(uint8_t old, uint8_t val,void *priv), + uint8_t (*read_status)(void *priv), + uint8_t (*read_ctrl)(void *priv), + void (*epp_write_data)(uint8_t is_addr, uint8_t val, void *priv), + void (*epp_request_read)(uint8_t is_addr, void *priv), + void *priv) +{ + int port = device_get_instance() - 1; + + lpt_devs[port].write_data = write_data; + lpt_devs[port].write_ctrl = write_ctrl; + lpt_devs[port].strobe = strobe; + lpt_devs[port].read_status = read_status; + lpt_devs[port].read_ctrl = read_ctrl; + lpt_devs[port].epp_write_data = epp_write_data; + lpt_devs[port].epp_request_read = epp_request_read; + lpt_devs[port].priv = priv; + + return lpt_ports[port].lpt; +} + void lpt_devices_close(void) { - for (uint8_t i = 0; i < PARALLEL_MAX; i++) { - if (lpt_devs[i].close) - lpt_devs[i].close(lpt_devs[i].priv); - + for (uint8_t i = 0; i < PARALLEL_MAX; i++) memset(&(lpt_devs[i]), 0x00, sizeof(lpt_device_t)); - } } static uint8_t @@ -954,10 +960,10 @@ lpt_init(const device_t *info) if (lpt_ports[next_inst].enabled || (info->local & 0xFFF00000)) { lpt_log("Adding parallel port %i...\n", next_inst); - dev->dt = &(lpt_devs[next_inst]); - dev->dt->lpt = dev; + dev->dt = &(lpt_devs[next_inst]); + lpt_ports[next_inst].lpt = dev; - dev->fifo = NULL; + dev->fifo = NULL; memset(&dev->fifo_out_timer, 0x00, sizeof(pc_timer_t)); lpt_port_zero(dev); @@ -1033,7 +1039,14 @@ lpt_standalone_init(void) { while (next_inst < (PARALLEL_MAX - 1)) device_add_inst(&lpt_port_device, next_inst + 1); -}; +} + +void +lpt_ports_reset(void) +{ + for (int i = 0; i < PARALLEL_MAX; i++) + lpt_ports[i].lpt = NULL; +} const device_t lpt_port_device = { .name = "Parallel Port", diff --git a/src/dma.c b/src/dma.c index bfc294f2a..5dfd70ae8 100644 --- a/src/dma.c +++ b/src/dma.c @@ -1503,7 +1503,7 @@ dma_channel_read_only(int channel) dma_channel_advance(channel); if (!dma_at && !channel) - refreshread(); + is_nec ? refreshread_vx0() : refreshread(); if (!dma_c->size) { temp = _dma_read(dma_c->ac, dma_c); @@ -1611,7 +1611,7 @@ dma_channel_read(int channel) dma_channel_advance(channel); if (!dma_at && !channel) - refreshread(); + is_nec ? refreshread_vx0() : refreshread(); if (!dma_c->size) { temp = _dma_read(dma_c->ac, dma_c); diff --git a/src/include/86box/86box.h b/src/include/86box/86box.h index d32e13895..9cb91e7c6 100644 --- a/src/include/86box/86box.h +++ b/src/include/86box/86box.h @@ -315,6 +315,9 @@ extern uint16_t get_last_addr(void); extern void sub_cycles(int c); extern void resub_cycles(int old_cycles); +extern void sub_cycles_vx0(int c); +extern void resub_cycles_vx0(int old_cycles); + extern void ack_pause(void); extern void do_pause(int p); diff --git a/src/include/86box/lpt.h b/src/include/86box/lpt.h index 61c95094f..fe5442379 100644 --- a/src/include/86box/lpt.h +++ b/src/include/86box/lpt.h @@ -18,11 +18,6 @@ #endif typedef struct lpt_device_s { - const char *name; - const char *internal_name; - - void *(*init)(void *lpt); - void (*close)(void *priv); void (*write_data)(uint8_t val, void *priv); void (*write_ctrl)(uint8_t val, void *priv); void (*strobe)(uint8_t old, uint8_t val,void *priv); @@ -31,13 +26,7 @@ typedef struct lpt_device_s { void (*epp_write_data)(uint8_t is_addr, uint8_t val, void *priv); void (*epp_request_read)(uint8_t is_addr, void *priv); - void *priv; - struct lpt_t *lpt; -//#ifdef EMU_DEVICE_H -// struct device_t *cfgdevice; -//#else - void *cfgdevice; -//#endif + void * priv; } lpt_device_t; #ifdef _TIMER_H_ @@ -86,6 +75,8 @@ typedef struct lpt_port_s { uint8_t enabled; int device; + + lpt_t *lpt; } lpt_port_t; extern lpt_port_t lpt_ports[PARALLEL_MAX]; @@ -96,6 +87,22 @@ typedef enum { LPT_STATE_WRITE_FIFO } lpt_state_t; +extern const device_t lpt_dac_device; +extern const device_t lpt_dac_stereo_device; + +extern const device_t dss_device; + +extern const device_t lpt_hasp_savquest_device; + +extern int lpt_device_available(int id); +#ifdef EMU_DEVICE_H +extern const device_t *lpt_device_getdevice(const int id); +#endif +extern int lpt_device_has_config(const int id); +extern const char *lpt_device_get_name(int id); +extern const char *lpt_device_get_internal_name(int id); +extern int lpt_device_get_from_internal_name(const char *str); + extern void lpt_write(uint16_t port, uint8_t val, void *priv); extern void lpt_write_to_fifo(void *priv, uint8_t val); @@ -109,24 +116,6 @@ extern uint8_t lpt_read_ecp_mode(lpt_t *dev); extern void lpt_irq(void *priv, int raise); -extern int lpt_device_get_from_internal_name(const char *str); - -extern const char *lpt_device_get_name(int id); -extern const char *lpt_device_get_internal_name(int id); - -#ifdef EMU_DEVICE_H -extern const device_t *lpt_device_getdevice(const int id); -#endif - -extern int lpt_device_has_config(const int id); - -extern const lpt_device_t lpt_dac_device; -extern const lpt_device_t lpt_dac_stereo_device; - -extern const lpt_device_t dss_device; - -extern const lpt_device_t lpt_hasp_savquest_device; - extern void lpt_set_ext(lpt_t *dev, uint8_t ext); extern void lpt_set_ecp(lpt_t *dev, uint8_t ecp); extern void lpt_set_epp(lpt_t *dev, uint8_t epp); @@ -143,12 +132,21 @@ extern void lpt_port_remove(lpt_t *dev); extern void lpt1_remove_ams(lpt_t *dev); extern void lpt_devices_init(void); +extern void * lpt_attach(void (*write_data)(uint8_t val, void *priv), + void (*write_ctrl)(uint8_t val, void *priv), + void (*strobe)(uint8_t old, uint8_t val,void *priv), + uint8_t (*read_status)(void *priv), + uint8_t (*read_ctrl)(void *priv), + void (*epp_write_data)(uint8_t is_addr, uint8_t val, void *priv), + void (*epp_request_read)(uint8_t is_addr, void *priv), + void *priv); extern void lpt_devices_close(void); extern void lpt_set_next_inst(int ni); extern void lpt_set_3bc_used(int is_3bc_used); extern void lpt_standalone_init(void); +extern void lpt_ports_reset(void); extern const device_t lpt_port_device; diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index 1786017ec..606b21b4b 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1409,6 +1409,9 @@ extern const device_t tandy_1000sl_video_device; extern int machine_tandy1000sl2_init(const machine_t *); /* m_v86p.c */ +#ifdef EMU_DEVICE_H +extern const device_t v86p_device; +#endif extern int machine_v86p_init(const machine_t *); /* m_xt.c */ @@ -1480,6 +1483,9 @@ extern int machine_xt_to16_init(const machine_t *); extern const device_t vendex_device; #endif extern int machine_xt_vendex_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t laserxt_device; +#endif extern int machine_xt_laserxt_init(const machine_t *); extern int machine_xt_znic_init(const machine_t *); extern int machine_xt_z151_init(const machine_t *); diff --git a/src/include/86box/network.h b/src/include/86box/network.h index 0642c3f53..2c91a6d9f 100644 --- a/src/include/86box/network.h +++ b/src/include/86box/network.h @@ -244,10 +244,8 @@ extern const device_t pcnet_am79c973_onboard_device; extern const device_t modem_device; /* PLIP */ -#ifdef EMU_LPT_H -extern const lpt_device_t lpt_plip_device; -#endif -extern const device_t plip_device; +extern const device_t lpt_plip_device; +extern const device_t plip_device; /* Realtek RTL8139C+ */ extern const device_t rtl8139c_plus_device; diff --git a/src/include/86box/prt_devs.h b/src/include/86box/prt_devs.h index d136d9d93..343182946 100644 --- a/src/include/86box/prt_devs.h +++ b/src/include/86box/prt_devs.h @@ -1,15 +1,9 @@ #ifndef EMU_PRT_DEVS_H #define EMU_PRT_DEVS_H -extern const lpt_device_t lpt_prt_text_device; -extern const device_t prt_text_device; -extern const lpt_device_t lpt_prt_escp_device; -extern const device_t prt_escp_device; -extern const lpt_device_t lpt_prt_ps_device; -extern const device_t prt_ps_device; -#ifdef USE_PCL -extern const lpt_device_t lpt_prt_pcl_device; -extern const device_t prt_pcl_device; -#endif +extern const device_t lpt_prt_text_device; +extern const device_t lpt_prt_escp_device; +extern const device_t lpt_prt_ps_device; +extern const device_t lpt_prt_pcl_device; #endif /*EMU_PRT_DEVS_H*/ diff --git a/src/machine/m_v86p.c b/src/machine/m_v86p.c index 126517345..d30d9c8a6 100644 --- a/src/machine/m_v86p.c +++ b/src/machine/m_v86p.c @@ -48,35 +48,101 @@ #include <86box/sio.h> #include <86box/video.h> +static const device_config_t v86p_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "v86p_122089", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "12/20/89", + .internal_name = "v86p_122089", + .bios_type = BIOS_NORMAL, + .files_no = 2, + .local = 0, + .size = 65536, + .files = { "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_122089_Even.rom", + "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_122089_Odd.rom", + "" } + }, + { + .name = "09/04/89", + .internal_name = "v86p_090489", + .bios_type = BIOS_NORMAL, + .files_no = 2, + .local = 0, + .size = 65536, + .files = { "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_090489_Even.rom", + "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_090489_Odd.rom", + "" } + }, + { + .name = "09/04/89 (Alt)", + .internal_name = "v86p_jvernet", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 1, + .size = 65536, + .files = { "roms/machines/v86p/V86P.ROM", + "" } + }, + { .files_no = 0 } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t v86p_device = { + .name = "Victor V86P", + .internal_name = "v86p_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = v86p_config +}; + int machine_v86p_init(const machine_t *model) { - int ret; - int rom_id = 0; + int ret = 0; + int files_no = 0; + int local = 0; + const char *fn1, *fn2; - ret = bios_load_interleavedr("roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_122089_Even.rom", - "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_122089_Odd.rom", - 0x000f8000, 65536, 0); + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; - if (!ret) { - /* Try an older version of the BIOS. */ - rom_id = 1; - ret = bios_load_interleavedr("roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_090489_Even.rom", - "roms/machines/v86p/INTEL8086AWD_BIOS_S3.1_V86P_090489_Odd.rom", - 0x000f8000, 65536, 0); - } - - if (!ret) { - /* Try JVERNET's BIOS. */ - rom_id = 2; - ret = bios_load_linear("roms/machines/v86p/V86P.ROM", - 0x000f0000, 65536, 0); + device_context(model->device); + files_no = device_get_bios_num_files(model->device, device_get_config_bios("bios")); + local = device_get_bios_local(model->device, device_get_config_bios("bios")); + fn1 = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + + if (files_no > 1) + { + fn2 = device_get_bios_file(model->device, device_get_config_bios("bios"), 1); + ret = bios_load_interleavedr(fn1, fn2, 0x000f8000, 65536, 0); } + else + ret = bios_load_linear(fn1, 0x000f0000, 65536, 0); + device_context_restore(); if (bios_only || !ret) return ret; - if (rom_id == 2) + if (local > 0) video_load_font("roms/machines/v86p/V86P.FON", FONT_FORMAT_PC1512_T1000, LOAD_FONT_NO_OFFSET); else video_load_font("roms/machines/v86p/v86pfont.rom", FONT_FORMAT_PC1512_T1000, LOAD_FONT_NO_OFFSET); diff --git a/src/machine/m_xt.c b/src/machine/m_xt.c index 81c9eba72..6da39d997 100644 --- a/src/machine/m_xt.c +++ b/src/machine/m_xt.c @@ -1884,10 +1884,17 @@ machine_xt_laserxt_common_init(const machine_t *model, int is_lxt3) int machine_xt_laserxt_init(const machine_t *model) { - int ret; + int ret = 0; + const char *fn; - ret = bios_load_linear("roms/machines/ltxt/27c64.bin", - 0x000fe000, 8192, 0); + /* No ROMs available. */ + if (!device_available(model->device)) + return ret; + + device_context(model->device); + fn = device_get_bios_file(model->device, device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000fe000, 8192, 0); + device_context_restore(); if (bios_only || !ret) return ret; diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index 8e1bd30de..7258a8296 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -2982,7 +2982,7 @@ const machine_t machines[] = { .kbc_p1 = 0xff, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &v86p_device, .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, @@ -18561,7 +18561,7 @@ const machine_t machines[] = { .max_multi = 5.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, - .flags = MACHINE_IDE_DUAL | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, + .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, .ram = { .min = 8192, .max = 262144, diff --git a/src/network/net_plip.c b/src/network/net_plip.c index 36df49153..f61c04646 100644 --- a/src/network/net_plip.c +++ b/src/network/net_plip.c @@ -441,13 +441,14 @@ plip_rx(void *priv, uint8_t *buf, int io_len) } static void * -plip_lpt_init(void *lpt) +plip_lpt_init(const device_t *info) { plip_t *dev = (plip_t *) calloc(1, sizeof(plip_t)); plip_log(1, "PLIP: lpt_init()\n"); - dev->lpt = lpt; + dev->lpt = lpt_attach(plip_write_data, plip_write_ctrl, NULL, plip_read_status, NULL, NULL, NULL, dev); + memset(dev->mac, 0xfc, 6); /* static MAC used by Linux; just a placeholder */ dev->status = 0x80; @@ -485,24 +486,22 @@ plip_close(void *priv) free(priv); } -const lpt_device_t lpt_plip_device = { - .name = "Parallel Line Internet Protocol", - .internal_name = "plip", - .init = plip_lpt_init, - .close = plip_close, - .write_data = plip_write_data, - .write_ctrl = plip_write_ctrl, - .strobe = NULL, - .read_status = plip_read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL +const device_t lpt_plip_device = { + .name = "Parallel Line Internet Protocol (LPT)", + .internal_name = "plip", + .flags = DEVICE_LPT, + .local = 0, + .init = plip_lpt_init, + .close = plip_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; const device_t plip_device = { - .name = "Parallel Line Internet Protocol", + .name = "Parallel Line Internet Protocol (Network)", .internal_name = "plip", .flags = DEVICE_LPT, .local = 0, diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index b5219cf23..2b2503904 100644 --- a/src/network/net_tulip.c +++ b/src/network/net_tulip.c @@ -886,7 +886,6 @@ static void tulip_reset(void *priv) { TULIPState *s = (TULIPState *) priv; - const uint16_t *eeprom_data = nmc93cxx_eeprom_data(s->eeprom); s->csr[0] = 0xfe000000; s->csr[1] = 0xffffffff; s->csr[2] = 0xffffffff; @@ -901,6 +900,8 @@ tulip_reset(void *priv) s->csr[14] = 0xffffffff; s->csr[15] = 0x8ff00000; if (s->device_info->local != 3) { + const uint16_t *eeprom_data = nmc93cxx_eeprom_data(s->eeprom); + s->subsys_id = eeprom_data[1]; s->subsys_ven_id = eeprom_data[0]; } diff --git a/src/printer/CMakeLists.txt b/src/printer/CMakeLists.txt index 0efb2aec2..1b4d9c0c5 100644 --- a/src/printer/CMakeLists.txt +++ b/src/printer/CMakeLists.txt @@ -23,10 +23,6 @@ add_library(print OBJECT prt_ps.c ) -if(PCL) - target_compile_definitions(print PRIVATE USE_PCL) -endif() - if(APPLE) find_library(GHOSTSCRIPT_LIB gs) if (NOT GHOSTSCRIPT_LIB) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index a24072971..2a50ae54f 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -1979,7 +1979,7 @@ read_status(void *priv) } static void * -escp_init(void *lpt) +escp_init(const device_t *info) { escp_t *dev = NULL; @@ -1995,7 +1995,8 @@ escp_init(void *lpt) /* Initialize a device instance. */ dev = (escp_t *) calloc(1, sizeof(escp_t)); dev->ctrl = 0x04; - dev->lpt = lpt; + + dev->lpt = lpt_attach(write_data, write_ctrl, strobe, read_status, read_ctrl, NULL, NULL, dev); rom_get_full_path(dev->fontpath, "roms/printer/fonts/"); @@ -2109,13 +2110,13 @@ static const device_config_t lpt_prt_escp_config[] = { #endif // clang-format on -const device_t prt_escp_device = { +const device_t lpt_prt_escp_device = { .name = "Generic ESC/P 2 Dot-Matrix Printer", .internal_name = "dot_matrix", .flags = DEVICE_LPT, .local = 0, - .init = NULL, - .close = NULL, + .init = escp_init, + .close = escp_close, .reset = NULL, .available = NULL, .speed_changed = NULL, @@ -2126,20 +2127,3 @@ const device_t prt_escp_device = { .config = NULL #endif }; - -const lpt_device_t lpt_prt_escp_device = { - .name = "Generic ESC/P 2 Dot-Matrix Printer", - .internal_name = "dot_matrix", - .init = escp_init, - .close = escp_close, - .write_data = write_data, - .write_ctrl = write_ctrl, - .strobe = strobe, - .read_status = read_status, - .read_ctrl = read_ctrl, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL, - .cfgdevice = (device_t *) &prt_escp_device -}; diff --git a/src/printer/prt_ps.c b/src/printer/prt_ps.c index adf57a523..29ae78feb 100644 --- a/src/printer/prt_ps.c +++ b/src/printer/prt_ps.c @@ -61,40 +61,55 @@ #define POSTSCRIPT_BUFFER_LENGTH 65536 +enum { + LANG_RAW = 0, + LANG_PS, + LANG_PCL_5E, + LANG_PCL_5C, + LANG_HP_RTL, + LANG_PCL_6 +}; + typedef struct ps_t { const char *name; - void *lpt; + void * lpt; - pc_timer_t pulse_timer; - pc_timer_t timeout_timer; + pc_timer_t pulse_timer; + pc_timer_t timeout_timer; - char data; - bool ack; - bool select; - bool busy; - bool int_pending; - bool error; - bool autofeed; - bool pcl; - bool pending; - bool pjl; - bool pjl_command; - uint8_t ctrl; - uint8_t pcl_escape; - uint16_t pjl_command_start; + bool ack; + bool select; + bool busy; + bool int_pending; + bool error; + bool autofeed; + bool pcl; + bool pending; + bool pjl; + bool pjl_command; - char printer_path[260]; + char data; - char filename[260]; + char printer_path[260]; + char filename[260]; - char buffer[POSTSCRIPT_BUFFER_LENGTH]; - size_t buffer_pos; + char buffer[POSTSCRIPT_BUFFER_LENGTH]; + + uint8_t ctrl; + uint8_t pcl_escape; + + uint16_t pjl_command_start; + + int lang; + + size_t buffer_pos; } ps_t; typedef struct gsapi_revision_s { const char *product; const char *copyright; + long revision; long revisiondate; } gsapi_revision_t; @@ -155,8 +170,23 @@ convert_to_pdf(ps_t *dev) gsargv[arg++] = "-dSAFER"; gsargv[arg++] = "-sDEVICE=pdfwrite"; if (dev->pcl) { - gsargv[arg++] = "-LPCL"; - gsargv[arg++] = "-lPCL5E"; + if (dev->lang == LANG_PCL_6) + gsargv[arg++] = "-LPCLXL"; + else { + gsargv[arg++] = "-LPCL"; + switch (dev->lang) { + default: + case LANG_PCL_5E: + gsargv[arg++] = "-lPCL5E"; + break; + case LANG_PCL_5C: + gsargv[arg++] = "-lPCL5C"; + break; + case LANG_HP_RTL: + gsargv[arg++] = "-lRTL"; + break; + } + } } gsargv[arg++] = "-q"; gsargv[arg++] = "-o"; @@ -196,7 +226,7 @@ reset_ps(ps_t *dev) dev->ack = false; if (dev->pending) { - if (ghostscript_handle != NULL) + if ((dev->lang != LANG_RAW) && (ghostscript_handle != NULL)) convert_to_pdf(dev); dev->filename[0] = 0; @@ -220,8 +250,14 @@ write_buffer(ps_t *dev, bool finish) if (dev->buffer_pos == 0) return; - if (dev->filename[0] == 0) - plat_tempfile(dev->filename, NULL, dev->pcl ? ".pcl" : ".ps"); + if (dev->filename[0] == 0) { + if (dev->lang == LANG_RAW) + plat_tempfile(dev->filename, NULL, ".raw"); + else if (dev->pcl) + plat_tempfile(dev->filename, NULL, (dev->lang == LANG_PCL_6) ? ".pxl" : ".pcl"); + else + plat_tempfile(dev->filename, NULL, ".ps"); + } strcpy(path, dev->printer_path); path_slash(path); @@ -244,7 +280,7 @@ write_buffer(ps_t *dev, bool finish) dev->buffer_pos = 0; if (finish) { - if (ghostscript_handle != NULL) + if ((dev->lang != LANG_RAW) && (ghostscript_handle != NULL)) convert_to_pdf(dev); dev->filename[0] = 0; @@ -262,7 +298,7 @@ timeout_timer(void *priv) if (dev->buffer_pos != 0) write_buffer(dev, true); else if (dev->pending) { - if (ghostscript_handle != NULL) + if ((dev->lang != LANG_RAW) && (ghostscript_handle != NULL)) convert_to_pdf(dev); dev->filename[0] = 0; @@ -284,92 +320,115 @@ ps_write_data(uint8_t val, void *priv) dev->data = (char) val; } +static int +process_escape(ps_t *dev, int do_pjl) +{ + int ret = 0; + + if (dev->data == 0x1b) + dev->pcl_escape = 1; + else switch (dev->pcl_escape) { + case 1: + dev->pcl_escape = (dev->data == 0x25) ? 2 : 0; + break; + case 2: + dev->pcl_escape = (dev->data == 0x2d) ? 3 : 0; + break; + case 3: + dev->pcl_escape = (dev->data == 0x31) ? 4 : 0; + break; + case 4: + dev->pcl_escape = (dev->data == 0x32) ? 5 : 0; + break; + case 5: + dev->pcl_escape = (dev->data == 0x33) ? 6 : 0; + break; + case 6: + dev->pcl_escape = (dev->data == 0x34) ? 7 : 0; + break; + case 7: + dev->pcl_escape = (dev->data == 0x35) ? 8 : 0; + break; + case 8: + dev->pcl_escape = 0; + if (dev->data == 0x58) { + if (do_pjl) + dev->pjl = true; + + dev->buffer[dev->buffer_pos++] = dev->data; + dev->buffer[dev->buffer_pos] = 0; + + /* Wipe the slate clean so that there won't be a bogus empty page output to PDF. */ + dev->pending = false; + ret = 1; + } + break; + } + + return ret; +} + static void process_data(ps_t *dev) { - /* On PCL, check for escape sequences. */ - if (dev->pcl) { - if (dev->pjl) { - dev->buffer[dev->buffer_pos++] = dev->data; - - /* Filter out any PJL commands. */ - if (dev->pjl_command && (dev->data == '\n')) { - dev->pjl_command = false; - if (!memcmp(&(dev->buffer[dev->pjl_command_start]), "@PJL ENTER LANGUAGE=PCL", 0x17)) - dev->pjl = false; - else if (!memcmp(&(dev->buffer[dev->pjl_command_start]), "@PJL ENTER LANGUAGE=POSTSCRIPT", 0x1e)) - fatal("Printing PostScript using the PCL printer is not (yet) supported!\n"); - dev->buffer_pos = dev->pjl_command_start; - } else if (!dev->pjl_command && (dev->buffer_pos >= 0x05) && !memcmp(&(dev->buffer[dev->buffer_pos - 0x5]), "@PJL ", 0x05)) { - dev->pjl_command = true; - dev->pjl_command_start = dev->buffer_pos - 0x05; - } - - dev->buffer[dev->buffer_pos] = 0; - return; - } else if (dev->data == 0x1b) - dev->pcl_escape = 1; - else switch (dev->pcl_escape) { - case 1: - dev->pcl_escape = (dev->data == 0x25) ? 2 : 0; - if (dev->data == 0x0e) { - dev->buffer[dev->buffer_pos++] = dev->data; - dev->buffer[dev->buffer_pos] = 0; - - if (dev->buffer_pos > 2) - write_buffer(dev, true); - - return; - } - break; - case 2: - dev->pcl_escape = (dev->data == 0x2d) ? 3 : 0; - break; - case 3: - dev->pcl_escape = (dev->data == 0x31) ? 4 : 0; - break; - case 4: - dev->pcl_escape = (dev->data == 0x32) ? 5 : 0; - break; - case 5: - dev->pcl_escape = (dev->data == 0x33) ? 6 : 0; - break; - case 6: - dev->pcl_escape = (dev->data == 0x34) ? 7 : 0; - break; - case 7: - dev->pcl_escape = (dev->data == 0x35) ? 8 : 0; - break; - case 8: - dev->pcl_escape = 0; - if (dev->data == 0x58) - dev->pjl = true; - break; + if (dev->lang == LANG_RAW) { + if ((dev->data == 0x1b) || (dev->pcl_escape > 0)) { + if (process_escape(dev, 0)) + return; } - } else if ((dev->data < 0x20) || (dev->data == 0x7f)) { - /* On PostScript, check for non-printable characters. */ - switch (dev->data) { - /* The following characters are considered white-space - by the PostScript specification */ - case '\t': - case '\n': - case '\f': - case '\r': - break; + } else { + /* On PCL, check for escape sequences. */ + if (dev->pcl) { + if (dev->pjl) { + dev->buffer[dev->buffer_pos++] = dev->data; - /* Same with NUL, except we better change it to a space first */ - case '\0': - dev->data = ' '; - break; + /* Filter out any PJL commands. */ + if (dev->pjl_command && (dev->data == '\n')) { + dev->pjl_command = false; + if (!memcmp(&(dev->buffer[dev->pjl_command_start]), "@PJL ENTER LANGUAGE=PCL", 0x17)) + dev->pjl = false; + else if (!memcmp(&(dev->buffer[dev->pjl_command_start]), "@PJL ENTER LANGUAGE=POSTSCRIPT", 0x1e)) + fatal("Printing PostScript using the PCL printer is not (yet) supported!\n"); + dev->buffer[dev->buffer_pos] = 0x00; + dev->buffer_pos = dev->pjl_command_start; + } else if (!dev->pjl_command && (dev->buffer_pos >= 0x05) && !memcmp(&(dev->buffer[dev->buffer_pos - 0x5]), "@PJL ", 0x05)) { + dev->pjl_command = true; + dev->pjl_command_start = dev->buffer_pos - 0x05; + } else if (!dev->pjl_command && (dev->data == 0x1b)) + /* The universal exit code is also valid in PJL. */ + dev->pcl_escape = 1; - /* Ctrl+D (0x04) marks the end of the document */ - case '\4': - write_buffer(dev, true); + dev->buffer[dev->buffer_pos] = 0; return; + } else if ((dev->data == 0x1b) || (dev->pcl_escape > 0)) { + if (process_escape(dev, 1)) + return; + } + } else if ((dev->data < 0x20) || (dev->data == 0x7f)) { + /* On PostScript, check for non-printable characters. */ + switch (dev->data) { + /* The following characters are considered white-space + by the PostScript specification */ + case '\t': + case '\n': + case '\f': + case '\r': + break; - /* Don't bother with the others */ - default: - return; + /* Same with NUL, except we better change it to a space first */ + case '\0': + dev->data = ' '; + break; + + /* Ctrl+D (0x04) marks the end of the document */ + case '\4': + write_buffer(dev, true); + return; + + /* Don't bother with the others */ + default: + return; + } } } @@ -460,34 +519,39 @@ ps_read_status(void *priv) } static void * -ps_init(void *lpt) +ps_init(const device_t *info) { ps_t *dev = (ps_t *) calloc(1, sizeof(ps_t)); gsapi_revision_t rev; dev->ctrl = 0x04; - dev->lpt = lpt; dev->pcl = false; - /* Try loading the DLL. */ - ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); + dev->lpt = lpt_attach(ps_write_data, ps_write_ctrl, ps_strobe, ps_read_status, NULL, NULL, NULL, dev); + dev->lang = device_get_config_int("language"); + + if (dev->lang != LANG_RAW) { + /* Try loading the DLL. */ + ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL, ghostscript_imports); #ifdef PATH_GHOSTSCRIPT_DLL_ALT1 - if (ghostscript_handle == NULL) { - ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL_ALT1, ghostscript_imports); + if (ghostscript_handle == NULL) { + ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL_ALT1, ghostscript_imports); # ifdef PATH_GHOSTSCRIPT_DLL_ALT2 - if (ghostscript_handle == NULL) - ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL_ALT2, ghostscript_imports); + if (ghostscript_handle == NULL) + ghostscript_handle = dynld_module(PATH_GHOSTSCRIPT_DLL_ALT2, ghostscript_imports); # endif - } + } #endif - if (ghostscript_handle == NULL) { - ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_GHOSTSCRIPT_ERROR_TITLE), plat_get_string(STRING_GHOSTSCRIPT_ERROR_DESC)); - } else { - if (gsapi_revision(&rev, sizeof(rev)) == 0) { - pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); - } else { - dynld_close(ghostscript_handle); - ghostscript_handle = NULL; + + if (ghostscript_handle == NULL) { + ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_GHOSTSCRIPT_ERROR_TITLE), plat_get_string(STRING_GHOSTSCRIPT_ERROR_DESC)); + } else { + if (gsapi_revision(&rev, sizeof(rev)) == 0) { + pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); + } else { + dynld_close(ghostscript_handle); + ghostscript_handle = NULL; + } } } @@ -506,36 +570,40 @@ ps_init(void *lpt) return dev; } -#ifdef USE_PCL static void * -pcl_init(void *lpt) +pcl_init(const device_t *info) { ps_t *dev = (ps_t *) calloc(1, sizeof(ps_t)); gsapi_revision_t rev; dev->ctrl = 0x04; - dev->lpt = lpt; dev->pcl = true; - /* Try loading the DLL. */ - ghostscript_handle = dynld_module(PATH_GHOSTPCL_DLL, ghostscript_imports); + dev->lpt = lpt_attach(ps_write_data, ps_write_ctrl, ps_strobe, ps_read_status, NULL, NULL, NULL, dev); + dev->lang = device_get_config_int("language"); + + if (dev->lang != LANG_RAW) { + /* Try loading the DLL. */ + ghostscript_handle = dynld_module(PATH_GHOSTPCL_DLL, ghostscript_imports); #ifdef PATH_GHOSTPCL_DLL_ALT1 - if (ghostscript_handle == NULL) { - ghostscript_handle = dynld_module(PATH_GHOSTPCL_DLL_ALT1, ghostscript_imports); + if (ghostscript_handle == NULL) { + ghostscript_handle = dynld_module(PATH_GHOSTPCL_DLL_ALT1, ghostscript_imports); # ifdef PATH_GHOSTPCL_DLL_ALT2 - if (ghostscript_handle == NULL) - ghostscript_handle = dynld_module(PATH_GHOSTPCL_DLL_ALT2, ghostscript_imports); + if (ghostscript_handle == NULL) + ghostscript_handle = dynld_module(PATH_GHOSTPCL_DLL_ALT2, ghostscript_imports); # endif - } + } #endif - if (ghostscript_handle == NULL) { - ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_GHOSTPCL_ERROR_TITLE), plat_get_string(STRING_GHOSTPCL_ERROR_DESC)); - } else { - if (gsapi_revision(&rev, sizeof(rev)) == 0) { - pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); + + if (ghostscript_handle == NULL) { + ui_msgbox_header(MBX_ERROR, plat_get_string(STRING_GHOSTPCL_ERROR_TITLE), plat_get_string(STRING_GHOSTPCL_ERROR_DESC)); } else { - dynld_close(ghostscript_handle); - ghostscript_handle = NULL; + if (gsapi_revision(&rev, sizeof(rev)) == 0) { + pclog("Loaded %s, rev %ld (%ld)\n", rev.product, rev.revision, rev.revisiondate); + } else { + dynld_close(ghostscript_handle); + ghostscript_handle = NULL; + } } } @@ -553,7 +621,6 @@ pcl_init(void *lpt) return dev; } -#endif static void ps_close(void *priv) @@ -574,36 +641,75 @@ ps_close(void *priv) free(dev); } -const lpt_device_t lpt_prt_ps_device = { - .name = "Generic PostScript Printer", - .internal_name = "postscript", - .init = ps_init, - .close = ps_close, - .write_data = ps_write_data, - .write_ctrl = ps_write_ctrl, - .strobe = ps_strobe, - .read_status = ps_read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL +// clang-format off +static const device_config_t lpt_prt_ps_config[] = { + { + .name = "language", + .description = "Language", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = LANG_PS, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Raw", .value = LANG_RAW }, + { .description = "PDF (PostScript)", .value = LANG_PS }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +// clang-format on + +// clang-format off +static const device_config_t lpt_prt_pcl_config[] = { + { + .name = "language", + .description = "Language", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = LANG_PCL_5E, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "Raw", .value = LANG_RAW }, + { .description = "PDF (PCL 5e)", .value = LANG_PCL_5E }, + { .description = "PDF (PCL 5c)", .value = LANG_PCL_5C }, + { .description = "PDF (HP-RTL)", .value = LANG_HP_RTL }, + { .description = "PDF (PCL 6)", .value = LANG_PCL_6 }, + { .description = "" } + }, + .bios = { { 0 } } + }, + { .name = "", .description = "", .type = CONFIG_END } +}; +// clang-format on + +const device_t lpt_prt_ps_device = { + .name = "Generic PostScript Printer", + .internal_name = "postscript", + .flags = DEVICE_LPT, + .local = 0, + .init = ps_init, + .close = ps_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = lpt_prt_ps_config }; -#ifdef USE_PCL -const lpt_device_t lpt_prt_pcl_device = { - .name = "Generic PCL5e Printer", - .internal_name = "pcl", - .init = pcl_init, - .close = ps_close, - .write_data = ps_write_data, - .write_ctrl = ps_write_ctrl, - .strobe = ps_strobe, - .read_status = ps_read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL +const device_t lpt_prt_pcl_device = { + .name = "Generic PCL Printer", + .internal_name = "pcl", + .flags = DEVICE_LPT, + .local = 0, + .init = pcl_init, + .close = ps_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = lpt_prt_pcl_config }; -#endif diff --git a/src/printer/prt_text.c b/src/printer/prt_text.c index af601af75..ad49bc56f 100644 --- a/src/printer/prt_text.c +++ b/src/printer/prt_text.c @@ -455,13 +455,13 @@ read_status(void *priv) } static void * -prnt_init(void *lpt) +prnt_init(const device_t *info) { /* Initialize a device instance. */ prnt_t *dev = (prnt_t *) calloc(1, sizeof(prnt_t)); dev->ctrl = 0x04; - dev->lpt = lpt; + dev->lpt = lpt_attach(write_data, write_ctrl, strobe, read_status, NULL, NULL, NULL, dev); /* Initialize parameters. */ reset_printer(dev); @@ -523,13 +523,13 @@ static const device_config_t lpt_prt_text_config[] = { #endif // clang-format on -const device_t prt_text_device = { +const device_t lpt_prt_text_device = { .name = "Generic Text Printer", .internal_name = "text_prt", .flags = DEVICE_LPT, .local = 0, - .init = NULL, - .close = NULL, + .init = prnt_init, + .close = prnt_close, .reset = NULL, .available = NULL, .speed_changed = NULL, @@ -540,20 +540,3 @@ const device_t prt_text_device = { .config = NULL #endif }; - -const lpt_device_t lpt_prt_text_device = { - .name = "Generic Text Printer", - .internal_name = "text_prt", - .init = prnt_init, - .close = prnt_close, - .write_data = write_data, - .write_ctrl = write_ctrl, - .strobe = strobe, - .read_status = read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL, - .cfgdevice = (device_t *) &prt_text_device -}; diff --git a/src/qt/languages/86box.pot b/src/qt/languages/86box.pot index c5d1d2514..c62c18ea8 100644 --- a/src/qt/languages/86box.pot +++ b/src/qt/languages/86box.pot @@ -3017,3 +3017,6 @@ msgstr "" msgid "To change the system directory, stop all running machines." msgstr "" + +msgid "Raw" +msgstr "" diff --git a/src/qt/languages/ca-ES.po b/src/qt/languages/ca-ES.po index ad9dd6eb1..0c1c8ac89 100644 --- a/src/qt/languages/ca-ES.po +++ b/src/qt/languages/ca-ES.po @@ -3016,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "&Permetre recompilació" msgid "&Fast forward" -msgstr "" +msgstr "&Avançar ràpidament" msgid "Fast forward" -msgstr "" +msgstr "Avançar ràpidament" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Per canviar el directori del sistema, atureu totes les màquines en funcionament." + +msgid "Raw" +msgstr "En brut" diff --git a/src/qt/languages/cs-CZ.po b/src/qt/languages/cs-CZ.po index 5e89f736a..1df82475f 100644 --- a/src/qt/languages/cs-CZ.po +++ b/src/qt/languages/cs-CZ.po @@ -3022,5 +3022,7 @@ msgid "Fast forward" msgstr "Zrychlit" msgid "To change the system directory, stop all running machines." -msgstr "" -"Před změnou systémového adresáře nejprve zastavte všechny běžící počítače." +msgstr "Před změnou systémového adresáře nejprve zastavte všechny běžící počítače." + +msgid "Raw" +msgstr "Surový" diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 38e829861..5dccc6e54 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2025-11-29 00:34+0000\n" +"PO-Revision-Date: 2026-01-28 08:57+0000\n" "Last-Translator: OBattler \n" "Language-Team: German \n" "Language: de-DE\n" @@ -2872,7 +2872,7 @@ msgid "%1 VM Manager" msgstr "" msgid "%n disk(s)" -msgstr "" +msgstr "%n Festplatte(n)" msgid "Unknown Status" msgstr "Unbekannter Status" @@ -3016,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "Recompilierung &zulassen" msgid "&Fast forward" -msgstr "" +msgstr "&Schnellvorlauf" msgid "Fast forward" -msgstr "" +msgstr "Schnellvorlauf" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Um das Systemverzeichnis zu ändern, stoppen Sie alle laufenden Maschinen." + +msgid "Raw" +msgstr "Roh" diff --git a/src/qt/languages/el-GR.po b/src/qt/languages/el-GR.po index 9243c24fb..6933075a5 100644 --- a/src/qt/languages/el-GR.po +++ b/src/qt/languages/el-GR.po @@ -1,6 +1,6 @@ msgid "" msgstr "" -"PO-Revision-Date: 2026-01-10 12:56+0000\n" +"PO-Revision-Date: 2026-01-26 17:57+0000\n" "Last-Translator: DimMan88 \n" "Language-Team: Greek \n" "Language: el-GR\n" @@ -2919,24 +2919,26 @@ msgstr "Επιτυχής διαγραφή των περιεχομένων NVRAM msgid "An error occurred trying to wipe the NVRAM contents of the virtual machine \"%1\"" msgstr "" +"Ένα σφάλμα προέκυψε κατά την εκκαθάριση των περιεχομένων της NVRAM της " +"εικονικής μηχανής \"%1\"" msgid "%1 VM Manager" -msgstr "" +msgstr "%1 VM Manager" msgid "%n disk(s)" -msgstr "" +msgstr "%n δίσκος(οι)" msgid "Unknown Status" -msgstr "" +msgstr "Άγνωστη Κατάσταση" msgid "No Machines Found!" -msgstr "" +msgstr "Δεν βρέθηκαν μηχανές!" msgid "Check for updates on startup" msgstr "Έλεγχος για ενημερώσεις κατα την εκκίνηση" msgid "Unable to determine release information" -msgstr "" +msgstr "Αδυναμία προσδιορισμού πληροφοριών έκδοσης" msgid "There was an error checking for updates:\n\n%1\n\nPlease try again later." msgstr "" @@ -2947,82 +2949,84 @@ msgstr "" "Παρακαλώ προσπαθήστε ξανά αργότερα." msgid "Update check complete" -msgstr "" +msgstr "Ο έλεγχος ενημερώσεων ολοκληρώθηκε" msgid "stable" -msgstr "" +msgstr "σταθερή" msgid "beta" -msgstr "" +msgstr "δοκιμαστική" msgid "You are running the latest %1 version of 86Box: %2" -msgstr "" +msgstr "Τρέχετε την τελευταία %1 έκδοση του 86Box: %2" msgid "version" -msgstr "" +msgstr "έκδοση" msgid "build" -msgstr "" +msgstr "build" msgid "You are currently running version %1." -msgstr "" +msgstr "Τρέχετε την έκδοση %1." msgid "Version %1 is now available." -msgstr "" +msgstr "Έκδοση %1 είναι διαθέσιμη." msgid "You are currently running build %1." -msgstr "" +msgstr "Τρέχετε το build %1." msgid "Build %1 is now available." -msgstr "" +msgstr "Build %1 είναι τώρα διαθέσιμο." msgid "Would you like to visit the download page?" -msgstr "" +msgstr "Επιθυμείτε να επισκεφθείτε την σελίδα λήψεων;" msgid "Visit download page" -msgstr "" +msgstr "Επίσκεψη σελίδας λήψεων" msgid "Update check" -msgstr "" +msgstr "Έλεγχος ενημερώσεων" msgid "Checking for updates…" msgstr "Έλεγχος για ενημερώσεις…" msgid "86Box Update" -msgstr "" +msgstr "Ενημέρωση 86Box" msgid "Release notes:" -msgstr "" +msgstr "Σημειώσεις έκδοσης:" msgid "%1 Hz" -msgstr "" +msgstr "%1 Hz" msgid "Virtual machine crash" -msgstr "" +msgstr "Σφάλμα εικονικής μηχανής" msgid "The virtual machine \"%1\"'s process has unexpectedly terminated with exit code %2." msgstr "" +"Η διεργασία της εικονικής μηχανής \"%1\" τερματίστηκε απροσδόκητα με κωδικό " +"εξόδου %2." msgid "The system will not be added." -msgstr "" +msgstr "Το σύστημα δεν θα προστεθεί." msgid "&Update mouse every CPU frame" msgstr "&Ανανέωση ποντικιού ανα καρέ CPU" msgid "Hue" -msgstr "" +msgstr "Απόχρωση" msgid "Saturation" -msgstr "" +msgstr "Κορεσμός" msgid "Contrast" -msgstr "" +msgstr "Αντίθεση" msgid "Brightness" -msgstr "" +msgstr "Φωτεινότητα" msgid "Sharpness" -msgstr "" +msgstr "Οξύτητα" msgid "&CGA composite settings…" msgstr "Ρυθμίσεις &CGA composite…" @@ -3073,10 +3077,13 @@ msgid "&Allow recompilation" msgstr "&Να επιτρέπεται ανασύνταξη" msgid "&Fast forward" -msgstr "" +msgstr "&Γρήγορα μπροστά" msgid "Fast forward" -msgstr "" +msgstr "Γρήγορα μπροστά" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Για να αλλάξετε τον κατάλογο συστήματος, σταματήστε πρώτα όλες τις μηχανές σε λειτουργία." + +msgid "Raw" +msgstr "Αρχικος" diff --git a/src/qt/languages/es-ES.po b/src/qt/languages/es-ES.po index 3d339efd0..4f34c34f5 100644 --- a/src/qt/languages/es-ES.po +++ b/src/qt/languages/es-ES.po @@ -3016,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "&Permitir recompilación" msgid "&Fast forward" -msgstr "" +msgstr "&Avance rápido" msgid "Fast forward" -msgstr "" +msgstr "Avance rápido" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Para cambiar el directorio del sistema, detenga todas las máquinas en funcionamiento." + +msgid "Raw" +msgstr "Plano" diff --git a/src/qt/languages/fi-FI.po b/src/qt/languages/fi-FI.po index fd6add696..2351f1afa 100644 --- a/src/qt/languages/fi-FI.po +++ b/src/qt/languages/fi-FI.po @@ -1,7 +1,7 @@ msgid "" msgstr "" -"PO-Revision-Date: 2025-12-29 09:54+0000\n" -"Last-Translator: Daniel Gurney \n" +"PO-Revision-Date: 2026-01-28 08:57+0000\n" +"Last-Translator: OBattler \n" "Language-Team: Finnish \n" "Language: fi-FI\n" "MIME-Version: 1.0\n" @@ -637,7 +637,7 @@ msgid "MO drives:" msgstr "Magneettisoptiset asemat (MO):" msgid "MO:" -msgstr "" +msgstr "MO:" msgid "Removable disks:" msgstr "Irrotettavat levyt:" @@ -1843,7 +1843,7 @@ msgid "Microsoft Serial Mouse" msgstr "Microsoft-sarjahiiri" msgid "Microsoft Serial BallPoint" -msgstr "" +msgstr "Microsoft BallPoint-sarjahiiri" msgid "Logitech Serial Mouse" msgstr "Logitech-sarjahiiri" @@ -1930,7 +1930,7 @@ msgid "Enable BIOS extension ROM Writes (ROM #4)" msgstr "Salli BIOS-laajennuksen ROM-kirjoitukset (ROM #4)" msgid "Linear framebuffer base" -msgstr "" +msgstr "Lineaarisen kehyspuskurin perusosoite" msgid "Address" msgstr "Osoite" @@ -2179,7 +2179,7 @@ msgid "WSS DMA" msgstr "WSS-DMA" msgid "RTC IRQ" -msgstr "" +msgstr "RTC:n IRQ" msgid "RTC Port Address" msgstr "RTC-portin osoite" @@ -2380,10 +2380,10 @@ msgid "Linear" msgstr "Lineaarinen" msgid "4th Order" -msgstr "" +msgstr "4. kertaluku" msgid "7th Order" -msgstr "" +msgstr "7. kertaluku" msgid "Non-timed (original)" msgstr "Ajastamaton (alkuperäinen)" @@ -3016,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "&Salli uudelleenkääntäminen" msgid "&Fast forward" -msgstr "" +msgstr "&Nopea eteneminen" msgid "Fast forward" -msgstr "" +msgstr "Nopea eteneminen" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Järjestelmähakemiston muuttamiseksi pysäytä kaikki käynnissä olevat koneet." + +msgid "Raw" +msgstr "Raaka" diff --git a/src/qt/languages/fr-FR.po b/src/qt/languages/fr-FR.po index 2e1422a08..42f1a8f40 100644 --- a/src/qt/languages/fr-FR.po +++ b/src/qt/languages/fr-FR.po @@ -3016,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "&Permettre la recompilation" msgid "&Fast forward" -msgstr "" +msgstr "&Avance rapide" msgid "Fast forward" -msgstr "" +msgstr "Avance rapide" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Pour modifier le répertoire système, arrêtez toutes les machines en cours d'exécution." + +msgid "Raw" +msgstr "Brut" diff --git a/src/qt/languages/hr-HR.po b/src/qt/languages/hr-HR.po index b3d9a68f1..32aaf1cf7 100644 --- a/src/qt/languages/hr-HR.po +++ b/src/qt/languages/hr-HR.po @@ -3018,10 +3018,13 @@ msgid "&Allow recompilation" msgstr "&Omogući rekompilaciju" msgid "&Fast forward" -msgstr "" +msgstr "&Brzo naprijed" msgid "Fast forward" -msgstr "" +msgstr "Brzo naprijed" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Za promjenu sustavskog direktorija zaustavite sve pokrenute strojeve." + +msgid "Raw" +msgstr "Neobrađeni podaci" diff --git a/src/qt/languages/it-IT.po b/src/qt/languages/it-IT.po index f4d16bf86..f46d09159 100644 --- a/src/qt/languages/it-IT.po +++ b/src/qt/languages/it-IT.po @@ -3016,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "&Permetti ricompilazione" msgid "&Fast forward" -msgstr "" +msgstr "&Avanti veloce" msgid "Fast forward" -msgstr "" +msgstr "Avanti veloce" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Per modificare la directory di sistema, arrestare tutte le macchine in funzione." + +msgid "Raw" +msgstr "Grezzo" diff --git a/src/qt/languages/ja-JP.po b/src/qt/languages/ja-JP.po index 2a7809a47..027b05204 100644 --- a/src/qt/languages/ja-JP.po +++ b/src/qt/languages/ja-JP.po @@ -3017,10 +3017,13 @@ msgid "&Allow recompilation" msgstr "再コンパイルを許可する(&A)" msgid "&Fast forward" -msgstr "" +msgstr "早送り(&F)" msgid "Fast forward" -msgstr "" +msgstr "早送り" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "システムディレクトリを変更するには、稼働中のマシンをすべて停止してください。" + +msgid "Raw" +msgstr "生" diff --git a/src/qt/languages/ko-KR.po b/src/qt/languages/ko-KR.po index 0318e85f3..a46dc07c7 100644 --- a/src/qt/languages/ko-KR.po +++ b/src/qt/languages/ko-KR.po @@ -1,8 +1,14 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-28 08:57+0000\n" +"Last-Translator: OBattler \n" +"Language-Team: Korean \n" +"Language: ko-KR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: ko_KR\n" "X-Source-Language: en_US\n" @@ -1780,7 +1786,7 @@ msgid "VDE Socket:" msgstr "VDE 소켓:" msgid "TAP Bridge Device:" -msgstr "" +msgstr "TAP 브리지 장치:" msgid "86Box Unit Tester" msgstr "86Box 유닛 테스터" @@ -2173,16 +2179,16 @@ msgid "WSS DMA" msgstr "WSS DMA" msgid "RTC IRQ" -msgstr "" +msgstr "RTC의 IRQ" msgid "RTC Port Address" -msgstr "" +msgstr "RTC의 포트 주소" msgid "Onboard RTC" -msgstr "" +msgstr "온보드 RTC" msgid "Not installed" -msgstr "" +msgstr "설치되지 않음" msgid "Enable OPL" msgstr "OPL 사용" @@ -2806,7 +2812,7 @@ msgid "Toggle fullscreen" msgstr "전체 화면 모드 전환" msgid "Toggle UI in fullscreen" -msgstr "" +msgstr "전체 화면 모드에서 UI 전환" msgid "Release mouse pointer" msgstr "마우스 포인터를 해제합니다" @@ -3010,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "재컴파일 허용(&A)" msgid "&Fast forward" -msgstr "" +msgstr "빠른 전진(&F)" msgid "Fast forward" -msgstr "" +msgstr "빠른 전진" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "시스템 디렉터리를 변경하려면 실행 중인 모든 머신을 중지하십시오." + +msgid "Raw" +msgstr "원본" diff --git a/src/qt/languages/nb-NO.po b/src/qt/languages/nb-NO.po index e31768305..b22f0bf69 100644 --- a/src/qt/languages/nb-NO.po +++ b/src/qt/languages/nb-NO.po @@ -1,8 +1,15 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-28 08:57+0000\n" +"Last-Translator: OBattler \n" +"Language-Team: Norwegian Bokmål \n" +"Language: nb-NO\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: nb_NO\n" "X-Source-Language: en_US\n" @@ -1780,7 +1787,7 @@ msgid "VDE Socket:" msgstr "VDE-kontakt:" msgid "TAP Bridge Device:" -msgstr "" +msgstr "TAP-broenhet:" msgid "86Box Unit Tester" msgstr "86Box-enhetstester" @@ -2173,16 +2180,16 @@ msgid "WSS DMA" msgstr "WSS-DMA" msgid "RTC IRQ" -msgstr "" +msgstr "IRQ for RTC" msgid "RTC Port Address" -msgstr "" +msgstr "Portadresse for RTC" msgid "Onboard RTC" -msgstr "" +msgstr "Innebygd RTC" msgid "Not installed" -msgstr "" +msgstr "Ikke installert" msgid "Enable OPL" msgstr "Aktiver OPL" @@ -2806,7 +2813,7 @@ msgid "Toggle fullscreen" msgstr "Veksle fullskjerm" msgid "Toggle UI in fullscreen" -msgstr "" +msgstr "Veksle mellom brukergrensesnittet i fullskjermmodus" msgid "Release mouse pointer" msgstr "Frigi musepeker" @@ -3010,10 +3017,13 @@ msgid "&Allow recompilation" msgstr "&Tillat rekompilering" msgid "&Fast forward" -msgstr "" +msgstr "&Spol fremover" msgid "Fast forward" -msgstr "" +msgstr "Spol fremover" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "For å endre systemkatalogen, stopp alle maskiner som er kjører." + +msgid "Raw" +msgstr "Rå" diff --git a/src/qt/languages/nl-NL.po b/src/qt/languages/nl-NL.po index 3d056a2ea..3ad6f4feb 100644 --- a/src/qt/languages/nl-NL.po +++ b/src/qt/languages/nl-NL.po @@ -1,8 +1,14 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-28 08:57+0000\n" +"Last-Translator: OBattler \n" +"Language-Team: Dutch \n" +"Language: nl-NL\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: nl_NL\n" "X-Source-Language: en_US\n" @@ -1780,7 +1786,7 @@ msgid "VDE Socket:" msgstr "VDE-socket:" msgid "TAP Bridge Device:" -msgstr "" +msgstr "TAP-brugapparaat:" msgid "86Box Unit Tester" msgstr "86Box Apparaattester" @@ -2173,16 +2179,16 @@ msgid "WSS DMA" msgstr "WSS DMA" msgid "RTC IRQ" -msgstr "" +msgstr "IRQ van de RTC" msgid "RTC Port Address" -msgstr "" +msgstr "Poortadres van de RTC" msgid "Onboard RTC" -msgstr "" +msgstr "Ingebouwde RTC" msgid "Not installed" -msgstr "" +msgstr "Niet geïnstalleerd" msgid "Enable OPL" msgstr "OPL inschakelen" @@ -2806,7 +2812,7 @@ msgid "Toggle fullscreen" msgstr "Volledig scherm omschakelen" msgid "Toggle UI in fullscreen" -msgstr "" +msgstr "Schakel de UI in volledig scherm" msgid "Release mouse pointer" msgstr "Geef muis vrij" @@ -3010,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "Recompilatie &toestaan" msgid "&Fast forward" -msgstr "" +msgstr "&Snel vooruitspoelen" msgid "Fast forward" -msgstr "" +msgstr "Snel vooruitspoelen" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Om de systeemmap te wijzigen, moet u alle actieve machines stoppen." + +msgid "Raw" +msgstr "Ruw" diff --git a/src/qt/languages/pl-PL.po b/src/qt/languages/pl-PL.po index 20317c9ec..e67ada685 100644 --- a/src/qt/languages/pl-PL.po +++ b/src/qt/languages/pl-PL.po @@ -3017,10 +3017,13 @@ msgid "&Allow recompilation" msgstr "&Zezwól na rekompilację" msgid "&Fast forward" -msgstr "" +msgstr "&Przewiń do przodu" msgid "Fast forward" -msgstr "" +msgstr "Przewiń do przodu" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Aby zmienić katalog systemowy, zatrzymaj wszystkie działające maszyny." + +msgid "Raw" +msgstr "Surowy" diff --git a/src/qt/languages/pt-BR.po b/src/qt/languages/pt-BR.po index 31875d7ba..5ffbc2c72 100644 --- a/src/qt/languages/pt-BR.po +++ b/src/qt/languages/pt-BR.po @@ -3010,10 +3010,13 @@ msgid "&Allow recompilation" msgstr "&Permitir recompilação" msgid "&Fast forward" -msgstr "" +msgstr "&Avançar rapidamente" msgid "Fast forward" -msgstr "" +msgstr "Avançar rapidamente" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Para alterar o diretório do sistema, pare todas as máquinas em funcionamento." + +msgid "Raw" +msgstr "Bruto" diff --git a/src/qt/languages/pt-PT.po b/src/qt/languages/pt-PT.po index f18eb8f1a..8f0f55caf 100644 --- a/src/qt/languages/pt-PT.po +++ b/src/qt/languages/pt-PT.po @@ -3017,10 +3017,13 @@ msgid "&Allow recompilation" msgstr "&Permitir recompilação" msgid "&Fast forward" -msgstr "" +msgstr "&Avançar rapidamente" msgid "Fast forward" -msgstr "" +msgstr "Avançar rapidamente" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Para alterar o diretório do sistema, pare todas as máquinas em funcionamento." + +msgid "Raw" +msgstr "Bruto" diff --git a/src/qt/languages/ru-RU.po b/src/qt/languages/ru-RU.po index 6102dceed..9ca679356 100644 --- a/src/qt/languages/ru-RU.po +++ b/src/qt/languages/ru-RU.po @@ -3036,3 +3036,6 @@ msgstr "Перемотка вперёд" msgid "To change the system directory, stop all running machines." msgstr "Чтобы изменить системную папку, остановите все запущенные машины." + +msgid "Raw" +msgstr "Сырой" diff --git a/src/qt/languages/sk-SK.po b/src/qt/languages/sk-SK.po index a112005da..a5570faeb 100644 --- a/src/qt/languages/sk-SK.po +++ b/src/qt/languages/sk-SK.po @@ -3016,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "&Povoliť rekompiláciu" msgid "&Fast forward" -msgstr "" +msgstr "&Rýchly posun dopredu" msgid "Fast forward" -msgstr "" +msgstr "Rýchly posun dopredu" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Ak chcete zmeniť systémový adresár, zastavte všetky bežiace stroje." + +msgid "Raw" +msgstr "Surový" diff --git a/src/qt/languages/sl-SI.po b/src/qt/languages/sl-SI.po index 64cc6e7eb..dfe0acbcd 100644 --- a/src/qt/languages/sl-SI.po +++ b/src/qt/languages/sl-SI.po @@ -3018,10 +3018,13 @@ msgid "&Allow recompilation" msgstr "&Dovoli prevajanje" msgid "&Fast forward" -msgstr "" +msgstr "&Hitro previj" msgid "Fast forward" -msgstr "" +msgstr "Hitro previj" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Da bi spremenili sistemski imenik, ustavite vse naprave, ki se izvajajo." + +msgid "Raw" +msgstr "Neobdelan" diff --git a/src/qt/languages/sv-SE.po b/src/qt/languages/sv-SE.po index f49235919..5a8c7291c 100644 --- a/src/qt/languages/sv-SE.po +++ b/src/qt/languages/sv-SE.po @@ -1,8 +1,14 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-28 08:57+0000\n" +"Last-Translator: OBattler \n" +"Language-Team: Swedish \n" +"Language: sv-SE\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=2; plural=n != 1;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: sv_SE\n" "X-Source-Language: en_US\n" @@ -1780,7 +1786,7 @@ msgid "VDE Socket:" msgstr "VDE-sockel:" msgid "TAP Bridge Device:" -msgstr "" +msgstr "TAP-bryggaenhet:" msgid "86Box Unit Tester" msgstr "86Box enhetsprövare" @@ -2173,16 +2179,16 @@ msgid "WSS DMA" msgstr "WSS DMA" msgid "RTC IRQ" -msgstr "" +msgstr "IRQ för RTC" msgid "RTC Port Address" -msgstr "" +msgstr "Portadress för RTC" msgid "Onboard RTC" -msgstr "" +msgstr "Inbyggd RTC" msgid "Not installed" -msgstr "" +msgstr "Ej installerad" msgid "Enable OPL" msgstr "Aktivera OPL" @@ -2806,7 +2812,7 @@ msgid "Toggle fullscreen" msgstr "Helskärm" msgid "Toggle UI in fullscreen" -msgstr "" +msgstr "Växla UI till helskärmsläge" msgid "Release mouse pointer" msgstr "Släpp muspekare" @@ -3010,10 +3016,13 @@ msgid "&Allow recompilation" msgstr "&Tillåt omkompilering" msgid "&Fast forward" -msgstr "" +msgstr "&Spola fram" msgid "Fast forward" -msgstr "" +msgstr "Spola fram" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "ör att ändra systemkatalogen, stoppa alla maskiner som är körs." + +msgid "Raw" +msgstr "Rå" diff --git a/src/qt/languages/tr-TR.po b/src/qt/languages/tr-TR.po index a40e07e4b..510fd82f3 100644 --- a/src/qt/languages/tr-TR.po +++ b/src/qt/languages/tr-TR.po @@ -3023,3 +3023,6 @@ msgstr "İleri sar" msgid "To change the system directory, stop all running machines." msgstr "Sistem dizinini değiştirmek için tüm çalışan makineleri durdurun." + +msgid "Raw" +msgstr "Ham" diff --git a/src/qt/languages/uk-UA.po b/src/qt/languages/uk-UA.po index 7fd0d0b33..d1964e647 100644 --- a/src/qt/languages/uk-UA.po +++ b/src/qt/languages/uk-UA.po @@ -3018,10 +3018,13 @@ msgid "&Allow recompilation" msgstr "&Дозволити рекомпіляцію" msgid "&Fast forward" -msgstr "" +msgstr "&Перемотай вперед" msgid "Fast forward" -msgstr "" +msgstr "Перемотай вперед" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Щоб змінити системний каталог, зупиніть усі машини, що працюють." + +msgid "Raw" +msgstr "Сирий" diff --git a/src/qt/languages/vi-VN.po b/src/qt/languages/vi-VN.po index b2c7491a1..73b59831a 100644 --- a/src/qt/languages/vi-VN.po +++ b/src/qt/languages/vi-VN.po @@ -1,8 +1,15 @@ msgid "" msgstr "" +"PO-Revision-Date: 2026-01-28 08:57+0000\n" +"Last-Translator: OBattler \n" +"Language-Team: Vietnamese \n" +"Language: vi-VN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" +"Plural-Forms: nplurals=1; plural=0;\n" +"X-Generator: Weblate 5.12.2\n" "X-Language: vi_VN\n" "X-Source-Language: en_US\n" @@ -1780,7 +1787,7 @@ msgid "VDE Socket:" msgstr "Ổ cắm VDE:" msgid "TAP Bridge Device:" -msgstr "" +msgstr "Thiết bị cầu nối TAP:" msgid "86Box Unit Tester" msgstr "Trình kiểm tra đơn vị 86box" @@ -2173,16 +2180,16 @@ msgid "WSS DMA" msgstr "WSS DMA" msgid "RTC IRQ" -msgstr "" +msgstr "IRQ của RTC" msgid "RTC Port Address" -msgstr "" +msgstr "Địa chỉ cổng của RTC" msgid "Onboard RTC" -msgstr "" +msgstr "RTC tích hợp trên bo mạch" msgid "Not installed" -msgstr "" +msgstr "Chưa được cài đặt" msgid "Enable OPL" msgstr "Bật OPL" @@ -2806,7 +2813,7 @@ msgid "Toggle fullscreen" msgstr "Bật/tắt toàn màn hình" msgid "Toggle UI in fullscreen" -msgstr "" +msgstr "Chuyển đổi giao diện người dùng sang chế độ toàn màn hình" msgid "Release mouse pointer" msgstr "Thả con trỏ chuột" @@ -3010,10 +3017,13 @@ msgid "&Allow recompilation" msgstr "&Cho phép biên dịch lại" msgid "&Fast forward" -msgstr "" +msgstr "&Chuyển nhanh băng" msgid "Fast forward" -msgstr "" +msgstr "Chuyển nhanh băng" msgid "To change the system directory, stop all running machines." -msgstr "" +msgstr "Để thay đổi thư mục hệ thống, hãy tắt tất cả các máy đang chạy." + +msgid "Raw" +msgstr "Thô" diff --git a/src/qt/languages/zh-CN.po b/src/qt/languages/zh-CN.po index c922e207b..7e98480cd 100644 --- a/src/qt/languages/zh-CN.po +++ b/src/qt/languages/zh-CN.po @@ -3024,3 +3024,6 @@ msgstr "快进" msgid "To change the system directory, stop all running machines." msgstr "请在变更系统目录前关闭所有正在运行的虚拟机。" + +msgid "Raw" +msgstr "原始" diff --git a/src/qt/languages/zh-TW.po b/src/qt/languages/zh-TW.po index 0bdcd215a..78365a911 100644 --- a/src/qt/languages/zh-TW.po +++ b/src/qt/languages/zh-TW.po @@ -3024,3 +3024,6 @@ msgstr "快轉" msgid "To change the system directory, stop all running machines." msgstr "欲變更系統目錄,請先停止全部運行中的機器。" + +msgid "Raw" +msgstr "原始" diff --git a/src/qt/qt_defs.hpp b/src/qt/qt_defs.hpp index 1190c0ed1..58de88b67 100644 --- a/src/qt/qt_defs.hpp +++ b/src/qt/qt_defs.hpp @@ -1,7 +1,7 @@ #ifndef QT_DEFS_HPP #define QT_DEFS_HPP -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0) #define CHECK_STATE_CHANGED checkStateChanged #else #define CHECK_STATE_CHANGED stateChanged diff --git a/src/qt/qt_settingsports.cpp b/src/qt/qt_settingsports.cpp index b1155629d..232822201 100644 --- a/src/qt/qt_settingsports.cpp +++ b/src/qt/qt_settingsports.cpp @@ -138,13 +138,15 @@ SettingsPorts::onCurrentMachineChanged(int machineId) if (lptName == nullptr) break; - const QString name = tr(lptName); + if (lpt_device_available(c)) { + const QString name = tr(lptName); - for (uint8_t i = 0; i < PARALLEL_MAX; ++i) { - int row = Models::AddEntry(models[i], name, c); + for (uint8_t i = 0; i < PARALLEL_MAX; ++i) { + int row = Models::AddEntry(models[i], name, c); - if (c == lpt_ports[i].device) - selectedRows[i] = row - removeRows_[i]; + if (c == lpt_ports[i].device) + selectedRows[i] = row - removeRows_[i]; + } } c++; diff --git a/src/sound/snd_lpt_dac.c b/src/sound/snd_lpt_dac.c index 33b197230..77271ed8d 100644 --- a/src/sound/snd_lpt_dac.c +++ b/src/sound/snd_lpt_dac.c @@ -89,11 +89,11 @@ dac_get_buffer(int32_t *buffer, int len, void *priv) } static void * -dac_init(void *lpt) +dac_init(UNUSED(const device_t *info)) { lpt_dac_t *lpt_dac = calloc(1, sizeof(lpt_dac_t)); - lpt_dac->lpt = lpt; + lpt_dac->lpt = lpt_attach(dac_write_data, dac_write_ctrl, dac_strobe, dac_read_status, NULL, NULL, NULL, lpt_dac); sound_add_handler(dac_get_buffer, lpt_dac); @@ -101,9 +101,9 @@ dac_init(void *lpt) } static void * -dac_stereo_init(void *lpt) +dac_stereo_init(const device_t *info) { - lpt_dac_t *lpt_dac = dac_init(lpt); + lpt_dac_t *lpt_dac = dac_init(info); lpt_dac->is_stereo = 1; @@ -117,34 +117,30 @@ dac_close(void *priv) free(lpt_dac); } -const lpt_device_t lpt_dac_device = { - .name = "LPT DAC / Covox Speech Thing", - .internal_name = "lpt_dac", - .init = dac_init, - .close = dac_close, - .write_data = dac_write_data, - .write_ctrl = dac_write_ctrl, - .strobe = dac_strobe, - .read_status = dac_read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL +const device_t lpt_dac_device = { + .name = "LPT DAC / Covox Speech Thing", + .internal_name = "lpt_dac", + .flags = DEVICE_LPT, + .local = 0, + .init = dac_init, + .close = dac_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; -const lpt_device_t lpt_dac_stereo_device = { - .name = "Stereo LPT DAC", - .internal_name = "lpt_dac_stereo", - .init = dac_stereo_init, - .close = dac_close, - .write_data = dac_write_data, - .write_ctrl = dac_write_ctrl, - .strobe = dac_strobe, - .read_status = dac_read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL +const device_t lpt_dac_stereo_device = { + .name = "Stereo LPT DAC", + .internal_name = "lpt_dac_stereo", + .flags = DEVICE_LPT, + .local = 0, + .init = dac_stereo_init, + .close = dac_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/sound/snd_lpt_dss.c b/src/sound/snd_lpt_dss.c index 5ea0048f4..6fac66b6e 100644 --- a/src/sound/snd_lpt_dss.c +++ b/src/sound/snd_lpt_dss.c @@ -114,11 +114,11 @@ dss_callback(void *priv) } static void * -dss_init(void *lpt) +dss_init(UNUSED(const device_t *info)) { dss_t *dss = calloc(1, sizeof(dss_t)); - dss->lpt = lpt; + dss->lpt = lpt_attach(dss_write_data, dss_write_ctrl, NULL, dss_read_status, NULL, NULL, NULL, dss); sound_add_handler(dss_get_buffer, dss); timer_add(&dss->timer, dss_callback, dss, 1); @@ -133,18 +133,16 @@ dss_close(void *priv) free(dss); } -const lpt_device_t dss_device = { - .name = "Disney Sound Source", - .internal_name = "dss", - .init = dss_init, - .close = dss_close, - .write_data = dss_write_data, - .strobe = NULL, - .write_ctrl = dss_write_ctrl, - .read_status = dss_read_status, - .read_ctrl = NULL, - .epp_write_data = NULL, - .epp_request_read = NULL, - .priv = NULL, - .lpt = NULL +const device_t dss_device = { + .name = "Disney Sound Source", + .internal_name = "dss", + .flags = DEVICE_LPT, + .local = 0, + .init = dss_init, + .close = dss_close, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = NULL }; diff --git a/src/unix/assets/86Box.spec b/src/unix/assets/86Box.spec index a189a5f41..aefac7a4f 100644 --- a/src/unix/assets/86Box.spec +++ b/src/unix/assets/86Box.spec @@ -12,10 +12,10 @@ # After a successful build, you can install the RPMs as follows: # sudo dnf install RPMS/$(uname -m)/86Box-3* RPMS/noarch/86Box-roms* -%global romver 5.4 +%global romver 6.0 Name: 86Box -Version: 5.4 +Version: 6.0 Release: 1%{?dist} Summary: Classic PC emulator License: GPLv2+ @@ -121,5 +121,5 @@ popd %{_datadir}/%{name}/roms %changelog -* Sat Aug 31 Jasmine Iwanek 5.4-1 +* Sat Aug 31 Jasmine Iwanek 6.0-1 - Bump release diff --git a/src/unix/assets/net.86box.86Box.metainfo.xml b/src/unix/assets/net.86box.86Box.metainfo.xml index c6a612a4c..4fdfe9c2a 100644 --- a/src/unix/assets/net.86box.86Box.metainfo.xml +++ b/src/unix/assets/net.86box.86Box.metainfo.xml @@ -11,7 +11,7 @@ net.86box.86Box.desktop - + diff --git a/src/video/vid_8514a.c b/src/video/vid_8514a.c index ca7e182b0..872743b72 100644 --- a/src/video/vid_8514a.c +++ b/src/video/vid_8514a.c @@ -261,8 +261,8 @@ void ibm8514_accel_out_pixtrans(svga_t *svga, UNUSED(uint16_t port), uint32_t val, int len) { ibm8514_t *dev = (ibm8514_t *) svga->dev8514; - uint8_t nibble = 0; - uint32_t pixelxfer = 0; + uint8_t nibble = 0x0000; + uint32_t pixelxfer = 0x00000000; uint32_t monoxfer = 0xffffffff; int pixcnt = 0; int pixcntl = (dev->accel.multifunc[0x0a] >> 6) & 3; @@ -289,8 +289,23 @@ ibm8514_accel_out_pixtrans(svga_t *svga, UNUSED(uint16_t port), uint32_t val, in val = (val >> 8) | (val << 8); } if ((cmd <= 2) || (cmd == 4) || (cmd == 6)) { - if ((dev->accel.cmd & 0x08) && (cmd >= 1)) { - monoxfer = val; + if (dev->accel.cmd & 0x08) { + if (val & 0x02) + nibble |= 0x08; + if (val & 0x04) + nibble |= 0x04; + if (val & 0x08) + nibble |= 0x02; + if (val & 0x10) + nibble |= 0x01; + if (val & 0x200) + nibble |= 0x80; + if (val & 0x400) + nibble |= 0x40; + if (val & 0x800) + nibble |= 0x20; + if (val & 0x1000) + nibble |= 0x10; } else { if (val & 0x02) nibble |= 0x80; @@ -308,9 +323,8 @@ ibm8514_accel_out_pixtrans(svga_t *svga, UNUSED(uint16_t port), uint32_t val, in nibble |= 0x02; if (val & 0x1000) nibble |= 0x01; - - monoxfer = nibble; } + monoxfer = nibble; } else monoxfer = val; } else @@ -545,7 +559,7 @@ ibm8514_accel_out_fifo(svga_t *svga, uint16_t port, uint32_t val, int len) if (dev->accel.cmd & 0x100) dev->accel.cmd_back = 0; - ibm8514_log("8514/A CMD=%04x, frgd color=%04x, frgdmix=%02x, pixcntl=%02x.\n", dev->accel.cmd, dev->accel.frgd_color, dev->accel.frgd_mix, dev->accel.multifunc[0x0a]); + ibm8514_log("8514A CMDflags=%04x, frgd color=%04x, frgdmix=%02x, pixcntl=%02x.\n", dev->accel.cmd, dev->accel.frgd_color, dev->accel.frgd_mix, dev->accel.multifunc[0x0a]); ibm8514_accel_start(-1, 0, -1, 0, svga, len); } break; @@ -894,9 +908,6 @@ ibm8514_accel_in_fifo(svga_t *svga, uint16_t port, int len) } ibm8514_accel_out_pixtrans(svga, port, (temp >> 8) & 0xff, len); } else { - if (dev->accel.input3) - temp = 0xffff; - ibm8514_accel_out_pixtrans(svga, port, temp, len); } } @@ -981,6 +992,10 @@ ibm8514_accel_in(uint16_t port, svga_t *svga) dev->data_available2 = 0; temp |= INT_FIFO_EMP; } + if (!dev->fifo_idx) { + if (dev->accel.cmd_back) + temp |= 0x800; + } temp |= (dev->subsys_stat | (dev->vram_512k_8514 ? 0x00 : 0x80)); temp |= 0x20; } @@ -1070,6 +1085,7 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat uint16_t bkgd_color = dev->accel.bkgd_color; uint32_t old_mix_dat; int and3 = dev->accel.cur_x & 3; + int and3_blt = dev->accel.destx & 3; int poly_src; if (!dev->bpp) { @@ -1229,7 +1245,6 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat old_dest_dat = dest_dat; MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if (dev->accel.ssv_draw) { if ((dev->accel.cmd & 0x04) && dev->accel.ssv_len) { WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); @@ -1300,42 +1315,44 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - src_dat = 0; - break; + if (ibm8514_cpu_src(svga) || !cpu_input) { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; - default: - break; - } + default: + break; + } - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - if ((compare_mode == 0) || - ((compare_mode == 0x10) && (dest_dat >= compare)) || - ((compare_mode == 0x18) && (dest_dat < compare)) || - ((compare_mode == 0x20) && (dest_dat != compare)) || - ((compare_mode == 0x28) && (dest_dat == compare)) || - ((compare_mode == 0x30) && (dest_dat <= compare)) || - ((compare_mode == 0x38) && (dest_dat > compare))) { - old_dest_dat = dest_dat; - MIX(mix_dat & mix_mask, dest_dat, src_dat); - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & mix_mask, dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if (dev->accel.ssv_draw) { - if ((dev->accel.cmd & 0x04) && dev->accel.ssv_len) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + if (dev->accel.ssv_draw) { + if ((dev->accel.cmd & 0x04) && dev->accel.ssv_len) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } } } } @@ -1397,12 +1414,8 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat case 1: /*Draw line*/ if (!cpu_input) { - dev->accel.init_cx = 0; - dev->accel.input3 = 0; dev->accel.output = 0; - dev->accel.output3 = 0; dev->accel.x_count = 0; - dev->accel.xx_count = 0; dev->accel.cx = dev->accel.cur_x; if (dev->accel.cur_x >= 0x600) @@ -1414,19 +1427,41 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->accel.sy = dev->accel.maj_axis_pcnt; - ibm8514_log("CMD=%d, full=%04x, curx=%d, cury=%d, pixcntl=%x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, bkgdmix=%02x, and3=%d, sy=%d.\n", - cmd, dev->accel.cmd, dev->accel.cx, dev->accel.cy, pixcntl, frgd_mix, bkgd_mix, dev->accel.frgd_mix, dev->accel.bkgd_mix, and3, dev->accel.sy); + ibm8514_log("CMD=%d, full=%04x, curx=%d, cury=%d, pixcntl=%x, frgdsel=%d, bkgdsel=%d, frgdmix=%02x, bkgdmix=%02x, and3=%d, sy=%d, polygon=%02x.\n", + cmd, dev->accel.cmd, dev->accel.cx, dev->accel.cy, pixcntl, frgd_mix, bkgd_mix, dev->accel.frgd_mix, dev->accel.bkgd_mix, and3, dev->accel.sy, dev->accel.multifunc[0x0a] & 0x06); ibm8514_log("Line Draw 8514/A CMD=%04x, frgdmix=%d, bkgdmix=%d, c(%d,%d), pixcntl=%d, sy=%d, polyfill=%x, selfrmix=%02x, selbkmix=%02x, bkgdcol=%02x, frgdcol=%02x, clipt=%d, clipb=%d.\n", dev->accel.cmd, frgd_mix, bkgd_mix, dev->accel.cx, dev->accel.cy, pixcntl, dev->accel.sy, dev->accel.multifunc[0x0a] & 6, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, bkgd_color, frgd_color, dev->accel.clip_top, clip_b); if (ibm8514_cpu_src(svga)) { if (dev->accel.cmd & 0x02) { if (!(dev->accel.cmd & 0x1000)) { if (dev->accel.cmd & 0x08) { - if (dev->accel.cmd == 0x211b) { - dev->accel.x_count = dev->accel.cx - (and3 + 3); - dev->accel.sy += (and3 + 3); - } else + if (and3) { + dev->accel.sy += and3; dev->accel.output = 1; + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.cx -= and3; + break; + case 0x20: + dev->accel.cx -= and3; + break; + case 0x60: + dev->accel.cx += and3; + break; + case 0x80: + dev->accel.cx += and3; + break; + case 0xa0: + dev->accel.cx += and3; + break; + case 0xe0: + dev->accel.cx -= and3; + break; + + default: + break; + } + } } } } @@ -1436,15 +1471,6 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat dev->data_available2 = 0; return; /*Wait for data from CPU*/ } else if (ibm8514_cpu_dest(svga)) { - if (dev->accel.cmd & 0x02) { - if (!(dev->accel.cmd & 0x1000)) { - if (dev->accel.cmd & 0x08) { - if ((frgd_mix == 3) && (bkgd_mix == 3) && (pixcntl == 0) && - ((dev->accel.multifunc[0x0a] & 0x06) == 0x04) && (dev->accel.frgd_mix != 0x07)) /*Kinda of a workaround for fill brushes on 8514/A using Windows 2.x*/ - dev->accel.input3 = 1; - } - } - } dev->force_busy = 1; dev->force_busy2 = 1; dev->data_available = 1; @@ -1454,239 +1480,253 @@ ibm8514_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat } if (dev->accel.cmd & 0x08) { /*Vector Line*/ - if (ibm8514_cpu_dest(svga) && cpu_input && (dev->accel.cmd & 0x02)) - count >>= 1; + if (ibm8514_cpu_dest(svga)) { + if (dev->accel.cmd & 0x02) + count >>= 1; - if (dev->accel.cmd == 0x211b) { - if (and3 >= 2) { - if (dev->accel.sy < (count << 1)) - count <<= 1; - } - } - if (dev->accel.cmd & 0x1000) - ibm8514_log("Vector Line %d: full=%04x, odd=%d, c(%d,%d), frgdmix=%d, bkgdmix=%d, xcount=%d, and3=%d, len(%d,%d), CURX=%d, Width=%d, pixcntl=%d, mix_dat=%08x, count=%d, cpu_data=%08x, cpu_input=%d.\n", cmd, dev->accel.cmd, dev->accel.input, dev->accel.cx, dev->accel.cy, frgd_mix, bkgd_mix, dev->accel.x_count, and3, dev->accel.sx, dev->accel.sy, dev->accel.cur_x, dev->accel.maj_axis_pcnt, pixcntl, mix_dat, count, cpu_dat, cpu_input); + if ((dev->accel.multifunc[0x0a] & 0x06) == 0x04) { + ibm8514_log("Destination Vector Line CNT=%d.\n", count); + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= clip_l) && + (dev->accel.cx <= clip_r) && + (dev->accel.cy >= clip_t) && + (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= INT_GE_BSY; + } else + ibm8514_log("Scissor out of bounds.\n"); - while (count-- && (dev->accel.sy >= 0)) { - ibm8514_log("CurrentX=%d, CurrentY=%d, Count=%d.\n", dev->accel.cx, dev->accel.cy, count); - if ((dev->accel.cx >= clip_l) && - (dev->accel.cx <= clip_r) && - (dev->accel.cy >= clip_t) && - (dev->accel.cy <= clip_b)) { - dev->subsys_stat |= INT_GE_BSY; - if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { - mix_dat = mix_mask; /* Mix data = forced to foreground register. */ - } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { - /* Mix data = current video memory value. */ - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, mix_dat); - mix_dat = ((mix_dat & rd_mask) == rd_mask); - mix_dat = mix_dat ? mix_mask : 0; + if (!dev->accel.sy) { + dev->force_busy = 0; + dev->force_busy2 = 0; + dev->fifo_idx = 0; + dev->accel.cmd_back = 1; + break; + } + + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.cx++; + break; + case 0x20: + dev->accel.cx++; + dev->accel.cy--; + break; + case 0x40: + dev->accel.cy--; + break; + case 0x60: + dev->accel.cx--; + dev->accel.cy--; + break; + case 0x80: + dev->accel.cx--; + break; + case 0xa0: + dev->accel.cx--; + dev->accel.cy++; + break; + case 0xc0: + dev->accel.cy++; + break; + case 0xe0: + dev->accel.cx++; + dev->accel.cy++; + break; + + default: + break; + } + + dev->accel.sy--; } + } else { + while (count-- && (dev->accel.sy >= 0)) { + if ((dev->accel.cx >= clip_l) && + (dev->accel.cx <= clip_r) && + (dev->accel.cy >= clip_t) && + (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= INT_GE_BSY; + } - if (ibm8514_cpu_dest(svga)) { - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, src_dat); - if (pixcntl == 3) - src_dat = ((src_dat & rd_mask) == rd_mask); - } else { - if (dev->accel.cmd == 0x211b) { - if (dev->accel.x_count != dev->accel.cx) { - dev->accel.output3 = 1; + if (!dev->accel.sy) { + dev->force_busy = 0; + dev->force_busy2 = 0; + dev->fifo_idx = 0; + dev->accel.cmd_back = 1; + break; + } + + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.cx++; + break; + case 0x20: + dev->accel.cx++; + dev->accel.cy--; + break; + case 0x40: + dev->accel.cy--; + break; + case 0x60: + dev->accel.cx--; + dev->accel.cy--; + break; + case 0x80: + dev->accel.cx--; + break; + case 0xa0: + dev->accel.cx--; + dev->accel.cy++; + break; + case 0xc0: + dev->accel.cy++; + break; + case 0xe0: + dev->accel.cx++; + dev->accel.cy++; + break; + + default: + break; + } + + dev->accel.sy--; + } + } + } else { + if (ibm8514_cpu_src(svga)) { + if ((dev->accel.cmd & 0x02) && (pixcntl != 2)) + count >>= 1; + } + + while (count-- && (dev->accel.sy >= 0)) { + ibm8514_log("CurrentX=%d, CurrentY=%d, Count=%d.\n", dev->accel.cx, dev->accel.cy, count); + if ((dev->accel.cx >= clip_l) && + (dev->accel.cx <= clip_r) && + (dev->accel.cy >= clip_t) && + (dev->accel.cy <= clip_b)) { + dev->subsys_stat |= INT_GE_BSY; + switch ((mix_dat & ((dev->accel.cmd & 0x02) ? 0x01 : mix_mask)) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; + + default: + break; + } + + READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & ((dev->accel.cmd & 0x02) ? 0x01 : mix_mask), dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); + if ((dev->accel.cmd & 0x02) && ibm8514_cpu_src(svga)) { + if (!(dev->accel.cmd & 0x1000)) { + if (dev->accel.x_count >= and3) { + if ((dev->accel.cmd & 0x04) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } + } + } else { + if ((dev->accel.cmd & 0x04) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } + } } else { - dev->accel.output3 = 0; - } - - if (dev->accel.output3 == 1) - goto skip_vector_line_write; - } - - if (dev->accel.output) { - switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - src_dat = 0; - break; - - default: - break; - } - } else { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - src_dat = 0; - break; - - default: - break; - } - } - } - - READ((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - - if ((compare_mode == 0) || - ((compare_mode == 0x10) && (dest_dat >= compare)) || - ((compare_mode == 0x18) && (dest_dat < compare)) || - ((compare_mode == 0x20) && (dest_dat != compare)) || - ((compare_mode == 0x28) && (dest_dat == compare)) || - ((compare_mode == 0x30) && (dest_dat <= compare)) || - ((compare_mode == 0x38) && (dest_dat > compare))) { - old_dest_dat = dest_dat; - if (dev->accel.output) { - MIX(mix_dat & 0x01, dest_dat, src_dat); - } else { - MIX(mix_dat & mix_mask, dest_dat, src_dat); - } - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if ((dev->accel.cmd & 0x02) && ibm8514_cpu_src(svga)) { - if ((dev->accel.cmd & 0x04) && dev->accel.sy) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } - } else { - if (ibm8514_cpu_src(svga) || !cpu_input) { - if ((dev->accel.cmd & 0x04) && dev->accel.sy) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); - } - } else if (dev->accel.input3) { - if ((dev->accel.cmd & 0x04) && dev->accel.sy) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat ? dest_dat : 0xff); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat ? dest_dat : 0xff); + if (ibm8514_cpu_src(svga) || !cpu_input) { + if ((dev->accel.cmd & 0x04) && dev->accel.sy) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE((dev->accel.cy * dev->pitch) + dev->accel.cx, dest_dat); + } } } } } - } - if (!dev->accel.sy) { - if (cpu_input) { - dev->force_busy = 0; - dev->force_busy2 = 0; + if (!dev->accel.sy) { + if (cpu_input) { + dev->force_busy = 0; + dev->force_busy2 = 0; + } + dev->fifo_idx = 0; + dev->accel.cmd_back = 1; + if (!cpu_input) { + dev->accel.cur_x = dev->accel.cx; + dev->accel.cur_y = dev->accel.cy; + } + break; } - dev->fifo_idx = 0; - dev->accel.cmd_back = 1; - if (!cpu_input) { - dev->accel.cur_x = dev->accel.cx; - dev->accel.cur_y = dev->accel.cy; + + if (dev->bpp) + cpu_dat >>= 16; + else + cpu_dat >>= 8; + + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.cx++; + break; + case 0x20: + dev->accel.cx++; + dev->accel.cy--; + break; + case 0x40: + dev->accel.cy--; + break; + case 0x60: + dev->accel.cx--; + dev->accel.cy--; + break; + case 0x80: + dev->accel.cx--; + break; + case 0xa0: + dev->accel.cx--; + dev->accel.cy++; + break; + case 0xc0: + dev->accel.cy++; + break; + case 0xe0: + dev->accel.cx++; + dev->accel.cy++; + break; + + default: + break; } - break; + + if (dev->accel.cmd & 0x02) + mix_dat >>= 1; + else { + mix_dat <<= 1; + mix_dat |= 1; + } + dev->accel.sy--; + dev->accel.x_count++; } - - if (dev->bpp) - cpu_dat >>= 16; - else - cpu_dat >>= 8; - - switch (dev->accel.cmd & 0xe0) { - case 0x00: - dev->accel.cx++; - break; - case 0x20: - dev->accel.cx++; - if (!dev->accel.output3) - dev->accel.cy--; - break; - case 0x40: - if (!dev->accel.output3) - dev->accel.cy--; - break; - case 0x60: - dev->accel.cx--; - if (!dev->accel.output3) - dev->accel.cy--; - break; - case 0x80: - dev->accel.cx--; - break; - case 0xa0: - dev->accel.cx--; - if (!dev->accel.output3) - dev->accel.cy++; - break; - case 0xc0: - if (!dev->accel.output3) - dev->accel.cy++; - break; - case 0xe0: - dev->accel.cx++; - if (!dev->accel.output3) - dev->accel.cy++; - break; - - default: - break; - } - -skip_vector_line_write: - switch (dev->accel.cmd & 0xe0) { - case 0x00: - dev->accel.x_count++; - break; - case 0x20: - dev->accel.x_count++; - if (dev->accel.output3) - dev->accel.cy--; - break; - case 0x40: - if (dev->accel.output3) - dev->accel.cy--; - break; - case 0x60: - dev->accel.x_count--; - if (dev->accel.output3) - dev->accel.cy--; - break; - case 0x80: - dev->accel.x_count--; - break; - case 0xa0: - dev->accel.x_count--; - if (dev->accel.output3) - dev->accel.cy++; - break; - case 0xc0: - if (dev->accel.output3) - dev->accel.cy++; - break; - case 0xe0: - dev->accel.x_count++; - if (dev->accel.output3) - dev->accel.cy++; - break; - - default: - break; - } - - if (dev->accel.output) - mix_dat >>= 1; - else { - mix_dat <<= 1; - mix_dat |= 1; - } - - dev->accel.sy--; } - dev->accel.output = 0; } else { /*Bresenham Line*/ if (pixcntl == 1) { dev->accel.temp_cnt = 8; @@ -1912,9 +1952,9 @@ skip_vector_line_write: if (!cpu_input) { dev->accel.x_count = 0; dev->accel.output = 0; + dev->accel.output2 = 0; dev->accel.input = 0; dev->accel.input2 = 0; - dev->accel.input3 = 0; dev->accel.odd_in = 0; dev->accel.cx = dev->accel.cur_x; @@ -1941,19 +1981,43 @@ skip_vector_line_write: if (ibm8514_cpu_src(svga)) { if (dev->accel.cmd & 0x02) { if (!(dev->accel.cmd & 0x1000)) { - if (dev->accel.cmd & 0x08) { - dev->accel.x_count = dev->accel.cx - (and3 + 3); - dev->accel.sx += (and3 + 3); - } else { - dev->accel.x_count = dev->accel.cx; + if (!(dev->accel.cmd & 0x08)) { if (and3) { if (dev->accel.cmd & 0x20) - dev->accel.x_count -= and3; + dev->accel.cx -= and3; else - dev->accel.x_count += and3; + dev->accel.cx += and3; dev->accel.sx += 8; } + } else { + if (and3) { + dev->accel.sx += and3; + dev->accel.output2 = 1; + switch (dev->accel.cmd & 0xe0) { + case 0x00: + dev->accel.cx -= and3; + break; + case 0x20: + dev->accel.cx -= and3; + break; + case 0x60: + dev->accel.cx += and3; + break; + case 0x80: + dev->accel.cx += and3; + break; + case 0xa0: + dev->accel.cx += and3; + break; + case 0xe0: + dev->accel.cx -= and3; + break; + + default: + break; + } + } } } } else { @@ -1982,10 +2046,6 @@ skip_vector_line_write: dev->accel.sx -= 2; } } - } else { - if ((dev->accel.cmd == 0x41f0) && (frgd_mix == 3) && (bkgd_mix == 3) && - (pixcntl == 0)) - dev->accel.input3 = 1; } } ibm8514_log("INPUT1=%d, INPUT2=%d.\n", dev->accel.input, dev->accel.input2); @@ -2008,7 +2068,8 @@ skip_vector_line_write: (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { + ibm8514_log("RectRadial: MIXDATA=%08x, mask=%04x, frgdcol=%02x, bkgdcol=%02x, cpudat=%08x.\n", mix_dat, mix_mask, frgd_color, bkgd_color, cpu_dat); + switch ((mix_dat & ((dev->accel.cmd & 0x02) ? 0x01 : mix_mask)) ? frgd_mix : bkgd_mix) { case 0: src_dat = bkgd_color; break; @@ -2036,15 +2097,15 @@ skip_vector_line_write: ((compare_mode == 0x30) && (dest_dat <= compare)) || ((compare_mode == 0x38) && (dest_dat > compare))) { old_dest_dat = dest_dat; - MIX(mix_dat & mix_mask, dest_dat, src_dat); + MIX(mix_dat & ((dev->accel.cmd & 0x02) ? 0x01 : mix_mask), dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if ((dev->accel.cmd & 0x02) && (dev->accel.x_count != dev->accel.cx)) - goto skip_vector_rect_write; - - if ((dev->accel.cmd & 0x04) && dev->accel.sx) { - WRITE(dev->accel.dest + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + if (dev->accel.x_count >= and3) { + if ((dev->accel.cmd & 0x04) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + ibm8514_log("RectFill Radial CX=%d, CY=%d, dstdat=%02x, olddst=%02x, srcdat=%02x.\n", dev->accel.cx, dev->accel.cy, dest_dat, old_dest_dat, src_dat); + } } } } @@ -2073,42 +2134,24 @@ skip_vector_line_write: break; } -skip_vector_rect_write: - switch (dev->accel.cmd & 0xe0) { - case 0x00: - dev->accel.x_count++; - break; - case 0x20: - dev->accel.x_count++; - break; - case 0x60: - dev->accel.x_count--; - break; - case 0x80: - dev->accel.x_count--; - break; - case 0xa0: - dev->accel.x_count--; - break; - case 0xe0: - dev->accel.x_count++; - break; - - default: - break; - } - if (dev->bpp) cpu_dat >>= 16; else cpu_dat >>= 8; - mix_dat <<= 1; - mix_dat |= 1; - + if (dev->accel.cmd & 0x02) + mix_dat >>= 1; + else { + mix_dat <<= 1; + mix_dat |= 1; + } dev->accel.sx--; + dev->accel.x_count++; if (dev->accel.sx < 0) { dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.x_count = 0; + if (dev->accel.output2) + dev->accel.sx += and3; if (dev->accel.cmd & 0x20) dev->accel.cx -= (dev->accel.sx + 1); @@ -2142,7 +2185,6 @@ skip_vector_rect_write: dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; - dev->accel.x_count = 0; if (dev->accel.sy < 0) { dev->force_busy = 0; @@ -2166,93 +2208,59 @@ skip_vector_rect_write: (dev->accel.cy >= clip_t) && (dev->accel.cy <= clip_b)) { dev->subsys_stat |= INT_GE_BSY; - if (ibm8514_cpu_dest(svga) && (pixcntl == 0)) { - mix_dat = mix_mask; /* Mix data = forced to foreground register. */ - } else if (ibm8514_cpu_dest(svga) && (pixcntl == 3)) { - /* Mix data = current video memory value. */ - READ(dev->accel.dest + dev->accel.cx, mix_dat); - mix_dat = ((mix_dat & rd_mask) == rd_mask); - mix_dat = mix_dat ? mix_mask : 0; - } + if (ibm8514_cpu_src(svga) || !cpu_input) { + switch ((mix_dat & ((dev->accel.cmd & 0x02) ? 0x01 : mix_mask)) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + src_dat = 0; + break; - if (ibm8514_cpu_dest(svga)) { - READ(dev->accel.dest + dev->accel.cx, src_dat); - if (pixcntl == 3) - src_dat = ((src_dat & rd_mask) == rd_mask); - } else { - if (dev->accel.cmd & 0x02) { - switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - src_dat = 0; - break; - - default: - break; - } - } else { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - src_dat = 0; - break; - - default: - break; - } + default: + break; } - } - READ(dev->accel.dest + dev->accel.cx, dest_dat); - - if ((compare_mode == 0) || - ((compare_mode == 0x10) && (dest_dat >= compare)) || - ((compare_mode == 0x18) && (dest_dat < compare)) || - ((compare_mode == 0x20) && (dest_dat != compare)) || - ((compare_mode == 0x28) && (dest_dat == compare)) || - ((compare_mode == 0x30) && (dest_dat <= compare)) || - ((compare_mode == 0x38) && (dest_dat > compare))) { - old_dest_dat = dest_dat; - if (dev->accel.cmd & 0x02) { - MIX(mix_dat & 0x01, dest_dat, src_dat); - if ((dev->accel.x_count != dev->accel.cx) && !(dev->accel.cmd & 0x1000) && and3) - goto skip_nibble_rect_write; + READ(dev->accel.dest + dev->accel.cx, dest_dat); + if ((compare_mode == 0) || + ((compare_mode == 0x10) && (dest_dat >= compare)) || + ((compare_mode == 0x18) && (dest_dat < compare)) || + ((compare_mode == 0x20) && (dest_dat != compare)) || + ((compare_mode == 0x28) && (dest_dat == compare)) || + ((compare_mode == 0x30) && (dest_dat <= compare)) || + ((compare_mode == 0x38) && (dest_dat > compare))) { + old_dest_dat = dest_dat; + MIX(mix_dat & ((dev->accel.cmd & 0x02) ? 0x01 : mix_mask), dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if ((dev->accel.cmd & 0x04) && dev->accel.sx) { - WRITE(dev->accel.dest + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE(dev->accel.dest + dev->accel.cx, dest_dat); - } - } else { - if (ibm8514_cpu_dest(svga) && (cmd == 2)) { - if (pixcntl == 3) { - MIX(mix_dat & mix_mask, dest_dat, src_dat); + if (dev->accel.cmd & 0x02) { + if (dev->accel.cmd & 0x1000) { + if ((dev->accel.cmd & 0x04) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } else { + if (dev->accel.x_count >= and3) { + if ((dev->accel.cmd & 0x04) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } + } } } else { - MIX(mix_dat & mix_mask, dest_dat, src_dat); - } - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - if ((dev->accel.cmd & 0x04) && dev->accel.sx) { - WRITE(dev->accel.dest + dev->accel.cx, dest_dat); - } else if (!(dev->accel.cmd & 0x04)) { - WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + if ((dev->accel.cmd & 0x04) && dev->accel.sx) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } else if (!(dev->accel.cmd & 0x04)) { + WRITE(dev->accel.dest + dev->accel.cx, dest_dat); + } } } } @@ -2262,12 +2270,6 @@ skip_vector_rect_write: else dev->accel.cx--; -skip_nibble_rect_write: - if (dev->accel.cmd & 0x20) - dev->accel.x_count++; - else - dev->accel.x_count--; - if (dev->accel.cmd & 0x02) mix_dat >>= 1; else { @@ -2281,10 +2283,13 @@ skip_nibble_rect_write: cpu_dat >>= 8; dev->accel.sx--; + dev->accel.x_count++; if (dev->accel.sx < 0) { dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; + dev->accel.x_count = 0; if (dev->accel.input) dev->accel.odd_in = 1; + if (dev->accel.output || dev->accel.input2) dev->accel.sx -= 2; @@ -2301,7 +2306,6 @@ skip_nibble_rect_write: dev->accel.dest = dev->accel.ge_offset + (dev->accel.cy * dev->pitch); dev->accel.sy--; - dev->accel.x_count = 0; if (dev->accel.sy < 0) { dev->fifo_idx = 0; @@ -2957,12 +2961,11 @@ skip_nibble_rect_write: if (ibm8514_cpu_src(svga)) { if (dev->accel.cmd & 0x02) { if (!(dev->accel.cmd & 0x1000)) { - dev->accel.x_count = dev->accel.cx; - if (and3) { + if (and3_blt) { if (dev->accel.cmd & 0x20) - dev->accel.x_count -= and3; + dev->accel.dx -= and3_blt; else - dev->accel.x_count += and3; + dev->accel.dx += and3_blt; dev->accel.sx += 8; } @@ -3006,50 +3009,27 @@ skip_nibble_rect_write: mix_dat = mix_dat ? mix_mask : 0x00; } } - if (dev->accel.cmd & 0x02) { - switch ((mix_dat & 0x01) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - READ(dev->accel.src + dev->accel.cx, src_dat); - if (pixcntl == 3) { - if (dev->accel.cmd & 0x10) - src_dat = ((src_dat & rd_mask) == rd_mask); - } - break; - default: - break; - } - } else { - switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) { - case 0: - src_dat = bkgd_color; - break; - case 1: - src_dat = frgd_color; - break; - case 2: - src_dat = cpu_dat; - break; - case 3: - READ(dev->accel.src + dev->accel.cx, src_dat); - if (pixcntl == 3) { - if (dev->accel.cmd & 0x10) - src_dat = ((src_dat & rd_mask) == rd_mask); - } - break; + switch (((mix_dat & (dev->accel.cmd & 0x02) ? 0x01 : mix_mask)) ? frgd_mix : bkgd_mix) { + case 0: + src_dat = bkgd_color; + break; + case 1: + src_dat = frgd_color; + break; + case 2: + src_dat = cpu_dat; + break; + case 3: + READ(dev->accel.src + dev->accel.cx, src_dat); + if (pixcntl == 3) { + if (dev->accel.cmd & 0x10) + src_dat = ((src_dat & rd_mask) == rd_mask); + } + break; - default: - break; - } + default: + break; } READ(dev->accel.dest + dev->accel.dx, dest_dat); @@ -3062,16 +3042,17 @@ skip_nibble_rect_write: ((compare_mode == 0x30) && (dest_dat <= compare)) || ((compare_mode == 0x38) && (dest_dat > compare))) { old_dest_dat = dest_dat; + MIX(mix_dat & ((dev->accel.cmd & 0x02) ? 0x01 : mix_mask), dest_dat, src_dat); + dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); if (dev->accel.cmd & 0x02) { - MIX(mix_dat & 0x01, dest_dat, src_dat); - if ((dev->accel.x_count != dev->accel.cx) && !(dev->accel.cmd & 0x1000) && and3) - goto skip_nibble_bitblt_write; - - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); - WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + if (dev->accel.cmd & 0x1000) { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } else { + if (dev->accel.x_count >= and3_blt) { + WRITE(dev->accel.dest + dev->accel.dx, dest_dat); + } + } } else { - MIX(mix_dat & mix_mask, dest_dat, src_dat); - dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); WRITE(dev->accel.dest + dev->accel.dx, dest_dat); } } @@ -3085,12 +3066,6 @@ skip_nibble_rect_write: dev->accel.cx--; } -skip_nibble_bitblt_write: - if (dev->accel.cmd & 0x20) - dev->accel.x_count++; - else - dev->accel.x_count--; - if (dev->accel.cmd & 0x02) mix_dat >>= 1; else { @@ -3104,7 +3079,9 @@ skip_nibble_bitblt_write: cpu_dat >>= 8; dev->accel.sx--; + dev->accel.x_count++; if (dev->accel.sx < 0) { + dev->accel.x_count = 0; dev->accel.sx = dev->accel.maj_axis_pcnt & 0x7ff; if (dev->accel.cmd & 0x20) { @@ -3127,7 +3104,6 @@ skip_nibble_bitblt_write: dev->accel.dest = dev->accel.ge_offset + (dev->accel.dy * dev->pitch); dev->accel.sy--; - dev->accel.x_count = 0; if (dev->accel.sy < 0) { dev->accel.cmd_back = 1; @@ -3358,7 +3334,10 @@ skip_nibble_bitblt_write: } } } else { - while (count-- && dev->accel.sy >= 0) { + if ((dev->accel.cmd == 0xc073) && (dev->accel.frgd_mix == 0x05) && (frgd_mix == 3)) + ibm8514_log("BitBLT PBRUSH: DX=%d, DY=%d, cl=%d, cr=%d, ct=%d, cb=%d.\n", dev->accel.dx, dev->accel.dy, clip_l, clip_r, clip_t, clip_b); + + while (count-- && (dev->accel.sy >= 0)) { if ((dev->accel.dx >= clip_l) && (dev->accel.dx <= clip_r) && (dev->accel.dy >= clip_t) && @@ -3409,7 +3388,8 @@ skip_nibble_bitblt_write: MIX(mix_dat & mix_mask, dest_dat, src_dat); dest_dat = (dest_dat & wrt_mask) | (old_dest_dat & ~wrt_mask); WRITE(dev->accel.dest + dev->accel.dx, dest_dat); - ibm8514_log("BitBLT DX=%d, DY=%d, data=%02x, old=%02x, src=%02x, frmix=%02x, bkmix=%02x, pixcntl=%d.\n", dev->accel.dx, dev->accel.dy, dest_dat, old_dest_dat, src_dat, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, pixcntl); + if ((dev->accel.cmd == 0xc073) && (dev->accel.frgd_mix == 0x05) && (frgd_mix == 3)) + ibm8514_log("BitBLT CX=%d, CY=%d, DX=%d, DY=%d, data=%02x, old=%02x, src=%02x, frmix=%02x, bkmix=%02x, pixcntl=%d.\n", dev->accel.cx, dev->accel.cy, dev->accel.dx, dev->accel.dy, dest_dat, old_dest_dat, src_dat, dev->accel.frgd_mix & 0x1f, dev->accel.bkgd_mix & 0x1f, pixcntl); } } diff --git a/src/video/vid_cga_compaq_plasma.c b/src/video/vid_cga_compaq_plasma.c index b894daa9f..9eea61e0f 100644 --- a/src/video/vid_cga_compaq_plasma.c +++ b/src/video/vid_cga_compaq_plasma.c @@ -106,7 +106,11 @@ compaq_plasma_waitstates(UNUSED(void *priv)) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + + if (is_nec) + sub_cycles_vx0(ws); + else + sub_cycles(ws); } static void diff --git a/src/video/vid_cga_ncr.c b/src/video/vid_cga_ncr.c index cda38036b..dabbd85bf 100644 --- a/src/video/vid_cga_ncr.c +++ b/src/video/vid_cga_ncr.c @@ -91,7 +91,11 @@ nga_waitstates(UNUSED(void *priv)) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + + if (is_nec) + sub_cycles_vx0(ws); + else + sub_cycles(ws); } void diff --git a/src/video/vid_cga_olivetti.c b/src/video/vid_cga_olivetti.c index 0279621a1..ae539d084 100644 --- a/src/video/vid_cga_olivetti.c +++ b/src/video/vid_cga_olivetti.c @@ -157,7 +157,11 @@ ogc_waitstates(UNUSED(void *priv)) int ws; ws = ws_array[cycles & 0xf]; - sub_cycles(ws); + + if (is_nec) + sub_cycles_vx0(ws); + else + sub_cycles(ws); } void diff --git a/vcpkg.json b/vcpkg.json index 4c0d502ef..6a4f6376c 100644 --- a/vcpkg.json +++ b/vcpkg.json @@ -1,6 +1,6 @@ { "name": "86box", - "version-string": "5.4", + "version-string": "6.0", "homepage": "https://86box.net/", "documentation": "https://86box.readthedocs.io/", "license": "GPL-2.0-or-later",