Debug: Detect bad COP2 DIV Unit Timing in Devel Builds

This commit is contained in:
refractionpcsx2 2021-07-12 20:45:50 +01:00
parent 1f0f584397
commit 14be2649cf
1 changed files with 67 additions and 0 deletions

View File

@ -1160,6 +1160,49 @@ int cop2flags(u32 code)
}
return 3;
}
int COP2DivUnitTimings(u32 code)
{
switch (code & 0x3FF)
{
case 0x3BC: // DIV
case 0x3BD: // SQRT
return 7;
case 0x3BE: // RSQRT
return 13;
default:
return 0; // Used mainly for WAITQ
}
}
bool COP2IsQOP(u32 code)
{
if(_Opcode_ != 022) // Not COP2 operation
return false;
if ((code & 0x3f) == 0x20) // VADDq
return true;
if ((code & 0x3f) == 0x21) // VMADDq
return true;
if ((code & 0x3f) == 0x24) // VSUBq
return true;
if ((code & 0x3f) == 0x25) // VMSUBq
return true;
if ((code & 0x3f) == 0x1C) // VMULq
return true;
if ((code & 0x7FF) == 0x1FC) // VMULAq
return true;
if ((code & 0x7FF) == 0x23C) // VADDAq
return true;
if ((code & 0x7FF) == 0x23D) // VMADDAq
return true;
if ((code & 0x7FF) == 0x27C) // VSUBAq
return true;
if ((code & 0x7FF) == 0x27D) // VMSUBAq
return true;
return false;
}
#endif
@ -1449,6 +1492,30 @@ void recompileNextInstruction(int delayslot)
; // TODO
else if (_Rs_ == 6) // CTC2
; // TODO
else if ((cpuRegs.code & 0x7FC) == 0x3BC) // DIV/RSQRT/SQRT/WAITQ
{
int cycles = COP2DivUnitTimings(cpuRegs.code);
for (u32 p = pc; cycles > 0 && p < s_nEndBlock; p += 4, cycles--)
{
cpuRegs.code = memRead32(p);
if((_Opcode_ == 022) && (cpuRegs.code & 0x7FC) == 0x3BC) // WaitQ or another DIV op hit (stalled), we're safe
break;
else if (COP2IsQOP(cpuRegs.code))
{
std::string disasm;
DevCon.Warning("Possible incorrect Q value used in COP2");
for (u32 i = s_pCurBlockEx->startpc; i < s_nEndBlock; i += 4)
{
disasm = "";
disR5900Fasm(disasm, memRead32(i), i, false);
DevCon.Warning("%x %s%08X %s", i, i == pc - 4 ? "*" : i == p ? "=" : " ", memRead32(i), disasm.c_str());
}
break;
}
}
}
else
{
int s = cop2flags(cpuRegs.code);