Skip to content

Commit

Permalink
VIF/VU: Cleaned up VIF Stall behaviour, sync XGKick with Unpacks.
Browse files Browse the repository at this point in the history
Also cleaned up a bunch of bad/old code
Fixed branches on E-Bit and M-Bit (VU0)
Fixed up VU Int behaviour with VU Instant on/off

Savestate bump
  • Loading branch information
refractionpcsx2 committed Sep 12, 2021
1 parent 7e29a7e commit 3f56414
Show file tree
Hide file tree
Showing 12 changed files with 120 additions and 105 deletions.
2 changes: 1 addition & 1 deletion pcsx2/SaveState.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions pcsx2/VU.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ struct __aligned16 VURegs
u32 xgkickdiff;
u32 xgkicksizeremaining;
u32 xgkicklastcycle;
u32 xgkickcyclecount;

u8 VIBackupCycles;
u32 VIOldValue;
Expand Down
16 changes: 9 additions & 7 deletions pcsx2/VU0microInterp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand All @@ -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;
}
}

Expand Down Expand Up @@ -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;
Expand Down
15 changes: 8 additions & 7 deletions pcsx2/VU1microInterp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
}
Expand Down
13 changes: 6 additions & 7 deletions pcsx2/VUmicro.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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);
Expand All @@ -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;
Expand Down
34 changes: 23 additions & 11 deletions pcsx2/VUops.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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;

Expand All @@ -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
Expand All @@ -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);
Expand All @@ -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)
Expand All @@ -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) {
Expand Down
5 changes: 4 additions & 1 deletion pcsx2/Vif0_Dma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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)
{
Expand Down
22 changes: 6 additions & 16 deletions pcsx2/Vif1_Dma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<<DMAC_VIF1) | (1 << DMAC_MFIFO_VIF))) == 0 && vif1ch.chcr.STR && !vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
if ((cpuRegs.interrupt & ((1 << DMAC_VIF1) | (1 << DMAC_MFIFO_VIF))) == 0 && vif1ch.chcr.STR && !vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
{
if(dmacRegs.ctrl.MFD == MFD_VIF1)
if (dmacRegs.ctrl.MFD == MFD_VIF1)
vifMFIFOInterrupt();
else
vif1Interrupt();
Expand Down Expand Up @@ -330,6 +316,10 @@ __fi void vif1Interrupt()
CPU_INT(VIF_VU1_FINISH, 16);
return;
}

if (vif1Regs.stat.VGW)
return;

if (!vif1ch.chcr.STR) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch.chcr._u32);

if (vif1.irq && vif1.vifstalled.enabled && vif1.vifstalled.value == VIF_IRQ_STALL)
Expand Down
Loading

0 comments on commit 3f56414

Please sign in to comment.