From 8c4aa133ca2aac4e45e7d03add5288925b11e849 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Sat, 26 May 2018 19:18:18 -0400 Subject: [PATCH] Interpreter_FloatingPoint: Handle NaN flag setting within fctiw and fctiwz If a NaN of any type is passed as the operand to either of these instructions, we shouldn't go down the regular code path, as we end up potentially setting the wrong flags. For example, we wouldn't set the FPSCR.VXCVI bit properly. We'd also set FPSCR.FI, when in actuality it should be unset. If an SNaN is passed as an operand, we also need to set the FPSCR.VXSNAN bit as well. The flag setting behavior for these can be found in Appendix C.4.2 in PowerPC Microprocessor Family: The Programming Environments Manual for 32 and 64-bit Microprocessors. --- .../Interpreter/Interpreter_FloatingPoint.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index f8f64ed37f..aa245c8662 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -22,13 +22,27 @@ enum class RoundingMode TowardsNegativeInfinity = 0b11 }; +// Note that the convert to integer operation is defined +// in Appendix C.4.2 in PowerPC Microprocessor Family: +// The Programming Environments Manual for 32 and 64-bit Microprocessors void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) { const double b = rPS0(inst.FB); u32 value; - if (b > static_cast(0x7fffffff)) + if (std::isnan(b)) { + if (Common::IsSNAN(b)) + SetFPException(FPSCR_VXSNAN); + + value = 0x80000000; + SetFPException(FPSCR_VXCVI); + FPSCR.FI = 0; + FPSCR.FR = 0; + } + else if (b > static_cast(0x7fffffff)) + { + // Positive large operand or +inf value = 0x7fffffff; SetFPException(FPSCR_VXCVI); FPSCR.FI = 0; @@ -36,6 +50,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) } else if (b < -static_cast(0x80000000)) { + // Negative large operand or -inf value = 0x80000000; SetFPException(FPSCR_VXCVI); FPSCR.FI = 0; @@ -84,6 +99,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode) } else { + // Also sets FPSCR[XX] SetFI(1); FPSCR.FR = fabs(di) > fabs(b); }