mirror of
https://github.com/cemu-project/Cemu.git
synced 2024-11-25 18:46:55 +01:00
PPCInterpreter: Improve overflow handling
This commit is contained in:
parent
4b5014c16a
commit
43b5ad2f1c
@ -14,7 +14,6 @@ static void PPCInterpreter_setXerOV(PPCInterpreter_t* hCPU, bool hasOverflow)
|
||||
|
||||
static bool checkAdditionOverflow(uint32 x, uint32 y, uint32 r)
|
||||
{
|
||||
// todo - update remaining *O instructions to use this function
|
||||
|
||||
/*
|
||||
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)
|
||||
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;
|
||||
if (result >= 0x100000000ULL)
|
||||
{
|
||||
hCPU->spr.XER |= XER_SO;
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
}
|
||||
else
|
||||
{
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
}
|
||||
if (opHasRC())
|
||||
ppc_update_cr0(hCPU, hCPU->gpr[rD]);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
@ -85,13 +76,7 @@ static void PPCInterpreter_ADDCO(PPCInterpreter_t* hCPU, uint32 opcode)
|
||||
else
|
||||
hCPU->xer_ca = 0;
|
||||
// set SO/OV
|
||||
if (hCPU->gpr[rD] < a)
|
||||
{
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
hCPU->spr.XER |= XER_SO;
|
||||
}
|
||||
else
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(a, b, hCPU->gpr[rD]));
|
||||
if (opHasRC())
|
||||
ppc_update_cr0(hCPU, hCPU->gpr[rD]);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
@ -266,15 +251,7 @@ static void PPCInterpreter_SUBFCO(PPCInterpreter_t* hCPU, uint32 opcode)
|
||||
else
|
||||
hCPU->xer_ca = 0;
|
||||
// update xer SO/OV
|
||||
if (checkAdditionOverflow(~a, b, hCPU->gpr[rD]))
|
||||
{
|
||||
hCPU->spr.XER |= XER_SO;
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
}
|
||||
else
|
||||
{
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
}
|
||||
PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, hCPU->gpr[rD]));
|
||||
if (opHasRC())
|
||||
ppc_update_cr0(hCPU, hCPU->gpr[rD]);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
@ -325,15 +302,7 @@ static void PPCInterpreter_SUBFEO(PPCInterpreter_t* hCPU, uint32 opcode)
|
||||
hCPU->xer_ca = 1;
|
||||
else
|
||||
hCPU->xer_ca = 0;
|
||||
if (checkAdditionOverflow(~a, b, result))
|
||||
{
|
||||
hCPU->spr.XER |= XER_SO;
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
}
|
||||
else
|
||||
{
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
}
|
||||
PPCInterpreter_setXerOV(hCPU, checkAdditionOverflow(~a, b, result));
|
||||
// update cr0
|
||||
if (opHasRC())
|
||||
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
|
||||
// also used by FullBlast when a save file exists + it uses mfxer to access overflow result
|
||||
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;
|
||||
if (result < -0x80000000ll || result > 0x7FFFFFFFLL)
|
||||
{
|
||||
hCPU->spr.XER |= XER_SO;
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
}
|
||||
else
|
||||
{
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
}
|
||||
PPCInterpreter_setXerOV(hCPU, result < -0x80000000ll || result > 0x7FFFFFFFLL);
|
||||
if (opHasRC())
|
||||
ppc_update_cr0(hCPU, hCPU->gpr[rD]);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
@ -467,15 +428,12 @@ static void PPCInterpreter_DIVWO(PPCInterpreter_t* hCPU, uint32 opcode)
|
||||
sint32 b = hCPU->gpr[rB];
|
||||
if (b == 0)
|
||||
{
|
||||
if (opcode & PPC_OPC_OE)
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
PPCInterpreter_setXerOV(hCPU, true);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
return;
|
||||
}
|
||||
hCPU->gpr[rD] = a / b;
|
||||
if (opcode & PPC_OPC_OE)
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
// todo: Handle SO
|
||||
PPCInterpreter_setXerOV(hCPU, false);
|
||||
if (opHasRC())
|
||||
ppc_update_cr0(hCPU, hCPU->gpr[rD]);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
@ -500,15 +458,12 @@ static void PPCInterpreter_DIVWUO(PPCInterpreter_t* hCPU, uint32 opcode)
|
||||
PPC_OPC_TEMPL3_XO();
|
||||
if (hCPU->gpr[rB] == 0)
|
||||
{
|
||||
if (opcode & PPC_OPC_OE)
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
PPCInterpreter_setXerOV(hCPU, true);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
return;
|
||||
}
|
||||
hCPU->gpr[rD] = hCPU->gpr[rA] / hCPU->gpr[rB];
|
||||
if (opcode & PPC_OPC_OE)
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
// todo: Handle SO
|
||||
PPCInterpreter_setXerOV(hCPU, false);
|
||||
if (opHasRC())
|
||||
ppc_update_cr0(hCPU, hCPU->gpr[rD]);
|
||||
PPCInterpreter_nextInstruction(hCPU);
|
||||
@ -577,15 +532,7 @@ static void PPCInterpreter_NEGO(PPCInterpreter_t* hCPU, uint32 opcode)
|
||||
{
|
||||
PPC_OPC_TEMPL3_XO();
|
||||
PPC_ASSERT(rB == 0);
|
||||
if (hCPU->gpr[rA] == 0x80000000)
|
||||
{
|
||||
hCPU->spr.XER |= XER_SO;
|
||||
hCPU->spr.XER |= XER_OV;
|
||||
}
|
||||
else
|
||||
{
|
||||
hCPU->spr.XER &= ~XER_OV;
|
||||
}
|
||||
PPCInterpreter_setXerOV(hCPU, hCPU->gpr[rA] == 0x80000000);
|
||||
hCPU->gpr[rD] = (uint32)-((sint32)hCPU->gpr[rA]);
|
||||
if (opHasRC())
|
||||
ppc_update_cr0(hCPU, hCPU->gpr[rD]);
|
||||
|
Loading…
Reference in New Issue
Block a user