mirror of
https://github.com/izzy2lost/dolphin.git
synced 2026-06-19 01:16:48 -07:00
Merge pull request #7889 from CrystalGamma/pr-floathelpers
PowerPC: Thread state through float helpers
This commit is contained in:
@@ -25,43 +25,22 @@ enum class FPCC
|
||||
FU = 1, // ?
|
||||
};
|
||||
|
||||
inline void SetFPException(u32 mask)
|
||||
inline void SetFPException(UReg_FPSCR* fpscr, u32 mask)
|
||||
{
|
||||
if ((FPSCR.Hex & mask) != mask)
|
||||
if ((fpscr->Hex & mask) != mask)
|
||||
{
|
||||
FPSCR.FX = 1;
|
||||
fpscr->FX = 1;
|
||||
}
|
||||
|
||||
FPSCR.Hex |= mask;
|
||||
FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0;
|
||||
fpscr->Hex |= mask;
|
||||
fpscr->VX = (fpscr->Hex & FPSCR_VX_ANY) != 0;
|
||||
}
|
||||
|
||||
inline void SetFI(int FI)
|
||||
{
|
||||
if (FI)
|
||||
{
|
||||
SetFPException(FPSCR_XX);
|
||||
}
|
||||
FPSCR.FI = FI;
|
||||
}
|
||||
|
||||
inline void UpdateFPSCR()
|
||||
{
|
||||
FPSCR.VX = (FPSCR.Hex & FPSCR_VX_ANY) != 0;
|
||||
FPSCR.FEX = (FPSCR.VX & FPSCR.VE) | (FPSCR.OX & FPSCR.OE) | (FPSCR.UX & FPSCR.UE) |
|
||||
(FPSCR.ZX & FPSCR.ZE) | (FPSCR.XX & FPSCR.XE);
|
||||
}
|
||||
|
||||
inline void Helper_UpdateCR1()
|
||||
{
|
||||
PowerPC::ppcState.cr.SetField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX);
|
||||
}
|
||||
|
||||
inline double ForceSingle(double value)
|
||||
inline double ForceSingle(const UReg_FPSCR& fpscr, double value)
|
||||
{
|
||||
// convert to float...
|
||||
float x = (float)value;
|
||||
if (!cpu_info.bFlushToZero && FPSCR.NI)
|
||||
if (!cpu_info.bFlushToZero && fpscr.NI)
|
||||
{
|
||||
x = Common::FlushToZero(x);
|
||||
}
|
||||
@@ -69,9 +48,9 @@ inline double ForceSingle(double value)
|
||||
return x;
|
||||
}
|
||||
|
||||
inline double ForceDouble(double d)
|
||||
inline double ForceDouble(const UReg_FPSCR& fpscr, double d)
|
||||
{
|
||||
if (!cpu_info.bFlushToZero && FPSCR.NI)
|
||||
if (!cpu_info.bFlushToZero && fpscr.NI)
|
||||
{
|
||||
d = Common::FlushToZero(d);
|
||||
}
|
||||
@@ -101,17 +80,17 @@ struct FPResult
|
||||
{
|
||||
bool HasNoInvalidExceptions() const { return (exception & FPSCR_VX_ANY) == 0; }
|
||||
|
||||
void SetException(FPSCRExceptionFlag flag)
|
||||
void SetException(UReg_FPSCR* fpscr, FPSCRExceptionFlag flag)
|
||||
{
|
||||
exception = flag;
|
||||
SetFPException(flag);
|
||||
SetFPException(fpscr, flag);
|
||||
}
|
||||
|
||||
double value = 0.0;
|
||||
FPSCRExceptionFlag exception{};
|
||||
};
|
||||
|
||||
inline FPResult NI_mul(double a, double b)
|
||||
inline FPResult NI_mul(UReg_FPSCR* fpscr, double a, double b)
|
||||
{
|
||||
FPResult result{a * b};
|
||||
|
||||
@@ -119,10 +98,10 @@ inline FPResult NI_mul(double a, double b)
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
{
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
}
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
{
|
||||
@@ -136,23 +115,23 @@ inline FPResult NI_mul(double a, double b)
|
||||
}
|
||||
|
||||
result.value = PPC_NAN;
|
||||
result.SetException(FPSCR_VXIMZ);
|
||||
result.SetException(fpscr, FPSCR_VXIMZ);
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline FPResult NI_div(double a, double b)
|
||||
inline FPResult NI_div(UReg_FPSCR* fpscr, double a, double b)
|
||||
{
|
||||
FPResult result{a / b};
|
||||
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
{
|
||||
@@ -169,16 +148,16 @@ inline FPResult NI_div(double a, double b)
|
||||
{
|
||||
if (a == 0.0)
|
||||
{
|
||||
result.SetException(FPSCR_VXZDZ);
|
||||
result.SetException(fpscr, FPSCR_VXZDZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
result.SetException(FPSCR_ZX);
|
||||
result.SetException(fpscr, FPSCR_ZX);
|
||||
}
|
||||
}
|
||||
else if (std::isinf(a) && std::isinf(b))
|
||||
{
|
||||
result.SetException(FPSCR_VXIDI);
|
||||
result.SetException(fpscr, FPSCR_VXIDI);
|
||||
}
|
||||
|
||||
result.value = PPC_NAN;
|
||||
@@ -188,16 +167,16 @@ inline FPResult NI_div(double a, double b)
|
||||
return result;
|
||||
}
|
||||
|
||||
inline FPResult NI_add(double a, double b)
|
||||
inline FPResult NI_add(UReg_FPSCR* fpscr, double a, double b)
|
||||
{
|
||||
FPResult result{a + b};
|
||||
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
{
|
||||
@@ -210,27 +189,27 @@ inline FPResult NI_add(double a, double b)
|
||||
return result;
|
||||
}
|
||||
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.SetException(fpscr, FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b))
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline FPResult NI_sub(double a, double b)
|
||||
inline FPResult NI_sub(UReg_FPSCR* fpscr, double a, double b)
|
||||
{
|
||||
FPResult result{a - b};
|
||||
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
{
|
||||
@@ -243,13 +222,13 @@ inline FPResult NI_sub(double a, double b)
|
||||
return result;
|
||||
}
|
||||
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.SetException(fpscr, FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b))
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -257,16 +236,16 @@ inline FPResult NI_sub(double a, double b)
|
||||
// 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 FPResult NI_madd(double a, double c, double b)
|
||||
inline FPResult NI_madd(UReg_FPSCR* fpscr, double a, double c, double b)
|
||||
{
|
||||
FPResult result{a * c};
|
||||
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
{
|
||||
@@ -284,7 +263,7 @@ inline FPResult NI_madd(double a, double c, double b)
|
||||
return result;
|
||||
}
|
||||
|
||||
result.SetException(FPSCR_VXIMZ);
|
||||
result.SetException(fpscr, FPSCR_VXIMZ);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
@@ -294,9 +273,9 @@ inline FPResult NI_madd(double a, double c, double b)
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(b))
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(b))
|
||||
{
|
||||
@@ -304,27 +283,27 @@ inline FPResult NI_madd(double a, double c, double b)
|
||||
return result;
|
||||
}
|
||||
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.SetException(fpscr, FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline FPResult NI_msub(double a, double c, double b)
|
||||
inline FPResult NI_msub(UReg_FPSCR* fpscr, double a, double c, double b)
|
||||
{
|
||||
FPResult result{a * c};
|
||||
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b) || Common::IsSNAN(c))
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(a))
|
||||
{
|
||||
@@ -342,7 +321,7 @@ inline FPResult NI_msub(double a, double c, double b)
|
||||
return result;
|
||||
}
|
||||
|
||||
result.SetException(FPSCR_VXIMZ);
|
||||
result.SetException(fpscr, FPSCR_VXIMZ);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
@@ -352,9 +331,9 @@ inline FPResult NI_msub(double a, double c, double b)
|
||||
if (std::isnan(result.value))
|
||||
{
|
||||
if (Common::IsSNAN(b))
|
||||
result.SetException(FPSCR_VXSNAN);
|
||||
result.SetException(fpscr, FPSCR_VXSNAN);
|
||||
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
if (std::isnan(b))
|
||||
{
|
||||
@@ -362,13 +341,13 @@ inline FPResult NI_msub(double a, double c, double b)
|
||||
return result;
|
||||
}
|
||||
|
||||
result.SetException(FPSCR_VXISI);
|
||||
result.SetException(fpscr, FPSCR_VXISI);
|
||||
result.value = PPC_NAN;
|
||||
return result;
|
||||
}
|
||||
|
||||
if (std::isinf(a) || std::isinf(b) || std::isinf(c))
|
||||
FPSCR.ClearFIFR();
|
||||
fpscr->ClearFIFR();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,7 +21,7 @@ void Interpreter::ps_sel(UGeckoInstruction inst)
|
||||
a.PS1AsDouble() >= -0.0 ? c.PS1AsDouble() : b.PS1AsDouble());
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_neg(UGeckoInstruction inst)
|
||||
@@ -31,7 +31,7 @@ void Interpreter::ps_neg(UGeckoInstruction inst)
|
||||
rPS(inst.FD).SetBoth(b.PS0AsU64() ^ (UINT64_C(1) << 63), b.PS1AsU64() ^ (UINT64_C(1) << 63));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_mr(UGeckoInstruction inst)
|
||||
@@ -39,7 +39,7 @@ void Interpreter::ps_mr(UGeckoInstruction inst)
|
||||
rPS(inst.FD) = rPS(inst.FB);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_nabs(UGeckoInstruction inst)
|
||||
@@ -49,7 +49,7 @@ void Interpreter::ps_nabs(UGeckoInstruction inst)
|
||||
rPS(inst.FD).SetBoth(b.PS0AsU64() | (UINT64_C(1) << 63), b.PS1AsU64() | (UINT64_C(1) << 63));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_abs(UGeckoInstruction inst)
|
||||
@@ -59,7 +59,7 @@ void Interpreter::ps_abs(UGeckoInstruction inst)
|
||||
rPS(inst.FD).SetBoth(b.PS0AsU64() & ~(UINT64_C(1) << 63), b.PS1AsU64() & ~(UINT64_C(1) << 63));
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
// These are just moves, double is OK.
|
||||
@@ -71,7 +71,7 @@ void Interpreter::ps_merge00(UGeckoInstruction inst)
|
||||
rPS(inst.FD).SetBoth(a.PS0AsDouble(), b.PS0AsDouble());
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_merge01(UGeckoInstruction inst)
|
||||
@@ -82,7 +82,7 @@ void Interpreter::ps_merge01(UGeckoInstruction inst)
|
||||
rPS(inst.FD).SetBoth(a.PS0AsDouble(), b.PS1AsDouble());
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_merge10(UGeckoInstruction inst)
|
||||
@@ -93,7 +93,7 @@ void Interpreter::ps_merge10(UGeckoInstruction inst)
|
||||
rPS(inst.FD).SetBoth(a.PS1AsDouble(), b.PS0AsDouble());
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_merge11(UGeckoInstruction inst)
|
||||
@@ -104,7 +104,7 @@ void Interpreter::ps_merge11(UGeckoInstruction inst)
|
||||
rPS(inst.FD).SetBoth(a.PS1AsDouble(), b.PS1AsDouble());
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
// From here on, the real deal.
|
||||
@@ -113,14 +113,14 @@ void Interpreter::ps_div(UGeckoInstruction inst)
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
|
||||
const double ps0 = ForceSingle(NI_div(a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(NI_div(a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
const double ps0 = ForceSingle(FPSCR, NI_div(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(FPSCR, NI_div(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_res(UGeckoInstruction inst)
|
||||
@@ -131,7 +131,7 @@ void Interpreter::ps_res(UGeckoInstruction inst)
|
||||
|
||||
if (a == 0.0 || b == 0.0)
|
||||
{
|
||||
SetFPException(FPSCR_ZX);
|
||||
SetFPException(&FPSCR, FPSCR_ZX);
|
||||
FPSCR.ClearFIFR();
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ void Interpreter::ps_res(UGeckoInstruction inst)
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (Common::IsSNAN(a) || Common::IsSNAN(b))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
|
||||
const double ps0 = Common::ApproximateReciprocal(a);
|
||||
const double ps1 = Common::ApproximateReciprocal(b);
|
||||
@@ -148,7 +148,7 @@ void Interpreter::ps_res(UGeckoInstruction inst)
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_rsqrte(UGeckoInstruction inst)
|
||||
@@ -158,13 +158,13 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
|
||||
|
||||
if (ps0 == 0.0 || ps1 == 0.0)
|
||||
{
|
||||
SetFPException(FPSCR_ZX);
|
||||
SetFPException(&FPSCR, FPSCR_ZX);
|
||||
FPSCR.ClearFIFR();
|
||||
}
|
||||
|
||||
if (ps0 < 0.0 || ps1 < 0.0)
|
||||
{
|
||||
SetFPException(FPSCR_VXSQRT);
|
||||
SetFPException(&FPSCR, FPSCR_VXSQRT);
|
||||
FPSCR.ClearFIFR();
|
||||
}
|
||||
|
||||
@@ -172,16 +172,16 @@ void Interpreter::ps_rsqrte(UGeckoInstruction inst)
|
||||
FPSCR.ClearFIFR();
|
||||
|
||||
if (Common::IsSNAN(ps0) || Common::IsSNAN(ps1))
|
||||
SetFPException(FPSCR_VXSNAN);
|
||||
SetFPException(&FPSCR, FPSCR_VXSNAN);
|
||||
|
||||
const double dst_ps0 = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps0));
|
||||
const double dst_ps1 = ForceSingle(Common::ApproximateReciprocalSquareRoot(ps1));
|
||||
const double dst_ps0 = ForceSingle(FPSCR, Common::ApproximateReciprocalSquareRoot(ps0));
|
||||
const double dst_ps1 = ForceSingle(FPSCR, Common::ApproximateReciprocalSquareRoot(ps1));
|
||||
|
||||
rPS(inst.FD).SetBoth(dst_ps0, dst_ps1);
|
||||
PowerPC::UpdateFPRF(dst_ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_sub(UGeckoInstruction inst)
|
||||
@@ -189,14 +189,14 @@ void Interpreter::ps_sub(UGeckoInstruction inst)
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
|
||||
const double ps0 = ForceSingle(NI_sub(a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(NI_sub(a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
const double ps0 = ForceSingle(FPSCR, NI_sub(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(FPSCR, NI_sub(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_add(UGeckoInstruction inst)
|
||||
@@ -204,14 +204,14 @@ void Interpreter::ps_add(UGeckoInstruction inst)
|
||||
const auto& a = rPS(inst.FA);
|
||||
const auto& b = rPS(inst.FB);
|
||||
|
||||
const double ps0 = ForceSingle(NI_add(a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(NI_add(a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
const double ps0 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS1AsDouble(), b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_mul(UGeckoInstruction inst)
|
||||
@@ -222,14 +222,14 @@ void Interpreter::ps_mul(UGeckoInstruction inst)
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const double ps0 = ForceSingle(NI_mul(a.PS0AsDouble(), c0).value);
|
||||
const double ps1 = ForceSingle(NI_mul(a.PS1AsDouble(), c1).value);
|
||||
const double ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c0).value);
|
||||
const double ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_msub(UGeckoInstruction inst)
|
||||
@@ -241,14 +241,16 @@ void Interpreter::ps_msub(UGeckoInstruction inst)
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const double ps0 = ForceSingle(NI_msub(a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(NI_msub(a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const double ps0 =
|
||||
ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double ps1 =
|
||||
ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_madd(UGeckoInstruction inst)
|
||||
@@ -260,14 +262,16 @@ void Interpreter::ps_madd(UGeckoInstruction inst)
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const double ps0 = ForceSingle(NI_madd(a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(NI_madd(a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const double ps0 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double ps1 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_nmsub(UGeckoInstruction inst)
|
||||
@@ -279,8 +283,10 @@ void Interpreter::ps_nmsub(UGeckoInstruction inst)
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const double tmp0 = ForceSingle(NI_msub(a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double tmp1 = ForceSingle(NI_msub(a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const double tmp0 =
|
||||
ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double tmp1 =
|
||||
ForceSingle(FPSCR, NI_msub(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
|
||||
const double ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
|
||||
const double ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
||||
@@ -289,7 +295,7 @@ void Interpreter::ps_nmsub(UGeckoInstruction inst)
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_nmadd(UGeckoInstruction inst)
|
||||
@@ -301,8 +307,10 @@ void Interpreter::ps_nmadd(UGeckoInstruction inst)
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
|
||||
const double tmp0 = ForceSingle(NI_madd(a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double tmp1 = ForceSingle(NI_madd(a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const double tmp0 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double tmp1 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
|
||||
const double ps0 = std::isnan(tmp0) ? tmp0 : -tmp0;
|
||||
const double ps1 = std::isnan(tmp1) ? tmp1 : -tmp1;
|
||||
@@ -311,7 +319,7 @@ void Interpreter::ps_nmadd(UGeckoInstruction inst)
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_sum0(UGeckoInstruction inst)
|
||||
@@ -320,14 +328,14 @@ void Interpreter::ps_sum0(UGeckoInstruction inst)
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
|
||||
const double ps0 = ForceSingle(NI_add(a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||
const double ps1 = ForceSingle(c.PS1AsDouble());
|
||||
const double ps0 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||
const double ps1 = ForceSingle(FPSCR, c.PS1AsDouble());
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_sum1(UGeckoInstruction inst)
|
||||
@@ -336,14 +344,14 @@ void Interpreter::ps_sum1(UGeckoInstruction inst)
|
||||
const auto& b = rPS(inst.FB);
|
||||
const auto& c = rPS(inst.FC);
|
||||
|
||||
const double ps0 = ForceSingle(c.PS0AsDouble());
|
||||
const double ps1 = ForceSingle(NI_add(a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||
const double ps0 = ForceSingle(FPSCR, c.PS0AsDouble());
|
||||
const double ps1 = ForceSingle(FPSCR, NI_add(&FPSCR, a.PS0AsDouble(), b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps1);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_muls0(UGeckoInstruction inst)
|
||||
@@ -352,14 +360,14 @@ void Interpreter::ps_muls0(UGeckoInstruction inst)
|
||||
const auto& c = rPS(inst.FC);
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double ps0 = ForceSingle(NI_mul(a.PS0AsDouble(), c0).value);
|
||||
const double ps1 = ForceSingle(NI_mul(a.PS1AsDouble(), c0).value);
|
||||
const double ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c0).value);
|
||||
const double ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c0).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_muls1(UGeckoInstruction inst)
|
||||
@@ -368,14 +376,14 @@ void Interpreter::ps_muls1(UGeckoInstruction inst)
|
||||
const auto& c = rPS(inst.FC);
|
||||
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
const double ps0 = ForceSingle(NI_mul(a.PS0AsDouble(), c1).value);
|
||||
const double ps1 = ForceSingle(NI_mul(a.PS1AsDouble(), c1).value);
|
||||
const double ps0 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS0AsDouble(), c1).value);
|
||||
const double ps1 = ForceSingle(FPSCR, NI_mul(&FPSCR, a.PS1AsDouble(), c1).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_madds0(UGeckoInstruction inst)
|
||||
@@ -385,14 +393,16 @@ void Interpreter::ps_madds0(UGeckoInstruction inst)
|
||||
const auto& c = rPS(inst.FC);
|
||||
|
||||
const double c0 = Force25Bit(c.PS0AsDouble());
|
||||
const double ps0 = ForceSingle(NI_madd(a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(NI_madd(a.PS1AsDouble(), c0, b.PS1AsDouble()).value);
|
||||
const double ps0 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c0, b.PS0AsDouble()).value);
|
||||
const double ps1 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c0, b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_madds1(UGeckoInstruction inst)
|
||||
@@ -402,14 +412,16 @@ void Interpreter::ps_madds1(UGeckoInstruction inst)
|
||||
const auto& c = rPS(inst.FC);
|
||||
|
||||
const double c1 = Force25Bit(c.PS1AsDouble());
|
||||
const double ps0 = ForceSingle(NI_madd(a.PS0AsDouble(), c1, b.PS0AsDouble()).value);
|
||||
const double ps1 = ForceSingle(NI_madd(a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
const double ps0 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS0AsDouble(), c1, b.PS0AsDouble()).value);
|
||||
const double ps1 =
|
||||
ForceSingle(FPSCR, NI_madd(&FPSCR, a.PS1AsDouble(), c1, b.PS1AsDouble()).value);
|
||||
|
||||
rPS(inst.FD).SetBoth(ps0, ps1);
|
||||
PowerPC::UpdateFPRF(ps0);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::ps_cmpu0(UGeckoInstruction inst)
|
||||
|
||||
@@ -45,6 +45,13 @@ static void FPSCRtoFPUSettings(UReg_FPSCR fp)
|
||||
FPURoundMode::SetSIMDMode(fp.RN, fp.NI);
|
||||
}
|
||||
|
||||
static void UpdateFPSCR(UReg_FPSCR* fpscr)
|
||||
{
|
||||
fpscr->VX = (fpscr->Hex & FPSCR_VX_ANY) != 0;
|
||||
fpscr->FEX = (fpscr->VX & fpscr->VE) | (fpscr->OX & fpscr->OE) | (fpscr->UX & fpscr->UE) |
|
||||
(fpscr->ZX & fpscr->ZE) | (fpscr->XX & fpscr->XE);
|
||||
}
|
||||
|
||||
void Interpreter::mtfsb0x(UGeckoInstruction inst)
|
||||
{
|
||||
u32 b = 0x80000000 >> inst.CRBD;
|
||||
@@ -53,7 +60,7 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst)
|
||||
FPSCRtoFPUSettings(FPSCR);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
// This instruction can affect FX
|
||||
@@ -63,14 +70,14 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst)
|
||||
const u32 b = 0x80000000 >> bit;
|
||||
|
||||
if (b & FPSCR_ANY_X)
|
||||
SetFPException(b);
|
||||
SetFPException(&FPSCR, b);
|
||||
else
|
||||
FPSCR |= b;
|
||||
|
||||
FPSCRtoFPUSettings(FPSCR);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::mtfsfix(UGeckoInstruction inst)
|
||||
@@ -85,7 +92,7 @@ void Interpreter::mtfsfix(UGeckoInstruction inst)
|
||||
FPSCRtoFPUSettings(FPSCR);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::mtfsfx(UGeckoInstruction inst)
|
||||
@@ -102,7 +109,7 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
|
||||
FPSCRtoFPUSettings(FPSCR);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
void Interpreter::mcrxr(UGeckoInstruction inst)
|
||||
@@ -187,13 +194,6 @@ void Interpreter::mtmsr(UGeckoInstruction inst)
|
||||
|
||||
// Segment registers. MMU control.
|
||||
|
||||
static void SetSR(u32 index, u32 value)
|
||||
{
|
||||
DEBUG_LOG(POWERPC, "%08x: MMU: Segment register %i set to %08x", PowerPC::ppcState.pc, index,
|
||||
value);
|
||||
PowerPC::ppcState.sr[index] = value;
|
||||
}
|
||||
|
||||
void Interpreter::mtsr(UGeckoInstruction inst)
|
||||
{
|
||||
if (MSR.PR)
|
||||
@@ -204,7 +204,7 @@ void Interpreter::mtsr(UGeckoInstruction inst)
|
||||
|
||||
const u32 index = inst.SR;
|
||||
const u32 value = rGPR[inst.RS];
|
||||
SetSR(index, value);
|
||||
PowerPC::ppcState.SetSR(index, value);
|
||||
}
|
||||
|
||||
void Interpreter::mtsrin(UGeckoInstruction inst)
|
||||
@@ -217,7 +217,7 @@ void Interpreter::mtsrin(UGeckoInstruction inst)
|
||||
|
||||
const u32 index = (rGPR[inst.RB] >> 28) & 0xF;
|
||||
const u32 value = rGPR[inst.RS];
|
||||
SetSR(index, value);
|
||||
PowerPC::ppcState.SetSR(index, value);
|
||||
}
|
||||
|
||||
void Interpreter::mftb(UGeckoInstruction inst)
|
||||
@@ -525,7 +525,7 @@ void Interpreter::isync(UGeckoInstruction inst)
|
||||
|
||||
void Interpreter::mcrfs(UGeckoInstruction inst)
|
||||
{
|
||||
UpdateFPSCR();
|
||||
UpdateFPSCR(&FPSCR);
|
||||
u32 fpflags = ((FPSCR.Hex >> (4 * (7 - inst.CRFS))) & 0xF);
|
||||
switch (inst.CRFS)
|
||||
{
|
||||
@@ -562,9 +562,9 @@ void Interpreter::mffsx(UGeckoInstruction inst)
|
||||
// load from FPSCR
|
||||
// TODO(ector): grab all overflow flags etc and set them in FPSCR
|
||||
|
||||
UpdateFPSCR();
|
||||
UpdateFPSCR(&FPSCR);
|
||||
rPS(inst.FD).SetPS0(UINT64_C(0xFFF8000000000000) | FPSCR.Hex);
|
||||
|
||||
if (inst.Rc)
|
||||
Helper_UpdateCR1();
|
||||
PowerPC::ppcState.UpdateCR1();
|
||||
}
|
||||
|
||||
@@ -600,6 +600,12 @@ void CheckBreakPoints()
|
||||
}
|
||||
}
|
||||
|
||||
void PowerPCState::SetSR(u32 index, u32 value)
|
||||
{
|
||||
DEBUG_LOG(POWERPC, "%08x: MMU: Segment register %i set to %08x", pc, index, value);
|
||||
sr[index] = value;
|
||||
}
|
||||
|
||||
// FPSCR update functions
|
||||
|
||||
void UpdateFPRF(double dvalue)
|
||||
|
||||
@@ -156,6 +156,13 @@ struct PowerPCState
|
||||
u32 pagetable_hashmask;
|
||||
|
||||
InstructionCache iCache;
|
||||
|
||||
void UpdateCR1()
|
||||
{
|
||||
cr.SetField(1, (fpscr.FX << 3) | (fpscr.FEX << 2) | (fpscr.VX << 1) | fpscr.OX);
|
||||
}
|
||||
|
||||
void SetSR(u32 index, u32 value);
|
||||
};
|
||||
|
||||
#if _M_X86_64
|
||||
|
||||
Reference in New Issue
Block a user