diff --git a/include/dynarmic/dynarmic.h b/include/dynarmic/dynarmic.h index bfe2ecf7..d5b82886 100644 --- a/include/dynarmic/dynarmic.h +++ b/include/dynarmic/dynarmic.h @@ -63,12 +63,12 @@ public: const std::array& ExtRegs() const; /// View and modify CPSR. - std::uint32_t& Cpsr(); std::uint32_t Cpsr() const; + void SetCpsr(std::uint32_t value); /// View and modify FPSCR. std::uint32_t Fpscr() const; - void SetFpscr(std::uint32_t value) const; + void SetFpscr(std::uint32_t value); /** * Returns true if Jit::Run was called but hasn't returned yet. diff --git a/src/backend_x64/emit_x64.cpp b/src/backend_x64/emit_x64.cpp index 6d63ee76..11d9b1a6 100644 --- a/src/backend_x64/emit_x64.cpp +++ b/src/backend_x64/emit_x64.cpp @@ -62,7 +62,7 @@ static Xbyak::Address MJitStateExtReg(Arm::ExtReg reg) { static Xbyak::Address MJitStateCpsr() { using namespace Xbyak::util; - return dword[r15 + offsetof(JitState, Cpsr)]; + return dword[r15 + offsetof(JitState, CPSR)]; } static void EraseInstruction(IR::Block& block, IR::Inst* inst) { @@ -196,16 +196,25 @@ void EmitX64::EmitSetExtendedRegister64(RegAlloc& reg_alloc, IR::Block&, IR::Ins code->movsd(MJitStateExtReg(reg), source); } +static u32 GetCpsrImpl(JitState* jit_state) { + return jit_state->Cpsr(); +} + void EmitX64::EmitGetCpsr(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) { - Xbyak::Reg32 result = reg_alloc.ScratchGpr().cvt32(); - code->mov(result, MJitStateCpsr()); - reg_alloc.DefineValue(inst, result); + reg_alloc.HostCall(inst); + code->mov(code->ABI_PARAM1, code->r15); + code->CallFunction(&GetCpsrImpl); +} + +static void SetCpsrImpl(u32 value, JitState* jit_state) { + jit_state->SetCpsr(value); } void EmitX64::EmitSetCpsr(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) { auto args = reg_alloc.GetArgumentInfo(inst); - Xbyak::Reg32 arg = reg_alloc.UseGpr(args[0]).cvt32(); - code->mov(MJitStateCpsr(), arg); + reg_alloc.HostCall(nullptr, args[0]); + code->mov(code->ABI_PARAM2, code->r15); + code->CallFunction(&SetCpsrImpl); } void EmitX64::EmitGetNFlag(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) { @@ -404,9 +413,9 @@ void EmitX64::EmitBXWritePC(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) { } else { using Xbyak::util::ptr; - Xbyak::Reg64 new_pc = reg_alloc.UseScratchGpr(arg); - Xbyak::Reg64 tmp1 = reg_alloc.ScratchGpr(); - Xbyak::Reg64 tmp2 = reg_alloc.ScratchGpr(); + Xbyak::Reg32 new_pc = reg_alloc.UseScratchGpr(arg).cvt32(); + Xbyak::Reg32 tmp1 = reg_alloc.ScratchGpr().cvt32(); + Xbyak::Reg32 tmp2 = reg_alloc.ScratchGpr().cvt32(); code->mov(tmp1, MJitStateCpsr()); code->mov(tmp2, tmp1); @@ -415,7 +424,7 @@ void EmitX64::EmitBXWritePC(RegAlloc& reg_alloc, IR::Block&, IR::Inst* inst) { code->test(new_pc, u32(1)); code->cmove(tmp1, tmp2); // CPSR.T = pc & 1 code->mov(MJitStateCpsr(), tmp1); - code->lea(tmp2, ptr[new_pc + new_pc * 1]); + code->lea(tmp2, ptr[new_pc.cvt64() + new_pc.cvt64() * 1]); code->or_(tmp2, u32(0xFFFFFFFC)); // tmp2 = pc & 1 ? 0xFFFFFFFE : 0xFFFFFFFC code->and_(new_pc, tmp2); code->mov(MJitStateReg(Arm::Reg::PC), new_pc); diff --git a/src/backend_x64/interface_x64.cpp b/src/backend_x64/interface_x64.cpp index 67d8e33e..ad991a36 100644 --- a/src/backend_x64/interface_x64.cpp +++ b/src/backend_x64/interface_x64.cpp @@ -127,7 +127,7 @@ private: JitState& jit_state = this_.jit_state; u32 pc = jit_state.Reg[15]; - Arm::PSR cpsr{jit_state.Cpsr}; + Arm::PSR cpsr{jit_state.Cpsr()}; Arm::FPSCR fpscr{jit_state.FPSCR_mode}; IR::LocationDescriptor descriptor{pc, cpsr, fpscr}; @@ -205,19 +205,19 @@ const std::array& Jit::ExtRegs() const { return impl->jit_state.ExtReg; } -u32& Jit::Cpsr() { - return impl->jit_state.Cpsr; +u32 Jit::Cpsr() const { + return impl->jit_state.Cpsr(); } -u32 Jit::Cpsr() const { - return impl->jit_state.Cpsr; +void Jit::SetCpsr(u32 value) { + return impl->jit_state.SetCpsr(value); } u32 Jit::Fpscr() const { return impl->jit_state.Fpscr(); } -void Jit::SetFpscr(u32 value) const { +void Jit::SetFpscr(u32 value) { return impl->jit_state.SetFpscr(value); } diff --git a/src/backend_x64/jitstate.cpp b/src/backend_x64/jitstate.cpp index 1d01c4a2..379eafb5 100644 --- a/src/backend_x64/jitstate.cpp +++ b/src/backend_x64/jitstate.cpp @@ -14,6 +14,44 @@ namespace Dynarmic { namespace BackendX64 { +/** + * CPSR Bits + * ========= + * + * ARM CPSR flags + * -------------- + * N bit 31 Negative flag + * Z bit 30 Zero flag + * C bit 29 Carry flag + * V bit 28 oVerflow flag + * Q bit 27 Saturation flag + * J bit 24 Jazelle instruction set flag + * GE bits 16-19 Greater than or Equal flags + * E bit 9 Data Endianness flag + * A bit 8 Disable imprecise Aborts + * I bit 7 Disable IRQ interrupts + * F bit 6 Disable FIQ interrupts + * T bit 5 Thumb instruction set flag + * M bits 0-4 Processor Mode bits + * + * x64 LAHF+SETO flags + * ------------------- + * SF bit 15 Sign flag + * ZF bit 14 Zero flag + * AF bit 12 Auxiliary flag + * PF bit 10 Parity flag + * CF bit 8 Carry flag + * OF bit 0 Overflow flag + */ + +u32 JitState::Cpsr() const { + return CPSR; +} + +void JitState::SetCpsr(u32 cpsr) { + CPSR = cpsr; +} + void JitState::ResetRSB() { rsb_location_descriptors.fill(0xFFFFFFFFFFFFFFFFull); rsb_codeptrs.fill(0); diff --git a/src/backend_x64/jitstate.h b/src/backend_x64/jitstate.h index b765d8d1..44ffd356 100644 --- a/src/backend_x64/jitstate.h +++ b/src/backend_x64/jitstate.h @@ -25,10 +25,13 @@ constexpr size_t SpillCount = 64; struct JitState { JitState() { ResetRSB(); } - u32 Cpsr = 0; std::array Reg{}; // Current register file. // TODO: Mode-specific register sets unimplemented. + u32 CPSR = 0; + u32 Cpsr() const; + void SetCpsr(u32 cpsr); + alignas(u64) std::array ExtReg{}; // Extension registers. std::array Spill{}; // Spill. diff --git a/tests/arm/fuzz_arm.cpp b/tests/arm/fuzz_arm.cpp index c8eefece..2458d947 100644 --- a/tests/arm/fuzz_arm.cpp +++ b/tests/arm/fuzz_arm.cpp @@ -115,7 +115,7 @@ static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void*) { jit->Regs() = interp_state.Reg; jit->ExtRegs() = interp_state.ExtReg; - jit->Cpsr() = interp_state.Cpsr; + jit->SetCpsr(interp_state.Cpsr); jit->SetFpscr(interp_state.VFP[VFP_FPSCR]); } @@ -233,7 +233,7 @@ void FuzzJitArm(const size_t instruction_count, const size_t instructions_to_exe interp.ExtReg = initial_extregs; interp.VFP[VFP_FPSCR] = initial_fpscr; jit.Reset(); - jit.Cpsr() = initial_cpsr; + jit.SetCpsr(initial_cpsr); jit.Regs() = initial_regs; jit.ExtRegs() = initial_extregs; jit.SetFpscr(initial_fpscr); @@ -369,7 +369,7 @@ TEST_CASE( "arm: Optimization Failure (Randomized test case)", "[arm]" ) { 0x6973b6bb, 0x267ea626, 0x69debf49, 0x8f976895, 0x4ecd2d0d, 0xcf89b8c7, 0xb6713f85, 0x15e2aa5, 0xcd14336a, 0xafca0f3e, 0xace2efd9, 0x68fb82cd, 0x775447c0, 0xc9e1f8cd, 0xebe0e626, 0x0 }; - jit.Cpsr() = 0x000001d0; // User-mode + jit.SetCpsr(0x000001d0); // User-mode jit.Run(6); @@ -407,7 +407,7 @@ TEST_CASE( "arm: shsax r11, sp, r9 (Edge-case)", "[arm]" ) { 0x3a3b8b18, 0x96156555, 0xffef039f, 0xafb946f2, 0x2030a69a, 0xafe09b2a, 0x896823c8, 0xabde0ded, 0x9825d6a6, 0x17498000, 0x999d2c95, 0x8b812a59, 0x209bdb58, 0x2f7fb1d4, 0x0f378107, 0x00000000 }; - jit.Cpsr() = 0x000001d0; // User-mode + jit.SetCpsr(0x000001d0); // User-mode jit.Run(2); @@ -443,7 +443,7 @@ TEST_CASE( "arm: uasx (Edge-case)", "[arm]" ) { jit.Regs()[4] = 0x8ed38f4c; jit.Regs()[5] = 0x0000261d; jit.Regs()[15] = 0x00000000; - jit.Cpsr() = 0x000001d0; // User-mode + jit.SetCpsr(0x000001d0); // User-mode jit.Run(2); @@ -472,7 +472,7 @@ static void RunVfpTests(u32 instr, std::vector tests) { for (const auto& test : tests) { jit.Regs()[15] = 0; - jit.Cpsr() = 0x000001d0; + jit.SetCpsr(0x000001d0); jit.ExtRegs()[4] = test.a; jit.ExtRegs()[6] = test.b; jit.SetFpscr(test.initial_fpscr); @@ -1106,7 +1106,7 @@ TEST_CASE( "SMUAD", "[JitX64]" ) { 0, 0, 0, 0, 0, 0, 0, 0, }; - jit.Cpsr() = 0x000001d0; // User-mode + jit.SetCpsr(0x000001d0); // User-mode jit.Run(6); @@ -1225,7 +1225,7 @@ TEST_CASE("arm: Test InvalidateCacheRange", "[arm]") { code_mem[3] = 0xeafffffe; // b +#0 (infinite loop) jit.Regs() = {}; - jit.Cpsr() = 0x000001d0; // User-mode + jit.SetCpsr(0x000001d0); // User-mode jit.Run(4); diff --git a/tests/arm/fuzz_thumb.cpp b/tests/arm/fuzz_thumb.cpp index 1fec6b2c..e4305c7b 100644 --- a/tests/arm/fuzz_thumb.cpp +++ b/tests/arm/fuzz_thumb.cpp @@ -107,7 +107,7 @@ static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void*) { interp_state.Reg[15] &= T ? 0xFFFFFFFE : 0xFFFFFFFC; jit->Regs() = interp_state.Reg; - jit->Cpsr() = interp_state.Cpsr; + jit->SetCpsr(interp_state.Cpsr); } static void Fail() { @@ -204,7 +204,7 @@ void FuzzJitThumb(const size_t instruction_count, const size_t instructions_to_e interp.Cpsr = 0x000001F0; interp.Reg = initial_regs; - jit.Cpsr() = 0x000001F0; + jit.SetCpsr(0x000001F0); jit.Regs() = initial_regs; std::generate_n(code_mem.begin(), instruction_count, instruction_generator); diff --git a/tests/arm/test_thumb_instructions.cpp b/tests/arm/test_thumb_instructions.cpp index 64375b42..ec4a94d3 100644 --- a/tests/arm/test_thumb_instructions.cpp +++ b/tests/arm/test_thumb_instructions.cpp @@ -43,7 +43,7 @@ static void InterpreterFallback(u32 pc, Dynarmic::Jit* jit, void*) { InterpreterMainLoop(&interp_state); jit->Regs() = interp_state.Reg; - jit->Cpsr() = interp_state.Cpsr; + jit->SetCpsr(interp_state.Cpsr); } static void AddTicks(u64) {} @@ -66,7 +66,7 @@ TEST_CASE( "thumb: lsls r0, r1, #2", "[thumb]" ) { jit.Regs()[0] = 1; jit.Regs()[1] = 2; jit.Regs()[15] = 0; // PC = 0 - jit.Cpsr() = 0x00000030; // Thumb, User-mode + jit.SetCpsr(0x00000030); // Thumb, User-mode jit.Run(1); @@ -85,7 +85,7 @@ TEST_CASE( "thumb: lsls r0, r1, #31", "[thumb]" ) { jit.Regs()[0] = 1; jit.Regs()[1] = 0xFFFFFFFF; jit.Regs()[15] = 0; // PC = 0 - jit.Cpsr() = 0x00000030; // Thumb, User-mode + jit.SetCpsr(0x00000030); // Thumb, User-mode jit.Run(1); @@ -103,7 +103,7 @@ TEST_CASE( "thumb: revsh r4, r3", "[thumb]" ) { jit.Regs()[3] = 0x12345678; jit.Regs()[15] = 0; // PC = 0 - jit.Cpsr() = 0x00000030; // Thumb, User-mode + jit.SetCpsr(0x00000030); // Thumb, User-mode jit.Run(1); @@ -121,7 +121,7 @@ TEST_CASE( "thumb: ldr r3, [r3, #28]", "[thumb]" ) { jit.Regs()[3] = 0x12345678; jit.Regs()[15] = 0; // PC = 0 - jit.Cpsr() = 0x00000030; // Thumb, User-mode + jit.SetCpsr(0x00000030); // Thumb, User-mode jit.Run(1); @@ -137,7 +137,7 @@ TEST_CASE( "thumb: blx +#67712", "[thumb]" ) { code_mem[2] = 0xE7FE; // b +#0 jit.Regs()[15] = 0; // PC = 0 - jit.Cpsr() = 0x00000030; // Thumb, User-mode + jit.SetCpsr(0x00000030); // Thumb, User-mode jit.Run(1); @@ -153,7 +153,7 @@ TEST_CASE( "thumb: bl +#234584", "[thumb]" ) { code_mem[2] = 0xE7FE; // b +#0 jit.Regs()[15] = 0; // PC = 0 - jit.Cpsr() = 0x00000030; // Thumb, User-mode + jit.SetCpsr(0x00000030); // Thumb, User-mode jit.Run(1); @@ -169,7 +169,7 @@ TEST_CASE( "thumb: bl -#42", "[thumb]" ) { code_mem[2] = 0xE7FE; // b +#0 jit.Regs()[15] = 0; // PC = 0 - jit.Cpsr() = 0x00000030; // Thumb, User-mode + jit.SetCpsr(0x00000030); // Thumb, User-mode jit.Run(1);