From 79134f3b21648d280f56303a2c43d92821565eb5 Mon Sep 17 00:00:00 2001 From: OBattler Date: Mon, 17 Mar 2025 03:40:52 +0100 Subject: [PATCH] Assorted Cyrix (and Codegen opcode Mod R/M passing table) fixes - fixes Windows 98 SE on Cyrix 6x86's with power management enabled. --- src/codegen/codegen_x86-64.c | 8 +++--- src/codegen/codegen_x86.c | 8 +++--- src/codegen_new/codegen.c | 8 +++--- src/cpu/386_common.c | 50 +++++++++++++++++++++++++++++++++++- src/cpu/x86.h | 6 +++++ src/cpu/x86_ops_cyrix.h | 11 ++++++-- src/cpu/x86_ops_rep.h | 2 ++ src/cpu/x86_ops_rep_2386.h | 2 ++ src/cpu/x86_ops_rep_dyn.h | 2 ++ src/cpu/x86seg.c | 10 +++----- src/io.c | 16 ++++++++++++ 11 files changed, 102 insertions(+), 21 deletions(-) diff --git a/src/codegen/codegen_x86-64.c b/src/codegen/codegen_x86-64.c index 04c2136ff..00db630a3 100644 --- a/src/codegen/codegen_x86-64.c +++ b/src/codegen/codegen_x86-64.c @@ -499,14 +499,14 @@ static int opcode_modrm[256] = { int opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/codegen/codegen_x86.c b/src/codegen/codegen_x86.c index df0ed3bfd..935e2bab6 100644 --- a/src/codegen/codegen_x86.c +++ b/src/codegen/codegen_x86.c @@ -1643,14 +1643,14 @@ static int opcode_modrm[256] = { int opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/codegen_new/codegen.c b/src/codegen_new/codegen.c index 39ab69b3d..82f6cd037 100644 --- a/src/codegen_new/codegen.c +++ b/src/codegen_new/codegen.c @@ -359,14 +359,14 @@ static uint8_t opcode_modrm[256] = { static uint8_t opcode_0f_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, /*00*/ - 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, /*30*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, /*50*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ - 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + 0, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index 8a2bb4ab8..5b0e1a5c4 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -107,6 +107,12 @@ uint32_t backupregs[16]; x86seg _oldds; +uint8_t rep_op = 0x00; +uint8_t is_smint = 0; + +uint16_t io_port = 0x0000; +uint32_t io_val = 0x00000000; + int opcode_has_modrm[256] = { 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ @@ -1215,7 +1221,7 @@ smram_restore_state_amd_k(uint32_t *saved_state) } static void -smram_save_state_cyrix(uint32_t *saved_state, UNUSED(int in_hlt)) +smram_save_state_cyrix(uint32_t *saved_state, int in_hlt) { saved_state[0] = dr[7]; saved_state[1] = cpu_state.flags | (cpu_state.eflags << 16); @@ -1224,6 +1230,35 @@ smram_save_state_cyrix(uint32_t *saved_state, UNUSED(int in_hlt)) saved_state[4] = cpu_state.pc; saved_state[5] = CS | (CPL << 21); saved_state[6] = 0x00000000; + saved_state[7] = 0x00010000; + + if (((opcode >= 0x6e) && (opcode <= 0x6f)) || ((opcode >= 0xe6) && (opcode <= 0xe7)) || + ((opcode >= 0xee) && (opcode <= 0xef))) { + saved_state[6] |= 0x00000002; + saved_state[7] = (opcode & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } else if (((opcode == 0xf2) || (opcode == 0xf3)) && (rep_op >= 0x6e) && (rep_op <= 0x6f)) { + saved_state[6] |= 0x00000006; + saved_state[7] = (rep_op & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } else if (((opcode == 0xf2) || (opcode == 0xf3)) && (rep_op >= 0x6e) && (rep_op <= 0x6f)) { + saved_state[6] |= 0x00000004; + saved_state[7] = (rep_op & 0x01) ? (cpu_state.op32 ? 0x000f0000 : 0x00030000) : 0x00010000; + } + + if (is_smint) { + saved_state[6] |= 0x00000008; + is_smint = 0; + } + + if (in_hlt) + saved_state[6] |= 0x00000010; + + saved_state[7] |= io_port; + saved_state[8] = io_val; + + if (saved_state[6] & 0x00000002) + saved_state[9] = ESI; + else + saved_state[9] = EDI; } static void @@ -1234,6 +1269,13 @@ smram_restore_state_cyrix(uint32_t *saved_state) cpu_state.eflags = saved_state[1] >> 16; cr0 = saved_state[2]; cpu_state.pc = saved_state[4]; + /* Restore CPL. */ + cpu_state.seg_cs.access = (cpu_state.seg_cs.access & ~0x9f) | (((saved_state[5] >> 21) & 0x03) << 5); + + if (saved_state[6] & 0x00000002) + ESI = saved_state[9]; + else + EDI = saved_state[9]; } void @@ -1368,6 +1410,9 @@ enter_smm(int in_hlt) writememl(0, smram_state - 0x14, saved_state[4]); writememl(0, smram_state - 0x18, saved_state[5]); writememl(0, smram_state - 0x24, saved_state[6]); + writememl(0, smram_state - 0x28, saved_state[7]); + writememl(0, smram_state - 0x2c, saved_state[8]); + writememl(0, smram_state - 0x30, saved_state[9]); } else { for (uint8_t n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { smram_state -= 4; @@ -1452,6 +1497,9 @@ leave_smm(void) else cyrix_load_seg_descriptor_2386(smram_state - 0x20, &cpu_state.seg_cs); saved_state[6] = readmeml(0, smram_state - 0x24); + saved_state[7] = readmeml(0, smram_state - 0x28); + saved_state[8] = readmeml(0, smram_state - 0x2c); + saved_state[9] = readmeml(0, smram_state - 0x30); } else { for (uint8_t n = 0; n < SMM_SAVE_STATE_MAP_SIZE; n++) { smram_state -= 4; diff --git a/src/cpu/x86.h b/src/cpu/x86.h index 327af8964..ccfeadea0 100644 --- a/src/cpu/x86.h +++ b/src/cpu/x86.h @@ -103,4 +103,10 @@ extern int fpu_cycles; extern void x86illegal(void); +extern uint8_t rep_op; +extern uint8_t is_smint; + +extern uint16_t io_port; +extern uint32_t io_val; + #endif /*EMU_X86_H*/ diff --git a/src/cpu/x86_ops_cyrix.h b/src/cpu/x86_ops_cyrix.h index 8c3d6e155..ac864cd20 100644 --- a/src/cpu/x86_ops_cyrix.h +++ b/src/cpu/x86_ops_cyrix.h @@ -63,18 +63,23 @@ opRSDC_common(uint32_t fetchdat) switch (rmdat & 0x38) { case 0x00: /*ES*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_es); + ES = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x18: /*DS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_ds); + DS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x10: /*SS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_ss); + SS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x20: /*FS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_fs); + FS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; case 0x28: /*GS*/ cyrix_load_seg_descriptor(easeg + cpu_state.eaaddr, &cpu_state.seg_gs); + GS = readmemw(0, easeg + cpu_state.eaaddr + 8); break; default: x86illegal(); @@ -216,8 +221,10 @@ opSMINT(UNUSED(uint32_t fetchdat)) { if (in_smm) fatal("opSMINT\n"); - else - x86illegal(); + else { + is_smint = 1; + enter_smm(0); + } return 1; } diff --git a/src/cpu/x86_ops_rep.h b/src/cpu/x86_ops_rep.h index c75684d31..6449912e9 100644 --- a/src/cpu/x86_ops_rep.h +++ b/src/cpu/x86_ops_rep.h @@ -855,6 +855,7 @@ opREPNE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -869,6 +870,7 @@ opREPE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86_ops_rep_2386.h b/src/cpu/x86_ops_rep_2386.h index aa1984f81..3b96d54e3 100644 --- a/src/cpu/x86_ops_rep_2386.h +++ b/src/cpu/x86_ops_rep_2386.h @@ -843,6 +843,7 @@ opREPNE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_2386_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -857,6 +858,7 @@ opREPE(uint32_t fetchdat) CLOCK_CYCLES(2); PREFETCH_PREFIX(); + rep_op = fetchdat & 0xff; if (x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_2386_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_2386_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86_ops_rep_dyn.h b/src/cpu/x86_ops_rep_dyn.h index bdb721ab0..1220c0da3 100644 --- a/src/cpu/x86_ops_rep_dyn.h +++ b/src/cpu/x86_ops_rep_dyn.h @@ -761,6 +761,7 @@ opREPNE(uint32_t fetchdat) cpu_state.pc++; CLOCK_CYCLES(2); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPNE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); @@ -774,6 +775,7 @@ opREPE(uint32_t fetchdat) cpu_state.pc++; CLOCK_CYCLES(2); + rep_op = fetchdat & 0xff; if (x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32]) return x86_opcodes_REPE[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); return x86_opcodes[(fetchdat & 0xff) | cpu_state.op32](fetchdat >> 8); diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index cd393812d..2a0601661 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -2581,19 +2581,17 @@ cyrix_load_seg_descriptor(uint32_t addr, x86seg *seg) cpu_cur_status &= ~CPU_STATUS_NOTFLATDS; else cpu_cur_status |= CPU_STATUS_NOTFLATDS; -#ifdef USE_DYNAREC - codegen_flat_ds = 0; -#endif } + + if (seg == &cpu_state.seg_cs) + set_use32(segdat[3] & 0x40); + if (seg == &cpu_state.seg_ss) { if (seg->base == 0 && seg->limit_low == 0 && seg->limit_high == 0xffffffff) cpu_cur_status &= ~CPU_STATUS_NOTFLATSS; else cpu_cur_status |= CPU_STATUS_NOTFLATSS; set_stack32((segdat[3] & 0x40) ? 1 : 0); -#ifdef USE_DYNAREC - codegen_flat_ss = 0; -#endif } } } diff --git a/src/io.c b/src/io.c index 27f8503b0..9554c971d 100644 --- a/src/io.c +++ b/src/io.c @@ -28,6 +28,7 @@ #include <86box/io.h> #include <86box/timer.h> #include "cpu.h" +#include "x86.h" #include <86box/m_amstrad.h> #include <86box/pci.h> @@ -344,6 +345,8 @@ inb(uint16_t port) int qfound = 0; #endif + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -408,6 +411,9 @@ outb(uint16_t port, uint8_t val) int qfound = 0; #endif + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -464,6 +470,8 @@ inw(uint16_t port) #endif uint8_t ret8[2]; + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -540,6 +548,9 @@ outw(uint16_t port, uint16_t val) int qfound = 0; #endif + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -612,6 +623,8 @@ inl(uint16_t port) int qfound = 0; #endif + io_port = port; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif @@ -720,6 +733,9 @@ outl(uint16_t port, uint32_t val) #endif int i = 0; + io_port = port; + io_val = val; + #ifdef USE_DEBUG_REGS_486 io_debug_check_addr(port); #endif