- Standardized DMA Source chains, all DMA's now act exactly the same (within reason) Explanation for this in Hw.cpp. Consequently this fixed a hack id done for FFX videos (Not the one there is a game fix for)

- Slight tweak to Path3 masking, an overlooked situation where Path3 can wait between GIFTags.
- Improved the stability of MFIFO on both sides greatly for games such at Tekken Tag (which boots again) Gran Turismo 4 and FF7 Dirge of Cerberus.

I'm expecting *Something* to break, so please report it here if something does, please make sure it is THIS revision.

git-svn-id: http://pcsx2.googlecode.com/svn/trunk@4035 96395faa-99c1-11dd-bbfe-3dabce05a288
This commit is contained in:
refraction 2010-11-19 16:29:28 +00:00
parent 55084dfc1a
commit 96ef86f560
13 changed files with 254 additions and 213 deletions

View File

@ -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);

View File

@ -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<<DMAC_MFIFO_GIF)))
{
if(gifch.chcr.STR == true)CPU_INT(DMAC_MFIFO_GIF, 4);
gifstate &= ~GIF_STATE_EMPTY;
}
gifRegs.stat.FQC = 16;
return;
}
if (gifRegs.ctrl.PSE) // temporarily stop
@ -545,15 +587,6 @@ void mfifoGIFtransfer(int qwc)
if (gifch.qwc == 0)
{
if (gifch.tadr == spr0ch.madr)
{
//if( gifqwc > 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);
}

View File

@ -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,

View File

@ -130,6 +130,14 @@ void hwDmacIrq(int n)
if(psHu16(DMAC_STAT+2) & (1<<n))cpuTestDMACInts();
}
void FireMFIFOEmpty()
{
SPR_LOG("VIF MFIFO Data Empty");
hwDmacIrq(DMAC_MFIFO_EMPTY);
if (dmacRegs.ctrl.MFD == MFD_VIF1) vif1Regs.stat.FQC = 0;
else if (dmacRegs.ctrl.MFD == MFD_GIF) gifRegs.stat.FQC = 0;
}
// Write 'size' bytes to memory address 'addr' from 'data'.
__ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc)
{
@ -137,6 +145,7 @@ __ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc)
pxAssume((dmacRegs.rbor.ADDR & 15) == 0);
pxAssume((addr & 15) == 0);
if(qwc > ((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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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:

View File

@ -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))
{

View File

@ -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<<DMAC_MFIFO_VIF)))
{
SPR_LOG("Data Added, Resuming");
CPU_INT(DMAC_MFIFO_VIF, 4);
}
vif1Regs.stat.FQC = 0x10; // FQC=16
}
@ -147,8 +173,9 @@ void mfifoVIF1transfer(int qwc)
return;
}
if (vif1ch.qwc == 0 && vifqwc > 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;

View File

@ -154,7 +154,7 @@ template<int idx> __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;
}

View File

@ -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)

View File

@ -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);
}
}

View File

@ -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);