PPCInterpreter: Improve overflow handling

This commit is contained in:
Exzap 2023-01-26 10:05:38 +01:00
parent 4b5014c16a
commit 43b5ad2f1c

View File

@ -14,7 +14,6 @@ static void PPCInterpreter_setXerOV(PPCInterpreter_t* hCPU, bool hasOverflow)
static bool checkAdditionOverflow(uint32 x, uint32 y, uint32 r) static bool checkAdditionOverflow(uint32 x, uint32 y, uint32 r)
{ {
// todo - update remaining *O instructions to use this function
/* /*
x y r result (has overflow) x y r result (has overflow)
@ -44,17 +43,9 @@ static void PPCInterpreter_ADDO(PPCInterpreter_t* hCPU, uint32 opcode)
{ {
// untested (Don't Starve Giant Edition uses this instruction + BSO) // untested (Don't Starve Giant Edition uses this instruction + BSO)
PPC_OPC_TEMPL3_XO(); PPC_OPC_TEMPL3_XO();
uint64 result = (uint64)hCPU->gpr[rA] + (uint64)hCPU->gpr[rB]; uint32 result = hCPU->gpr[rA] + hCPU->gpr[rB];
PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(hCPU->gpr[rA], hCPU->gpr[rB], result));
hCPU->gpr[rD] = (uint32)result; hCPU->gpr[rD] = (uint32)result;
if (result >= 0x100000000ULL)
{
hCPU->spr.XER |= XER_SO;
hCPU->spr.XER |= XER_OV;
}
else
{
hCPU->spr.XER &= ~XER_OV;
}
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
@ -85,13 +76,7 @@ static void PPCInterpreter_ADDCO(PPCInterpreter_t* hCPU, uint32 opcode)
else else
hCPU->xer_ca = 0; hCPU->xer_ca = 0;
// set SO/OV // set SO/OV
if (hCPU->gpr[rD] < a) PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, b, hCPU->gpr[rD]));
{
hCPU->spr.XER |= XER_OV;
hCPU->spr.XER |= XER_SO;
}
else
hCPU->spr.XER &= ~XER_OV;
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
@ -266,15 +251,7 @@ static void PPCInterpreter_SUBFCO(PPCInterpreter_t* hCPU, uint32 opcode)
else else
hCPU->xer_ca = 0; hCPU->xer_ca = 0;
// update xer SO/OV // update xer SO/OV
if (checkAdditionOverflow(~a, b, hCPU->gpr[rD])) PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, hCPU->gpr[rD]));
{
hCPU->spr.XER |= XER_SO;
hCPU->spr.XER |= XER_OV;
}
else
{
hCPU->spr.XER &= ~XER_OV;
}
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
@ -325,15 +302,7 @@ static void PPCInterpreter_SUBFEO(PPCInterpreter_t* hCPU, uint32 opcode)
hCPU->xer_ca = 1; hCPU->xer_ca = 1;
else else
hCPU->xer_ca = 0; hCPU->xer_ca = 0;
if (checkAdditionOverflow(~a, b, result)) PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, result));
{
hCPU->spr.XER |= XER_SO;
hCPU->spr.XER |= XER_OV;
}
else
{
hCPU->spr.XER &= ~XER_OV;
}
// update cr0 // update cr0
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);
@ -419,17 +388,9 @@ static void PPCInterpreter_MULLWO(PPCInterpreter_t* hCPU, uint32 opcode)
// Don't Starve Giant Edition uses this instruction + BSO // Don't Starve Giant Edition uses this instruction + BSO
// also used by FullBlast when a save file exists + it uses mfxer to access overflow result // also used by FullBlast when a save file exists + it uses mfxer to access overflow result
PPC_OPC_TEMPL3_XO(); PPC_OPC_TEMPL3_XO();
sint64 result = (sint64)hCPU->gpr[rA] * (sint64)hCPU->gpr[rB]; sint64 result = (sint64)(sint32)hCPU->gpr[rA] * (sint64)(sint32)hCPU->gpr[rB];
hCPU->gpr[rD] = (uint32)result; hCPU->gpr[rD] = (uint32)result;
if (result < -0x80000000ll || result > 0x7FFFFFFFLL) PPCInterpreter_setXerOV(hCPU, result < -0x80000000ll || result > 0x7FFFFFFFLL);
{
hCPU->spr.XER |= XER_SO;
hCPU->spr.XER |= XER_OV;
}
else
{
hCPU->spr.XER &= ~XER_OV;
}
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
@ -467,15 +428,12 @@ static void PPCInterpreter_DIVWO(PPCInterpreter_t* hCPU, uint32 opcode)
sint32 b = hCPU->gpr[rB]; sint32 b = hCPU->gpr[rB];
if (b == 0) if (b == 0)
{ {
if (opcode & PPC_OPC_OE) PPCInterpreter_setXerOV(hCPU, true);
hCPU->spr.XER |= XER_OV;
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
return; return;
} }
hCPU->gpr[rD] = a / b; hCPU->gpr[rD] = a / b;
if (opcode & PPC_OPC_OE) PPCInterpreter_setXerOV(hCPU, false);
hCPU->spr.XER &= ~XER_OV;
// todo: Handle SO
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
@ -500,15 +458,12 @@ static void PPCInterpreter_DIVWUO(PPCInterpreter_t* hCPU, uint32 opcode)
PPC_OPC_TEMPL3_XO(); PPC_OPC_TEMPL3_XO();
if (hCPU->gpr[rB] == 0) if (hCPU->gpr[rB] == 0)
{ {
if (opcode & PPC_OPC_OE) PPCInterpreter_setXerOV(hCPU, true);
hCPU->spr.XER |= XER_OV;
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
return; return;
} }
hCPU->gpr[rD] = hCPU->gpr[rA] / hCPU->gpr[rB]; hCPU->gpr[rD] = hCPU->gpr[rA] / hCPU->gpr[rB];
if (opcode & PPC_OPC_OE) PPCInterpreter_setXerOV(hCPU, false);
hCPU->spr.XER &= ~XER_OV;
// todo: Handle SO
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);
PPCInterpreter_nextInstruction(hCPU); PPCInterpreter_nextInstruction(hCPU);
@ -577,15 +532,7 @@ static void PPCInterpreter_NEGO(PPCInterpreter_t* hCPU, uint32 opcode)
{ {
PPC_OPC_TEMPL3_XO(); PPC_OPC_TEMPL3_XO();
PPC_ASSERT(rB == 0); PPC_ASSERT(rB == 0);
if (hCPU->gpr[rA] == 0x80000000) PPCInterpreter_setXerOV(hCPU, hCPU->gpr[rA] == 0x80000000);
{
hCPU->spr.XER |= XER_SO;
hCPU->spr.XER |= XER_OV;
}
else
{
hCPU->spr.XER &= ~XER_OV;
}
hCPU->gpr[rD] = (uint32)-((sint32)hCPU->gpr[rA]); hCPU->gpr[rD] = (uint32)-((sint32)hCPU->gpr[rA]);
if (opHasRC()) if (opHasRC())
ppc_update_cr0(hCPU, hCPU->gpr[rD]); ppc_update_cr0(hCPU, hCPU->gpr[rD]);