Merge pull request #7141 from lioncash/fp
Interpreter_FPUtils: Handle the FPSCR.ZE and FPSCR.VE flags with arithmetic instructions
This commit is contained in:
commit
9ea3e833ba
|
@ -97,206 +97,280 @@ inline double MakeQuiet(double d)
|
|||
// these functions allow globally modify operations behaviour
|
||||
// also, these may be used to set flags like FR, FI, OX, UX
|
||||
|
||||
inline double NI_mul(double a, double b)
|
||||
struct FPResult
|
||||
{
|
||||
const double t = a * b;
|
||||
if (std::isnan(t))
|
||||
bool HasNoInvalidExceptions() const { return (exception & FPSCR_VX_ANY) == 0; }
|
||||
|
||||
void SetException(FPSCRExceptionFlag flag)
|
||||
{
|
||||
exception = flag;
|
||||
SetFPException(flag);
|
||||
}
|
||||
|
||||
double value = 0.0;
|
||||
FPSCRExceptionFlag exception{};
|
||||
};
|
||||
|
||||
inline FPResult NI_mul(double a, double b)
|
||||
{
|
||||
FPResult result{a * b};
|
||||
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
{
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
}
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
return MakeQuiet(a);
|
||||
{
|
||||
result.value = MakeQuiet(a);
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b);
|
||||
{
|
||||
result.value = MakeQuiet(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
SetFPException(FPSCR_VXIMZ);
|
||||
return PPC_NAN;
|
||||
result.value = PPC_NAN;
|
||||
result.SetException(FPSCR_VXIMZ);
|
||||
return result;
|
||||
}
|
||||
return t;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline double NI_div(double a, double b)
|
||||
inline FPResult NI_div(double a, double b)
|
||||
{
|
||||
const double t = a / b;
|
||||
FPResult result{a / b};
|
||||
|
||||
if (std::isnan(t))
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
return MakeQuiet(a);
|
||||
{
|
||||
result.value = MakeQuiet(a);
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b);
|
||||
{
|
||||
result.value = MakeQuiet(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
if (b == 0.0)
|
||||
{
|
||||
if (a == 0.0)
|
||||
{
|
||||
SetFPException(FPSCR_VXZDZ);
|
||||
result.SetException(FPSCR_VXZDZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetFPException(FPSCR_ZX);
|
||||
result.SetException(FPSCR_ZX);
|
||||
}
|
||||
}
|
||||
else if (std::isinf(a) && std::isinf(b))
|
||||
{
|
||||
SetFPException(FPSCR_VXIDI);
|
||||
result.SetException(FPSCR_VXIDI);
|
||||
}
|
||||
|
||||
return PPC_NAN;
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
return t;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline double NI_add(double a, double b)
|
||||
inline FPResult NI_add(double a, double b)
|
||||
{
|
||||
const double t = a + b;
|
||||
FPResult result{a + b};
|
||||
|
||||
if (std::isnan(t))
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
return MakeQuiet(a);
|
||||
{
|
||||
result.value = MakeQuiet(a);
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b);
|
||||
{
|
||||
result.value = MakeQuiet(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b))
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
return t;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline double NI_sub(double a, double b)
|
||||
inline FPResult NI_sub(double a, double b)
|
||||
{
|
||||
const double t = a - b;
|
||||
FPResult result{a - b};
|
||||
|
||||
if (std::isnan(t))
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
return MakeQuiet(a);
|
||||
{
|
||||
result.value = MakeQuiet(a);
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b);
|
||||
{
|
||||
result.value = MakeQuiet(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b))
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
return t;
|
||||
return result;
|
||||
}
|
||||
|
||||
// FMA instructions on PowerPC are weird:
|
||||
// They calculate (a * c) + b, but the order in which
|
||||
// inputs are checked for NaN is still a, b, c.
|
||||
inline double NI_madd(double a, double c, double b)
|
||||
inline FPResult NI_madd(double a, double c, double b)
|
||||
{
|
||||
double t = a * c;
|
||||
FPResult result{a * c};
|
||||
|
||||
if (std::isnan(t))
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
return MakeQuiet(a);
|
||||
{
|
||||
result.value = MakeQuiet(a);
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b); // !
|
||||
{
|
||||
result.value = MakeQuiet(b); // !
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(c))
|
||||
return MakeQuiet(c);
|
||||
{
|
||||
result.value = MakeQuiet(c);
|
||||
return result;
|
||||
}
|
||||
|
||||
SetFPException(FPSCR_VXIMZ);
|
||||
return PPC_NAN;
|
||||
result.SetException(FPSCR_VXIMZ);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
t += b;
|
||||
result.value += b;
|
||||
|
||||
if (std::isnan(t))
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(b))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b);
|
||||
{
|
||||
result.value = MakeQuiet(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
return t;
|
||||
return result;
|
||||
}
|
||||
|
||||
inline double NI_msub(double a, double c, double b)
|
||||
inline FPResult NI_msub(double a, double c, double b)
|
||||
{
|
||||
double t = a * c;
|
||||
FPResult result{a * c};
|
||||
|
||||
if (std::isnan(t))
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
return MakeQuiet(a);
|
||||
{
|
||||
result.value = MakeQuiet(a);
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b); // !
|
||||
{
|
||||
result.value = MakeQuiet(b); // !
|
||||
return result;
|
||||
}
|
||||
if (std::isnan(c))
|
||||
return MakeQuiet(c);
|
||||
{
|
||||
result.value = MakeQuiet(c);
|
||||
return result;
|
||||
}
|
||||
|
||||
SetFPException(FPSCR_VXIMZ);
|
||||
return PPC_NAN;
|
||||
result.SetException(FPSCR_VXIMZ);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
t -= b;
|
||||
result.value -= b;
|
||||
|
||||
if (std::isnan(t))
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(b))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (std::isnan(b))
|
||||
return MakeQuiet(b);
|
||||
{
|
||||
result.value = MakeQuiet(b);
|
||||
return result;
|
||||
}
|
||||
|
||||
SetFPException(FPSCR_VXISI);
|
||||
return PPC_NAN;
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
return t;
|
||||
return result;
|
||||
}
|
||||
|
||||
// used by stfsXX instructions and ps_rsqrte
|
||||
|
|
|
@ -300,23 +300,35 @@ void Interpreter::frspx(UGeckoInstruction inst) // round to single
|
|||
|
||||
void Interpreter::fmulx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = ForceDouble(NI_mul(rPS0(inst.FA), rPS0(inst.FC)));
|
||||
FPSCR.FI = 0; // are these flags important?
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult product = NI_mul(rPS0(inst.FA), rPS0(inst.FC));
|
||||
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceDouble(product.value);
|
||||
|
||||
rPS0(inst.FD) = result;
|
||||
FPSCR.FI = 0; // are these flags important?
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
}
|
||||
void Interpreter::fmulsx(UGeckoInstruction inst)
|
||||
{
|
||||
double c_value = Force25Bit(rPS0(inst.FC));
|
||||
double d_value = NI_mul(rPS0(inst.FA), c_value);
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(d_value);
|
||||
// FPSCR.FI = d_value != rPS0(_inst.FD);
|
||||
FPSCR.FI = 0;
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const double c_value = Force25Bit(rPS0(inst.FC));
|
||||
const FPResult d_value = NI_mul(rPS0(inst.FA), c_value);
|
||||
|
||||
if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceSingle(d_value.value);
|
||||
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = result;
|
||||
FPSCR.FI = 0;
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -324,9 +336,14 @@ void Interpreter::fmulsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fmaddx(UGeckoInstruction inst)
|
||||
{
|
||||
double result = ForceDouble(NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB)));
|
||||
rPS0(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
const FPResult product = NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceDouble(product.value);
|
||||
rPS0(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -334,12 +351,18 @@ void Interpreter::fmaddx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fmaddsx(UGeckoInstruction inst)
|
||||
{
|
||||
double c_value = Force25Bit(rPS0(inst.FC));
|
||||
double d_value = NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB));
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(d_value);
|
||||
FPSCR.FI = d_value != rPS0(inst.FD);
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const double c_value = Force25Bit(rPS0(inst.FC));
|
||||
const FPResult d_value = NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || d_value.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceSingle(d_value.value);
|
||||
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = result;
|
||||
FPSCR.FI = d_value.value != result;
|
||||
FPSCR.FR = 0;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -347,16 +370,28 @@ void Interpreter::fmaddsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::faddx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = ForceDouble(NI_add(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult sum = NI_add(rPS0(inst.FA), rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceDouble(sum.value);
|
||||
rPS0(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
}
|
||||
void Interpreter::faddsx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_add(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult sum = NI_add(rPS0(inst.FA), rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || sum.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceSingle(sum.value);
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -364,8 +399,16 @@ void Interpreter::faddsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fdivx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = ForceDouble(NI_div(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult quotient = NI_div(rPS0(inst.FA), rPS0(inst.FB));
|
||||
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||
|
||||
if (not_divide_by_zero && not_invalid)
|
||||
{
|
||||
const double result = ForceDouble(quotient.value);
|
||||
rPS0(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
// FR,FI,OX,UX???
|
||||
if (inst.Rc)
|
||||
|
@ -373,8 +416,16 @@ void Interpreter::fdivx(UGeckoInstruction inst)
|
|||
}
|
||||
void Interpreter::fdivsx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_div(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult quotient = NI_div(rPS0(inst.FA), rPS0(inst.FB));
|
||||
const bool not_divide_by_zero = FPSCR.ZE == 0 || quotient.exception != FPSCR_ZX;
|
||||
const bool not_invalid = FPSCR.VE == 0 || quotient.HasNoInvalidExceptions();
|
||||
|
||||
if (not_divide_by_zero && not_invalid)
|
||||
{
|
||||
const double result = ForceSingle(quotient.value);
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -465,20 +516,32 @@ void Interpreter::frsqrtex(UGeckoInstruction inst)
|
|||
Helper_UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::fmsubx(UGeckoInstruction _inst)
|
||||
void Interpreter::fmsubx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(_inst.FD) = ForceDouble(NI_msub(rPS0(_inst.FA), rPS0(_inst.FC), rPS0(_inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(_inst.FD));
|
||||
const FPResult product = NI_msub(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
|
||||
|
||||
if (_inst.Rc)
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceDouble(product.value);
|
||||
rPS0(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::fmsubsx(UGeckoInstruction inst)
|
||||
{
|
||||
double c_value = Force25Bit(rPS0(inst.FC));
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const double c_value = Force25Bit(rPS0(inst.FC));
|
||||
const FPResult product = NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceSingle(product.value);
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -486,9 +549,14 @@ void Interpreter::fmsubsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmaddx(UGeckoInstruction inst)
|
||||
{
|
||||
double result = ForceDouble(NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB)));
|
||||
rPS0(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult product = NI_madd(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceDouble(product.value);
|
||||
rPS0(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -496,10 +564,15 @@ void Interpreter::fnmaddx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmaddsx(UGeckoInstruction inst)
|
||||
{
|
||||
double c_value = Force25Bit(rPS0(inst.FC));
|
||||
double result = ForceSingle(NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB)));
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const double c_value = Force25Bit(rPS0(inst.FC));
|
||||
const FPResult product = NI_madd(rPS0(inst.FA), c_value, rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceSingle(product.value);
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -507,9 +580,14 @@ void Interpreter::fnmaddsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmsubx(UGeckoInstruction inst)
|
||||
{
|
||||
double result = ForceDouble(NI_msub(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB)));
|
||||
rPS0(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult product = NI_msub(rPS0(inst.FA), rPS0(inst.FC), rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceDouble(product.value);
|
||||
rPS0(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -517,10 +595,15 @@ void Interpreter::fnmsubx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fnmsubsx(UGeckoInstruction inst)
|
||||
{
|
||||
double c_value = Force25Bit(rPS0(inst.FC));
|
||||
double result = ForceSingle(NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB)));
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const double c_value = Force25Bit(rPS0(inst.FC));
|
||||
const FPResult product = NI_msub(rPS0(inst.FA), c_value, rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || product.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceSingle(product.value);
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = std::isnan(result) ? result : -result;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -528,8 +611,14 @@ void Interpreter::fnmsubsx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fsubx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = ForceDouble(NI_sub(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult difference = NI_sub(rPS0(inst.FA), rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceDouble(difference.value);
|
||||
rPS0(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
@ -537,8 +626,14 @@ void Interpreter::fsubx(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::fsubsx(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = ForceSingle(NI_sub(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
const FPResult difference = NI_sub(rPS0(inst.FA), rPS0(inst.FB));
|
||||
|
||||
if (FPSCR.VE == 0 || difference.HasNoInvalidExceptions())
|
||||
{
|
||||
const double result = ForceSingle(difference.value);
|
||||
rPS0(inst.FD) = rPS1(inst.FD) = result;
|
||||
PowerPC::UpdateFPRF(result);
|
||||
}
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
|
|
|
@ -104,8 +104,8 @@ void Interpreter::ps_merge11(UGeckoInstruction inst)
|
|||
// From here on, the real deal.
|
||||
void Interpreter::ps_div(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = ForceSingle(NI_div(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
rPS1(inst.FD) = ForceSingle(NI_div(rPS1(inst.FA), rPS1(inst.FB)));
|
||||
rPS0(inst.FD) = ForceSingle(NI_div(rPS0(inst.FA), rPS0(inst.FB)).value);
|
||||
rPS1(inst.FD) = ForceSingle(NI_div(rPS1(inst.FA), rPS1(inst.FB)).value);
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -172,8 +172,8 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_sub(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = ForceSingle(NI_sub(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
rPS1(inst.FD) = ForceSingle(NI_sub(rPS1(inst.FA), rPS1(inst.FB)));
|
||||
rPS0(inst.FD) = ForceSingle(NI_sub(rPS0(inst.FA), rPS0(inst.FB)).value);
|
||||
rPS1(inst.FD) = ForceSingle(NI_sub(rPS1(inst.FA), rPS1(inst.FB)).value);
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -182,8 +182,8 @@ void Interpreter::ps_sub(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_add(UGeckoInstruction inst)
|
||||
{
|
||||
rPS0(inst.FD) = ForceSingle(NI_add(rPS0(inst.FA), rPS0(inst.FB)));
|
||||
rPS1(inst.FD) = ForceSingle(NI_add(rPS1(inst.FA), rPS1(inst.FB)));
|
||||
rPS0(inst.FD) = ForceSingle(NI_add(rPS0(inst.FA), rPS0(inst.FB)).value);
|
||||
rPS1(inst.FD) = ForceSingle(NI_add(rPS1(inst.FA), rPS1(inst.FB)).value);
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -192,10 +192,10 @@ void Interpreter::ps_add(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_mul(UGeckoInstruction inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(inst.FC));
|
||||
double c1 = Force25Bit(rPS1(inst.FC));
|
||||
rPS0(inst.FD) = ForceSingle(NI_mul(rPS0(inst.FA), c0));
|
||||
rPS1(inst.FD) = ForceSingle(NI_mul(rPS1(inst.FA), c1));
|
||||
const double c0 = Force25Bit(rPS0(inst.FC));
|
||||
const double c1 = Force25Bit(rPS1(inst.FC));
|
||||
rPS0(inst.FD) = ForceSingle(NI_mul(rPS0(inst.FA), c0).value);
|
||||
rPS1(inst.FD) = ForceSingle(NI_mul(rPS1(inst.FA), c1).value);
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -204,10 +204,10 @@ void Interpreter::ps_mul(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_msub(UGeckoInstruction inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(inst.FC));
|
||||
double c1 = Force25Bit(rPS1(inst.FC));
|
||||
rPS0(inst.FD) = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)));
|
||||
rPS1(inst.FD) = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)));
|
||||
const double c0 = Force25Bit(rPS0(inst.FC));
|
||||
const double c1 = Force25Bit(rPS1(inst.FC));
|
||||
rPS0(inst.FD) = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
|
||||
rPS1(inst.FD) = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -216,10 +216,10 @@ void Interpreter::ps_msub(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_madd(UGeckoInstruction inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(inst.FC));
|
||||
double c1 = Force25Bit(rPS1(inst.FC));
|
||||
rPS0(inst.FD) = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)));
|
||||
rPS1(inst.FD) = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)));
|
||||
const double c0 = Force25Bit(rPS0(inst.FC));
|
||||
const double c1 = Force25Bit(rPS1(inst.FC));
|
||||
rPS0(inst.FD) = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
|
||||
rPS1(inst.FD) = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
||||
if (inst.Rc)
|
||||
|
@ -228,10 +228,10 @@ void Interpreter::ps_madd(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_nmsub(UGeckoInstruction inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(inst.FC));
|
||||
double c1 = Force25Bit(rPS1(inst.FC));
|
||||
double result0 = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)));
|
||||
double result1 = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)));
|
||||
const double c0 = Force25Bit(rPS0(inst.FC));
|
||||
const double c1 = Force25Bit(rPS1(inst.FC));
|
||||
const double result0 = ForceSingle(NI_msub(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
|
||||
const double result1 = ForceSingle(NI_msub(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
|
||||
rPS0(inst.FD) = std::isnan(result0) ? result0 : -result0;
|
||||
rPS1(inst.FD) = std::isnan(result1) ? result1 : -result1;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
@ -242,10 +242,10 @@ void Interpreter::ps_nmsub(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_nmadd(UGeckoInstruction inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(inst.FC));
|
||||
double c1 = Force25Bit(rPS1(inst.FC));
|
||||
double result0 = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)));
|
||||
double result1 = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)));
|
||||
const double c0 = Force25Bit(rPS0(inst.FC));
|
||||
const double c1 = Force25Bit(rPS1(inst.FC));
|
||||
const double result0 = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
|
||||
const double result1 = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
|
||||
rPS0(inst.FD) = std::isnan(result0) ? result0 : -result0;
|
||||
rPS1(inst.FD) = std::isnan(result1) ? result1 : -result1;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
@ -256,8 +256,8 @@ void Interpreter::ps_nmadd(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_sum0(UGeckoInstruction inst)
|
||||
{
|
||||
double p0 = ForceSingle(NI_add(rPS0(inst.FA), rPS1(inst.FB)));
|
||||
double p1 = ForceSingle(rPS1(inst.FC));
|
||||
const double p0 = ForceSingle(NI_add(rPS0(inst.FA), rPS1(inst.FB)).value);
|
||||
const double p1 = ForceSingle(rPS1(inst.FC));
|
||||
rPS0(inst.FD) = p0;
|
||||
rPS1(inst.FD) = p1;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
@ -268,8 +268,8 @@ void Interpreter::ps_sum0(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_sum1(UGeckoInstruction inst)
|
||||
{
|
||||
double p0 = ForceSingle(rPS0(inst.FC));
|
||||
double p1 = ForceSingle(NI_add(rPS0(inst.FA), rPS1(inst.FB)));
|
||||
const double p0 = ForceSingle(rPS0(inst.FC));
|
||||
const double p1 = ForceSingle(NI_add(rPS0(inst.FA), rPS1(inst.FB)).value);
|
||||
rPS0(inst.FD) = p0;
|
||||
rPS1(inst.FD) = p1;
|
||||
PowerPC::UpdateFPRF(rPS1(inst.FD));
|
||||
|
@ -280,9 +280,9 @@ void Interpreter::ps_sum1(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_muls0(UGeckoInstruction inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(inst.FC));
|
||||
double p0 = ForceSingle(NI_mul(rPS0(inst.FA), c0));
|
||||
double p1 = ForceSingle(NI_mul(rPS1(inst.FA), c0));
|
||||
const double c0 = Force25Bit(rPS0(inst.FC));
|
||||
const double p0 = ForceSingle(NI_mul(rPS0(inst.FA), c0).value);
|
||||
const double p1 = ForceSingle(NI_mul(rPS1(inst.FA), c0).value);
|
||||
rPS0(inst.FD) = p0;
|
||||
rPS1(inst.FD) = p1;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
@ -293,9 +293,9 @@ void Interpreter::ps_muls0(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_muls1(UGeckoInstruction inst)
|
||||
{
|
||||
double c1 = Force25Bit(rPS1(inst.FC));
|
||||
double p0 = ForceSingle(NI_mul(rPS0(inst.FA), c1));
|
||||
double p1 = ForceSingle(NI_mul(rPS1(inst.FA), c1));
|
||||
const double c1 = Force25Bit(rPS1(inst.FC));
|
||||
const double p0 = ForceSingle(NI_mul(rPS0(inst.FA), c1).value);
|
||||
const double p1 = ForceSingle(NI_mul(rPS1(inst.FA), c1).value);
|
||||
rPS0(inst.FD) = p0;
|
||||
rPS1(inst.FD) = p1;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
@ -306,9 +306,9 @@ void Interpreter::ps_muls1(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_madds0(UGeckoInstruction inst)
|
||||
{
|
||||
double c0 = Force25Bit(rPS0(inst.FC));
|
||||
double p0 = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)));
|
||||
double p1 = ForceSingle(NI_madd(rPS1(inst.FA), c0, rPS1(inst.FB)));
|
||||
const double c0 = Force25Bit(rPS0(inst.FC));
|
||||
const double p0 = ForceSingle(NI_madd(rPS0(inst.FA), c0, rPS0(inst.FB)).value);
|
||||
const double p1 = ForceSingle(NI_madd(rPS1(inst.FA), c0, rPS1(inst.FB)).value);
|
||||
rPS0(inst.FD) = p0;
|
||||
rPS1(inst.FD) = p1;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
@ -319,9 +319,9 @@ void Interpreter::ps_madds0(UGeckoInstruction inst)
|
|||
|
||||
void Interpreter::ps_madds1(UGeckoInstruction inst)
|
||||
{
|
||||
double c1 = Force25Bit(rPS1(inst.FC));
|
||||
double p0 = ForceSingle(NI_madd(rPS0(inst.FA), c1, rPS0(inst.FB)));
|
||||
double p1 = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)));
|
||||
const double c1 = Force25Bit(rPS1(inst.FC));
|
||||
const double p0 = ForceSingle(NI_madd(rPS0(inst.FA), c1, rPS0(inst.FB)).value);
|
||||
const double p1 = ForceSingle(NI_madd(rPS1(inst.FA), c1, rPS1(inst.FB)).value);
|
||||
rPS0(inst.FD) = p0;
|
||||
rPS1(inst.FD) = p1;
|
||||
PowerPC::UpdateFPRF(rPS0(inst.FD));
|
||||
|
|
Loading…
Reference in New Issue