diff options
Diffstat (limited to 'src/devices/cpu/i386/i386op32.inc')
-rw-r--r-- | src/devices/cpu/i386/i386op32.inc | 3585 |
1 files changed, 3585 insertions, 0 deletions
diff --git a/src/devices/cpu/i386/i386op32.inc b/src/devices/cpu/i386/i386op32.inc new file mode 100644 index 00000000000..96b3baddb1c --- /dev/null +++ b/src/devices/cpu/i386/i386op32.inc @@ -0,0 +1,3585 @@ +// license:BSD-3-Clause +// copyright-holders:Ville Linde, Barry Rodewald, Carl, Philip Bennett +UINT32 i386_device::i386_shift_rotate32(UINT8 modrm, UINT32 value, UINT8 shift) +{ + UINT32 dst, src; + dst = value; + src = value; + + if( shift == 0 ) { + CYCLES_RM(modrm, 3, 7); + } else if( shift == 1 ) { + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm32, 1 */ + m_CF = (src & 0x80000000) ? 1 : 0; + dst = (src << 1) + m_CF; + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm32, 1 */ + m_CF = (src & 0x1) ? 1 : 0; + dst = (m_CF << 31) | (src >> 1); + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm32, 1 */ + dst = (src << 1) + m_CF; + m_CF = (src & 0x80000000) ? 1 : 0; + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm32, 1 */ + dst = (m_CF << 31) | (src >> 1); + m_CF = src & 0x1; + m_OF = ((src ^ dst) & 0x80000000) ? 1 : 0; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm32, 1 */ + case 6: + dst = src << 1; + m_CF = (src & 0x80000000) ? 1 : 0; + m_OF = (((m_CF << 31) ^ dst) & 0x80000000) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm32, 1 */ + dst = src >> 1; + m_CF = src & 0x1; + m_OF = (src & 0x80000000) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm32, 1 */ + dst = (INT32)(src) >> 1; + m_CF = src & 0x1; + m_OF = 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + + } else { + shift &= 31; + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* ROL rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff >> shift)) << shift) | + ((src & ((UINT32)0xffffffff << (32-shift))) >> (32-shift)); + m_CF = dst & 0x1; + m_OF = (dst & 1) ^ (dst >> 31); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 1: /* ROR rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff << shift)) >> shift) | + ((src & ((UINT32)0xffffffff >> (32-shift))) << (32-shift)); + m_CF = (dst >> 31) & 0x1; + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 2: /* RCL rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff >> shift)) << shift) | + ((src & ((UINT32)0xffffffff << (33-shift))) >> (33-shift)) | + (m_CF << (shift-1)); + m_CF = (src >> (32-shift)) & 0x1; + m_OF = m_CF ^ ((dst >> 31) & 1); + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 3: /* RCR rm32, i8 */ + dst = ((src & ((UINT32)0xffffffff << shift)) >> shift) | + ((src & ((UINT32)0xffffffff >> (32-shift))) << (33-shift)) | + (m_CF << (32-shift)); + m_CF = (src >> (shift-1)) & 0x1; + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + CYCLES_RM(modrm, CYCLES_ROTATE_CARRY_REG, CYCLES_ROTATE_CARRY_MEM); + break; + case 4: /* SHL/SAL rm32, i8 */ + case 6: + dst = src << shift; + m_CF = (src & (1 << (32-shift))) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 5: /* SHR rm32, i8 */ + dst = src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + case 7: /* SAR rm32, i8 */ + dst = (INT32)src >> shift; + m_CF = (src & (1 << (shift-1))) ? 1 : 0; + SetSZPF32(dst); + CYCLES_RM(modrm, CYCLES_ROTATE_REG, CYCLES_ROTATE_MEM); + break; + } + + } + return dst; +} + + + +void i386_device::i386_adc_rm32_r32() // Opcode 0x11 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = ADC32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = ADC32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_adc_r32_rm32() // Opcode 0x13 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = ADC32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = ADC32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_adc_eax_i32() // Opcode 0x15 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = ADC32(dst, src, m_CF); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_add_rm32_r32() // Opcode 0x01 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = ADD32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = ADD32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_add_r32_rm32() // Opcode 0x03 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = ADD32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = ADD32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_add_eax_i32() // Opcode 0x05 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = ADD32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_and_rm32_r32() // Opcode 0x21 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = AND32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = AND32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_and_r32_rm32() // Opcode 0x23 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = AND32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = AND32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_and_eax_i32() // Opcode 0x25 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = AND32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_bsf_r32_rm32() // Opcode 0x0f bc +{ + UINT32 src, dst, temp; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + } + + dst = 0; + + if( src == 0 ) { + m_ZF = 1; + } else { + m_ZF = 0; + temp = 0; + while( (src & (1 << temp)) == 0 ) { + temp++; + dst = temp; + CYCLES(CYCLES_BSF); + } + STORE_REG32(modrm, dst); + } + CYCLES(CYCLES_BSF_BASE); +} + +void i386_device::i386_bsr_r32_rm32() // Opcode 0x0f bd +{ + UINT32 src, dst, temp; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + } + + dst = 0; + + if( src == 0 ) { + m_ZF = 1; + } else { + m_ZF = 0; + dst = temp = 31; + while( (src & (1 << temp)) == 0 ) { + temp--; + dst = temp; + CYCLES(CYCLES_BSR); + } + STORE_REG32(modrm, dst); + } + CYCLES(CYCLES_BSR_BASE); +} + +void i386_device::i386_bt_rm32_r32() // Opcode 0x0f a3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),0); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_REG_MEM); + } +} + +void i386_device::i386_btc_rm32_r32() // Opcode 0x0f bb +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTC_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTC_REG_MEM); + } +} + +void i386_device::i386_btr_rm32_r32() // Opcode 0x0f b3 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTR_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTR_REG_MEM); + } +} + +void i386_device::i386_bts_rm32_r32() // Opcode 0x0f ab +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 bit = LOAD_REG32(modrm); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTS_REG_REG); + } else { + UINT8 segment; + UINT32 ea = GetNonTranslatedEA(modrm,&segment); + UINT32 bit = LOAD_REG32(modrm); + ea += 4*(bit/32); + ea = i386_translate(segment,(m_address_size)?ea:(ea&0xffff),1); + bit %= 32; + UINT32 dst = READ32(ea); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTS_REG_MEM); + } +} + +void i386_device::i386_call_abs32() // Opcode 0x9a +{ + UINT32 offset = FETCH32(); + UINT16 ptr = FETCH16(); + + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_call(ptr,offset,0,1); + } + else + { + PUSH32(m_sreg[CS].selector ); + PUSH32(m_eip ); + m_sreg[CS].selector = ptr; + m_performed_intersegment_jump = 1; + m_eip = offset; + i386_load_segment_descriptor(CS); + } + CYCLES(CYCLES_CALL_INTERSEG); + CHANGE_PC(m_eip); +} + +void i386_device::i386_call_rel32() // Opcode 0xe8 +{ + INT32 disp = FETCH32(); + PUSH32(m_eip ); + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_CALL); /* TODO: Timing = 7 + m */ +} + +void i386_device::i386_cdq() // Opcode 0x99 +{ + if( REG32(EAX) & 0x80000000 ) { + REG32(EDX) = 0xffffffff; + } else { + REG32(EDX) = 0x00000000; + } + CYCLES(CYCLES_CWD); +} + +void i386_device::i386_cmp_rm32_r32() // Opcode 0x39 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG32(modrm); + dst = READ32(ea); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } +} + +void i386_device::i386_cmp_r32_rm32() // Opcode 0x3b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + SUB32(dst, src); + CYCLES(CYCLES_CMP_MEM_REG); + } +} + +void i386_device::i386_cmp_eax_i32() // Opcode 0x3d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + SUB32(dst, src); + CYCLES(CYCLES_CMP_IMM_ACC); +} + +void i386_device::i386_cmpsd() // Opcode 0xa7 +{ + UINT32 eas, ead, src, dst; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ32(eas); + dst = READ32(ead); + SUB32(src,dst); + BUMP_SI(4); + BUMP_DI(4); + CYCLES(CYCLES_CMPS); +} + +void i386_device::i386_cwde() // Opcode 0x98 +{ + REG32(EAX) = (INT32)((INT16)REG16(AX)); + CYCLES(CYCLES_CBW); +} + +void i386_device::i386_dec_eax() // Opcode 0x48 +{ + REG32(EAX) = DEC32(REG32(EAX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_ecx() // Opcode 0x49 +{ + REG32(ECX) = DEC32(REG32(ECX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_edx() // Opcode 0x4a +{ + REG32(EDX) = DEC32(REG32(EDX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_ebx() // Opcode 0x4b +{ + REG32(EBX) = DEC32(REG32(EBX) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_esp() // Opcode 0x4c +{ + REG32(ESP) = DEC32(REG32(ESP) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_ebp() // Opcode 0x4d +{ + REG32(EBP) = DEC32(REG32(EBP) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_esi() // Opcode 0x4e +{ + REG32(ESI) = DEC32(REG32(ESI) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_dec_edi() // Opcode 0x4f +{ + REG32(EDI) = DEC32(REG32(EDI) ); + CYCLES(CYCLES_DEC_REG); +} + +void i386_device::i386_imul_r32_rm32() // Opcode 0x0f af +{ + UINT8 modrm = FETCH(); + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + src = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_REG_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_REG_REG); /* TODO: Correct multiply timing */ + } + + dst = (INT64)(INT32)LOAD_REG32(modrm); + result = src * dst; + + STORE_REG32(modrm, (UINT32)result); + + m_CF = m_OF = !(result == (INT64)(INT32)result); +} + +void i386_device::i386_imul_r32_rm32_i32() // Opcode 0x69 +{ + UINT8 modrm = FETCH(); + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + dst = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_REG_IMM_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + dst = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_MEM_IMM_REG); /* TODO: Correct multiply timing */ + } + + src = (INT64)(INT32)FETCH32(); + result = src * dst; + + STORE_REG32(modrm, (UINT32)result); + + m_CF = m_OF = !(result == (INT64)(INT32)result); +} + +void i386_device::i386_imul_r32_rm32_i8() // Opcode 0x6b +{ + UINT8 modrm = FETCH(); + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + dst = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_REG_IMM_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + dst = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_MEM_IMM_REG); /* TODO: Correct multiply timing */ + } + + src = (INT64)(INT8)FETCH(); + result = src * dst; + + STORE_REG32(modrm, (UINT32)result); + + m_CF = m_OF = !(result == (INT64)(INT32)result); +} + +void i386_device::i386_in_eax_i8() // Opcode 0xe5 +{ + UINT16 port = FETCH(); + UINT32 data = READPORT32(port); + REG32(EAX) = data; + CYCLES(CYCLES_IN_VAR); +} + +void i386_device::i386_in_eax_dx() // Opcode 0xed +{ + UINT16 port = REG16(DX); + UINT32 data = READPORT32(port); + REG32(EAX) = data; + CYCLES(CYCLES_IN); +} + +void i386_device::i386_inc_eax() // Opcode 0x40 +{ + REG32(EAX) = INC32(REG32(EAX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_ecx() // Opcode 0x41 +{ + REG32(ECX) = INC32(REG32(ECX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_edx() // Opcode 0x42 +{ + REG32(EDX) = INC32(REG32(EDX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_ebx() // Opcode 0x43 +{ + REG32(EBX) = INC32(REG32(EBX) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_esp() // Opcode 0x44 +{ + REG32(ESP) = INC32(REG32(ESP) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_ebp() // Opcode 0x45 +{ + REG32(EBP) = INC32(REG32(EBP) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_esi() // Opcode 0x46 +{ + REG32(ESI) = INC32(REG32(ESI) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_inc_edi() // Opcode 0x47 +{ + REG32(EDI) = INC32(REG32(EDI) ); + CYCLES(CYCLES_INC_REG); +} + +void i386_device::i386_iret32() // Opcode 0xcf +{ + if( PROTECTED_MODE ) + { + i386_protected_mode_iret(1); + } + else + { + /* TODO: #SS(0) exception */ + /* TODO: #GP(0) exception */ + m_eip = POP32(); + m_sreg[CS].selector = POP32() & 0xffff; + set_flags(POP32() ); + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_IRET); +} + +void i386_device::i386_ja_rel32() // Opcode 0x0f 87 +{ + INT32 disp = FETCH32(); + if( m_CF == 0 && m_ZF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jbe_rel32() // Opcode 0x0f 86 +{ + INT32 disp = FETCH32(); + if( m_CF != 0 || m_ZF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jc_rel32() // Opcode 0x0f 82 +{ + INT32 disp = FETCH32(); + if( m_CF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jg_rel32() // Opcode 0x0f 8f +{ + INT32 disp = FETCH32(); + if( m_ZF == 0 && (m_SF == m_OF) ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jge_rel32() // Opcode 0x0f 8d +{ + INT32 disp = FETCH32(); + if(m_SF == m_OF) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jl_rel32() // Opcode 0x0f 8c +{ + INT32 disp = FETCH32(); + if( (m_SF != m_OF) ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jle_rel32() // Opcode 0x0f 8e +{ + INT32 disp = FETCH32(); + if( m_ZF != 0 || (m_SF != m_OF) ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnc_rel32() // Opcode 0x0f 83 +{ + INT32 disp = FETCH32(); + if( m_CF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jno_rel32() // Opcode 0x0f 81 +{ + INT32 disp = FETCH32(); + if( m_OF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnp_rel32() // Opcode 0x0f 8b +{ + INT32 disp = FETCH32(); + if( m_PF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jns_rel32() // Opcode 0x0f 89 +{ + INT32 disp = FETCH32(); + if( m_SF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jnz_rel32() // Opcode 0x0f 85 +{ + INT32 disp = FETCH32(); + if( m_ZF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jo_rel32() // Opcode 0x0f 80 +{ + INT32 disp = FETCH32(); + if( m_OF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jp_rel32() // Opcode 0x0f 8a +{ + INT32 disp = FETCH32(); + if( m_PF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_js_rel32() // Opcode 0x0f 88 +{ + INT32 disp = FETCH32(); + if( m_SF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jz_rel32() // Opcode 0x0f 84 +{ + INT32 disp = FETCH32(); + if( m_ZF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCC_FULL_DISP); /* TODO: Timing = 7 + m */ + } else { + CYCLES(CYCLES_JCC_FULL_DISP_NOBRANCH); + } +} + +void i386_device::i386_jcxz32() // Opcode 0xe3 +{ + INT8 disp = FETCH(); + int val = (m_address_size)?(REG32(ECX) == 0):(REG16(CX) == 0); + if( val ) { + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JCXZ); /* TODO: Timing = 9 + m */ + } else { + CYCLES(CYCLES_JCXZ_NOBRANCH); + } +} + +void i386_device::i386_jmp_rel32() // Opcode 0xe9 +{ + UINT32 disp = FETCH32(); + /* TODO: Segment limit */ + m_eip += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_JMP); /* TODO: Timing = 7 + m */ +} + +void i386_device::i386_jmp_abs32() // Opcode 0xea +{ + UINT32 address = FETCH32(); + UINT16 segment = FETCH16(); + + if( PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_jump(segment,address,0,1); + } + else + { + m_eip = address; + m_sreg[CS].selector = segment; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS); + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_JMP_INTERSEG); +} + +void i386_device::i386_lea32() // Opcode 0x8d +{ + UINT8 modrm = FETCH(); + UINT32 ea = GetNonTranslatedEA(modrm,NULL); + if (!m_address_size) + { + ea &= 0xffff; + } + STORE_REG32(modrm, ea); + CYCLES(CYCLES_LEA); +} + +void i386_device::i386_enter32() // Opcode 0xc8 +{ + UINT16 framesize = FETCH16(); + UINT8 level = FETCH() % 32; + UINT8 x; + UINT32 frameptr; + PUSH32(REG32(EBP)); + if(!STACK_32BIT) + frameptr = REG16(SP); + else + frameptr = REG32(ESP); + + if(level > 0) + { + for(x=1;x<level-1;x++) + { + REG32(EBP) -= 4; + PUSH32(READ32(REG32(EBP))); + } + PUSH32(frameptr); + } + REG32(EBP) = frameptr; + if(!STACK_32BIT) + REG16(SP) -= framesize; + else + REG32(ESP) -= framesize; + CYCLES(CYCLES_ENTER); +} + +void i386_device::i386_leave32() // Opcode 0xc9 +{ + if(!STACK_32BIT) + REG16(SP) = REG16(BP); + else + REG32(ESP) = REG32(EBP); + REG32(EBP) = POP32(); + CYCLES(CYCLES_LEAVE); +} + +void i386_device::i386_lodsd() // Opcode 0xad +{ + UINT32 eas; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + REG32(EAX) = READ32(eas); + BUMP_SI(4); + CYCLES(CYCLES_LODS); +} + +void i386_device::i386_loop32() // Opcode 0xe2 +{ + INT8 disp = FETCH(); + INT32 reg = (m_address_size)?--REG32(ECX):--REG16(CX); + if( reg != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_LOOP); /* TODO: Timing = 11 + m */ +} + +void i386_device::i386_loopne32() // Opcode 0xe0 +{ + INT8 disp = FETCH(); + INT32 reg = (m_address_size)?--REG32(ECX):--REG16(CX); + if( reg != 0 && m_ZF == 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_LOOPNZ); /* TODO: Timing = 11 + m */ +} + +void i386_device::i386_loopz32() // Opcode 0xe1 +{ + INT8 disp = FETCH(); + INT32 reg = (m_address_size)?--REG32(ECX):--REG16(CX); + if( reg != 0 && m_ZF != 0 ) { + m_eip += disp; + CHANGE_PC(m_eip); + } + CYCLES(CYCLES_LOOPZ); /* TODO: Timing = 11 + m */ +} + +void i386_device::i386_mov_rm32_r32() // Opcode 0x89 +{ + UINT32 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + STORE_RM32(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + WRITE32(ea, src); + CYCLES(CYCLES_MOV_REG_MEM); + } +} + +void i386_device::i386_mov_r32_rm32() // Opcode 0x8b +{ + UINT32 src; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOV_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOV_MEM_REG); + } +} + +void i386_device::i386_mov_rm32_i32() // Opcode 0xc7 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 value = FETCH32(); + STORE_RM32(modrm, value); + CYCLES(CYCLES_MOV_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 value = FETCH32(); + WRITE32(ea, value); + CYCLES(CYCLES_MOV_IMM_MEM); + } +} + +void i386_device::i386_mov_eax_m32() // Opcode 0xa1 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 0 ); + } else { + ea = i386_translate(DS, offset, 0 ); + } + REG32(EAX) = READ32(ea); + CYCLES(CYCLES_MOV_MEM_ACC); +} + +void i386_device::i386_mov_m32_eax() // Opcode 0xa3 +{ + UINT32 offset, ea; + if( m_address_size ) { + offset = FETCH32(); + } else { + offset = FETCH16(); + } + if( m_segment_prefix ) { + ea = i386_translate(m_segment_override, offset, 1 ); + } else { + ea = i386_translate(DS, offset, 1 ); + } + WRITE32(ea, REG32(EAX) ); + CYCLES(CYCLES_MOV_ACC_MEM); +} + +void i386_device::i386_mov_eax_i32() // Opcode 0xb8 +{ + REG32(EAX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ecx_i32() // Opcode 0xb9 +{ + REG32(ECX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_edx_i32() // Opcode 0xba +{ + REG32(EDX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ebx_i32() // Opcode 0xbb +{ + REG32(EBX) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_esp_i32() // Opcode 0xbc +{ + REG32(ESP) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_ebp_i32() // Opcode 0xbd +{ + REG32(EBP) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_esi_i32() // Opcode 0xbe +{ + REG32(ESI) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_mov_edi_i32() // Opcode 0xbf +{ + REG32(EDI) = FETCH32(); + CYCLES(CYCLES_MOV_IMM_REG); +} + +void i386_device::i386_movsd() // Opcode 0xa5 +{ + UINT32 eas, ead, v; + if( m_segment_prefix ) { + eas = i386_translate(m_segment_override, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } else { + eas = i386_translate(DS, m_address_size ? REG32(ESI) : REG16(SI), 0 ); + } + ead = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + v = READ32(eas); + WRITE32(ead, v); + BUMP_SI(4); + BUMP_DI(4); + CYCLES(CYCLES_MOVS); +} + +void i386_device::i386_movsx_r32_rm8() // Opcode 0x0f be +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + INT32 src = (INT8)LOAD_RM8(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + INT32 src = (INT8)READ8(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_MEM_REG); + } +} + +void i386_device::i386_movsx_r32_rm16() // Opcode 0x0f bf +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + INT32 src = (INT16)LOAD_RM16(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + INT32 src = (INT16)READ16(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVSX_MEM_REG); + } +} + +void i386_device::i386_movzx_r32_rm8() // Opcode 0x0f b6 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 src = (UINT8)LOAD_RM8(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 src = (UINT8)READ8(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_MEM_REG); + } +} + +void i386_device::i386_movzx_r32_rm16() // Opcode 0x0f b7 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 src = (UINT16)LOAD_RM16(modrm); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 src = (UINT16)READ16(ea); + STORE_REG32(modrm, src); + CYCLES(CYCLES_MOVZX_MEM_REG); + } +} + +void i386_device::i386_or_rm32_r32() // Opcode 0x09 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = OR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = OR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_or_r32_rm32() // Opcode 0x0b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = OR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = OR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_or_eax_i32() // Opcode 0x0d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = OR32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_out_eax_i8() // Opcode 0xe7 +{ + UINT16 port = FETCH(); + UINT32 data = REG32(EAX); + WRITEPORT32(port, data); + CYCLES(CYCLES_OUT_VAR); +} + +void i386_device::i386_out_eax_dx() // Opcode 0xef +{ + UINT16 port = REG16(DX); + UINT32 data = REG32(EAX); + WRITEPORT32(port, data); + CYCLES(CYCLES_OUT); +} + +void i386_device::i386_pop_eax() // Opcode 0x58 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EAX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_ecx() // Opcode 0x59 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(ECX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_edx() // Opcode 0x5a +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EDX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_ebx() // Opcode 0x5b +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EBX) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_esp() // Opcode 0x5c +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(ESP) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_ebp() // Opcode 0x5d +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EBP) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_esi() // Opcode 0x5e +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(ESI) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +void i386_device::i386_pop_edi() // Opcode 0x5f +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + REG32(EDI) = POP32(); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_REG_SHORT); +} + +bool i386_device::i386_pop_seg32(int segment) +{ + UINT32 ea, offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + UINT32 value; + bool fault; + if(i386_limit_check(SS,offset+3) == 0) + { + ea = i386_translate(SS, offset, 0); + value = READ32(ea); + i386_sreg_load(value, segment, &fault); + if(fault) return false; + if(STACK_32BIT) + REG32(ESP) = offset + 4; + else + REG16(SP) = offset + 4; + } + else + { + m_ext = 1; + i386_trap_with_error(FAULT_SS,0,0,0); + return false; + } + CYCLES(CYCLES_POP_SREG); + return true; +} + +void i386_device::i386_pop_ds32() // Opcode 0x1f +{ + i386_pop_seg32(DS); +} + +void i386_device::i386_pop_es32() // Opcode 0x07 +{ + i386_pop_seg32(ES); +} + +void i386_device::i386_pop_fs32() // Opcode 0x0f a1 +{ + i386_pop_seg32(FS); +} + +void i386_device::i386_pop_gs32() // Opcode 0x0f a9 +{ + i386_pop_seg32(GS); +} + +void i386_device::i386_pop_ss32() // Opcode 0x17 +{ + if(!i386_pop_seg32(SS)) return; + if(m_IF != 0) // if external interrupts are enabled + { + m_IF = 0; // reset IF for the next instruction + m_delayed_interrupt_enable = 1; + } +} + +void i386_device::i386_pop_rm32() // Opcode 0x8f +{ + UINT8 modrm = FETCH(); + UINT32 value; + UINT32 ea, offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+3) == 0) + { + // be careful here, if the write references the esp register + // it expects the post-pop value but esp must be wound back + // if the write faults + UINT32 temp_sp = REG32(ESP); + value = POP32(); + + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, value); + } else { + ea = GetEA(modrm,1); + try + { + WRITE32(ea, value); + } + catch(UINT64 e) + { + REG32(ESP) = temp_sp; + throw e; + } + } + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POP_RM); +} + +void i386_device::i386_popad() // Opcode 0x61 +{ + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + if(i386_limit_check(SS,offset+31) == 0) + { + REG32(EDI) = POP32(); + REG32(ESI) = POP32(); + REG32(EBP) = POP32(); + REG32(ESP) += 4; + REG32(EBX) = POP32(); + REG32(EDX) = POP32(); + REG32(ECX) = POP32(); + REG32(EAX) = POP32(); + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POPA); +} + +void i386_device::i386_popfd() // Opcode 0x9d +{ + UINT32 value; + UINT32 current = get_flags(); + UINT8 IOPL = (current >> 12) & 0x03; + UINT32 mask = 0x00257fd5; // VM, VIP and VIF cannot be set by POPF/POPFD + UINT32 offset = (STACK_32BIT ? REG32(ESP) : REG16(SP)); + + // IOPL can only change if CPL is 0 + if(m_CPL != 0) + mask &= ~0x00003000; + + // IF can only change if CPL is at least as privileged as IOPL + if(m_CPL > IOPL) + mask &= ~0x00000200; + + if(V8086_MODE) + { + if(IOPL < 3) + { + logerror("POPFD(%08x): IOPL < 3 while in V86 mode.\n",m_pc); + FAULT(FAULT_GP,0) // #GP(0) + } + mask &= ~0x00003000; // IOPL cannot be changed while in V8086 mode + } + + if(i386_limit_check(SS,offset+3) == 0) + { + value = POP32(); + value &= ~0x00010000; // RF will always return zero + set_flags((current & ~mask) | (value & mask)); // mask out reserved bits + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_POPF); +} + +void i386_device::i386_push_eax() // Opcode 0x50 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EAX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_ecx() // Opcode 0x51 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(ECX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_edx() // Opcode 0x52 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EDX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_ebx() // Opcode 0x53 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EBX) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_esp() // Opcode 0x54 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(ESP) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_ebp() // Opcode 0x55 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EBP) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_esi() // Opcode 0x56 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(ESI) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_edi() // Opcode 0x57 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(REG32(EDI) ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_REG_SHORT); +} + +void i386_device::i386_push_cs32() // Opcode 0x0e +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[CS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_ds32() // Opcode 0x1e +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[DS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_es32() // Opcode 0x06 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[ES].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_fs32() // Opcode 0x0f a0 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[FS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_gs32() // Opcode 0x0f a8 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[GS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_ss32() // Opcode 0x16 +{ + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(m_sreg[SS].selector ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_SREG); +} + +void i386_device::i386_push_i32() // Opcode 0x68 +{ + UINT32 value = FETCH32(); + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(value); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSH_IMM); +} + +void i386_device::i386_pushad() // Opcode 0x60 +{ + UINT32 temp = REG32(ESP); + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 32; + else + offset = (REG16(SP) - 32) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + { + PUSH32(REG32(EAX) ); + PUSH32(REG32(ECX) ); + PUSH32(REG32(EDX) ); + PUSH32(REG32(EBX) ); + PUSH32(temp ); + PUSH32(REG32(EBP) ); + PUSH32(REG32(ESI) ); + PUSH32(REG32(EDI) ); + } + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSHA); +} + +void i386_device::i386_pushfd() // Opcode 0x9c +{ + if(!m_IOP1 && !m_IOP2 && V8086_MODE) + FAULT(FAULT_GP,0) + UINT32 offset; + if(STACK_32BIT) + offset = REG32(ESP) - 4; + else + offset = (REG16(SP) - 4) & 0xffff; + if(i386_limit_check(SS,offset) == 0) + PUSH32(get_flags() & 0x00fcffff ); + else + FAULT(FAULT_SS,0) + CYCLES(CYCLES_PUSHF); +} + +void i386_device::i386_ret_near32_i16() // Opcode 0xc2 +{ + INT16 disp = FETCH16(); + m_eip = POP32(); + REG32(ESP) += disp; + CHANGE_PC(m_eip); + CYCLES(CYCLES_RET_IMM); /* TODO: Timing = 10 + m */ +} + +void i386_device::i386_ret_near32() // Opcode 0xc3 +{ + m_eip = POP32(); + CHANGE_PC(m_eip); + CYCLES(CYCLES_RET); /* TODO: Timing = 10 + m */ +} + +void i386_device::i386_sbb_rm32_r32() // Opcode 0x19 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = SBB32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = SBB32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sbb_r32_rm32() // Opcode 0x1b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = SBB32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = SBB32(dst, src, m_CF); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sbb_eax_i32() // Opcode 0x1d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = SBB32(dst, src, m_CF); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_scasd() // Opcode 0xaf +{ + UINT32 eas, src, dst; + eas = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 0 ); + src = READ32(eas); + dst = REG32(EAX); + SUB32(dst, src); + BUMP_DI(4); + CYCLES(CYCLES_SCAS); +} + +void i386_device::i386_shld32_i8() // Opcode 0x0f a4 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHLD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHLD_MEM); + } +} + +void i386_device::i386_shld32_cl() // Opcode 0x0f a5 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHLD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (32-shift))) ? 1 : 0; + dst = (dst << shift) | (upper >> (32-shift)); + m_OF = m_CF ^ (dst >> 31); + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHLD_MEM); + } +} + +void i386_device::i386_shrd32_i8() // Opcode 0x0f ac +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHRD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = FETCH(); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHRD_MEM); + } +} + +void i386_device::i386_shrd32_cl() // Opcode 0x0f ad +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + STORE_RM32(modrm, dst); + CYCLES(CYCLES_SHRD_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT32 upper = LOAD_REG32(modrm); + UINT8 shift = REG8(CL); + shift &= 31; + if( shift == 0 ) { + } else { + m_CF = (dst & (1 << (shift-1))) ? 1 : 0; + dst = (dst >> shift) | (upper << (32-shift)); + m_OF = ((dst >> 31) ^ (dst >> 30)) & 1; + SetSZPF32(dst); + } + WRITE32(ea, dst); + CYCLES(CYCLES_SHRD_MEM); + } +} + +void i386_device::i386_stosd() // Opcode 0xab +{ + UINT32 eas = i386_translate(ES, m_address_size ? REG32(EDI) : REG16(DI), 1 ); + WRITE32(eas, REG32(EAX)); + BUMP_DI(4); + CYCLES(CYCLES_STOS); +} + +void i386_device::i386_sub_rm32_r32() // Opcode 0x29 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = SUB32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = SUB32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_sub_r32_rm32() // Opcode 0x2b +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = SUB32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = SUB32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_sub_eax_i32() // Opcode 0x2d +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = SUB32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + +void i386_device::i386_test_eax_i32() // Opcode 0xa9 +{ + UINT32 src = FETCH32(); + UINT32 dst = REG32(EAX); + dst = src & dst; + SetSZPF32(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_IMM_ACC); +} + +void i386_device::i386_test_rm32_r32() // Opcode 0x85 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = src & dst; + SetSZPF32(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = src & dst; + SetSZPF32(dst); + m_CF = 0; + m_OF = 0; + CYCLES(CYCLES_TEST_REG_MEM); + } +} + +void i386_device::i386_xchg_eax_ecx() // Opcode 0x91 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(ECX); + REG32(ECX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_edx() // Opcode 0x92 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EDX); + REG32(EDX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_ebx() // Opcode 0x93 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EBX); + REG32(EBX) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_esp() // Opcode 0x94 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(ESP); + REG32(ESP) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_ebp() // Opcode 0x95 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EBP); + REG32(EBP) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_esi() // Opcode 0x96 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(ESI); + REG32(ESI) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_eax_edi() // Opcode 0x97 +{ + UINT32 temp; + temp = REG32(EAX); + REG32(EAX) = REG32(EDI); + REG32(EDI) = temp; + CYCLES(CYCLES_XCHG_REG_REG); +} + +void i386_device::i386_xchg_r32_rm32() // Opcode 0x87 +{ + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + UINT32 src = LOAD_RM32(modrm); + UINT32 dst = LOAD_REG32(modrm); + STORE_REG32(modrm, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_XCHG_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 src = READ32(ea); + UINT32 dst = LOAD_REG32(modrm); + WRITE32(ea, dst); + STORE_REG32(modrm, src); + CYCLES(CYCLES_XCHG_REG_MEM); + } +} + +void i386_device::i386_xor_rm32_r32() // Opcode 0x31 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_REG32(modrm); + dst = LOAD_RM32(modrm); + dst = XOR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + src = LOAD_REG32(modrm); + dst = READ32(ea); + dst = XOR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } +} + +void i386_device::i386_xor_r32_rm32() // Opcode 0x33 +{ + UINT32 src, dst; + UINT8 modrm = FETCH(); + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + dst = LOAD_REG32(modrm); + dst = XOR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + dst = LOAD_REG32(modrm); + dst = XOR32(dst, src); + STORE_REG32(modrm, dst); + CYCLES(CYCLES_ALU_MEM_REG); + } +} + +void i386_device::i386_xor_eax_i32() // Opcode 0x35 +{ + UINT32 src, dst; + src = FETCH32(); + dst = REG32(EAX); + dst = XOR32(dst, src); + REG32(EAX) = dst; + CYCLES(CYCLES_ALU_IMM_ACC); +} + + + +void i386_device::i386_group81_32() // Opcode 0x81 +{ + UINT32 ea; + UINT32 src, dst; + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: // ADD Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = ADD32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = ADD32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 1: // OR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = OR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = OR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 2: // ADC Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = ADC32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = ADC32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 3: // SBB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = SBB32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = SBB32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 4: // AND Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = AND32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = AND32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 5: // SUB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = SUB32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = SUB32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 6: // XOR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + dst = XOR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = FETCH32(); + dst = XOR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 7: // CMP Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = FETCH32(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ32(ea); + src = FETCH32(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } + break; + } +} + +void i386_device::i386_group83_32() // Opcode 0x83 +{ + UINT32 ea; + UINT32 src, dst; + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: // ADD Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADD32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADD32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 1: // OR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = OR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = OR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 2: // ADC Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADC32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = ADC32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 3: // SBB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = ((UINT32)(INT32)(INT8)FETCH()); + dst = SBB32(dst, src, m_CF); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = ((UINT32)(INT32)(INT8)FETCH()); + dst = SBB32(dst, src, m_CF); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 4: // AND Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = AND32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = AND32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 5: // SUB Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = SUB32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = SUB32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 6: // XOR Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = XOR32(dst, src); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_ALU_REG_REG); + } else { + ea = GetEA(modrm,1); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + dst = XOR32(dst, src); + WRITE32(ea, dst); + CYCLES(CYCLES_ALU_REG_MEM); + } + break; + case 7: // CMP Rm32, i32 + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + src = (UINT32)(INT32)(INT8)FETCH(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_REG); + } else { + ea = GetEA(modrm,0); + dst = READ32(ea); + src = (UINT32)(INT32)(INT8)FETCH(); + SUB32(dst, src); + CYCLES(CYCLES_CMP_REG_MEM); + } + break; + } +} + +void i386_device::i386_groupC1_32() // Opcode 0xc1 +{ + UINT32 dst; + UINT8 modrm = FETCH(); + UINT8 shift; + + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate32(modrm, dst, shift); + STORE_RM32(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ32(ea); + shift = FETCH() & 0x1f; + dst = i386_shift_rotate32(modrm, dst, shift); + WRITE32(ea, dst); + } +} + +void i386_device::i386_groupD1_32() // Opcode 0xd1 +{ + UINT32 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + dst = i386_shift_rotate32(modrm, dst, 1); + STORE_RM32(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ32(ea); + dst = i386_shift_rotate32(modrm, dst, 1); + WRITE32(ea, dst); + } +} + +void i386_device::i386_groupD3_32() // Opcode 0xd3 +{ + UINT32 dst; + UINT8 modrm = FETCH(); + + if( modrm >= 0xc0 ) { + dst = LOAD_RM32(modrm); + dst = i386_shift_rotate32(modrm, dst, REG8(CL)); + STORE_RM32(modrm, dst); + } else { + UINT32 ea = GetEA(modrm,1); + dst = READ32(ea); + dst = i386_shift_rotate32(modrm, dst, REG8(CL)); + WRITE32(ea, dst); + } +} + +void i386_device::i386_groupF7_32() // Opcode 0xf7 +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* TEST Rm32, i32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT32 src = FETCH32(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF32(dst); + CYCLES(CYCLES_TEST_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 dst = READ32(ea); + UINT32 src = FETCH32(); + dst &= src; + m_CF = m_OF = m_AF = 0; + SetSZPF32(dst); + CYCLES(CYCLES_TEST_IMM_MEM); + } + break; + case 2: /* NOT Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = ~dst; + STORE_RM32(modrm, dst); + CYCLES(CYCLES_NOT_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = ~dst; + WRITE32(ea, dst); + CYCLES(CYCLES_NOT_MEM); + } + break; + case 3: /* NEG Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = SUB32(0, dst ); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_NEG_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = SUB32(0, dst ); + WRITE32(ea, dst); + CYCLES(CYCLES_NEG_MEM); + } + break; + case 4: /* MUL EAX, Rm32 */ + { + UINT64 result; + UINT32 src, dst; + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + CYCLES(CYCLES_MUL32_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + CYCLES(CYCLES_MUL32_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = REG32(EAX); + result = (UINT64)src * (UINT64)dst; + REG32(EDX) = (UINT32)(result >> 32); + REG32(EAX) = (UINT32)result; + + m_CF = m_OF = (REG32(EDX) != 0); + } + break; + case 5: /* IMUL EAX, Rm32 */ + { + INT64 result; + INT64 src, dst; + if( modrm >= 0xc0 ) { + src = (INT64)(INT32)LOAD_RM32(modrm); + CYCLES(CYCLES_IMUL32_ACC_REG); /* TODO: Correct multiply timing */ + } else { + UINT32 ea = GetEA(modrm,0); + src = (INT64)(INT32)READ32(ea); + CYCLES(CYCLES_IMUL32_ACC_MEM); /* TODO: Correct multiply timing */ + } + + dst = (INT64)(INT32)REG32(EAX); + result = src * dst; + + REG32(EDX) = (UINT32)(result >> 32); + REG32(EAX) = (UINT32)result; + + m_CF = m_OF = !(result == (INT64)(INT32)result); + } + break; + case 6: /* DIV EAX, Rm32 */ + { + UINT64 quotient, remainder, result; + UINT32 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + CYCLES(CYCLES_DIV32_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + CYCLES(CYCLES_DIV32_ACC_MEM); + } + + quotient = ((UINT64)(REG32(EDX)) << 32) | (UINT64)(REG32(EAX)); + if( src ) { + remainder = quotient % (UINT64)src; + result = quotient / (UINT64)src; + if( result > 0xffffffff ) { + /* TODO: Divide error */ + } else { + REG32(EDX) = (UINT32)remainder; + REG32(EAX) = (UINT32)result; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + case 7: /* IDIV EAX, Rm32 */ + { + INT64 quotient, remainder, result; + UINT32 src; + if( modrm >= 0xc0 ) { + src = LOAD_RM32(modrm); + CYCLES(CYCLES_IDIV32_ACC_REG); + } else { + UINT32 ea = GetEA(modrm,0); + src = READ32(ea); + CYCLES(CYCLES_IDIV32_ACC_MEM); + } + + quotient = (((INT64)REG32(EDX)) << 32) | ((UINT64)REG32(EAX)); + if( src ) { + remainder = quotient % (INT64)(INT32)src; + result = quotient / (INT64)(INT32)src; + if( result > 0xffffffff ) { + /* TODO: Divide error */ + } else { + REG32(EDX) = (UINT32)remainder; + REG32(EAX) = (UINT32)result; + } + } else { + i386_trap(0, 0, 0); + } + } + break; + } +} + +void i386_device::i386_groupFF_32() // Opcode 0xff +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* INC Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = INC32(dst); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_INC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = INC32(dst); + WRITE32(ea, dst); + CYCLES(CYCLES_INC_MEM); + } + break; + case 1: /* DEC Rm32 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + dst = DEC32(dst); + STORE_RM32(modrm, dst); + CYCLES(CYCLES_DEC_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + dst = DEC32(dst); + WRITE32(ea, dst); + CYCLES(CYCLES_DEC_MEM); + } + break; + case 2: /* CALL Rm32 */ + { + UINT32 address; + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + CYCLES(CYCLES_CALL_REG); /* TODO: Timing = 7 + m */ + } else { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea); + CYCLES(CYCLES_CALL_MEM); /* TODO: Timing = 10 + m */ + } + PUSH32(m_eip ); + m_eip = address; + CHANGE_PC(m_eip); + } + break; + case 3: /* CALL FAR Rm32 */ + { + UINT16 selector; + UINT32 address; + + if( modrm >= 0xc0 ) + { + report_invalid_modrm("groupFF_32", modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea + 0); + selector = READ16(ea + 4); + CYCLES(CYCLES_CALL_MEM_INTERSEG); /* TODO: Timing = 10 + m */ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_call(selector,address,1,1); + } + else + { + PUSH32(m_sreg[CS].selector ); + PUSH32(m_eip ); + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS ); + m_eip = address; + CHANGE_PC(m_eip); + } + } + } + break; + case 4: /* JMP Rm32 */ + { + UINT32 address; + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + CYCLES(CYCLES_JMP_REG); /* TODO: Timing = 7 + m */ + } else { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea); + CYCLES(CYCLES_JMP_MEM); /* TODO: Timing = 10 + m */ + } + m_eip = address; + CHANGE_PC(m_eip); + } + break; + case 5: /* JMP FAR Rm32 */ + { + UINT16 selector; + UINT32 address; + + if( modrm >= 0xc0 ) + { + report_invalid_modrm("groupFF_32", modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + address = READ32(ea + 0); + selector = READ16(ea + 4); + CYCLES(CYCLES_JMP_MEM_INTERSEG); /* TODO: Timing = 10 + m */ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_jump(selector,address,1,1); + } + else + { + m_sreg[CS].selector = selector; + m_performed_intersegment_jump = 1; + i386_load_segment_descriptor(CS ); + m_eip = address; + CHANGE_PC(m_eip); + } + } + } + break; + case 6: /* PUSH Rm32 */ + { + UINT32 value; + if( modrm >= 0xc0 ) { + value = LOAD_RM32(modrm); + } else { + UINT32 ea = GetEA(modrm,0); + value = READ32(ea); + } + PUSH32(value); + CYCLES(CYCLES_PUSH_RM); + } + break; + default: + report_invalid_modrm("groupFF_32", modrm); + break; + } +} + +void i386_device::i386_group0F00_32() // Opcode 0x0f 00 +{ + UINT32 address, ea; + UINT8 modrm = FETCH(); + I386_SREG seg; + UINT8 result; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SLDT */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, m_ldtr.segment); + CYCLES(CYCLES_SLDT_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_ldtr.segment); + CYCLES(CYCLES_SLDT_MEM); + } + } + else + { + i386_trap(6, 0, 0); + } + break; + case 1: /* STR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + STORE_RM32(modrm, m_task.segment); + CYCLES(CYCLES_STR_REG); + } else { + ea = GetEA(modrm,1); + WRITE16(ea, m_task.segment); + CYCLES(CYCLES_STR_MEM); + } + } + else + { + i386_trap(6, 0, 0); + } + break; + case 2: /* LLDT */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + m_ldtr.segment = address; + CYCLES(CYCLES_LLDT_REG); + } else { + ea = GetEA(modrm,0); + m_ldtr.segment = READ32(ea); + CYCLES(CYCLES_LLDT_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = m_ldtr.segment; + i386_load_protected_mode_segment(&seg,NULL); + m_ldtr.limit = seg.limit; + m_ldtr.base = seg.base; + m_ldtr.flags = seg.flags; + } + else + { + i386_trap(6, 0, 0); + } + break; + + case 3: /* LTR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if(m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + m_task.segment = address; + CYCLES(CYCLES_LTR_REG); + } else { + ea = GetEA(modrm,0); + m_task.segment = READ32(ea); + CYCLES(CYCLES_LTR_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = m_task.segment; + i386_load_protected_mode_segment(&seg,NULL); + + UINT32 addr = ((seg.selector & 4) ? m_ldtr.base : m_gdtr.base) + (seg.selector & ~7) + 5; + i386_translate_address(TRANSLATE_READ, &addr, NULL); + m_program->write_byte(addr, (seg.flags & 0xff) | 2); + + m_task.limit = seg.limit; + m_task.base = seg.base; + m_task.flags = seg.flags | 2; + } + else + { + i386_trap(6, 0, 0); + } + break; + + case 4: /* VERR */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + CYCLES(CYCLES_VERR_REG); + } else { + ea = GetEA(modrm,0); + address = READ32(ea); + CYCLES(CYCLES_VERR_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = address; + result = i386_load_protected_mode_segment(&seg,NULL); + // check if the segment is a code or data segment (not a special segment type, like a TSS, gate, LDT...) + if(!(seg.flags & 0x10)) + result = 0; + // check that the segment is readable + if(seg.flags & 0x10) // is code or data segment + { + if(seg.flags & 0x08) // is code segment, so check if it's readable + { + if(!(seg.flags & 0x02)) + { + result = 0; + } + else + { // check if conforming, these are always readable, regardless of privilege + if(!(seg.flags & 0x04)) + { + // if not conforming, then we must check privilege levels (TODO: current privilege level check) + if(((seg.flags >> 5) & 0x03) < (address & 0x03)) + result = 0; + } + } + } + } + // check that the descriptor privilege is greater or equal to the selector's privilege level and the current privilege (TODO) + SetZF(result); + } + else + { + i386_trap(6, 0, 0); + logerror("i386: VERR: Exception - Running in real mode or virtual 8086 mode.\n"); + } + break; + + case 5: /* VERW */ + if ( PROTECTED_MODE && !V8086_MODE ) + { + if( modrm >= 0xc0 ) { + address = LOAD_RM16(modrm); + CYCLES(CYCLES_VERW_REG); + } else { + ea = GetEA(modrm,0); + address = READ16(ea); + CYCLES(CYCLES_VERW_MEM); + } + memset(&seg, 0, sizeof(seg)); + seg.selector = address; + result = i386_load_protected_mode_segment(&seg,NULL); + // check if the segment is a code or data segment (not a special segment type, like a TSS, gate, LDT...) + if(!(seg.flags & 0x10)) + result = 0; + // check that the segment is writable + if(seg.flags & 0x10) // is code or data segment + { + if(seg.flags & 0x08) // is code segment (and thus, not writable) + { + result = 0; + } + else + { // is data segment + if(!(seg.flags & 0x02)) + result = 0; + } + } + // check that the descriptor privilege is greater or equal to the selector's privilege level and the current privilege (TODO) + if(((seg.flags >> 5) & 0x03) < (address & 0x03)) + result = 0; + SetZF(result); + } + else + { + i386_trap(6, 0, 0); + logerror("i386: VERW: Exception - Running in real mode or virtual 8086 mode.\n"); + } + break; + + default: + report_invalid_modrm("group0F00_32", modrm); + break; + } +} + +void i386_device::i386_group0F01_32() // Opcode 0x0f 01 +{ + UINT8 modrm = FETCH(); + UINT32 address, ea; + + switch( (modrm >> 3) & 0x7 ) + { + case 0: /* SGDT */ + { + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 1 ); + } else { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_gdtr.limit); + WRITE32(ea + 2, m_gdtr.base); + CYCLES(CYCLES_SGDT); + break; + } + case 1: /* SIDT */ + { + if (modrm >= 0xc0) + { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 1 ); + } + else + { + ea = GetEA(modrm,1); + } + WRITE16(ea, m_idtr.limit); + WRITE32(ea + 2, m_idtr.base); + CYCLES(CYCLES_SIDT); + break; + } + case 2: /* LGDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_gdtr.limit = READ16(ea); + m_gdtr.base = READ32(ea + 2); + CYCLES(CYCLES_LGDT); + break; + } + case 3: /* LIDT */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + if( modrm >= 0xc0 ) { + address = LOAD_RM32(modrm); + ea = i386_translate(CS, address, 0 ); + } else { + ea = GetEA(modrm,0); + } + m_idtr.limit = READ16(ea); + m_idtr.base = READ32(ea + 2); + CYCLES(CYCLES_LIDT); + break; + } + case 4: /* SMSW */ + { + if( modrm >= 0xc0 ) { + // smsw stores all of cr0 into register + STORE_RM32(modrm, m_cr[0]); + CYCLES(CYCLES_SMSW_REG); + } else { + /* always 16-bit memory operand */ + ea = GetEA(modrm,1); + WRITE16(ea, m_cr[0]); + CYCLES(CYCLES_SMSW_MEM); + } + break; + } + case 6: /* LMSW */ + { + if(PROTECTED_MODE && m_CPL) + FAULT(FAULT_GP,0) + UINT16 b; + if( modrm >= 0xc0 ) { + b = LOAD_RM16(modrm); + CYCLES(CYCLES_LMSW_REG); + } else { + ea = GetEA(modrm,0); + CYCLES(CYCLES_LMSW_MEM); + b = READ16(ea); + } + if(PROTECTED_MODE) + b |= 0x0001; // cannot return to real mode using this instruction. + m_cr[0] &= ~0x0000000f; + m_cr[0] |= b & 0x0000000f; + break; + } + default: + report_invalid_modrm("group0F01_32", modrm); + break; + } +} + +void i386_device::i386_group0FBA_32() // Opcode 0x0f ba +{ + UINT8 modrm = FETCH(); + + switch( (modrm >> 3) & 0x7 ) + { + case 4: /* BT Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,0); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + + CYCLES(CYCLES_BT_IMM_MEM); + } + break; + case 5: /* BTS Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTS_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst |= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTS_IMM_MEM); + } + break; + case 6: /* BTR Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTR_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst &= ~(1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTR_IMM_MEM); + } + break; + case 7: /* BTC Rm32, i8 */ + if( modrm >= 0xc0 ) { + UINT32 dst = LOAD_RM32(modrm); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + STORE_RM32(modrm, dst); + CYCLES(CYCLES_BTC_IMM_REG); + } else { + UINT32 ea = GetEA(modrm,1); + UINT32 dst = READ32(ea); + UINT8 bit = FETCH(); + + if( dst & (1 << bit) ) + m_CF = 1; + else + m_CF = 0; + dst ^= (1 << bit); + + WRITE32(ea, dst); + CYCLES(CYCLES_BTC_IMM_MEM); + } + break; + default: + report_invalid_modrm("group0FBA_32", modrm); + break; + } +} + +void i386_device::i386_lar_r32_rm32() // Opcode 0x0f 0x02 +{ + UINT8 modrm = FETCH(); + I386_SREG seg; + UINT8 type; + + if(PROTECTED_MODE && !V8086_MODE) + { + memset(&seg,0,sizeof(seg)); + if(modrm >= 0xc0) + { + seg.selector = LOAD_RM32(modrm); + CYCLES(CYCLES_LAR_REG); + } + else + { + UINT32 ea = GetEA(modrm,0); + seg.selector = READ32(ea); + CYCLES(CYCLES_LAR_MEM); + } + if(seg.selector == 0) + { + SetZF(0); // not a valid segment + } + else + { + UINT64 desc; + if(!i386_load_protected_mode_segment(&seg,&desc)) + { + SetZF(0); + return; + } + UINT8 DPL = (seg.flags >> 5) & 3; + if(((DPL < m_CPL) || (DPL < (seg.selector & 3))) && ((seg.flags & 0x1c) != 0x1c)) + { + SetZF(0); + return; + } + if(!(seg.flags & 0x10)) // special segment + { + // check for invalid segment types + type = seg.flags & 0x000f; + if(type == 0x00 || type == 0x08 || type == 0x0a || type == 0x0d) + { + SetZF(0); // invalid segment type + } + else + { + STORE_REG32(modrm,(desc>>32) & 0x00ffff00); + SetZF(1); + } + } + else + { + STORE_REG32(modrm,(desc>>32) & 0x00ffff00); + SetZF(1); + } + } + } + else + { + // illegal opcode + i386_trap(6,0, 0); + logerror("i386: LAR: Exception - running in real mode or virtual 8086 mode.\n"); + } +} + +void i386_device::i386_lsl_r32_rm32() // Opcode 0x0f 0x03 +{ + UINT8 modrm = FETCH(); + UINT32 limit; + I386_SREG seg; + + if(PROTECTED_MODE && !V8086_MODE) + { + memset(&seg, 0, sizeof(seg)); + if(modrm >= 0xc0) + { + seg.selector = LOAD_RM32(modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + seg.selector = READ32(ea); + } + if(seg.selector == 0) + { + SetZF(0); // not a valid segment + } + else + { + UINT8 type; + if(!i386_load_protected_mode_segment(&seg,NULL)) + { + SetZF(0); + return; + } + UINT8 DPL = (seg.flags >> 5) & 3; + if(((DPL < m_CPL) || (DPL < (seg.selector & 3))) && ((seg.flags & 0x1c) != 0x1c)) + { + SetZF(0); + return; + } + type = seg.flags & 0x1f; + switch(type) + { + case 0: + case 4: + case 5: + case 6: + case 7: + case 8: + case 10: + case 12: + case 13: + case 14: + case 15: + SetZF(0); + return; + default: + limit = seg.limit; + STORE_REG32(modrm,limit); + SetZF(1); + } + } + } + else + i386_trap(6, 0, 0); +} + +void i386_device::i386_bound_r32_m32_m32() // Opcode 0x62 +{ + UINT8 modrm; + INT32 val, low, high; + + modrm = FETCH(); + + if (modrm >= 0xc0) + { + low = high = LOAD_RM32(modrm); + } + else + { + UINT32 ea = GetEA(modrm,0); + low = READ32(ea + 0); + high = READ32(ea + 4); + } + val = LOAD_REG32(modrm); + + if ((val < low) || (val > high)) + { + CYCLES(CYCLES_BOUND_OUT_RANGE); + i386_trap(5, 0, 0); + } + else + { + CYCLES(CYCLES_BOUND_IN_RANGE); + } +} + +void i386_device::i386_retf32() // Opcode 0xcb +{ + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_retf(0,1); + } + else + { + m_eip = POP32(); + m_sreg[CS].selector = POP32(); + i386_load_segment_descriptor(CS ); + CHANGE_PC(m_eip); + } + + CYCLES(CYCLES_RET_INTERSEG); +} + +void i386_device::i386_retf_i32() // Opcode 0xca +{ + UINT16 count = FETCH16(); + + if(PROTECTED_MODE && !V8086_MODE) + { + i386_protected_mode_retf(count,1); + } + else + { + m_eip = POP32(); + m_sreg[CS].selector = POP32(); + i386_load_segment_descriptor(CS ); + CHANGE_PC(m_eip); + REG32(ESP) += count; + } + + CYCLES(CYCLES_RET_IMM_INTERSEG); +} + +void i386_device::i386_load_far_pointer32(int s) +{ + UINT8 modrm = FETCH(); + UINT16 selector; + + if( modrm >= 0xc0 ) { + report_invalid_modrm("load_far_pointer32", modrm); + } else { + UINT32 ea = GetEA(modrm,0); + STORE_REG32(modrm, READ32(ea + 0)); + selector = READ16(ea + 4); + i386_sreg_load(selector,s,NULL); + } +} + +void i386_device::i386_lds32() // Opcode 0xc5 +{ + i386_load_far_pointer32(DS); + CYCLES(CYCLES_LDS); +} + +void i386_device::i386_lss32() // Opcode 0x0f 0xb2 +{ + i386_load_far_pointer32(SS); + CYCLES(CYCLES_LSS); +} + +void i386_device::i386_les32() // Opcode 0xc4 +{ + i386_load_far_pointer32(ES); + CYCLES(CYCLES_LES); +} + +void i386_device::i386_lfs32() // Opcode 0x0f 0xb4 +{ + i386_load_far_pointer32(FS); + CYCLES(CYCLES_LFS); +} + +void i386_device::i386_lgs32() // Opcode 0x0f 0xb5 +{ + i386_load_far_pointer32(GS); + CYCLES(CYCLES_LGS); +} |