diff --git a/nvr/ami386dx_opti495.nvr b/nvr/ami386dx_opti495.nvr index dca4bd2..b6de20e 100644 Binary files a/nvr/ami386dx_opti495.nvr and b/nvr/ami386dx_opti495.nvr differ diff --git a/src/386.h b/src/386.h index d78be84..9ed872e 100644 --- a/src/386.h +++ b/src/386.h @@ -7,6 +7,7 @@ void loadcsjmp(uint16_t seg, uint32_t oxpc); void pmoderetf(int is32, uint16_t off); void pmodeiret(int is32); void x86_int_sw(int num); +int x86_int_sw_rm(int num); int divl(uint32_t val); int idivl(int32_t val); diff --git a/src/386_dynarec.c b/src/386_dynarec.c index 6ce33ba..6ab9418 100644 --- a/src/386_dynarec.c +++ b/src/386_dynarec.c @@ -263,6 +263,38 @@ void x86_int_sw(int num) CPU_BLOCK_END(); } +int x86_int_sw_rm(int num) +{ + uint32_t addr; + uint16_t new_pc, new_cs; + + flags_rebuild(); + cycles -= timing_int; + + addr = num << 2; + new_pc = readmemw(0, addr); + new_cs = readmemw(0, addr + 2); + + if (cpu_state.abrt) return 1; + + writememw(ss,((SP-2)&0xFFFF),flags); if (cpu_state.abrt) {pclog("abrt5\n"); return 1; } + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); if (cpu_state.abrt) {pclog("abrt6\n"); return 1; } + SP-=6; + + eflags &= ~VIF_FLAG; + flags &= ~T_FLAG; + cpu_state.pc = new_pc; + loadcs(new_cs); + oxpc=cpu_state.pc; + + cycles -= timing_int_rm; + trap = 0; + CPU_BLOCK_END(); + + return 0; +} + void x86illegal() { // pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); diff --git a/src/808x.c b/src/808x.c index 7933f58..a78b52c 100644 --- a/src/808x.c +++ b/src/808x.c @@ -602,7 +602,7 @@ chdir(pcempath); if (is386) { printf("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); - printf("CR0=%08X CR2=%08X CR3=%08X\n",cr0,cr2,cr3); + printf("CR0=%08X CR2=%08X CR3=%08X CR4=%08x\n",cr0,cr2,cr3, cr4); } printf("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); for (c=0;c<1024*1024;c++) diff --git a/src/codegen_ops_misc.h b/src/codegen_ops_misc.h index 1ccbcff..b4576d4 100644 --- a/src/codegen_ops_misc.h +++ b/src/codegen_ops_misc.h @@ -16,11 +16,13 @@ static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32 static uint32_t ropCLI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { + return 0; CLEAR_BITS((uintptr_t)&flags, I_FLAG); return op_pc; } static uint32_t ropSTI(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) { + return 0; SET_BITS((uintptr_t)&flags, I_FLAG); return op_pc; } diff --git a/src/cpu.c b/src/cpu.c index c58c7df..9552c1d 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -51,6 +51,7 @@ OpFn *x86_opcodes_df_a32; enum { CPUID_FPU = (1 << 0), + CPUID_VME = (1 << 1), CPUID_TSC = (1 << 4), CPUID_MSR = (1 << 5), CPUID_CMPXCHG8B = (1 << 8), @@ -67,6 +68,7 @@ int cpu_busspeed; int cpu_hasrdtsc; int cpu_hasMMX, cpu_hasMSR; int cpu_hasCR4; +int cpu_hasVME; int cpu_use_dynarec; int cpu_cyrix_alignment; @@ -294,8 +296,8 @@ CPU cpus_i486[] = {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 8,8,6,6}, {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC, 12,12,6,6}, - {"iDX4/75", CPU_i486DX, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9}, /*CPUID available on DX4, >= 75 MHz*/ - {"iDX4/100", CPU_i486DX,10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"iDX4/75", CPU_iDX4, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 12,12,9,9}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_iDX4, 10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC, 18,18,9,9}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ {"Pentium OverDrive/63", CPU_PENTIUM, 6, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 10,10,7,7}, {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC, 15,15,8,8}, {"", -1, 0, 0, 0} @@ -761,7 +763,11 @@ void cpu_set() timing_jmp_pm_gate = 37; timing_misaligned = 3; break; - + + case CPU_iDX4: + cpu_hasCR4 = 1; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_VME; case CPU_i486SX: case CPU_i486DX: timing_rr = 1; /*register dest - register src*/ @@ -971,7 +977,8 @@ void cpu_set() cpu_hasMMX = 0; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_pentium); break; @@ -1011,7 +1018,8 @@ void cpu_set() cpu_hasMMX = 1; cpu_hasMSR = 1; cpu_hasCR4 = 1; - cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + cpu_hasVME = 1; + cpu_CR4_mask = CR4_VME | CR4_PVI | CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; codegen_timing_set(&codegen_timing_pentium); break; @@ -1197,6 +1205,24 @@ void cpu_CPUID() EAX = 0; break; + case CPU_iDX4: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_VME; + } + else + EAX = 0; + break; + case CPU_Am486SX: if (!EAX) { @@ -1273,7 +1299,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; } else EAX = 0; @@ -1291,7 +1317,7 @@ void cpu_CPUID() { EAX = CPUID; EBX = ECX = 0; - EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + EDX = CPUID_FPU | CPUID_VME | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; } else EAX = 0; diff --git a/src/cpu.h b/src/cpu.h index 60ff266..2a94816 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -23,16 +23,17 @@ extern int cpu, cpu_manufacturer; #define CPU_i486DX 10 #define CPU_Am486DX 11 #define CPU_Cx486DX 12 -#define CPU_Cx5x86 13 +#define CPU_iDX4 13 +#define CPU_Cx5x86 14 /*586 class CPUs*/ -#define CPU_WINCHIP 14 -#define CPU_PENTIUM 15 -#define CPU_PENTIUMMMX 16 -#define CPU_Cx6x86 17 -#define CPU_Cx6x86MX 18 -#define CPU_Cx6x86L 19 -#define CPU_CxGX1 20 +#define CPU_WINCHIP 15 +#define CPU_PENTIUM 16 +#define CPU_PENTIUMMMX 17 +#define CPU_Cx6x86 18 +#define CPU_Cx6x86MX 19 +#define CPU_Cx6x86L 20 +#define CPU_CxGX1 21 #define MANU_INTEL 0 #define MANU_AMD 1 @@ -106,6 +107,7 @@ extern int cpu_hasrdtsc; extern int cpu_hasMSR; extern int cpu_hasMMX; extern int cpu_hasCR4; +extern int cpu_hasVME; #define CR4_TSD (1 << 2) #define CR4_DE (1 << 3) diff --git a/src/ibm.h b/src/ibm.h index 183d462..47ba64b 100644 --- a/src/ibm.h +++ b/src/ibm.h @@ -244,9 +244,14 @@ uint32_t dr[8]; #define V_FLAG 0x0800 #define NT_FLAG 0x4000 #define VM_FLAG 0x0002 /*In EFLAGS*/ +#define VIF_FLAG 0x0008 /*In EFLAGS*/ +#define VIP_FLAG 0x0010 /*In EFLAGS*/ #define WP_FLAG 0x10000 /*In CR0*/ +#define CR4_VME (1 << 0) +#define CR4_PVI (1 << 1) + #define IOPL ((flags>>12)&3) #define IOPLp ((!(msw&1)) || (CPL<=IOPL)) diff --git a/src/x86_ops_flag.h b/src/x86_ops_flag.h index 3fbaba6..9d3c0d7 100644 --- a/src/x86_ops_flag.h +++ b/src/x86_ops_flag.h @@ -27,8 +27,16 @@ static int opCLI(uint32_t fetchdat) { if (!IOPLp) { - x86gpf(NULL,0); - return 1; + if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + eflags &= ~VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } } else flags &= ~I_FLAG; @@ -57,8 +65,22 @@ static int opSTI(uint32_t fetchdat) { if (!IOPLp) { - x86gpf(NULL,0); - return 1; + if ((!(eflags & VM_FLAG) && (cr4 & CR4_PVI)) || + ((eflags & VM_FLAG) && (cr4 & CR4_VME))) + { + if (eflags & VIP_FLAG) + { + x86gpf(NULL,0); + return 1; + } + else + eflags |= VIF_FLAG; + } + else + { + x86gpf(NULL,0); + return 1; + } } else flags |= I_FLAG; @@ -94,11 +116,27 @@ static int opPUSHF(uint32_t fetchdat) { if ((eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL,0); - return 1; + if (cr4 & CR4_VME) + { + uint16_t temp; + + flags_rebuild(); + temp = (flags & ~I_FLAG) | 0x3000; + if (eflags & VIF_FLAG) + temp |= I_FLAG; + PUSH_W(temp); + } + else + { + x86gpf(NULL,0); + return 1; + } + } + else + { + flags_rebuild(); + PUSH_W(flags); } - flags_rebuild(); - PUSH_W(flags); CLOCK_CYCLES(4); PREFETCH_RUN(4, 1, -1, 0,0,1,0, 0); return cpu_state.abrt; @@ -111,8 +149,9 @@ static int opPUSHFD(uint32_t fetchdat) x86gpf(NULL, 0); return 1; } - if (CPUID) tempw = eflags & 0x24; - else tempw = eflags & 4; + if (cpu_CR4_mask & CR4_VME) tempw = eflags & 0x3c; + else if (CPUID) tempw = eflags & 0x24; + else tempw = eflags & 4; flags_rebuild(); PUSH_L(flags | (tempw << 16)); CLOCK_CYCLES(4); @@ -151,15 +190,48 @@ static int opPOPF(uint32_t fetchdat) if ((eflags & VM_FLAG) && (IOPL < 3)) { - x86gpf(NULL, 0); - return 1; - } - - tempw = POP_W(); if (cpu_state.abrt) return 1; + if (cr4 & CR4_VME) + { + uint32_t old_esp = ESP; - if (!(CPL) || !(msw & 1)) flags = (tempw & 0x7fd5) | 2; - else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; - else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + tempw = POP_W(); + if (cpu_state.abrt) + { + ESP = old_esp; + return 1; + } + + if ((tempw & T_FLAG) || ((tempw & I_FLAG) && (eflags & VIP_FLAG))) + { + ESP = old_esp; + x86gpf(NULL, 0); + return 1; + } + if (tempw & I_FLAG) + eflags |= VIF_FLAG; + else + eflags &= ~VIF_FLAG; + flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + } + else + { + x86gpf(NULL, 0); + return 1; + } + } + else + { + tempw = POP_W(); + if (cpu_state.abrt) + return 1; + + if (!(CPL) || !(msw & 1)) + flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) + flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else + flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + } flags_extract(); CLOCK_CYCLES(5); @@ -185,11 +257,12 @@ static int opPOPFD(uint32_t fetchdat) else if (IOPLp) flags = (flags & 0x3000) | (templ & 0x4fd5) | 2; else flags = (flags & 0x3200) | (templ & 0x4dd5) | 2; - templ &= is486 ? 0x240000 : 0; + templ &= is486 ? 0x3c0000 : 0; templ |= ((eflags&3) << 16); - if (CPUID) eflags = (templ >> 16) & 0x27; - else if (is486) eflags = (templ >> 16) & 7; - else eflags = (templ >> 16) & 3; + if (cpu_CR4_mask & CR4_VME) eflags = (templ >> 16) & 0x3f; + else if (CPUID) eflags = (templ >> 16) & 0x27; + else if (is486) eflags = (templ >> 16) & 7; + else eflags = (templ >> 16) & 3; flags_extract(); diff --git a/src/x86_ops_int.h b/src/x86_ops_int.h index f72ef60..ce85225 100644 --- a/src/x86_ops_int.h +++ b/src/x86_ops_int.h @@ -29,15 +29,39 @@ static int opINT1(uint32_t fetchdat) static int opINT(uint32_t fetchdat) { int cycles_old = cycles; UNUSED(cycles_old); - uint8_t temp; - - /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + uint8_t temp = getbytef(); + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { + if (cr4 & CR4_VME) + { + uint16_t t; + uint8_t d; + + cpl_override = 1; + t = readmemw(tr.base, 0x66) - 32; + cpl_override = 0; + if (cpu_state.abrt) return 1; + + t += (temp >> 3); + if (t <= tr.limit) + { + cpl_override = 1; + d = readmemb(tr.base, t);// + (temp >> 3)); + cpl_override = 0; + if (cpu_state.abrt) return 1; + + if (!(d & (1 << (temp & 7)))) + { + x86_int_sw_rm(temp); + PREFETCH_RUN(cycles_old-cycles, 2, -1, 0,0,0,0, 0); + return 1; + } + } + } x86gpf(NULL,0); return 1; } - temp = getbytef(); // /*if (temp == 0x10 && AH == 0xe) */pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc); // if (CS == 0x0028 && pc == 0xC03813C0) // output = 3; diff --git a/src/x86_ops_ret.h b/src/x86_ops_ret.h index 3a600ce..d9db8ba 100644 --- a/src/x86_ops_ret.h +++ b/src/x86_ops_ret.h @@ -141,35 +141,67 @@ static int opIRET(uint32_t fetchdat) if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) { - x86gpf(NULL,0); - return 1; - } - if (msw&1) - { - optype = IRET; - pmodeiret(0); - optype = 0; - } - else - { - uint16_t new_cs; - oxpc = cpu_state.pc; - if (stack32) + if (cr4 & CR4_VME) { - cpu_state.pc = readmemw(ss, ESP); - new_cs = readmemw(ss, ESP + 2); - flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; - ESP += 6; + uint16_t new_pc, new_cs, new_flags; + + new_pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + new_flags = readmemw(ss, ((SP + 4) & 0xffff)); + if (cpu_state.abrt) + return 1; + + if ((new_flags & T_FLAG) || ((new_flags & I_FLAG) && (eflags & VIP_FLAG))) + { + x86gpf(NULL, 0); + return 1; + } + SP += 6; + if (new_flags & I_FLAG) + eflags |= VIF_FLAG; + else + eflags &= ~VIF_FLAG; + flags = (flags & 0x3300) | (new_flags & 0x4cd5) | 2; + loadcs(new_cs); + cpu_state.pc = new_pc; + + cycles -= timing_iret_rm; } else { - cpu_state.pc = readmemw(ss, SP); - new_cs = readmemw(ss, ((SP + 2) & 0xffff)); - flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; - SP += 6; + x86gpf(NULL,0); + return 1; + } + } + else + { + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; } - loadcs(new_cs); - cycles -= timing_iret_rm; } flags_extract(); nmi_enable = 1;