diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 118f76ad0d..b1f6d44f88 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -31,7 +31,7 @@ enum class FreezeAction // the lower 16 bit value. IF the change is breaking of all compatibility with old // states, increment the upper 16 bit value, and clear the lower 16 bits to 0. -static const u32 g_SaveVersion = (0x9A23 << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A24 << 16) | 0x0000; // the freezing data between submodules and core // an interesting thing to note is that this dates back from before plugin diff --git a/pcsx2/VU.h b/pcsx2/VU.h index 5e286bad8a..cd9f083eca 100644 --- a/pcsx2/VU.h +++ b/pcsx2/VU.h @@ -180,6 +180,7 @@ struct __aligned16 VURegs u32 xgkickdiff; u32 xgkicksizeremaining; u32 xgkicklastcycle; + u32 xgkickcyclecount; u8 VIBackupCycles; u32 VIOldValue; diff --git a/pcsx2/VU0microInterp.cpp b/pcsx2/VU0microInterp.cpp index c2489b0ea0..bd19149b01 100644 --- a/pcsx2/VU0microInterp.cpp +++ b/pcsx2/VU0microInterp.cpp @@ -183,8 +183,7 @@ static void _vu0Exec(VURegs* VU) { VU->VI[REG_TPC].UL = VU->branchpc; - if (VU->blockhasmbit) - VU->blockhasmbit = false; + VU->blockhasmbit = false; if(VU->takedelaybranch) { @@ -205,8 +204,7 @@ static void _vu0Exec(VURegs* VU) VU0.VI[REG_VPU_STAT].UL&= ~0x1; /* E flag */ vif0Regs.stat.VEW = false; - if (VU->blockhasmbit) - VU->blockhasmbit = false; + VU->blockhasmbit = false; } } @@ -267,12 +265,16 @@ void InterpVU0::Execute(u32 cycles) VU0.flags &= ~VUFLAG_MFLAGSET; u32 startcycles = VU0.cycle; while((VU0.cycle - startcycles) < cycles) { - if (!(VU0.VI[REG_VPU_STAT].UL & 0x1) || (VU0.flags & VUFLAG_MFLAGSET)) { - if (VU0.branch || VU0.ebit) { - vu0Exec(&VU0); // run branch delay slot? + if (!(VU0.VI[REG_VPU_STAT].UL & 0x1)) { + // Branches advance the PC to the new location if there was a branch in the E-Bit delay slot + if (VU0.branch) { + VU0.VI[REG_TPC].UL = VU0.branchpc; + VU0.branch = 0; } break; } + if (VU0.flags & VUFLAG_MFLAGSET) + break; vu0Exec(&VU0); } VU0.VI[REG_TPC].UL >>= 3; diff --git a/pcsx2/VU1microInterp.cpp b/pcsx2/VU1microInterp.cpp index a07cd70b17..d69ef956be 100644 --- a/pcsx2/VU1microInterp.cpp +++ b/pcsx2/VU1microInterp.cpp @@ -207,13 +207,12 @@ static void _vu1Exec(VURegs* VU) _vuFlushAll(VU); VU0.VI[REG_VPU_STAT].UL &= ~0x100; vif1Regs.stat.VEW = false; + // In instant VU mode, VU1 goes WAY ahead of the CPU, making the XGKick fall way behind + // We also have some code to update it in VIF Unpacks too, since in some games (Aggressive Inline) overwrite the XGKick data + if (INSTANT_VU1) + VU1.xgkicklastcycle = cpuRegs.cycle; } } - - if (VU->xgkickenable && (VU1.cycle - VU->xgkicklastcycle) >= 2) - { - _vuXGKICKTransfer(VU, (VU1.cycle - VU->xgkicklastcycle), false); - } // Progress the write position of the FMAC pipeline by one place if (uregs.pipe == VUPIPE_FMAC || lregs.pipe == VUPIPE_FMAC) @@ -278,13 +277,15 @@ void InterpVU1::Execute(u32 cycles) VU1.VI[REG_TPC].UL <<= 3; u32 startcycles = VU1.cycle; + while ((VU1.cycle - startcycles) < cycles) { if (!(VU0.VI[REG_VPU_STAT].UL & 0x100)) { - if (VU1.branch || VU1.ebit) + if (VU1.branch == 1) { - Step(); // run branch delay slot? + VU1.VI[REG_TPC].UL = VU1.branchpc; + VU1.branch = 0; } break; } diff --git a/pcsx2/VUmicro.cpp b/pcsx2/VUmicro.cpp index 5e9af433dc..dcdb45e687 100644 --- a/pcsx2/VUmicro.cpp +++ b/pcsx2/VUmicro.cpp @@ -35,12 +35,9 @@ void BaseVUmicroCPU::ExecuteBlock(bool startUp) if (!(stat & test)) { - if (m_Idx == 1) + if (m_Idx == 1 && VU1.xgkickenable) { - if (VU1.xgkickenable && (cpuRegs.cycle - VU1.xgkicklastcycle) >= 2) - { - _vuXGKICKTransfer(&VU1, (cpuRegs.cycle - VU1.xgkicklastcycle), false); - } + _vuXGKICKTransfer(&VU1, (cpuRegs.cycle - VU1.xgkicklastcycle), false); } return; } @@ -63,7 +60,9 @@ void BaseVUmicroCPU::ExecuteBlock(bool startUp) u32 nextblockcycles = m_Idx ? VU1.nextBlockCycles : VU0.nextBlockCycles; - if((VU0.flags & VUFLAG_MFLAGSET) || VU0.blockhasmbit) + bool useNextBlocks = (VU0.flags & VUFLAG_MFLAGSET) || VU0.blockhasmbit || !EmuConfig.Cpu.Recompiler.EnableVU0; + + if(useNextBlocks) cpuSetNextEventDelta(nextblockcycles); else if(s) cpuSetNextEventDelta(s); @@ -86,7 +85,7 @@ void BaseVUmicroCPU::ExecuteBlock(bool startUp) Execute(delta); } - if ((stat & test) && !EmuConfig.Gamefixes.VUKickstartHack) + if ((stat & test) && (!EmuConfig.Gamefixes.VUKickstartHack || (!m_Idx && !EmuConfig.Cpu.Recompiler.EnableVU0))) { // Queue up next required time to run a block nextblockcycles = m_Idx ? VU1.nextBlockCycles : VU0.nextBlockCycles; diff --git a/pcsx2/VUops.cpp b/pcsx2/VUops.cpp index f9d9f6485c..add6d46072 100644 --- a/pcsx2/VUops.cpp +++ b/pcsx2/VUops.cpp @@ -207,6 +207,14 @@ __fi void _vuTestPipes(VURegs * VU) flushed |= _vuEFUflush(VU); flushed |= _vuIALUflush(VU); } while (flushed == true); + + if (VU == &VU1) + { + if (VU1.xgkickenable) + { + _vuXGKICKTransfer(&VU1, (VU1.cycle - VU1.xgkicklastcycle), false); + } + } } static void __fastcall _vuFMACTestStall(VURegs* VU, int reg, int xyzw) @@ -2322,7 +2330,11 @@ void _vuXGKICKTransfer(VURegs* VU, u32 cycles, bool flush) if (!VU->xgkickenable) return; - while (!VU->xgkickendpacket || VU->xgkicksizeremaining > 0) + VU->xgkickcyclecount += cycles; + VU->xgkicklastcycle += cycles; + VUM_LOG("Adding %d cycles, total XGKick cycles to run now %d", cycles, VU->xgkickcyclecount); + + while ((!VU->xgkickendpacket || VU->xgkicksizeremaining > 0) && (flush || VU->xgkickcyclecount >= 2)) { u32 transfersize = 0; @@ -2345,7 +2357,7 @@ void _vuXGKICKTransfer(VURegs* VU, u32 cycles, bool flush) if (!flush) { - transfersize = std::min(VU->xgkicksizeremaining / 0x10, cycles / 2); + transfersize = std::min(VU->xgkicksizeremaining / 0x10, VU->xgkickcyclecount / 2); transfersize = std::min(transfersize, VU->xgkickdiff / 0x10); } else @@ -2366,12 +2378,11 @@ void _vuXGKICKTransfer(VURegs* VU, u32 cycles, bool flush) if ((VU0.VI[REG_VPU_STAT].UL & 0x100) && flush) VU->cycle += transfersize * 2; - cycles -= transfersize * 2; + VU->xgkickcyclecount -= transfersize * 2; VU->xgkickaddr = (VU->xgkickaddr + (transfersize * 0x10)) & 0x3FFF; VU->xgkicksizeremaining -= (transfersize * 0x10); VU->xgkickdiff = 0x4000 - VU->xgkickaddr; - VU->xgkicklastcycle += std::max(transfersize * 2, 2U); if (VU->xgkicksizeremaining || !VU->xgkickendpacket) VUM_LOG("XGKICK next addr %x left size %x", VU->xgkickaddr, VU->xgkicksizeremaining); @@ -2386,13 +2397,13 @@ void _vuXGKICKTransfer(VURegs* VU, u32 cycles, bool flush) CPU_INT(DMAC_VIF1, 8); } } - - if (!flush && cycles < 2) - return; } - VUM_LOG("Disabling XGKICK"); - VU->xgkickenable = false; - _vuTestPipes(VU); + if (flush) + { + VUM_LOG("Disabling XGKICK"); + VU->xgkickenable = false; + _vuTestPipes(VU); + } } static __ri void _vuXGKICK(VURegs * VU) @@ -2411,7 +2422,8 @@ static __ri void _vuXGKICK(VURegs * VU) VU->xgkicksizeremaining = 0; VU->xgkickendpacket = false; VU->xgkicklastcycle = VU->cycle; - IPU_LOG("XGKICK size %x EOP %d addr %x", VU->xgkicksizeremaining, VU->xgkickendpacket, addr); + VU->xgkickcyclecount = 0; + VUM_LOG("XGKICK addr %x", addr); } static __ri void _vuXTOP(VURegs * VU) { diff --git a/pcsx2/Vif0_Dma.cpp b/pcsx2/Vif0_Dma.cpp index 1412576ab5..4d7eff39c4 100644 --- a/pcsx2/Vif0_Dma.cpp +++ b/pcsx2/Vif0_Dma.cpp @@ -157,7 +157,6 @@ __fi void vif0VUFinish() if(vif0.waitforvu) { vif0.waitforvu = false; - ExecuteVU(0); //Make sure VIF0 isnt already scheduled to spin. if(!(cpuRegs.interrupt & 0x1) && vif0ch.chcr.STR && !vif0Regs.stat.test(VIF0_STAT_VSS | VIF0_STAT_VIS | VIF0_STAT_VFS)) vif0Interrupt(); @@ -180,6 +179,10 @@ __fi void vif0Interrupt() CPU_INT(VIF_VU0_FINISH, 16); return; } + if (vif0Regs.stat.VGW) + { + DevCon.Warning("VIF0 waiting for path"); + } if (vif0.irq && vif0.vifstalled.enabled && vif0.vifstalled.value == VIF_IRQ_STALL) { diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index dd2d0248b6..c51da1592a 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -252,27 +252,13 @@ __fi void vif1VUFinish() vif1Regs.stat.VEW = false; VIF_LOG("VU1 finished"); - if( gifRegs.stat.APATH == 1 ) - { - VIF_LOG("Clear APATH1"); - gifRegs.stat.APATH = 0; - gifRegs.stat.OPH = 0; - vif1Regs.stat.VGW = false; //Let vif continue if it's stuck on a flush - - if(!vif1.waitforvu) - { - if(gifUnit.checkPaths(0,1,1)) gifUnit.Execute(false, true); - } - - } if(vif1.waitforvu) { vif1.waitforvu = false; - ExecuteVU(1); //Check if VIF is already scheduled to interrupt, if it's waiting, kick it :P - if((cpuRegs.interrupt & ((1< 1) { - vuExecMicro(idx, (u16)(vifXRegs.code)); - vifX.cmd = 0; - vifX.pass = 0; - if (GetVifX.vifpacketsize > 1) + //Warship Gunner 2 has a rather big dislike for the delays + if (((data[1] >> 24) & 0x60) == 0x60) // Immediate following Unpack { - //Warship Gunner 2 has a rather big dislike for the delays - if (((data[1] >> 24) & 0x60) == 0x60) // Immediate following Unpack - { - //Snowblind games only use MSCAL, so other MS kicks force the program directly. - vifExecQueue(idx); - } + //Snowblind games only use MSCAL, so other MS kicks force the program directly. + vifExecQueue(idx); } } } @@ -460,13 +452,14 @@ vifOp(vifCode_MSCALF) vifX.vifstalled.enabled = VifStallEnable(vifXch); vifX.vifstalled.value = VIF_TIMING_BREAK; } - if (!vifX.waitforvu) - { - vuExecMicro(idx, (u16)(vifXRegs.code)); - vifX.cmd = 0; - vifX.pass = 0; - vifExecQueue(idx); - } + + if (vifX.waitforvu || vif1Regs.stat.VGW) + return 0; + + vuExecMicro(idx, (u16)(vifXRegs.code), true); + vifX.cmd = 0; + vifX.pass = 0; + vifExecQueue(idx); } pass3 { VifCodeLog("MSCALF"); } return 1; @@ -478,17 +471,18 @@ vifOp(vifCode_MSCNT) pass1 { vifFlush(idx); - if (!vifX.waitforvu) + + if (vifX.waitforvu) + return 0; + + vuExecMicro(idx, -1, false); + vifX.cmd = 0; + vifX.pass = 0; + if (GetVifX.vifpacketsize > 1) { - vuExecMicro(idx, -1); - vifX.cmd = 0; - vifX.pass = 0; - if (GetVifX.vifpacketsize > 1) + if (((data[1] >> 24) & 0x60) == 0x60) // Immediate following Unpack { - if (((data[1] >> 24) & 0x60) == 0x60) // Immediate following Unpack - { - vifExecQueue(idx); - } + vifExecQueue(idx); } } } diff --git a/pcsx2/Vif_Dma.h b/pcsx2/Vif_Dma.h index 13022ceaf4..57bbadd39a 100644 --- a/pcsx2/Vif_Dma.h +++ b/pcsx2/Vif_Dma.h @@ -94,15 +94,13 @@ struct vifStruct { bool queued_program; u32 queued_pc; - - + bool queued_gif_wait; }; extern __aligned16 vifStruct vif0, vif1; _vifT extern u32 vifRead32(u32 mem); _vifT extern bool vifWrite32(u32 mem, u32 value); -void ExecuteVU(int idx); extern void vif0Interrupt(); extern void vif0VUFinish(); extern void vif0Reset(); diff --git a/pcsx2/Vif_Transfer.cpp b/pcsx2/Vif_Transfer.cpp index f3cc466b4f..4c8c60f259 100644 --- a/pcsx2/Vif_Transfer.cpp +++ b/pcsx2/Vif_Transfer.cpp @@ -59,6 +59,12 @@ _vifT void vifTransferLoop(u32* &data) { ret = vifCmdHandler[idx][vifX.cmd & 0x7f](vifX.pass, data); data += ret; pSize -= ret; + if (vifX.vifstalled.enabled) + { + int current_STR = idx ? vif1ch.chcr.STR : vif0ch.chcr.STR; + if (!current_STR) + DevCon.Warning("Warning! VIF%d stalled during FIFO transfer!", idx); + } } } diff --git a/pcsx2/x86/newVif_Unpack.cpp b/pcsx2/x86/newVif_Unpack.cpp index 7010a90abc..9fae5e8806 100644 --- a/pcsx2/x86/newVif_Unpack.cpp +++ b/pcsx2/x86/newVif_Unpack.cpp @@ -113,6 +113,15 @@ _vifT int nVifUnpack(const u8* data) const bool isFill = (vifRegs.cycle.cl < wl); s32 size = ret << 2; + // This is for use when XGKick is synced as VIF can overwrite XG Kick data as it's transferring out + // Test with Aggressive Inline Skating, or K-1 Premium 2005 Dynamite! + if (idx == 1 && VU1.xgkickenable && !(VU0.VI[REG_TPC].UL & 0x100)) + { + // Catch up first, then the unpack cycles + _vuXGKICKTransfer(&VU1, cpuRegs.cycle - VU1.xgkicklastcycle, false); + _vuXGKICKTransfer(&VU1, ret/2, false); + } + if (ret == vif.tag.size) // Full Transfer { if (v.bSize) // Last transfer was partial