GIF: Handle PATH2 ending when VIF not running

This commit is contained in:
refractionpcsx2 2021-09-10 10:26:25 +01:00
parent c2af477758
commit 7966c27246
3 changed files with 53 additions and 11 deletions

View File

@ -108,11 +108,14 @@ int GIF_Fifo::write_fifo(u32* pMem, int size)
int writePos = fifoSize * 4;
GIF_LOG("GIF FIFO Adding %d QW to GIF FIFO at offset %d FIFO now contains %d QW", transferSize, writePos, fifoSize);
memcpy(&data[writePos], pMem, transferSize * 16);
fifoSize += transferSize;
GIF_LOG("GIF FIFO Adding %d QW to GIF FIFO at offset %d FIFO now contains %d QW", transferSize, writePos, fifoSize);
gifRegs.stat.FQC = fifoSize;
CalculateFIFOCSR();
@ -185,6 +188,13 @@ void incGifChAddr(u32 qwc)
__fi void gifCheckPathStatus(bool calledFromGIF)
{
// If GIF is running on it's own, let it handle its own timing.
if (calledFromGIF && gifch.chcr.STR)
{
if(gif_fifo.fifoSize == 16)
GifDMAInt(16);
return;
}
if (gifRegs.stat.APATH == 3)
{
gifRegs.stat.APATH = 0;
@ -222,7 +232,7 @@ __fi void gifCheckPathStatus(bool calledFromGIF)
__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);
GIF_LOG("gifInterrupt caught qwc=%d fifo=%d(%d) apath=%d oph=%d state=%d!", gifch.qwc, gifRegs.stat.FQC, gif_fifo.fifoSize, gifRegs.stat.APATH, gifRegs.stat.OPH, gifUnit.gifPath[GIF_PATH_3].state);
gifCheckPathStatus(false);
if (gifUnit.gifPath[GIF_PATH_3].state == GIF_PATH_IDLE)
@ -280,8 +290,9 @@ __fi void gifInterrupt()
}
}
}
if (((gifch.qwc > 0) || (!gif.gspath3done)) && gif_fifo.fifoSize)
// If the dma has data waiting and there's something in the fifo, drain the fifo
// If the GIF is currently paused, check if the FIFO is full, otherwise fill it
if (((gifch.qwc > 0) || (!gif.gspath3done)) && (CheckPaths() || gif_fifo.fifoSize == 16 || readSize))
return;
}
@ -791,7 +802,9 @@ void gifMFIFOInterrupt()
}
}
if (((gifch.qwc > 0) || (!gif.gspath3done)) && gif_fifo.fifoSize)
// If the dma has data waiting and there's something in the fifo, drain the fifo
// If the GIF is currently paused, check if the FIFO is full, otherwise fill it
if (((gifch.qwc > 0) || (!gif.gspath3done)) && (CheckPaths() || gif_fifo.fifoSize == 16 || readSize))
return;
}

View File

@ -327,6 +327,7 @@ struct Gif_Path
if (curOffset + 16 > curSize)
{
//GUNIT_LOG("Path Buffer: Not enough data for gif tag! [%d]", curSize-curOffset);
GUNIT_WARN("PATH %d not enough data pre tag, available %d wanted %d", gifRegs.stat.APATH, curSize - curOffset, 16);
return gsPack;
}
@ -339,11 +340,12 @@ struct Gif_Path
gifTag.setTag(&buffer[curOffset], 1);
state = (GIF_PATH_STATE)(gifTag.tag.FLG + 1);
GUNIT_WARN("PATH %d New tag State %d FLG %d EOP %d NLOOP %d", gifRegs.stat.APATH, gifRegs.stat.APATH, state, gifTag.tag.FLG, gifTag.tag.EOP, gifTag.tag.NLOOP);
// We don't have enough data for a complete GS packet
if (!gifTag.hasAD && curOffset + 16 + gifTag.len > curSize)
{
gifTag.isValid = false; // So next time we test again
GUNIT_WARN("PATH %d not enough data, available %d wanted %d", gifRegs.stat.APATH, curSize - curOffset, 16 + gifTag.len);
return gsPack;
}
@ -357,7 +359,10 @@ struct Gif_Path
while (gifTag.nLoop && !dblSIGNAL)
{
if (curOffset + 16 > curSize)
{
GUNIT_WARN("PATH %d not enough data AD, available %d wanted %d", gifRegs.stat.APATH, curSize - curOffset, 16);
return gsPack; // Exit Early
}
if (gifTag.curReg() == GIF_REG_A_D)
{
if (!isMTVU())
@ -367,7 +372,10 @@ struct Gif_Path
gifTag.packedStep();
}
if (dblSIGNAL && !(gifTag.tag.EOP && !gifTag.nLoop))
{
GUNIT_WARN("PATH %d early exit (double signal)", gifRegs.stat.APATH);
return gsPack; // Exit Early
}
}
else
incTag(curOffset, gsPack.size, gifTag.len); // Data length
@ -384,7 +392,7 @@ struct Gif_Path
gsPack.Reset();
gsPack.offset = curOffset;
GUNIT_WARN("EOP PATH %d", gifRegs.stat.APATH);
//Path 3 Masking is timing sensitive, we need to simulate its length! (NFSU2/Outrun 2006)
if ((gifRegs.stat.APATH - 1) == GIF_PATH_3)
@ -707,6 +715,7 @@ struct Gif_Unit
return 0;
}
bool didPath3 = false;
bool path3Check = isPath3;
int curPath = stat.APATH > 0 ? stat.APATH - 1 : 0; //Init to zero if no path is already set.
gifPath[2].dmaRewind = 0;
stat.OPH = 1;
@ -756,30 +765,43 @@ struct Gif_Unit
}
if (!gsSIGNAL.queued && !gifPath[0].isDone())
{
GUNIT_WARN("Swapping to PATH 1");
stat.APATH = 1;
stat.P1Q = 0;
curPath = 0;
}
else if (!gsSIGNAL.queued && !gifPath[1].isDone())
{
GUNIT_WARN("Swapping to PATH 2");
stat.APATH = 2;
stat.P2Q = 0;
curPath = 1;
}
else if (!gsSIGNAL.queued && !gifPath[2].isDone() && !Path3Masked())
{
GUNIT_WARN("Swapping to PATH 3");
stat.APATH = 3;
stat.P3Q = 0;
stat.IP3 = 0;
curPath = 2;
path3Check = true;
}
else
{
GUNIT_WARN("Finished Processing");
// 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)
if (stat.APATH == 3 || path3Check)
gifCheckPathStatus(true);
else
{
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);
}
stat.APATH = 0;
stat.OPH = 0;
}

View File

@ -230,8 +230,11 @@ vifOp(vifCode_Flush)
vif1.vifstalled.value = VIF_TIMING_BREAK;
return 0;
}
else
vif1.cmd = 0;
if (vif1.waitforvu)
return 0;
vif1.cmd = 0;
vif1.pass = 0;
}
pass3 { VifCodeLog("Flush"); }
@ -258,6 +261,10 @@ vifOp(vifCode_FlushA)
vif1.vifstalled.value = VIF_TIMING_BREAK;
return 0;
}
if (vif1.waitforvu)
return 0;
vif1.cmd = 0;
vif1.pass = 0;
}