summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorLéo Lam <leo@innovatetechnologi.es>2018-06-03 15:36:12 +0200
committerGitHub <noreply@github.com>2018-06-03 15:36:12 +0200
commitc22205cd7e70a46558f6e7e5532ad5154b4e93bd (patch)
tree00e3160337d01c2e9c38a615787423b7cb3fb043 /Source/Core
parent66ee47c4179c2948dfa107df852fdb709cedf7b4 (diff)
parent3e63d7104634c719956e1f518cd64ded622a1eb5 (diff)
Merge pull request #7053 from lioncash/frfi
Interpreter_FPUtils/FloatingPoint/Paired: Amend cases where FPSCR.FR and FPSCR.FI should be unset
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/PowerPC/Gekko.h6
-rw-r--r--Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h36
-rw-r--r--Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp20
-rw-r--r--Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp30
4 files changed, 72 insertions, 20 deletions
diff --git a/Source/Core/Core/PowerPC/Gekko.h b/Source/Core/Core/PowerPC/Gekko.h
index a046b883c2..ca083b1219 100644
--- a/Source/Core/Core/PowerPC/Gekko.h
+++ b/Source/Core/Core/PowerPC/Gekko.h
@@ -476,6 +476,12 @@ union UReg_FPSCR
UReg_FPSCR() = default;
explicit UReg_FPSCR(u32 hex_) : Hex{hex_} {}
+
+ void ClearFIFR()
+ {
+ FI = 0;
+ FR = 0;
+ }
};
// Hardware Implementation-Dependent Register 0
diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h
index abc798d220..ed15cef6da 100644
--- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h
+++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h
@@ -103,7 +103,10 @@ inline double NI_mul(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(a))
return MakeQuiet(a);
@@ -111,6 +114,7 @@ inline double NI_mul(double a, double b)
return MakeQuiet(b);
SetFPException(FPSCR_VXIMZ);
+ FPSCR.ClearFIFR();
return PPC_NAN;
}
return t;
@@ -123,7 +127,10 @@ inline double NI_div(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(a))
return MakeQuiet(a);
@@ -135,17 +142,18 @@ inline double NI_div(double a, double b)
if (a == 0.0)
{
SetFPException(FPSCR_VXZDZ);
+ FPSCR.ClearFIFR();
}
else
{
SetFPException(FPSCR_ZX);
- FPSCR.FI = 0;
- FPSCR.FR = 0;
+ FPSCR.ClearFIFR();
}
}
else if (std::isinf(a) && std::isinf(b))
{
SetFPException(FPSCR_VXIDI);
+ FPSCR.ClearFIFR();
}
return PPC_NAN;
@@ -161,7 +169,10 @@ inline double NI_add(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(a))
return MakeQuiet(a);
@@ -169,6 +180,7 @@ inline double NI_add(double a, double b)
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
+ FPSCR.ClearFIFR();
return PPC_NAN;
}
@@ -182,7 +194,10 @@ inline double NI_sub(double a, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(a))
return MakeQuiet(a);
@@ -190,6 +205,7 @@ inline double NI_sub(double a, double b)
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
+ FPSCR.ClearFIFR();
return PPC_NAN;
}
@@ -206,7 +222,10 @@ inline double NI_madd(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(a))
return MakeQuiet(a);
@@ -216,6 +235,7 @@ inline double NI_madd(double a, double c, double b)
return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
+ FPSCR.ClearFIFR();
return PPC_NAN;
}
@@ -224,12 +244,16 @@ inline double NI_madd(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(b))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
+ FPSCR.ClearFIFR();
return PPC_NAN;
}
@@ -243,7 +267,10 @@ inline double NI_msub(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(a))
return MakeQuiet(a);
@@ -253,6 +280,7 @@ inline double NI_msub(double a, double c, double b)
return MakeQuiet(c);
SetFPException(FPSCR_VXIMZ);
+ FPSCR.ClearFIFR();
return PPC_NAN;
}
@@ -261,12 +289,16 @@ inline double NI_msub(double a, double c, double b)
if (std::isnan(t))
{
if (Common::IsSNAN(b))
+ {
SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
+ }
if (std::isnan(b))
return MakeQuiet(b);
SetFPException(FPSCR_VXISI);
+ FPSCR.ClearFIFR();
return PPC_NAN;
}
diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
index 3782c748a5..32f78343e9 100644
--- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
+++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
@@ -92,8 +92,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
const double di = i;
if (di == b)
{
- FPSCR.FI = 0;
- FPSCR.FR = 0;
+ FPSCR.ClearFIFR();
}
else
{
@@ -105,8 +104,7 @@ void ConvertToInteger(UGeckoInstruction inst, RoundingMode rounding_mode)
if (exception_occurred)
{
- FPSCR.FI = 0;
- FPSCR.FR = 0;
+ FPSCR.ClearFIFR();
}
if (!exception_occurred || FPSCR.VE == 0)
@@ -285,8 +283,7 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single
PowerPC::UpdateFPRF(b);
}
- SetFI(0);
- FPSCR.FR = 0;
+ FPSCR.ClearFIFR();
}
else
{
@@ -397,6 +394,7 @@ void Interpreter::fresx(UGeckoInstruction inst)
if (b == 0.0)
{
SetFPException(FPSCR_ZX);
+ FPSCR.ClearFIFR();
if (FPSCR.ZE == 0)
compute_result(b);
@@ -404,8 +402,7 @@ void Interpreter::fresx(UGeckoInstruction inst)
else if (Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
- FPSCR.FI = 0;
- FPSCR.FR = 0;
+ FPSCR.ClearFIFR();
if (FPSCR.VE == 0)
compute_result(b);
@@ -432,8 +429,7 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
if (b < 0.0)
{
SetFPException(FPSCR_VXSQRT);
- FPSCR.FI = 0;
- FPSCR.FR = 0;
+ FPSCR.ClearFIFR();
if (FPSCR.VE == 0)
compute_result(b);
@@ -441,6 +437,7 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
else if (b == 0.0)
{
SetFPException(FPSCR_ZX);
+ FPSCR.ClearFIFR();
if (FPSCR.ZE == 0)
compute_result(b);
@@ -448,8 +445,7 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
else if (Common::IsSNAN(b))
{
SetFPException(FPSCR_VXSNAN);
- FPSCR.FI = 0;
- FPSCR.FR = 0;
+ FPSCR.ClearFIFR();
if (FPSCR.VE == 0)
compute_result(b);
diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp
index 6a84132c96..380c9ac103 100644
--- a/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp
+++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter_Paired.cpp
@@ -115,12 +115,19 @@ void Interpreter::ps_div(UGeckoInstruction inst)
void Interpreter::ps_res(UGeckoInstruction inst)
{
// this code is based on the real hardware tests
- double a = rPS0(inst.FB);
- double b = rPS1(inst.FB);
+ const double a = rPS0(inst.FB);
+ const double b = rPS1(inst.FB);
if (a == 0.0 || b == 0.0)
{
SetFPException(FPSCR_ZX);
+ FPSCR.ClearFIFR();
+ }
+
+ if (Common::IsSNAN(a) || Common::IsSNAN(b))
+ {
+ SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
}
rPS0(inst.FD) = Common::ApproximateReciprocal(a);
@@ -133,18 +140,29 @@ void Interpreter::ps_res(UGeckoInstruction inst)
void Interpreter::ps_rsqrte(UGeckoInstruction inst)
{
- if (rPS0(inst.FB) == 0.0 || rPS1(inst.FB) == 0.0)
+ const double ps0 = rPS0(inst.FB);
+ const double ps1 = rPS1(inst.FB);
+
+ if (ps0 == 0.0 || ps1 == 0.0)
{
SetFPException(FPSCR_ZX);
+ FPSCR.ClearFIFR();
}
- if (rPS0(inst.FB) < 0.0 || rPS1(inst.FB) < 0.0)
+ if (ps0 < 0.0 || ps1 < 0.0)
{
SetFPException(FPSCR_VXSQRT);
+ FPSCR.ClearFIFR();
+ }
+
+ if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
+ {
+ SetFPException(FPSCR_VXSNAN);
+ FPSCR.ClearFIFR();
}
- rPS0(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(rPS0(inst.FB)));
- rPS1(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(rPS1(inst.FB)));
+ rPS0(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps0));
+ rPS1(inst.FD) = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps1));
PowerPC::UpdateFPRF(rPS0(inst.FD));