Merge pull request #12796 from JosJuice/interpreter-cr0-so-gt

Interpreter: Fix GT when setting SO of CR
This commit is contained in:
Tilka 2024-05-26 17:57:06 +01:00 committed by GitHub
commit 8582644058
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 17 additions and 6 deletions

View file

@ -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);

View file

@ -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));

View file

@ -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));