mirror of https://github.com/PCSX2/pcsx2.git
iop: fix division handling based on the EE div operator
Division will now handle properly division by 0 and signed overflow
This commit is contained in:
parent
11f59ada16
commit
b21ce8c9fb
|
@ -506,114 +506,71 @@ void rpsxDIV_const()
|
||||||
*/
|
*/
|
||||||
// Of course x86 cpu does overflow !
|
// Of course x86 cpu does overflow !
|
||||||
if (g_psxConstRegs[_Rs_] == 0x80000000u && g_psxConstRegs[_Rt_] == 0xFFFFFFFFu) {
|
if (g_psxConstRegs[_Rs_] == 0x80000000u && g_psxConstRegs[_Rt_] == 0xFFFFFFFFu) {
|
||||||
// FIXME depends if div/divu
|
|
||||||
xMOV(ptr32[&psxRegs.GPR.n.hi], 0);
|
xMOV(ptr32[&psxRegs.GPR.n.hi], 0);
|
||||||
xMOV(ptr32[&psxRegs.GPR.n.lo], 0x80000000);
|
xMOV(ptr32[&psxRegs.GPR.n.lo], 0x80000000);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_psxConstRegs[_Rt_] == 0) {
|
|
||||||
// FIXME
|
|
||||||
// hi must be rs
|
|
||||||
// lo must be 0xFFFF_FFFFF is rs >= 0, 0x1 otherwise if rs < 0 and sign
|
|
||||||
}
|
|
||||||
|
|
||||||
if (g_psxConstRegs[_Rt_] != 0) {
|
if (g_psxConstRegs[_Rt_] != 0) {
|
||||||
lo = *(int*)&g_psxConstRegs[_Rs_] / *(int*)&g_psxConstRegs[_Rt_];
|
lo = *(int*)&g_psxConstRegs[_Rs_] / *(int*)&g_psxConstRegs[_Rt_];
|
||||||
hi = *(int*)&g_psxConstRegs[_Rs_] % *(int*)&g_psxConstRegs[_Rt_];
|
hi = *(int*)&g_psxConstRegs[_Rs_] % *(int*)&g_psxConstRegs[_Rt_];
|
||||||
xMOV(ptr32[&psxRegs.GPR.n.hi], hi);
|
xMOV(ptr32[&psxRegs.GPR.n.hi], hi);
|
||||||
xMOV(ptr32[&psxRegs.GPR.n.lo], lo);
|
xMOV(ptr32[&psxRegs.GPR.n.lo], lo);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpsxDIVsuperconsts(int info, int sign)
|
|
||||||
{
|
|
||||||
u32 imm = g_psxConstRegs[_Rs_];
|
|
||||||
|
|
||||||
if (imm == 0x80000000u) {
|
|
||||||
// FIXME if RT is 0xFFFFFFFFu
|
|
||||||
// hi must be 0
|
|
||||||
// lo must be 0x80000000
|
|
||||||
// FIXME depends if div/divu
|
|
||||||
//
|
|
||||||
// Otherwise standard division
|
|
||||||
}
|
|
||||||
|
|
||||||
if( imm ) {
|
|
||||||
// Lo/Hi = Rs / Rt (signed)
|
|
||||||
xMOV(ecx, ptr[&psxRegs.GPR.r[_Rt_]]);
|
|
||||||
xCMP(ecx, 0);
|
|
||||||
j8Ptr[0] = JE8(0);
|
|
||||||
xMOV(eax, imm);
|
|
||||||
|
|
||||||
|
|
||||||
if( sign ) {
|
|
||||||
xCDQ();
|
|
||||||
xDIV(ecx);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
xXOR(edx, edx);
|
|
||||||
xUDIV(ecx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
xMOV(ptr[&psxRegs.GPR.n.lo], eax);
|
|
||||||
xMOV(ptr[&psxRegs.GPR.n.hi], edx);
|
|
||||||
x86SetJ8(j8Ptr[0]);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
xXOR(eax, eax);
|
|
||||||
xMOV(ptr[&psxRegs.GPR.n.hi], eax);
|
|
||||||
xMOV(ptr[&psxRegs.GPR.n.lo], eax);
|
|
||||||
// FIXME lo must be 0xFFFF_FFFFF if rt is 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rpsxDIVsuperconstt(int info, int sign)
|
|
||||||
{
|
|
||||||
u32 imm = g_psxConstRegs[_Rt_];
|
|
||||||
|
|
||||||
if (imm == 0xFFFFFFFFu) {
|
|
||||||
// FIXME if RS is 0x80000000
|
|
||||||
// hi must be 0
|
|
||||||
// lo must be 0x80000000
|
|
||||||
// FIXME depends if div/divu
|
|
||||||
//
|
|
||||||
// Otherwise standard division
|
|
||||||
}
|
|
||||||
|
|
||||||
if( imm ) {
|
|
||||||
xMOV(eax, ptr[&psxRegs.GPR.r[_Rs_]]);
|
|
||||||
xMOV(ecx, imm);
|
|
||||||
//xCDQ();
|
|
||||||
|
|
||||||
if( sign ) {
|
|
||||||
xCDQ();
|
|
||||||
xDIV(ecx);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
xXOR(edx, edx);
|
|
||||||
xUDIV(ecx);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
xMOV(ptr[&psxRegs.GPR.n.lo], eax);
|
|
||||||
xMOV(ptr[&psxRegs.GPR.n.hi], edx);
|
|
||||||
} else {
|
} else {
|
||||||
// FIXME
|
xMOV(ptr32[&psxRegs.GPR.n.hi], g_psxConstRegs[_Rs_]);
|
||||||
// hi must be rs
|
if (g_psxConstRegs[_Rs_] & 0x80000000u) {
|
||||||
// lo must be 0xFFFF_FFFFF is rs >= 0, 0x1 otherwise if rs < 0 and sign
|
xMOV(ptr32[&psxRegs.GPR.n.lo], 0x1);
|
||||||
|
} else {
|
||||||
|
xMOV(ptr32[&psxRegs.GPR.n.lo], 0xFFFFFFFFu);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpsxDIVsuper(int info, int sign)
|
void rpsxDIVsuper(int info, int sign, int process = 0)
|
||||||
{
|
{
|
||||||
// Lo/Hi = Rs / Rt (signed)
|
// Lo/Hi = Rs / Rt (signed)
|
||||||
xMOV(ecx, ptr[&psxRegs.GPR.r[_Rt_]]);
|
if( process & PROCESS_CONSTT )
|
||||||
xCMP(ecx, 0);
|
xMOV(ecx, g_psxConstRegs[_Rt_]);
|
||||||
j8Ptr[0] = JE8(0);
|
else
|
||||||
xMOV(eax, ptr[&psxRegs.GPR.r[_Rs_]]);
|
xMOV(ecx, ptr[&psxRegs.GPR.r[_Rt_]]);
|
||||||
|
|
||||||
|
if( process & PROCESS_CONSTS )
|
||||||
|
xMOV(eax, g_psxConstRegs[_Rs_]);
|
||||||
|
else
|
||||||
|
xMOV(eax, ptr[&psxRegs.GPR.r[_Rs_]]);
|
||||||
|
|
||||||
|
u8 *end1;
|
||||||
|
if (sign) //test for overflow (x86 will just throw an exception)
|
||||||
|
{
|
||||||
|
xCMP(eax, 0x80000000 );
|
||||||
|
u8 *cont1 = JNE8(0);
|
||||||
|
xCMP(ecx, 0xffffffff );
|
||||||
|
u8 *cont2 = JNE8(0);
|
||||||
|
//overflow case:
|
||||||
|
xXOR(edx, edx); //EAX remains 0x80000000
|
||||||
|
end1 = JMP8(0);
|
||||||
|
|
||||||
|
x86SetJ8(cont1);
|
||||||
|
x86SetJ8(cont2);
|
||||||
|
}
|
||||||
|
|
||||||
|
xCMP(ecx, 0 );
|
||||||
|
u8 *cont3 = JNE8(0);
|
||||||
|
|
||||||
|
//divide by zero
|
||||||
|
xMOV(edx, eax);
|
||||||
|
if (sign) //set EAX to (EAX < 0)?1:-1
|
||||||
|
{
|
||||||
|
xSAR(eax, 31 ); //(EAX < 0)?-1:0
|
||||||
|
xSHL(eax, 1 ); //(EAX < 0)?-2:0
|
||||||
|
xNOT(eax); //(EAX < 0)?1:-1
|
||||||
|
}
|
||||||
|
else
|
||||||
|
xMOV(eax, 0xffffffff );
|
||||||
|
u8 *end2 = JMP8(0);
|
||||||
|
|
||||||
|
// Normal division
|
||||||
|
x86SetJ8(cont3);
|
||||||
if( sign ) {
|
if( sign ) {
|
||||||
xCDQ();
|
xCDQ();
|
||||||
xDIV(ecx);
|
xDIV(ecx);
|
||||||
|
@ -623,22 +580,15 @@ void rpsxDIVsuper(int info, int sign)
|
||||||
xUDIV(ecx);
|
xUDIV(ecx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (sign) x86SetJ8( end1 );
|
||||||
|
x86SetJ8( end2 );
|
||||||
|
|
||||||
xMOV(ptr[&psxRegs.GPR.n.lo], eax);
|
xMOV(ptr[&psxRegs.GPR.n.lo], eax);
|
||||||
xMOV(ptr[&psxRegs.GPR.n.hi], edx);
|
xMOV(ptr[&psxRegs.GPR.n.hi], edx);
|
||||||
x86SetJ8(j8Ptr[0]);
|
|
||||||
|
|
||||||
// FIXME if RS is 0x80000000 and RT is 0xFFFF_FFFFF
|
|
||||||
// hi must be 0
|
|
||||||
// lo must be 0x80000000
|
|
||||||
// FIXME depends if div/divu
|
|
||||||
|
|
||||||
// FIXME
|
|
||||||
// hi must be rs
|
|
||||||
// lo must be 0xFFFF_FFFFF is rs >= 0, 0x1 otherwise
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpsxDIV_consts(int info) { rpsxDIVsuperconsts(info, 1); }
|
void rpsxDIV_consts(int info) { rpsxDIVsuper(info, 1, PROCESS_CONSTS); }
|
||||||
void rpsxDIV_constt(int info) { rpsxDIVsuperconstt(info, 1); }
|
void rpsxDIV_constt(int info) { rpsxDIVsuper(info, 1, PROCESS_CONSTT); }
|
||||||
void rpsxDIV_(int info) { rpsxDIVsuper(info, 1); }
|
void rpsxDIV_(int info) { rpsxDIVsuper(info, 1); }
|
||||||
|
|
||||||
PSXRECOMPILE_CONSTCODE3_PENALTY(DIV, 1, psxInstCycles_Div);
|
PSXRECOMPILE_CONSTCODE3_PENALTY(DIV, 1, psxInstCycles_Div);
|
||||||
|
@ -653,11 +603,14 @@ void rpsxDIVU_const()
|
||||||
hi = g_psxConstRegs[_Rs_] % g_psxConstRegs[_Rt_];
|
hi = g_psxConstRegs[_Rs_] % g_psxConstRegs[_Rt_];
|
||||||
xMOV(ptr32[&psxRegs.GPR.n.hi], hi);
|
xMOV(ptr32[&psxRegs.GPR.n.hi], hi);
|
||||||
xMOV(ptr32[&psxRegs.GPR.n.lo], lo);
|
xMOV(ptr32[&psxRegs.GPR.n.lo], lo);
|
||||||
|
} else {
|
||||||
|
xMOV(ptr32[&psxRegs.GPR.n.hi], g_psxConstRegs[_Rs_]);
|
||||||
|
xMOV(ptr32[&psxRegs.GPR.n.lo], 0xFFFFFFFFu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void rpsxDIVU_consts(int info) { rpsxDIVsuperconsts(info, 0); }
|
void rpsxDIVU_consts(int info) { rpsxDIVsuper(info, 0, PROCESS_CONSTS); }
|
||||||
void rpsxDIVU_constt(int info) { rpsxDIVsuperconstt(info, 0); }
|
void rpsxDIVU_constt(int info) { rpsxDIVsuper(info, 0, PROCESS_CONSTT); }
|
||||||
void rpsxDIVU_(int info) { rpsxDIVsuper(info, 0); }
|
void rpsxDIVU_(int info) { rpsxDIVsuper(info, 0); }
|
||||||
|
|
||||||
PSXRECOMPILE_CONSTCODE3_PENALTY(DIVU, 1, psxInstCycles_Div);
|
PSXRECOMPILE_CONSTCODE3_PENALTY(DIVU, 1, psxInstCycles_Div);
|
||||||
|
|
Loading…
Reference in New Issue