mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
VU: SQRT's Invalid missed a negative zero the same way RSQRT's did
_vuSQRT and recCOP2_VSQRT decide it with an ordered compare against zero, which -0 passes; the negative denormals reach them already flushed to -0 and pass too. mVU_SQRT tested the sign bit and was the only one raising Invalid for either. The console raises it for all of them. The compare had a second effect on the macro side, since an unordered compare is not "greater or equal": a positive operand with exponent field 255 raised Invalid there and nowhere else.
This commit is contained in:
+3
-1
@@ -980,7 +980,9 @@ static __fi void _vuSQRT(VURegs* VU)
|
||||
|
||||
VU->statusflag &= ~0x30;
|
||||
|
||||
if (ft < 0.0)
|
||||
// Sign bit, not `ft < 0.0`: -0 raises I, and so do the denormals vuDouble
|
||||
// has already flushed to it.
|
||||
if (VU->VF[_Ft_].UL[_Ftf_] & 0x80000000)
|
||||
VU->statusflag |= 0x10;
|
||||
VU->q.F = sqrt(fabs(ft));
|
||||
VU->q.F = vuDouble(VU->q.UL);
|
||||
|
||||
@@ -2524,25 +2524,20 @@ void recCOP2_VSQRT()
|
||||
|
||||
const int ftf = _Ftf_cop2;
|
||||
|
||||
// Clear D/I flags
|
||||
// Clear D/I, then take I from the sign bit: a compare against zero misses
|
||||
// -0 and reads an unordered result as negative.
|
||||
armAsm->Ldr(RWSCRATCH, armVU0Mem(&VU0.statusflag));
|
||||
armAsm->Mov(RWARG1, 0x30); armAsm->Bic(RWSCRATCH, RWSCRATCH, RWARG1); // clear D/I bits
|
||||
armAsm->Ldr(a64::w1, armVU0Mem(&VU0.VF[_Ft_cop2].UL[ftf]));
|
||||
a64::Label ftPositive;
|
||||
armAsm->Tbz(a64::w1, 31, &ftPositive);
|
||||
armAsm->Orr(RWSCRATCH, RWSCRATCH, 0x10);
|
||||
armAsm->Bind(&ftPositive);
|
||||
armAsm->Str(RWSCRATCH, armVU0Mem(&VU0.statusflag));
|
||||
|
||||
// Load ft scalar
|
||||
armAsm->Ldr(RSSCRATCH, armVU0Mem(&VU0.VF[_Ft_cop2].UL[ftf]));
|
||||
|
||||
// If ft < 0, set invalid flag (D flag = 0x10)
|
||||
a64::Label notNeg;
|
||||
armAsm->Fcmp(RSSCRATCH, 0.0);
|
||||
armAsm->B(a64::ge, ¬Neg);
|
||||
{
|
||||
armAsm->Ldr(RWSCRATCH, armVU0Mem(&VU0.statusflag));
|
||||
armAsm->Orr(RWSCRATCH, RWSCRATCH, 0x10);
|
||||
armAsm->Str(RWSCRATCH, armVU0Mem(&VU0.statusflag));
|
||||
}
|
||||
armAsm->Bind(¬Neg);
|
||||
|
||||
// Q = sqrt(|ft|)
|
||||
armAsm->Fabs(RSSCRATCH, RSSCRATCH);
|
||||
armAsm->Fsqrt(RSSCRATCH, RSSCRATCH);
|
||||
|
||||
Reference in New Issue
Block a user