diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index c0e7d569..2a274126 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -1066,10 +1066,10 @@ void EmitX64::EmitTerminal(IR::Terminal terminal, Arm::LocationDescriptor initia } void EmitX64::EmitTerminalInterpret(IR::Term::Interpret terminal, Arm::LocationDescriptor initial_location) { - ASSERT_MSG(terminal.next.TFlag == initial_location.TFlag, "Unimplemented"); - ASSERT_MSG(terminal.next.EFlag == initial_location.EFlag, "Unimplemented"); + ASSERT_MSG(terminal.next.TFlag() == initial_location.TFlag(), "Unimplemented"); + ASSERT_MSG(terminal.next.EFlag() == initial_location.EFlag(), "Unimplemented"); - code->MOV(64, R(ABI_PARAM1), Imm64(terminal.next.arm_pc)); + code->MOV(64, R(ABI_PARAM1), Imm64(terminal.next.PC())); code->MOV(64, R(ABI_PARAM2), Imm64(reinterpret_cast(jit_interface))); code->MOV(32, MJitStateReg(Arm::Reg::PC), R(ABI_PARAM1)); code->MOV(64, R(RSP), MDisp(R15, offsetof(JitState, save_host_RSP))); @@ -1082,16 +1082,16 @@ void EmitX64::EmitTerminalReturnToDispatch(IR::Term::ReturnToDispatch, Arm::Loca } void EmitX64::EmitTerminalLinkBlock(IR::Term::LinkBlock terminal, Arm::LocationDescriptor initial_location) { - code->MOV(32, MJitStateReg(Arm::Reg::PC), Imm32(terminal.next.arm_pc)); - if (terminal.next.TFlag != initial_location.TFlag) { - if (terminal.next.TFlag) { + code->MOV(32, MJitStateReg(Arm::Reg::PC), Imm32(terminal.next.PC())); + if (terminal.next.TFlag() != initial_location.TFlag()) { + if (terminal.next.TFlag()) { code->OR(32, MJitStateCpsr(), Imm32(1 << 5)); } else { code->AND(32, MJitStateCpsr(), Imm32(~(1 << 5))); } } - if (terminal.next.EFlag != initial_location.EFlag) { - if (terminal.next.EFlag) { + if (terminal.next.EFlag() != initial_location.EFlag()) { + if (terminal.next.EFlag()) { code->OR(32, MJitStateCpsr(), Imm32(1 << 9)); } else { code->AND(32, MJitStateCpsr(), Imm32(~(1 << 9))); diff --git a/src/backend_x64/interface_x64.cpp b/src/backend_x64/interface_x64.cpp index e2616b88..18679cb4 100644 --- a/src/backend_x64/interface_x64.cpp +++ b/src/backend_x64/interface_x64.cpp @@ -42,7 +42,7 @@ struct Jit::Impl { bool TFlag = Common::Bit<5>(jit_state.Cpsr); bool EFlag = Common::Bit<9>(jit_state.Cpsr); - Arm::LocationDescriptor descriptor{pc, TFlag, EFlag}; + Arm::LocationDescriptor descriptor{pc, TFlag, EFlag, jit_state.Fpscr}; CodePtr code_ptr = GetBasicBlock(descriptor); return routines.RunCode(&jit_state, code_ptr, cycle_count); diff --git a/src/backend_x64/jitstate.h b/src/backend_x64/jitstate.h index adb22e15..4f7cc893 100644 --- a/src/backend_x64/jitstate.h +++ b/src/backend_x64/jitstate.h @@ -19,6 +19,8 @@ struct JitState { std::array Reg{}; // Current register file. // TODO: Mode-specific register sets unimplemented. + u32 Fpscr = 0; + std::array Spill{}; // Spill. // For internal use (See: Routines::RunCode) diff --git a/src/frontend/arm_types.h b/src/frontend/arm_types.h index da0e9330..b1ed29df 100644 --- a/src/frontend/arm_types.h +++ b/src/frontend/arm_types.h @@ -76,23 +76,53 @@ enum class SignExtendRotation { }; struct LocationDescriptor { - LocationDescriptor(u32 arm_pc, bool TFlag, bool EFlag) - : arm_pc(arm_pc), TFlag(TFlag), EFlag(EFlag) {} + static constexpr u32 FPSCR_MASK = 0x3F79F9F; - u32 arm_pc; - bool TFlag; ///< Thumb / ARM - bool EFlag; ///< Big / Little Endian + LocationDescriptor(u32 arm_pc, bool tflag, bool eflag, u32 fpscr) + : arm_pc(arm_pc), tflag(tflag), eflag(eflag), fpscr(fpscr & FPSCR_MASK) {} + + u32 PC() const { return arm_pc; } + bool TFlag() const { return tflag; } + bool EFlag() const { return eflag; } + u32 FPSCR() const { return fpscr; } bool operator == (const LocationDescriptor& o) const { - return std::tie(arm_pc, TFlag, EFlag) == std::tie(o.arm_pc, o.TFlag, o.EFlag); + return std::tie(arm_pc, tflag, eflag, fpscr) == std::tie(o.arm_pc, o.tflag, o.eflag, o.fpscr); } + + LocationDescriptor SetPC(u32 new_arm_pc) const { + return LocationDescriptor(new_arm_pc, tflag, eflag, fpscr); + } + + LocationDescriptor AdvancePC(s32 amount) const { + return LocationDescriptor(arm_pc + amount, tflag, eflag, fpscr); + } + + LocationDescriptor SetTFlag(bool new_tflag) const { + return LocationDescriptor(arm_pc, new_tflag, eflag, fpscr); + } + + LocationDescriptor SetEFlag(bool new_eflag) const { + return LocationDescriptor(arm_pc, tflag, new_eflag, fpscr); + } + + LocationDescriptor SetFPSCR(u32 new_fpscr) const { + return LocationDescriptor(arm_pc, tflag, eflag, new_fpscr & FPSCR_MASK); + } + +private: + u32 arm_pc; + bool tflag; ///< Thumb / ARM + bool eflag; ///< Big / Little Endian + u32 fpscr; ///< Floating point status control register }; struct LocationDescriptorHash { size_t operator()(const LocationDescriptor& x) const { - return std::hash()(static_cast(x.arm_pc) - ^ (static_cast(x.TFlag) << 32) - ^ (static_cast(x.EFlag) << 33)); + return std::hash()(static_cast(x.PC()) + ^ static_cast(x.TFlag()) + ^ (static_cast(x.EFlag()) << 1) + ^ (static_cast(x.FPSCR()) << 32)); } }; diff --git a/src/frontend/ir/ir.cpp b/src/frontend/ir/ir.cpp index fef77010..d14a45d4 100644 --- a/src/frontend/ir/ir.cpp +++ b/src/frontend/ir/ir.cpp @@ -133,10 +133,11 @@ std::string DumpBlock(const IR::Block& block) { std::string ret; const auto loc_to_string = [](Arm::LocationDescriptor loc) -> std::string { - return Common::StringFromFormat("{%u,%s,%s}", - loc.arm_pc, - loc.TFlag ? "T" : "!T", - loc.EFlag ? "E" : "!E"); + return Common::StringFromFormat("{%u,%s,%s,%u}", + loc.PC(), + loc.TFlag() ? "T" : "!T", + loc.EFlag() ? "E" : "!E", + loc.FPSCR()); }; ret += Common::StringFromFormat("Block: location=%s\n", loc_to_string(block.location).c_str()); diff --git a/src/frontend/ir/ir_emitter.cpp b/src/frontend/ir/ir_emitter.cpp index 1b57fd89..869b5335 100644 --- a/src/frontend/ir/ir_emitter.cpp +++ b/src/frontend/ir/ir_emitter.cpp @@ -15,8 +15,8 @@ void IREmitter::Unimplemented() { } u32 IREmitter::PC() { - u32 offset = current_location.TFlag ? 4 : 8; - return current_location.arm_pc + offset; + u32 offset = current_location.TFlag() ? 4 : 8; + return current_location.PC() + offset; } u32 IREmitter::AlignPC(size_t alignment) { @@ -55,7 +55,7 @@ void IREmitter::ALUWritePC(const IR::Value& value) { } void IREmitter::BranchWritePC(const IR::Value& value) { - if (!current_location.TFlag) { + if (!current_location.TFlag()) { auto new_pc = And(value, Imm32(0xFFFFFFFC)); Inst(IR::Opcode::SetRegister, { IR::Value(Reg::PC), new_pc }); } else { @@ -211,17 +211,17 @@ IR::Value IREmitter::ReadMemory8(const IR::Value& vaddr) { IR::Value IREmitter::ReadMemory16(const IR::Value& vaddr) { auto value = Inst(IR::Opcode::ReadMemory16, {vaddr}); - return current_location.EFlag ? ByteReverseHalf(value) : value; + return current_location.EFlag() ? ByteReverseHalf(value) : value; } IR::Value IREmitter::ReadMemory32(const IR::Value& vaddr) { auto value = Inst(IR::Opcode::ReadMemory32, {vaddr}); - return current_location.EFlag ? ByteReverseWord(value) : value; + return current_location.EFlag() ? ByteReverseWord(value) : value; } IR::Value IREmitter::ReadMemory64(const IR::Value& vaddr) { auto value = Inst(IR::Opcode::ReadMemory64, {vaddr}); - return current_location.EFlag ? ByteReverseDual(value) : value; + return current_location.EFlag() ? ByteReverseDual(value) : value; } void IREmitter::WriteMemory8(const IR::Value& vaddr, const IR::Value& value) { @@ -229,7 +229,7 @@ void IREmitter::WriteMemory8(const IR::Value& vaddr, const IR::Value& value) { } void IREmitter::WriteMemory16(const IR::Value& vaddr, const IR::Value& value) { - if (current_location.EFlag) { + if (current_location.EFlag()) { auto v = ByteReverseHalf(value); Inst(IR::Opcode::WriteMemory16, {vaddr, v}); } else { @@ -238,7 +238,7 @@ void IREmitter::WriteMemory16(const IR::Value& vaddr, const IR::Value& value) { } void IREmitter::WriteMemory32(const IR::Value& vaddr, const IR::Value& value) { - if (current_location.EFlag) { + if (current_location.EFlag()) { auto v = ByteReverseWord(value); Inst(IR::Opcode::WriteMemory32, {vaddr, v}); } else { @@ -247,7 +247,7 @@ void IREmitter::WriteMemory32(const IR::Value& vaddr, const IR::Value& value) { } void IREmitter::WriteMemory64(const IR::Value& vaddr, const IR::Value& value) { - if (current_location.EFlag) { + if (current_location.EFlag()) { auto v = ByteReverseDual(value); Inst(IR::Opcode::WriteMemory64, {vaddr, v}); } else { diff --git a/src/frontend/translate/translate.cpp b/src/frontend/translate/translate.cpp index 59ee2083..2dc33755 100644 --- a/src/frontend/translate/translate.cpp +++ b/src/frontend/translate/translate.cpp @@ -15,7 +15,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memor IR::Block TranslateThumb(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32); IR::Block Translate(LocationDescriptor descriptor, MemoryRead32FuncType memory_read_32) { - return (descriptor.TFlag ? TranslateThumb : TranslateArm)(descriptor, memory_read_32); + return (descriptor.TFlag() ? TranslateThumb : TranslateArm)(descriptor, memory_read_32); } } // namespace Arm diff --git a/src/frontend/translate/translate_arm.cpp b/src/frontend/translate/translate_arm.cpp index 3d158ac2..fc56cad3 100644 --- a/src/frontend/translate/translate_arm.cpp +++ b/src/frontend/translate/translate_arm.cpp @@ -27,7 +27,7 @@ enum class ConditionalState { struct ArmTranslatorVisitor final { explicit ArmTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) { - ASSERT_MSG(!descriptor.TFlag, "The processor must be in Arm mode"); + ASSERT_MSG(!descriptor.TFlag(), "The processor must be in Arm mode"); } IREmitter ir; @@ -44,8 +44,7 @@ struct ArmTranslatorVisitor final { } bool LinkToNextInstruction() { - auto next_location = ir.current_location; - next_location.arm_pc += 4; + auto next_location = ir.current_location.AdvancePC(4); ir.SetTerm(IR::Term::LinkBlock{next_location}); return false; } @@ -315,7 +314,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memor bool should_continue = true; while (should_continue && visitor.cond_state == ConditionalState::None) { - const u32 arm_pc = visitor.ir.current_location.arm_pc; + const u32 arm_pc = visitor.ir.current_location.PC(); const u32 arm_instruction = (*memory_read_32)(arm_pc); const auto decoder = DecodeArm(arm_instruction); @@ -329,7 +328,7 @@ IR::Block TranslateArm(LocationDescriptor descriptor, MemoryRead32FuncType memor break; } - visitor.ir.current_location.arm_pc += 4; + visitor.ir.current_location = visitor.ir.current_location.AdvancePC(4); visitor.ir.block.cycle_count++; } diff --git a/src/frontend/translate/translate_thumb.cpp b/src/frontend/translate/translate_thumb.cpp index babe816d..3a1178ab 100644 --- a/src/frontend/translate/translate_thumb.cpp +++ b/src/frontend/translate/translate_thumb.cpp @@ -21,7 +21,7 @@ namespace { struct ThumbTranslatorVisitor final { explicit ThumbTranslatorVisitor(LocationDescriptor descriptor) : ir(descriptor) { - ASSERT_MSG(descriptor.TFlag, "The processor must be in Thumb mode"); + ASSERT_MSG(descriptor.TFlag(), "The processor must be in Thumb mode"); } IREmitter ir; @@ -678,13 +678,10 @@ struct ThumbTranslatorVisitor final { bool thumb16_SETEND(bool E) { // SETEND - if (E == ir.current_location.EFlag) { + if (E == ir.current_location.EFlag()) { return true; } - auto next_location = ir.current_location; - next_location.arm_pc += 2; - next_location.EFlag = E; - ir.SetTerm(IR::Term::LinkBlock{next_location}); + ir.SetTerm(IR::Term::LinkBlock{ir.current_location.AdvancePC(2).SetEFlag(E)}); return false; } @@ -762,7 +759,7 @@ struct ThumbTranslatorVisitor final { bool thumb16_BLX_reg(Reg m) { // BLX - ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.arm_pc + 2) | 1)); + ir.SetRegister(Reg::LR, ir.Imm32((ir.current_location.PC() + 2) | 1)); ir.BXWritePC(ir.GetRegister(m)); // TODO(optimization): Possible push RSB location ir.SetTerm(IR::Term::ReturnToDispatch{}); @@ -783,10 +780,8 @@ struct ThumbTranslatorVisitor final { return thumb16_UDF(); } // B