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:
pstef
2026-08-09 11:21:33 +02:00
parent cecdf52737
commit 7413241b9f
2 changed files with 10 additions and 13 deletions
+3 -1
View File
@@ -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);
+7 -12
View File
@@ -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, &notNeg);
{
armAsm->Ldr(RWSCRATCH, armVU0Mem(&VU0.statusflag));
armAsm->Orr(RWSCRATCH, RWSCRATCH, 0x10);
armAsm->Str(RWSCRATCH, armVU0Mem(&VU0.statusflag));
}
armAsm->Bind(&notNeg);
// Q = sqrt(|ft|)
armAsm->Fabs(RSSCRATCH, RSSCRATCH);
armAsm->Fsqrt(RSSCRATCH, RSSCRATCH);