From 78a934bb12bc5f209242445bb58073b08ff3aad7 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 26 May 2018 19:58:19 -0400 Subject: [PATCH] Interpreter_FloatingPoint: Handle cases when FPSCR.VE is set and exceptions occur in fctiw and fctiwz If invalid operation exceptions are enabled and an invalid operation occurs, then the destination value remains untouched. This fixes issues that may arise when using these two instructions where the destination gets steamrolled by an infinity or NaN value. --- .../Interpreter/Interpreter_FloatingPoint.cpp | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index aa245c8662..e3d194ee4f 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -29,6 +29,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) { const double b = rPS0(inst.FB); u32 value; + bool exception_occurred = false; if (std::isnan(b)) { @@ -37,24 +38,21 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) value = 0x80000000; SetFPException(FPSCR_VXCVI); - FPSCR.FI = 0; - FPSCR.FR = 0; + exception_occurred = true; } else if (b > static_cast(0x7fffffff)) { // Positive large operand or +inf value = 0x7fffffff; SetFPException(FPSCR_VXCVI); - FPSCR.FI = 0; - FPSCR.FR = 0; + exception_occurred = true; } else if (b < -static_cast(0x80000000)) { // Negative large operand or -inf value = 0x80000000; SetFPException(FPSCR_VXCVI); - FPSCR.FI = 0; - FPSCR.FR = 0; + exception_occurred = true; } else { @@ -105,11 +103,21 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) } } - // Based on HW tests - // FPRF is not affected - riPS0(inst.FD) = 0xfff8000000000000ull | value; - if (value == 0 && std::signbit(b)) - riPS0(inst.FD) |= 0x100000000ull; + if (exception_occurred) + { + FPSCR.FI = 0; + FPSCR.FR = 0; + } + + if (!exception_occurred || FPSCR.VE == 0) + { + // Based on HW tests + // FPRF is not affected + riPS0(inst.FD) = 0xfff8000000000000ull | value; + if (value == 0 && std::signbit(b)) + riPS0(inst.FD) |= 0x100000000ull; + } + if (inst.Rc) Helper_UpdateCR1(); }