mirror of https://github.com/PCSX2/pcsx2.git
VIF/VU: Cleaned up VIF Stall behaviour, sync XGKick with Unpacks.
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
This commit is contained in:
parent
7e29a7e5a4
commit
3f56414824
|
@ -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
|
||||
|
|
|
@ -180,6 +180,7 @@ struct __aligned16 VURegs
|
|||
u32 xgkickdiff;
|
||||
u32 xgkicksizeremaining;
|
||||
u32 xgkicklastcycle;
|
||||
u32 xgkickcyclecount;
|
||||
|
||||
u8 VIBackupCycles;
|
||||
u32 VIOldValue;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -207,14 +207,13 @@ 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)
|
||||
VU->fmacwritepos = ++VU->fmacwritepos & 3;
|
||||
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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();
|
||||
|
@ -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)
|
||||
|
|
|
@ -43,6 +43,12 @@ __ri void vifExecQueue(int idx)
|
|||
if (!GetVifX.queued_program || (VU0.VI[REG_VPU_STAT].UL & 1 << (idx * 8)))
|
||||
return;
|
||||
|
||||
if (GetVifX.queued_gif_wait)
|
||||
{
|
||||
if (gifUnit.checkPaths(1, 1, 0))
|
||||
return;
|
||||
}
|
||||
|
||||
GetVifX.queued_program = false;
|
||||
|
||||
if (!idx)
|
||||
|
@ -71,7 +77,7 @@ static __fi void vifFlush(int idx)
|
|||
vifExecQueue(idx);
|
||||
}
|
||||
|
||||
static __fi void vuExecMicro(int idx, u32 addr)
|
||||
static __fi void vuExecMicro(int idx, u32 addr, bool requires_wait)
|
||||
{
|
||||
VIFregisters& vifRegs = vifXRegs;
|
||||
|
||||
|
@ -114,29 +120,12 @@ static __fi void vuExecMicro(int idx, u32 addr)
|
|||
GetVifX.queued_pc = addr & (idx ? 0x7ffu : 0x1ffu);
|
||||
GetVifX.unpackcalls = 0;
|
||||
|
||||
GetVifX.queued_gif_wait = requires_wait;
|
||||
|
||||
if (!idx || (!THREAD_VU1 && !INSTANT_VU1))
|
||||
vifExecQueue(idx);
|
||||
}
|
||||
|
||||
void ExecuteVU(int idx)
|
||||
{
|
||||
vifStruct& vifX = GetVifX;
|
||||
|
||||
if ((vifX.cmd & 0x7f) == 0x17)
|
||||
{
|
||||
vuExecMicro(idx, -1);
|
||||
vifX.cmd = 0;
|
||||
vifX.pass = 0;
|
||||
}
|
||||
else if ((vifX.cmd & 0x7f) == 0x14 || (vifX.cmd & 0x7f) == 0x15)
|
||||
{
|
||||
vuExecMicro(idx, (u16)(vifXRegs.code));
|
||||
vifX.cmd = 0;
|
||||
vifX.pass = 0;
|
||||
}
|
||||
vifExecQueue(idx);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------
|
||||
// Vif0/Vif1 Code Implementations
|
||||
//------------------------------------------------------------------
|
||||
|
@ -228,10 +217,9 @@ vifOp(vifCode_Flush)
|
|||
vif1Regs.stat.VGW = true;
|
||||
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
|
||||
vif1.vifstalled.value = VIF_TIMING_BREAK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vif1.waitforvu)
|
||||
if (vif1.waitforvu || vif1Regs.stat.VGW)
|
||||
return 0;
|
||||
|
||||
vif1.cmd = 0;
|
||||
|
@ -259,10 +247,9 @@ vifOp(vifCode_FlushA)
|
|||
vif1Regs.stat.VGW = true;
|
||||
vif1.vifstalled.enabled = VifStallEnable(vif1ch);
|
||||
vif1.vifstalled.value = VIF_TIMING_BREAK;
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (vif1.waitforvu)
|
||||
if (vif1.waitforvu || vif1Regs.stat.VGW)
|
||||
return 0;
|
||||
|
||||
vif1.cmd = 0;
|
||||
|
@ -279,6 +266,10 @@ vifOp(vifCode_FlushE)
|
|||
pass1
|
||||
{
|
||||
vifFlush(idx);
|
||||
|
||||
if (vifX.waitforvu)
|
||||
return 0;
|
||||
|
||||
vifX.cmd = 0;
|
||||
vifX.pass = 0;
|
||||
}
|
||||
|
@ -381,7 +372,7 @@ vifOp(vifCode_MPG)
|
|||
vifX.tag.size = vifNum ? (vifNum * 2) : 512;
|
||||
vifFlush(idx);
|
||||
|
||||
if (vifX.vifstalled.enabled)
|
||||
if (vifX.waitforvu)
|
||||
return 0;
|
||||
else
|
||||
{
|
||||
|
@ -426,19 +417,20 @@ vifOp(vifCode_MSCAL)
|
|||
{
|
||||
vifFlush(idx);
|
||||
|
||||
if (!vifX.waitforvu)
|
||||
if (vifX.waitforvu)
|
||||
return 0;
|
||||
|
||||
vuExecMicro(idx, (u16)(vifXRegs.code), false);
|
||||
vifX.cmd = 0;
|
||||
vifX.pass = 0;
|
||||
|
||||
if (GetVifX.vifpacketsize > 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue