VU Int: Combine XGKick handling in to one function

Also fixed a situation where PATH3 could transfer a packet to the GIF and finish its DMA while PATH1 was busy, so PATH3 never finished transferring properly as it relies on the DMA to handle the pretend timing of PATH3.
This commit is contained in:
refractionpcsx2 2021-09-08 17:48:30 +01:00
parent b4eaf3722f
commit c2af477758
8 changed files with 84 additions and 108 deletions

View File

@ -183,14 +183,13 @@ void incGifChAddr(u32 qwc)
DevCon.Error("incGifAddr() Error!");
}
__fi void gifCheckPathStatus()
__fi void gifCheckPathStatus(bool calledFromGIF)
{
if (gifRegs.stat.APATH == 3)
{
gifRegs.stat.APATH = 0;
gifRegs.stat.OPH = 0;
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE || gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_WAIT)
if (!calledFromGIF && (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE || gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_WAIT))
{
if (gifUnit.checkPaths(1, 1, 0))
gifUnit.Execute(false, true);
@ -200,12 +199,31 @@ __fi void gifCheckPathStatus()
// Required for Path3 Masking timing!
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_WAIT)
gifUnit.gifPath[GIF_PATH_3].state = GIF_PATH_IDLE;
// GIF DMA isn't running but VIF might be waiting on PATH3 so resume it here
if (calledFromGIF && gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
{
if (vif1Regs.stat.VGW)
{
// Check if VIF is in a cycle or is currently "idle" waiting for GIF to come back.
if (!(cpuRegs.interrupt & (1 << DMAC_VIF1)))
CPU_INT(DMAC_VIF1, 1);
// Make sure it loops if the GIF packet is empty to prepare for the next packet
// or end if it was the end of a packet.
// This must trigger after VIF retriggers as VIf might instantly mask Path3
if ((!gifUnit.Path3Masked() || gifch.qwc == 0) && (gifch.chcr.STR || gif_fifo.fifoSize))
{
GifDMAInt(16);
}
}
}
}
__fi void gifInterrupt()
{
GIF_LOG("gifInterrupt caught qwc=%d fifo=%d apath=%d oph=%d state=%d!", gifch.qwc, gifRegs.stat.FQC, gifRegs.stat.APATH, gifRegs.stat.OPH, gifUnit.gifPath[GIF_PATH_3].state);
gifCheckPathStatus();
gifCheckPathStatus(false);
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
{
@ -249,7 +267,7 @@ __fi void gifInterrupt()
if (readSize)
GifDMAInt(readSize * BIAS);
gifCheckPathStatus();
gifCheckPathStatus(false);
// Double check as we might have read the fifo as it's ending the DMA
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
{
@ -292,7 +310,7 @@ __fi void gifInterrupt()
if (gif_fifo.fifoSize)
GifDMAInt(8 * BIAS);
GIF_LOG("GIF DMA End QWC in fifo %x APATH = %x OPH = %x state = %x", gifRegs.stat.FQC, gifRegs.stat.APATH, gifRegs.stat.OPH, gifUnit.gifPath[GIF_PATH_3].state);
GIF_LOG("GIF DMA End QWC in fifo %x (%x) APATH = %x OPH = %x state = %x", gifRegs.stat.FQC, gif_fifo.fifoSize, gifRegs.stat.APATH, gifRegs.stat.OPH, gifUnit.gifPath[GIF_PATH_3].state);
}
static u32 WRITERING_DMA(u32* pMem, u32 qwc)
@ -703,7 +721,7 @@ void gifMFIFOInterrupt()
return;
}
gifCheckPathStatus();
gifCheckPathStatus(false);
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
{
@ -730,7 +748,7 @@ void gifMFIFOInterrupt()
return;
}
gifCheckPathStatus();
gifCheckPathStatus(false);
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
{
@ -759,7 +777,7 @@ void gifMFIFOInterrupt()
if (readSize)
GifDMAInt(readSize * BIAS);
gifCheckPathStatus();
gifCheckPathStatus(false);
// Double check as we might have read the fifo as it's ending the DMA
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
{

View File

@ -287,3 +287,4 @@ extern void dmaGIF();
extern void mfifoGIFtransfer();
extern void gifMFIFOInterrupt();
extern void clearFIFOstuff(bool full);
extern void gifCheckPathStatus(bool calledFromGIF);

View File

@ -775,6 +775,9 @@ struct Gif_Unit
}
else
{
// If PATH3 was stalled due to another transfer but the DMA ended, it'll never check this
// So lets quickly check if it's currently set to path3
gifCheckPathStatus(true);
if (isResume || curPath == 0)
{
stat.APATH = 0;

View File

@ -212,44 +212,7 @@ static void _vu1Exec(VURegs* VU)
if (VU->xgkickenable && (VU1.cycle - VU->xgkicklastcycle) >= 2)
{
if (VU->xgkicksizeremaining == 0)
{
u32 size = gifUnit.GetGSPacketSize(GIF_PATH_1, VU->Mem, VU->xgkickaddr);
VU->xgkicksizeremaining = size & 0xFFFF;
VU->xgkickendpacket = size >> 31;
if (VU->xgkicksizeremaining == 0)
{
VUM_LOG("Invalid GS packet size returned, cancelling XGKick");
VU->xgkickenable = false;
}
else
VUM_LOG("XGKICK New tag size %d bytes EOP %d", VU->xgkicksizeremaining, VU->xgkickendpacket);
}
u32 transfersize = std::min(VU->xgkicksizeremaining / 0x10, (VU1.cycle - VU->xgkicklastcycle) / 2);
transfersize = std::min(transfersize, VU->xgkickdiff / 0x10);
if (transfersize)
{
VUM_LOG("XGKICK Transferring %x bytes from %x size left %x", transfersize * 0x10, VU->xgkickaddr, VU->xgkicksizeremaining);
if ((transfersize * 0x10) > VU->xgkicksizeremaining)
gifUnit.gifPath[GIF_PATH_1].CopyGSPacketData(&VU->Mem[VU->xgkickaddr], transfersize * 0x10, true);
else
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &VU->Mem[VU->xgkickaddr], transfersize * 0x10, true);
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);
else
{
VUM_LOG("XGKICK transfer finished");
VU->xgkickenable = false;
}
}
_vuXGKICKTransfer(VU, (VU1.cycle - VU->xgkicklastcycle), false);
}
// Progress the write position of the FMAC pipeline by one place

View File

@ -39,44 +39,7 @@ void BaseVUmicroCPU::ExecuteBlock(bool startUp)
{
if (VU1.xgkickenable && (cpuRegs.cycle - VU1.xgkicklastcycle) >= 2)
{
if (VU1.xgkicksizeremaining == 0)
{
u32 size = gifUnit.GetGSPacketSize(GIF_PATH_1, VU1.Mem, VU1.xgkickaddr);
VU1.xgkicksizeremaining = size & 0xFFFF;
VU1.xgkickendpacket = size >> 31;
VUM_LOG("XGKICK New packet size %x", VU1.xgkicksizeremaining);
if (VU1.xgkicksizeremaining == 0)
{
VUM_LOG("Invalid GS packet size returned, cancelling XGKick");
VU1.xgkickenable = false;
return;
}
}
u32 transfersize = std::min(VU1.xgkicksizeremaining / 0x10, (cpuRegs.cycle - VU1.xgkicklastcycle) / 2);
transfersize = std::min(transfersize, VU1.xgkickdiff / 0x10);
if (transfersize)
{
VUM_LOG("XGKICK Transferring %x bytes from %x size left %x", transfersize * 0x10, VU1.xgkickaddr, VU1.xgkicksizeremaining);
if ((transfersize * 0x10) > VU1.xgkicksizeremaining)
gifUnit.gifPath[GIF_PATH_1].CopyGSPacketData(&VU1.Mem[VU1.xgkickaddr], transfersize * 0x10, true);
else
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &VU1.Mem[VU1.xgkickaddr], transfersize * 0x10, true);
VU1.xgkickaddr = (VU1.xgkickaddr + (transfersize * 0x10)) & 0x3FFF;
VU1.xgkicksizeremaining -= (transfersize * 0x10);
VU1.xgkickdiff = 0x4000 - VU1.xgkickaddr;
VU1.xgkicklastcycle += std::max(transfersize * 2, 2U);
if (VU1.xgkicksizeremaining || !VU1.xgkickendpacket)
VUM_LOG("XGKICK next addr %x left size %x", VU1.xgkickaddr, VU1.xgkicksizeremaining);
else
{
VU1.xgkickenable = false;
VUM_LOG("XGKICK transfer finished");
}
}
_vuXGKICKTransfer(&VU1, (cpuRegs.cycle - VU1.xgkicklastcycle), false);
}
}
return;

View File

@ -2317,10 +2317,15 @@ static __ri void _vuXITOP(VURegs * VU) {
else VU->VI[_It_].US[0] = VU->GetVifRegs().itop;
}
void _vuXGKICKFlush(VURegs* VU)
void _vuXGKICKTransfer(VURegs* VU, u32 cycles, bool flush)
{
if (!VU->xgkickenable)
return;
while (!VU->xgkickendpacket || VU->xgkicksizeremaining > 0)
{
u32 transfersize = 0;
if (VU->xgkicksizeremaining == 0)
{
u32 size = gifUnit.GetGSPacketSize(GIF_PATH_1, VU->Mem, VU->xgkickaddr);
@ -2338,30 +2343,52 @@ void _vuXGKICKFlush(VURegs* VU)
VUM_LOG("XGKICK New tag size %d bytes EOP %d", VU->xgkicksizeremaining, VU->xgkickendpacket);
}
VUM_LOG("XGKICK Force Transferring %x bytes from %x size left %x", VU->xgkicksizeremaining, VU->xgkickaddr, VU->xgkicksizeremaining);
if (VU->xgkicksizeremaining > VU->xgkickdiff) {
//VUM_LOG( "VU1 Int: XGkick Wrap!");
gifUnit.gifPath[GIF_PATH_1].CopyGSPacketData(&VU->Mem[VU->xgkickaddr], VU->xgkickdiff, true);
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &VU->Mem[0], VU->xgkicksizeremaining - VU->xgkickdiff, true);
if (!flush)
{
transfersize = std::min(VU->xgkicksizeremaining / 0x10, cycles / 2);
transfersize = std::min(transfersize, VU->xgkickdiff / 0x10);
}
else {
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &VU->Mem[VU->xgkickaddr], VU->xgkicksizeremaining, true);
}
VU->xgkickaddr = (VU->xgkickaddr + VU->xgkicksizeremaining) & 0x3fff;
if (VU0.VI[REG_VPU_STAT].UL & 0x100)
VU->cycle += VU->xgkicksizeremaining / 2;
VU->xgkicksizeremaining = 0;
if (!VU->xgkickendpacket)
VUM_LOG("XGKICK next addr %x left size %x EOP %d", VU->xgkickaddr, VU->xgkicksizeremaining, VU->xgkickendpacket);
else
VUM_LOG("XGKICK transfer finished");
{
transfersize = VU->xgkicksizeremaining / 0x10;
transfersize = std::min(transfersize, VU->xgkickdiff / 0x10);
}
VUM_LOG("XGKICK Transferring %x bytes from %x size %x", transfersize * 0x10, VU->xgkickaddr, VU->xgkicksizeremaining);
if ((transfersize * 0x10) < VU->xgkicksizeremaining)
gifUnit.gifPath[GIF_PATH_1].CopyGSPacketData(&VU->Mem[VU->xgkickaddr], transfersize * 0x10, true);
else
gifUnit.TransferGSPacketData(GIF_TRANS_XGKICK, &VU->Mem[VU->xgkickaddr], transfersize * 0x10, true);
if ((VU0.VI[REG_VPU_STAT].UL & 0x100) && flush)
VU->cycle += transfersize * 2;
cycles -= 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);
else
{
VUM_LOG("XGKICK transfer finished");
VU->xgkickenable = false;
// Check if VIF is waiting for the GIF to not be busy
if (vif1Regs.stat.VGW)
{
vif1Regs.stat.VGW = false;
CPU_INT(DMAC_VIF1, 8);
}
}
if (!flush && cycles < 2)
return;
}
VUM_LOG("Disabling XGKICK");
VU->xgkickenable = false;
_vuTestPipes(VU);
}
@ -2370,7 +2397,7 @@ static __ri void _vuXGKICK(VURegs * VU)
{
if (VU->xgkickenable)
{
_vuXGKICKFlush(VU);
_vuXGKICKTransfer(VU, 0, true);
}
u32 addr = (VU->VI[_Is_].US[0] & 0x3ff) * 16;

View File

@ -59,3 +59,4 @@ extern void _vuTestUpperStalls(VURegs * VU, _VURegsNum *VUregsn);
extern void _vuTestLowerStalls(VURegs * VU, _VURegsNum *VUregsn);
extern void _vuAddUpperStalls(VURegs * VU, _VURegsNum *VUregsn);
extern void _vuAddLowerStalls(VURegs * VU, _VURegsNum *VUregsn);
extern void _vuXGKICKTransfer(VURegs* VU, u32 cycles, bool flush);

View File

@ -32,7 +32,7 @@ _vifT void vifTransferLoop(u32* &data) {
vifXRegs.stat.VPS |= VPS_TRANSFERRING;
vifXRegs.stat.ER1 = false;
if(!idx)VIF_LOG("Starting VIF0 loop, pSize = %x, stalled = %x", pSize, vifX.vifstalled.enabled );
//VIF_LOG("Starting VIF%d loop, pSize = %x, stalled = %x", idx, pSize, vifX.vifstalled.enabled );
while (pSize > 0 && !vifX.vifstalled.enabled) {
if(!vifX.cmd) { // Get new VifCode