From a08ad82ace064f961b13369c96a0f3b48ca7ca5c Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 1 Jun 2018 18:55:26 -0400 Subject: [PATCH 1/2] Interpreter_FloatingPoint: Don't store to destination in fres if VE or ZE is set and a relevant exception occurs In the PowerPC Microprocessor Family: The Programming Environments Manual for 32 and 64-bit Microprocessors, in section 3.3.6.1, Table 3-12 lists what should occur if an invalid operation exception occurs in situations where VE is set and when VE is not set. In the case where VE is set, it lists the frD as "Unchanged". It also lists the FPRF flags as "Unchanged". Further down in Table 3-13, the listings for what should occur when zero divide exceptions occur is listed, both for when ZE is set, and when it isn't. When ZE is set, it lists frD as "Unchanged". It also lists the FPRF flags as "Unchanged" as well. This also alters the code so that we don't even calculate the result if we don't need to compute it, making it a little bit less wasteful. --- .../Interpreter/Interpreter_FloatingPoint.cpp | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index e3d194ee4f..5578a4b9bb 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -387,27 +387,30 @@ void Interpreter::fdivsx(UGeckoInstruction inst) void Interpreter::fresx(UGeckoInstruction inst) { const double b = rPS0(inst.FB); - const double result = Common::ApproximateReciprocal(b); - rPS0(inst.FD) = rPS1(inst.FD) = result; + const auto compute_result = [inst](double value) { + const double result = Common::ApproximateReciprocal(value); + rPS0(inst.FD) = rPS1(inst.FD) = result; + PowerPC::UpdateFPRF(result); + }; if (b == 0.0) { SetFPException(FPSCR_ZX); if (FPSCR.ZE == 0) - PowerPC::UpdateFPRF(result); + compute_result(b); } else if (Common::IsSNAN(b)) { SetFPException(FPSCR_VXSNAN); if (FPSCR.VE == 0) - PowerPC::UpdateFPRF(result); + compute_result(b); } else { - PowerPC::UpdateFPRF(result); + compute_result(b); } if (inst.Rc) From 179d73ac0d2873ebf2dedd7a4069ea5ded4a66f1 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Fri, 1 Jun 2018 19:05:43 -0400 Subject: [PATCH 2/2] Interpreter_FloatingPoint: Clear FPSCR.FI and FPSCR.FR if an SNaN is an input to fres In the PEM manual, within Table 3-12, which lists what should occur for invalid operation exceptions, the FPSCR.FI and FPSCR.FR bits are listed as "Cleared" for when FPSCR.VE is unset and set. So we clear these bits as well to match hardware behavior. --- .../Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp index 5578a4b9bb..91504ede1a 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp @@ -404,6 +404,8 @@ void Interpreter::fresx(UGeckoInstruction inst) else if (Common::IsSNAN(b)) { SetFPException(FPSCR_VXSNAN); + FPSCR.FI = 0; + FPSCR.FR = 0; if (FPSCR.VE == 0) compute_result(b);