From 3deadd1fffae81083bb30449b868f2de48e3505d Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 28 May 2018 15:46:16 -0400 Subject: [PATCH 1/2] Interpreter_FPUtils: Correct setting the FPSCR's zero divide exception flag in the 0/0 case FPSCR[ZX] is the bit defined to represent the zero divide exception condition bit, and is defined as (according to PowerPC Microprocessor Family: The Programming Environments Manual for 32 and 64-bit Microprocessors, which will be referred to as "PEM" for the rest of this commit message) at section 3.3.6.1: " A zero divide exception condition occurs when a divide instructions is executed with a zero divisor value and a finite, nonzero dividend value or when a floating reciprocal estimate single (fres) or a floating reciprocal square root estimate (frsqrte) instruction is executed with a zero operand value. " Note that it states the divisor must be zero and the dividend must be nonzero in order for ZX to be set. This means that the interpreter was performing the wrong behavior for the case where 0/0 (with any sign on the zeros) is performed. We would incorrectly set the ZX bit when only the VXZDZ bit should be set. It's also worth pointing out that N/0 (where N is any finite nonzero value) and 0/0 are not within the same exception class. N/0 is a zero divide exception case, while 0/0 is considered an invalid operation exception case, which is also indicated in the PEM section 3.3.6.1 as well where it lists the criteria for invalid operation exceptions. Therefore we should only be setting the VXZDZ bit in the 0/0 case, not VXZDZ and ZX. This was also verified via hardware tests to ensure that this behavior indeed holds. --- Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index 843b580fdd..511d34f073 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -127,9 +127,14 @@ inline double NI_div(double a, double b) if (b == 0.0) { - SetFPException(FPSCR_ZX); if (a == 0.0) + { SetFPException(FPSCR_VXZDZ); + } + else + { + SetFPException(FPSCR_ZX); + } } else if (std::isinf(a) && std::isinf(b)) { From 7bfeffe32f9f1aa7ead0eaaa746eaaaee67e0be6 Mon Sep 17 00:00:00 2001 From: Lioncash Date: Mon, 28 May 2018 16:03:56 -0400 Subject: [PATCH 2/2] Interpreter_FPUtils: Unset FPSCR.FI and FPSCR.FR when FPSCR.ZX is set in NI_div() Another bit of behavior that we weren't performing correctly is the unsetting of FPSCR.FI and FPSCR.FR when FPSCR.ZX is supposed to be set. This is supported in PEM's section 3.3.6.1 where the following is stated: " When a zero divide condition occurs, the following actions are taken: - Zero divide exception condition bit is set FPSCR[ZX] = 1. - FPSCR[FR, FI] are cleared. " And so, this fixes that behavior. --- Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h index 511d34f073..c8ffc262d4 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h @@ -134,6 +134,8 @@ inline double NI_div(double a, double b) else { SetFPException(FPSCR_ZX); + FPSCR.FI = 0; + FPSCR.FR = 0; } } else if (std::isinf(a) && std::isinf(b))