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) __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;
return std::max(1, cycles); 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. // 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); u128* pMem = (u128*)dmaGetAddr(vif1ch.madr, false);
// VIF from gsMemory // VIF from gsMemory
if (pMem == NULL) { // Is vif0ptag empty? if (pMem == NULL)
{ // Is vif0ptag empty?
Console.WriteLn("Vif1 Tag BUSERR"); Console.WriteLn("Vif1 Tag BUSERR");
dmacRegs.stat.BEIS = true; // Bus Error dmacRegs.stat.BEIS = true; // Bus Error
vif1Regs.stat.FQC = 0; vif1Regs.stat.FQC = 0;
@ -55,10 +56,11 @@ void vif1TransferToMemory()
// stuff from the GS. The *only* way to handle this case safely is to flush the GS // stuff from the GS. The *only* way to handle this case safely is to flush the GS
// completely and execute the transfer there-after. // completely and execute the transfer there-after.
//Console.Warning("Real QWC %x", vif1ch.qwc); //Console.Warning("Real QWC %x", vif1ch.qwc);
const u32 size = std::min(vif1.GSLastDownloadSize, (u32)vif1ch.qwc); const u32 size = std::min(vif1.GSLastDownloadSize, (u32)vif1ch.qwc);
//const u128* pMemEnd = vif1.GSLastDownloadSize + pMem; //const u128* pMemEnd = vif1.GSLastDownloadSize + pMem;
if (size) { if (size)
{
// Checking if any crazy game does a partial // Checking if any crazy game does a partial
// gs primitive and then does a gs download... // gs primitive and then does a gs download...
Gif_Path& p1 = gifUnit.gifPath[GIF_PATH_1]; Gif_Path& p1 = gifUnit.gifPath[GIF_PATH_1];
@ -70,7 +72,7 @@ void vif1TransferToMemory()
} }
GetMTGS().InitAndReadFIFO(reinterpret_cast<u8*>(pMem), size); 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 //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. //Clearing the memory is clearing memory it shouldn't be and kills it.
@ -89,25 +91,25 @@ void vif1TransferToMemory()
g_vif1Cycles += size * 2; g_vif1Cycles += size * 2;
vif1ch.madr += size * 16; // mgs3 scene changes vif1ch.madr += size * 16; // mgs3 scene changes
if (vif1.GSLastDownloadSize >= vif1ch.qwc) { if (vif1.GSLastDownloadSize >= vif1ch.qwc)
{
vif1.GSLastDownloadSize -= vif1ch.qwc; vif1.GSLastDownloadSize -= vif1ch.qwc;
vif1Regs.stat.FQC = std::min((u32)16, vif1.GSLastDownloadSize); vif1Regs.stat.FQC = std::min((u32)16, vif1.GSLastDownloadSize);
vif1ch.qwc = 0; vif1ch.qwc = 0;
} }
else { else
{
vif1Regs.stat.FQC = 0; vif1Regs.stat.FQC = 0;
vif1ch.qwc -= vif1.GSLastDownloadSize; vif1ch.qwc -= vif1.GSLastDownloadSize;
vif1.GSLastDownloadSize = 0; vif1.GSLastDownloadSize = 0;
//This could be potentially bad and cause hangs. I guess we will find out. //This could be potentially bad and cause hangs. I guess we will find out.
DevCon.Warning("QWC left on VIF FIFO Reverse"); DevCon.Warning("QWC left on VIF FIFO Reverse");
} }
} }
bool _VIF1chain() bool _VIF1chain()
{ {
u32 *pMem; u32* pMem;
if (vif1ch.qwc == 0) if (vif1ch.qwc == 0)
{ {
@ -135,7 +137,7 @@ bool _VIF1chain()
} }
VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx", VIF_LOG("VIF1chain size=%d, madr=%lx, tadr=%lx",
vif1ch.qwc, vif1ch.madr, vif1ch.tadr); vif1ch.qwc, vif1ch.madr, vif1ch.tadr);
if (vif1.irqoffset.enabled) if (vif1.irqoffset.enabled)
return VIF1transfer(pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value, false); return VIF1transfer(pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value, false);
@ -145,20 +147,21 @@ bool _VIF1chain()
__fi void vif1SetupTransfer() __fi void vif1SetupTransfer()
{ {
tDMA_TAG *ptag; tDMA_TAG* ptag;
ptag = dmaGetAddr(vif1ch.tadr, false); //Set memory pointer to TADR 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 vif1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR
g_vif1Cycles += 1; // Add 1 g_vifCycles from the QW read for the tag g_vif1Cycles += 1; // Add 1 g_vifCycles from the QW read for the tag
vif1.inprogress &= ~1; vif1.inprogress &= ~1;
VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx", VIF_LOG("VIF1 Tag %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx",
ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr); ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr);
if (!vif1.done && ((dmacRegs.ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1 if (!vif1.done && ((dmacRegs.ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1
{ {
// there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall // there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall
if ((vif1ch.madr + vif1ch.qwc * 16) > dmacRegs.stadr.ADDR) if ((vif1ch.madr + vif1ch.qwc * 16) > dmacRegs.stadr.ADDR)
@ -177,7 +180,7 @@ __fi void vif1SetupTransfer()
bool ret; bool ret;
alignas(16) static u128 masked_tag; alignas(16) static u128 masked_tag;
masked_tag._u64[0] = 0; masked_tag._u64[0] = 0;
masked_tag._u64[1] = *((u64*)ptag + 1); masked_tag._u64[1] = *((u64*)ptag + 1);
@ -185,7 +188,7 @@ __fi void vif1SetupTransfer()
if (vif1.irqoffset.enabled) if (vif1.irqoffset.enabled)
{ {
ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall
//ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall //ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall
} }
else else
@ -194,7 +197,7 @@ __fi void vif1SetupTransfer()
// to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words // to the VU's, which breaks stuff, this is where the 128bit packet will fail, so we ignore the first 2 words
vif1.irqoffset.value = 2; vif1.irqoffset.value = 2;
vif1.irqoffset.enabled = true; vif1.irqoffset.enabled = true;
ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag
//ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
} }
@ -202,7 +205,7 @@ __fi void vif1SetupTransfer()
{ {
vif1.inprogress &= ~1; // Better clear this so it has to do it again (Jak 1) vif1.inprogress &= ~1; // Better clear this so it has to do it again (Jak 1)
vif1ch.qwc = 0; // Gumball 3000 pauses the DMA when the tag stalls so we need to reset the QWC, it'll be gotten again later vif1ch.qwc = 0; // Gumball 3000 pauses the DMA when the tag stalls so we need to reset the QWC, it'll be gotten again later
return; // IRQ set by VIFTransfer return; // IRQ set by VIFTransfer
} }
} }
vif1.irqoffset.value = 0; vif1.irqoffset.value = 0;
@ -210,14 +213,15 @@ __fi void vif1SetupTransfer()
vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); 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 //Check TIE bit of CHCR and IRQ bit of tag
if (vif1ch.chcr.TIE && ptag->IRQ) if (vif1ch.chcr.TIE && ptag->IRQ)
{ {
VIF_LOG("dmaIrq Set"); VIF_LOG("dmaIrq Set");
//End Transfer //End Transfer
vif1.done = true; vif1.done = true;
return; return;
} }
@ -228,14 +232,14 @@ __fi void vif1VUFinish()
if (VU0.VI[REG_VPU_STAT].UL & 0x500) if (VU0.VI[REG_VPU_STAT].UL & 0x500)
{ {
vu1Thread.Get_MTVUChanges(); vu1Thread.Get_MTVUChanges();
if (THREAD_VU1 && !INSTANT_VU1 && (VU0.VI[REG_VPU_STAT].UL & 0x100)) if (THREAD_VU1 && !INSTANT_VU1 && (VU0.VI[REG_VPU_STAT].UL & 0x100))
CPU_INT(VIF_VU1_FINISH, cpuGetCycles(VU_MTVU_BUSY)); CPU_INT(VIF_VU1_FINISH, cpuGetCycles(VU_MTVU_BUSY));
else else
CPU_INT(VIF_VU1_FINISH, 128); CPU_INT(VIF_VU1_FINISH, 128);
return; return;
} }
if (VU0.VI[REG_VPU_STAT].UL & 0x100) if (VU0.VI[REG_VPU_STAT].UL & 0x100)
{ {
u32 _cycles = VU1.cycle; u32 _cycles = VU1.cycle;
@ -251,7 +255,7 @@ __fi void vif1VUFinish()
vif1Regs.stat.VEW = false; vif1Regs.stat.VEW = false;
VIF_LOG("VU1 finished"); VIF_LOG("VU1 finished");
if(vif1.waitforvu) if (vif1.waitforvu)
{ {
vif1.waitforvu = false; vif1.waitforvu = false;
//Check if VIF is already scheduled to interrupt, if it's waiting, kick it :P //Check if VIF is already scheduled to interrupt, if it's waiting, kick it :P
@ -263,7 +267,7 @@ __fi void vif1VUFinish()
vif1Interrupt(); vif1Interrupt();
} }
} }
//DevCon.Warning("VU1 state cleared"); //DevCon.Warning("VU1 state cleared");
} }
@ -273,19 +277,22 @@ __fi void vif1Interrupt()
g_vif1Cycles = 0; 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.APATH = 0;
gifRegs.stat.OPH = 0; gifRegs.stat.OPH = 0;
vif1Regs.stat.VGW = false; //Let vif continue if it's stuck on a flush 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. //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"); //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. // 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); vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
vifMFIFOInterrupt(); vifMFIFOInterrupt();
return; return;
@ -293,42 +300,46 @@ __fi void vif1Interrupt()
// We need to check the direction, if it is downloading // We need to check the direction, if it is downloading
// from the GS then we handle that separately (KH2 for testing) // 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 isDirect = (vif1.cmd & 0x7f) == 0x50;
bool isDirectHL = (vif1.cmd & 0x7f) == 0x51; bool isDirectHL = (vif1.cmd & 0x7f) == 0x51;
if((isDirect && !gifUnit.CanDoPath2()) if ((isDirect && !gifUnit.CanDoPath2()) || (isDirectHL && !gifUnit.CanDoPath2HL()))
|| (isDirectHL && !gifUnit.CanDoPath2HL())) { {
GUNIT_WARN("vif1Interrupt() - Waiting for Path 2 to be ready"); GUNIT_WARN("vif1Interrupt() - Waiting for Path 2 to be ready");
CPU_INT(DMAC_VIF1, 128); 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; return;
} }
vif1Regs.stat.VGW = 0; //Path 3 isn't busy so we don't need to wait for it. vif1Regs.stat.VGW = 0; //Path 3 isn't busy so we don't need to wait for it.
vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16); vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16);
//Simulated GS transfer time done, clear the flags //Simulated GS transfer time done, clear the flags
} }
if(vif1.waitforvu) if (vif1.waitforvu)
{ {
//DevCon.Warning("Waiting on VU1"); //DevCon.Warning("Waiting on VU1");
//CPU_INT(DMAC_VIF1, 16); //CPU_INT(DMAC_VIF1, 16);
CPU_INT(VIF_VU1_FINISH, 16); CPU_INT(VIF_VU1_FINISH, std::max(16, cpuGetCycles(VU_MTVU_BUSY)));
return; return;
} }
if (vif1Regs.stat.VGW) if (vif1Regs.stat.VGW)
return; 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) if (vif1.irq && vif1.vifstalled.enabled && vif1.vifstalled.value == VIF_IRQ_STALL)
{ {
VIF_LOG("VIF IRQ Firing"); VIF_LOG("VIF IRQ Firing");
if (!vif1Regs.stat.ER1) if (!vif1Regs.stat.ER1)
vif1Regs.stat.INT = true; vif1Regs.stat.INT = true;
//Yakuza watches VIF_STAT so lets do this here. //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; 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) //NFSHPS stalls when the whole packet has gone across (it stalls in the last 32bit cmd)
//In this case VIF will end //In this case VIF will end
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc); 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) 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"); VIF_LOG("VIF1 Stalled");
@ -356,40 +367,62 @@ __fi void vif1Interrupt()
//Mirroring change to VIF0 //Mirroring change to VIF0
if (vif1.cmd) 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 else
{ {
vif1Regs.stat.VPS = VPS_IDLE; vif1Regs.stat.VPS = VPS_IDLE;
} }
if (vif1.inprogress & 0x1) if (vif1.inprogress & 0x1)
{ {
_VIF1chain(); _VIF1chain();
// VIF_NORMAL_FROM_MEM_MODE is a very slow operation. // VIF_NORMAL_FROM_MEM_MODE is a very slow operation.
// Timesplitters 2 depends on this beeing a bit higher than 128. // 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); CPU_INT(DMAC_VIF1, g_vif1Cycles);
return; }
} return;
}
if (!vif1.done) if (!vif1.done)
{ {
if (!(dmacRegs.ctrl.DMAE) || vif1Regs.stat.VSS) //Stopped or DMA Disabled if (!(dmacRegs.ctrl.DMAE) || vif1Regs.stat.VSS) //Stopped or DMA Disabled
{ {
//Console.WriteLn("vif1 dma masked"); //Console.WriteLn("vif1 dma masked");
return; return;
} }
if ((vif1.inprogress & 0x1) == 0) vif1SetupTransfer(); if ((vif1.inprogress & 0x1) == 0)
if (vif1ch.chcr.DIR) vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16); 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!)
CPU_INT(DMAC_VIF1, g_vif1Cycles); {
return; 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;
} }
if (vif1.vifstalled.enabled && vif1.done) if (vif1.vifstalled.enabled && vif1.done)
@ -399,52 +432,55 @@ __fi void vif1Interrupt()
return; //Dont want to end if vif is stalled. return; //Dont want to end if vif is stalled.
} }
#ifdef PCSX2_DEVBUILD #ifdef PCSX2_DEVBUILD
if (vif1ch.qwc > 0) DevCon.WriteLn("VIF1 Ending with %x QWC left", vif1ch.qwc); if (vif1ch.qwc > 0)
if (vif1.cmd != 0) DevCon.WriteLn("vif1.cmd still set %x tag size %x", vif1.cmd, vif1.tag.size); 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 #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 //Reverse fifo has finished and nothing is left, so lets clear the outputting flag
gifRegs.stat.OPH = false; 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; vif1ch.chcr.STR = false;
vif1.vifstalled.enabled = false; vif1.vifstalled.enabled = false;
vif1.irqoffset.enabled = false; vif1.irqoffset.enabled = false;
if(vif1.queued_program) vifExecQueue(1); if (vif1.queued_program)
vifExecQueue(1);
g_vif1Cycles = 0; g_vif1Cycles = 0;
VIF_LOG("VIF1 DMA End"); VIF_LOG("VIF1 DMA End");
hwDmacIrq(DMAC_VIF1); hwDmacIrq(DMAC_VIF1);
} }
void dmaVIF1() void dmaVIF1()
{ {
VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n"
" tadr = %lx, asr0 = %lx, asr1 = %lx", " tadr = %lx, asr0 = %lx, asr1 = %lx",
vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc, vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc,
vif1ch.tadr, vif1ch.asr0, vif1ch.asr1); vif1ch.tadr, vif1ch.asr0, vif1ch.asr1);
g_vif1Cycles = 0; g_vif1Cycles = 0;
vif1.inprogress = 0; vif1.inprogress = 0;
if (vif1ch.qwc > 0) // Normal Mode if (vif1ch.qwc > 0) // Normal Mode
{ {
// ignore tag if it's a GS download (Def Jam Fight for NY) // 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; vif1.dmamode = VIF_CHAIN_MODE;
//DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc()); //DevCon.Warning(L"VIF1 QWC on Chain CHCR " + vif1ch.chcr.desc());
if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END) || (vif1ch.chcr.tag().IRQ && vif1ch.chcr.TIE)) if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END) || (vif1ch.chcr.tag().IRQ && vif1ch.chcr.TIE))
{ {
vif1.done = true; vif1.done = true;
} }
else else
{ {
vif1.done = false; vif1.done = false;
} }
@ -454,12 +490,13 @@ void dmaVIF1()
if (dmacRegs.ctrl.STD == STD_VIF1) if (dmacRegs.ctrl.STD == STD_VIF1)
Console.WriteLn("DMA Stall Control on VIF1 normal not implemented - Report which game to PCSX2 Team"); Console.WriteLn("DMA Stall Control on VIF1 normal not implemented - Report which game to PCSX2 Team");
if (vif1ch.chcr.DIR) // from Memory if (vif1ch.chcr.DIR) // from Memory
vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE; vif1.dmamode = VIF_NORMAL_FROM_MEM_MODE;
else else
vif1.dmamode = VIF_NORMAL_TO_MEM_MODE; 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; vif1.done = true;
} }
@ -470,10 +507,10 @@ void dmaVIF1()
vif1.inprogress &= ~0x1; vif1.inprogress &= ~0x1;
vif1.dmamode = VIF_CHAIN_MODE; vif1.dmamode = VIF_CHAIN_MODE;
vif1.done = false; 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. // 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 // Batman Vengence does something stupid and instead of cancelling a stall it tries to restart VIF, THEN check the stall

View File

@ -27,9 +27,9 @@ static u32 qwctag(u32 mask)
static u32 QWCinVIFMFIFO(u32 DrainADDR, u32 qwc) static u32 QWCinVIFMFIFO(u32 DrainADDR, u32 qwc)
{ {
u32 ret; u32 ret;
//Calculate what we have in the fifo. //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 //Drain is below the tadr, calculate the difference between them
ret = (spr0ch.madr - DrainADDR) >> 4; ret = (spr0ch.madr - DrainADDR) >> 4;
@ -37,7 +37,7 @@ static u32 QWCinVIFMFIFO(u32 DrainADDR, u32 qwc)
else else
{ {
u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
//Drain is higher than SPR so it has looped round, //Drain is higher than SPR so it has looped round,
//calculate from base to the SPR tag addr and what is left in the top of the ring //calculate from base to the SPR tag addr and what is left in the top of the ring
ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4; ret = ((spr0ch.madr - dmacRegs.rbor.ADDR) + (limit - DrainADDR)) >> 4;
} }
@ -50,18 +50,19 @@ static __fi bool mfifoVIF1rbTransfer()
{ {
u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16;
u32 mfifoqwc = std::min(QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc), vif1ch.qwc); u32 mfifoqwc = std::min(QWCinVIFMFIFO(vif1ch.madr, vif1ch.qwc), vif1ch.qwc);
u32 *src; u32* src;
bool ret; bool ret;
if (mfifoqwc == 0) { if (mfifoqwc == 0)
{
DevCon.Warning("VIF MFIFO no QWC before transfer (in transfer function, bit late really)"); DevCon.Warning("VIF MFIFO no QWC before transfer (in transfer function, bit late really)");
return true; //Cant do anything, lets forget it return true; //Cant do anything, lets forget it
} }
/* Check if the transfer should wrap around the ring buffer */ /* Check if the transfer should wrap around the ring buffer */
if ((vif1ch.madr + (mfifoqwc << 4)) > (msize)) if ((vif1ch.madr + (mfifoqwc << 4)) > (msize))
{ {
int s1 = ((msize) - vif1ch.madr) >> 2; int s1 = ((msize)-vif1ch.madr) >> 2;
VIF_LOG("Split MFIFO"); VIF_LOG("Split MFIFO");
@ -69,7 +70,8 @@ static __fi bool mfifoVIF1rbTransfer()
vif1ch.madr = qwctag(vif1ch.madr); vif1ch.madr = qwctag(vif1ch.madr);
src = (u32*)PSM(vif1ch.madr); src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false; if (src == NULL)
return false;
if (vif1.irqoffset.enabled) if (vif1.irqoffset.enabled)
ret = VIF1transfer(src + vif1.irqoffset.value, s1 - vif1.irqoffset.value); ret = VIF1transfer(src + vif1.irqoffset.value, s1 - vif1.irqoffset.value);
@ -78,15 +80,17 @@ static __fi bool mfifoVIF1rbTransfer()
if (ret) if (ret)
{ {
if(vif1.irqoffset.value != 0) DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset.value); if (vif1.irqoffset.value != 0)
/* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset.value);
/* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
//DevCon.Warning("Loopyloop"); //DevCon.Warning("Loopyloop");
vif1ch.tadr = qwctag(vif1ch.tadr); vif1ch.tadr = qwctag(vif1ch.tadr);
vif1ch.madr = qwctag(vif1ch.madr); vif1ch.madr = qwctag(vif1ch.madr);
src = (u32*)PSM(vif1ch.madr); src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false; if (src == NULL)
VIF1transfer(src, ((mfifoqwc << 2) - s1)); return false;
VIF1transfer(src, ((mfifoqwc << 2) - s1));
} }
} }
else else
@ -95,7 +99,8 @@ static __fi bool mfifoVIF1rbTransfer()
/* it doesn't, so just transfer 'qwc*4' words */ /* it doesn't, so just transfer 'qwc*4' words */
src = (u32*)PSM(vif1ch.madr); src = (u32*)PSM(vif1ch.madr);
if (src == NULL) return false; if (src == NULL)
return false;
if (vif1.irqoffset.enabled) if (vif1.irqoffset.enabled)
ret = VIF1transfer(src + vif1.irqoffset.value, mfifoqwc * 4 - vif1.irqoffset.value); ret = VIF1transfer(src + vif1.irqoffset.value, mfifoqwc * 4 - vif1.irqoffset.value);
@ -115,10 +120,11 @@ static __fi void mfifo_VIF1chain()
} }
if (vif1ch.madr >= dmacRegs.rbor.ADDR && if (vif1ch.madr >= dmacRegs.rbor.ADDR &&
vif1ch.madr < (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16u)) vif1ch.madr < (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16u))
{ {
//if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1"); //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"); VIF_LOG("VIF MFIFO Empty before transfer");
vif1.inprogress |= 0x10; vif1.inprogress |= 0x10;
g_vif1Cycles += 4; 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) //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. //with a QWC of 1 (rare) so we need to increment the TADR in the case of MFIFO.
vif1ch.tadr = vif1ch.madr; vif1ch.tadr = vif1ch.madr;
} }
else else
{ {
tDMA_TAG *pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR); tDMA_TAG* pMem = dmaGetAddr(vif1ch.madr, !vif1ch.chcr.DIR);
VIF_LOG("Non-MFIFO Location"); 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 //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) if (vif1.irqoffset.enabled)
VIF1transfer((u32*)pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value); 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) 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) //These five transfer data following the tag, need to check its within the buffer (Front Mission 4)
case TAG_CNT: case TAG_CNT:
case TAG_NEXT: case TAG_NEXT:
case TAG_CALL: case TAG_CALL:
case TAG_RET: case TAG_RET:
case TAG_END: 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); //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); 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); //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); vif1ch.madr = qwctag(vif1ch.madr);
@ -178,13 +185,14 @@ void mfifoVifMaskMem(int id)
void mfifoVIF1transfer() void mfifoVIF1transfer()
{ {
tDMA_TAG *ptag; tDMA_TAG* ptag;
g_vif1Cycles = 0; g_vif1Cycles = 0;
if (vif1ch.qwc == 0) if (vif1ch.qwc == 0)
{ {
if (QWCinVIFMFIFO(vif1ch.tadr, 1) == 0) { if (QWCinVIFMFIFO(vif1ch.tadr, 1) == 0)
{
VIF_LOG("VIF MFIFO Empty before tag"); VIF_LOG("VIF MFIFO Empty before tag");
vif1.inprogress |= 0x10; vif1.inprogress |= 0x10;
g_vif1Cycles += 4; g_vif1Cycles += 4;
@ -212,21 +220,20 @@ void mfifoVIF1transfer()
if (vif1.irqoffset.enabled) if (vif1.irqoffset.enabled)
{ {
ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall ret = VIF1transfer((u32*)&masked_tag + vif1.irqoffset.value, 4 - vif1.irqoffset.value, true); //Transfer Tag on stall
//ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall //ret = VIF1transfer((u32*)ptag + (2 + vif1.irqoffset), 2 - vif1.irqoffset); //Transfer Tag on stall
} }
else else
{ {
vif1.irqoffset.value = 2; vif1.irqoffset.value = 2;
vif1.irqoffset.enabled = true; vif1.irqoffset.enabled = true;
ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag
} }
if (!ret && vif1.irqoffset.enabled) if (!ret && vif1.irqoffset.enabled)
{ {
vif1.inprogress &= ~1; vif1.inprogress &= ~1;
return; //IRQ set by VIFTransfer return; //IRQ set by VIFTransfer
} }
g_vif1Cycles += 2; g_vif1Cycles += 2;
} }
@ -234,12 +241,12 @@ void mfifoVIF1transfer()
vif1.irqoffset.value = 0; vif1.irqoffset.value = 0;
vif1.irqoffset.enabled = false; vif1.irqoffset.enabled = false;
vif1ch.unsafeTransfer(ptag); vif1ch.unsafeTransfer(ptag);
vif1ch.madr = ptag[1]._u32; vif1ch.madr = ptag[1]._u32;
VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx spr0 madr = %x", VIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx spr0 madr = %x",
ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, spr0ch.madr); ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, spr0ch.madr);
vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID);
@ -253,13 +260,14 @@ void mfifoVIF1transfer()
vif1ch.tadr = qwctag(vif1ch.tadr); vif1ch.tadr = qwctag(vif1ch.tadr);
if(vif1ch.qwc > 0) vif1.inprogress |= 1; if (vif1ch.qwc > 0)
vif1.inprogress |= 1;
} }
else else
{ {
DevCon.Warning("Vif MFIFO QWC not 0 on tag"); DevCon.Warning("Vif MFIFO QWC not 0 on tag");
} }
VIF_LOG("mfifoVIF1transfer end %x madr %x, tadr %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr); VIF_LOG("mfifoVIF1transfer end %x madr %x, tadr %x", vif1ch.chcr._u32, vif1ch.madr, vif1ch.tadr);
} }
@ -269,33 +277,36 @@ void vifMFIFOInterrupt()
g_vif1Cycles = 0; g_vif1Cycles = 0;
VIF_LOG("vif mfifo interrupt"); VIF_LOG("vif mfifo interrupt");
if (dmacRegs.ctrl.MFD != MFD_VIF1) { if (dmacRegs.ctrl.MFD != MFD_VIF1)
{
vif1Interrupt(); vif1Interrupt();
return; 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.APATH = 0;
gifRegs.stat.OPH = 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 isDirect = (vif1.cmd & 0x7f) == 0x50;
bool isDirectHL = (vif1.cmd & 0x7f) == 0x51; bool isDirectHL = (vif1.cmd & 0x7f) == 0x51;
if((isDirect && !gifUnit.CanDoPath2()) if ((isDirect && !gifUnit.CanDoPath2()) || (isDirectHL && !gifUnit.CanDoPath2HL()))
|| (isDirectHL && !gifUnit.CanDoPath2HL())) { {
GUNIT_WARN("vifMFIFOInterrupt() - Waiting for Path 2 to be ready"); GUNIT_WARN("vifMFIFOInterrupt() - Waiting for Path 2 to be ready");
CPU_INT(DMAC_MFIFO_VIF, 128); CPU_INT(DMAC_MFIFO_VIF, 128);
return; return;
} }
} }
if(vif1.waitforvu) if (vif1.waitforvu)
{ {
// DevCon.Warning("Waiting on VU1 MFIFO"); //DevCon.Warning("Waiting on VU1 MFIFO");
CPU_INT(VIF_VU1_FINISH, 16); CPU_INT(VIF_VU1_FINISH, std::max(16, cpuGetCycles(VU_MTVU_BUSY)));
return; return;
} }
@ -303,25 +314,29 @@ void vifMFIFOInterrupt()
// we handle that separately (KH2 for testing) // we handle that separately (KH2 for testing)
// Simulated GS transfer time done, clear the flags // 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"); VIF_LOG("VIF MFIFO Code Interrupt detected");
vif1Regs.stat.INT = true; vif1Regs.stat.INT = true;
if (((vif1Regs.code >> 24) & 0x7f) != 0x7) { if (((vif1Regs.code >> 24) & 0x7f) != 0x7)
{
vif1Regs.stat.VIS = true; vif1Regs.stat.VIS = true;
} }
hwIntcIrq(INTC_VIF1); hwIntcIrq(INTC_VIF1);
--vif1.irq; --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 //vif1Regs.stat.FQC = 0; // FQC=0
//vif1ch.chcr.STR = false; //vif1ch.chcr.STR = false;
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc); 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); 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. //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) 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"); VIF_LOG("VIF1 MFIFO Stalled");
return; return;
@ -330,33 +345,48 @@ void vifMFIFOInterrupt()
} }
//Mirroring change to VIF0 //Mirroring change to VIF0
if (vif1.cmd) { 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 { else
{
vif1Regs.stat.VPS = VPS_IDLE; vif1Regs.stat.VPS = VPS_IDLE;
} }
if(vif1.inprogress & 0x10) { if (vif1.inprogress & 0x10)
{
FireMFIFOEmpty(); FireMFIFOEmpty();
return; return;
} }
vif1.vifstalled.enabled = false; vif1.vifstalled.enabled = false;
if (!vif1.done || vif1ch.qwc) { if (!vif1.done || vif1ch.qwc)
switch(vif1.inprogress & 1) { {
switch (vif1.inprogress & 1)
{
case 0: //Set up transfer case 0: //Set up transfer
mfifoVIF1transfer(); mfifoVIF1transfer();
vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc); vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
[[fallthrough]]; [[fallthrough]];
case 1: //Transfer data 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(); mfifo_VIF1chain();
//Sanity check! making sure we always have non-zero values //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!) 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 (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); vif1Regs.stat.FQC = std::min((u32)0x10, vif1ch.qwc);
return; return;
@ -368,7 +398,8 @@ void vifMFIFOInterrupt()
vif1.irqoffset.enabled = false; vif1.irqoffset.enabled = false;
vif1.done = 1; vif1.done = 1;
if (spr0ch.madr == vif1ch.tadr) { if (spr0ch.madr == vif1ch.tadr)
{
FireMFIFOEmpty(); FireMFIFOEmpty();
} }