From b058e72fdd6c47ec5b3727634695341f6aecdbc9 Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Sat, 30 Jul 2022 09:29:27 +0100 Subject: [PATCH] VIF: Wait for VU on flush + clang format Improves performance in MTVU + Non-instant a little. --- pcsx2/R5900.cpp | 11 ++- pcsx2/Vif1_Dma.cpp | 207 +++++++++++++++++++++++++------------------ pcsx2/Vif1_MFIFO.cpp | 151 ++++++++++++++++++------------- 3 files changed, 221 insertions(+), 148 deletions(-) diff --git a/pcsx2/R5900.cpp b/pcsx2/R5900.cpp index a43cfb9c29..785ff68573 100644 --- a/pcsx2/R5900.cpp +++ b/pcsx2/R5900.cpp @@ -248,9 +248,14 @@ __fi void cpuSetNextEventDelta( s32 delta ) __fi int cpuGetCycles(int interrupt) { - int cycles = (cpuRegs.sCycle[interrupt] + cpuRegs.eCycle[interrupt]) - cpuRegs.cycle; - - return std::max(1, cycles); + 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. diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index e93a88a9bd..4e67ec10b0 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -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; @@ -55,10 +56,11 @@ void vif1TransferToMemory() // stuff from the GS. The *only* way to handle this case safely is to flush the GS // completely and execute the transfer there-after. //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; - 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(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) { @@ -135,7 +137,7 @@ bool _VIF1chain() } 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) return VIF1transfer(pMem + vif1.irqoffset.value, vif1ch.qwc * 4 - vif1.irqoffset.value, false); @@ -145,20 +147,21 @@ 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 + vif1ch.madr = ptag[1]._u32; //MADR = ADDR field + SPR g_vif1Cycles += 1; // Add 1 g_vifCycles from the QW read for the tag vif1.inprogress &= ~1; 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 if ((vif1ch.madr + vif1ch.qwc * 16) > dmacRegs.stadr.ADDR) @@ -177,7 +180,7 @@ __fi void vif1SetupTransfer() bool ret; alignas(16) static u128 masked_tag; - + masked_tag._u64[0] = 0; masked_tag._u64[1] = *((u64*)ptag + 1); @@ -185,7 +188,7 @@ __fi void vif1SetupTransfer() 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 } 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 vif1.irqoffset.value = 2; 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 } @@ -202,7 +205,7 @@ __fi void vif1SetupTransfer() { 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 - return; // IRQ set by VIFTransfer + return; // IRQ set by VIFTransfer } } vif1.irqoffset.value = 0; @@ -210,14 +213,15 @@ __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) { VIF_LOG("dmaIrq Set"); - //End Transfer + //End Transfer vif1.done = true; return; } @@ -228,14 +232,14 @@ __fi void vif1VUFinish() if (VU0.VI[REG_VPU_STAT].UL & 0x500) { vu1Thread.Get_MTVUChanges(); - + if (THREAD_VU1 && !INSTANT_VU1 && (VU0.VI[REG_VPU_STAT].UL & 0x100)) CPU_INT(VIF_VU1_FINISH, cpuGetCycles(VU_MTVU_BUSY)); else CPU_INT(VIF_VU1_FINISH, 128); return; } - + if (VU0.VI[REG_VPU_STAT].UL & 0x100) { u32 _cycles = VU1.cycle; @@ -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 @@ -263,7 +267,7 @@ __fi void vif1VUFinish() vif1Interrupt(); } } - + //DevCon.Warning("VU1 state cleared"); } @@ -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,42 +300,46 @@ __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) { - bool isDirect = (vif1.cmd & 0x7f) == 0x50; + 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. vif1Regs.stat.FQC = std::min(vif1ch.qwc, (u32)16); //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) { VIF_LOG("VIF IRQ Firing"); if (!vif1Regs.stat.ER1) 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,40 +367,62 @@ __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 { vif1Regs.stat.VPS = VPS_IDLE; } - + if (vif1.inprogress & 0x1) - { - _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(!(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!) + { + _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 (!(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(g_vif1Cycles)) + // DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast(g_vif1Cycles)); + CPU_INT(DMAC_VIF1, std::max(static_cast(g_vif1Cycles), cpuGetCycles(VU_MTVU_BUSY))); + } + else 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 - { - //Console.WriteLn("vif1 dma masked"); - return; - } + if (!(dmacRegs.ctrl.DMAE) || vif1Regs.stat.VSS) //Stopped or DMA Disabled + { + //Console.WriteLn("vif1 dma masked"); + 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!) - CPU_INT(DMAC_VIF1, g_vif1Cycles); - return; + 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(g_vif1Cycles)) + // DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast(g_vif1Cycles)); + CPU_INT(DMAC_VIF1, std::max(static_cast(g_vif1Cycles), cpuGetCycles(VU_MTVU_BUSY))); + } + else + CPU_INT(DMAC_VIF1, g_vif1Cycles); + } + return; } if (vif1.vifstalled.enabled && vif1.done) @@ -399,52 +432,55 @@ __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() { VIF_LOG("dmaVIF1 chcr = %lx, madr = %lx, qwc = %lx\n" - " tadr = %lx, asr0 = %lx, asr1 = %lx", - vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc, - vif1ch.tadr, vif1ch.asr0, vif1ch.asr1); + " tadr = %lx, asr0 = %lx, asr1 = %lx", + vif1ch.chcr._u32, vif1ch.madr, vif1ch.qwc, + vif1ch.tadr, vif1ch.asr0, vif1ch.asr1); g_vif1Cycles = 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) - 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()); - + if ((vif1ch.chcr.tag().ID == TAG_REFE) || (vif1ch.chcr.tag().ID == TAG_END) || (vif1ch.chcr.tag().IRQ && vif1ch.chcr.TIE)) { vif1.done = true; } - else + else { vif1.done = false; } @@ -454,12 +490,13 @@ void dmaVIF1() if (dmacRegs.ctrl.STD == STD_VIF1) 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; 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 diff --git a/pcsx2/Vif1_MFIFO.cpp b/pcsx2/Vif1_MFIFO.cpp index 4eff4a7928..5e2f9d7961 100644 --- a/pcsx2/Vif1_MFIFO.cpp +++ b/pcsx2/Vif1_MFIFO.cpp @@ -27,9 +27,9 @@ static u32 qwctag(u32 mask) 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; @@ -37,7 +37,7 @@ static u32 QWCinVIFMFIFO(u32 DrainADDR, u32 qwc) else { 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 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 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 + return true; //Cant do anything, lets forget it } /* 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,15 +80,17 @@ static __fi bool mfifoVIF1rbTransfer() if (ret) { - 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]' */ + 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; - VIF1transfer(src, ((mfifoqwc << 2) - s1)); + src = (u32*)PSM(vif1ch.madr); + if (src == NULL) + return false; + VIF1transfer(src, ((mfifoqwc << 2) - s1)); } } else @@ -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); @@ -115,10 +120,11 @@ static __fi void mfifo_VIF1chain() } 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 (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_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; @@ -212,21 +220,20 @@ void mfifoVIF1transfer() 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 } else { vif1.irqoffset.value = 2; 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) { vif1.inprogress &= ~1; - return; //IRQ set by VIFTransfer - + return; //IRQ set by VIFTransfer } g_vif1Cycles += 2; } @@ -234,12 +241,12 @@ void mfifoVIF1transfer() vif1.irqoffset.value = 0; vif1.irqoffset.enabled = false; - vif1ch.unsafeTransfer(ptag); + vif1ch.unsafeTransfer(ptag); vif1ch.madr = ptag[1]._u32; 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); @@ -253,13 +260,14 @@ void mfifoVIF1transfer() vif1ch.tadr = qwctag(vif1ch.tadr); - if(vif1ch.qwc > 0) vif1.inprogress |= 1; + if (vif1ch.qwc > 0) + vif1.inprogress |= 1; } else { 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); } @@ -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) { - bool isDirect = (vif1.cmd & 0x7f) == 0x50; + 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; } @@ -303,25 +314,29 @@ void vifMFIFOInterrupt() // we handle that separately (KH2 for testing) // 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(g_vif1Cycles)) + // DevCon.Warning("Waiting %d instead of %d", cpuGetCycles(VU_MTVU_BUSY), static_cast(g_vif1Cycles)); + CPU_INT(DMAC_MFIFO_VIF, std::max(static_cast((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(); }