From 46dc406325726e32eb5f0d578b07baab30b3c4e0 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Fri, 24 May 2024 21:21:46 +0200 Subject: [PATCH 1/2] Interpreter: Fix GT when setting SO of CR This is the same fixup as in Jit64::FixGTBeforeSettingCRFieldBit. --- .../Core/PowerPC/Interpreter/Interpreter_Integer.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp index 3cf0be2178..d5bd50720b 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp @@ -16,6 +16,15 @@ void Interpreter::Helper_UpdateCR0(PowerPC::PowerPCState& ppc_state, u32 value) { const s64 sign_extended = s64{s32(value)}; u64 cr_val = u64(sign_extended); + + if (value == 0) + { + // GT is considered unset if cr_val is zero or if bit 63 of cr_val is set. + // If we're about to turn cr_val from zero to non-zero by setting the SO bit, + // we need to set bit 63 so we don't accidentally change GT. + cr_val |= 1ULL << 63; + } + cr_val = (cr_val & ~(1ULL << PowerPC::CR_EMU_SO_BIT)) | (u64{ppc_state.GetXER_SO()} << PowerPC::CR_EMU_SO_BIT); From 921d711113ec6a4150dac15f77ac5e319d734194 Mon Sep 17 00:00:00 2001 From: JosJuice Date: Sun, 26 May 2024 08:32:25 +0200 Subject: [PATCH 2/2] Jit: Clarify FixGTBeforeSettingCRFieldBit comment --- Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp | 7 ++++--- .../Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index 31794b9ba9..6331358359 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -152,9 +152,10 @@ void Jit64::SetCRFieldBit(int field, int bit) void Jit64::FixGTBeforeSettingCRFieldBit(Gen::X64Reg reg) { - // Gross but necessary; if the input is totally zero and we set SO or LT, - // or even just add the (1<<32), GT will suddenly end up set without us - // intending to. This can break actual games, so fix it up. + // GT is considered unset if the internal representation is <= 0, or in other words, + // if the internal representation either has bit 63 set or has all bits set to zero. + // If all bits are zero and we set some bit that's unrelated to GT, we need to set bit 63 so GT + // doesn't accidentally become considered set. Gross but necessary; this can break actual games. TEST(64, R(reg), R(reg)); FixupBranch dont_clear_gt = J_CC(CC_NZ); BTS(64, R(reg), Imm8(63)); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index 58bb7c6c24..87f652d6d4 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -44,9 +44,10 @@ FixupBranch JitArm64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set) void JitArm64::FixGTBeforeSettingCRFieldBit(Arm64Gen::ARM64Reg reg) { - // Gross but necessary; if the input is totally zero and we set SO or LT, - // or even just add the (1<<32), GT will suddenly end up set without us - // intending to. This can break actual games, so fix it up. + // GT is considered unset if the internal representation is <= 0, or in other words, + // if the internal representation either has bit 63 set or has all bits set to zero. + // If all bits are zero and we set some bit that's unrelated to GT, we need to set bit 63 so GT + // doesn't accidentally become considered set. Gross but necessary; this can break actual games. ARM64Reg WA = gpr.GetReg(); ARM64Reg XA = EncodeRegTo64(WA); ORR(XA, reg, LogicalImm(1ULL << 63, GPRSize::B64));