diff options
author | Merry <[email protected]> | 2024-02-13 02:19:38 +0000 |
---|---|---|
committer | Merry <[email protected]> | 2024-02-13 02:19:55 +0000 |
commit | 4ae4750b5a960871c10325e0864fd8646d53f2ef (patch) | |
tree | 2a2d24b2a08cf116b7364d307318a9ec3b0ecc99 | |
parent | ba8192d89078af51ae6f97c9352e3683612cdff1 (diff) | |
download | dynarmic-4ae4750b5a960871c10325e0864fd8646d53f2ef.tar.gz dynarmic-4ae4750b5a960871c10325e0864fd8646d53f2ef.zip |
emit_arm64_a64: Take into account currently loaded FPSR
Previously we just retrieved the last stored FPSR and used that when the guest asks for the current FPSR.
This is incorrect behaviour. We failed to take into account the current state of the host FPSR.
Here we take this into account. This bug was discovered via #795.
-rw-r--r-- | src/dynarmic/backend/arm64/emit_arm64_a64.cpp | 5 | ||||
-rw-r--r-- | src/dynarmic/backend/arm64/fpsr_manager.cpp | 9 | ||||
-rw-r--r-- | src/dynarmic/backend/arm64/fpsr_manager.h | 3 |
3 files changed, 15 insertions, 2 deletions
diff --git a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp index 67fd91f2..5152a54b 100644 --- a/src/dynarmic/backend/arm64/emit_arm64_a64.cpp +++ b/src/dynarmic/backend/arm64/emit_arm64_a64.cpp @@ -10,6 +10,7 @@ #include "dynarmic/backend/arm64/abi.h" #include "dynarmic/backend/arm64/emit_arm64.h" #include "dynarmic/backend/arm64/emit_context.h" +#include "dynarmic/backend/arm64/fpsr_manager.h" #include "dynarmic/backend/arm64/reg_alloc.h" #include "dynarmic/interface/halt_reason.h" #include "dynarmic/ir/basic_block.h" @@ -277,11 +278,11 @@ void EmitIR<IR::Opcode::A64GetFPCR>(oaknut::CodeGenerator& code, EmitContext& ct } template<> -void EmitIR<IR::Opcode::A64GetFPSR>(oaknut::CodeGenerator& code, EmitContext& ctx, IR::Inst* inst) { +void EmitIR<IR::Opcode::A64GetFPSR>(oaknut::CodeGenerator&, EmitContext& ctx, IR::Inst* inst) { auto Wresult = ctx.reg_alloc.WriteW(inst); RegAlloc::Realize(Wresult); - code.LDR(Wresult, Xstate, offsetof(A64JitState, fpsr)); + ctx.fpsr.GetFpsr(Wresult); } template<> diff --git a/src/dynarmic/backend/arm64/fpsr_manager.cpp b/src/dynarmic/backend/arm64/fpsr_manager.cpp index 1a1c323e..1c614745 100644 --- a/src/dynarmic/backend/arm64/fpsr_manager.cpp +++ b/src/dynarmic/backend/arm64/fpsr_manager.cpp @@ -37,4 +37,13 @@ void FpsrManager::Load() { fpsr_loaded = true; } +void FpsrManager::GetFpsr(oaknut::WReg dest) { + code.LDR(dest, Xstate, state_fpsr_offset); + + if (fpsr_loaded) { + code.MRS(Xscratch1, oaknut::SystemReg::FPSR); + code.ORR(dest, dest, Wscratch1); + } +} + } // namespace Dynarmic::Backend::Arm64 diff --git a/src/dynarmic/backend/arm64/fpsr_manager.h b/src/dynarmic/backend/arm64/fpsr_manager.h index e003522d..9e5d68bf 100644 --- a/src/dynarmic/backend/arm64/fpsr_manager.h +++ b/src/dynarmic/backend/arm64/fpsr_manager.h @@ -9,6 +9,7 @@ namespace oaknut { struct CodeGenerator; +struct WReg; } // namespace oaknut namespace Dynarmic::Backend::Arm64 { @@ -21,6 +22,8 @@ public: void Load(); void Overwrite() { fpsr_loaded = false; } + void GetFpsr(oaknut::WReg); + private: oaknut::CodeGenerator& code; size_t state_fpsr_offset; |