VIF: Wait for VU on flush + clang format

Improves performance in MTVU + Non-instant a little.
This commit is contained in:
refractionpcsx2 2022-07-30 09:29:27 +01:00
parent 38ee8ccfe3
commit b058e72fdd
3 changed files with 221 additions and 148 deletions

View File

@ -248,9 +248,14 @@ __fi void cpuSetNextEventDelta( s32 delta )
__fi int cpuGetCycles(int interrupt)
{
int cycles = (cpuRegs.sCycle[interrupt] + cpuRegs.eCycle[interrupt]) - cpuRegs.cycle;
if(interrupt == VU_MTVU_BUSY && (!THREAD_VU1 || INSTANT_VU1))
return 1;
else
{
const int cycles = (cpuRegs.sCycle[interrupt] + cpuRegs.eCycle[interrupt]) - cpuRegs.cycle;
return std::max(1, cycles);
}
}
// tests the cpu cycle against the given start and delta values.

View File

@ -40,7 +40,8 @@ void vif1TransferToMemory()
u128* pMem = (u128*)dmaGetAddr(vif1ch.madr, false);
// VIF from gsMemory
if (pMem == NULL) { // Is vif0ptag empty?
if (pMem == NULL)
{ // Is vif0ptag empty?
Console.WriteLn("Vif1 Tag BUSERR");
dmacRegs.stat.BEIS = true; // Bus Error
vif1Regs.stat.FQC = 0;
@ -58,7 +59,8 @@ void vif1TransferToMemory()
const u32 size = std::min(vif1.GSLastDownloadSize, (u32)vif1ch.qwc);
//const u128* pMemEnd = vif1.GSLastDownloadSize + pMem;
if (size) {
if (size)
{
// Checking if any crazy game does a partial
// gs primitive and then does a gs download...
Gif_Path& p1 = gifUnit.gifPath[GIF_PATH_1];
@ -70,7 +72,7 @@ void vif1TransferToMemory()
}
GetMTGS().InitAndReadFIFO(reinterpret_cast<u8*>(pMem), size);
// pMem += size;
// pMem += size;
//Some games such as Alex Ferguson's Player Manager 2001 reads less than GSLastDownloadSize by VIF then reads the remainder by FIFO
//Clearing the memory is clearing memory it shouldn't be and kills it.
@ -89,25 +91,25 @@ void vif1TransferToMemory()
g_vif1Cycles += size * 2;
vif1ch.madr += size * 16; // mgs3 scene changes
if (vif1.GSLastDownloadSize >= vif1ch.qwc) {
if (vif1.GSLastDownloadSize >= vif1ch.qwc)
{
vif1.GSLastDownloadSize -= vif1ch.qwc;
vif1Regs.stat.FQC = std::min((u32)16, vif1.GSLastDownloadSize);
vif1ch.qwc = 0;
}
else {
else
{
vif1Regs.stat.FQC = 0;
vif1ch.qwc -= vif1.GSLastDownloadSize;
vif1.GSLastDownloadSize = 0;
//This could be potentially bad and cause hangs. I guess we will find out.
DevCon.Warning("QWC left on VIF FIFO Reverse");
}
}
bool _VIF1chain()
{
u32 *pMem;
u32* pMem;
if (vif1ch.qwc == 0)
{
@ -145,11 +147,12 @@ bool _VIF1chain()
__fi void vif1SetupTransfer()
{
tDMA_TAG *ptag;
tDMA_TAG* ptag;
ptag = dmaGetAddr(vif1ch.tadr, false); //Set memory pointer to TADR
if (!(vif1ch.transfer("Vif1 Tag", ptag))) return;
if (!(vif1ch.transfer("Vif1 Tag", ptag)))
return;
vif1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
g_vif1Cycles += 1; // Add 1 g_vifCycles from the QW read for the tag
@ -210,7 +213,8 @@ __fi void vif1SetupTransfer()
vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID);
if(vif1ch.qwc > 0) vif1.inprogress |= 1;
if (vif1ch.qwc > 0)
vif1.inprogress |= 1;
//Check TIE bit of CHCR and IRQ bit of tag
if (vif1ch.chcr.TIE && ptag->IRQ)
@ -251,7 +255,7 @@ __fi void vif1VUFinish()
vif1Regs.stat.VEW = false;
VIF_LOG("VU1 finished");
if(vif1.waitforvu)
if (vif1.waitforvu)
{
vif1.waitforvu = false;
//Check if VIF is already scheduled to interrupt, if it's waiting, kick it :P
@ -273,19 +277,22 @@ __fi void vif1Interrupt()
g_vif1Cycles = 0;
if( gifRegs.stat.APATH == 2 && gifUnit.gifPath[GIF_PATH_2].isDone())
if (gifRegs.stat.APATH == 2 && gifUnit.gifPath[GIF_PATH_2].isDone())
{
gifRegs.stat.APATH = 0;
gifRegs.stat.OPH = 0;
vif1Regs.stat.VGW = false; //Let vif continue if it's stuck on a flush
if(gifUnit.checkPaths(1,0,1)) gifUnit.Execute(false, true);
if (gifUnit.checkPaths(1, 0, 1))
gifUnit.Execute(false, true);
}
//Some games (Fahrenheit being one) start vif first, let it loop through blankness while it sets MFIFO mode, so we need to check it here.
if (dmacRegs.ctrl.MFD == MFD_VIF1) {
if (dmacRegs.ctrl.MFD == MFD_VIF1)
{
//Console.WriteLn("VIFMFIFO\n");
// Test changed because the Final Fantasy 12 opening somehow has the tag in *Undefined* mode, which is not in the documentation that I saw.
if (vif1ch.chcr.MOD == NORMAL_MODE) Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch.chcr._u32);
if (vif1ch.chcr.MOD == NORMAL_MODE)
Console.WriteLn("MFIFO mode is normal (which isn't normal here)! %x", vif1ch.chcr._u32);
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
vifMFIFOInterrupt();
return;
@ -293,14 +300,16 @@ __fi void vif1Interrupt()
// We need to check the direction, if it is downloading
// from the GS then we handle that separately (KH2 for testing)
if (vif1ch.chcr.DIR) {
if (vif1ch.chcr.DIR)
{
bool isDirect = (vif1.cmd & 0x7f) == 0x50;
bool isDirectHL = (vif1.cmd & 0x7f) == 0x51;
if((isDirect && !gifUnit.CanDoPath2())
|| (isDirectHL && !gifUnit.CanDoPath2HL())) {
if ((isDirect && !gifUnit.CanDoPath2()) || (isDirectHL && !gifUnit.CanDoPath2HL()))
{
GUNIT_WARN("vif1Interrupt() - Waiting for Path 2 to be ready");
CPU_INT(DMAC_VIF1, 128);
if(gifRegs.stat.APATH == 3) vif1Regs.stat.VGW = 1; //We're waiting for path 3. Gunslinger II
if (gifRegs.stat.APATH == 3)
vif1Regs.stat.VGW = 1; //We're waiting for path 3. Gunslinger II
return;
}
vif1Regs.stat.VGW = 0; //Path 3 isn't busy so we don't need to wait for it.
@ -308,18 +317,19 @@ __fi void vif1Interrupt()
//Simulated GS transfer time done, clear the flags
}
if(vif1.waitforvu)
if (vif1.waitforvu)
{
//DevCon.Warning("Waiting on VU1");
//CPU_INT(DMAC_VIF1, 16);
CPU_INT(VIF_VU1_FINISH, 16);
CPU_INT(VIF_VU1_FINISH, std::max(16, cpuGetCycles(VU_MTVU_BUSY)));
return;
}
if (vif1Regs.stat.VGW)
return;
if (!vif1ch.chcr.STR) Console.WriteLn("Vif1 running when CHCR == %x", vif1ch.chcr._u32);
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)
{
@ -328,7 +338,8 @@ __fi void vif1Interrupt()
vif1Regs.stat.INT = true;
//Yakuza watches VIF_STAT so lets do this here.
if (((vif1Regs.code >> 24) & 0x7f) != 0x7) {
if (((vif1Regs.code >> 24) & 0x7f) != 0x7)
{
vif1Regs.stat.VIS = true;
}
@ -342,7 +353,7 @@ __fi void vif1Interrupt()
//NFSHPS stalls when the whole packet has gone across (it stalls in the last 32bit cmd)
//In this case VIF will end
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
if((vif1ch.qwc > 0 || !vif1.done) && !CHECK_VIF1STALLHACK)
if ((vif1ch.qwc > 0 || !vif1.done) && !CHECK_VIF1STALLHACK)
{
vif1Regs.stat.VPS = VPS_DECODING; //If there's more data you need to say it's decoding the next VIF CMD (Onimusha - Blade Warriors)
VIF_LOG("VIF1 Stalled");
@ -356,7 +367,8 @@ __fi void vif1Interrupt()
//Mirroring change to VIF0
if (vif1.cmd)
{
if (vif1.done && (vif1ch.qwc == 0)) vif1Regs.stat.VPS = VPS_WAITING;
if (vif1.done && (vif1ch.qwc == 0))
vif1Regs.stat.VPS = VPS_WAITING;
}
else
{
@ -368,10 +380,20 @@ __fi void vif1Interrupt()
_VIF1chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128.
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
if (!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
{
if (vif1.waitforvu)
{
//if (cpuGetCycles(VU_MTVU_BUSY) > static_cast<int>(g_vif1Cycles))
// DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast<int>(g_vif1Cycles));
CPU_INT(DMAC_VIF1, std::max(static_cast<int>(g_vif1Cycles), cpuGetCycles(VU_MTVU_BUSY)));
}
else
CPU_INT(DMAC_VIF1, g_vif1Cycles);
}
return;
}
@ -384,11 +406,22 @@ __fi void vif1Interrupt()
return;
}
if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer();
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if ((vif1.inprogress & 0x1) == 0)
vif1SetupTransfer();
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
if (!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
{
if (vif1.waitforvu)
{
//if (cpuGetCycles(VU_MTVU_BUSY) > static_cast<int>(g_vif1Cycles))
// DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast<int>(g_vif1Cycles));
CPU_INT(DMAC_VIF1, std::max(static_cast<int>(g_vif1Cycles), cpuGetCycles(VU_MTVU_BUSY)));
}
else
CPU_INT(DMAC_VIF1, g_vif1Cycles);
}
return;
}
@ -399,26 +432,29 @@ __fi void vif1Interrupt()
return; //Dont want to end if vif is stalled.
}
#ifdef PCSX2_DEVBUILD
if (vif1ch.qwc > 0) DevCon.WriteLn("VIF1 Ending with %x QWC left", vif1ch.qwc);
if (vif1.cmd != 0) DevCon.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size);
if (vif1ch.qwc > 0)
DevCon.WriteLn("VIF1 Ending with %x QWC left", vif1ch.qwc);
if (vif1.cmd != 0)
DevCon.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size);
#endif
if((vif1ch.chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16)
if ((vif1ch.chcr.DIR == VIF_NORMAL_TO_MEM_MODE) && vif1.GSLastDownloadSize <= 16)
{
//Reverse fifo has finished and nothing is left, so lets clear the outputting flag
gifRegs.stat.OPH = false;
}
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
vif1ch.chcr.STR = false;
vif1.vifstalled.enabled = false;
vif1.irqoffset.enabled = false;
if(vif1.queued_program) vifExecQueue(1);
if (vif1.queued_program)
vifExecQueue(1);
g_vif1Cycles = 0;
VIF_LOG("VIF1 DMA End");
hwDmacIrq(DMAC_VIF1);
}
void dmaVIF1()
@ -435,7 +471,7 @@ void dmaVIF1()
{
// ignore tag if it's a GS download (Def Jam Fight for NY)
if(vif1ch.chcr.MOD == CHAIN_MODE && vif1ch.chcr.DIR)
if (vif1ch.chcr.MOD == CHAIN_MODE && vif1ch.chcr.DIR)
{
vif1.dmamode = VIF_CHAIN_MODE;
//DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc());
@ -459,7 +495,8 @@ void dmaVIF1()
else
vif1.dmamode = VIF_NORMAL_TO_MEM_MODE;
if(vif1.irqoffset.enabled && !vif1.done) DevCon.Warning("Warning! VIF1 starting a Normal transfer with vif offset set (Possible force stop?)");
if (vif1.irqoffset.enabled && !vif1.done)
DevCon.Warning("Warning! VIF1 starting a Normal transfer with vif offset set (Possible force stop?)");
vif1.done = true;
}
@ -470,10 +507,10 @@ void dmaVIF1()
vif1.inprogress &= ~0x1;
vif1.dmamode = VIF_CHAIN_MODE;
vif1.done = false;
}
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
if (vif1ch.chcr.DIR)
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
// Check VIF isn't stalled before starting the loop.
// Batman Vengence does something stupid and instead of cancelling a stall it tries to restart VIF, THEN check the stall

View File

@ -29,7 +29,7 @@ static u32 QWCinVIFMFIFO(u32 DrainADDR, u32 qwc)
u32 ret;
//Calculate what we have in the fifo.
if(DrainADDR <= spr0ch.madr)
if (DrainADDR <= spr0ch.madr)
{
//Drain is below the tadr, calculate the difference between them
ret = (spr0ch.madr - DrainADDR) >> 4;
@ -50,10 +50,11 @@ static __fi bool mfifoVIF1rbTransfer()
{
u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
u32 mfifoqwc = std::min(QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc), vif1ch.qwc);
u32 *src;
u32* src;
bool ret;
if (mfifoqwc == 0) {
if (mfifoqwc == 0)
{
DevCon.Warning("VIF MFIFO no QWC before transfer (in transfer function, bit late really)");
return true; //Cant do anything, lets forget it
}
@ -61,7 +62,7 @@ static __fi bool mfifoVIF1rbTransfer()
/* Check if the transfer should wrap around the ring buffer */
if ((vif1ch.madr + (mfifoqwc << 4)) > (msize))
{
int s1 = ((msize) - vif1ch.madr) >> 2;
int s1 = ((msize)-vif1ch.madr) >> 2;
VIF_LOG("Split MFIFO");
@ -69,7 +70,8 @@ static __fi bool mfifoVIF1rbTransfer()
vif1ch.madr = qwctag(vif1ch.madr);
src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false;
if (src == NULL)
return false;
if (vif1.irqoffset.enabled)
ret = VIF1transfer(src + vif1.irqoffset.value, s1 - vif1.irqoffset.value);
@ -78,14 +80,16 @@ static __fi bool mfifoVIF1rbTransfer()
if (ret)
{
if(vif1.irqoffset.value != 0) DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset.value);
if (vif1.irqoffset.value != 0)
DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset.value);
/* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
//DevCon.Warning("Loopyloop");
vif1ch.tadr = qwctag(vif1ch.tadr);
vif1ch.madr = qwctag(vif1ch.madr);
src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false;
if (src == NULL)
return false;
VIF1transfer(src, ((mfifoqwc << 2) - s1));
}
}
@ -95,7 +99,8 @@ static __fi bool mfifoVIF1rbTransfer()
/* it doesn't, so just transfer 'qwc*4' words */
src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false;
if (src == NULL)
return false;
if (vif1.irqoffset.enabled)
ret = VIF1transfer(src + vif1.irqoffset.value, mfifoqwc * 4 - vif1.irqoffset.value);
@ -118,7 +123,8 @@ static __fi void mfifo_VIF1chain()
vif1ch.madr < (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16u))
{
//if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1");
if (QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc) == 0) {
if (QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc) == 0)
{
VIF_LOG("VIF MFIFO Empty before transfer");
vif1.inprogress |= 0x10;
g_vif1Cycles += 4;
@ -132,16 +138,16 @@ static __fi void mfifo_VIF1chain()
//It does an END tag (which normally doesn't increment TADR because it breaks Soul Calibur 2)
//with a QWC of 1 (rare) so we need to increment the TADR in the case of MFIFO.
vif1ch.tadr = vif1ch.madr;
}
else
{
tDMA_TAG *pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
tDMA_TAG* pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
VIF_LOG("Non-MFIFO Location");
//No need to exit on non-mfifo as it is indirect anyway, so it can be transferring this while spr refills the mfifo
if (pMem == NULL) return;
if (pMem == NULL)
return;
if (vif1.irqoffset.enabled)
VIF1transfer((u32*)pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value);
@ -152,19 +158,20 @@ static __fi void mfifo_VIF1chain()
void mfifoVifMaskMem(int id)
{
switch (id) {
switch (id)
{
//These five transfer data following the tag, need to check its within the buffer (Front Mission 4)
case TAG_CNT:
case TAG_NEXT:
case TAG_CALL:
case TAG_RET:
case TAG_END:
if(vif1ch.madr < dmacRegs.rbor.ADDR) //probably not needed but we will check anyway.
if (vif1ch.madr < dmacRegs.rbor.ADDR) //probably not needed but we will check anyway.
{
//DevCon.Warning("VIF MFIFO MADR below bottom of ring buffer, wrapping VIF MADR = %x Ring Bottom %x", vif1ch.madr, dmacRegs.rbor.ADDR);
vif1ch.madr = qwctag(vif1ch.madr);
}
if(vif1ch.madr > (dmacRegs.rbor.ADDR + (u32)dmacRegs.rbsr.RMSK)) //Usual scenario is the tag is near the end (Front Mission 4)
if (vif1ch.madr > (dmacRegs.rbor.ADDR + (u32)dmacRegs.rbsr.RMSK)) //Usual scenario is the tag is near the end (Front Mission 4)
{
//DevCon.Warning("VIF MFIFO MADR outside top of ring buffer, wrapping VIF MADR = %x Ring Top %x", vif1ch.madr, (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)+16);
vif1ch.madr = qwctag(vif1ch.madr);
@ -178,13 +185,14 @@ void mfifoVifMaskMem(int id)
void mfifoVIF1transfer()
{
tDMA_TAG *ptag;
tDMA_TAG* ptag;
g_vif1Cycles = 0;
if (vif1ch.qwc == 0)
{
if (QWCinVIFMFIFO(vif1ch.tadr, 1) == 0) {
if (QWCinVIFMFIFO(vif1ch.tadr, 1) == 0)
{
VIF_LOG("VIF MFIFO Empty before tag");
vif1.inprogress |= 0x10;
g_vif1Cycles += 4;
@ -226,7 +234,6 @@ void mfifoVIF1transfer()
{
vif1.inprogress &= ~1;
return; //IRQ set by VIFTransfer
}
g_vif1Cycles += 2;
}
@ -253,7 +260,8 @@ void mfifoVIF1transfer()
vif1ch.tadr = qwctag(vif1ch.tadr);
if(vif1ch.qwc > 0) vif1.inprogress |= 1;
if (vif1ch.qwc > 0)
vif1.inprogress |= 1;
}
else
{
@ -269,33 +277,36 @@ void vifMFIFOInterrupt()
g_vif1Cycles = 0;
VIF_LOG("vif mfifo interrupt");
if (dmacRegs.ctrl.MFD != MFD_VIF1) {
if (dmacRegs.ctrl.MFD != MFD_VIF1)
{
vif1Interrupt();
return;
}
if( gifRegs.stat.APATH == 2 && gifUnit.gifPath[1].isDone())
if (gifRegs.stat.APATH == 2 && gifUnit.gifPath[1].isDone())
{
gifRegs.stat.APATH = 0;
gifRegs.stat.OPH = 0;
if(gifUnit.checkPaths(1,0,1)) gifUnit.Execute(false, true);
if (gifUnit.checkPaths(1, 0, 1))
gifUnit.Execute(false, true);
}
if (vif1ch.chcr.DIR) {
if (vif1ch.chcr.DIR)
{
bool isDirect = (vif1.cmd & 0x7f) == 0x50;
bool isDirectHL = (vif1.cmd & 0x7f) == 0x51;
if((isDirect && !gifUnit.CanDoPath2())
|| (isDirectHL && !gifUnit.CanDoPath2HL())) {
if ((isDirect && !gifUnit.CanDoPath2()) || (isDirectHL && !gifUnit.CanDoPath2HL()))
{
GUNIT_WARN("vifMFIFOInterrupt() - Waiting for Path 2 to be ready");
CPU_INT(DMAC_MFIFO_VIF, 128);
return;
}
}
if(vif1.waitforvu)
if (vif1.waitforvu)
{
// DevCon.Warning("Waiting on VU1 MFIFO");
CPU_INT(VIF_VU1_FINISH, 16);
//DevCon.Warning("Waiting on VU1 MFIFO");
CPU_INT(VIF_VU1_FINISH, std::max(16, cpuGetCycles(VU_MTVU_BUSY)));
return;
}
@ -304,24 +315,28 @@ void vifMFIFOInterrupt()
// Simulated GS transfer time done, clear the flags
if (vif1.irq && vif1.vifstalled.enabled && vif1.vifstalled.value == VIF_IRQ_STALL) {
if (vif1.irq && vif1.vifstalled.enabled && vif1.vifstalled.value == VIF_IRQ_STALL)
{
VIF_LOG("VIF MFIFO Code Interrupt detected");
vif1Regs.stat.INT = true;
if (((vif1Regs.code >> 24) & 0x7f) != 0x7) {
if (((vif1Regs.code >> 24) & 0x7f) != 0x7)
{
vif1Regs.stat.VIS = true;
}
hwIntcIrq(INTC_VIF1);
--vif1.irq;
if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS)) {
if (vif1Regs.stat.test(VIF1_STAT_VSS | VIF1_STAT_VIS | VIF1_STAT_VFS))
{
//vif1Regs.stat.FQC = 0; // FQC=0
//vif1ch.chcr.STR = false;
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
VIF_LOG("VIF1 MFIFO Stalled qwc = %x done = %x inprogress = %x", vif1ch.qwc, vif1.done, vif1.inprogress & 0x10);
//Used to check if the MFIFO was empty, there's really no need if it's finished what it needed.
if((vif1ch.qwc > 0 || !vif1.done)) {
if ((vif1ch.qwc > 0 || !vif1.done))
{
vif1Regs.stat.VPS = VPS_DECODING; //If there's more data you need to say it's decoding the next VIF CMD (Onimusha - Blade Warriors)
VIF_LOG("VIF1 MFIFO Stalled");
return;
@ -330,33 +345,48 @@ void vifMFIFOInterrupt()
}
//Mirroring change to VIF0
if (vif1.cmd) {
if (vif1.done && vif1ch.qwc == 0) vif1Regs.stat.VPS = VPS_WAITING;
if (vif1.cmd)
{
if (vif1.done && vif1ch.qwc == 0)
vif1Regs.stat.VPS = VPS_WAITING;
}
else {
else
{
vif1Regs.stat.VPS = VPS_IDLE;
}
if(vif1.inprogress & 0x10) {
if (vif1.inprogress & 0x10)
{
FireMFIFOEmpty();
return;
}
vif1.vifstalled.enabled = false;
if (!vif1.done || vif1ch.qwc) {
switch(vif1.inprogress & 1) {
if (!vif1.done || vif1ch.qwc)
{
switch (vif1.inprogress & 1)
{
case 0: //Set up transfer
mfifoVIF1transfer();
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
[[fallthrough]];
case 1: //Transfer data
if(vif1.inprogress & 0x1) //Just in case the tag breaks early (or something wierd happens)!
if (vif1.inprogress & 0x1) //Just in case the tag breaks early (or something wierd happens)!
mfifo_VIF1chain();
//Sanity check! making sure we always have non-zero values
if(!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
CPU_INT(DMAC_MFIFO_VIF, (g_vif1Cycles == 0 ? 4 : g_vif1Cycles) );
if (!(vif1Regs.stat.VGW && gifUnit.gifPath[GIF_PATH_3].state != GIF_PATH_IDLE)) //If we're waiting on GIF, stop looping, (can be over 1000 loops!)
{
if (vif1.waitforvu)
{
//if (cpuGetCycles(VU_MTVU_BUSY) > static_cast<int>(g_vif1Cycles))
// DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast<int>(g_vif1Cycles));
CPU_INT(DMAC_MFIFO_VIF, std::max(static_cast<int>((g_vif1Cycles == 0 ? 4 : g_vif1Cycles)), cpuGetCycles(VU_MTVU_BUSY)));
}
else
CPU_INT(DMAC_MFIFO_VIF, (g_vif1Cycles == 0 ? 4 : g_vif1Cycles));
}
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
return;
@ -368,7 +398,8 @@ void vifMFIFOInterrupt()
vif1.irqoffset.enabled = false;
vif1.done = 1;
if (spr0ch.madr == vif1ch.tadr) {
if (spr0ch.madr == vif1ch.tadr)
{
FireMFIFOEmpty();
}