diff --git a/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py b/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py index 0027df7cd2..ab76a69b3e 100644 --- a/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py +++ b/.github/workflows/scripts/validation/lint-gamedb/lint-gamedb.py @@ -34,7 +34,7 @@ allowed_game_fixes = [ "GoemonTlbHack", "VUKickstartHack", "IbitHack", - "RatchetDynaHack", + "VUOverflowHack", ] allowed_speed_hacks = ["mvuFlagSpeedHack", "InstantVU1SpeedHack"] # Patches are allowed to have a 'default' key or a crc-32 key, followed by diff --git a/bin/GameIndex.yaml b/bin/GameIndex.yaml index cba968838b..e12d7fe4b9 100644 --- a/bin/GameIndex.yaml +++ b/bin/GameIndex.yaml @@ -14344,6 +14344,8 @@ SLES-53744: SLES-53746: name: "Superman Returns" region: "PAL-E" + gameFixes: + - VUOverflowHack # Fixes SPS. SLES-53747: name: "Ed, Edd, 'n Eddy - The Misadventure" region: "PAL-E" @@ -15535,15 +15537,23 @@ SLES-54347: SLES-54348: name: "Superman Returns" region: "PAL-F" + gameFixes: + - VUOverflowHack # Fixes SPS. SLES-54349: name: "Superman Returns" region: "PAL-I" + gameFixes: + - VUOverflowHack # Fixes SPS. SLES-54350: name: "Superman Returns" region: "PAL-G" + gameFixes: + - VUOverflowHack # Fixes SPS. SLES-54351: name: "Superman Returns" region: "PAL-S" + gameFixes: + - VUOverflowHack # Fixes SPS. SLES-54354: name: "Final Fantasy XII" region: "PAL-E" @@ -38365,6 +38375,8 @@ SLUS-21434: name: "Superman Returns - The Video Game" region: "NTSC-U" compat: 4 + gameFixes: + - VUOverflowHack # Fixes SPS. SLUS-21435: name: "One Piece - Grand Adventure" region: "NTSC-U" diff --git a/pcsx2/Config.h b/pcsx2/Config.h index d4208825a7..6584d573c5 100644 --- a/pcsx2/Config.h +++ b/pcsx2/Config.h @@ -39,6 +39,7 @@ enum GamefixId Fix_GoemonTlbMiss, Fix_Ibit, Fix_VUKickstart, + Fix_VUOverflow, GamefixId_COUNT }; @@ -345,7 +346,8 @@ struct Pcsx2Config GIFFIFOHack : 1, // Enabled the GIF FIFO (more correct but slower) GoemonTlbHack : 1, // Gomeon tlb miss hack. The game need to access unmapped virtual address. Instead to handle it as exception, tlb are preloaded at startup IbitHack : 1, // I bit hack. Needed to stop constant VU recompilation in some games - VUKickstartHack : 1; // Gives new VU programs a slight head start and runs VU's ahead of EE to avoid VU register reading/writing issues + VUKickstartHack : 1, // Gives new VU programs a slight head start and runs VU's ahead of EE to avoid VU register reading/writing issues + VUOverflowHack : 1; // Tries to simulate overflow flag checks (not really possible on x86 without soft floats) BITFIELD_END GamefixOptions(); @@ -532,6 +534,7 @@ TraceLogFilters& SetTraceConfig(); #define CHECK_VIFFIFOHACK (EmuConfig.Gamefixes.VIFFIFOHack) // Pretends to fill the non-existant VIF FIFO Buffer. #define CHECK_VIF1STALLHACK (EmuConfig.Gamefixes.VIF1StallHack) // Like above, processes FIFO data before the stall is allowed (to make sure data goes over). #define CHECK_GIFFIFOHACK (EmuConfig.Gamefixes.GIFFIFOHack) // Enabled the GIF FIFO (more correct but slower) +#define CHECK_VUOVERFLOWHACK (EmuConfig.Gamefixes.VUOverflowHack) // Special Fix for Superman Returns, they check for overflows on PS2 floats which we can't do without soft floats. //------------ Advanced Options!!! --------------- #define CHECK_VU_OVERFLOW (EmuConfig.Cpu.Recompiler.vuOverflow) diff --git a/pcsx2/Pcsx2Config.cpp b/pcsx2/Pcsx2Config.cpp index b9f95d1238..09cc5aaf09 100644 --- a/pcsx2/Pcsx2Config.cpp +++ b/pcsx2/Pcsx2Config.cpp @@ -269,7 +269,8 @@ const wxChar *const tbl_GamefixNames[] = L"GIFFIFO", L"GoemonTlb", L"Ibit", - L"VUKickstart" + L"VUKickstart", + L"VUOverflow" }; const __fi wxChar* EnumToString( GamefixId id ) @@ -329,7 +330,8 @@ void Pcsx2Config::GamefixOptions::Set( GamefixId id, bool enabled ) case Fix_GIFFIFO: GIFFIFOHack = enabled; break; case Fix_GoemonTlbMiss: GoemonTlbHack = enabled; break; case Fix_Ibit: IbitHack = enabled; break; - case Fix_VUKickstart: VUKickstartHack = enabled; break; + case Fix_VUKickstart: VUKickstartHack = enabled; break; + case Fix_VUOverflow: VUOverflowHack = enabled; break; jNO_DEFAULT; } } @@ -353,6 +355,7 @@ bool Pcsx2Config::GamefixOptions::Get( GamefixId id ) const case Fix_GoemonTlbMiss: return GoemonTlbHack; case Fix_Ibit: return IbitHack; case Fix_VUKickstart: return VUKickstartHack; + case Fix_VUOverflow: return VUOverflowHack; jNO_DEFAULT; } return false; // unreachable, but we still need to suppress warnings >_< @@ -376,6 +379,7 @@ void Pcsx2Config::GamefixOptions::LoadSave( IniInterface& ini ) IniBitBool( GoemonTlbHack ); IniBitBool( IbitHack ); IniBitBool( VUKickstartHack ); + IniBitBool( VUOverflowHack ); } diff --git a/pcsx2/gui/Panels/GameFixesPanel.cpp b/pcsx2/gui/Panels/GameFixesPanel.cpp index 1c0ddfa890..864a631a31 100644 --- a/pcsx2/gui/Panels/GameFixesPanel.cpp +++ b/pcsx2/gui/Panels/GameFixesPanel.cpp @@ -96,6 +96,10 @@ Panels::GameFixesPanel::GameFixesPanel( wxWindow* parent ) { _("VU Kickstart (Run ahead) to avoid sync problems when reading or writing VU registers"), wxEmptyString + }, + { + _("VU Overflow hack to check for possible float overflows (Superman Returns)"), + wxEmptyString } }; diff --git a/pcsx2/x86/microVU_Upper.inl b/pcsx2/x86/microVU_Upper.inl index f55897581b..ccf9102957 100644 --- a/pcsx2/x86/microVU_Upper.inl +++ b/pcsx2/x86/microVU_Upper.inl @@ -78,17 +78,18 @@ static void mVUupdateFlags(mV, const xmm& reg, const xmm& regT1in = xEmptyReg, c xMOVMSKPS(gprT2, regT1); // Used for Zero Flag Calculation xAND(mReg, AND_XYZW); // Grab "Is Signed" bits from the previous calculation - xSHL(mReg, 4 + ADD_XYZW); + xSHL(mReg, 4); //-------------------------Check for Zero flags------------------------------ xAND(gprT2, AND_XYZW); // Grab "Is Zero" bits from the previous calculation - if (mFLAG.doFlag) - SHIFT_XYZW(gprT2); xOR(mReg, gprT2); //-------------------------Overflow Flags----------------------------------- - if (sFLAG.doFlag) + // We can't really do this because of the limited range of x86 and the value MIGHT genuinely be FLT_MAX (x86) + // so this will need to remain as a gamefix for the one game that needs it (Superman Returns) + // until some sort of soft float implementation. + if (sFLAG.doFlag && CHECK_VUOVERFLOWHACK) { //Calculate overflow xMOVAPS(regT1, regT2); @@ -97,16 +98,23 @@ static void mVUupdateFlags(mV, const xmm& reg, const xmm& regT1in = xEmptyReg, c xMOVMSKPS(gprT2, regT1); // Grab sign bits for equal results xAND(gprT2, AND_XYZW); // Grab "Is FLT_MAX" bits from the previous calculation xForwardJump32 oJMP(Jcc_Zero); - xOR(sReg, 0x820000); + + xOR(sReg, 0x820000); + if (mFLAG.doFlag) + { + xSHL(gprT2, 12); // Add the results to the MAC Flag + xOR(mReg, gprT2); + } + oJMP.SetTarget(); - - xSHL(gprT2, 12 + ADD_XYZW); // Add the results to the MAC Flag - xOR(mReg, gprT2); } - //-------------------------Write back flags------------------------------ + //-------------------------Write back flags------------------------------ if (mFLAG.doFlag) + { + SHIFT_XYZW(mReg); // If it was Single Scalar, move the flags in to the correct position mVUallocMFLAGb(mVU, mReg, mFLAG.write); // Set Mac Flag + } if (sFLAG.doFlag) { xAND(mReg, 0xFF); // Ignore overflow bits, they're handled separately