mirror of
https://github.com/holub/mame
synced 2025-10-04 16:34:53 +03:00
i386: Improved accuracy of the various emulated models, makes CPU detection programs detect the correct CPU (in MESS).
- eflags mask added - Initial values for the EAX and EDX registers fixed - cpuid values improved - feature flags improved - initial value for the cr0 register improved - changed 486 to not support the cpuid instruction by default - take a trap on invalid instructions instead of throwing a fatalerror - emulated the undefined flag behavior for the DIV/IDIV instructions on Intel CPUs
This commit is contained in:
parent
43ce0bbbd1
commit
3997330a94
@ -94,7 +94,7 @@ static UINT32 get_flags(i386_state *cpustate)
|
||||
f |= cpustate->IOP1 << 12;
|
||||
f |= cpustate->IOP2 << 13;
|
||||
f |= cpustate->NT << 14;
|
||||
return (cpustate->eflags & 0xFFFF0000) | (f & 0xFFFF);
|
||||
return (cpustate->eflags & cpustate->eflags_mask) | (f & 0xffff);
|
||||
}
|
||||
|
||||
static void set_flags(i386_state *cpustate, UINT32 f )
|
||||
@ -111,6 +111,7 @@ static void set_flags(i386_state *cpustate, UINT32 f )
|
||||
cpustate->IOP1 = (f & 0x1000) ? 1 : 0;
|
||||
cpustate->IOP2 = (f & 0x2000) ? 1 : 0;
|
||||
cpustate->NT = (f & 0x4000) ? 1 : 0;
|
||||
cpustate->eflags = f & cpustate->eflags_mask;
|
||||
}
|
||||
|
||||
static void sib_byte(i386_state *cpustate,UINT8 mod, UINT32* out_ea, UINT8* out_segment)
|
||||
@ -662,12 +663,17 @@ static CPU_RESET( i386 )
|
||||
|
||||
cpustate->a20_mask = ~0;
|
||||
|
||||
cpustate->cr[0] = 0;
|
||||
cpustate->cr[0] = 0x7ffffff0; // reserved bits set to 1
|
||||
cpustate->eflags = 0;
|
||||
cpustate->eflags_mask = 0x00030000;
|
||||
cpustate->eip = 0xfff0;
|
||||
|
||||
REG32(EAX) = 0x0308; // Intel 386, stepping D1
|
||||
REG32(EDX) = 0;
|
||||
// [11:8] Family
|
||||
// [ 7:4] Model
|
||||
// [ 3:0] Stepping ID
|
||||
// Family 3 (386), Model 0 (DX), Stepping 8 (D1)
|
||||
REG32(EAX) = 0;
|
||||
REG32(EDX) = (3 << 8) | (0 << 4) | (8);
|
||||
|
||||
build_opcode_table(cpustate, OP_I386);
|
||||
cpustate->cycle_table_rm = cycle_table_rm[CPU_CYCLES_I386];
|
||||
@ -1111,12 +1117,17 @@ static CPU_RESET( i486 )
|
||||
|
||||
cpustate->a20_mask = ~0;
|
||||
|
||||
cpustate->cr[0] = 0;
|
||||
cpustate->cr[0] = 0x00000010;
|
||||
cpustate->eflags = 0;
|
||||
cpustate->eflags_mask = 0x00070000;
|
||||
cpustate->eip = 0xfff0;
|
||||
|
||||
REG32(EAX) = 0x0308; // Intel 386, stepping D1
|
||||
REG32(EDX) = 0;
|
||||
// [11:8] Family
|
||||
// [ 7:4] Model
|
||||
// [ 3:0] Stepping ID
|
||||
// Family 4 (486), Model 0/1 (DX), Stepping 3
|
||||
REG32(EAX) = 0;
|
||||
REG32(EDX) = (4 << 8) | (0 << 4) | (3);
|
||||
|
||||
build_opcode_table(cpustate, OP_I386 | OP_FPU | OP_I486);
|
||||
cpustate->cycle_table_rm = cycle_table_rm[CPU_CYCLES_I486];
|
||||
@ -1222,12 +1233,17 @@ static CPU_RESET( pentium )
|
||||
|
||||
cpustate->a20_mask = ~0;
|
||||
|
||||
cpustate->cr[0] = 0;
|
||||
cpustate->cr[0] = 0x00000010;
|
||||
cpustate->eflags = 0;
|
||||
cpustate->eflags_mask = 0x003b0000;
|
||||
cpustate->eip = 0xfff0;
|
||||
|
||||
REG32(EAX) = 0x0308; // Intel 386, stepping D1
|
||||
REG32(EDX) = 0;
|
||||
// [11:8] Family
|
||||
// [ 7:4] Model
|
||||
// [ 3:0] Stepping ID
|
||||
// Family 5 (Pentium), Model 2 (75 - 200MHz), Stepping 5
|
||||
REG32(EAX) = 0;
|
||||
REG32(EDX) = (5 << 8) | (2 << 4) | (5);
|
||||
|
||||
build_opcode_table(cpustate, OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM);
|
||||
cpustate->cycle_table_rm = cycle_table_rm[CPU_CYCLES_PENTIUM];
|
||||
@ -1238,12 +1254,7 @@ static CPU_RESET( pentium )
|
||||
cpustate->cpuid_id2 = 0x6c65746e; // ntel
|
||||
|
||||
cpustate->cpuid_max_input_value_eax = 0x01;
|
||||
|
||||
// [11:8] Family
|
||||
// [ 7:4] Model
|
||||
// [ 3:0] Stepping ID
|
||||
// Family 5 (Pentium), Model 2 (75 - 200MHz), Stepping 1
|
||||
cpustate->cpu_version = (5 << 8) | (2 << 4) | (1);
|
||||
cpustate->cpu_version = REG32(EDX);
|
||||
|
||||
// [ 0:0] FPU on chip
|
||||
// [ 2:2] I/O breakpoints
|
||||
@ -1251,7 +1262,7 @@ static CPU_RESET( pentium )
|
||||
// [ 5:5] Pentium CPU style model specific registers
|
||||
// [ 7:7] Machine Check Exception
|
||||
// [ 8:8] CMPXCHG8B instruction
|
||||
cpustate->feature_flags = 0x00000000;
|
||||
cpustate->feature_flags = 0x000001bf;
|
||||
|
||||
CHANGE_PC(cpustate,cpustate->eip);
|
||||
}
|
||||
@ -1353,12 +1364,17 @@ static CPU_RESET( mediagx )
|
||||
|
||||
cpustate->a20_mask = ~0;
|
||||
|
||||
cpustate->cr[0] = 0;
|
||||
cpustate->cr[0] = 0x00000010;
|
||||
cpustate->eflags = 0;
|
||||
cpustate->eflags_mask = 0x00270000; /* TODO: is this correct? */
|
||||
cpustate->eip = 0xfff0;
|
||||
|
||||
REG32(EAX) = 0x0308; // Intel 386, stepping D1
|
||||
REG32(EDX) = 0;
|
||||
// [11:8] Family
|
||||
// [ 7:4] Model
|
||||
// [ 3:0] Stepping ID
|
||||
// Family 4, Model 4 (MediaGX)
|
||||
REG32(EAX) = 0;
|
||||
REG32(EDX) = (4 << 8) | (4 << 4) | (1); /* TODO: is this correct? */
|
||||
|
||||
build_opcode_table(cpustate, OP_I386 | OP_FPU | OP_I486 | OP_PENTIUM | OP_CYRIX);
|
||||
cpustate->cycle_table_rm = cycle_table_rm[CPU_CYCLES_MEDIAGX];
|
||||
@ -1369,19 +1385,9 @@ static CPU_RESET( mediagx )
|
||||
cpustate->cpuid_id2 = 0x6d616574; // tead
|
||||
|
||||
cpustate->cpuid_max_input_value_eax = 0x01;
|
||||
|
||||
// [11:8] Family
|
||||
// [ 7:4] Model
|
||||
// [ 3:0] Stepping ID
|
||||
// Family 4, Model 4 (MediaGX)
|
||||
cpustate->cpu_version = (4 << 8) | (4 << 4) | (1);
|
||||
cpustate->cpu_version = REG32(EDX);
|
||||
|
||||
// [ 0:0] FPU on chip
|
||||
// [ 2:2] I/O breakpoints
|
||||
// [ 4:4] Time Stamp Counter
|
||||
// [ 5:5] Pentium CPU style model specific registers
|
||||
// [ 7:7] Machine Check Exception
|
||||
// [ 8:8] CMPXCHG8B instruction
|
||||
cpustate->feature_flags = 0x00000001;
|
||||
|
||||
CHANGE_PC(cpustate,cpustate->eip);
|
||||
|
@ -2639,6 +2639,10 @@ static void I386OP(groupF7_16)(i386_state *cpustate) // Opcode 0xf7
|
||||
} else {
|
||||
REG16(DX) = (UINT16)remainder;
|
||||
REG16(AX) = (UINT16)result;
|
||||
|
||||
// this flag is actually undefined, enable on non-cyrix
|
||||
if (cpustate->cpuid_id0 != 0x69727943)
|
||||
cpustate->CF = 1;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Divide by zero */
|
||||
@ -2667,6 +2671,10 @@ static void I386OP(groupF7_16)(i386_state *cpustate) // Opcode 0xf7
|
||||
} else {
|
||||
REG16(DX) = (UINT16)remainder;
|
||||
REG16(AX) = (UINT16)result;
|
||||
|
||||
// this flag is actually undefined, enable on non-cyrix
|
||||
if (cpustate->cpuid_id0 != 0x69727943)
|
||||
cpustate->CF = 1;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Divide by zero */
|
||||
|
@ -2023,6 +2023,10 @@ static void I386OP(groupF6_8)(i386_state *cpustate) // Opcode 0xf6
|
||||
} else {
|
||||
REG8(AH) = (UINT8)remainder & 0xff;
|
||||
REG8(AL) = (UINT8)result & 0xff;
|
||||
|
||||
// this flag is actually undefined, enable on non-cyrix
|
||||
if (cpustate->cpuid_id0 != 0x69727943)
|
||||
cpustate->CF = 1;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Divide by zero */
|
||||
@ -2051,6 +2055,10 @@ static void I386OP(groupF6_8)(i386_state *cpustate) // Opcode 0xf6
|
||||
} else {
|
||||
REG8(AH) = (UINT8)remainder & 0xff;
|
||||
REG8(AL) = (UINT8)result & 0xff;
|
||||
|
||||
// this flag is actually undefined, enable on non-cyrix
|
||||
if (cpustate->cpuid_id0 != 0x69727943)
|
||||
cpustate->CF = 1;
|
||||
}
|
||||
} else {
|
||||
/* TODO: Divide by zero */
|
||||
@ -2361,6 +2369,6 @@ static void I386OP(unimplemented)(i386_state *cpustate)
|
||||
|
||||
static void I386OP(invalid)(i386_state *cpustate)
|
||||
{
|
||||
//i386_trap(cpustate,6);
|
||||
fatalerror("i386: Invalid opcode %02X at %08X", cpustate->opcode, cpustate->pc - 1);
|
||||
logerror("i386: Invalid opcode %02X at %08X\n", cpustate->opcode, cpustate->pc - 1);
|
||||
i386_trap(cpustate, 6, 0);
|
||||
}
|
||||
|
@ -187,6 +187,7 @@ struct _i386_state
|
||||
UINT32 pc;
|
||||
UINT32 prev_eip;
|
||||
UINT32 eflags;
|
||||
UINT32 eflags_mask;
|
||||
UINT8 CF;
|
||||
UINT8 DF;
|
||||
UINT8 SF;
|
||||
|
@ -2,24 +2,33 @@
|
||||
|
||||
static void I486OP(cpuid)(i386_state *cpustate) // Opcode 0x0F A2
|
||||
{
|
||||
switch (REG32(EAX))
|
||||
if (cpustate->cpuid_id0 == 0)
|
||||
{
|
||||
case 0:
|
||||
// this 486 doesn't support the CPUID instruction
|
||||
logerror("CPUID not supported at %08x!\n", cpustate->eip);
|
||||
i386_trap(cpustate, 6, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (REG32(EAX))
|
||||
{
|
||||
REG32(EAX) = cpustate->cpuid_max_input_value_eax;
|
||||
REG32(EBX) = cpustate->cpuid_id0;
|
||||
REG32(ECX) = cpustate->cpuid_id2;
|
||||
REG32(EDX) = cpustate->cpuid_id1;
|
||||
CYCLES(cpustate,CYCLES_CPUID);
|
||||
break;
|
||||
}
|
||||
case 0:
|
||||
{
|
||||
REG32(EAX) = cpustate->cpuid_max_input_value_eax;
|
||||
REG32(EBX) = cpustate->cpuid_id0;
|
||||
REG32(ECX) = cpustate->cpuid_id2;
|
||||
REG32(EDX) = cpustate->cpuid_id1;
|
||||
CYCLES(cpustate,CYCLES_CPUID);
|
||||
break;
|
||||
}
|
||||
|
||||
case 1:
|
||||
{
|
||||
REG32(EAX) = cpustate->cpu_version;
|
||||
REG32(EDX) = cpustate->feature_flags;
|
||||
CYCLES(cpustate,CYCLES_CPUID_EAX1);
|
||||
break;
|
||||
case 1:
|
||||
{
|
||||
REG32(EAX) = cpustate->cpu_version;
|
||||
REG32(EDX) = cpustate->feature_flags;
|
||||
CYCLES(cpustate,CYCLES_CPUID_EAX1);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user