diff --git a/pcsx2/Dmac.h b/pcsx2/Dmac.h index d22145677f..9dededbe0d 100644 --- a/pcsx2/Dmac.h +++ b/pcsx2/Dmac.h @@ -556,7 +556,9 @@ extern tDMA_TAG *dmaGetAddr(u32 addr, bool write); extern void hwIntcIrq(int n); extern void hwDmacIrq(int n); +extern void FireMFIFOEmpty(); extern bool hwMFIFOWrite(u32 addr, const u128* data, uint size_qwc); +extern void hwDmacSrcTadrInc(DMACh& dma); extern bool hwDmacSrcChainWithStack(DMACh& dma, int id); extern bool hwDmacSrcChain(DMACh& dma, int id); diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index d3d2840451..c152cb8e83 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -234,6 +234,7 @@ bool CheckPaths(int Channel) { if((vif1.cmd & 0x7f) != 0x51 || gifRegs.stat.P1Q == true) { + //DevCon.Warning("GIF Stall 1 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); gifRegs.stat.IP3 = true; if(gifRegs.stat.P1Q) gsPath1Interrupt(); CPU_INT(DMAC_GIF, 16); @@ -246,6 +247,7 @@ bool CheckPaths(int Channel) //This should cover both scenarios, as DIRECTHL doesn't gain priority when image mode is running (PENDINGIMAGE_MODE == fininshed). if((gifRegs.stat.P1Q == true || gifRegs.stat.P2Q == true) || (gifRegs.stat.APATH > GIF_APATH_IDLE && gifRegs.stat.APATH < GIF_APATH3)) { + //DevCon.Warning("GIF Stall 2 P1Q %x P2Q %x APATH %x PTH3 %x vif1cmd %x", gifRegs.stat.P1Q, gifRegs.stat.P2Q, gifRegs.stat.APATH, GSTransferStatus.PTH3, vif1.cmd); gifRegs.stat.IP3 = true; CPU_INT(DMAC_GIF, 16); return false; @@ -440,51 +442,85 @@ void dmaGIF() GIFdma(); } +static u16 QWCinGIFMFIFO(u32 DrainADDR) +{ + u32 ret; + + + GIF_LOG("GIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", gifch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR); + //Calculate what we have in the fifo. + if(DrainADDR <= spr0ch.madr) + { + //Drain is below the tadr, calculate the difference between them + ret = (spr0ch.madr - DrainADDR) >> 4; + } + else + { + u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; + //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; + } + GIF_LOG("%x Available of the %x requested", ret, gifch.qwc); + if((s32)ret < 0) DevCon.Warning("GIF Returning %x!", ret); + return ret; +} + // called from only one location, so forceinline it: static __fi bool mfifoGIFrbTransfer() { - u32 mfifoqwc = min(gifqwc, (u32)gifch.qwc); + u16 mfifoqwc = min(QWCinGIFMFIFO(gifch.madr), gifch.qwc); u32 *src; + if(mfifoqwc == 0) return true; //Lets skip all this, we don't have the data + GetMTGS().PrepDataPacket(GIF_PATH_3, mfifoqwc); // TODO (minor optimization): The new GIFpath parser can do rather efficient wrapping of // its own internally now. We just need to groom a version of it that can wrap around MFIFO // memory similarly to how it wraps VU1 memory on PATH1. - + GIF_LOG("MFIFO QWC to Transfer %x", mfifoqwc); /* Check if the transfer should wrap around the ring buffer */ - if ((gifch.madr + mfifoqwc * 16) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) + if ( (gifch.madr + (mfifoqwc * 16)) > (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) { uint s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4; uint s2 = (mfifoqwc - s1); - + GIF_LOG("Split transfer doing %x QWC of %x Total QWC", s1, mfifoqwc); /* it does (wrap around), so first copy 's1' bytes from 'addr' to 'data' */ /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ - + + gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); src = (u32*)PSM(gifch.madr); if (src == NULL) return false; uint copied = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s1); if (copied == s1) // but only copy second if first didn't abort prematurely for some reason. { + GIF_LOG("Transferring last %x QWC", s2); src = (u32*)PSM(dmacRegs.rbor.ADDR); + gifch.madr = dmacRegs.rbor.ADDR; if (src == NULL) return false; copied += GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s2); } mfifoqwc = copied; + GIF_LOG("Copied %x QWC, %x QWC Left", mfifoqwc, gifch.qwc); } else { + GIF_LOG("Direct MFIFO transfer doing %x Total QWC", mfifoqwc); /* it doesn't, so just transfer 'qwc*16' words from 'gifch.madr' to GS */ + + gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); src = (u32*)PSM(gifch.madr); if (src == NULL) return false; mfifoqwc = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, mfifoqwc); - gifch.madr = dmacRegs.rbor.ADDR + (gifch.madr & dmacRegs.rbsr.RMSK); + GIF_LOG("%X QWC Copied direct %x QWC Left", mfifoqwc, gifch.qwc); } GetMTGS().SendDataPacket(); - gifqwc -= mfifoqwc; + //gifqwc -= mfifoqwc; + mfifocycles += (mfifoqwc) * 2; /* guessing */ return true; } @@ -496,14 +532,19 @@ static __fi bool mfifoGIFchain() if (gifch.qwc == 0) return true; if (gifch.madr >= dmacRegs.rbor.ADDR && - gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)) + gifch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) { - if (!mfifoGIFrbTransfer()) return false; + bool ret = true; + if(gifch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge GIF"); + if (!mfifoGIFrbTransfer()) ret = false; + if(QWCinGIFMFIFO(gifch.madr) == 0) gifstate |= GIF_STATE_EMPTY; + return ret; + } else { int mfifoqwc; - + GIF_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc); tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false); if (pMem == NULL) return false; @@ -528,12 +569,13 @@ void mfifoGIFtransfer(int qwc) if(qwc > 0 ) { - gifqwc += qwc; - - if (!(gifstate & GIF_STATE_EMPTY)) return; - // if (gifempty == false) return; - gifstate &= ~GIF_STATE_EMPTY; - gifempty = false; + if ((gifstate & GIF_STATE_EMPTY) && !(cpuRegs.interrupt & (1< 1 ) DevCon.WriteLn("gif mfifo tadr==madr but qwc = %d", gifqwc); - hwDmacIrq(DMAC_MFIFO_EMPTY); - gifstate |= GIF_STATE_EMPTY; - gifempty = true; - return; - } - gifch.tadr = qwctag(gifch.tadr); ptag = dmaGetAddr(gifch.tadr, false); @@ -565,42 +598,10 @@ void mfifoGIFtransfer(int qwc) GIF_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", ptag[1]._u32, ptag[0]._u32, gifch.qwc, ptag->ID, gifch.madr, gifch.tadr, gifqwc, spr0ch.madr); - gifqwc--; + gspath3done = hwDmacSrcChainWithStack(gifch, ptag->ID); - switch (ptag->ID) - { - case TAG_REFE: // Refe - Transfer Packet According to ADDR field - gifch.tadr = qwctag(gifch.tadr + 16); - gifstate = GIF_STATE_DONE; //End Transfer - break; - - case TAG_CNT: // CNT - Transfer QWC following the tag. - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to QW after Tag - gifch.tadr = qwctag(gifch.madr + (gifch.qwc << 4)); //Set TADR to QW following the data - gifstate = GIF_STATE_READY; - break; - - case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR - { - u32 temp = gifch.madr; //Temporarily Store ADDR - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to QW following the tag - gifch.tadr = temp; //Copy temporarily stored ADDR to Tag - gifstate = GIF_STATE_READY; - break; - } - - case TAG_REF: // Ref - Transfer QWC from ADDR field - case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) - gifch.tadr = qwctag(gifch.tadr + 16); //Set TADR to next tag - gifstate = GIF_STATE_READY; - break; - - case TAG_END: // End - Transfer QWC following the tag - gifch.madr = qwctag(gifch.tadr + 16); //Set MADR to data following the tag - gifch.tadr = qwctag(gifch.madr + (gifch.qwc << 4)); //Set TADR to QW following the data - gifstate = GIF_STATE_DONE; //End Transfer - break; - } + if(gspath3done == true) gifstate = GIF_STATE_DONE; + else gifstate = GIF_STATE_READY; if ((gifch.chcr.TIE) && (ptag->IRQ)) { @@ -608,7 +609,8 @@ void mfifoGIFtransfer(int qwc) gifstate = GIF_STATE_DONE; gifmfifoirq = true; } - } + if (QWCinGIFMFIFO(gifch.tadr) == 0) gifstate |= GIF_STATE_EMPTY; + } if (!mfifoGIFchain()) { @@ -616,7 +618,7 @@ void mfifoGIFtransfer(int qwc) gifstate = GIF_STATE_STALL; } - if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate = GIF_STATE_STALL; + if ((gifch.qwc == 0) && (gifstate & GIF_STATE_DONE)) gifstate |= GIF_STATE_STALL; CPU_INT(DMAC_MFIFO_GIF,mfifocycles); SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gifch.chcr._u32, gifch.madr, gifch.tadr); @@ -624,9 +626,21 @@ void mfifoGIFtransfer(int qwc) void gifMFIFOInterrupt() { - //Console.WriteLn("gifMFIFOInterrupt"); + GIF_LOG("gifMFIFOInterrupt"); mfifocycles = 0; + if((gifstate & GIF_STATE_EMPTY)) + { + FireMFIFOEmpty(); + if(!(gifstate & GIF_STATE_STALL)) return; + } + + if (dmacRegs.ctrl.MFD != MFD_GIF) + { + DevCon.Warning("Not in GIF MFIFO mode! Stopping GIF MFIFO"); + return; + } + if(SIGNAL_IMR_Pending == true) { //DevCon.Warning("Path 3 Paused"); @@ -634,9 +648,10 @@ void gifMFIFOInterrupt() return; } - if(GSTransferStatus.PTH3 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH3 ) + if(GSTransferStatus.PTH3 >= PENDINGSTOP_MODE && gifRegs.stat.APATH == GIF_APATH3 ) { gifRegs.stat.OPH = false; + GSTransferStatus.PTH3 = STOPPED_MODE; gifRegs.stat.APATH = GIF_APATH_IDLE; if(gifRegs.stat.P1Q) gsPath1Interrupt(); } @@ -652,16 +667,13 @@ void gifMFIFOInterrupt() if (!(gifstate & GIF_STATE_STALL)) { - if (gifqwc <= 0) + if (QWCinGIFMFIFO(gifch.tadr) == 0) { - //Console.WriteLn("Empty"); - hwDmacIrq(DMAC_MFIFO_EMPTY); gifstate |= GIF_STATE_EMPTY; - gifempty = true; - - gifRegs.stat.IMT = false; + CPU_INT(DMAC_MFIFO_GIF, 4); return; } + mfifoGIFtransfer(0); return; } @@ -685,6 +697,7 @@ void gifMFIFOInterrupt() gifch.chcr.STR = false; gifstate = GIF_STATE_READY; hwDmacIrq(DMAC_GIF); + GIF_LOG("gifMFIFO End"); clearFIFOstuff(false); } diff --git a/pcsx2/Gif.h b/pcsx2/Gif.h index 6a03820659..d02ddf14c9 100644 --- a/pcsx2/Gif.h +++ b/pcsx2/Gif.h @@ -26,7 +26,7 @@ enum gifstate_t enum GSTransferModes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet { - PENDINGIMAGE_MODE = 0, + WAITING_MODE = 0, IMAGE_MODE = 1, TRANSFER_MODE = 2, PENDINGSTOP_MODE = 3, diff --git a/pcsx2/Hw.cpp b/pcsx2/Hw.cpp index f9fbec01e7..237865f475 100644 --- a/pcsx2/Hw.cpp +++ b/pcsx2/Hw.cpp @@ -130,6 +130,14 @@ void hwDmacIrq(int n) if(psHu16(DMAC_STAT+2) & (1< ((dmacRegs.rbsr.RMSK + 16) >> 4)) DevCon.Warning("MFIFO Write bigger than MFIFO! QWC=%x FifoSize=%x", qwc, ((dmacRegs.rbsr.RMSK + 16) >> 4)); // DMAC Address resolution: FIFO can be placed anywhere in the *physical* memory map // for the PS2. Its probably a serious error for a PS2 app to have the buffer cross // valid/invalid page areas of ram, so realistically we only need to test the base address @@ -162,13 +171,15 @@ __ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc) __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) { switch (id) { case TAG_REFE: // Refe - Transfer Packet According to ADDR field + dma.tadr += 16; //End Transfer return true; case TAG_CNT: // CNT - Transfer QWC following the tag. // Set MADR to QW afer tag, and set TADR to QW following the data. - dma.madr = dma.tadr + 16; - dma.tadr = dma.madr + (dma.qwc << 4); + dma.tadr += 16; + dma.madr = dma.tadr; + //dma.tadr = dma.madr + (dma.qwc << 4); return false; case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR @@ -267,6 +278,33 @@ __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) { return false; } + +/********TADR NOTES*********** +From what i've gathered from testing tadr increment stuff (with CNT) is that we might not be 100% accurate in what +increments it and what doesnt. Previously we presumed REFE and END didn't increment the tag, but SIF and IPU never +liked this. + +From what i've deduced, REFE does in fact increment, but END doesn't, after much testing, i've concluded this is how +we can standardize DMA chains, so i've modified the code to work like this. The below function controls the increment +of the TADR along with the MADR on VIF, GIF and SPR1 when using the CNT tag, the others don't use it yet, but they +can probably be modified to do so now. + +Reason for this:- Many games (such as clock tower 3 and FFX Videos) watched the TADR to see when a transfer has finished, +so we need to simulate this wherever we can! Even the FFX video gets corruption and tries to fire multiple DMA Kicks +if this doesnt happen, which was the reasoning for the hacked up SPR timing we had, that is no longer required. + +-Refraction +******************************/ + +void hwDmacSrcTadrInc(DMACh& dma) +{ + u16 tagid = (dma.chcr.TAG >> 12) & 0x7; + + if(tagid == TAG_CNT) + { + dma.tadr = dma.madr; + } +} bool hwDmacSrcChain(DMACh& dma, int id) { u32 temp; @@ -280,7 +318,7 @@ bool hwDmacSrcChain(DMACh& dma, int id) case TAG_CNT: // CNT - Transfer QWC following the tag. // Set MADR to QW after the tag, and TADR to QW following the data. dma.madr = dma.tadr + 16; - dma.tadr = dma.madr + (dma.qwc << 4); + dma.tadr = dma.madr; return false; case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR @@ -305,3 +343,4 @@ bool hwDmacSrcChain(DMACh& dma, int id) return false; } + diff --git a/pcsx2/IPU/IPUdma.cpp b/pcsx2/IPU/IPUdma.cpp index 857d3fc922..f430980df5 100644 --- a/pcsx2/IPU/IPUdma.cpp +++ b/pcsx2/IPU/IPUdma.cpp @@ -42,21 +42,6 @@ void SaveStateBase::ipuDmaFreeze() Freeze(IPU1Status); } -static __fi bool ipuDmacPartialChain(tDMA_TAG tag) -{ - switch (tag.ID) - { - case TAG_REFE: // refe - ipu1dma.tadr += 16; - return true; - - case TAG_END: // end - ipu1dma.tadr = ipu1dma.madr; - return true; - } - return false; -} - static __fi void ipuDmacSrcChain() { switch (IPU1Status.ChainMode) @@ -82,7 +67,7 @@ static __fi void ipuDmacSrcChain() break; case TAG_END: // end - ipu1dma.tadr = ipu1dma.madr; + //ipu1dma.tadr = ipu1dma.madr; IPU1Status.DMAFinished = true; break; } @@ -136,15 +121,12 @@ static __fi int IPU1chain() { ipu1dma.qwc -= qwc; totalqwc += qwc; } + + //Update TADR etc + if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); + if( ipu1dma.qwc == 0) - { - //Update TADR etc - if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); - //If the transfer has finished or we have room in the FIFO, schedule to the interrupt code. - - //No data left IPU1Status.InProgress = false; - } //If we still have data the commands should pull this across when need be. return totalqwc; } @@ -238,7 +220,8 @@ int IPU1dma() break; case TAG_CNT: // cnt - ipu1dma.madr = ipu1dma.tadr + 16; + ipu1dma.tadr += 16; + ipu1dma.madr = ipu1dma.tadr; IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16); //ipu1dma.tadr = ipu1dma.madr + (ipu1dma.qwc * 16); // Set the taddr to the next tag @@ -262,7 +245,7 @@ int IPU1dma() case TAG_END: // end // do not change tadr ipu1dma.madr = ipu1dma.tadr + 16; - ipu1dma.tadr += 16; + //ipu1dma.tadr += 16; IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16); break; diff --git a/pcsx2/SPR.cpp b/pcsx2/SPR.cpp index 5ea0243ae9..3164661e0a 100644 --- a/pcsx2/SPR.cpp +++ b/pcsx2/SPR.cpp @@ -86,7 +86,7 @@ int _SPR0chain() __fi void SPR0chain() { - CPU_INT(DMAC_FROM_SPR, _SPR0chain() / BIAS); + CPU_INT(DMAC_FROM_SPR, _SPR0chain() * BIAS); spr0ch.qwc = 0; } @@ -102,7 +102,7 @@ void _SPR0interleave() SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr0ch.qwc, tqwc, sqwc, spr0ch.madr, spr0ch.sadr); - CPU_INT(DMAC_FROM_SPR, qwc / BIAS); + CPU_INT(DMAC_FROM_SPR, qwc * BIAS); while (qwc > 0) { @@ -290,13 +290,14 @@ int _SPR1chain() SPR1transfer(pMem, spr1ch.qwc); spr1ch.madr += spr1ch.qwc * 16; + hwDmacSrcTadrInc(spr1ch); return (spr1ch.qwc); } __fi void SPR1chain() { - CPU_INT(DMAC_TO_SPR, _SPR1chain() / BIAS); + CPU_INT(DMAC_TO_SPR, _SPR1chain() * BIAS); spr1ch.qwc = 0; } @@ -310,7 +311,7 @@ void _SPR1interleave() if (tqwc == 0) tqwc = qwc; SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", spr1ch.qwc, tqwc, sqwc, spr1ch.madr, spr1ch.sadr); - CPU_INT(DMAC_TO_SPR, qwc / BIAS); + CPU_INT(DMAC_TO_SPR, qwc * BIAS); while (qwc > 0) { spr1ch.qwc = std::min(tqwc, qwc); diff --git a/pcsx2/Sif1.cpp b/pcsx2/Sif1.cpp index 67fb0148e5..e8f7fdc3cd 100644 --- a/pcsx2/Sif1.cpp +++ b/pcsx2/Sif1.cpp @@ -52,6 +52,7 @@ static __fi bool WriteEEtoFifo() sif1.fifo.write((u32*)ptag, writeSize << 2); sif1dma.madr += writeSize << 4; + hwDmacSrcTadrInc(sif1dma); sif1.ee.cycles += writeSize; // fixme : BIAS is factored in above sif1dma.qwc -= writeSize; @@ -114,8 +115,8 @@ static __fi bool ProcessEETag() break; case TAG_CNT: - sif1dma.madr = sif1dma.tadr + 16; - sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); + sif1dma.tadr += 16; + sif1dma.madr = sif1dma.tadr; break; case TAG_NEXT: @@ -132,7 +133,7 @@ static __fi bool ProcessEETag() case TAG_END: sif1.ee.end = true; sif1dma.madr = sif1dma.tadr + 16; - sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); + //sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); break; default: diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index 4cf76447ae..caebc4c470 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -155,9 +155,9 @@ bool _VIF1chain() vif1ch.qwc, vif1ch.madr, vif1ch.tadr); if (vif1.vifstalled) - return VIF1transfer(pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset); + return VIF1transfer(pMem + vif1.irqoffset, vif1ch.qwc * 4 - vif1.irqoffset, false); else - return VIF1transfer(pMem, vif1ch.qwc * 4); + return VIF1transfer(pMem, vif1ch.qwc * 4, false); } __fi void vif1SetupTransfer() @@ -490,7 +490,7 @@ void dmaVIF1() if(vif1ch.chcr.MOD == CHAIN_MODE && vif1.dmamode != VIF_NORMAL_TO_MEM_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)) { diff --git a/pcsx2/Vif1_MFIFO.cpp b/pcsx2/Vif1_MFIFO.cpp index 910a51e752..a5699ec335 100644 --- a/pcsx2/Vif1_MFIFO.cpp +++ b/pcsx2/Vif1_MFIFO.cpp @@ -32,14 +32,39 @@ static u32 qwctag(u32 mask) return (dmacRegs.rbor.ADDR + (mask & dmacRegs.rbsr.RMSK)); } +static u16 QWCinVIFMFIFO(u32 DrainADDR) +{ + u32 ret; + + + SPR_LOG("VIF MFIFO Requesting %x QWC from the MFIFO Base %x, SPR MADR %x Drain %x", vif1ch.qwc, dmacRegs.rbor.ADDR, spr0ch.madr, DrainADDR); + //Calculate what we have in the fifo. + if(DrainADDR <= spr0ch.madr) + { + //Drain is below the tadr, calculate the difference between them + ret = (spr0ch.madr - DrainADDR) >> 4; + } + else + { + u32 limit = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; + //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; + } + SPR_LOG("%x Available of the %x requested", ret, vif1ch.qwc); + + return ret; +} static __fi bool mfifoVIF1rbTransfer() { u32 maddr = dmacRegs.rbor.ADDR; u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; - u16 mfifoqwc = std::min(vif1ch.qwc, vifqwc); + u16 mfifoqwc = min(QWCinVIFMFIFO(vif1ch.madr), vif1ch.qwc); u32 *src; bool ret; + if(mfifoqwc == 0) return true; //Cant do anything, lets forget it + /* Check if the transfer should wrap around the ring buffer */ if ((vif1ch.madr + (mfifoqwc << 4)) > (msize)) { @@ -48,6 +73,8 @@ static __fi bool mfifoVIF1rbTransfer() SPR_LOG("Split MFIFO"); /* it does, so first copy 's1' bytes from 'addr' to 'data' */ + vif1ch.madr = qwctag(vif1ch.madr); + src = (u32*)PSM(vif1ch.madr); if (src == NULL) return false; @@ -56,10 +83,9 @@ static __fi bool mfifoVIF1rbTransfer() else ret = VIF1transfer(src, s1); - vif1ch.madr = qwctag(vif1ch.madr); - if (ret) { + if(vif1.irqoffset != 0) DevCon.Warning("VIF1 MFIFO Offest != 0! vifoffset=%x", vif1.irqoffset); /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ vif1ch.madr = maddr; @@ -67,13 +93,12 @@ static __fi bool mfifoVIF1rbTransfer() if (src == NULL) return false; VIF1transfer(src, ((mfifoqwc << 2) - s1)); } - vif1ch.madr = qwctag(vif1ch.madr); } else { SPR_LOG("Direct MFIFO"); - + vif1ch.madr = qwctag(vif1ch.madr); /* it doesn't, so just transfer 'qwc*4' words */ src = (u32*)PSM(vif1ch.madr); if (src == NULL) return false; @@ -83,8 +108,6 @@ static __fi bool mfifoVIF1rbTransfer() else ret = VIF1transfer(src, mfifoqwc << 2); - vif1ch.madr = qwctag(vif1ch.madr); - } return ret; } @@ -99,13 +122,14 @@ static __fi void mfifo_VIF1chain() } if (vif1ch.madr >= dmacRegs.rbor.ADDR && - vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK)) - { - //Need to exit on mfifo locations, if the madr is matching the madr of spr, we dont have any data left :( - - u16 startqwc = vif1ch.qwc; + vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) + { + if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1"); mfifoVIF1rbTransfer(); - vifqwc -= startqwc - vif1ch.qwc; + + if(QWCinVIFMFIFO(vif1ch.madr) == 0) vif1.inprogress |= 0x10; + + //vifqwc -= startqwc - vif1ch.qwc; } else @@ -124,8 +148,6 @@ static __fi void mfifo_VIF1chain() } } -int NextTADR = 0; //Bodge for Clock Tower 3 (see below) - void mfifoVIF1transfer(int qwc) { tDMA_TAG *ptag; @@ -134,11 +156,15 @@ void mfifoVIF1transfer(int qwc) if (qwc > 0) { - vifqwc += qwc; - SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vifqwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done); + //vifqwc += qwc; + SPR_LOG("Added %x qw to mfifo, total now %x - Vif CHCR %x Stalled %x done %x", qwc, vif1ch.chcr._u32, vif1.vifstalled, vif1.done); if (vif1.inprogress & 0x10) { - if(vif1ch.chcr.STR == true)CPU_INT(DMAC_MFIFO_VIF, 4); + if(vif1ch.chcr.STR == true && !(cpuRegs.interrupt & (1< 0) + if (vif1ch.qwc == 0) { + vif1ch.tadr = qwctag(vif1ch.tadr); ptag = dmaGetAddr(vif1ch.tadr, false); if (vif1ch.chcr.TTE) @@ -169,12 +196,14 @@ void mfifoVIF1transfer(int qwc) } else { - ret = VIF1transfer((u32*)&masked_tag, 4, true); //Transfer Tag + vif1.irqoffset = 2; + ret = VIF1transfer((u32*)&masked_tag + 2, 2, true); //Transfer Tag //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag } if (!ret && vif1.irqoffset) { + vif1.inprogress &= ~1; return; //IRQ set by VIFTransfer } //else vif1.vifstalled = false; @@ -186,46 +215,13 @@ void mfifoVIF1transfer(int qwc) vif1ch.unsafeTransfer(ptag); vif1ch.madr = ptag[1]._u32; - vifqwc--; + + //vifqwc--; SPR_LOG("dmaChain %8.8x_%8.8x size=%d, id=%d, madr=%lx, tadr=%lx mfifo qwc = %x spr0 madr = %x", ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, vifqwc, spr0ch.madr); - switch (ptag->ID) - { - case TAG_REFE: // Refe - Transfer Packet According to ADDR field - NextTADR = qwctag(vif1ch.tadr + 16); - vif1.done = true; //End Transfer - break; - - case TAG_CNT: // CNT - Transfer QWC following the tag. - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW after Tag - NextTADR = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data - vif1.done = false; - break; - - case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR - { - int temp = vif1ch.madr; //Temporarily Store ADDR - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to QW following the tag - NextTADR = temp; //Copy temporarily stored ADDR to Tag - if ((temp & dmacRegs.rbsr.RMSK) != dmacRegs.rbor.ADDR) Console.WriteLn("Next tag = %x outside ring %x size %x", temp, psHu32(DMAC_RBOR), psHu32(DMAC_RBSR)); - vif1.done = false; - break; - } - - case TAG_REF: // Ref - Transfer QWC from ADDR field - case TAG_REFS: // Refs - Transfer QWC from ADDR field (Stall Control) - NextTADR = qwctag(vif1ch.tadr + 16); //Set TADR to next tag - vif1.done = false; - break; - - case TAG_END: // End - Transfer QWC following the tag - vif1ch.madr = qwctag(vif1ch.tadr + 16); //Set MADR to data following the tag - NextTADR = qwctag(vif1ch.madr + (vif1ch.qwc << 4)); //Set TADR to QW following the data - vif1.done = true; //End Transfer - break; - } + vif1.done |= hwDmacSrcChainWithStack(vif1ch, ptag->ID); if (vif1ch.chcr.TIE && ptag->IRQ) { @@ -233,8 +229,14 @@ void mfifoVIF1transfer(int qwc) vif1.done = true; } - vif1Regs.stat.FQC = min(vif1ch.qwc, (u16)16); - vif1.inprogress |= 1; + + if(vif1ch.qwc > 0) vif1.inprogress |= 1; + + if(QWCinVIFMFIFO(vif1ch.tadr) == 0) vif1.inprogress |= 0x10; + } + else + { + DevCon.Warning("Vif MFIFO QWC not 0 on tag"); } @@ -246,15 +248,15 @@ void vifMFIFOInterrupt() g_vifCycles = 0; VIF_LOG("vif mfifo interrupt"); - - if(NextTADR != 0 && vif1ch.qwc == 0) + if(vif1.inprogress & 0x10) { - // Clock Tower 3 Note! - /* If the DMA starts the transfer then hammers the TADR to see when the transfer has finished(as clock tower does) - and we have preincremented before all data has arrived, it breaks. Idealy we increment this as we transfer the data. - "NextTADR" bodge in for the moment! - Refraction */ - vif1ch.tadr = NextTADR; - NextTADR = 0; + FireMFIFOEmpty(); + if(!(vif1.done && vif1ch.qwc == 0))return; + } + if (dmacRegs.ctrl.MFD != MFD_VIF1) + { + DevCon.Warning("Not in VIF MFIFO mode! Stopping VIF MFIFO"); + return; } if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2) @@ -269,7 +271,11 @@ void vifMFIFOInterrupt() if (schedulepath3msk & 0x10) Vif1MskPath3(); - if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) return; + if(vif1ch.chcr.DIR && CheckPath2GIF(DMAC_MFIFO_VIF) == false) + { + SPR_LOG("Waiting for PATH to be ready"); + return; + } //We need to check the direction, if it is downloading from the GS, we handle that seperately (KH2 for testing) //Simulated GS transfer time done, clear the flags @@ -285,6 +291,7 @@ void vifMFIFOInterrupt() if (vif1.irq && vif1.tag.size == 0) { + SPR_LOG("VIF MFIFO Code Interrupt detected"); vif1Regs.stat.INT = true; hwIntcIrq(INTC_VIF1); --vif1.irq; @@ -299,49 +306,28 @@ void vifMFIFOInterrupt() if (vif1.done == false || vif1ch.qwc) { + switch(vif1.inprogress & 1) { case 0: //Set up transfer - if (vif1ch.tadr == spr0ch.madr) + if (QWCinVIFMFIFO(vif1ch.tadr) == 0) { - // Console.WriteLn("Empty 1"); - vifqwc = 0; - if((vif1.inprogress & 0x10) == 0) - { - hwDmacIrq(DMAC_MFIFO_EMPTY); - vif1.inprogress |= 0x10; - } - vif1Regs.stat.FQC = 0; + vif1.inprogress |= 0x10; + CPU_INT(DMAC_MFIFO_VIF, 4 ); return; } - + mfifoVIF1transfer(0); - - CPU_INT(DMAC_MFIFO_VIF, 4); - return; - case 1: //Transfer data mfifo_VIF1chain(); //Sanity check! making sure we always have non-zero values - CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) ); + CPU_INT(DMAC_MFIFO_VIF, (g_vifCycles == 0 ? 4 : g_vifCycles) ); return; } return; - } + } - - //FF7 Dirge of Cerberus seems to like the mfifo to tell it when it's empty, even if it's ending. - //Doesn't seem to care about the vif1 dma interrupting (possibly disabled the interrupt?) - if (vif1ch.tadr == spr0ch.madr) - { - vifqwc = 0; - if((vif1.inprogress & 0x10) == 0) - { - hwDmacIrq(DMAC_MFIFO_EMPTY); - vif1.inprogress |= 0x10; - } - } vif1.vifstalled = false; vif1.done = 1; g_vifCycles = 0; diff --git a/pcsx2/Vif_Codes.cpp b/pcsx2/Vif_Codes.cpp index 1e299668a0..cf2ec2353c 100644 --- a/pcsx2/Vif_Codes.cpp +++ b/pcsx2/Vif_Codes.cpp @@ -154,7 +154,7 @@ template __fi int _vifCode_Direct(int pass, const u8* data, bool isDire } if(SIGNAL_IMR_Pending == true) { - DevCon.Warning("Path 2 Paused (At start)"); + //DevCon.Warning("Path 2 Paused (At start)"); vif1.vifstalled = true; return 0; } diff --git a/pcsx2/Vif_Transfer.cpp b/pcsx2/Vif_Transfer.cpp index ea027086a4..0d35c946b8 100644 --- a/pcsx2/Vif_Transfer.cpp +++ b/pcsx2/Vif_Transfer.cpp @@ -25,7 +25,7 @@ // Doesn't stall if the next vifCode is the Mark command _vifT bool runMark(u32* &data) { if (((vifXRegs.code >> 24) & 0x7f) == 0x7) { - DevCon.WriteLn("Vif%d: Running Mark with I-bit", idx); + //DevCon.WriteLn("Vif%d: Running Mark with I-bit", idx); return 1; // No Stall? } return 1; // Stall @@ -145,6 +145,7 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) { vifXch.madr +=(transferred << 4); vifXch.qwc -= transferred; + if(vifXch.chcr.STR)hwDmacSrcTadrInc(vifXch); } if (!vifXch.qwc && !vifX.irqoffset) diff --git a/pcsx2/ps2/GIFpath.cpp b/pcsx2/ps2/GIFpath.cpp index bebe2c486a..9b2ebaac0d 100644 --- a/pcsx2/ps2/GIFpath.cpp +++ b/pcsx2/ps2/GIFpath.cpp @@ -897,25 +897,39 @@ __fi int GIFPath::CopyTag(const u128* pMem128, u32 size) case GIF_PATH_2: GSTransferStatus.PTH2 = STOPPED_MODE; break; - case GIF_PATH_3: + case GIF_PATH_3: //For huge chunks we may have delay problems, so we need to stall it till the interrupt, else we get desync (Lemmings) if(size > 8) GSTransferStatus.PTH3 = PENDINGSTOP_MODE; else GSTransferStatus.PTH3 = STOPPED_MODE; - if (gifch.chcr.STR) { //Make sure we are really doing a DMA and not using FIFO - //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3); - gifch.madr += size * 16; - gifch.qwc -= size; - } break; } } - else if(pathidx == 2) + else if( nloop == 0) + { + //Need to set GIF as WAITING, sometimes it can get stuck in a bit of a loop if other paths think it's still doing REGLIST for example. + //Do NOT use IDLE mode here, it will freak Path3 masking out if it gets used. + switch(pathidx) + { + case GIF_PATH_1: + GSTransferStatus.PTH1 = WAITING_MODE; + break; + case GIF_PATH_2: + GSTransferStatus.PTH2 = WAITING_MODE; + break; + case GIF_PATH_3: + if(GSTransferStatus.PTH3 < IDLE_MODE) GSTransferStatus.PTH3 = WAITING_MODE; + break; + } + } + + if(pathidx == 2) { //if(nloop <= 16 && GSTransferStatus.PTH3 == IMAGE_MODE)GSTransferStatus.PTH3 = PENDINGIMAGE_MODE; if (gifch.chcr.STR) { //Make sure we are really doing a DMA and not using FIFO //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3); gifch.madr += size * 16; gifch.qwc -= size; + hwDmacSrcTadrInc(gifch); } } diff --git a/pcsx2/ps2/eeHwTraceLog.inl b/pcsx2/ps2/eeHwTraceLog.inl index 7f3fc8718b..4ac1f14c5e 100644 --- a/pcsx2/ps2/eeHwTraceLog.inl +++ b/pcsx2/ps2/eeHwTraceLog.inl @@ -133,6 +133,7 @@ static __ri const char* _eelog_GetHwName( u32 addr, T val ) EasyCase(VIF0_ASR1); EasyCase(VIF1_CHCR); + EasyCase(VIF1_MADR); EasyCase(VIF1_QWC); EasyCase(VIF1_TADR); EasyCase(VIF1_ASR0);