diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp index 20d065a03f..6558d7fd65 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -853,33 +853,139 @@ void SoftCPU::AAM(const X86::Instruction&) { TODO(); } void SoftCPU::AAS(const X86::Instruction&) { TODO(); } void SoftCPU::ARPL(const X86::Instruction&) { TODO(); } void SoftCPU::BOUND(const X86::Instruction&) { TODO(); } -void SoftCPU::BSF_reg16_RM16(const X86::Instruction&) { TODO(); } -void SoftCPU::BSF_reg32_RM32(const X86::Instruction&) { TODO(); } -void SoftCPU::BSR_reg16_RM16(const X86::Instruction&) { TODO(); } -void SoftCPU::BSR_reg32_RM32(const X86::Instruction&) { TODO(); } +void SoftCPU::BSF_reg16_RM16(const X86::Instruction&) { } +void SoftCPU::BSF_reg32_RM32(const X86::Instruction&) { } +void SoftCPU::BSR_reg16_RM16(const X86::Instruction&) { } +void SoftCPU::BSR_reg32_RM32(const X86::Instruction&) { } void SoftCPU::BSWAP_reg32(const X86::Instruction& insn) { gpr32(insn.reg32()) = __builtin_bswap32(gpr32(insn.reg32())); } -void SoftCPU::BTC_RM16_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BTC_RM16_reg16(const X86::Instruction&) { TODO(); } -void SoftCPU::BTC_RM32_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BTC_RM32_reg32(const X86::Instruction&) { TODO(); } -void SoftCPU::BTR_RM16_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BTR_RM16_reg16(const X86::Instruction&) { TODO(); } -void SoftCPU::BTR_RM32_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BTR_RM32_reg32(const X86::Instruction&) { TODO(); } -void SoftCPU::BTS_RM16_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BTS_RM16_reg16(const X86::Instruction&) { TODO(); } -void SoftCPU::BTS_RM32_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BTS_RM32_reg32(const X86::Instruction&) { TODO(); } -void SoftCPU::BT_RM16_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BT_RM16_reg16(const X86::Instruction&) { TODO(); } -void SoftCPU::BT_RM32_imm8(const X86::Instruction&) { TODO(); } -void SoftCPU::BT_RM32_reg32(const X86::Instruction&) { TODO(); } -void SoftCPU::CALL_FAR_mem16(const X86::Instruction&) { TODO(); } +template +ALWAYS_INLINE static T op_bt(T value, T) +{ + return value; +} + +template +ALWAYS_INLINE static T op_bts(T value, T bit_mask) +{ + return value | bit_mask; +} + +template +ALWAYS_INLINE static T op_btr(T value, T bit_mask) +{ + return value & ~bit_mask; +} + +template +ALWAYS_INLINE static T op_btc(T value, T bit_mask) +{ + return value ^ bit_mask; +} + +template +ALWAYS_INLINE void BTx_RM16_reg16(SoftCPU& cpu, const X86::Instruction& insn, Op op) +{ + if (insn.modrm().is_register()) { + unsigned bit_index = cpu.gpr16(insn.reg16()) & (X86::TypeTrivia::bits - 1); + u16 original = insn.modrm().read16(cpu, insn); + u16 bit_mask = 1 << bit_index; + u16 result = op(original, bit_mask); + cpu.set_cf((original & bit_mask) != 0); + if (should_update) + insn.modrm().write16(cpu, insn, result); + return; + } + // FIXME: Is this supposed to perform a full 16-bit read/modify/write? + unsigned bit_offset_in_array = cpu.gpr16(insn.reg16()) / 8; + unsigned bit_offset_in_byte = cpu.gpr16(insn.reg16()) & 7; + auto address = insn.modrm().resolve(cpu, insn); + address.set_offset(address.offset() + bit_offset_in_array); + u8 dest = cpu.read_memory8(address); + u8 bit_mask = 1 << bit_offset_in_byte; + u8 result = op(dest, bit_mask); + cpu.set_cf((dest & bit_mask) != 0); + if (should_update) + cpu.write_memory8(address, result); +} + +template +ALWAYS_INLINE void BTx_RM32_reg32(SoftCPU& cpu, const X86::Instruction& insn, Op op) +{ + if (insn.modrm().is_register()) { + unsigned bit_index = cpu.gpr32(insn.reg32()) & (X86::TypeTrivia::bits - 1); + u32 original = insn.modrm().read32(cpu, insn); + u32 bit_mask = 1 << bit_index; + u32 result = op(original, bit_mask); + cpu.set_cf((original & bit_mask) != 0); + if (should_update) + insn.modrm().write32(cpu, insn, result); + return; + } + // FIXME: Is this supposed to perform a full 32-bit read/modify/write? + unsigned bit_offset_in_array = cpu.gpr32(insn.reg32()) / 8; + unsigned bit_offset_in_byte = cpu.gpr32(insn.reg32()) & 7; + auto address = insn.modrm().resolve(cpu, insn); + address.set_offset(address.offset() + bit_offset_in_array); + u8 dest = cpu.read_memory8(address); + u8 bit_mask = 1 << bit_offset_in_byte; + u8 result = op(dest, bit_mask); + cpu.set_cf((dest & bit_mask) != 0); + if (should_update) + cpu.write_memory8(address, result); +} + +template +ALWAYS_INLINE void BTx_RM16_imm8(SoftCPU& cpu, const X86::Instruction& insn, Op op) +{ + unsigned bit_index = insn.imm8() & (X86::TypeTrivia::mask); + + // FIXME: Support higher bit indices + ASSERT(bit_index < 16); + + u16 original = insn.modrm().read16(cpu, insn); + u16 bit_mask = 1 << bit_index; + u16 result = op(original, bit_mask); + cpu.set_cf((original & bit_mask) != 0); + if (should_update) + insn.modrm().write16(cpu, insn, result); +} + +template +ALWAYS_INLINE void BTx_RM32_imm8(SoftCPU& cpu, const X86::Instruction& insn, Op op) +{ + unsigned bit_index = insn.imm8() & (X86::TypeTrivia::mask); + + // FIXME: Support higher bit indices + ASSERT(bit_index < 32); + + u32 original = insn.modrm().read32(cpu, insn); + u32 bit_mask = 1 << bit_index; + u32 result = op(original, bit_mask); + cpu.set_cf((original & bit_mask) != 0); + if (should_update) + insn.modrm().write32(cpu, insn, result); +} + +#define DEFINE_GENERIC_BTx_INSN_HANDLERS(mnemonic, op, update_dest) \ + void SoftCPU::mnemonic##_RM32_reg32(const X86::Instruction& insn) { BTx_RM32_reg32(*this, insn, op); } \ + void SoftCPU::mnemonic##_RM16_reg16(const X86::Instruction& insn) { BTx_RM16_reg16(*this, insn, op); } \ + void SoftCPU::mnemonic##_RM32_imm8(const X86::Instruction& insn) { BTx_RM32_imm8(*this, insn, op); } \ + void SoftCPU::mnemonic##_RM16_imm8(const X86::Instruction& insn) { BTx_RM16_imm8(*this, insn, op); } + +DEFINE_GENERIC_BTx_INSN_HANDLERS(BTS, op_bts, true); +DEFINE_GENERIC_BTx_INSN_HANDLERS(BTR, op_btr, true); +DEFINE_GENERIC_BTx_INSN_HANDLERS(BTC, op_btc, true); +DEFINE_GENERIC_BTx_INSN_HANDLERS(BT, op_bt, false); + +void SoftCPU::CALL_FAR_mem16(const X86::Instruction&) +{ + TODO(); +} void SoftCPU::CALL_FAR_mem32(const X86::Instruction&) { TODO(); } void SoftCPU::CALL_RM16(const X86::Instruction&) { TODO(); }