// Intel 486+ specific opcodes static void I486OP(cpuid)(i386_state *cpustate) // Opcode 0x0F A2 { switch (REG32(EAX)) { 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; } } } static void I486OP(invd)(i386_state *cpustate) // Opcode 0x0f 08 { // Nothing to do ? CYCLES(cpustate,CYCLES_INVD); } static void I486OP(wbinvd)(i386_state *cpustate) // Opcode 0x0f 09 { // Nothing to do ? } static void I486OP(cmpxchg_rm8_r8)(i386_state *cpustate) // Opcode 0x0f b0 { UINT8 modrm = FETCH(cpustate); if( modrm >= 0xc0 ) { UINT8 dst = LOAD_RM8(modrm); UINT8 src = LOAD_REG8(modrm); if( REG8(AL) == dst ) { STORE_RM8(modrm, src); cpustate->ZF = 1; CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T); } else { REG8(AL) = dst; cpustate->ZF = 0; CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F); } } else { UINT32 ea = GetEA(cpustate,modrm); UINT8 dst = READ8(cpustate,ea); UINT8 src = LOAD_REG8(modrm); if( REG8(AL) == dst ) { WRITE8(cpustate,modrm, src); cpustate->ZF = 1; CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T); } else { REG8(AL) = dst; cpustate->ZF = 0; CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F); } } } static void I486OP(cmpxchg_rm16_r16)(i386_state *cpustate) // Opcode 0x0f b1 { UINT8 modrm = FETCH(cpustate); if( modrm >= 0xc0 ) { UINT16 dst = LOAD_RM16(modrm); UINT16 src = LOAD_REG16(modrm); if( REG16(AX) == dst ) { STORE_RM16(modrm, src); cpustate->ZF = 1; CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T); } else { REG16(AX) = dst; cpustate->ZF = 0; CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F); } } else { UINT32 ea = GetEA(cpustate,modrm); UINT16 dst = READ16(cpustate,ea); UINT16 src = LOAD_REG16(modrm); if( REG16(AX) == dst ) { WRITE16(cpustate,modrm, src); cpustate->ZF = 1; CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T); } else { REG16(AX) = dst; cpustate->ZF = 0; CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F); } } } static void I486OP(cmpxchg_rm32_r32)(i386_state *cpustate) // Opcode 0x0f b1 { UINT8 modrm = FETCH(cpustate); if( modrm >= 0xc0 ) { UINT32 dst = LOAD_RM32(modrm); UINT32 src = LOAD_REG32(modrm); if( REG32(EAX) == dst ) { STORE_RM32(modrm, src); cpustate->ZF = 1; CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_T); } else { REG32(EAX) = dst; cpustate->ZF = 0; CYCLES(cpustate,CYCLES_CMPXCHG_REG_REG_F); } } else { UINT32 ea = GetEA(cpustate,modrm); UINT32 dst = READ32(cpustate,ea); UINT32 src = LOAD_REG32(modrm); if( REG32(EAX) == dst ) { WRITE32(cpustate,ea, src); cpustate->ZF = 1; CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_T); } else { REG32(EAX) = dst; cpustate->ZF = 0; CYCLES(cpustate,CYCLES_CMPXCHG_REG_MEM_F); } } } static void I486OP(xadd_rm8_r8)(i386_state *cpustate) // Opcode 0x0f c0 { UINT8 modrm = FETCH(cpustate); if( modrm >= 0xc0 ) { UINT8 dst = LOAD_RM8(modrm); UINT8 src = LOAD_REG8(modrm); STORE_RM16(modrm, dst + src); STORE_REG16(modrm, dst); CYCLES(cpustate,CYCLES_XADD_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); UINT8 dst = READ8(cpustate,ea); UINT8 src = LOAD_REG8(modrm); WRITE8(cpustate,ea, dst + src); STORE_REG8(modrm, dst); CYCLES(cpustate,CYCLES_XADD_REG_MEM); } } static void I486OP(xadd_rm16_r16)(i386_state *cpustate) // Opcode 0x0f c1 { UINT8 modrm = FETCH(cpustate); if( modrm >= 0xc0 ) { UINT16 dst = LOAD_RM16(modrm); UINT16 src = LOAD_REG16(modrm); STORE_RM16(modrm, dst + src); STORE_REG16(modrm, dst); CYCLES(cpustate,CYCLES_XADD_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); UINT16 dst = READ16(cpustate,ea); UINT16 src = LOAD_REG16(modrm); WRITE16(cpustate,ea, dst + src); STORE_REG16(modrm, dst); CYCLES(cpustate,CYCLES_XADD_REG_MEM); } } static void I486OP(xadd_rm32_r32)(i386_state *cpustate) // Opcode 0x0f c1 { UINT8 modrm = FETCH(cpustate); if( modrm >= 0xc0 ) { UINT32 dst = LOAD_RM32(modrm); UINT32 src = LOAD_REG32(modrm); STORE_RM32(modrm, dst + src); STORE_REG32(modrm, dst); CYCLES(cpustate,CYCLES_XADD_REG_REG); } else { UINT32 ea = GetEA(cpustate,modrm); UINT32 dst = READ32(cpustate,ea); UINT32 src = LOAD_REG32(modrm); WRITE32(cpustate,ea, dst + src); STORE_REG32(modrm, dst); CYCLES(cpustate,CYCLES_XADD_REG_MEM); } } static void I486OP(group0F01_16)(i386_state *cpustate) // Opcode 0x0f 01 { UINT8 modrm = FETCH(cpustate); UINT16 address; UINT32 ea; switch( (modrm >> 3) & 0x7 ) { case 0: /* SGDT */ { if( modrm >= 0xc0 ) { address = LOAD_RM16(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } WRITE16(cpustate,ea, cpustate->gdtr.limit); WRITE32(cpustate,ea + 2, cpustate->gdtr.base & 0xffffff); CYCLES(cpustate,CYCLES_SGDT); break; } case 1: /* SIDT */ { if (modrm >= 0xc0) { address = LOAD_RM16(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } WRITE16(cpustate,ea, cpustate->idtr.limit); WRITE32(cpustate,ea + 2, cpustate->idtr.base & 0xffffff); CYCLES(cpustate,CYCLES_SIDT); break; } case 2: /* LGDT */ { if( modrm >= 0xc0 ) { address = LOAD_RM16(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } cpustate->gdtr.limit = READ16(cpustate,ea); cpustate->gdtr.base = READ32(cpustate,ea + 2) & 0xffffff; CYCLES(cpustate,CYCLES_LGDT); break; } case 3: /* LIDT */ { if( modrm >= 0xc0 ) { address = LOAD_RM16(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } cpustate->idtr.limit = READ16(cpustate,ea); cpustate->idtr.base = READ32(cpustate,ea + 2) & 0xffffff; CYCLES(cpustate,CYCLES_LIDT); break; } case 4: /* SMSW */ { if( modrm >= 0xc0 ) { STORE_RM16(modrm, cpustate->cr[0]); CYCLES(cpustate,CYCLES_SMSW_REG); } else { UINT32 ea = GetEA(cpustate,modrm); WRITE16(cpustate,ea, cpustate->cr[0]); CYCLES(cpustate,CYCLES_SMSW_MEM); } break; } case 6: /* LMSW */ { // TODO: Check for protection fault UINT8 b; if( modrm >= 0xc0 ) { b = LOAD_RM8(modrm); CYCLES(cpustate,CYCLES_LMSW_REG); } else { ea = GetEA(cpustate,modrm); CYCLES(cpustate,CYCLES_LMSW_MEM); b = READ8(cpustate,ea); } cpustate->cr[0] &= ~0x03; cpustate->cr[0] |= b & 0x03; break; } case 7: /* INVLPG */ { // Nothing to do ? break; } default: fatalerror("i486: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, cpustate->eip - 2); break; } } static void I486OP(group0F01_32)(i386_state *cpustate) // Opcode 0x0f 01 { UINT8 modrm = FETCH(cpustate); UINT32 address, ea; switch( (modrm >> 3) & 0x7 ) { case 0: /* SGDT */ { if( modrm >= 0xc0 ) { address = LOAD_RM32(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } WRITE16(cpustate,ea, cpustate->gdtr.limit); WRITE32(cpustate,ea + 2, cpustate->gdtr.base); CYCLES(cpustate,CYCLES_SGDT); break; } case 1: /* SIDT */ { if (modrm >= 0xc0) { address = LOAD_RM32(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } WRITE16(cpustate,ea, cpustate->idtr.limit); WRITE32(cpustate,ea + 2, cpustate->idtr.base); CYCLES(cpustate,CYCLES_SIDT); break; } case 2: /* LGDT */ { if( modrm >= 0xc0 ) { address = LOAD_RM32(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } cpustate->gdtr.limit = READ16(cpustate,ea); cpustate->gdtr.base = READ32(cpustate,ea + 2); CYCLES(cpustate,CYCLES_LGDT); break; } case 3: /* LIDT */ { if( modrm >= 0xc0 ) { address = LOAD_RM32(modrm); ea = i386_translate( cpustate, CS, address ); } else { ea = GetEA(cpustate,modrm); } cpustate->idtr.limit = READ16(cpustate,ea); cpustate->idtr.base = READ32(cpustate,ea + 2); CYCLES(cpustate,CYCLES_LIDT); break; } case 7: /* INVLPG */ { // Nothing to do ? break; } default: fatalerror("i486: unimplemented opcode 0x0f 01 /%d at %08X", (modrm >> 3) & 0x7, cpustate->eip - 2); break; } }