From e53fffeb908cf3f6feb11597298b36fbfa9fee37 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Wed, 21 Mar 2018 23:51:31 -0400 Subject: [PATCH] PowerPC: Properly unset the overflow bit The OV bit is non-sticky. Therefore, after an overflow-enabled instruction executes, if an overflow does *not* occur, then OV is cleared. SO is sticky however, so it staying set in this case is correct. --- .../Interpreter/Interpreter_Integer.cpp | 38 +++++++++---------- Source/Core/Core/PowerPC/PowerPC.h | 2 +- 2 files changed, 19 insertions(+), 21 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp index 8b7a3c8742..7367e85fdc 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp @@ -492,16 +492,12 @@ void Interpreter::addzex(UGeckoInstruction inst) void Interpreter::divwx(UGeckoInstruction inst) { - s32 a = rGPR[inst.RA]; - s32 b = rGPR[inst.RB]; + const s32 a = rGPR[inst.RA]; + const s32 b = rGPR[inst.RB]; + const bool overflow = b == 0 || ((u32)a == 0x80000000 && b == -1); - if (b == 0 || ((u32)a == 0x80000000 && b == -1)) + if (overflow) { - if (inst.OE) - { - SetXER_OV(true); - } - if (((u32)a & 0x80000000) && b == 0) rGPR[inst.RD] = UINT32_MAX; else @@ -512,22 +508,21 @@ void Interpreter::divwx(UGeckoInstruction inst) rGPR[inst.RD] = (u32)(a / b); } + if (inst.OE) + SetXER_OV(overflow); + if (inst.Rc) Helper_UpdateCR0(rGPR[inst.RD]); } void Interpreter::divwux(UGeckoInstruction inst) { - u32 a = rGPR[inst.RA]; - u32 b = rGPR[inst.RB]; + const u32 a = rGPR[inst.RA]; + const u32 b = rGPR[inst.RB]; + const bool overflow = b == 0; - if (b == 0) + if (overflow) { - if (inst.OE) - { - SetXER_OV(true); - } - rGPR[inst.RD] = 0; } else @@ -535,6 +530,9 @@ void Interpreter::divwux(UGeckoInstruction inst) rGPR[inst.RD] = a / b; } + if (inst.OE) + SetXER_OV(overflow); + if (inst.Rc) Helper_UpdateCR0(rGPR[inst.RD]); } @@ -572,8 +570,8 @@ void Interpreter::mullwx(UGeckoInstruction inst) rGPR[inst.RD] = static_cast(result); - if (inst.OE && (result < -0x80000000LL || result > 0x7FFFFFFFLL)) - SetXER_OV(true); + if (inst.OE) + SetXER_OV(result < -0x80000000LL || result > 0x7FFFFFFFLL); if (inst.Rc) Helper_UpdateCR0(rGPR[inst.RD]); @@ -588,8 +586,8 @@ void Interpreter::negx(UGeckoInstruction inst) if (inst.Rc) Helper_UpdateCR0(rGPR[inst.RD]); - if (inst.OE && a == 0x80000000) - SetXER_OV(true); + if (inst.OE) + SetXER_OV(a == 0x80000000); } void Interpreter::subfx(UGeckoInstruction inst) diff --git a/Source/Core/Core/PowerPC/PowerPC.h b/Source/Core/Core/PowerPC/PowerPC.h index 5b74df1a58..ba838a610d 100644 --- a/Source/Core/Core/PowerPC/PowerPC.h +++ b/Source/Core/Core/PowerPC/PowerPC.h @@ -434,7 +434,7 @@ inline u32 GetXER_OV() inline void SetXER_OV(bool value) { - PowerPC::ppcState.xer_so_ov |= static_cast(value); + PowerPC::ppcState.xer_so_ov = (PowerPC::ppcState.xer_so_ov & 0xFE) | static_cast(value); SetXER_SO(value); }