From c0f8d5cd448f7613558f9a29d63a8341c76a9fb8 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Fri, 3 Nov 2023 21:30:23 +0000 Subject: [PATCH] EE/Int: Improve FPU emulation --- pcsx2/COP2.cpp | 4 ++-- pcsx2/FPU.cpp | 39 +++++++++++++++++++++++++++---------- pcsx2/VUops.cpp | 4 ++-- pcsx2/x86/microVU_Macro.inl | 1 + 4 files changed, 34 insertions(+), 14 deletions(-) diff --git a/pcsx2/COP2.cpp b/pcsx2/COP2.cpp index 90bb21bc13eb7..716746acb1306 100644 --- a/pcsx2/COP2.cpp +++ b/pcsx2/COP2.cpp @@ -27,13 +27,13 @@ using namespace R5900::Interpreter; //Run the FINISH either side of the VCALL's as we have no control over it past here. void VCALLMS() { - vu0Finish(); + _vu0FinishMicro(); vu0ExecMicro(((cpuRegs.code >> 6) & 0x7FFF)); //vif0Regs.stat.VEW = false; } void VCALLMSR() { - vu0Finish(); + _vu0FinishMicro(); vu0ExecMicro(VU0.VI[REG_CMSAR0].US[0]); //vif0Regs.stat.VEW = false; } diff --git a/pcsx2/FPU.cpp b/pcsx2/FPU.cpp index c6662c37af966..d7be8fac591b5 100644 --- a/pcsx2/FPU.cpp +++ b/pcsx2/FPU.cpp @@ -76,12 +76,14 @@ // If we have an infinity value, then Overflow has occured. bool checkOverflow(u32& xReg, u32 cFlagsToSet) { - if ( (xReg & ~0x80000000) == PosInfinity ) { + if ((xReg & ~0x80000000) == PosInfinity) { /*Console.Warning( "FPU OVERFLOW!: Changing to +/-Fmax!!!!!!!!!!!!\n" );*/ xReg = (xReg & 0x80000000) | posFmax; _ContVal_ |= (cFlagsToSet); return true; } + else if (cFlagsToSet & FPUflagO) + _ContVal_ &= ~FPUflagO; return false; } @@ -94,10 +96,22 @@ bool checkUnderflow(u32& xReg, u32 cFlagsToSet) { _ContVal_ |= (cFlagsToSet); return true; } + else if (cFlagsToSet & FPUflagU) + _ContVal_ &= ~FPUflagU; return false; } +__fi u32 fp_max(u32 a, u32 b) +{ + return ((s32)a < 0 && (s32)b < 0) ? std::min(a, b) : std::max(a, b); +} + +__fi u32 fp_min(u32 a, u32 b) +{ + return ((s32)a < 0 && (s32)b < 0) ? std::max(a, b) : std::min(a, b); +} + /* Checks if Divide by Zero will occur. (z/y = x) cFlagsToSet1 = Flags to set if (z != 0) cFlagsToSet2 = Flags to set if (z == 0) @@ -137,7 +151,7 @@ bool checkDivideByZero(u32& xReg, u32 yDivisorReg, u32 zDividendReg, u32 cFlagsT #else // Used for Comparing; This compares if the floats are exactly the same. #define C_cond_S(cond) { \ - _ContVal_ = ( _FsValf_ cond _FtValf_ ) ? \ + _ContVal_ = ( fpuDouble(_FsValUl_) cond fpuDouble(_FtValUl_) ) ? \ ( _ContVal_ | FPUflagC ) : \ ( _ContVal_ & ~FPUflagC ); \ } @@ -231,12 +245,14 @@ void C_LT() { } void CFC1() { - if ( !_Rt_ ) return; + if (!_Rt_) return; - if (_Fs_ >= 16) + if (_Fs_ == 31) cpuRegs.GPR.r[_Rt_].SD[0] = (s32)fpuRegs.fprc[31]; // force sign extension to 64 bit + else if (_Fs_ == 0) + cpuRegs.GPR.r[_Rt_].SD[0] = 0x2E00; else - cpuRegs.GPR.r[_Rt_].SD[0] = (s32)fpuRegs.fprc[0]; // force sign extension to 64 bit + cpuRegs.GPR.r[_Rt_].SD[0] = 0; } void CTC1() { @@ -281,7 +297,7 @@ void MADDA_S() { } void MAX_S() { - _FdValf_ = std::max( _FsValf_, _FtValf_ ); + _FdValUl_ = fp_max( _FsValUl_, _FtValUl_ ); clearFPUFlags( FPUflagO | FPUflagU ); } @@ -291,7 +307,7 @@ void MFC1() { } void MIN_S() { - _FdValf_ = std::min( _FsValf_, _FtValf_ ); + _FdValUl_ = fp_min(_FsValUl_, _FtValUl_); clearFPUFlags( FPUflagO | FPUflagU ); } @@ -336,9 +352,11 @@ void NEG_S() { void RSQRT_S() { FPRreg temp; + clearFPUFlags(FPUflagD | FPUflagI); + if ( ( _FtValUl_ & 0x7F800000 ) == 0 ) { // Ft is zero (Denormals are Zero) _ContVal_ |= FPUflagD | FPUflagSD; - _FdValUl_ = ( ( _FsValUl_ ^ _FtValUl_ ) & 0x80000000 ) | posFmax; + _FdValUl_ = ( _FtValUl_ & 0x80000000 ) | posFmax; return; } else if ( _FtValUl_ & 0x80000000 ) { // Ft is negative @@ -353,14 +371,15 @@ void RSQRT_S() { } void SQRT_S() { + clearFPUFlags(FPUflagI | FPUflagD); + if ( ( _FtValUl_ & 0x7F800000 ) == 0 ) // If Ft = +/-0 - _FdValUl_ = 0;// result is 0 + _FdValUl_ = _FtValUl_ & 0x80000000;// result is 0 else if ( _FtValUl_ & 0x80000000 ) { // If Ft is Negative _ContVal_ |= FPUflagI | FPUflagSI; _FdValf_ = sqrt( fabs( fpuDouble( _FtValUl_ ) ) ); } else _FdValf_ = sqrt( fpuDouble( _FtValUl_ ) ); // If Ft is Positive - clearFPUFlags( FPUflagD ); } void SUB_S() { diff --git a/pcsx2/VUops.cpp b/pcsx2/VUops.cpp index 257da0d2f2445..2b55dc838ff3b 100644 --- a/pcsx2/VUops.cpp +++ b/pcsx2/VUops.cpp @@ -4692,7 +4692,7 @@ _vuRegsTables(VU1, VU1regs, Fnptr_VuRegsN) static __fi void SYNCMSFLAGS() { - VU0.VI[REG_STATUS_FLAG].UL = (VU0.VI[REG_STATUS_FLAG].UL & 0xC30) | (VU0.statusflag & 0xF) | ((VU0.statusflag & 0xF) << 6); + VU0.VI[REG_STATUS_FLAG].UL = (VU0.VI[REG_STATUS_FLAG].UL & 0xFC0) | (VU0.statusflag & 0xF) | ((VU0.statusflag & 0xF) << 6); VU0.VI[REG_MAC_FLAG].UL = VU0.macflag; } @@ -4703,7 +4703,7 @@ static __fi void SYNCCLIPFLAG() static __fi void SYNCSTATUSFLAG() { - VU0.VI[REG_STATUS_FLAG].UL = (VU0.VI[REG_STATUS_FLAG].UL & 0x3F) | (VU0.statusflag & 0xFC0); + VU0.VI[REG_STATUS_FLAG].UL = (VU0.VI[REG_STATUS_FLAG].UL & 0xFC0) | (VU0.statusflag & 0xF) | ((VU0.statusflag & 0xF) << 6); } static __fi void SYNCFDIV() diff --git a/pcsx2/x86/microVU_Macro.inl b/pcsx2/x86/microVU_Macro.inl index 9e506667eaa81..bafad491a1531 100644 --- a/pcsx2/x86/microVU_Macro.inl +++ b/pcsx2/x86/microVU_Macro.inl @@ -890,6 +890,7 @@ void recSQC2() } #else +namespace Interp = R5900::Interpreter::OpcodeImpl; REC_FUNC(LQC2); REC_FUNC(SQC2);