diff --git a/pcsx2/R3000AOpcodeTables.cpp b/pcsx2/R3000AOpcodeTables.cpp index 839269251d..295c81efc5 100644 --- a/pcsx2/R3000AOpcodeTables.cpp +++ b/pcsx2/R3000AOpcodeTables.cpp @@ -71,14 +71,36 @@ void psxSLTU() { if (!_Rd_) return; _rRd_ = _u32(_rRs_) < _u32(_rRt_); } // Rd * Format: OP rs, rt * *********************************************************/ void psxDIV() { - if (_rRt_ != 0) { + if (_rRt_ == 0) { + // Division by 0 + _rLo_ = _i32(_rRs_) < 0 ? 1 : 0xFFFFFFFFu; + _rHi_ = _rRs_; + + } else if (_rRs_ == 0x80000000u && _rRt_ == 0xFFFFFFFFu) { + // x86 overflow + _rLo_ = 0x80000000u; + _rHi_ = 0; + + } else { + // Normal behavior _rLo_ = _i32(_rRs_) / _i32(_rRt_); _rHi_ = _i32(_rRs_) % _i32(_rRt_); } } void psxDIVU() { - if (_rRt_ != 0) { + if (_rRt_ == 0) { + // Division by 0 + _rLo_ = 0xFFFFFFFFu; + _rHi_ = _rRs_; + + } else if (_rRs_ == 0x80000000u && _rRt_ == 0xFFFFFFFFu) { + // x86 overflow + _rLo_ = 0; + _rHi_ = 0x80000000u; + + } else { + // Normal behavior _rLo_ = _rRs_ / _rRt_; _rHi_ = _rRs_ % _rRt_; } diff --git a/pcsx2/x86/iR3000Atables.cpp b/pcsx2/x86/iR3000Atables.cpp index 9b4c5a11da..0771d0f71a 100644 --- a/pcsx2/x86/iR3000Atables.cpp +++ b/pcsx2/x86/iR3000Atables.cpp @@ -506,11 +506,18 @@ void rpsxDIV_const() */ // Of course x86 cpu does overflow ! 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.lo], 0x80000000); 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) { lo = *(int*)&g_psxConstRegs[_Rs_] / *(int*)&g_psxConstRegs[_Rt_]; hi = *(int*)&g_psxConstRegs[_Rs_] % *(int*)&g_psxConstRegs[_Rt_]; @@ -523,6 +530,15 @@ 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_]]); @@ -549,6 +565,7 @@ void rpsxDIVsuperconsts(int info, int sign) 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 } } @@ -556,6 +573,15 @@ 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); @@ -573,6 +599,10 @@ void rpsxDIVsuperconstt(int info, int sign) xMOV(ptr[&psxRegs.GPR.n.lo], eax); xMOV(ptr[&psxRegs.GPR.n.hi], edx); + } else { + // FIXME + // hi must be rs + // lo must be 0xFFFF_FFFFF is rs >= 0, 0x1 otherwise if rs < 0 and sign } } @@ -596,6 +626,15 @@ void rpsxDIVsuper(int info, int sign) xMOV(ptr[&psxRegs.GPR.n.lo], eax); 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); }