diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index 8044986492..c074fdd96a 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -638,20 +638,26 @@ void Jit64::mcrfs(UGeckoInstruction inst) // Only clear exception bits (but not FEX/VX). mask &= FPSCR_FX | FPSCR_ANY_X; - MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); if (cpu_info.bBMI1) { + MOV(32, R(RSCRATCH), PPCSTATE(fpscr)); MOV(32, R(RSCRATCH2), Imm32((4 << 8) | shift)); BEXTR(32, RSCRATCH2, R(RSCRATCH), RSCRATCH2); } else { - MOV(32, R(RSCRATCH2), R(RSCRATCH)); + MOV(32, R(RSCRATCH2), PPCSTATE(fpscr)); + if (mask != 0) + MOV(32, R(RSCRATCH), R(RSCRATCH2)); + SHR(32, R(RSCRATCH2), Imm8(shift)); AND(32, R(RSCRATCH2), Imm32(0xF)); } - AND(32, R(RSCRATCH), Imm32(~mask)); - MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + if (mask != 0) + { + AND(32, R(RSCRATCH), Imm32(~mask)); + MOV(32, PPCSTATE(fpscr), R(RSCRATCH)); + } LEA(64, RSCRATCH, MConst(PowerPC::ConditionRegister::s_crTable)); MOV(64, R(RSCRATCH), MComplex(RSCRATCH, RSCRATCH2, SCALE_8, 0)); MOV(64, CROffset(inst.CRFD), R(RSCRATCH)); diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.h b/Source/Core/Core/PowerPC/JitArm64/Jit.h index c16521b240..c9f6d60919 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.h +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.h @@ -118,6 +118,7 @@ public: void crXXX(UGeckoInstruction inst); void mfcr(UGeckoInstruction inst); void mtcrf(UGeckoInstruction inst); + void mcrfs(UGeckoInstruction inst); // LoadStore void lXX(UGeckoInstruction inst); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 33cf6d51b7..668e7fce26 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -687,3 +687,37 @@ void JitArm64::mtcrf(UGeckoInstruction inst) gpr.Unlock(WB); } } + +void JitArm64::mcrfs(UGeckoInstruction inst) +{ + INSTRUCTION_START + JITDISABLE(bJITSystemRegistersOff); + + u8 shift = 4 * (7 - inst.CRFS); + u32 mask = 0xF << shift; + u32 field = inst.CRFD; + + // Only clear exception bits (but not FEX/VX). + mask &= FPSCR_FX | FPSCR_ANY_X; + + gpr.BindCRToRegister(field, false); + ARM64Reg CR = gpr.CR(field); + ARM64Reg WA = gpr.GetReg(); + ARM64Reg WCR = EncodeRegTo32(CR); + ARM64Reg XA = EncodeRegTo64(WA); + + LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr)); + LSR(WCR, WA, shift); + ANDI2R(WCR, WCR, 0xF); + + if (mask != 0) + { + ANDI2R(WA, WA, ~mask); + STR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(fpscr)); + } + + MOVP2R(XA, PowerPC::ConditionRegister::s_crTable.data()); + LDR(CR, XA, ArithOption(CR, true)); + + gpr.Unlock(WA); +} diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp index 471a4566c8..a3b5cce8c9 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Tables.cpp @@ -315,7 +315,7 @@ constexpr std::array table63{{ {40, &JitArm64::fp_logic}, // fnegx {12, &JitArm64::frspx}, // frspx - {64, &JitArm64::FallBackToInterpreter}, // mcrfs + {64, &JitArm64::mcrfs}, // mcrfs {583, &JitArm64::FallBackToInterpreter}, // mffsx {70, &JitArm64::FallBackToInterpreter}, // mtfsb0x {38, &JitArm64::FallBackToInterpreter}, // mtfsb1x