diff options
Diffstat (limited to 'trunk/src/emu/cpu/i386/pentops.c')
-rw-r--r-- | trunk/src/emu/cpu/i386/pentops.c | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/trunk/src/emu/cpu/i386/pentops.c b/trunk/src/emu/cpu/i386/pentops.c new file mode 100644 index 00000000000..f16cbb6ef75 --- /dev/null +++ b/trunk/src/emu/cpu/i386/pentops.c @@ -0,0 +1,88 @@ +// Pentium+ specific opcodes + +static void PENTIUMOP(rdmsr)(i386_state *cpustate) // Opcode 0x0f 32 +{ + UINT64 data; + UINT8 valid_msr = 0; + + data = MSR_READ(cpustate,REG32(ECX),&valid_msr); + REG32(EDX) = data >> 32; + REG32(EAX) = data & 0xffffffff; + + if(cpustate->CPL != 0 || valid_msr == 0) // if current privilege level isn't 0 or the register isn't recognized ... + FAULT(FAULT_GP,0) // ... throw a general exception fault + + CYCLES(cpustate,CYCLES_RDMSR); +} + +static void PENTIUMOP(wrmsr)(i386_state *cpustate) // Opcode 0x0f 30 +{ + UINT64 data; + UINT8 valid_msr = 0; + + data = (UINT64)REG32(EAX); + data |= (UINT64)(REG32(EDX)) << 32; + + MSR_WRITE(cpustate,REG32(ECX),data,&valid_msr); + + if(cpustate->CPL != 0 || valid_msr == 0) // if current privilege level isn't 0 or the register isn't recognized + FAULT(FAULT_GP,0) // ... throw a general exception fault + + CYCLES(cpustate,1); // TODO: correct cycle count (~30-45) +} + +static void PENTIUMOP(rdtsc)(i386_state *cpustate) // Opcode 0x0f 31 +{ + UINT64 ts = cpustate->tsc + (cpustate->base_cycles - cpustate->cycles); + REG32(EAX) = (UINT32)(ts); + REG32(EDX) = (UINT32)(ts >> 32); + + CYCLES(cpustate,CYCLES_RDTSC); +} + +static void I386OP(cyrix_unknown)(i386_state *cpustate) // Opcode 0x0f 74 +{ + logerror("Unemulated 0x0f 0x74 opcode called\n"); + + CYCLES(cpustate,1); +} + +static void PENTIUMOP(cmpxchg8b_m64)(i386_state *cpustate) // Opcode 0x0f c7 +{ + UINT8 modm = FETCH(cpustate); + if( modm >= 0xc0 ) { + fatalerror("pentium: cmpxchg8b_m64 - invalid modm"); + } else { + UINT32 ea = GetEA(cpustate,modm,0); + UINT64 value = READ64(cpustate,ea); + UINT64 edx_eax = (((UINT64) REG32(EDX)) << 32) | REG32(EAX); + UINT64 ecx_ebx = (((UINT64) REG32(ECX)) << 32) | REG32(EBX); + + if( value == edx_eax ) { + WRITE64(cpustate,ea, ecx_ebx); + cpustate->ZF = 1; + CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T); + } else { + REG32(EDX) = (UINT32) (value >> 32); + REG32(EAX) = (UINT32) (value >> 0); + cpustate->ZF = 0; + CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F); + } + } +} + +static void PENTIUMOP(sse_group0fae)(i386_state *cpustate) // Opcode 0x0f ae +{ + UINT8 modm = FETCH(cpustate); + if( modm == 0xf8 ) { + logerror("Unemulated SFENCE opcode called\n"); + CYCLES(cpustate,1); // sfence instruction + } else { + fatalerror("pentium: bad/unsupported 0f ae opcode"); + } +} + +static void PENTIUMOP(ud2)(i386_state *cpustate) // Opcode 0x0f 0b +{ + i386_trap(cpustate, 6, 0, 0); +} |