diff --git a/pcsx2/VUmicro.cpp b/pcsx2/VUmicro.cpp index 38a3684e0d..b4d4c7a9c0 100644 --- a/pcsx2/VUmicro.cpp +++ b/pcsx2/VUmicro.cpp @@ -20,6 +20,19 @@ #include "GS.h" #include "Gif_Unit.h" +__inline u32 CalculateMinRunCycles(u32 cycles, bool requiresAccurateCycles) +{ + // If we're running an interlocked COP2 operation + // run for an exact amount of cycles + if(requiresAccurateCycles) + return cycles; + + // Allow a minimum of 16 cycles to avoid running small blocks + // Running a block of like 3 cycles is highly inefficient + // so while sync isn't tight, it's okay to run ahead a little bit. + return std::max(16U, cycles); +} + // Executes a Block based on EE delta time void BaseVUmicroCPU::ExecuteBlock(bool startUp) { @@ -57,12 +70,12 @@ void BaseVUmicroCPU::ExecuteBlock(bool startUp) if (EmuConfig.Gamefixes.VUKickstartHack) { if (delta > 0) // When kickstarting we just need 1 cycle for run ahead - Execute(delta); + Execute(CalculateMinRunCycles(delta, false)); } else { if (delta >= nextblockcycles && delta > 0) // When running behind, make sure we have enough cycles passed for the block to run - Execute(delta); + Execute(CalculateMinRunCycles(delta, false)); } } } @@ -71,7 +84,7 @@ void BaseVUmicroCPU::ExecuteBlock(bool startUp) // EE data to VU0's registers. We want to run VU0 Micro right after this // to ensure that the register is used at the correct time. // This fixes spinning/hanging in some games like Ratchet and Clank's Intro. -void BaseVUmicroCPU::ExecuteBlockJIT(BaseVUmicroCPU* cpu) +void BaseVUmicroCPU::ExecuteBlockJIT(BaseVUmicroCPU* cpu, bool interlocked) { const u32& stat = VU0.VI[REG_VPU_STAT].UL; const int test = 1; @@ -83,7 +96,7 @@ void BaseVUmicroCPU::ExecuteBlockJIT(BaseVUmicroCPU* cpu) if (delta > 0) { - cpu->Execute(delta); // Execute the time since the last call + cpu->Execute(CalculateMinRunCycles(delta, interlocked)); // Execute the time since the last call } } } diff --git a/pcsx2/VUmicro.h b/pcsx2/VUmicro.h index 4195816ca7..b4246f5b00 100644 --- a/pcsx2/VUmicro.h +++ b/pcsx2/VUmicro.h @@ -147,7 +147,7 @@ public: // Executes a Block based on EE delta time (see VUmicro.cpp) virtual void ExecuteBlock(bool startUp=0); - static void __fastcall ExecuteBlockJIT(BaseVUmicroCPU* cpu); + static void __fastcall ExecuteBlockJIT(BaseVUmicroCPU* cpu, bool interlocked); // VU1 sometimes needs to break execution on XGkick Path1 transfers if // there is another gif path 2/3 transfer already taking place. diff --git a/pcsx2/x86/iR5900.h b/pcsx2/x86/iR5900.h index 0335a99cf0..e155ee4781 100644 --- a/pcsx2/x86/iR5900.h +++ b/pcsx2/x86/iR5900.h @@ -27,6 +27,7 @@ extern u32 pc; // recompiler pc extern int g_branch; // set for branch extern u32 target; // branch target extern u32 s_nBlockCycles; // cycles of current block recompiling +extern bool s_nBlockInterlocked; // Current block has VU0 interlocking ////////////////////////////////////////////////////////////////////////////////////////// // diff --git a/pcsx2/x86/ix86-32/iR5900-32.cpp b/pcsx2/x86/ix86-32/iR5900-32.cpp index f4ceef2e7e..44431fd2b2 100644 --- a/pcsx2/x86/ix86-32/iR5900-32.cpp +++ b/pcsx2/x86/ix86-32/iR5900-32.cpp @@ -61,7 +61,7 @@ alignas(16) static u32 hwLUT[_64kb]; static __fi u32 HWADDR(u32 mem) { return hwLUT[mem >> 16] + mem; } u32 s_nBlockCycles = 0; // cycles of current block recompiling - +bool s_nBlockInterlocked = false; // Block is VU0 interlocked u32 pc; // recompiler pc int g_branch; // set for branch @@ -1927,6 +1927,7 @@ static void __fastcall recRecompile(const u32 startpc) // reset recomp state variables s_nBlockCycles = 0; + s_nBlockInterlocked = false; pc = startpc; g_cpuHasConstReg = g_cpuFlushedConstReg = 1; pxAssert(g_cpuConstRegs[0].UD[0] == 0); diff --git a/pcsx2/x86/ix86-32/iR5900LoadStore.cpp b/pcsx2/x86/ix86-32/iR5900LoadStore.cpp index 287de45c73..9d1a082c5b 100644 --- a/pcsx2/x86/ix86-32/iR5900LoadStore.cpp +++ b/pcsx2/x86/ix86-32/iR5900LoadStore.cpp @@ -963,7 +963,8 @@ void recLQC2() xForwardJL32 skip; _cop2BackupRegs(); xLoadFarAddr(arg1reg, CpuVU0); - xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg); + xMOV(arg2reg, s_nBlockInterlocked); + xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg, arg2reg); _cop2RestoreRegs(); skip.SetTarget(); skipvuidle.SetTarget(); @@ -1012,7 +1013,8 @@ void recSQC2() xForwardJL32 skip; _cop2BackupRegs(); xLoadFarAddr(arg1reg, CpuVU0); - xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg); + xMOV(arg2reg, s_nBlockInterlocked); + xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg, arg2reg); _cop2RestoreRegs(); skip.SetTarget(); skipvuidle.SetTarget(); diff --git a/pcsx2/x86/microVU_Macro.inl b/pcsx2/x86/microVU_Macro.inl index 3a4bf0b762..f8d2e76a68 100644 --- a/pcsx2/x86/microVU_Macro.inl +++ b/pcsx2/x86/microVU_Macro.inl @@ -327,6 +327,7 @@ void COP2_Interlock(bool mBitSync) if (cpuRegs.code & 1) { + s_nBlockInterlocked = true; _freeX86reg(eax); xMOV(eax, ptr32[&cpuRegs.cycle]); xADD(eax, scaleblockcycles_clear()); @@ -342,7 +343,8 @@ void COP2_Interlock(bool mBitSync) xCMP(eax, 0); xForwardJL32 skip; xLoadFarAddr(arg1reg, CpuVU0); - xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg); + xMOV(arg2reg, s_nBlockInterlocked); + xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg, arg2reg); skip.SetTarget(); xFastCall((void*)_vu0WaitMicro); @@ -387,7 +389,8 @@ static void recCFC2() xForwardJL32 skip; _cop2BackupRegs(); xLoadFarAddr(arg1reg, CpuVU0); - xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg); + xMOV(arg2reg, s_nBlockInterlocked); + xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg, arg2reg); _cop2RestoreRegs(); skip.SetTarget(); skipvuidle.SetTarget(); @@ -449,7 +452,8 @@ static void recCTC2() xForwardJL32 skip; _cop2BackupRegs(); xLoadFarAddr(arg1reg, CpuVU0); - xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg); + xMOV(arg2reg, s_nBlockInterlocked); + xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg, arg2reg); _cop2RestoreRegs(); skip.SetTarget(); skipvuidle.SetTarget(); @@ -551,7 +555,8 @@ static void recQMFC2() xForwardJL32 skip; _cop2BackupRegs(); xLoadFarAddr(arg1reg, CpuVU0); - xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg); + xMOV(arg2reg, s_nBlockInterlocked); + xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg, arg2reg); _cop2RestoreRegs(); skip.SetTarget(); skipvuidle.SetTarget(); @@ -591,7 +596,8 @@ static void recQMTC2() xForwardJL32 skip; _cop2BackupRegs(); xLoadFarAddr(arg1reg, CpuVU0); - xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg); + xMOV(arg2reg, s_nBlockInterlocked); + xFastCall((void*)BaseVUmicroCPU::ExecuteBlockJIT, arg1reg, arg2reg); _cop2RestoreRegs(); skip.SetTarget(); skipvuidle.SetTarget();