[Soft-Float] - Improves the PS2Float class by using a raw float to speed-up simple calculations.

This greatly improves performance while using Soft-Floats.
This commit is contained in:
GitHubProUser67 2024-12-07 22:38:10 +01:00
parent 8bc2ed9282
commit 745e4746fc
5 changed files with 125 additions and 161 deletions

View File

@ -146,16 +146,13 @@ bool checkDivideByZero(u32& xReg, u32 yDivisorReg, u32 zDividendReg, u32 cFlagsT
_ContVal_ |= dividendZero ? cFlagsToSet2 : cFlagsToSet1; _ContVal_ |= dividendZero ? cFlagsToSet2 : cFlagsToSet1;
bool IsSigned = yMatrix.Sign ^ zMatrix.Sign; bool IsSigned = yMatrix.Sign() ^ zMatrix.Sign();
if (dividendZero) if (dividendZero)
xReg = IsSigned ? PS2Float::MIN_FLOATING_POINT_VALUE : PS2Float::MAX_FLOATING_POINT_VALUE; xReg = IsSigned ? PS2Float::MIN_FLOATING_POINT_VALUE : PS2Float::MAX_FLOATING_POINT_VALUE;
else else
{ {
PS2Float zeroRes = PS2Float(0); xReg = PS2Float(IsSigned, 0, 0).raw;
zeroRes.Sign = IsSigned;
xReg = zeroRes.AsUInt32();
} }
return true; return true;
@ -221,28 +218,28 @@ float fpuDouble(u32 f)
static __fi u32 fpuAccurateAdd(u32 a, u32 b) static __fi u32 fpuAccurateAdd(u32 a, u32 b)
{ {
if (CHECK_FPU_SOFT_ADDSUB) return PS2Float(a).Add(PS2Float(b)).AsUInt32(); if (CHECK_FPU_SOFT_ADDSUB) return PS2Float(a).Add(PS2Float(b)).raw;
return std::bit_cast<u32>(fpuDouble(a) + fpuDouble(b)); return std::bit_cast<u32>(fpuDouble(a) + fpuDouble(b));
} }
static __fi u32 fpuAccurateSub(u32 a, u32 b) static __fi u32 fpuAccurateSub(u32 a, u32 b)
{ {
if (CHECK_FPU_SOFT_ADDSUB) return PS2Float(a).Sub(PS2Float(b)).AsUInt32(); if (CHECK_FPU_SOFT_ADDSUB) return PS2Float(a).Sub(PS2Float(b)).raw;
return std::bit_cast<u32>(fpuDouble(a) - fpuDouble(b)); return std::bit_cast<u32>(fpuDouble(a) - fpuDouble(b));
} }
static __fi u32 fpuAccurateMul(u32 a, u32 b) static __fi u32 fpuAccurateMul(u32 a, u32 b)
{ {
if (CHECK_FPU_SOFT_MULDIV) return PS2Float(a).Mul(PS2Float(b)).AsUInt32(); if (CHECK_FPU_SOFT_MULDIV) return PS2Float(a).Mul(PS2Float(b)).raw;
return std::bit_cast<u32>(fpuDouble(a) * fpuDouble(b)); return std::bit_cast<u32>(fpuDouble(a) * fpuDouble(b));
} }
static __fi u32 fpuAccurateDiv(u32 a, u32 b) static __fi u32 fpuAccurateDiv(u32 a, u32 b)
{ {
if (CHECK_FPU_SOFT_MULDIV) return PS2Float(a).Div(PS2Float(b)).AsUInt32(); if (CHECK_FPU_SOFT_MULDIV) return PS2Float(a).Div(PS2Float(b)).raw;
return std::bit_cast<u32>(fpuDouble(a) / fpuDouble(b)); return std::bit_cast<u32>(fpuDouble(a) / fpuDouble(b));
} }
@ -472,17 +469,17 @@ void RSQRT_S() {
if (value.IsDenormalized()) if (value.IsDenormalized())
{ {
_ContVal_ |= FPUflagD | FPUflagSD; _ContVal_ |= FPUflagD | FPUflagSD;
_FdValUl_ = value.Sign ? PS2Float::MIN_FLOATING_POINT_VALUE : PS2Float::MAX_FLOATING_POINT_VALUE; _FdValUl_ = value.Sign() ? PS2Float::MIN_FLOATING_POINT_VALUE : PS2Float::MAX_FLOATING_POINT_VALUE;
return; return;
} }
else if (_FtValUl_ & 0x80000000) // Ft is negative else if (_FtValUl_ & 0x80000000) // Ft is negative
{ {
_ContVal_ |= FPUflagI | FPUflagSI; _ContVal_ |= FPUflagI | FPUflagSI;
_FdValUl_ = PS2Float(_FsValUl_).Rsqrt(PS2Float(value.Abs())).AsUInt32(); _FdValUl_ = PS2Float(_FsValUl_).Rsqrt(PS2Float(value.Abs())).raw;
} }
else // Ft is positive and not zero else // Ft is positive and not zero
{ {
_FdValUl_ = PS2Float(_FsValUl_).Rsqrt(value).AsUInt32(); _FdValUl_ = PS2Float(_FsValUl_).Rsqrt(value).raw;
} }
} }
else else
@ -519,10 +516,10 @@ void SQRT_S() {
if (_FtValUl_ & 0x80000000) // If Ft is Negative if (_FtValUl_ & 0x80000000) // If Ft is Negative
{ {
_ContVal_ |= FPUflagI | FPUflagSI; _ContVal_ |= FPUflagI | FPUflagSI;
_FdValUl_ = PS2Float(value.Abs()).Sqrt().AsUInt32(); _FdValUl_ = PS2Float(value.Abs()).Sqrt().raw;
} }
else else
_FdValUl_ = value.Sqrt().AsUInt32(); // If Ft is Positive _FdValUl_ = value.Sqrt().raw; // If Ft is Positive
} }
else else
{ {

View File

@ -74,18 +74,14 @@ u64 PS2Float::MulMantissa(u32 a, u32 b)
// Float Processor // Float Processor
//**************************************************************** //****************************************************************
PS2Float::PS2Float(u32 value) PS2Float::PS2Float(u32 value) { raw = value; }
: Sign((value >> 31) & 1)
, Exponent((u8)(((value >> 23) & 0xFF)))
, Mantissa(value & 0x7FFFFF)
{
}
PS2Float::PS2Float(bool sign, u8 exponent, u32 mantissa) PS2Float::PS2Float(bool sign, u8 exponent, u32 mantissa)
: Sign(sign)
, Exponent(exponent)
, Mantissa(mantissa)
{ {
raw = 0;
raw |= (sign ? 1u : 0u) << 31;
raw |= (u32)(exponent << 23);
raw |= mantissa;
} }
PS2Float PS2Float::Max() PS2Float PS2Float::Max()
@ -108,15 +104,6 @@ PS2Float PS2Float::MinOne()
return PS2Float(MIN_ONE); return PS2Float(MIN_ONE);
} }
u32 PS2Float::AsUInt32() const
{
u32 result = 0;
result |= (Sign ? 1u : 0u) << 31;
result |= (u32)(Exponent << 23);
result |= Mantissa;
return result;
}
PS2Float PS2Float::Add(PS2Float addend) PS2Float PS2Float::Add(PS2Float addend)
{ {
if (IsDenormalized() || addend.IsDenormalized()) if (IsDenormalized() || addend.IsDenormalized())
@ -125,8 +112,8 @@ PS2Float PS2Float::Add(PS2Float addend)
if (IsAbnormal() && addend.IsAbnormal()) if (IsAbnormal() && addend.IsAbnormal())
return SolveAbnormalAdditionOrSubtractionOperation(*this, addend, true); return SolveAbnormalAdditionOrSubtractionOperation(*this, addend, true);
u32 a = AsUInt32(); u32 a = raw;
u32 b = addend.AsUInt32(); u32 b = addend.raw;
//exponent difference //exponent difference
s32 exp_diff = ((a >> 23) & 0xFF) - ((b >> 23) & 0xFF); s32 exp_diff = ((a >> 23) & 0xFF) - ((b >> 23) & 0xFF);
@ -169,8 +156,8 @@ PS2Float PS2Float::Sub(PS2Float subtrahend)
if (IsAbnormal() && subtrahend.IsAbnormal()) if (IsAbnormal() && subtrahend.IsAbnormal())
return SolveAbnormalAdditionOrSubtractionOperation(*this, subtrahend, false); return SolveAbnormalAdditionOrSubtractionOperation(*this, subtrahend, false);
u32 a = AsUInt32(); u32 a = raw;
u32 b = subtrahend.AsUInt32(); u32 b = subtrahend.raw;
//exponent difference //exponent difference
s32 exp_diff = ((a >> 23) & 0xFF) - ((b >> 23) & 0xFF); s32 exp_diff = ((a >> 23) & 0xFF) - ((b >> 23) & 0xFF);
@ -203,7 +190,7 @@ PS2Float PS2Float::Sub(PS2Float subtrahend)
} }
return PS2Float(a).DoAdd(Neg(PS2Float(b))); return PS2Float(a).DoAdd(PS2Float(b).Negate());
} }
PS2Float PS2Float::Mul(PS2Float mulend) PS2Float PS2Float::Mul(PS2Float mulend)
@ -215,12 +202,7 @@ PS2Float PS2Float::Mul(PS2Float mulend)
return SolveAbnormalMultiplicationOrDivisionOperation(*this, mulend, true); return SolveAbnormalMultiplicationOrDivisionOperation(*this, mulend, true);
if (IsZero() || mulend.IsZero()) if (IsZero() || mulend.IsZero())
{ return PS2Float(DetermineMultiplicationDivisionOperationSign(*this, mulend), 0, 0);
PS2Float result = PS2Float(0);
result.Sign = DetermineMultiplicationDivisionOperationSign(*this, mulend);
return result;
}
return DoMul(mulend); return DoMul(mulend);
} }
@ -234,12 +216,7 @@ PS2Float PS2Float::Div(PS2Float divend)
return SolveAbnormalMultiplicationOrDivisionOperation(*this, divend, false); return SolveAbnormalMultiplicationOrDivisionOperation(*this, divend, false);
if (IsZero()) if (IsZero())
{ return PS2Float(DetermineMultiplicationDivisionOperationSign(*this, divend), 0, 0);
PS2Float result = PS2Float(0);
result.Sign = DetermineMultiplicationDivisionOperationSign(*this, divend);
return result;
}
else if (divend.IsZero()) else if (divend.IsZero())
return DetermineMultiplicationDivisionOperationSign(*this, divend) ? Min() : Max(); return DetermineMultiplicationDivisionOperationSign(*this, divend) ? Min() : Max();
@ -258,7 +235,7 @@ PS2Float PS2Float::Sqrt()
return PS2Float(0); return PS2Float(0);
// PS2 only takes positive numbers for SQRT, and convert if necessary. // PS2 only takes positive numbers for SQRT, and convert if necessary.
s32 ix = (s32)(PS2Float(false, Exponent, Mantissa).AsUInt32()); s32 ix = (s32)PS2Float(false, Exponent(), Mantissa()).raw;
/* extract mantissa and unbias exponent */ /* extract mantissa and unbias exponent */
s32 m = (ix >> 23) - BIAS; s32 m = (ix >> 23) - BIAS;
@ -308,39 +285,44 @@ PS2Float PS2Float::Rsqrt(PS2Float other)
bool PS2Float::IsDenormalized() bool PS2Float::IsDenormalized()
{ {
return Exponent == 0; return Exponent() == 0;
} }
bool PS2Float::IsAbnormal() bool PS2Float::IsAbnormal()
{ {
u32 val = AsUInt32(); u32 val = raw;
return val == MAX_FLOATING_POINT_VALUE || val == MIN_FLOATING_POINT_VALUE || return val == MAX_FLOATING_POINT_VALUE || val == MIN_FLOATING_POINT_VALUE ||
val == POSITIVE_INFINITY_VALUE || val == NEGATIVE_INFINITY_VALUE; val == POSITIVE_INFINITY_VALUE || val == NEGATIVE_INFINITY_VALUE;
} }
bool PS2Float::IsZero() bool PS2Float::IsZero()
{ {
return (Abs()) == 0; return Abs() == 0;
} }
u32 PS2Float::Abs() u32 PS2Float::Abs()
{ {
return (AsUInt32() & MAX_FLOATING_POINT_VALUE); return (raw & MAX_FLOATING_POINT_VALUE);
}
PS2Float PS2Float::Negate()
{
return PS2Float(raw ^ 0x80000000);
} }
PS2Float PS2Float::RoundTowardsZero() PS2Float PS2Float::RoundTowardsZero()
{ {
return PS2Float((u32)(std::trunc((double)(AsUInt32())))); return PS2Float((u32)std::trunc((double)raw));
} }
s32 PS2Float::CompareTo(PS2Float other) s32 PS2Float::CompareTo(PS2Float other)
{ {
s32 selfTwoComplementVal = (s32)(Abs()); s32 selfTwoComplementVal = (s32)Abs();
if (Sign) if (Sign())
selfTwoComplementVal = -selfTwoComplementVal; selfTwoComplementVal = -selfTwoComplementVal;
s32 otherTwoComplementVal = (s32)(other.Abs()); s32 otherTwoComplementVal = (s32)other.Abs();
if (other.Sign) if (other.Sign())
otherTwoComplementVal = -otherTwoComplementVal; otherTwoComplementVal = -otherTwoComplementVal;
if (selfTwoComplementVal < otherTwoComplementVal) if (selfTwoComplementVal < otherTwoComplementVal)
@ -353,8 +335,8 @@ s32 PS2Float::CompareTo(PS2Float other)
s32 PS2Float::CompareOperand(PS2Float other) s32 PS2Float::CompareOperand(PS2Float other)
{ {
s32 selfTwoComplementVal = (s32)(Abs()); s32 selfTwoComplementVal = (s32)Abs();
s32 otherTwoComplementVal = (s32)(other.Abs()); s32 otherTwoComplementVal = (s32)other.Abs();
if (selfTwoComplementVal < otherTwoComplementVal) if (selfTwoComplementVal < otherTwoComplementVal)
return -1; return -1;
@ -366,14 +348,14 @@ s32 PS2Float::CompareOperand(PS2Float other)
double PS2Float::ToDouble() double PS2Float::ToDouble()
{ {
return std::bit_cast<double>(((u64)Sign << 63) | ((((u64)Exponent - BIAS) + 1023ULL) << 52) | ((u64)Mantissa << 29)); return std::bit_cast<double>(((u64)Sign() << 63) | ((((u64)Exponent() - BIAS) + 1023ULL) << 52) | ((u64)Mantissa() << 29));
} }
std::string PS2Float::ToString() std::string PS2Float::ToString()
{ {
double res = ToDouble(); double res = ToDouble();
u32 value = AsUInt32(); u32 value = raw;
std::ostringstream oss; std::ostringstream oss;
oss << std::fixed << std::setprecision(6); oss << std::fixed << std::setprecision(6);
@ -409,8 +391,8 @@ PS2Float PS2Float::DoAdd(PS2Float other)
{ {
const u8 roundingMultiplier = 6; const u8 roundingMultiplier = 6;
u8 selfExponent = Exponent; u8 selfExponent = Exponent();
s32 resExponent = selfExponent - other.Exponent; s32 resExponent = selfExponent - other.Exponent();
if (resExponent < 0) if (resExponent < 0)
return other.DoAdd(*this); return other.DoAdd(*this);
@ -418,10 +400,10 @@ PS2Float PS2Float::DoAdd(PS2Float other)
return *this; return *this;
// http://graphics.stanford.edu/~seander/bithacks.html#ConditionalNegate // http://graphics.stanford.edu/~seander/bithacks.html#ConditionalNegate
u32 sign1 = (u32)((s32)AsUInt32() >> 31); u32 sign1 = (u32)((s32)raw >> 31);
s32 selfMantissa = (s32)(((Mantissa | 0x800000) ^ sign1) - sign1); s32 selfMantissa = (s32)(((Mantissa() | 0x800000) ^ sign1) - sign1);
u32 sign2 = (u32)((s32)other.AsUInt32() >> 31); u32 sign2 = (u32)((s32)other.raw >> 31);
s32 otherMantissa = (s32)(((other.Mantissa | 0x800000) ^ sign2) - sign2); s32 otherMantissa = (s32)(((other.Mantissa() | 0x800000) ^ sign2) - sign2);
// PS2 multiply by 2 before doing the Math here. // PS2 multiply by 2 before doing the Math here.
s32 man = (selfMantissa << roundingMultiplier) + ((otherMantissa << roundingMultiplier) >> resExponent); s32 man = (selfMantissa << roundingMultiplier) + ((otherMantissa << roundingMultiplier) >> resExponent);
@ -450,11 +432,11 @@ PS2Float PS2Float::DoAdd(PS2Float other)
PS2Float PS2Float::DoMul(PS2Float other) PS2Float PS2Float::DoMul(PS2Float other)
{ {
u8 selfExponent = Exponent; u8 selfExponent = Exponent();
u8 otherExponent = other.Exponent; u8 otherExponent = other.Exponent();
u32 selfMantissa = Mantissa | 0x800000; u32 selfMantissa = Mantissa() | 0x800000;
u32 otherMantissa = other.Mantissa | 0x800000; u32 otherMantissa = other.Mantissa() | 0x800000;
u32 sign = (AsUInt32() ^ other.AsUInt32()) & SIGNMASK; u32 sign = (raw ^ other.raw) & SIGNMASK;
s32 resExponent = selfExponent + otherExponent - 127; s32 resExponent = selfExponent + otherExponent - 127;
u32 resMantissa = (u32)(MulMantissa(selfMantissa, otherMantissa) >> 23); u32 resMantissa = (u32)(MulMantissa(selfMantissa, otherMantissa) >> 23);
@ -476,25 +458,22 @@ PS2Float PS2Float::DoMul(PS2Float other)
// Rounding can be slightly off: (PS2: 0x3F800000 / 0x3F800001 = 0x3F7FFFFF | SoftFloat/IEEE754: 0x3F800000 / 0x3F800001 = 0x3F7FFFFE). // Rounding can be slightly off: (PS2: 0x3F800000 / 0x3F800001 = 0x3F7FFFFF | SoftFloat/IEEE754: 0x3F800000 / 0x3F800001 = 0x3F7FFFFE).
PS2Float PS2Float::DoDiv(PS2Float other) PS2Float PS2Float::DoDiv(PS2Float other)
{ {
bool sign = DetermineMultiplicationDivisionOperationSign(*this, other);
u32 selfMantissa = Mantissa() | 0x800000;
u32 otherMantissa = other.Mantissa() | 0x800000;
s32 resExponent = Exponent() - other.Exponent() + BIAS;
u64 selfMantissa64; u64 selfMantissa64;
u32 selfMantissa = Mantissa | 0x800000;
u32 otherMantissa = other.Mantissa | 0x800000;
s32 resExponent = Exponent - other.Exponent + BIAS;
PS2Float result = PS2Float(0);
result.Sign = DetermineMultiplicationDivisionOperationSign(*this, other);
if (resExponent > 255) if (resExponent > 255)
return result.Sign ? Min() : Max(); return sign ? Min() : Max();
else if (resExponent <= 0) else if (resExponent <= 0)
return PS2Float(result.Sign, 0, 0); return PS2Float(sign, 0, 0);
if (selfMantissa < otherMantissa) if (selfMantissa < otherMantissa)
{ {
--resExponent; --resExponent;
if (resExponent == 0) if (resExponent == 0)
return PS2Float(result.Sign, 0, 0); return PS2Float(sign, 0, 0);
selfMantissa64 = (u64)(selfMantissa) << 31; selfMantissa64 = (u64)(selfMantissa) << 31;
} }
else else
@ -503,55 +482,55 @@ PS2Float PS2Float::DoDiv(PS2Float other)
} }
u32 resMantissa = (u32)(selfMantissa64 / otherMantissa); u32 resMantissa = (u32)(selfMantissa64 / otherMantissa);
if ((resMantissa & 0x3F) == 0) if ((resMantissa & 0x3F) == 0)
resMantissa |= ((u64)(otherMantissa)*resMantissa != selfMantissa64) ? 1U : 0; resMantissa |= ((u64)(otherMantissa)*resMantissa != selfMantissa64) ? 1U : 0;
result.Exponent = (u8)(resExponent); resMantissa = (resMantissa + 0x40U) >> 7;
result.Mantissa = (resMantissa + 0x40U) >> 7;
if (result.Mantissa > 0) if (resMantissa > 0)
{ {
s32 leadingBitPosition = PS2Float::GetMostSignificantBitPosition(result.Mantissa); s32 leadingBitPosition = PS2Float::GetMostSignificantBitPosition(resMantissa);
while (leadingBitPosition != IMPLICIT_LEADING_BIT_POS) while (leadingBitPosition != IMPLICIT_LEADING_BIT_POS)
{ {
if (leadingBitPosition > IMPLICIT_LEADING_BIT_POS) if (leadingBitPosition > IMPLICIT_LEADING_BIT_POS)
{ {
result.Mantissa >>= 1; resMantissa >>= 1;
s32 exp = ((s32)result.Exponent + 1); s32 exp = resExponent + 1;
if (exp > 255) if (exp > 255)
return result.Sign ? Min() : Max(); return sign ? Min() : Max();
result.Exponent = (u8)exp; resExponent = exp;
leadingBitPosition--; leadingBitPosition--;
} }
else if (leadingBitPosition < IMPLICIT_LEADING_BIT_POS) else if (leadingBitPosition < IMPLICIT_LEADING_BIT_POS)
{ {
result.Mantissa <<= 1; resMantissa <<= 1;
s32 exp = ((s32)result.Exponent - 1); s32 exp = resExponent - 1;
if (exp <= 0) if (exp <= 0)
return PS2Float(result.Sign, 0, 0); return PS2Float(sign, 0, 0);
result.Exponent = (u8)exp; resExponent = exp;
leadingBitPosition++; leadingBitPosition++;
} }
} }
} }
result.Mantissa &= 0x7FFFFF; resMantissa &= 0x7FFFFF;
return result.RoundTowardsZero(); return PS2Float(sign, (u8)resExponent, resMantissa).RoundTowardsZero();
} }
PS2Float PS2Float::SolveAbnormalAdditionOrSubtractionOperation(PS2Float a, PS2Float b, bool add) PS2Float PS2Float::SolveAbnormalAdditionOrSubtractionOperation(PS2Float a, PS2Float b, bool add)
{ {
u32 aval = a.AsUInt32(); u32 aval = a.raw;
u32 bval = b.AsUInt32(); u32 bval = b.raw;
if (aval == MAX_FLOATING_POINT_VALUE && bval == MAX_FLOATING_POINT_VALUE) if (aval == MAX_FLOATING_POINT_VALUE && bval == MAX_FLOATING_POINT_VALUE)
return add ? Max() : PS2Float(0); return add ? Max() : PS2Float(0);
@ -608,8 +587,8 @@ PS2Float PS2Float::SolveAbnormalAdditionOrSubtractionOperation(PS2Float a, PS2Fl
PS2Float PS2Float::SolveAbnormalMultiplicationOrDivisionOperation(PS2Float a, PS2Float b, bool mul) PS2Float PS2Float::SolveAbnormalMultiplicationOrDivisionOperation(PS2Float a, PS2Float b, bool mul)
{ {
u32 aval = a.AsUInt32(); u32 aval = a.raw;
u32 bval = b.AsUInt32(); u32 bval = b.raw;
if (mul) if (mul)
{ {
@ -711,38 +690,31 @@ PS2Float PS2Float::SolveAbnormalMultiplicationOrDivisionOperation(PS2Float a, PS
PS2Float PS2Float::SolveAddSubDenormalizedOperation(PS2Float a, PS2Float b, bool add) PS2Float PS2Float::SolveAddSubDenormalizedOperation(PS2Float a, PS2Float b, bool add)
{ {
PS2Float result = PS2Float(0); bool sign = add ? DetermineAdditionOperationSign(a, b) : DetermineSubtractionOperationSign(a, b);
if (a.IsDenormalized() && !b.IsDenormalized()) if (a.IsDenormalized() && !b.IsDenormalized())
result = b; return PS2Float(sign, b.Exponent(), b.Mantissa());
else if (!a.IsDenormalized() && b.IsDenormalized()) else if (!a.IsDenormalized() && b.IsDenormalized())
result = a; return PS2Float(sign, a.Exponent(), a.Mantissa());
else if (a.IsDenormalized() && b.IsDenormalized()) else if (a.IsDenormalized() && b.IsDenormalized())
{ return PS2Float(sign, 0, 0);
}
else else
Console.Error("Both numbers are not denormalized"); Console.Error("Both numbers are not denormalized");
result.Sign = add ? DetermineAdditionOperationSign(a, b) : DetermineSubtractionOperationSign(a, b); return PS2Float(0);
return result;
} }
PS2Float PS2Float::SolveMultiplicationDenormalizedOperation(PS2Float a, PS2Float b) PS2Float PS2Float::SolveMultiplicationDenormalizedOperation(PS2Float a, PS2Float b)
{ {
PS2Float result = PS2Float(0); return PS2Float(DetermineMultiplicationDivisionOperationSign(a, b), 0, 0);
result.Sign = DetermineMultiplicationDivisionOperationSign(a, b);
return result;
} }
PS2Float PS2Float::SolveDivisionDenormalizedOperation(PS2Float a, PS2Float b) PS2Float PS2Float::SolveDivisionDenormalizedOperation(PS2Float a, PS2Float b)
{ {
bool sign = DetermineMultiplicationDivisionOperationSign(a, b); bool sign = DetermineMultiplicationDivisionOperationSign(a, b);
PS2Float result = PS2Float(0);
if (a.IsDenormalized() && !b.IsDenormalized()) if (a.IsDenormalized() && !b.IsDenormalized())
{ return PS2Float(sign, 0, 0);
}
else if (!a.IsDenormalized() && b.IsDenormalized()) else if (!a.IsDenormalized() && b.IsDenormalized())
return sign ? Min() : Max(); return sign ? Min() : Max();
else if (a.IsDenormalized() && b.IsDenormalized()) else if (a.IsDenormalized() && b.IsDenormalized())
@ -750,48 +722,42 @@ PS2Float PS2Float::SolveDivisionDenormalizedOperation(PS2Float a, PS2Float b)
else else
Console.Error("Both numbers are not denormalized"); Console.Error("Both numbers are not denormalized");
result.Sign = sign; return PS2Float(0);
return result;
}
PS2Float PS2Float::Neg(PS2Float self)
{
return PS2Float(self.AsUInt32() ^ SIGNMASK);
} }
bool PS2Float::DetermineMultiplicationDivisionOperationSign(PS2Float a, PS2Float b) bool PS2Float::DetermineMultiplicationDivisionOperationSign(PS2Float a, PS2Float b)
{ {
return a.Sign ^ b.Sign; return a.Sign() ^ b.Sign();
} }
bool PS2Float::DetermineAdditionOperationSign(PS2Float a, PS2Float b) bool PS2Float::DetermineAdditionOperationSign(PS2Float a, PS2Float b)
{ {
if (a.IsZero() && b.IsZero()) if (a.IsZero() && b.IsZero())
{ {
if (!a.Sign || !b.Sign) if (!a.Sign() || !b.Sign())
return false; return false;
else if (a.Sign && b.Sign) else if (a.Sign() && b.Sign())
return true; return true;
else else
Console.Error("Unhandled addition operation flags"); Console.Error("Unhandled addition operation flags");
} }
return a.CompareOperand(b) >= 0 ? a.Sign : b.Sign; return a.CompareOperand(b) >= 0 ? a.Sign() : b.Sign();
} }
bool PS2Float::DetermineSubtractionOperationSign(PS2Float a, PS2Float b) bool PS2Float::DetermineSubtractionOperationSign(PS2Float a, PS2Float b)
{ {
if (a.IsZero() && b.IsZero()) if (a.IsZero() && b.IsZero())
{ {
if (!a.Sign || b.Sign) if (!a.Sign() || b.Sign())
return false; return false;
else if (a.Sign && !b.Sign) else if (a.Sign() && !b.Sign())
return true; return true;
else else
Console.Error("Unhandled subtraction operation flags"); Console.Error("Unhandled subtraction operation flags");
} }
return a.CompareOperand(b) >= 0 ? a.Sign : !b.Sign; return a.CompareOperand(b) >= 0 ? a.Sign() : !b.Sign();
} }
s32 PS2Float::clz(s32 x) s32 PS2Float::clz(s32 x)

View File

@ -26,9 +26,6 @@ class PS2Float
static AddResult Add3(u32 a, u32 b, u32 c); static AddResult Add3(u32 a, u32 b, u32 c);
public: public:
bool Sign;
u8 Exponent;
u32 Mantissa;
static constexpr u8 BIAS = 127; static constexpr u8 BIAS = 127;
static constexpr u32 SIGNMASK = 0x80000000; static constexpr u32 SIGNMASK = 0x80000000;
@ -62,6 +59,12 @@ public:
0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24
}; };
u32 raw;
constexpr u32 Mantissa() const { return raw & 0x7FFFFF; }
constexpr u8 Exponent() const { return (raw >> 23) & 0xFF; }
constexpr bool Sign() const { return ((raw >> 31) & 1) != 0; }
PS2Float(u32 value); PS2Float(u32 value);
PS2Float(bool sign, u8 exponent, u32 mantissa); PS2Float(bool sign, u8 exponent, u32 mantissa);
@ -74,10 +77,6 @@ public:
static PS2Float MinOne(); static PS2Float MinOne();
static PS2Float Neg(PS2Float self);
u32 AsUInt32() const;
PS2Float Add(PS2Float addend); PS2Float Add(PS2Float addend);
PS2Float Sub(PS2Float subtrahend); PS2Float Sub(PS2Float subtrahend);
@ -98,6 +97,8 @@ public:
u32 Abs(); u32 Abs();
PS2Float Negate();
PS2Float RoundTowardsZero(); PS2Float RoundTowardsZero();
s32 CompareTo(PS2Float other); s32 CompareTo(PS2Float other);

View File

@ -16,8 +16,8 @@ static __ri u32 VU_MAC_UPDATE(int shift, VURegs* VU, u32 f)
{ {
PS2Float ps2f = PS2Float(f); PS2Float ps2f = PS2Float(f);
u32 exp = ps2f.Exponent; u32 exp = ps2f.Exponent();
u32 s = ps2f.AsUInt32() & PS2Float::SIGNMASK; u32 s = ps2f.raw & PS2Float::SIGNMASK;
if (s) if (s)
VU->macflag |= 0x0010<<shift; VU->macflag |= 0x0010<<shift;

View File

@ -465,28 +465,28 @@ static __fi float vuDouble(u32 f)
static __fi u32 vuAccurateAdd(VURegs* VU, u32 a, u32 b) static __fi u32 vuAccurateAdd(VURegs* VU, u32 a, u32 b)
{ {
if (CHECK_VU_SOFT_ADDSUB((VU == &VU1) ? 1 : 0)) return PS2Float(a).Add(PS2Float(b)).AsUInt32(); if (CHECK_VU_SOFT_ADDSUB((VU == &VU1) ? 1 : 0)) return PS2Float(a).Add(PS2Float(b)).raw;
return std::bit_cast<u32>(vuDouble(a) + vuDouble(b)); return std::bit_cast<u32>(vuDouble(a) + vuDouble(b));
} }
static __fi u32 vuAccurateSub(VURegs* VU, u32 a, u32 b) static __fi u32 vuAccurateSub(VURegs* VU, u32 a, u32 b)
{ {
if (CHECK_VU_SOFT_ADDSUB((VU == &VU1) ? 1 : 0)) return PS2Float(a).Sub(PS2Float(b)).AsUInt32(); if (CHECK_VU_SOFT_ADDSUB((VU == &VU1) ? 1 : 0)) return PS2Float(a).Sub(PS2Float(b)).raw;
return std::bit_cast<u32>(vuDouble(a) - vuDouble(b)); return std::bit_cast<u32>(vuDouble(a) - vuDouble(b));
} }
static __fi u32 vuAccurateMul(VURegs* VU, u32 a, u32 b) static __fi u32 vuAccurateMul(VURegs* VU, u32 a, u32 b)
{ {
if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0)) return PS2Float(a).Mul(PS2Float(b)).AsUInt32(); if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0)) return PS2Float(a).Mul(PS2Float(b)).raw;
return std::bit_cast<u32>(vuDouble(a) * vuDouble(b)); return std::bit_cast<u32>(vuDouble(a) * vuDouble(b));
} }
static __fi u32 vuAccurateDiv(VURegs* VU, u32 a, u32 b) static __fi u32 vuAccurateDiv(VURegs* VU, u32 a, u32 b)
{ {
if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0)) return PS2Float(a).Div(PS2Float(b)).AsUInt32(); if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0)) return PS2Float(a).Div(PS2Float(b)).raw;
return std::bit_cast<u32>(vuDouble(a) / vuDouble(b)); return std::bit_cast<u32>(vuDouble(a) / vuDouble(b));
} }
@ -1778,7 +1778,7 @@ static __fi void _vuDIV(VURegs* VU)
} }
else else
{ {
VU->q.UL = fs.Div(ft).AsUInt32(); VU->q.UL = fs.Div(ft).raw;
} }
} }
else else
@ -1819,7 +1819,7 @@ static __fi void _vuSQRT(VURegs* VU)
if (ft.ToDouble() < 0.0) if (ft.ToDouble() < 0.0)
VU->statusflag |= 0x10; VU->statusflag |= 0x10;
VU->q.UL = PS2Float(ft.Abs()).Sqrt().AsUInt32(); VU->q.UL = PS2Float(ft.Abs()).Sqrt().raw;
} }
else else
{ {
@ -1874,11 +1874,11 @@ static __fi void _vuRSQRT(VURegs* VU)
} }
if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0)) if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0))
VU->q.UL = fs.Div(PS2Float(ft.Abs()).Sqrt()).AsUInt32(); VU->q.UL = fs.Div(PS2Float(ft.Abs()).Sqrt()).raw;
else else
{ {
float temp = sqrt(fabs(vuDouble(ft.AsUInt32()))); float temp = sqrt(fabs(vuDouble(ft.raw)));
VU->q.F = vuDouble(fs.AsUInt32()) / temp; VU->q.F = vuDouble(fs.raw) / temp;
VU->q.F = vuDouble(VU->q.UL); VU->q.F = vuDouble(VU->q.UL);
} }
} }
@ -2589,12 +2589,12 @@ static __ri void _vuERSADD(VURegs* VU)
p = PS2Float::One().Div(p); p = PS2Float::One().Div(p);
else else
{ {
VU->p.F = 1.0f / vuDouble(p.AsUInt32()); VU->p.F = 1.0f / vuDouble(p.raw);
return; return;
} }
} }
VU->p.UL = p.AsUInt32(); VU->p.UL = p.raw;
} }
static __ri void _vuELENG(VURegs* VU) static __ri void _vuELENG(VURegs* VU)
@ -2611,11 +2611,11 @@ static __ri void _vuELENG(VURegs* VU)
{ {
value = value.Sqrt(); value = value.Sqrt();
} }
VU->p.UL = value.AsUInt32(); VU->p.UL = value.raw;
} }
else else
{ {
float p = vuDouble(value.AsUInt32()); float p = vuDouble(value.raw);
if (p >= 0) if (p >= 0)
{ {
@ -2646,16 +2646,16 @@ static __ri void _vuERLENG(VURegs* VU)
} }
else else
{ {
VU->p.F = 1.0 / vuDouble(value.AsUInt32()); VU->p.F = 1.0 / vuDouble(value.raw);
return; return;
} }
} }
} }
VU->p.UL = value.AsUInt32(); VU->p.UL = value.raw;
} }
else else
{ {
float p = vuDouble(value.AsUInt32()); float p = vuDouble(value.raw);
if (p >= 0) if (p >= 0)
{ {
@ -2731,12 +2731,12 @@ static __ri void _vuERCPR(VURegs* VU)
} }
else else
{ {
VU->p.F = 1.0 / vuDouble(p.AsUInt32()); VU->p.F = 1.0 / vuDouble(p.raw);
return; return;
} }
} }
VU->p.UL = p.AsUInt32(); VU->p.UL = p.raw;
} }
static __ri void _vuESQRT(VURegs* VU) static __ri void _vuESQRT(VURegs* VU)
@ -2750,7 +2750,7 @@ static __ri void _vuESQRT(VURegs* VU)
value = value.Sqrt(); value = value.Sqrt();
} }
VU->p.UL = value.AsUInt32(); VU->p.UL = value.raw;
} }
else else
{ {
@ -2778,7 +2778,7 @@ static __ri void _vuERSQRT(VURegs* VU)
{ {
if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0)) if (CHECK_VU_SOFT_MULDIV((VU == &VU1) ? 1 : 0))
{ {
VU->p.F = 1.0f / vuDouble(value.AsUInt32()); VU->p.F = 1.0f / vuDouble(value.raw);
return; return;
} }
else else
@ -2788,7 +2788,7 @@ static __ri void _vuERSQRT(VURegs* VU)
} }
} }
VU->p.UL = value.AsUInt32(); VU->p.UL = value.raw;
} }
else else
{ {