From e9c41fe7d4c84489a4088f4df29900495cb58b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Wed, 28 Jan 2026 20:34:51 +0100 Subject: [PATCH 01/26] Update CONTRIBUTING.md --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4f4f32b2e2c..de6541e36d1 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 From 3bcf6a75e5915fc4f21381e8b58c2dcfc19d8858 Mon Sep 17 00:00:00 2001 From: fleur!3 <149212571+cyrix6x86mx@users.noreply.github.com> Date: Wed, 28 Jan 2026 20:44:13 +0000 Subject: [PATCH 02/26] Update Pentium CPU table names for Socket 4 and 5/7 --- src/cpu/cpu_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index cb337b405e4..5d68b56cd85 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 (Socket 4)", .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 (Socket 5/7)", .internal_name = "pentium_p54c", .cpus = (const CPU[]) { { From bd13b21cd1cbf8f774ac49b3d9c896e36d275560 Mon Sep 17 00:00:00 2001 From: fleur!3 <149212571+cyrix6x86mx@users.noreply.github.com> Date: Wed, 28 Jan 2026 20:54:34 +0000 Subject: [PATCH 03/26] Update the CPU names to be P5 and P54C instead of Socket 4 and 5/7 --- src/cpu/cpu_table.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cpu/cpu_table.c b/src/cpu/cpu_table.c index 5d68b56cd85..91808299a48 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 (Socket 4)", + .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 (Socket 5/7)", + .name = "Pentium (P54C)", .internal_name = "pentium_p54c", .cpus = (const CPU[]) { { From 0055917012c79a0c880eae8ad77993e9206f8fd2 Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 29 Jan 2026 18:48:41 +0100 Subject: [PATCH 04/26] DEC Tulip 21040: Do not attempt to read the EEPROM data on reset, fixes #6768. --- src/network/net_tulip.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/network/net_tulip.c b/src/network/net_tulip.c index b5219cf2375..2b250390475 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]; } From 484a61f65a69f964309a3c63741196165c7ac96a Mon Sep 17 00:00:00 2001 From: OBattler Date: Thu, 29 Jan 2026 19:47:26 +0100 Subject: [PATCH 05/26] Only use checkStateChanged from Qt 6.7 onwards, should fix GitHub Actions builds. --- src/qt/qt_defs.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/qt_defs.hpp b/src/qt/qt_defs.hpp index 1190c0ed180..58de88b67a7 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 From d1d39415422c9fc85cf9174810c77768602987d8 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 30 Jan 2026 04:03:20 +0100 Subject: [PATCH 06/26] NEC Vx0: Swap the two operands in CMPSB/CMPSW, fixes #6764. Also do some refactoring to make thinking back to old 808x instructions easier for debugging purposes. --- src/cpu/808x.c | 3093 ++++++++++++++++++++++----------------------- src/cpu/vx0.c | 133 +- src/cpu/vx0_biu.h | 19 +- 3 files changed, 1604 insertions(+), 1641 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index 7908160e80d..a1d29e56adb 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; @@ -54,6 +55,23 @@ static uint8_t pfq[6]; 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; + +uint32_t cpu_src = 0; +uint32_t cpu_dest = 0; + +uint32_t cpu_data = 0; + +uint32_t * ovr_seg = NULL; + /* The IP equivalent of the current prefetch queue position. */ static uint16_t pfq_ip; @@ -61,18 +79,11 @@ static uint16_t pfq_ip; static uint32_t *opseg[4]; static x86seg *_opseg[4]; -static int noint = 0; -static int cpu_alu_op, pfq_size; - -static uint32_t cpu_src = 0, cpu_dest = 0; -static uint32_t cpu_data = 0; +static int pfq_size; 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; @@ -136,8 +147,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); @@ -246,8 +255,12 @@ fetch_and_bus(int c, int bus) static void wait_cycs(int c, int bus) { - cycles -= c; - fetch_and_bus(c, bus); + if (is_nec) + wait_vx0(c); + else { + cycles -= c; + fetch_and_bus(c, bus); + } } /* This is for external subtraction of cycles. */ @@ -283,55 +296,63 @@ resub_cycles(int old_cycles) static void cpu_io(int bits, int out, uint16_t port) { - 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 (is_nec) + 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); + } 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_nec) + 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. */ @@ -350,18 +371,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_nec) + return readmemw_vx0(s, a); else { + uint16_t ret; + wait_cycs(4, 1); - ret = read_mem_b(s + a); - ret |= read_mem_b(s + (is186 ? (a + 1) : (a + 1) & 0xffff)) << 8; - } + 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 ? (a + 1) : (a + 1) & 0xffff)) << 8; + } - return ret; + return ret; + } } static uint16_t @@ -377,88 +402,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_nec) + 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_nec) + 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_nec) + 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_nec) + 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_nec) + writememw_vx0(s, a, v); else { - write_mem_b(addr, v & 0xff); + uint32_t addr = s + a; + wait_cycs(4, 1); - addr = s + (is186 ? (a + 1) : ((a + 1) & 0xffff)); - write_mem_b(addr, v >> 8); - } + if (is8086 && !(a & 1)) + write_mem_w(addr, v); + else { + write_mem_b(addr, v & 0xff); + wait_cycs(4, 1); + addr = s + (is186 ? (a + 1) : ((a + 1) & 0xffff)); + write_mem_b(addr, v >> 8); + } - if ((addr >= 0xf0000) && (addr <= 0xfffff)) - last_addr = addr & 0xffff; + 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_nec) + 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_nec) + 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_nec) + writememl_vx0(s, a, v); + else { + writememl(s, a, v & 0xffffffff); + writememl(s, a + 4, v >> 32); + } } static void @@ -485,13 +542,17 @@ pfq_write(void) static uint8_t pfq_read(void) { - uint8_t temp = pfq[0]; + if (is_nec) + 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 @@ -499,28 +560,36 @@ pfq_read(void) static uint8_t pfq_fetchb_common(void) { - uint8_t temp; + if (is_nec) + 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_nec) + 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 @@ -528,22 +597,30 @@ pfq_fetchb(void) static uint16_t pfq_fetchw(void) { - uint16_t temp; + if (is_nec) + 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_nec) + 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. */ @@ -562,12 +639,26 @@ pfq_add(int c, int add) } } +static void +pfq_clear_pos(void) +{ + if (is_nec) + 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_nec) { + biu_suspend_fetch(); + biu_queue_flush(); + } else { + pfq_pos = 0; + prefetching = 0; + } } static void @@ -586,12 +677,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) @@ -659,8 +750,13 @@ reset_808x(int hard) static void set_ip(uint16_t new_ip) { - pfq_ip = cpu_state.pc = new_ip; - prefetching = 1; + if (is_nec) { + cpu_state.pc = new_ip; + biu_queue_flush(); + } else { + pfq_ip = cpu_state.pc = new_ip; + prefetching = 1; + } } /* Memory refresh read - called by reads and writes on DMA channel 0. */ @@ -754,7 +850,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. */ @@ -798,7 +894,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) { @@ -816,7 +912,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. */ @@ -1180,10 +1276,15 @@ jump(uint16_t delta) { uint16_t old_ip; access(67, 8); - pfq_clear(); + if (is_nec) + biu_suspend_fetch(); + else + pfq_clear(); wait_cycs(5, 0); old_ip = cpu_state.pc; set_ip((cpu_state.pc + delta) & 0xffff); + if (is_nec) + biu_queue_flush(); return old_ip; } @@ -1621,7 +1722,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); } @@ -1776,9 +1877,8 @@ cpu_outw(uint16_t port, uint16_t val) resub_cycles(old_cycles); } -/* Executes instructions up to the specified number of cycles. */ void -execx86(int cycs) +execx86_instruction(void) { uint8_t temp = 0, temp2, old_af, nests; uint16_t addr, tempw, new_cs, new_ip, handled = 0; @@ -1787,1569 +1887,1396 @@ execx86(int cycs) int bits; uint32_t dest_seg; - cycles += cycs; - - while (cycles > 0) { - 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; - clear_lock = 0; - } - wait_cycs(1, 0); - } + 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; + completed = 1; + // pclog("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); - 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; + 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 0x68: - wordtopush = pfq_fetchw(); - wait_cycs(1, 0); - push(&wordtopush); - 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 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 0x68: + wordtopush = pfq_fetchw(); + wait_cycs(1, 0); + push(&wordtopush); + handled = 1; + break; - case 0x6a: - wordtopush = sign_extend(pfq_fetchb()); - 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 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 0x6a: + wordtopush = sign_extend(pfq_fetchb()); + push(&wordtopush); + 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); + 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; - if (rep_action(bits)) - break; - else if (!repeating) - wait_cycs(7, 0); + case 0x6c ... 0x6d: /* INM dst, DW/INS dst, DX */ + bits = 8 << (opcode & 1); + handled = 1; + if (!repeating) + wait_cycs(2, 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 (rep_action(bits)) + break; + else if (!repeating) + wait_cycs(7, 0); - if (in_rep == 0) - break; + 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; + } - repeating = 1; - clock_end(); + if (in_rep == 0) 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); + repeating = 1; + clock_end(); + break; - if (rep_action(bits)) - break; - else if (!repeating) - wait_cycs(7, 0); + 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 (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; + if (rep_action(bits)) + break; + else if (!repeating) + wait_cycs(7, 0); - repeating = 1; - clock_end(); + 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; - 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); + 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); } - BP = tempw_int; - SP -= size; - handled = 1; - break; + 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(); + 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); + wait_cycs((cpu_mod != 3) ? 9 : 6, 0); - 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; + 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; } - access(17, bits); - set_ea(cpu_data); - handled = 1; - 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; - } + 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 */ - 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; + } + 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 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; + 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) { - cpu_dest = tempw; - cpu_src = get_reg(cpu_reg); + access(10, bits); + set_ea(cpu_data); + if (cpu_mod == 3) + wait_cycs(1, 0); } else { - cpu_dest = get_reg(cpu_reg); - cpu_src = tempw; + set_reg(cpu_reg, cpu_data); + wait_cycs(1, 0); } - if (cpu_mod != 3) - wait_cycs(2, 0); + } else 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; + 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 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; + 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); - 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_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); - 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 */ + 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 = 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(); + } + 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); - break; + } + cpu_dest = AL; + cpu_data = cpu_dest - cpu_src; + set_of_sub(8); + aa(); + 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 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 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 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 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)); + 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(2, 0); + 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); - 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; + 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: - 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()); + 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); - if (cpu_mod != 3) - wait_cycs(2, 0); - break; + access(14, 16); + seteaw(_opseg[(rmdat & 0x18) >> 3]->seg); + 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 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 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 0x8F: /*POPW*/ - do_mod_rm(); + 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); - cpu_src = cpu_state.eaaddr; - access(24, 16); - if (cpu_mod != 3) - wait_cycs(2, 0); - cpu_data = pop(); - cpu_state.eaaddr = cpu_src; + 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); - access(15, 16); - seteaw(cpu_data); - break; + 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(); +#endif + break; + case 0x9c: /* PUSHF */ + access(33, 16); + tempw = (cpu_state.flags & 0x0fd7) | 0xf000; + push(&tempw); + break; + case 0x9d: { /* POPF */ + uint16_t old_flags = cpu_state.flags; + access(25, 16); + 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 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 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 0x98: /*CBW*/ + case 0xa4 ... 0xa5: /* MOVS */ + case 0xac ... 0xad: /* LODS */ + bits = 8 << (opcode & 1); + if (!repeating) { wait_cycs(1, 0); - AX = sign_extend(AL); - break; - case 0x99: /*CWD*/ - wait_cycs(4, 0); - if (!top_bit(AX, 16)) - DX = 0; - else { + if ((opcode & 8) == 0 && in_rep != 0) wait_cycs(1, 0); - DX = 0xffff; - } - break; - case 0x9A: /*CALL FAR*/ - wait_cycs(1, 0); - new_ip = pfq_fetchw(); + } + if (rep_action(bits)) { 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(); -#endif + if ((opcode & 8) != 0) + wait_cycs(1, 0); break; - case 0x9C: /*PUSHF*/ - access(33, 16); - tempw = (cpu_state.flags & 0x0fd7) | 0xf000; - push(&tempw); - break; - case 0x9D: { /*POPF*/ - uint16_t old_flags = cpu_state.flags; - access(25, 16); - cpu_state.flags = pop() | 0x0002; + } + if (in_rep != 0 && (opcode & 8) != 0) wait_cycs(1, 0); - if ((old_flags ^ cpu_state.flags) & T_FLAG) - noint = 1; + 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; - } case 0x9E: /*SAHF*/ + } + repeating = 1; + if (!is_nec) + clock_end(); + break; + + case 0xa6 ... 0xa7: /* CMPS */ + case 0xae ... 0xaf: /* SCAS */ + bits = 8 << (opcode & 1); + if (!repeating) wait_cycs(1, 0); - cpu_state.flags = (cpu_state.flags & 0xff02) | AH; + if (rep_action(bits)) { 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); + } + if (in_rep != 0) 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); + 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; - 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)); + } + if ((!!(cpu_state.flags & (rep_c_flag ? C_FLAG : Z_FLAG))) == (in_rep == 1)) { + completed = 1; + wait_cycs(4, 0); 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; + } + repeating = 1; + if (!is_nec) clock_end(); - break; + 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; - } + 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); - 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); + } + cpu_data = AX; + access(28, bits); + stos(bits); + if (in_rep == 0) { + wait_cycs(3, 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; + } + repeating = 1; + if (!is_nec) clock_end(); - break; + 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 0xB0: - case 0xB1: - case 0xB2: - case 0xB3: /*MOV cpu_reg,#8*/ - case 0xB4: - case 0xB5: - case 0xB6: - case 0xB7: + 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 & 0x04) - cpu_state.regs[opcode & 0x03].b.h = pfq_fetchb(); - else - cpu_state.regs[opcode & 0x03].b.l = pfq_fetchb(); + if (!(opcode & 1)) { + cpu_src = pfq_fetchw(); 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: + } + if ((opcode & 9) == 9) wait_cycs(1, 0); - cpu_state.regs[opcode & 0x07].w = pfq_fetchw(); + 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); - break; + } + load_cs(new_cs); + access(72, bits); + set_ip(new_ip); + 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 ... 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 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); + 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); - break; + access(16, bits); + set_ea(cpu_data); + 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); + cpu_state.flags = pop() | 0x0002; + wait_cycs(5, 0); + noint = 2; + nmi_enable = 1; + break; - case 0xCC: /*INT 3*/ - interrupt(3); - break; - case 0xCD: /*INT*/ + case 0xd0 ... 0xd3: /* rot rm */ + bits = 8 << (opcode & 1); + do_mod_rm(); + if (cpu_mod == 3) 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); + 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) + 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; } - break; + if ((opcode & 2) != 0) + wait_cycs(4, 0); + --cpu_src; + } + access(17, bits); + set_ea(cpu_data); + 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); - cpu_state.flags = pop() | 0x0002; - wait_cycs(5, 0); - noint = 2; - nmi_enable = 1; - 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); + 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 */ + wait_cycs(1, 0); + AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; + wait_cycs(1, 0); + break; + 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 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) - 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 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; - case 0xD4: /*AAM*/ + 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); - cpu_src = pfq_fetchb(); - if (x86_div(AL, 0)) { - cpu_data = AL; - set_pzs(8); + 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; } - break; - case 0xD5: /*AAD*/ - wait_cycs(1, 0); - 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*/ - wait_cycs(1, 0); - AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; - wait_cycs(1, 0); - break; - 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; + } else + oldc = (CX == 0); + if (oldc) + jump_short(); + 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. */ + case 0xe4 ... 0xe7: + case 0xec ... 0xef: + bits = 8 << (opcode & 1); + if ((opcode & 0x0e) != 0x0c) 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); + if ((opcode & 8) == 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); + 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) - cpu_data = pfq_fetchb(); + access(8, bits); 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; + 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 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 ... 0xf1: /*LOCK - F1 is alias*/ + in_lock = 1; + wait_cycs(1, 0); + completed = 0; + break; - case 0xF0: - case 0xF1: /*LOCK - F1 is alias*/ - in_lock = 1; + 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()) { + wait_cycs(cycles & 1, 0); + check_interrupts(); + } else { + repeating = 1; completed = 0; - break; + clock_end(); + } + break; + case 0xf5: /* CMC */ + wait_cycs(1, 0); + cpu_state.flags ^= C_FLAG; + 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 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 */ + 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)); + cpu_data = AH; + } + set_sf(bits); + set_pf(); + if (cpu_mod != 3) + wait_cycs(1, 0); + 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 0xF4: /*HLT*/ - if (!repeating) { + 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); pfq_clear(); - } - wait_cycs(1, 0); - if (irq_pending()) { - wait_cycs(cycles & 1, 0); - check_interrupts(); - } 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(4, 0); + if (cpu_mod != 3) 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 */ + 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: case 0x38: /* PUSH rm */ + if (cpu_mod != 3) 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)); - cpu_data = AH; - } - set_sf(bits); - set_pf(); - if (cpu_mod != 3) - wait_cycs(1, 0); - 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; + access(38, bits); + push((uint16_t *) &(cpu_data)); + 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; + default: + x808x_log("Illegal opcode: %02X\n", opcode); + pfq_fetchb(); + wait_cycs(8, 0); + 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; +/* Executes instructions up to the specified number of cycles. */ +void +execx86(int cycs) +{ + cycles += cycs; - default: - x808x_log("Illegal opcode: %02X\n", opcode); - pfq_fetchb(); - wait_cycs(8, 0); - break; + while (cycles > 0) { + cycdiff = cycles; + + if (!repeating) { + cpu_state.oldpc = cpu_state.pc; + opcode = pfq_fetchb(); + oldc = cpu_state.flags & C_FLAG; + if (clear_lock) { + in_lock = 0; + clear_lock = 0; } + wait_cycs(1, 0); } + execx86_instruction(); + if (completed) { repeating = 0; ovr_seg = NULL; diff --git a/src/cpu/vx0.c b/src/cpu/vx0.c index 42bd7cc4b83..ab4fc557363 100644 --- a/src/cpu/vx0.c +++ b/src/cpu/vx0.c @@ -224,20 +224,6 @@ const uint8_t opf_0f[256] = { 0, 0, 0, 0, 0, 0, int nx = 0; -static uint32_t cpu_src = 0; -static uint32_t cpu_dest = 0; - -static uint32_t cpu_data = 0; - -static int oldc; -static int cpu_alu_op; -static int completed = 1; -static int in_rep = 0; -static int repeating = 0; -static int rep_c_flag = 0; -static int clear_lock = 0; -static int noint = 0; -static int tempc_fpu = 0; static int started = 0; static int group_delay = 0; static int modrm_loaded = 0; @@ -246,8 +232,6 @@ static int in_hlt = 0; static int retem = 0; static int halted = 0; -static uint32_t * ovr_seg = NULL; - /* Pointer tables needed for segment overrides. */ static uint32_t * opseg[4]; @@ -489,6 +473,8 @@ void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val) void reset_vx0(int hard) { + reset_808x(hard); + halted = 0; in_hlt = 0; in_0f = 0; @@ -1854,9 +1840,53 @@ do_mod_rm(void) } static void -decode(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) @@ -1864,8 +1894,6 @@ decode(void) else opcode = biu_pfq_fetchb_common(); - modrm_loaded = 0; - while (1) { prefix = 0; @@ -1913,43 +1941,6 @@ decode(void) opcode = biu_pfq_fetchb_common(); } - - 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 @@ -1992,6 +1983,10 @@ string_op(int bits) 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; @@ -4735,7 +4730,16 @@ execvx0(int cycs) startx86(); } +#ifdef DEBUG_INSTRUCTIONS + if (repeating) { + if ((opcode >= 0xa0) && (opcode <= 0xaf) && (opcode != 0x8e)) { + execx86_instruction(); + goto check_completed; + } + } else { +#else if (!repeating) { +#endif cpu_state.oldpc = cpu_state.pc; if (clear_lock) { @@ -4743,9 +4747,21 @@ execvx0(int cycs) clear_lock = 0; } - if (!is_nec || (cpu_state.flags & MD_FLAG)) + if (!is_nec || (cpu_state.flags & MD_FLAG)) { decode(); +#ifdef DEBUG_INSTRUCTIONS + if ((opcode >= 0xa0) && (opcode <= 0xaf) && (opcode != 0x8e)) { + oldc = cpu_state.flags & C_FLAG; + + execx86_instruction(); + goto check_completed; + } +#endif + + decode_modrm(); + } + oldc = cpu_state.flags & C_FLAG; } @@ -4753,6 +4769,9 @@ execvx0(int cycs) execute_instruction(); +#ifdef DEBUG_INSTRUCTIONS +check_completed: +#endif if (completed) { if (opcode != 0xf4) finalize(); diff --git a/src/cpu/vx0_biu.h b/src/cpu/vx0_biu.h index 27d44797c43..92eb661afc2 100644 --- a/src/cpu/vx0_biu.h +++ b/src/cpu/vx0_biu.h @@ -76,7 +76,8 @@ enum { DMA_STATE_OPERATING }; -/* Temporary BIU externs - move to 808x_biu.h. */ +extern void execx86_instruction(void); + extern void biu_resume_on_queue_read(void); extern void wait_vx0(int c); extern void biu_reset(void); @@ -106,6 +107,15 @@ 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 schedule_fetch; extern int in_lock; @@ -113,4 +123,11 @@ 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; + #endif /*EMU_808X_BIU_H*/ From e8eb606510b475cb84429b63753bedf467041074 Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 30 Jan 2026 07:59:24 +0100 Subject: [PATCH 07/26] Some improvements on said debug thunking to old 808x instructions. --- src/cpu/808x.c | 323 +++++++++++++++++++++++++++++----------------- src/cpu/vx0.c | 12 +- src/cpu/vx0_biu.h | 5 + 3 files changed, 214 insertions(+), 126 deletions(-) diff --git a/src/cpu/808x.c b/src/cpu/808x.c index a1d29e56adb..8cb153cd22c 100644 --- a/src/cpu/808x.c +++ b/src/cpu/808x.c @@ -64,6 +64,7 @@ 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; @@ -72,13 +73,13 @@ 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; uint16_t last_addr = 0x0000; @@ -255,7 +256,7 @@ fetch_and_bus(int c, int bus) static void wait_cycs(int c, int bus) { - if (is_nec) + if (is_new_biu) wait_vx0(c); else { cycles -= c; @@ -296,7 +297,7 @@ resub_cycles(int old_cycles) static void cpu_io(int bits, int out, uint16_t port) { - if (is_nec) + if (is_new_biu) cpu_io_vx0(bits, out, port); else { int old_cycles = cycles; @@ -343,7 +344,7 @@ cpu_io(int bits, int out, uint16_t port) static uint8_t readmemb(uint32_t s, uint32_t a) { - if (is_nec) + if (is_new_biu) return readmemb_vx0(s, a); else { uint8_t ret; @@ -371,7 +372,7 @@ readmembf(uint32_t a) static uint16_t readmemw(uint32_t s, uint16_t a) { - if (is_nec) + if (is_new_biu) return readmemw_vx0(s, a); else { uint16_t ret; @@ -382,7 +383,7 @@ readmemw(uint32_t s, uint16_t a) else { wait_cycs(4, 1); ret = read_mem_b(s + a); - ret |= read_mem_b(s + (is186 ? (a + 1) : (a + 1) & 0xffff)) << 8; + ret |= read_mem_b(s + ((is186 && !is_nec) ? (a + 1) : (a + 1) & 0xffff)) << 8; } return ret; @@ -402,7 +403,7 @@ readmemwf(uint16_t a) static uint16_t readmem(uint32_t s) { - if (is_nec) + if (is_new_biu) return readmem_vx0(s); else { if (opcode & 1) @@ -415,7 +416,7 @@ readmem(uint32_t s) static uint32_t readmeml(uint32_t s, uint16_t a) { - if (is_nec) + if (is_new_biu) return readmeml_vx0(s, a); else { uint32_t temp; @@ -430,7 +431,7 @@ readmeml(uint32_t s, uint16_t a) static uint64_t readmemq(uint32_t s, uint16_t a) { - if (is_nec) + if (is_new_biu) return readmemq_vx0(s, a); else { uint64_t temp; @@ -446,7 +447,7 @@ readmemq(uint32_t s, uint16_t a) static void writememb(uint32_t s, uint32_t a, uint8_t v) { - if (is_nec) + if (is_new_biu) writememb_vx0(s, a, v); else { uint32_t addr = s + a; @@ -463,7 +464,7 @@ writememb(uint32_t s, uint32_t a, uint8_t v) static void writememw(uint32_t s, uint32_t a, uint16_t v) { - if (is_nec) + if (is_new_biu) writememw_vx0(s, a, v); else { uint32_t addr = s + a; @@ -474,7 +475,7 @@ writememw(uint32_t s, uint32_t a, uint16_t v) else { write_mem_b(addr, v & 0xff); wait_cycs(4, 1); - addr = s + (is186 ? (a + 1) : ((a + 1) & 0xffff)); + addr = s + ((is186 && !is_nec) ? (a + 1) : ((a + 1) & 0xffff)); write_mem_b(addr, v >> 8); } @@ -486,7 +487,7 @@ writememw(uint32_t s, uint32_t a, uint16_t v) static void writemem(uint32_t s, uint16_t v) { - if (is_nec) + if (is_new_biu) writemem_vx0(s, v); else { if (opcode & 1) @@ -499,7 +500,7 @@ writemem(uint32_t s, uint16_t v) static void writememl(uint32_t s, uint32_t a, uint32_t v) { - if (is_nec) + if (is_new_biu) writememl_vx0(s, a, v); else { writememw(s, a, v & 0xffff); @@ -510,7 +511,7 @@ writememl(uint32_t s, uint32_t a, uint32_t v) static void writememq(uint32_t s, uint32_t a, uint64_t v) { - if (is_nec) + if (is_new_biu) writememl_vx0(s, a, v); else { writememl(s, a, v & 0xffffffff); @@ -542,7 +543,7 @@ pfq_write(void) static uint8_t pfq_read(void) { - if (is_nec) + if (is_new_biu) return biu_pfq_read(); else { uint8_t temp = pfq[0]; @@ -560,7 +561,7 @@ pfq_read(void) static uint8_t pfq_fetchb_common(void) { - if (is_nec) + if (is_new_biu) return biu_pfq_fetchb_common(); else { uint8_t temp; @@ -581,7 +582,7 @@ pfq_fetchb_common(void) static uint8_t pfq_fetchb(void) { - if (is_nec) + if (is_new_biu) return biu_pfq_fetchb(); else { uint8_t ret; @@ -597,7 +598,7 @@ pfq_fetchb(void) static uint16_t pfq_fetchw(void) { - if (is_nec) + if (is_new_biu) return biu_pfq_fetchw(); else { uint16_t temp; @@ -613,7 +614,7 @@ pfq_fetchw(void) static uint16_t pfq_fetch(void) { - if (is_nec) + if (is_new_biu) return biu_pfq_fetch(); else { if (opcode & 1) @@ -642,7 +643,7 @@ pfq_add(int c, int add) static void pfq_clear_pos(void) { - if (is_nec) + if (is_new_biu) biu_queue_flush(); else pfq_pos = 0; @@ -652,7 +653,7 @@ pfq_clear_pos(void) static void pfq_clear(void) { - if (is_nec) { + if (is_new_biu) { biu_suspend_fetch(); biu_queue_flush(); } else { @@ -705,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; @@ -730,6 +732,8 @@ reset_808x(int hard) load_cs(0xFFFF); cpu_state.pc = 0; + if (is_nec) + cpu_state.flags |= MD_FLAG; rammask = 0xfffff; prefetching = 1; @@ -750,10 +754,9 @@ reset_808x(int hard) static void set_ip(uint16_t new_ip) { - if (is_nec) { + if (is_new_biu) cpu_state.pc = new_ip; - biu_queue_flush(); - } else { + else { pfq_ip = cpu_state.pc = new_ip; prefetching = 1; } @@ -969,7 +972,7 @@ seteaq(uint64_t val) static void push(uint16_t *val) { - if (is186 && (SP == 1)) { + if ((is186 && !is_nec) && (SP == 1)) { writememw(ss - 1, 0, *val); SP = cpu_state.eaaddr = 0xFFFF; return; @@ -992,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: @@ -1050,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; @@ -1079,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); @@ -1087,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: @@ -1102,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); @@ -1134,20 +1127,39 @@ 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); - tempf = cpu_state.flags & 0x0fd7; + 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); - access(40, 16); + if (is_nec) + cpu_state.flags |= MD_FLAG; + 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); } @@ -1172,9 +1184,11 @@ custom_nmi(void) pfq_clear(); ovr_seg = NULL; access(39, 16); - tempf = cpu_state.flags & 0x0fd7; + 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); push(&old_cs); old_ip = cpu_state.pc; @@ -1186,10 +1200,10 @@ custom_nmi(void) } static int -irq_pending(void) +irq_pending(int nec_hlt) { uint8_t temp; - int i_flag = (cpu_state.flags & I_FLAG); + int i_flag = (cpu_state.flags & I_FLAG) || nec_hlt; temp = (nmi && nmi_enable && nmi_mask) || ((cpu_state.flags & T_FLAG) && !noint) || (i_flag && pic.int_pending && !noint); @@ -1197,12 +1211,12 @@ irq_pending(void) } static void -check_interrupts(void) +check_interrupts(int nec_hlt) { int temp; - int i_flag = (cpu_state.flags & I_FLAG); + int i_flag = (cpu_state.flags & I_FLAG) || nec_hlt; - if (irq_pending()) { + if (irq_pending(nec_hlt)) { if ((cpu_state.flags & T_FLAG) && !(noint & 1)) { interrupt(1); return; @@ -1251,10 +1265,13 @@ rep_action(int bits) return 0; wait_cycs(2, 0); t = CX; - if (irq_pending() && (repeating != 0)) { + if (irq_pending(0) && (repeating != 0)) { access(71, bits); pfq_clear(); - set_ip(cpu_state.pc - 2); + if (is_nec && (ovr_seg != NULL)) + set_ip(cpu_state.pc - 3); + else + set_ip(cpu_state.pc - 2); t = 0; } if (t == 0) { @@ -1276,14 +1293,14 @@ jump(uint16_t delta) { uint16_t old_ip; access(67, 8); - if (is_nec) + 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_nec) + if (is_new_biu) biu_queue_flush(); return old_ip; } @@ -1882,7 +1899,7 @@ 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; + uint16_t tempw_int, size, tempbp, lowbound, old_flags; uint16_t highbound, regval, orig_sp, wordtopush, immediate; int bits; uint32_t dest_seg; @@ -1937,6 +1954,18 @@ execx86_instruction(void) 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); @@ -2058,7 +2087,9 @@ execx86_instruction(void) wait_cycs((cpu_mod != 3) ? 9 : 6, 0); - cpu_src &= 0x1F; + if (!is_nec) + cpu_src &= 0x1f; + while (cpu_src != 0) { cpu_dest = cpu_data; oldc = cpu_state.flags & C_FLAG; @@ -2516,13 +2547,22 @@ execx86_instruction(void) new_ip = pfq_fetchw(); wait_cycs(1, 0); new_cs = pfq_fetchw(); - pfq_clear(); - access(31, 16); + if (is_new_biu) + biu_suspend_fetch(); + else { + pfq_clear(); + access(31, 16); + } push(&(CS)); - access(60, 16); + 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; @@ -2537,22 +2577,29 @@ execx86_instruction(void) } else { repeating = 1; completed = 0; - clock_end(); + if (!is_new_biu) + clock_end(); } #else wait_cycs(7, 0); - check_interrupts(); + check_interrupts(0); #endif break; case 0x9c: /* PUSHF */ access(33, 16); - tempw = (cpu_state.flags & 0x0fd7) | 0xf000; + 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); - cpu_state.flags = pop() | 0x0002; + 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; @@ -2616,7 +2663,7 @@ execx86_instruction(void) break; } repeating = 1; - if (!is_nec) + if (!is_new_biu) clock_end(); break; @@ -2656,7 +2703,7 @@ execx86_instruction(void) break; } repeating = 1; - if (!is_nec) + if (!is_new_biu) clock_end(); break; @@ -2687,7 +2734,7 @@ execx86_instruction(void) break; } repeating = 1; - if (!is_nec) + if (!is_new_biu) clock_end(); break; @@ -2717,7 +2764,10 @@ execx86_instruction(void) } if ((opcode & 9) == 9) wait_cycs(1, 0); - pfq_clear(); + if (is_new_biu) + biu_suspend_fetch(); + else + pfq_clear(); access(26, bits); new_ip = pop(); wait_cycs(2, 0); @@ -2736,6 +2786,8 @@ execx86_instruction(void) 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 */ @@ -2786,8 +2838,13 @@ execx86_instruction(void) load_cs(new_cs); access(62, 8); set_ip(new_ip); + if (is_new_biu) + biu_queue_flush(); access(45, 8); - cpu_state.flags = pop() | 0x0002; + 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; @@ -2807,7 +2864,7 @@ execx86_instruction(void) cpu_src = CL; wait_cycs((cpu_mod != 3) ? 9 : 6, 0); } - if (is186) + if (is186 && !is_nec) cpu_src &= 0x1f; while (cpu_src != 0) { cpu_dest = cpu_data; @@ -2894,7 +2951,11 @@ execx86_instruction(void) break; case 0xd5: /* AAD */ wait_cycs(1, 0); - mul(pfq_fetchb(), AH); + if (is_nec) { + (void) pfq_fetchb(); + mul(10, AH); + } else + mul(pfq_fetchb(), AH); cpu_dest = AL; cpu_src = cpu_data; add(8); @@ -2903,10 +2964,13 @@ execx86_instruction(void) set_pzs(8); break; case 0xd6: /* SALC */ - wait_cycs(1, 0); - AL = (cpu_state.flags & C_FLAG) ? 0xff : 0x00; - wait_cycs(1, 0); - break; + 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); @@ -3054,8 +3118,13 @@ execx86_instruction(void) tempw = pfq_fetchw(); load_cs(tempw); access(70, 8); - pfq_clear(); + 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); @@ -3083,9 +3152,9 @@ execx86_instruction(void) pfq_clear(); } wait_cycs(1, 0); - if (irq_pending()) { + if (irq_pending(is_nec)) { wait_cycs(cycles & 1, 0); - check_interrupts(); + check_interrupts(is_nec); } else { repeating = 1; completed = 0; @@ -3126,6 +3195,7 @@ execx86_instruction(void) 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) { @@ -3137,12 +3207,17 @@ execx86_instruction(void) AL = (uint8_t) cpu_data; AH = (uint8_t) cpu_dest; set_co_mul(bits, AH != ((AL & 0x80) == 0 || (rmdat & 0x38) == 0x20 ? 0 : 0xff)); - cpu_data = AH; + 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) @@ -3193,13 +3268,18 @@ execx86_instruction(void) cpu_data_opff_rm(); access(63, bits); wait_cycs(1, 0); - pfq_clear(); + 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)); @@ -3214,10 +3294,15 @@ execx86_instruction(void) access(36, bits); push(&(CS)); access(64, bits); - wait_cycs(4, 0); + 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; @@ -3225,6 +3310,8 @@ execx86_instruction(void) 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; @@ -3236,6 +3323,8 @@ execx86_instruction(void) 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) @@ -3285,7 +3374,7 @@ execx86(int cycs) if (in_lock) clear_lock = 1; clock_end(); - check_interrupts(); + check_interrupts(0); if (noint) noint = 0; diff --git a/src/cpu/vx0.c b/src/cpu/vx0.c index ab4fc557363..ee26e41c55f 100644 --- a/src/cpu/vx0.c +++ b/src/cpu/vx0.c @@ -232,11 +232,6 @@ static int in_hlt = 0; static int retem = 0; static int halted = 0; -/* Pointer tables needed for segment overrides. */ -static uint32_t * opseg[4]; - -static x86seg * _opseg[4]; - enum { MODRM_ADDR_BX_SI = 0x00, MODRM_ADDR_BX_DI, @@ -473,8 +468,7 @@ void i8080_port_out(UNUSED(void* priv), uint8_t port, uint8_t val) void reset_vx0(int hard) { - reset_808x(hard); - + is_new_biu = 1; halted = 0; in_hlt = 0; in_0f = 0; @@ -4732,7 +4726,7 @@ execvx0(int cycs) #ifdef DEBUG_INSTRUCTIONS if (repeating) { - if ((opcode >= 0xa0) && (opcode <= 0xaf) && (opcode != 0x8e)) { + if ((opcode >= MIN_INS) && (opcode <= MAX_INS) && (opcode != SKIP_INS)) { execx86_instruction(); goto check_completed; } @@ -4751,7 +4745,7 @@ execvx0(int cycs) decode(); #ifdef DEBUG_INSTRUCTIONS - if ((opcode >= 0xa0) && (opcode <= 0xaf) && (opcode != 0x8e)) { + if ((opcode >= MIN_INS) && (opcode <= MAX_INS) && (opcode != SKIP_INS)) { oldc = cpu_state.flags & C_FLAG; execx86_instruction(); diff --git a/src/cpu/vx0_biu.h b/src/cpu/vx0_biu.h index 92eb661afc2..173a6947b99 100644 --- a/src/cpu/vx0_biu.h +++ b/src/cpu/vx0_biu.h @@ -116,6 +116,7 @@ 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; @@ -130,4 +131,8 @@ 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*/ From 561a7171c33f34c5b9df09048e68fcb8581f010f Mon Sep 17 00:00:00 2001 From: OBattler Date: Fri, 30 Jan 2026 08:58:48 +0100 Subject: [PATCH 08/26] NEC Vx0: Rename the logging functions. --- src/cpu/vx0.c | 34 +++++++++++++++++----------------- src/cpu/vx0_biu.c | 34 +++++++++++++++++----------------- 2 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/cpu/vx0.c b/src/cpu/vx0.c index ee26e41c55f..20924ea04ce 100644 --- a/src/cpu/vx0.c +++ b/src/cpu/vx0.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * 808x CPU emulation, mostly ported from reenigne's XTCE, which + * Vx0 CPU emulation, mostly ported from reenigne's XTCE, which * is cycle-accurate. * * Authors: Andrew Jenner, @@ -317,25 +317,25 @@ static uint8_t modrm_cycs_post[256] = { [MODRM_ADDR_BX_SI] = 0, [MODRM_ADDR_BX_DISP16] = 2, [0x88 ... 0xff] = 0 }; -#ifdef ENABLE_808X_LOG +#ifdef ENABLE_VX0_LOG #if 0 void dumpregs(int); #endif -int x808x_do_log = ENABLE_808X_LOG; +int vx0_do_log = ENABLE_VX0_LOG; static void -x808x_log(const char *fmt, ...) +vx0_log(const char *fmt, ...) { va_list ap; - if (x808x_do_log) { + if (vx0_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else -# define x808x_log(fmt, ...) +# define vx0_log(fmt, ...) #endif static i8080 emulated_processor; @@ -584,7 +584,7 @@ geteal(void) uint32_t ret; if (cpu_mod == 3) { - fatal("808x register geteal()\n"); + fatal("Vx0 register geteal()\n"); ret = 0xffffffff; } else ret = readmeml(easeg, cpu_state.eaaddr); @@ -599,7 +599,7 @@ geteaq(void) uint32_t ret; if (cpu_mod == 3) { - fatal("808x register geteaq()\n"); + fatal("Vx0 register geteaq()\n"); ret = 0xffffffff; } else ret = readmemq(easeg, cpu_state.eaaddr); @@ -669,7 +669,7 @@ static void seteal(uint32_t val) { if (cpu_mod == 3) { - fatal("808x register seteal()\n"); + fatal("Vx0 register seteal()\n"); return; } else writememl(easeg, cpu_state.eaaddr, val); @@ -679,7 +679,7 @@ static void seteaq(uint64_t val) { if (cpu_mod == 3) { - fatal("808x register seteaq()\n"); + fatal("Vx0 register seteaq()\n"); return; } else writememq(easeg, cpu_state.eaaddr, val); @@ -1023,7 +1023,7 @@ intr_routine(uint16_t intr, int skip_first) if (!(cpu_state.flags & MD_FLAG) && is_nec) { sync_from_i8080(); - x808x_log("CALLN/INT#/NMI#\n"); + vx0_log("CALLN/INT#/NMI#\n"); } if (!skip_first) @@ -1268,7 +1268,7 @@ sw_int(uint16_t intr) if (!(cpu_state.flags & MD_FLAG) && is_nec) { sync_from_i8080(); - x808x_log("CALLN/INT#/NMI#\n"); + vx0_log("CALLN/INT#/NMI#\n"); } do_cycles_i(3); @@ -1344,7 +1344,7 @@ interrupt_brkem(uint16_t addr) push(&old_ip); sync_to_i8080(); - x808x_log("BRKEM mode\n"); + vx0_log("BRKEM mode\n"); } void @@ -1367,7 +1367,7 @@ retem_i8080(void) retem = 1; - x808x_log("RETEM mode\n"); + vx0_log("RETEM mode\n"); } void @@ -1388,7 +1388,7 @@ custom_nmi(void) if (!(cpu_state.flags & MD_FLAG) && is_nec) { sync_from_i8080(); - x808x_log("CALLN/INT#/NMI#\n"); + vx0_log("CALLN/INT#/NMI#\n"); } do_cycle_i(); @@ -4705,7 +4705,7 @@ execute_instruction(void) break; default: - x808x_log("Illegal opcode: %02X\n", opcode); + vx0_log("Illegal opcode: %02X\n", opcode); biu_pfq_fetchb(); do_cycles(8); break; @@ -4759,7 +4759,7 @@ execvx0(int cycs) oldc = cpu_state.flags & C_FLAG; } - x808x_log("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); + vx0_log("[%04X:%04X] Opcode: %02X\n", CS, cpu_state.pc, opcode); execute_instruction(); diff --git a/src/cpu/vx0_biu.c b/src/cpu/vx0_biu.c index 4f7a8e1d2a2..92f1909a6c7 100644 --- a/src/cpu/vx0_biu.c +++ b/src/cpu/vx0_biu.c @@ -6,7 +6,7 @@ * * This file is part of the 86Box distribution. * - * 808x BIU emulation. + * Vx0 BIU emulation. * * Authors: Andrew Jenner, * Miran Grca, @@ -86,22 +86,22 @@ static int dma_wait_states = 0; /* DEBUG stuff. */ const char *lpBiuStates[7] = { "Ti ", "Ti S ", "Ti D ", "Ti R ", "Tw ", "T%i PF", "T%i EU" }; -#ifdef ENABLE_808X_BIU_LOG -int x808x_biu_do_log = ENABLE_808X_BIU_LOG; +#ifdef ENABLE_VX0_BIU_LOG +int vx0_biu_do_log = ENABLE_VX0_BIU_LOG; static void -x808x_biu_log(const char *fmt, ...) +vx0_biu_log(const char *fmt, ...) { va_list ap; - if (x808x_biu_do_log) { + if (vx0_biu_do_log) { va_start(ap, fmt); pclog_ex(fmt, ap); va_end(ap); } } #else -# define x808x_biu_log(fmt, ...) +# define vx0_biu_log(fmt, ...) #endif void @@ -301,7 +301,7 @@ bus_do_io(int io_type) { int old_cycles = cycles; - x808x_biu_log("(%02X) bus_do_io(%02X): %04X\n", opcode, io_type, cpu_state.eaaddr); + 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) @@ -388,18 +388,18 @@ 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) { - x808x_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); + 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); - x808x_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, - pfq_pos, temp); + vx0_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, + pfq_pos, temp); } } else { - x808x_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, - pfq_pos, lpBiuStates[biu_state]); + vx0_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, + pfq_pos, lpBiuStates[biu_state]); } } } @@ -456,8 +456,8 @@ static void biu_cycle_idle(int type) { if ((CS == DEBUG_SEG) && (cpu_state.pc >= DEBUG_OFF_L) && (cpu_state.pc <= DEBUG_OFF_H)) { - x808x_biu_log("[%04X:%04X] [%i, %i] (%i) %s\n", CS, cpu_state.pc, dma_state, dma_wait_states, - pfq_pos, lpBiuStates[type]); + 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(); @@ -493,7 +493,7 @@ do_bus_access(void) { int io_type = (biu_state == BIU_STATE_EU) ? bus_request_type : BUS_CODE; - x808x_biu_log("[%04X:%04X] %02X bus access %02X\n", CS, cpu_state.pc, opcode, io_type); + vx0_biu_log("[%04X:%04X] %02X bus access %02X\n", CS, cpu_state.pc, opcode, io_type); if (io_type != 0) { wait_states = 0; @@ -707,7 +707,7 @@ biu_eu_request(void) void wait_vx0(int c) { - x808x_biu_log("[%04X:%04X] %02X %i cycles\n", CS, cpu_state.pc, opcode, 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(); From 8e1acfa3b1be3bb60b8a23baf6f14f98595fac7a Mon Sep 17 00:00:00 2001 From: OBattler Date: Sat, 31 Jan 2026 06:17:25 +0100 Subject: [PATCH 09/26] Mouse Systems mice: The last two bytes of the report are now correctly the mouse movement delta between when we've initially prepared the report for sending and when we've reached the 3rd byte. --- src/device/mouse_serial.c | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/device/mouse_serial.c b/src/device/mouse_serial.c index 45750ef0956..340d3d1442d 100644 --- a/src/device/mouse_serial.c +++ b/src/device/mouse_serial.c @@ -143,8 +143,24 @@ sermouse_transmit_byte(mouse_t *dev, int do_next) if (dev->buf_pos == 0) dev->acc_time = 0.0; - if (dev->serial) + if (dev->serial) { + if ((dev->state == STATE_TRANSMIT_REPORT) && (dev->format == FORMAT_PB_5BYTE) && + (dev->buf_pos == 3)) { + /* + The last two bytes are the delta between now and when we originally + prepared the report for sending. + */ + int delta_x = 0; + int delta_y = 0; + + mouse_subtract_coords(&delta_x, &delta_y, NULL, NULL, -128, 127, 1, 0); + + dev->buf[3] = delta_x; /* same as byte 1 */ + dev->buf[4] = delta_y; /* same as byte 2 */ + } + serial_write_fifo(dev->serial, dev->buf[dev->buf_pos]); + } if (do_next) { /* If we have a buffer length of 0, pretend the state is STATE_SKIP_PACKET. */ From e7fee34332c61b9209468a4e8335d05cc02f32f6 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 14:41:04 +0100 Subject: [PATCH 10/26] ESC/P 2: 4 versions, filtering by version, selectable paper. The four versions are: - EX-1000 and 7 other early printers (including FX-80, the only Epson available OOTB for Windows 1.03), have ESC i and ESC j. - 9-pin ESC/P, a superset of EX-1000 besides ESC i and ESC j. - 24-pin ESC/P in 360 DPI instead of 240. - ESC/P 2 with raster graphics. As for paper, four sizes: Letter, A4, Legal, B4. The former ones are mainly for EX-800, the latter two are sideways and meant for EX-1000. I did some other minor changes, like converting a bunch of defines to enum. --- src/include/86box/prt_papersizes.h | 4 + src/printer/prt_escp.c | 580 ++++++++++++++++++----------- 2 files changed, 373 insertions(+), 211 deletions(-) diff --git a/src/include/86box/prt_papersizes.h b/src/include/86box/prt_papersizes.h index c45c7456887..e468abb35bb 100644 --- a/src/include/86box/prt_papersizes.h +++ b/src/include/86box/prt_papersizes.h @@ -47,4 +47,8 @@ #define A4_PAGE_WIDTH 8.25 #define A4_PAGE_HEIGHT 11.75 +/* Standard B4 */ +#define B4_PAGE_WIDTH 9.875 +#define B4_PAGE_HEIGHT 13.875 + #endif /*EMU_PLAT_FALLTHROUGH_H*/ diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 2a50ae54f17..e87fa88db33 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -72,31 +72,38 @@ #include <86box/prt_devs.h> #include <86box/prt_papersizes.h> +enum { + LANG_EX1000 = 0, // last printer with ESC i and j + LANG_9PIN, + LANG_ESCP, // also known as 24/48-pin + LANG_ESCP2 +}; + +enum { + PAPER_LETTER = 0, + PAPER_A4, + PAPER_LEGAL_SIDE, + PAPER_B4_SIDE +}; + /* Default page values (for now.) */ #define COLOR_BLACK 7 << 5 -#define PAGE_WIDTH LETTER_PAGE_WIDTH -#define PAGE_HEIGHT LETTER_PAGE_HEIGHT -#if 0 -#define PAGE_LMARGIN 0.0 -#define PAGE_RMARGIN PAGE_WIDTH -#define PAGE_TMARGIN 0.0 -#define PAGE_BMARGIN PAGE_HEIGHT -#endif -#define PAGE_DPI 360 -#define PAGE_CPI 10.0 /* standard 10 cpi */ +#define PAGE_CPI 10.0 /* standard310 cpi */ #define PAGE_LPI 6.0 /* standard 6 lpi */ /* FreeType library handles - global so they can be shared. */ FT_Library ft_lib = NULL; /* The fonts. */ -#define FONT_DEFAULT 0 -#define FONT_ROMAN 1 -#define FONT_SANSSERIF 2 -#define FONT_COURIER 3 -#define FONT_SCRIPT 4 -#define FONT_OCRA 5 -#define FONT_OCRB 6 +enum { + FONT_DEFAULT = 0, + FONT_ROMAN, + FONT_SANSSERIF, + FONT_COURIER, + FONT_SCRIPT, + FONT_OCRA, + FONT_OCRB +}; /* Font styles. */ #define STYLE_PROP 0x0001 @@ -125,20 +132,22 @@ FT_Library ft_lib = NULL; #define QUALITY_LQ 0x02 /* Typefaces. */ -#define TYPEFACE_ROMAN 0 -#define TYPEFACE_SANSSERIF 1 -#define TYPEFACE_COURIER 2 -#define TYPEFACE_PRESTIGE 3 -#define TYPEFACE_SCRIPT 4 -#define TYPEFACE_OCRB 5 -#define TYPEFACE_OCRA 6 -#define TYPEFACE_ORATOR 7 -#define TYPEFACE_ORATORS 8 -#define TYPEFACE_SCRIPTC 9 -#define TYPEFACE_ROMANT 10 -#define TYPEFACE_SANSSERIFH 11 -#define TYPEFACE_SVBUSABA 30 -#define TYPEFACE_SVJITTRA 31 +enum { + TYPEFACE_ROMAN = 0, + TYPEFACE_SANSSERIF, + TYPEFACE_COURIER, + TYPEFACE_PRESTIGE, + TYPEFACE_SCRIPT, + TYPEFACE_OCRB, + TYPEFACE_OCRA, + TYPEFACE_ORATOR, + TYPEFACE_ORATORS, + TYPEFACE_SCRIPTC, + TYPEFACE_ROMANT, + TYPEFACE_SANSSERIFH, + TYPEFACE_SVBUSABA = 30, + TYPEFACE_SVJITTRA +}; /* Some helper macros. */ #define PARAM16(x) (dev->esc_parms[x + 1] * 256 + dev->esc_parms[x]) @@ -164,6 +173,9 @@ typedef struct escp_t { pc_timer_t pulse_timer; pc_timer_t timeout_timer; + int lang; + int paper_size; + char page_fn[260]; uint8_t color; @@ -423,6 +435,23 @@ fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, static void reset_printer(escp_t *dev) { + dev->top_margin = dev->left_margin = 0.0; + dev->right_margin = dev->page_width; + switch (dev->paper_size) { + case PAPER_A4: + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + break; + case PAPER_LETTER: + default: + dev->page_height = LETTER_PAGE_HEIGHT; + } + dev->bottom_margin = dev->page_height; /* TODO: these should be configurable. */ dev->color = COLOR_BLACK; dev->curr_x = dev->curr_y = 0.0; @@ -430,23 +459,20 @@ reset_printer(escp_t *dev) dev->fss_seen = 0; dev->esc_pending = 0; dev->esc_parms_req = dev->esc_parms_curr = 0; - dev->top_margin = dev->left_margin = 0.0; - dev->right_margin = dev->page_width = PAGE_WIDTH; - dev->bottom_margin = dev->page_height = PAGE_HEIGHT; - dev->lpi = PAGE_LPI; - dev->linespacing = 1.0 / dev->lpi; - dev->cpi = PAGE_CPI; - dev->curr_char_table = 1; - dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; - dev->extra_intra_space = 0.0; - dev->print_upper_control = 1; - dev->bg_remaining_bytes = 0; - dev->density_k = 0; - dev->density_l = 1; - dev->density_y = 2; - dev->density_z = 3; - dev->char_tables[0] = 0; /* italics */ + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; + dev->print_quality = QUALITY_DRAFT; + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ dev->defined_unit = -1.0; dev->multipoint_mode = 0; @@ -633,73 +659,55 @@ process_char(escp_t *dev, uint8_t ch) escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { case 0x02: // Undocumented - case 0x0a: // Reverse line feed - case 0x0c: // Return to top of current page case 0x0e: // Select double-width printing (one line) (ESC SO) case 0x0f: // Select condensed printing (ESC SI) - case 0x23: // Cancel MSB control (ESC #) - case 0x30: // Select 1/8-inch line spacing (ESC 0) - case 0x31: // Select 7/60-inch line spacing - case 0x32: // Select 1/6-inch line spacing (ESC 2) - case 0x34: // Select italic font (ESC 4) - case 0x35: // Cancel italic font (ESC 5) - case 0x36: // Enable printing of upper control codes (ESC 6) - case 0x37: // Enable upper control codes (ESC 7) - case 0x38: // Disable paper-out detector - case 0x39: // Enable paper-out detector - case 0x3c: // Unidirectional mode (one line) (ESC <) - case 0x3d: // Set MSB to 0 (ESC =) - case 0x3e: // Set MSB to 1 (ESC >) - case 0x40: // Initialize printer (ESC @) - case 0x45: // Select bold font (ESC E) - case 0x46: // Cancel bold font (ESC F) - case 0x47: // Select double-strike printing (ESC G) - case 0x48: // Cancel double-strike printing (ESC H) - case 0x4d: // Select 10.5-point, 12-cpi (ESC M) - case 0x4f: // Cancel bottom margin - case 0x50: // Select 10.5-point, 10-cpi (ESC P) - case 0x54: // Cancel superscript/subscript printing (ESC T) - case 0x5e: // Enable printing of all character codes on next character - case 0x67: // Select 10.5-point, 15-cpi (ESC g) - + case '#': // Cancel MSB control + case '0': // Select 1/8-inch line spacing + case '1': // Select 7/60-inch line spacing + case '2': // Select 1/6-inch line spacing + case '4': // Select italic font + case '5': // Cancel italic font + case '6': // Enable printing of upper control codes + case '7': // Enable upper control codes + case '8': // Disable paper-out detector + case '9': // Enable paper-out detector + case '<': // Unidirectional mode (one line) + case '=': // Set MSB to 0 + case '>': // Set MSB to 1 + case '@': // Initialize printer + case 'E': // Select bold font + case 'F': // Cancel bold font + case 'G': // Select double-strike printing + case 'H': // Cancel double-strike printing + case 'M': // Select 10.5-point, 12-cpi + case 'O': // Cancel bottom margin + case 'P': // Select 10.5-point, 10-cpi + case 'T': // Cancel superscript/subscript printing + case '^': // Enable printing of all character codes on next character + dev->esc_parms_req = 0; + break; + case 'g': // Select 10.5-point, 15-cpi + dev->esc_parms_req = 0; + if (dev->lang == LANG_EX1000) { + dev->esc_pending = 0; + return 1; + } + break; + case 0x0a: // Reverse line feed (IBM's ESC LF) + case 0x0c: // Return to top of current page (IBM's ESC FF) case 0x834: // Select italic font (FS 4) (= ESC 4) case 0x835: // Cancel italic font (FS 5) (= ESC 5) case 0x846: // Select forward feed mode (FS F) case 0x852: // Select reverse feed mode (FS R) dev->esc_parms_req = 0; + if (dev->lang < LANG_ESCP2) { + dev->esc_pending = 0; + return 1; + } break; - case 0x19: // Control paper loading/ejecting (ESC EM) - case 0x20: // Set intercharacter space (ESC SP) - case 0x21: // Master select (ESC !) - case 0x2b: // Set n/360-inch line spacing (ESC +) - case 0x2d: // Turn underline on/off (ESC -) - case 0x2f: // Select vertical tab channel (ESC /) - case 0x33: // Set n/180-inch line spacing (ESC 3) - case 0x41: // Set n/60-inch line spacing - case 0x43: // Set page length in lines (ESC C) - case 0x49: // Select character type and print pitch - case 0x4a: // Advance print position vertically (ESC J n) - case 0x4e: // Set bottom margin (ESC N) - case 0x51: // Set right margin (ESC Q) - case 0x52: // Select an international character set (ESC R) - case 0x53: // Select superscript/subscript printing (ESC S) - case 0x55: // Turn unidirectional mode on/off (ESC U) - case 0x57: // Turn double-width printing on/off (ESC W) - case 0x61: // Select justification (ESC a) - case 0x66: // Absolute horizontal tab in columns [conflict] - case 0x68: // Select double or quadruple size - case 0x69: // Immediate print - case 0x6a: // Reverse paper feed - case 0x6b: // Select typeface (ESC k) - case 0x6c: // Set left margin (ESC 1) - case 0x70: // Turn proportional mode on/off (ESC p) - case 0x72: // Select printing color (ESC r) - case 0x73: // Select low-speed mode (ESC s) - case 0x74: // Select character table (ESC t) - case 0x77: // Turn double-height printing on/off (ESC w) - case 0x78: // Select LQ or draft (ESC x) - case 0x7e: // Select/Deselect slash zero (ESC ~) + case 'h': // Select double or quadruple size (IBM's) + case '~': // Select/Deselect slash zero (IBM's?) case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) @@ -708,53 +716,142 @@ process_char(escp_t *dev, uint8_t ch) case 0x849: // Select character table (FS I) (= ESC t) case 0x853: // Select High Speed/High Density elite pitch (FS S) case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '+': // Set n/360-inch line spacing + if (dev->lang < LANG_ESCP) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 'w': // Turn double-height printing on/off + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 0x19: // Control paper loading/ejecting (ESC EM) + case ' ': // Set intercharacter space + case '!': // Master select + case '-': // Turn underline on/off + case '/': // Select vertical tab channel + case '3': // Set n/180-inch line spacing + case 'A': // Set n/60-inch line spacing + case 'C': // Set page length in lines + case 'I': // Select character type and print pitch + case 'J': // Advance print position vertically + case 'N': // Set bottom margin + case 'Q': // Set right margin + case 'R': // Select an international character set + case 'S': // Select superscript/subscript printing + case 'U': // Turn unidirectional mode on/off + case 'W': // Turn double-width printing on/off + case 'a': // Select justification + case 'k': // Select typeface + case 'l': // Set left margin + case 'p': // Turn proportional mode on/off + case 'r': // Select printing color + case 's': // Select low-speed mode + case 't': // Select character table + case 'x': // Select LQ or draft + dev->esc_parms_req = 1; + break; + case 'f': // Absolute horizontal tab in columns + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 1; + break; + case 'i': // Immediate print + case 'j': // Reverse paper feed + if (dev->lang != LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 1; break; - case 0x24: // Set absolute horizontal print position (ESC $) - case 0x3f: // Reassign bit-image mode (ESC ?) - case 0x4b: // Select 60-dpi graphics (ESC K) - case 0x4c: // Select 120-dpi graphics (ESC L) - case 0x59: // Select 120-dpi, double-speed graphics (ESC Y) - case 0x5a: // Select 240-dpi graphics (ESC Z) - case 0x5c: // Set relative horizontal print position (ESC \) - case 0x63: // Set horizontal motion index (HMI) (ESC c) - case 0x65: // Set vertical tab stops every n lines (ESC e) + case 'c': // Set horizontal motion index (HMI) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '$': // Set absolute horizontal print position + case '?': // Reassign bit-image mode + case 'K': // Select 60-dpi graphics + case 'L': // Select 120-dpi graphics + case 'Y': // Select 120-dpi, double-speed graphics + case 'Z': // Select 240-dpi graphics + case '\\': // Set relative horizontal print position case 0x85a: // Print 24-bit hex-density graphics (FS Z) dev->esc_parms_req = 2; break; + case 'e': // Set vertical tab stops every n lines + if (dev->lang != LANG_9PIN) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + dev->esc_parms_req = 2; + break; - case 0x2a: // Select bit image (ESC *) - case 0x58: // Select font by pitch and point (ESC X) + case 'X': // Select font by pitch and point + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '*': // Select bit image dev->esc_parms_req = 3; break; - case 0x5b: // Select character height, width, line spacing + case '[': // Select character height, width, line spacing (IBM's) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } dev->esc_parms_req = 7; break; - case 0x62: // Set vertical tabs in VFU channels (ESC b) - case 0x42: // Set vertical tabs (ESC B) + case 'b': // Set vertical tabs in VFU channels + case 'B': // Set vertical tabs dev->num_vertical_tabs = 0; return 1; - case 0x44: // Set horizontal tabs (ESC D) + case 'D': // Set horizontal tabs dev->num_horizontal_tabs = 0; return 1; - case 0x25: // Select user-defined set (ESC %) - case 0x26: // Define user-defined characters (ESC &) - case 0x3a: // Copy ROM to RAM (ESC :) + case '%': // Select user-defined set + case '&': // Define user-defined characters + case ':': // Copy ROM to RAM escp_log("ESC/P: User-defined characters not supported (0x%02x).\n", dev->esc_pending); return 1; - case 0x28: // Two bytes sequence + case '(': // Two bytes sequence + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + } /* return and wait for second ESC byte */ return 1; - case 0x2e: - fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); - exit(-1); + case '.': + if (dev->lang >= LANG_ESCP2) { + fatal("ESC/P: Print Raster Graphics (2E) command is not implemented.\nTerminating the emulator to avoid endless PNG generation.\n"); + exit(-1); + } + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; default: escp_log("ESC/P: Unknown command ESC %c (0x%02x). Unable to skip parameters.\n", @@ -776,50 +873,67 @@ process_char(escp_t *dev, uint8_t ch) escp_log("Two-byte command pending=%03x, font path=%s\n", dev->esc_pending, dev->fontpath); switch (dev->esc_pending) { - case 0x0242: // Bar code setup and print (ESC (B) case 0x025e: // Print data as characters (ESC (^) + if (dev->lang < LANG_ESCP2) + default: + /* ESC ( commands are always followed by a "number of parameters" word parameter */ + dev->esc_pending = 0x101; /* dummy value to be checked later */ + case 0x0242: // Bar code setup and print (ESC (B) dev->esc_parms_req = 2; break; case 0x0255: // Set unit (ESC (U) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 3; break; case 0x0243: // Set page length in defined unit (ESC (C) case 0x0256: // Set absolute vertical print position (ESC (V) case 0x0276: // Set relative vertical print position (ESC (v) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 4; break; - case 0x0228: // Assign character table (ESC (t) case 0x022d: // Select line/score (ESC (-) + if (dev->lang == LANG_9PIN) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } + case 0x0228: // Assign character table (ESC (t) dev->esc_parms_req = 5; break; case 0x0263: // Set page format (ESC (c) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 2; + dev->esc_pending = 0x101; + break; + } dev->esc_parms_req = 6; break; - - default: - /* ESC ( commands are always followed by a "number of parameters" word parameter */ - dev->esc_parms_req = 2; - dev->esc_pending = 0x101; /* dummy value to be checked later */ - return 1; } - /* If we need parameters, return and wait for them to appear. */ - if (dev->esc_parms_req > 0) - return 1; + // Wait for more parameters. + return 1; } /* Ignore VFU channel setting. */ - if (dev->esc_pending == 0x62) { - dev->esc_pending = 0x42; + if (dev->esc_pending == 'b') { + dev->esc_pending = 'B'; return 1; } /* Collect vertical tabs. */ - if (dev->esc_pending == 0x42) { + if (dev->esc_pending == 'B') { /* check if we're done */ if ((ch == 0) || (dev->num_vertical_tabs > 0 && dev->vertical_tabs[dev->num_vertical_tabs - 1] > (double) ch * dev->linespacing)) { dev->esc_pending = 0; @@ -830,7 +944,7 @@ process_char(escp_t *dev, uint8_t ch) } /* Collect horizontal tabs. */ - if (dev->esc_pending == 0x44) { + if (dev->esc_pending == 'D') { /* check if we're done... */ if ((ch == 0) || (dev->num_horizontal_tabs > 0 && dev->horizontal_tabs[dev->num_horizontal_tabs - 1] > (double) ch * (1.0 / dev->cpi))) { dev->esc_pending = 0; @@ -887,7 +1001,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x21: /* master select (ESC !) */ + case '!': /* master select */ dev->cpi = (dev->esc_parms[0]) & 0x01 ? 12.0 : 10.0; /* Reset first seven bits. */ @@ -914,11 +1028,11 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x23: /* cancel MSB control (ESC #) */ + case '#': /* cancel MSB control */ dev->msb = 255; break; - case 0x24: /* set abs horizontal print position (ESC $) */ + case '$': /* set abs horizontal print position */ unit_size = dev->defined_unit; if (unit_size < 0) unit_size = 60.0; @@ -932,12 +1046,12 @@ process_char(escp_t *dev, uint8_t ch) setup_bit_image(dev, 40, PARAM16(0)); break; - case 0x2a: /* select bit image (ESC *) */ + case '*': /* select bit image */ setup_bit_image(dev, dev->esc_parms[0], PARAM16(1)); break; - case 0x2b: /* set n/360-inch line spacing (ESC +) */ case 0x833: /* Set n/360-inch line spacing (FS 3) */ + case '+': /* set n/360-inch line spacing */ dev->linespacing = (double) dev->esc_parms[0] / 360.0; break; @@ -951,58 +1065,58 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x2f: /* select vertical tab channel (ESC /) */ + case '/': /* select vertical tab channel */ /* Ignore */ break; - case 0x30: /* select 1/8-inch line spacing (ESC 0) */ + case '0': /* select 1/8-inch line spacing */ dev->linespacing = 1.0 / 8.0; break; - case 0x31: /* select 7/60-inch line spacing */ + case '1': /* select 7/60-inch line spacing */ dev->linespacing = 7.0 / 60.0; break; - case 0x32: /* select 1/6-inch line spacing (ESC 2) */ + case '2': /* select 1/6-inch line spacing */ dev->linespacing = 1.0 / 6.0; break; - case 0x33: /* set n/180-inch line spacing (ESC 3) */ + case '3': /* set n/180-inch line spacing */ dev->linespacing = (double) dev->esc_parms[0] / 180.0; break; - case 0x34: /* select italic font (ESC 4) */ + case '4': /* select italic font */ dev->font_style |= STYLE_ITALICS; update_font(dev); break; - case 0x35: /* cancel italic font (ESC 5) */ + case '5': /* cancel italic font */ dev->font_style &= ~STYLE_ITALICS; update_font(dev); break; - case 0x36: /* enable printing of upper control codes (ESC 6) */ + case '6': /* enable printing of upper control codes */ dev->print_upper_control = 1; break; - case 0x37: /* enable upper control codes (ESC 7) */ + case '7': /* enable upper control codes */ dev->print_upper_control = 0; break; - case 0x3c: /* unidirectional mode (one line) (ESC <) */ + case '<': /* unidirectional mode (one line) */ /* We don't have a print head, so just * ignore this. */ break; - case 0x3d: /* set MSB to 0 (ESC =) */ + case '=': /* set MSB to 0 */ dev->msb = 0; break; - case 0x3e: /* set MSB to 1 (ESC >) */ + case '>': /* set MSB to 1 */ dev->msb = 1; break; - case 0x3f: /* reassign bit-image mode (ESC ?) */ + case '?': /* reassign bit-image mode */ if (dev->esc_parms[0] == 'K') dev->density_k = dev->esc_parms[1]; if (dev->esc_parms[0] == 'L') @@ -1013,16 +1127,16 @@ process_char(escp_t *dev, uint8_t ch) dev->density_z = dev->esc_parms[1]; break; - case 0x40: /* initialize printer (ESC @) */ + case '@': /* initialize printer */ reset_printer(dev); break; - case 0x41: /* set n/60-inch line spacing */ - case 0x841: + case 'A': /* set n/60-inch line spacing */ + case 0x841: // FS A dev->linespacing = (double) dev->esc_parms[0] / 60.0; break; - case 0x43: /* set page length in lines (ESC C) */ + case 'C': /* set page length in lines */ if (dev->esc_parms[0] != 0) { dev->page_height = dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; } else { /* == 0 => Set page length in inches */ @@ -1033,69 +1147,69 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x45: /* select bold font (ESC E) */ + case 'E': /* select bold font */ dev->font_style |= STYLE_BOLD; update_font(dev); break; - case 0x46: /* cancel bold font (ESC F) */ + case 'F': /* cancel bold font */ dev->font_style &= ~STYLE_BOLD; update_font(dev); break; - case 0x47: /* select double-strike printing (ESC G) */ + case 'G': /* select double-strike printing */ dev->font_style |= STYLE_DOUBLESTRIKE; break; - case 0x48: /* cancel double-strike printing (ESC H) */ + case 'H': /* cancel double-strike printing */ dev->font_style &= ~STYLE_DOUBLESTRIKE; break; - case 0x4a: /* advance print pos vertically (ESC J n) */ + case 'J': /* advance print pos vertically */ dev->curr_y += (double) ((double) dev->esc_parms[0] / 180.0); if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); break; - case 0x4b: /* select 60-dpi graphics (ESC K) */ + case 'K': /* select 60-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_k, PARAM16(0)); break; - case 0x4c: /* select 120-dpi graphics (ESC L) */ + case 'L': /* select 120-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_l, PARAM16(0)); break; - case 0x4d: /* select 10.5-point, 12-cpi (ESC M) */ + case 'M': /* select 10.5-point, 12-cpi */ dev->cpi = 12.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x4e: /* set bottom margin (ESC N) */ + case 'N': /* set bottom margin */ dev->top_margin = 0.0; dev->bottom_margin = (double) dev->esc_parms[0] * dev->linespacing; break; - case 0x4f: /* cancel bottom (and top) margin */ + case 'O': /* cancel bottom (and top) margin */ dev->top_margin = 0.0; dev->bottom_margin = dev->page_height; break; - case 0x50: /* select 10.5-point, 10-cpi (ESC P) */ + case 'P': /* select 10.5-point, 10-cpi */ dev->cpi = 10.0; dev->hmi = -1; dev->multipoint_mode = 0; update_font(dev); break; - case 0x51: /* set right margin */ + case 'Q': /* set right margin */ dev->right_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; break; - case 0x52: /* select an intl character set (ESC R) */ + case 'R': /* select an intl character set */ if ((dev->esc_parms[0] <= 13) || (dev->esc_parms[0] == 64)) { if (dev->esc_parms[0] == 64) dev->esc_parms[0] = 14; @@ -1115,7 +1229,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x53: /* select superscript/subscript printing (ESC S) */ + case 'S': /* select superscript/subscript printing */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style |= STYLE_SUBSCRIPT; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[1] == '1')) @@ -1123,16 +1237,16 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x54: /* cancel superscript/subscript printing (ESC T) */ + case 'T': /* cancel superscript/subscript printing */ dev->font_style &= 0xFFFF - STYLE_SUPERSCRIPT - STYLE_SUBSCRIPT; update_font(dev); break; - case 0x55: /* turn unidirectional mode on/off (ESC U) */ + case 'U': /* turn unidirectional mode on/off */ /* We don't have a print head, so just ignore this. */ break; - case 0x57: /* turn double-width printing on/off (ESC W) */ + case 'W': /* turn double-width printing on/off */ if (!dev->multipoint_mode) { dev->hmi = -1; if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) @@ -1143,7 +1257,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x58: /* select font by pitch and point (ESC X) */ + case 'X': /* select font by pitch and point */ dev->multipoint_mode = 1; /* Copy currently non-multipoint CPI if no value was set so far. */ if (dev->multipoint_cpi == 0.0) { @@ -1165,17 +1279,17 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x59: /* select 120-dpi, double-speed graphics (ESC Y) */ + case 'Y': /* select 120-dpi, double-speed graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_y, PARAM16(0)); break; - case 0x5a: /* select 240-dpi graphics (ESC Z) */ + case 'Z': /* select 240-dpi graphics */ /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_z, PARAM16(0)); break; - case 0x5c: /* set relative horizontal print pos (ESC \) */ + case '\\': /* set relative horizontal print pos */ rel_move = PARAM16(0); unit_size = dev->defined_unit; if (unit_size < 0) @@ -1183,16 +1297,16 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_x += ((double) rel_move / unit_size); break; - case 0x61: /* select justification (ESC a) */ + case 'a': /* select justification */ /* Ignore. */ break; - case 0x63: /* set horizontal motion index (HMI) (ESC c) */ + case 'c': /* set horizontal motion index (HMI) */ dev->hmi = (double) PARAM16(0) / 360.0; dev->extra_intra_space = 0.0; break; - case 0x67: /* select 10.5-point, 15-cpi (ESC g) */ + case 'g': /* select 10.5-point, 15-cpi */ dev->cpi = 15; dev->hmi = -1; dev->multipoint_mode = 0; @@ -1204,7 +1318,7 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing *= -1; break; - case 0x6a: // Reverse paper feed (ESC j) + case 'j': // Reverse paper feed (ESC j) reverse = (double) PARAM16(0) / (double) 216.0; reverse = dev->curr_y - reverse; if (reverse < dev->left_margin) @@ -1213,20 +1327,20 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_y = reverse; break; - case 0x6b: /* select typeface (ESC k) */ + case 'k': /* select typeface */ if ((dev->esc_parms[0] <= 11) || (dev->esc_parms[0] == 30) || (dev->esc_parms[0] == 31)) dev->lq_typeface = dev->esc_parms[0]; update_font(dev); break; - case 0x6c: /* set left margin (ESC 1) */ + case 'l': /* set left margin */ dev->left_margin = ((double) dev->esc_parms[0] - 1.0) / dev->cpi; if (dev->curr_x < dev->left_margin) dev->curr_x = dev->left_margin; break; - case 0x70: /* Turn proportional mode on/off (ESC p) */ + case 'p': /* Turn proportional mode on/off */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_PROP; if ((dev->esc_parms[0] == 1) || (dev->esc_parms[0] == '1')) { @@ -1238,18 +1352,18 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x72: /* select printing color (ESC r) */ + case 'r': /* select printing color */ if (dev->esc_parms[0] == 0 || dev->esc_parms[0] > 6) dev->color = COLOR_BLACK; else dev->color = dev->esc_parms[0] << 5; break; - case 0x73: /* select low-speed mode (ESC s) */ + case 's': /* select low-speed mode */ /* Ignore. */ break; - case 0x74: /* select character table (ESC t) */ + case 't': /* select character table */ case 0x849: /* Select character table (FS I) */ if (dev->esc_parms[0] < 4) { dev->curr_char_table = dev->esc_parms[0]; @@ -1260,7 +1374,7 @@ process_char(escp_t *dev, uint8_t ch) update_font(dev); break; - case 0x77: /* turn double-height printing on/off (ESC w) */ + case 'w': /* turn double-height printing on/off */ if (!dev->multipoint_mode) { if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) dev->font_style &= ~STYLE_DOUBLEHEIGHT; @@ -1270,7 +1384,7 @@ process_char(escp_t *dev, uint8_t ch) } break; - case 0x78: /* select LQ or draft (ESC x) */ + case 'x': /* select LQ or draft */ if ((dev->esc_parms[0] == 0) || (dev->esc_parms[0] == '0')) { dev->print_quality = QUALITY_DRAFT; dev->font_style |= STYLE_CONDENSED; @@ -1523,9 +1637,12 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_seen = 1; return 1; - case 0x1c: /* FS (IBM commands) */ - dev->fss_seen = 1; - return 1; + case 0x1c: /* FS (IBM Proprinter II) + TODO: Make an IBM printer. */ + if (dev->lang == LANG_ESCP2) { + dev->fss_seen = 1; + return 1; + } default: /* This is a printable character -> print it. */ @@ -1998,6 +2115,8 @@ escp_init(const device_t *info) dev->lpt = lpt_attach(write_data, write_ctrl, strobe, read_status, read_ctrl, NULL, NULL, dev); + dev->lang = device_get_config_int("language"); + rom_get_full_path(dev->fontpath, "roms/printer/fonts/"); /* Create a full pathname for the font files. */ @@ -2014,9 +2133,28 @@ escp_init(const device_t *info) plat_dir_create(dev->pagepath); path_slash(dev->pagepath); - dev->page_width = PAGE_WIDTH; - dev->page_height = PAGE_HEIGHT; - dev->dpi = PAGE_DPI; + dev->paper_size = device_get_config_int("paper_size"); + + switch (dev->paper_size) { + case PAPER_A4: + dev->page_width = A4_PAGE_WIDTH; + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + dev->page_width = LEGAL_PAGE_HEIGHT; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + dev->page_width = B4_PAGE_HEIGHT; + break; + case PAPER_LETTER: + default: + dev->page_width = LETTER_PAGE_WIDTH; + dev->page_height = LETTER_PAGE_HEIGHT; + } + + dev->dpi = dev->lang >= LANG_ESCP ? 360 : 240; /* Create 8-bit grayscale buffer for the page. */ dev->page = (psurface_t *) malloc(sizeof(psurface_t)); @@ -2089,7 +2227,30 @@ escp_close(void *priv) // clang-format off #if 0 +static const device_config_t lpt_prt_escp_config[] = { + { .name = "", .description = "", .type = CONFIG_END } +}; +#endif static const device_config_t lpt_prt_escp_config[] = { + { + .name = "language", + .description = "Language", + .type = CONFIG_SELECTION, + .default_string = NULL, + .default_int = LANG_ESCP2, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { + { .description = "EX-1000", .value = LANG_EX1000 }, +#if 0 + { .description = "9-pin", .value = LANG_9PIN }, + { .description = "ESC/P", .value = LANG_ESCP }, +#endif + { .description = "ESC/P 2", .value = LANG_ESCP2 }, + { .description = "" } + }, + .bios = { { 0 } } + }, { .name = "paper_size", .description = "Paper Size", @@ -2099,15 +2260,16 @@ static const device_config_t lpt_prt_escp_config[] = { .file_filter = NULL, .spinner = { 0 }, .selection = { - { .description = "Letter", .value = 0 }, - { .description = "A4", .value = 1 }, + { .description = "Letter", .value = PAPER_LETTER }, + { .description = "A4", .value = PAPER_A4 }, + { .description = "Legal (sideways)", .value = PAPER_LEGAL_SIDE }, + { .description = "B4 (sideways)", .value = PAPER_B4_SIDE }, { .description = "" } }, .bios = { { 0 } } }, { .name = "", .description = "", .type = CONFIG_END } }; -#endif // clang-format on const device_t lpt_prt_escp_device = { @@ -2121,9 +2283,5 @@ const device_t lpt_prt_escp_device = { .available = NULL, .speed_changed = NULL, .force_redraw = NULL, -#if 0 .config = lpt_prt_escp_config -#else - .config = NULL -#endif }; From c850beccc9cc9f2acd279599f59f41032bd13a2f Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 15:01:34 +0100 Subject: [PATCH 11/26] ESC/P 2: Implement ESC 3, A, M, P, \ for 9-pin ESC/P Also removed forward declarations. --- src/printer/prt_escp.c | 867 ++++++++++++++++++++--------------------- 1 file changed, 425 insertions(+), 442 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index e87fa88db33..b49589ee0a9 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -267,23 +267,6 @@ typedef struct escp_t { PALETTE palcol; } escp_t; -static void -update_font(escp_t *dev); -static void -blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add); -static void -draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken); -static void -init_codepage(escp_t *dev, uint16_t num); -static void -reset_printer(escp_t *dev); -static void -setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns); -static void -print_bit_graph(escp_t *dev, uint8_t ch); -static void -new_page(escp_t *dev, int8_t save, int8_t resetx); - /* Codepage table, needed for ESC t ( */ static const uint16_t codepages[15] = { 0, 437, 932, 850, 851, 853, 855, 860, @@ -432,93 +415,6 @@ fill_palette(uint8_t redmax, uint8_t greenmax, uint8_t bluemax, uint8_t colorID, } } -static void -reset_printer(escp_t *dev) -{ - dev->top_margin = dev->left_margin = 0.0; - dev->right_margin = dev->page_width; - switch (dev->paper_size) { - case PAPER_A4: - dev->page_height = A4_PAGE_HEIGHT; - break; - case PAPER_LEGAL_SIDE: - dev->page_height = LEGAL_PAGE_WIDTH; - break; - case PAPER_B4_SIDE: - dev->page_height = B4_PAGE_WIDTH; - break; - case PAPER_LETTER: - default: - dev->page_height = LETTER_PAGE_HEIGHT; - } - dev->bottom_margin = dev->page_height; - /* TODO: these should be configurable. */ - dev->color = COLOR_BLACK; - dev->curr_x = dev->curr_y = 0.0; - dev->esc_seen = 0; - dev->fss_seen = 0; - dev->esc_pending = 0; - dev->esc_parms_req = dev->esc_parms_curr = 0; - dev->lpi = PAGE_LPI; - dev->linespacing = 1.0 / dev->lpi; - dev->cpi = PAGE_CPI; - dev->curr_char_table = 1; - dev->font_style = 0; - dev->print_quality = QUALITY_DRAFT; - dev->extra_intra_space = 0.0; - dev->print_upper_control = 1; - dev->bg_remaining_bytes = 0; - dev->density_k = 0; - dev->density_l = 1; - dev->density_y = 2; - dev->density_z = 3; - dev->char_tables[0] = 0; /* italics */ - dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ - dev->defined_unit = -1.0; - dev->multipoint_mode = 0; - dev->multipoint_size = 0.0; - dev->multipoint_cpi = 0.0; - dev->hmi = -1; - dev->msb = 255; - dev->print_everything_count = 0; - dev->lq_typeface = TYPEFACE_COURIER; - - init_codepage(dev, dev->char_tables[dev->curr_char_table]); - - update_font(dev); - - new_page(dev, 0, 1); - - for (uint8_t i = 0; i < 32; i++) - dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); - dev->num_horizontal_tabs = 32; - dev->num_vertical_tabs = -1; - - if (dev->page != NULL) - dev->page->dirty = 0; - - escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", - dev->page_width, dev->page_height, (int) dev->dpi, - (int) dev->cpi, (int) dev->lpi); -} - -static void -reset_printer_hard(escp_t *dev) -{ - dev->ack = 0; - timer_disable(&dev->pulse_timer); - timer_stop(&dev->timeout_timer); - reset_printer(dev); -} - -/* Select a ASCII->Unicode mapping by CP number */ -static void -init_codepage(escp_t *dev, uint16_t num) -{ - /* Get the codepage map for this number. */ - select_codepage(num, dev->curr_cpmap); -} - static void update_font(escp_t *dev) { @@ -633,113 +529,312 @@ update_font(escp_t *dev) } } -/* This is the actual ESC/P interpreter. */ -static int -process_char(escp_t *dev, uint8_t ch) +/* Select a ASCII->Unicode mapping by CP number */ +static void +init_codepage(escp_t *dev, uint16_t num) { - double new_x; - double new_y; - double move_to; - double unit_size; - double reverse; - double new_top; - double new_bottom; - uint16_t rel_move; - int16_t i; + /* Get the codepage map for this number. */ + select_codepage(num, dev->curr_cpmap); +} - escp_log("Esc_seen=%d, fss_seen=%d\n", dev->esc_seen, dev->fss_seen); - /* Determine number of additional command params that are expected. */ - if (dev->esc_seen || dev->fss_seen) { - dev->esc_pending = ch; - if (dev->fss_seen) - dev->esc_pending |= 0x800; - dev->esc_seen = dev->fss_seen = 0; - dev->esc_parms_curr = 0; +static void +reset_printer(escp_t *dev) +{ + dev->top_margin = dev->left_margin = 0.0; + dev->right_margin = dev->page_width; + switch (dev->paper_size) { + case PAPER_A4: + dev->page_height = A4_PAGE_HEIGHT; + break; + case PAPER_LEGAL_SIDE: + dev->page_height = LEGAL_PAGE_WIDTH; + break; + case PAPER_B4_SIDE: + dev->page_height = B4_PAGE_WIDTH; + break; + case PAPER_LETTER: + default: + dev->page_height = LETTER_PAGE_HEIGHT; + } + dev->bottom_margin = dev->page_height; + /* TODO: these should be configurable. */ + dev->color = COLOR_BLACK; + dev->curr_x = dev->curr_y = 0.0; + dev->esc_seen = 0; + dev->fss_seen = 0; + dev->esc_pending = 0; + dev->esc_parms_req = dev->esc_parms_curr = 0; + dev->lpi = PAGE_LPI; + dev->linespacing = 1.0 / dev->lpi; + dev->cpi = PAGE_CPI; + dev->curr_char_table = 1; + dev->font_style = 0; + dev->print_quality = QUALITY_DRAFT; + dev->extra_intra_space = 0.0; + dev->print_upper_control = 1; + dev->bg_remaining_bytes = 0; + dev->density_k = 0; + dev->density_l = 1; + dev->density_y = 2; + dev->density_z = 3; + dev->char_tables[0] = 0; /* italics */ + dev->char_tables[1] = dev->char_tables[2] = dev->char_tables[3] = 437; /* all other tables use CP437 */ + dev->defined_unit = -1.0; + dev->multipoint_mode = 0; + dev->multipoint_size = 0.0; + dev->multipoint_cpi = 0.0; + dev->hmi = -1; + dev->msb = 255; + dev->print_everything_count = 0; + dev->lq_typeface = TYPEFACE_COURIER; - escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); - switch (dev->esc_pending) { - case 0x02: // Undocumented - case 0x0e: // Select double-width printing (one line) (ESC SO) - case 0x0f: // Select condensed printing (ESC SI) - case '#': // Cancel MSB control - case '0': // Select 1/8-inch line spacing - case '1': // Select 7/60-inch line spacing - case '2': // Select 1/6-inch line spacing - case '4': // Select italic font - case '5': // Cancel italic font - case '6': // Enable printing of upper control codes - case '7': // Enable upper control codes - case '8': // Disable paper-out detector - case '9': // Enable paper-out detector - case '<': // Unidirectional mode (one line) - case '=': // Set MSB to 0 - case '>': // Set MSB to 1 - case '@': // Initialize printer - case 'E': // Select bold font - case 'F': // Cancel bold font - case 'G': // Select double-strike printing - case 'H': // Cancel double-strike printing - case 'M': // Select 10.5-point, 12-cpi - case 'O': // Cancel bottom margin - case 'P': // Select 10.5-point, 10-cpi - case 'T': // Cancel superscript/subscript printing - case '^': // Enable printing of all character codes on next character - dev->esc_parms_req = 0; - break; - case 'g': // Select 10.5-point, 15-cpi - dev->esc_parms_req = 0; - if (dev->lang == LANG_EX1000) { - dev->esc_pending = 0; - return 1; - } - break; - case 0x0a: // Reverse line feed (IBM's ESC LF) - case 0x0c: // Return to top of current page (IBM's ESC FF) - case 0x834: // Select italic font (FS 4) (= ESC 4) - case 0x835: // Cancel italic font (FS 5) (= ESC 5) - case 0x846: // Select forward feed mode (FS F) - case 0x852: // Select reverse feed mode (FS R) - dev->esc_parms_req = 0; - if (dev->lang < LANG_ESCP2) { - dev->esc_pending = 0; - return 1; - } - break; + init_codepage(dev, dev->char_tables[dev->curr_char_table]); - case 'h': // Select double or quadruple size (IBM's) - case '~': // Select/Deselect slash zero (IBM's?) - case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) - case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) - case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) - case 0x843: // Select LQ type style (FS C) (= ESC k) - case 0x845: // Select character width (FS E) - case 0x849: // Select character table (FS I) (= ESC t) - case 0x853: // Select High Speed/High Density elite pitch (FS S) - case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) - if (dev->lang < LANG_ESCP2) { - dev->esc_parms_req = 0; - dev->esc_pending = 0; - return 1; - } - case '+': // Set n/360-inch line spacing - if (dev->lang < LANG_ESCP) { - dev->esc_parms_req = 0; - dev->esc_pending = 0; - return 1; - } - case 'w': // Turn double-height printing on/off - if (dev->lang == LANG_EX1000) { - dev->esc_parms_req = 0; - dev->esc_pending = 0; - return 1; - } - case 0x19: // Control paper loading/ejecting (ESC EM) - case ' ': // Set intercharacter space - case '!': // Master select - case '-': // Turn underline on/off - case '/': // Select vertical tab channel - case '3': // Set n/180-inch line spacing - case 'A': // Set n/60-inch line spacing + update_font(dev); + + new_page(dev, 0, 1); + + for (uint8_t i = 0; i < 32; i++) + dev->horizontal_tabs[i] = i * 8.0 * (1.0 / dev->cpi); + dev->num_horizontal_tabs = 32; + dev->num_vertical_tabs = -1; + + if (dev->page != NULL) + dev->page->dirty = 0; + + escp_log("ESC/P: width=%.1fin,height=%.1fin dpi=%i cpi=%i lpi=%i\n", + dev->page_width, dev->page_height, (int) dev->dpi, + (int) dev->cpi, (int) dev->lpi); +} + +static void +reset_printer_hard(escp_t *dev) +{ + dev->ack = 0; + timer_disable(&dev->pulse_timer); + timer_stop(&dev->timeout_timer); + reset_printer(dev); +} + +static void +setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) +{ + escp_log("Density=%d\n", density); + switch (density) { + case 0: + dev->bg_h_density = 60; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 1: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 2: + dev->bg_h_density = 120; + dev->bg_v_density = 60; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 3: + dev->bg_h_density = 60; + dev->bg_v_density = 240; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 1; + break; + + case 4: + dev->bg_h_density = 80; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 6: + dev->bg_h_density = 90; + dev->bg_v_density = 60; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 32: + dev->bg_h_density = 60; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 33: + dev->bg_h_density = 120; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 38: + dev->bg_h_density = 90; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 39: + dev->bg_h_density = 180; + dev->bg_v_density = 180; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 3; + break; + + case 40: + dev->bg_h_density = 360; + dev->bg_v_density = 180; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 3; + break; + + case 71: + dev->bg_h_density = 180; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + case 72: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 0; + dev->bg_bytes_per_column = 6; + break; + + case 73: + dev->bg_h_density = 360; + dev->bg_v_density = 360; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 6; + break; + + default: + escp_log("ESC/P: Unsupported bit image density %d.\n", density); + break; + } + + dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; + dev->bg_bytes_read = 0; +} + +/* This is the actual ESC/P interpreter. */ +static int +process_char(escp_t *dev, uint8_t ch) +{ + double new_x; + double new_y; + double move_to; + double unit_size; + double reverse; + double new_top; + double new_bottom; + uint16_t rel_move; + int16_t i; + + escp_log("Esc_seen=%d, fss_seen=%d\n", dev->esc_seen, dev->fss_seen); + /* Determine number of additional command params that are expected. */ + if (dev->esc_seen || dev->fss_seen) { + dev->esc_pending = ch; + if (dev->fss_seen) + dev->esc_pending |= 0x800; + dev->esc_seen = dev->fss_seen = 0; + dev->esc_parms_curr = 0; + + escp_log("Command pending=%02x, font path=%s\n", dev->esc_pending, dev->fontpath); + switch (dev->esc_pending) { + case 0x02: // Undocumented + case 0x0e: // Select double-width printing (one line) (ESC SO) + case 0x0f: // Select condensed printing (ESC SI) + case '#': // Cancel MSB control + case '0': // Select 1/8-inch line spacing + case '1': // Select 7/60-inch line spacing + case '2': // Select 1/6-inch line spacing + case '4': // Select italic font + case '5': // Cancel italic font + case '6': // Enable printing of upper control codes + case '7': // Enable upper control codes + case '8': // Disable paper-out detector + case '9': // Enable paper-out detector + case '<': // Unidirectional mode (one line) + case '=': // Set MSB to 0 + case '>': // Set MSB to 1 + case '@': // Initialize printer + case 'E': // Select bold font + case 'F': // Cancel bold font + case 'G': // Select double-strike printing + case 'H': // Cancel double-strike printing + case 'M': // Select 10.5-point, 12-cpi + case 'O': // Cancel bottom margin + case 'P': // Select 10.5-point, 10-cpi + case 'T': // Cancel superscript/subscript printing + case '^': // Enable printing of all character codes on next character + dev->esc_parms_req = 0; + break; + case 'g': // Select 10.5-point, 15-cpi + dev->esc_parms_req = 0; + if (dev->lang == LANG_EX1000) { + dev->esc_pending = 0; + return 1; + } + break; + case 0x0a: // Reverse line feed (IBM's ESC LF) + case 0x0c: // Return to top of current page (IBM's ESC FF) + case 0x834: // Select italic font (FS 4) (= ESC 4) + case 0x835: // Cancel italic font (FS 5) (= ESC 5) + case 0x846: // Select forward feed mode (FS F) + case 0x852: // Select reverse feed mode (FS R) + dev->esc_parms_req = 0; + if (dev->lang < LANG_ESCP2) { + dev->esc_pending = 0; + return 1; + } + break; + + case 'h': // Select double or quadruple size (IBM's) + case '~': // Select/Deselect slash zero (IBM's?) + case 0x832: // Select 1/6-inch line spacing (FS 2) (= ESC 2) + case 0x833: // Set n/360-inch line spacing (FS 3) (= ESC +) + case 0x841: // Set n/60-inch line spacing (FS A) (= ESC A) + case 0x843: // Select LQ type style (FS C) (= ESC k) + case 0x845: // Select character width (FS E) + case 0x849: // Select character table (FS I) (= ESC t) + case 0x853: // Select High Speed/High Density elite pitch (FS S) + case 0x856: // Turn double-height printing on/off (FS V) (= ESC w) + if (dev->lang < LANG_ESCP2) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case '+': // Set n/360-inch line spacing + if (dev->lang < LANG_ESCP) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 'w': // Turn double-height printing on/off + if (dev->lang == LANG_EX1000) { + dev->esc_parms_req = 0; + dev->esc_pending = 0; + return 1; + } + case 0x19: // Control paper loading/ejecting (ESC EM) + case ' ': // Set intercharacter space + case '!': // Master select + case '-': // Turn underline on/off + case '/': // Select vertical tab channel + case '3': // Set n/180-inch line spacing + case 'A': // Set n/60-inch line spacing case 'C': // Set page length in lines case 'I': // Select character type and print pitch case 'J': // Advance print position vertically @@ -1081,8 +1176,8 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing = 1.0 / 6.0; break; - case '3': /* set n/180-inch line spacing */ - dev->linespacing = (double) dev->esc_parms[0] / 180.0; + case '3': /* set n/180 or n/216-inch line spacing */ + dev->linespacing = (double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 180.0 : 216.0); break; case '4': /* select italic font */ @@ -1131,9 +1226,9 @@ process_char(escp_t *dev, uint8_t ch) reset_printer(dev); break; - case 'A': /* set n/60-inch line spacing */ + case 'A': /* set n/60 or n/72-inch line spacing */ case 0x841: // FS A - dev->linespacing = (double) dev->esc_parms[0] / 60.0; + dev->linespacing = (double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 60.0 : 72.0); break; case 'C': /* set page length in lines */ @@ -1293,7 +1388,7 @@ process_char(escp_t *dev, uint8_t ch) rel_move = PARAM16(0); unit_size = dev->defined_unit; if (unit_size < 0) - unit_size = (dev->print_quality == QUALITY_DRAFT ? 120.0 : 180.0); + unit_size = (dev->print_quality == QUALITY_DRAFT || dev->lang < LANG_ESCP) ? 120.0 : 180.0; dev->curr_x += ((double) rel_move / unit_size); break; @@ -1650,17 +1745,126 @@ process_char(escp_t *dev, uint8_t ch) } } +/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ static void -handle_char(escp_t *dev, uint8_t ch) +blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) { - FT_UInt char_index; - uint16_t pen_x; - uint16_t pen_y; - uint16_t line_start; - uint16_t line_y; - double x_advance; - - if (dev->page == NULL) + const FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; + uint8_t src; + uint8_t *dst; + + /* check if freetype is available */ + if (ft_lib == NULL) + return; + + for (unsigned int y = 0; y < bitmap->rows; y++) { + for (unsigned int x = 0; x < bitmap->width; x++) { + src = *(bitmap->buffer + x + y * bitmap->pitch); + /* ignore background, and respect page size */ + if (src > 0 && (destx + x < (unsigned) dev->page->w) && (desty + y < (unsigned) dev->page->h)) { + dst = (uint8_t *) dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; + src >>= 3; + + if (add) { + if (((*dst) & 0x1f) + src > 31) + *dst |= (dev->color | 0x1f); + else { + *dst += src; + *dst |= dev->color; + } + } else + *dst = src | dev->color; + } + } + } +} + +/* Draw anti-aliased line. */ +static void +draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) +{ + unsigned breakmod = dev->dpi / 15; + unsigned gapstart = (breakmod * 4) / 5; + + for (unsigned int x = from_x; x <= to_x; x++) { + /* Skip parts if broken line or going over the border. */ + if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { + if (y > 0 && (y - 1) < dev->page->h) + *((uint8_t *) dev->page->pixels + x + (y - 1) * (unsigned) dev->page->pitch) = 240; + if (y < dev->page->h) + *((uint8_t *) dev->page->pixels + x + y * (unsigned) dev->page->pitch) = !broken ? 255 : 240; + if (y + 1 < dev->page->h) + *((uint8_t *) dev->page->pixels + x + (y + 1) * (unsigned) dev->page->pitch) = 240; + } + } +} + +static void +print_bit_graph(escp_t *dev, uint8_t ch) +{ + uint8_t pixel_w; /* width of the "pixel" */ + uint8_t pixel_h; /* height of the "pixel" */ + double old_y; + + dev->bg_column[dev->bg_bytes_read++] = ch; + dev->bg_remaining_bytes--; + + /* Only print after reading a full column. */ + if (dev->bg_bytes_read < dev->bg_bytes_per_column) + return; + + old_y = dev->curr_y; + + pixel_w = 1; + pixel_h = 1; + + if (dev->bg_adjacent) { + /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ + pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; + pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; + } + + for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { + /* for each byte */ + for (uint8_t j = 128; j != 0; j >>= 1) { + /* for each bit */ + if (dev->bg_column[i] & j) { + /* draw a "pixel" */ + for (uint8_t xx = 0; xx < pixel_w; xx++) { + for (uint8_t yy = 0; yy < pixel_h; yy++) { + if (((PIXX + xx) < (unsigned) dev->page->w) && ((PIXY + yy) < (unsigned) dev->page->h)) + *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); + } + } + } + + dev->curr_y += 1.0 / (double) dev->bg_v_density; + } + } + + /* Mark page dirty. */ + dev->page->dirty = 1; + + /* Restore Y-position. */ + dev->curr_y = old_y; + + dev->bg_bytes_read = 0; + + /* Advance print head. */ + dev->curr_x += 1.0 / dev->bg_h_density; +} + +static void +handle_char(escp_t *dev, uint8_t ch) +{ + FT_UInt char_index; + uint16_t pen_x; + uint16_t pen_y; + uint16_t line_start; + uint16_t line_y; + double x_advance; + + if (dev->page == NULL) return; /* MSB mode */ @@ -1767,227 +1971,6 @@ handle_char(escp_t *dev, uint8_t ch) } } -/* TODO: This can be optimized quite a bit... I'm just too lazy right now ;-) */ -static void -blit_glyph(escp_t *dev, unsigned destx, unsigned desty, int8_t add) -{ - const FT_Bitmap *bitmap = &dev->fontface->glyph->bitmap; - uint8_t src; - uint8_t *dst; - - /* check if freetype is available */ - if (ft_lib == NULL) - return; - - for (unsigned int y = 0; y < bitmap->rows; y++) { - for (unsigned int x = 0; x < bitmap->width; x++) { - src = *(bitmap->buffer + x + y * bitmap->pitch); - /* ignore background, and respect page size */ - if (src > 0 && (destx + x < (unsigned) dev->page->w) && (desty + y < (unsigned) dev->page->h)) { - dst = (uint8_t *) dev->page->pixels + (x + destx) + (y + desty) * dev->page->pitch; - src >>= 3; - - if (add) { - if (((*dst) & 0x1f) + src > 31) - *dst |= (dev->color | 0x1f); - else { - *dst += src; - *dst |= dev->color; - } - } else - *dst = src | dev->color; - } - } - } -} - -/* Draw anti-aliased line. */ -static void -draw_hline(escp_t *dev, unsigned from_x, unsigned to_x, unsigned y, int8_t broken) -{ - unsigned breakmod = dev->dpi / 15; - unsigned gapstart = (breakmod * 4) / 5; - - for (unsigned int x = from_x; x <= to_x; x++) { - /* Skip parts if broken line or going over the border. */ - if ((!broken || (x % breakmod <= gapstart)) && (x < dev->page->w)) { - if (y > 0 && (y - 1) < dev->page->h) - *((uint8_t *) dev->page->pixels + x + (y - 1) * (unsigned) dev->page->pitch) = 240; - if (y < dev->page->h) - *((uint8_t *) dev->page->pixels + x + y * (unsigned) dev->page->pitch) = !broken ? 255 : 240; - if (y + 1 < dev->page->h) - *((uint8_t *) dev->page->pixels + x + (y + 1) * (unsigned) dev->page->pitch) = 240; - } - } -} - -static void -setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) -{ - escp_log("Density=%d\n", density); - switch (density) { - case 0: - dev->bg_h_density = 60; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 1: - dev->bg_h_density = 120; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 2: - dev->bg_h_density = 120; - dev->bg_v_density = 60; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 1; - break; - - case 3: - dev->bg_h_density = 60; - dev->bg_v_density = 240; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 1; - break; - - case 4: - dev->bg_h_density = 80; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 6: - dev->bg_h_density = 90; - dev->bg_v_density = 60; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 1; - break; - - case 32: - dev->bg_h_density = 60; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 33: - dev->bg_h_density = 120; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 38: - dev->bg_h_density = 90; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 39: - dev->bg_h_density = 180; - dev->bg_v_density = 180; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 3; - break; - - case 40: - dev->bg_h_density = 360; - dev->bg_v_density = 180; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 3; - break; - - case 71: - dev->bg_h_density = 180; - dev->bg_v_density = 360; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 6; - break; - - case 72: - dev->bg_h_density = 360; - dev->bg_v_density = 360; - dev->bg_adjacent = 0; - dev->bg_bytes_per_column = 6; - break; - - case 73: - dev->bg_h_density = 360; - dev->bg_v_density = 360; - dev->bg_adjacent = 1; - dev->bg_bytes_per_column = 6; - break; - - default: - escp_log("ESC/P: Unsupported bit image density %d.\n", density); - break; - } - - dev->bg_remaining_bytes = num_columns * dev->bg_bytes_per_column; - dev->bg_bytes_read = 0; -} - -static void -print_bit_graph(escp_t *dev, uint8_t ch) -{ - uint8_t pixel_w; /* width of the "pixel" */ - uint8_t pixel_h; /* height of the "pixel" */ - double old_y; - - dev->bg_column[dev->bg_bytes_read++] = ch; - dev->bg_remaining_bytes--; - - /* Only print after reading a full column. */ - if (dev->bg_bytes_read < dev->bg_bytes_per_column) - return; - - old_y = dev->curr_y; - - pixel_w = 1; - pixel_h = 1; - - if (dev->bg_adjacent) { - /* if page DPI is bigger than bitgraphics DPI, drawn pixels get "bigger" */ - pixel_w = dev->dpi / dev->bg_h_density > 0 ? dev->dpi / dev->bg_h_density : 1; - pixel_h = dev->dpi / dev->bg_v_density > 0 ? dev->dpi / dev->bg_v_density : 1; - } - - for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { - /* for each byte */ - for (uint8_t j = 128; j != 0; j >>= 1) { - /* for each bit */ - if (dev->bg_column[i] & j) { - /* draw a "pixel" */ - for (uint8_t xx = 0; xx < pixel_w; xx++) { - for (uint8_t yy = 0; yy < pixel_h; yy++) { - if (((PIXX + xx) < (unsigned) dev->page->w) && ((PIXY + yy) < (unsigned) dev->page->h)) - *((uint8_t *) dev->page->pixels + (PIXX + xx) + (PIXY + yy) * dev->page->pitch) |= (dev->color | 0x1f); - } - } - } - - dev->curr_y += 1.0 / (double) dev->bg_v_density; - } - } - - /* Mark page dirty. */ - dev->page->dirty = 1; - - /* Restore Y-position. */ - dev->curr_y = old_y; - - dev->bg_bytes_read = 0; - - /* Advance print head. */ - dev->curr_x += 1.0 / dev->bg_h_density; -} - static void write_data(uint8_t val, void *priv) { From 397120b28253a4041f52d4013be65d195db21cbd Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 16:26:06 +0100 Subject: [PATCH 12/26] ESC/P 2: 9-bit graphics mode (9-pin ESC/P) --- src/printer/prt_escp.c | 114 ++++++++++++++++++++++++++++++++++------- 1 file changed, 95 insertions(+), 19 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index b49589ee0a9..6269573f982 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -623,47 +623,67 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) switch (density) { case 0: dev->bg_h_density = 60; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 1: dev->bg_h_density = 120; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 2: dev->bg_h_density = 120; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 0; dev->bg_bytes_per_column = 1; break; case 3: - dev->bg_h_density = 60; - dev->bg_v_density = 240; + dev->bg_h_density = 240; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; dev->bg_adjacent = 0; dev->bg_bytes_per_column = 1; break; case 4: dev->bg_h_density = 80; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 5: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 72; + dev->bg_v_density = 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 6: dev->bg_h_density = 90; - dev->bg_v_density = 60; + dev->bg_v_density = dev->lang >= LANG_ESCP ? 60 : 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 1; + break; + + case 7: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 144; + dev->bg_v_density = 72; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 1; break; case 32: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 60; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -671,6 +691,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 33: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 120; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -678,6 +700,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 38: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 90; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -685,6 +709,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 39: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 180; dev->bg_v_density = 180; dev->bg_adjacent = 1; @@ -692,6 +718,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 40: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 360; dev->bg_v_density = 180; dev->bg_adjacent = 0; @@ -699,6 +727,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 71: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 180; dev->bg_v_density = 360; dev->bg_adjacent = 1; @@ -706,6 +736,8 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 72: + if (dev->lang < LANG_ESCP) + break; dev->bg_h_density = 360; dev->bg_v_density = 360; dev->bg_adjacent = 0; @@ -713,12 +745,32 @@ setup_bit_image(escp_t *dev, uint8_t density, uint16_t num_columns) break; case 73: + if (dev->lang < LANG_ESCP2) + break; dev->bg_h_density = 360; dev->bg_v_density = 360; dev->bg_adjacent = 1; dev->bg_bytes_per_column = 6; break; + case 254: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 120; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 2; + break; + + case 255: + if (dev->lang >= LANG_ESCP) + break; + dev->bg_h_density = 60; + dev->bg_v_density = 72; + dev->bg_adjacent = 1; + dev->bg_bytes_per_column = 2; + break; + default: escp_log("ESC/P: Unsupported bit image density %d.\n", density); break; @@ -758,14 +810,11 @@ process_char(escp_t *dev, uint8_t ch) case 0x0f: // Select condensed printing (ESC SI) case '#': // Cancel MSB control case '0': // Select 1/8-inch line spacing - case '1': // Select 7/60-inch line spacing case '2': // Select 1/6-inch line spacing case '4': // Select italic font case '5': // Cancel italic font case '6': // Enable printing of upper control codes case '7': // Enable upper control codes - case '8': // Disable paper-out detector - case '9': // Enable paper-out detector case '<': // Unidirectional mode (one line) case '=': // Set MSB to 0 case '>': // Set MSB to 1 @@ -778,7 +827,6 @@ process_char(escp_t *dev, uint8_t ch) case 'O': // Cancel bottom margin case 'P': // Select 10.5-point, 10-cpi case 'T': // Cancel superscript/subscript printing - case '^': // Enable printing of all character codes on next character dev->esc_parms_req = 0; break; case 'g': // Select 10.5-point, 15-cpi @@ -788,6 +836,15 @@ process_char(escp_t *dev, uint8_t ch) return 1; } break; + case '1': // Select 7/72-inch line spacing + case '8': // Disable paper-out detector + case '9': // Enable paper-out detector + dev->esc_parms_req = 0; + if (dev->lang >= LANG_ESCP) { + dev->esc_pending = 0; + return 1; + } + break; case 0x0a: // Reverse line feed (IBM's ESC LF) case 0x0c: // Return to top of current page (IBM's ESC FF) case 0x834: // Select italic font (FS 4) (= ESC 4) @@ -903,6 +960,16 @@ process_char(escp_t *dev, uint8_t ch) dev->esc_pending = 0; return 1; } + case '^': /* 9-pin ESC/P: Select 60/120-dpi, 9-bit graphics + IBM: Enable printing of all character codes on next character */ + if (dev->lang <= LANG_9PIN) + dev->esc_parms_req = 3; + else { + dev->esc_parms_req = 0; + if (dev->lang == LANG_ESCP) + dev->esc_pending = 0; + } + break; case '*': // Select bit image dev->esc_parms_req = 3; break; @@ -1168,8 +1235,8 @@ process_char(escp_t *dev, uint8_t ch) dev->linespacing = 1.0 / 8.0; break; - case '1': /* select 7/60-inch line spacing */ - dev->linespacing = 7.0 / 60.0; + case '1': /* select 7/72-inch line spacing */ + dev->linespacing = 7.0 / 72.0; break; case '2': /* select 1/6-inch line spacing */ @@ -1212,6 +1279,14 @@ process_char(escp_t *dev, uint8_t ch) break; case '?': /* reassign bit-image mode */ + if ((dev->esc_parms[1] == 3 || dev->esc_parms[1] == 5) && dev->lang >= LANG_ESCP) + break; + if (dev->esc_parms[1] > 7) { + if (dev->lang < LANG_ESCP) + break; + if (dev->esc_parms[1] > 40 && dev->lang < LANG_ESCP2) + break; + } if (dev->esc_parms[0] == 'K') dev->density_k = dev->esc_parms[1]; if (dev->esc_parms[0] == 'L') @@ -1267,12 +1342,10 @@ process_char(escp_t *dev, uint8_t ch) break; case 'K': /* select 60-dpi graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_k, PARAM16(0)); break; case 'L': /* select 120-dpi graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_l, PARAM16(0)); break; @@ -1375,12 +1448,10 @@ process_char(escp_t *dev, uint8_t ch) break; case 'Y': /* select 120-dpi, double-speed graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_y, PARAM16(0)); break; case 'Z': /* select 240-dpi graphics */ - /* TODO: graphics stuff */ setup_bit_image(dev, dev->density_z, PARAM16(0)); break; @@ -1392,6 +1463,10 @@ process_char(escp_t *dev, uint8_t ch) dev->curr_x += ((double) rel_move / unit_size); break; + case '^': // Select 60/120-dpi, 9-pin graphics) + setup_bit_image(dev, 255 - dev->esc_parms[0], PARAM16(0)); + break; + case 'a': /* select justification */ /* Ignore. */ break; @@ -1414,8 +1489,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 'j': // Reverse paper feed (ESC j) - reverse = (double) PARAM16(0) / (double) 216.0; - reverse = dev->curr_y - reverse; + reverse = dev->curr_y - (double) PARAM16(0) / (double) 216.0; if (reverse < dev->left_margin) dev->curr_y = dev->left_margin; else @@ -1827,6 +1901,8 @@ print_bit_graph(escp_t *dev, uint8_t ch) for (uint8_t i = 0; i < dev->bg_bytes_per_column; i++) { /* for each byte */ for (uint8_t j = 128; j != 0; j >>= 1) { + if (dev->bg_v_density == 72 && i == 1 && j != 128) // 9-bit mode from ESC ^ + break; /* for each bit */ if (dev->bg_column[i] & j) { /* draw a "pixel" */ From 686936714192c9075f9f40d9bd7d3bc16a373297 Mon Sep 17 00:00:00 2001 From: Lili1228 Date: Sat, 31 Jan 2026 21:24:29 +0100 Subject: [PATCH 13/26] ESC/P 2: Fix ESC J on 9-pin printers --- src/printer/prt_escp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/printer/prt_escp.c b/src/printer/prt_escp.c index 6269573f982..e8ccb74f97c 100644 --- a/src/printer/prt_escp.c +++ b/src/printer/prt_escp.c @@ -1336,7 +1336,7 @@ process_char(escp_t *dev, uint8_t ch) break; case 'J': /* advance print pos vertically */ - dev->curr_y += (double) ((double) dev->esc_parms[0] / 180.0); + dev->curr_y += ((double) dev->esc_parms[0] / (dev->lang >= LANG_ESCP ? 180.0 : 216.0)); if (dev->curr_y > dev->bottom_margin) new_page(dev, 1, 0); break; @@ -1460,7 +1460,8 @@ process_char(escp_t *dev, uint8_t ch) unit_size = dev->defined_unit; if (unit_size < 0) unit_size = (dev->print_quality == QUALITY_DRAFT || dev->lang < LANG_ESCP) ? 120.0 : 180.0; - dev->curr_x += ((double) rel_move / unit_size); + if (dev->curr_x + ((double) rel_move / unit_size) < dev->right_margin) + dev->curr_x += ((double) rel_move / unit_size); break; case '^': // Select 60/120-dpi, 9-pin graphics) From 156f2aaa622841bc12e8a65855d876deb43f0d62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miran=20Gr=C4=8Da?= Date: Sat, 31 Jan 2026 21:45:34 +0100 Subject: [PATCH 14/26] Update CODE_OF_CONDUCT.md --- CODE_OF_CONDUCT.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index e0aaf14104a..0fec8df133d 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -3,7 +3,7 @@ In order for everyone to enjoy their time contributing to 86Box or otherwise bei ## 1. No illegal activity or GitHub ToS violations - 1.1. Do not distribute malware for non-research purposes. Post samples in a clearly named encrypted archive. -- 1.2. Posting old software is allowed if at least 10 years old and out of support. +- 1.2. Disclosure of copyrighted materials is permitted only if they are demo/trial versions, shareware, freeware, or open-source software, or if they are disclosed by the copyright holder or on the copyright holder’s behalf. If such materials need to be disclosed for testing or bug-fixing purposes, any available private channels should be used. Developers undertake to remove any materials obtained for such purposes as soon as they are no longer needed. - 1.3. Do not post NSFW content (defined at the staff's discretion). - 1.4. Do not do anything forbidden by the law or the Discord or GitHub Terms of Service. From dbb44ebde31bd86968bcab771a381c60cea4ef38 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 04:59:26 +0100 Subject: [PATCH 15/26] Fixed session numbers in the raw TOC mode of READ TOC/PMA/ATIP and cancel sector caching on audio play if the sector to be played is not the one already cached, fixes CD Audio in Rayman for DOS. --- src/cdrom/cdrom.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/cdrom/cdrom.c b/src/cdrom/cdrom.c index e5f6ba259d4..8c781caf76f 100644 --- a/src/cdrom/cdrom.c +++ b/src/cdrom/cdrom.c @@ -692,14 +692,14 @@ read_toc_raw(const cdrom_t *dev, unsigned char *b, const unsigned char start_tra int num = 0; int len = 4; - /* Bytes 2 and 3 = Number of first and last sessions */ - read_toc_identify_sessions((raw_track_info_t *) rti, num, b); - cdrom_log(dev->log, "read_toc_raw(%016" PRIXPTR ", %016" PRIXPTR ", %02X)\n", (uintptr_t) dev, (uintptr_t) b, start_track); dev->ops->get_raw_track_info(dev->local, &num, rti); + /* Bytes 2 and 3 = Number of first and last sessions */ + read_toc_identify_sessions((raw_track_info_t *) rti, num, b); + if (num != 0) for (int i = 0; i < num; i++) if (t[i].session >= start_track) { memcpy(&(b[len]), &(t[i]), 11); @@ -1654,6 +1654,9 @@ cdrom_audio_play(cdrom_t *dev, const uint32_t pos, const uint32_t len, const int dev->cd_end = len2; dev->cd_status = CD_STATUS_PLAYING; dev->cd_buflen = 0; + + if (dev->cached_sector != dev->seek_pos) + dev->cached_sector = -1; } else { cdrom_log(dev->log, "LBA %08X not on an audio track\n", pos); cdrom_stop(dev); From 85a63dd1d64325ad19d8d410387c4ae777d4729c Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 05:29:25 +0100 Subject: [PATCH 16/26] Always load HDD audio profiles at initialization. --- src/86box.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/86box.c b/src/86box.c index 24e8be26ab9..cf992df4cfb 100644 --- a/src/86box.c +++ b/src/86box.c @@ -1494,6 +1494,7 @@ pc_init_modules(void) fdd_audio_init(); } + hdd_audio_load_profiles(); hdd_audio_init(); sound_init(); From a900405a81b5410ff775679d7ee19f5491e4ea65 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 05:51:16 +0100 Subject: [PATCH 17/26] Settings dialog: On Cancel button, remove the VM directory if it is empty, closes #6769. --- src/qt/qt_settings.hpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/qt/qt_settings.hpp b/src/qt/qt_settings.hpp index 8603c42b6ae..b64ea8e8379 100644 --- a/src/qt/qt_settings.hpp +++ b/src/qt/qt_settings.hpp @@ -30,6 +30,7 @@ class Settings : public QDialog { static Settings *settings; protected slots: void accept() override; + void reject() override; private: Ui::Settings *ui; From 378ade3d3a5a61d4cb6782031a100b9e999f0121 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 06:34:21 +0100 Subject: [PATCH 18/26] The forgotten qt/qt_settings.cpp. --- src/qt/qt_settings.cpp | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/src/qt/qt_settings.cpp b/src/qt/qt_settings.cpp index 312b48996f1..d1c25a014a0 100644 --- a/src/qt/qt_settings.cpp +++ b/src/qt/qt_settings.cpp @@ -44,6 +44,9 @@ extern "C" { #include #include +#include +#include + class SettingsModel : public QAbstractListModel { public: SettingsModel(QObject *parent) @@ -236,5 +239,36 @@ Settings::accept() return; } } + QDialog::accept(); } + +static int +plat_path_is_empty(char *path) +{ + int n = 0; + DIR *dir = opendir(path); + struct dirent *d; + + if (dir == NULL) + /* Not a directory or doesn't exist. */ + return 1; + + while ((d = readdir(dir)) != NULL) { + if (++n > 2) + break; + } + + closedir(dir); + + return (n <= 2); +} + +void +Settings::reject() +{ + if (plat_path_is_empty(usr_path)) + rmdir(usr_path); + + QDialog::reject(); +} From f66e2d5fd773ccb841bd393234f3648a972677f7 Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 07:08:53 +0100 Subject: [PATCH 19/26] Fix Ctrl+NumLock processing. --- src/qt/qt_main.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/qt/qt_main.cpp b/src/qt/qt_main.cpp index 9d55ba7caa7..8a12dd44120 100644 --- a/src/qt/qt_main.cpp +++ b/src/qt/qt_main.cpp @@ -400,7 +400,8 @@ emu_LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam) ret = CallNextHookEx(NULL, nCode, wParam, lParam); if (lpKdhs->scanCode == 0x00000045) { - if ((lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000090)) { + if ((lpKdhs->flags & LLKHF_EXTENDED) && ((lpKdhs->vkCode == 0x00000090) || + (lpKdhs->vkCode == 0x00000013))) { /* NumLock. */ lpKdhs->flags &= ~LLKHF_EXTENDED; } else if (!(lpKdhs->flags & LLKHF_EXTENDED) && (lpKdhs->vkCode == 0x00000013)) { From 37a4a99a3e3c6a9e6539a4bb3bbed690ede3167b Mon Sep 17 00:00:00 2001 From: OBattler Date: Sun, 1 Feb 2026 09:14:39 +0100 Subject: [PATCH 20/26] Make the activity indicator orange instead of green to be more easily visible for color-blind people. --- src/qt/icons/active.ico | Bin 9622 -> 9622 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/qt/icons/active.ico b/src/qt/icons/active.ico index 9569a3962ba1d76f735492b689bfd8fd1cd95839..ebd5bb4524a62656d27c8598b103f52f77c8db5c 100644 GIT binary patch literal 9622 zcmeHMJ5Iwu5S@q!geXXnB3;}dQE~%PaSkfP8K_cHA&!A4sG);9aDYhkh>`*^ys`Hs zo3GZ6<0xoG8jZcXGjI3Bo>^~1TGEzIM_@C#Zi`%qNVi+uKkth?p{>^|?r#r8u8u^q zthj%G-zUbN!Uva#P_)Cy0DfzV!k=0;l*-M^M2k3SG2nOiu6pt~(L7dajBWedD#ILX z9j0OaY3t{xY5v&i))}bGfPSdz8*~_{-CKKtSe`+;$@7inE0cTVsG5YiCbm^WPjb)n zdt|Z8$%1^s+*B$r5!K_3b9*KJjK{zs^DAwoJRAKkx&QR@!d|z|fHTk#1Nwcg`qft* z9nY(^TYm|$x`i#YoIzQ)F0q&1fW)!{d|b z#dg#D80rd){QD>M+imd*iq?R^T2C9EomHOceZa`$#WvmBM>+$}fHSbO45%Kc{_d&% zw6MpLd9`-yw{aE3_F)-x0OdYxXa|?g3HM~NZ34Z(i|Y!ntDmu^&U;+bxZjHHxZc%K zqi1J?HCmmH@s?eOI&M7GC)>m?flW?o<-qZipS^#{zr95zo`G7QJ-)%)#*a8ymWMX- z9l`a}f(QN<#G}o5xBez1%wvq%6mAo1a|~y|8E^)i0cXG&*l7lE0MW-EKsaO=;jrNq UhYqGg97xP6`)r(zH^24e4?=A9M*si- literal 9622 zcmeHMy-ve05Wb2Egc#`1p<6RD@&uPeF)|>`_t`ncazmBG zNh+1Q>f-q4?(8r2-N_Z1$W&%CL0QPdROD7f=JQa0Jr#LD+hP&wkLM!y7a~Ow>d%n- zz}PFu;1wD|I|^ArE|VPOmD{RvvWBd3(9=u@WJr*%e$>-c$D!r9%5n~VAzVwCf3x-L zD9R{no0Wz@1_Ex2&G-&pN6b3g8xZ{r+>Q4)^jD-O_^6&p&v;yRRb8DOJwxFPQg=Io z94Ycf)q5A6rY{dae!UXIbjx<~v$`AjEmPJ$D-8idU^E2W*Ntw;;wX zq|kB=*0^#!Uk1;y%yfFbZ75OD6yxt|l~z9-1B5VuoiJNr4V12GRP zz$>ukVQXGojz^j=#pM{*gT4CrqH`H)9#u@!d@C+>PJP7abOq2&+MD}nFXz$s91dx} zjqM>YF#FB--ZA3Ov)E=2VC+$yKdzrtV(^zA@|%P{Dy%=q^!=pnXdY_Q&#CO|+hnai zwH24O1Fg{zFa!(%L% Date: Sun, 1 Feb 2026 21:50:31 -0600 Subject: [PATCH 21/26] CS423x: Make bits 2-0 of control register C0 writable, fixes Win3.1 v2.02 driver invalid codec error and Win9x v2.86 driver code 10 --- src/sound/snd_cs423x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sound/snd_cs423x.c b/src/sound/snd_cs423x.c index b9004454e8c..264171b1eea 100644 --- a/src/sound/snd_cs423x.c +++ b/src/sound/snd_cs423x.c @@ -290,7 +290,7 @@ cs423x_write(uint16_t addr, uint8_t val, void *priv) ad1848_init(&dev->ad1848, dev->ad1848_type); ad1848_set_cd_audio_channel(&dev->ad1848, AD1848_AUX2); } - val = 0x00; + val &= 0x07; break; case 1: /* Version / Chip ID */ From 2d777403f91236c757104bf07e7e72681a79b54f Mon Sep 17 00:00:00 2001 From: win2kgamer <47463859+win2kgamer@users.noreply.github.com> Date: Sun, 1 Feb 2026 22:11:30 -0600 Subject: [PATCH 22/26] AD1848: Remove old CS423xB/4235/4239 I18/I19 mixer hack as it's no longer needed --- src/sound/snd_ad1848.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/sound/snd_ad1848.c b/src/sound/snd_ad1848.c index 44e328842db..181d2158e07 100644 --- a/src/sound/snd_ad1848.c +++ b/src/sound/snd_ad1848.c @@ -411,19 +411,6 @@ ad1848_write(uint16_t addr, uint8_t val, void *priv) goto readonly_i; } - /* HACK: the Windows 9x driver's "Synth" control writes to this - register with no remapping, even if internal FM is enabled. */ - if (ad1848->index == 18) { - if (val & 0x80) - ad1848->fm_vol_l = 0; - else - ad1848->fm_vol_l = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; - } else { - if (val & 0x80) - ad1848->fm_vol_r = 0; - else - ad1848->fm_vol_r = (int) ad1848_vols_5bits_aux_gain[val & 0x1f]; - } } if ((ad1848->type >= AD1848_TYPE_CS4232) && (ad1848->type <= AD1848_TYPE_CS4236)) { if (ad1848->index == 18) { From be36624ed95c516bbe7d985a7ce153474ad009be Mon Sep 17 00:00:00 2001 From: Paradyx0392 Date: Mon, 2 Feb 2026 18:28:22 +0800 Subject: [PATCH 23/26] Update de-DE.po --- src/qt/languages/de-DE.po | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 5dccc6e54ce..8d0bf7fde9b 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -55,10 +55,10 @@ msgid "&Resizeable window" msgstr "G&rößenverstellbares Fenster" msgid "R&emember size && position" -msgstr "Größe && &Position merken" +msgstr "Größe und &Position merken" msgid "Remember size && position" -msgstr "Größe && Position merken" +msgstr "Größe und Position merken" msgid "Re&nderer" msgstr "Re&nderer" @@ -742,10 +742,10 @@ msgid "Video card \"%hs\" is not available due to missing ROMs in the roms/video msgstr "Die Videokarte \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird auf eine verfügbare Videokarte gewechselt." msgid "Video card #2 \"%hs\" is not available due to missing ROMs in the roms/video directory. Disabling the second video card." -msgstr "Das Gerät \"%hs\" ist aufgrund von fehlenden ROMs nicht verfügbar. Es wird ignoriert." +msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird deaktiviert." msgid "Device \"%hs\" is not available due to missing ROMs. Ignoring the device." -msgstr "Die Videokarte 2 \"%hs\" ist aufgrund von fehlenden ROMs im Verzeichnis roms/video nicht verfügbar. Es wird deaktiviert." +msgstr "Das Gerät \"%hs\" ist aufgrund von fehlenden ROMs nicht verfügbar. Es wird ignoriert." msgid "Machine" msgstr "System" @@ -2848,10 +2848,10 @@ msgid "Hostname:" msgstr "Hostname:" msgid "ISA RAM:" -msgstr "" +msgstr "ISA RAM:" msgid "ISA ROM:" -msgstr "" +msgstr "ISA ROM:" msgid "&Wipe NVRAM" msgstr "NVRAM leeren" @@ -2869,7 +2869,7 @@ msgid "An error occurred trying to wipe the NVRAM contents of the virtual machin msgstr "Beim Leeren des NVRAMs der virtuellen Maschine ist ein Fehler aufgetreten \"%1\"" msgid "%1 VM Manager" -msgstr "" +msgstr "%1 VM-Manager" msgid "%n disk(s)" msgstr "%n Festplatte(n)" From 9d94482040960404f4409bac778ce8b58e706109 Mon Sep 17 00:00:00 2001 From: Paradyx0392 Date: Mon, 2 Feb 2026 18:33:10 +0800 Subject: [PATCH 24/26] Update de-DE.po --- src/qt/languages/de-DE.po | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/qt/languages/de-DE.po b/src/qt/languages/de-DE.po index 8d0bf7fde9b..d0e649bc2d0 100644 --- a/src/qt/languages/de-DE.po +++ b/src/qt/languages/de-DE.po @@ -2869,7 +2869,7 @@ msgid "An error occurred trying to wipe the NVRAM contents of the virtual machin msgstr "Beim Leeren des NVRAMs der virtuellen Maschine ist ein Fehler aufgetreten \"%1\"" msgid "%1 VM Manager" -msgstr "%1 VM-Manager" +msgstr "%1 VM Manager" msgid "%n disk(s)" msgstr "%n Festplatte(n)" From d7f011e85ffe9164ad775e711bd2a47d67e73639 Mon Sep 17 00:00:00 2001 From: Maxwell Scott Date: Mon, 2 Feb 2026 20:04:32 +0700 Subject: [PATCH 25/26] Added Olivetti OEM BIOS to TriGem Como The Olivetti OEM BIOS' date (06/05/99) is newer than the current one (01/18/99). Until the actual voltage and multiplier bus speeds are found, I adjusted them to match other i440LX/EX machines. Also added a note about onboard video. --- src/include/86box/machine.h | 3 ++ src/machine/m_at_slot1.c | 65 ++++++++++++++++++++++++++++++++++--- src/machine/machine_table.c | 13 ++++---- 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/include/86box/machine.h b/src/include/86box/machine.h index caf929c1946..ea5d5625762 100644 --- a/src/include/86box/machine.h +++ b/src/include/86box/machine.h @@ -1210,6 +1210,9 @@ extern int machine_at_ma30d_init(const machine_t *); /* i440EX */ extern int machine_at_brio83xx_init(const machine_t *); extern int machine_at_p6i440e2_init(const machine_t *); +#ifdef EMU_DEVICE_H +extern const device_t como_device; +#endif extern int machine_at_como_init(const machine_t *); /* i440BX */ diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index cbd0cdec5fd..efd5d5d6fe5 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -544,17 +544,72 @@ machine_at_brio83xx_init(const machine_t *model) return ret; } +static const device_config_t como_config[] = { + // clang-format off + { + .name = "bios", + .description = "BIOS Version", + .type = CONFIG_BIOS, + .default_string = "como", + .default_int = 0, + .file_filter = NULL, + .spinner = { 0 }, + .selection = { { 0 } }, + .bios = { + { + .name = "AMIBIOS 6 (071595) - Revision 1.08 (Olivetti OEM)", + .internal_name = "como_olivetti", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/como/COMO_Olivetti_OEM.ROM", "" } + }, + { + .name = "AMIBIOS 6 (071595) - Revision 1.12", + .internal_name = "como", + .bios_type = BIOS_NORMAL, + .files_no = 1, + .local = 0, + .size = 262144, + .files = { "roms/machines/como/COMO.ROM", "" } + }, + { .files_no = 0 } + } + }, + { .name = "", .description = "", .type = CONFIG_END } + // clang-format on +}; + +const device_t como_device = { + .name = "TriGem Como", + .internal_name = "como_device", + .flags = 0, + .local = 0, + .init = NULL, + .close = NULL, + .reset = NULL, + .available = NULL, + .speed_changed = NULL, + .force_redraw = NULL, + .config = como_config +}; + int machine_at_como_init(const machine_t *model) { - int ret; - - ret = bios_load_linear("roms/machines/como/COMO.ROM", - 0x000c0000, 262144, 0); + int ret = 0; + const char *fn; - if (bios_only || !ret) + /* No ROMs available */ + if (!device_available(model->device)) return ret; + device_context(model->device); + fn = device_get_bios_file(machine_get_device(machine), device_get_config_bios("bios"), 0); + ret = bios_load_linear(fn, 0x000c0000, 262144, 0); + device_context_restore(); + machine_at_common_init_ex(model, 2); pci_init(PCI_CONFIG_TYPE_1); diff --git a/src/machine/machine_table.c b/src/machine/machine_table.c index ca484969d93..bf13025ff78 100644 --- a/src/machine/machine_table.c +++ b/src/machine/machine_table.c @@ -18511,10 +18511,11 @@ const machine_t machines[] = { .block = CPU_BLOCK(CPU_CYRIX3S), .min_bus = 66666667, .max_bus = 83333333, - .min_voltage = 2050, - .max_voltage = 3100, - .min_multi = 3.5, - .max_multi = 5.0 + /* TODO: to find the actual voltage and multiplier bus speeds. */ + .min_voltage = 1800, + .max_voltage = 3500, + .min_multi = 1.5, + .max_multi = 8.0 }, .bus_flags = MACHINE_PS2_PCI | MACHINE_BUS_USB, .flags = MACHINE_IDE_DUAL | MACHINE_SOUND | MACHINE_APM | MACHINE_ACPI | MACHINE_USB, @@ -18531,11 +18532,11 @@ const machine_t machines[] = { .kbc_p1 = 0x00000cf0, .gpio = 0xffffffff, .gpio_acpi = 0xffffffff, - .device = NULL, + .device = &como_device, .kbd_device = NULL, .fdc_device = NULL, .sio_device = NULL, - .vid_device = NULL, + .vid_device = NULL, /* Onboard video not yet emulated: ATi Rage IIc AGP */ .snd_device = &cs4235_onboard_device, .net_device = NULL }, From 6829fee32af5cabf8ecbfdb544a29affbd68dd9a Mon Sep 17 00:00:00 2001 From: Maxwell Scott Date: Mon, 2 Feb 2026 20:36:03 +0700 Subject: [PATCH 26/26] Added "eMachines OEM" name to revision 1.12 According to their 1.12 BIOS' first POST screen, it appears to be distributed by eMachines. --- src/machine/m_at_slot1.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/machine/m_at_slot1.c b/src/machine/m_at_slot1.c index efd5d5d6fe5..a40fac2dde5 100644 --- a/src/machine/m_at_slot1.c +++ b/src/machine/m_at_slot1.c @@ -566,7 +566,7 @@ static const device_config_t como_config[] = { .files = { "roms/machines/como/COMO_Olivetti_OEM.ROM", "" } }, { - .name = "AMIBIOS 6 (071595) - Revision 1.12", + .name = "AMIBIOS 6 (071595) - Revision 1.12 (eMachines OEM)", .internal_name = "como", .bios_type = BIOS_NORMAL, .files_no = 1,