diff --git a/src/cpu/386.c b/src/cpu/386.c index 3e96911ba..657bd0894 100644 --- a/src/cpu/386.c +++ b/src/cpu/386.c @@ -212,11 +212,11 @@ fetch_ea_16_long(uint32_t rmdat) #define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) #define CHECK_READ_CS(size) \ - if ((cpu_state.pc < cpu_state.seg_cs.limit_low) || \ - ((cpu_state.pc + size - 1) > cpu_state.seg_cs.limit_high)) \ - x86gpf("Limit check (READ)", 0); \ if (msw & 1 && !(cpu_state.eflags & VM_FLAG) && !(cpu_state.seg_cs.access & 0x80)) \ x86np("Read from seg not present", cpu_state.seg_cs.seg & 0xfffc); \ + else if ((cpu_state.pc < cpu_state.seg_cs.limit_low) || \ + ((cpu_state.pc + size - 1) > cpu_state.seg_cs.limit_high)) \ + x86gpf("Limit check (READ CS)", 0); #include "386_ops.h" @@ -261,7 +261,13 @@ exec386_2386(int32_t cycs) fetchdat = fastreadl_fetch(cs + cpu_state.pc); ol = opcode_length[fetchdat & 0xff]; - CHECK_READ_CS(MIN(ol, 4)); + if ((ol == 3) && opcode_has_modrm[fetchdat & 0xff] && (((fetchdat >> 14) & 0x03) == 0x03)) + ol = 2; + if (cpu_16bitbus) { + CHECK_READ_CS(MIN(ol, 2)); + } else { + CHECK_READ_CS(MIN(ol, 4)); + } ins_fetch_fault = cpu_386_check_instruction_fault(); /* Breakpoint fault has priority over other faults. */ diff --git a/src/cpu/386_common.c b/src/cpu/386_common.c index d1d38006b..1d130cd8a 100644 --- a/src/cpu/386_common.c +++ b/src/cpu/386_common.c @@ -106,6 +106,28 @@ uint32_t backupregs[16]; x86seg _oldds; +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*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; + int opcode_length[256] = { 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 3, /* 0x0x */ 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x1x */ 3, 3, 3, 3, 3, 3, 1, 1, 3, 3, 3, 3, 3, 3, 1, 1, /* 0x2x */ diff --git a/src/cpu/386_common.h b/src/cpu/386_common.h index 6ef65771d..8ca89181c 100644 --- a/src/cpu/386_common.h +++ b/src/cpu/386_common.h @@ -449,6 +449,7 @@ get_ram_ptr(uint32_t a) } } +extern int opcode_has_modrm[256]; extern int opcode_length[256]; #ifdef OPS_286_386 diff --git a/src/cpu/x86seg.c b/src/cpu/x86seg.c index d912a755b..96ec726b0 100644 --- a/src/cpu/x86seg.c +++ b/src/cpu/x86seg.c @@ -798,6 +798,27 @@ PUSHL(uint32_t v) } } +static void +PUSHL_SEL(uint32_t v) +{ + if (cpu_16bitbus) { + PUSHW(v >> 16); + PUSHW(v & 0xffff); + } else { + if (stack32) { + writememw(ss, ESP - 4, v); + if (cpu_state.abrt) + return; + ESP -= 4; + } else { + writememw(ss, ((SP - 4) & 0xffff), v); + if (cpu_state.abrt) + return; + SP -= 4; + } + } +} + static uint16_t POPW(void) { @@ -1092,7 +1113,7 @@ loadcscall(uint16_t seg) x86seg_log("Type %04X\n", type); if (type == 0x0c00) { - PUSHL(oldss); + PUSHL_SEL(oldss); PUSHL(oldsp2); if (cpu_state.abrt) { SS = oldss; @@ -1622,10 +1643,10 @@ pmodeint(int num, int soft) cpl_override = 1; if (type >= 0x0800) { if (cpu_state.eflags & VM_FLAG) { - PUSHL(GS); - PUSHL(FS); - PUSHL(DS); - PUSHL(ES); + PUSHL_SEL(GS); + PUSHL_SEL(FS); + PUSHL_SEL(DS); + PUSHL_SEL(ES); if (cpu_state.abrt) return; op_loadseg(0, &cpu_state.seg_ds); @@ -1633,10 +1654,10 @@ pmodeint(int num, int soft) op_loadseg(0, &cpu_state.seg_fs); op_loadseg(0, &cpu_state.seg_gs); } - PUSHL(oldss); + PUSHL_SEL(oldss); PUSHL(oldsp); PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL(CS); + PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return; @@ -1672,7 +1693,7 @@ pmodeint(int num, int soft) } if (type > 0x0800) { PUSHL(cpu_state.flags | (cpu_state.eflags << 16)); - PUSHL(CS); + PUSHL_SEL(CS); PUSHL(cpu_state.pc); if (cpu_state.abrt) return;