- 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 hwIntcIrq(int n);
extern void hwDmacIrq(int n); extern void hwDmacIrq(int n);
extern void FireMFIFOEmpty();
extern bool hwMFIFOWrite(u32 addr, const u128* data, uint size_qwc); 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 hwDmacSrcChainWithStack(DMACh& dma, int id);
extern bool hwDmacSrcChain(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) 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; gifRegs.stat.IP3 = true;
if(gifRegs.stat.P1Q) gsPath1Interrupt(); if(gifRegs.stat.P1Q) gsPath1Interrupt();
CPU_INT(DMAC_GIF, 16); 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). //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)) 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; gifRegs.stat.IP3 = true;
CPU_INT(DMAC_GIF, 16); CPU_INT(DMAC_GIF, 16);
return false; return false;
@ -440,51 +442,85 @@ void dmaGIF()
GIFdma(); 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: // called from only one location, so forceinline it:
static __fi bool mfifoGIFrbTransfer() static __fi bool mfifoGIFrbTransfer()
{ {
u32 mfifoqwc = min(gifqwc, (u32)gifch.qwc); u16 mfifoqwc = min(QWCinGIFMFIFO(gifch.madr), gifch.qwc);
u32 *src; u32 *src;
if(mfifoqwc == 0) return true; //Lets skip all this, we don't have the data
GetMTGS().PrepDataPacket(GIF_PATH_3, mfifoqwc); GetMTGS().PrepDataPacket(GIF_PATH_3, mfifoqwc);
// TODO (minor optimization): The new GIFpath parser can do rather efficient wrapping of // 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 // 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. // 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 */ /* 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 s1 = ((dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16) - gifch.madr) >> 4;
uint s2 = (mfifoqwc - s1); 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' */ /* it does (wrap around), so first copy 's1' bytes from 'addr' to 'data' */
/* and second copy 's2' bytes from 'maddr' to '&data[s1]' */ /* 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); src = (u32*)PSM(gifch.madr);
if (src == NULL) return false; if (src == NULL) return false;
uint copied = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s1); 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. 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); src = (u32*)PSM(dmacRegs.rbor.ADDR);
gifch.madr = dmacRegs.rbor.ADDR;
if (src == NULL) return false; if (src == NULL) return false;
copied += GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s2); copied += GIFPath_CopyTag(GIF_PATH_3, (u128*)src, s2);
} }
mfifoqwc = copied; mfifoqwc = copied;
GIF_LOG("Copied %x QWC, %x QWC Left", mfifoqwc, gifch.qwc);
} }
else 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 */ /* 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); src = (u32*)PSM(gifch.madr);
if (src == NULL) return false; if (src == NULL) return false;
mfifoqwc = GIFPath_CopyTag(GIF_PATH_3, (u128*)src, mfifoqwc); 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(); GetMTGS().SendDataPacket();
gifqwc -= mfifoqwc; //gifqwc -= mfifoqwc;
mfifocycles += (mfifoqwc) * 2; /* guessing */
return true; return true;
} }
@ -496,14 +532,19 @@ static __fi bool mfifoGIFchain()
if (gifch.qwc == 0) return true; if (gifch.qwc == 0) return true;
if (gifch.madr >= dmacRegs.rbor.ADDR && 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 else
{ {
int mfifoqwc; int mfifoqwc;
GIF_LOG("Non-MFIFO Location transfer doing %x Total QWC", gifch.qwc);
tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false); tDMA_TAG *pMem = dmaGetAddr(gifch.madr, false);
if (pMem == NULL) return false; if (pMem == NULL) return false;
@ -528,12 +569,13 @@ void mfifoGIFtransfer(int qwc)
if(qwc > 0 ) if(qwc > 0 )
{ {
gifqwc += qwc; if ((gifstate & GIF_STATE_EMPTY) && !(cpuRegs.interrupt & (1<<DMAC_MFIFO_GIF)))
{
if (!(gifstate & GIF_STATE_EMPTY)) return; if(gifch.chcr.STR == true)CPU_INT(DMAC_MFIFO_GIF, 4);
// if (gifempty == false) return;
gifstate &= ~GIF_STATE_EMPTY; gifstate &= ~GIF_STATE_EMPTY;
gifempty = false; }
gifRegs.stat.FQC = 16;
return;
} }
if (gifRegs.ctrl.PSE) // temporarily stop if (gifRegs.ctrl.PSE) // temporarily stop
@ -545,15 +587,6 @@ void mfifoGIFtransfer(int qwc)
if (gifch.qwc == 0) 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); gifch.tadr = qwctag(gifch.tadr);
ptag = dmaGetAddr(gifch.tadr, false); 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", 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); 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) if(gspath3done == true) gifstate = GIF_STATE_DONE;
{ else gifstate = GIF_STATE_READY;
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 ((gifch.chcr.TIE) && (ptag->IRQ)) if ((gifch.chcr.TIE) && (ptag->IRQ))
{ {
@ -608,6 +609,7 @@ void mfifoGIFtransfer(int qwc)
gifstate = GIF_STATE_DONE; gifstate = GIF_STATE_DONE;
gifmfifoirq = true; gifmfifoirq = true;
} }
if (QWCinGIFMFIFO(gifch.tadr) == 0) gifstate |= GIF_STATE_EMPTY;
} }
if (!mfifoGIFchain()) if (!mfifoGIFchain())
@ -616,7 +618,7 @@ void mfifoGIFtransfer(int qwc)
gifstate = GIF_STATE_STALL; 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); CPU_INT(DMAC_MFIFO_GIF,mfifocycles);
SPR_LOG("mfifoGIFtransfer end %x madr %x, tadr %x", gifch.chcr._u32, gifch.madr, gifch.tadr); 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() void gifMFIFOInterrupt()
{ {
//Console.WriteLn("gifMFIFOInterrupt"); GIF_LOG("gifMFIFOInterrupt");
mfifocycles = 0; 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) if(SIGNAL_IMR_Pending == true)
{ {
//DevCon.Warning("Path 3 Paused"); //DevCon.Warning("Path 3 Paused");
@ -634,9 +648,10 @@ void gifMFIFOInterrupt()
return; 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; gifRegs.stat.OPH = false;
GSTransferStatus.PTH3 = STOPPED_MODE;
gifRegs.stat.APATH = GIF_APATH_IDLE; gifRegs.stat.APATH = GIF_APATH_IDLE;
if(gifRegs.stat.P1Q) gsPath1Interrupt(); if(gifRegs.stat.P1Q) gsPath1Interrupt();
} }
@ -652,16 +667,13 @@ void gifMFIFOInterrupt()
if (!(gifstate & GIF_STATE_STALL)) if (!(gifstate & GIF_STATE_STALL))
{ {
if (gifqwc <= 0) if (QWCinGIFMFIFO(gifch.tadr) == 0)
{ {
//Console.WriteLn("Empty");
hwDmacIrq(DMAC_MFIFO_EMPTY);
gifstate |= GIF_STATE_EMPTY; gifstate |= GIF_STATE_EMPTY;
gifempty = true; CPU_INT(DMAC_MFIFO_GIF, 4);
gifRegs.stat.IMT = false;
return; return;
} }
mfifoGIFtransfer(0); mfifoGIFtransfer(0);
return; return;
} }
@ -685,6 +697,7 @@ void gifMFIFOInterrupt()
gifch.chcr.STR = false; gifch.chcr.STR = false;
gifstate = GIF_STATE_READY; gifstate = GIF_STATE_READY;
hwDmacIrq(DMAC_GIF); hwDmacIrq(DMAC_GIF);
GIF_LOG("gifMFIFO End");
clearFIFOstuff(false); 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 enum GSTransferModes //0 = Image Mode (DirectHL), 1 = transferring, 2 = Stopped at End of Packet
{ {
PENDINGIMAGE_MODE = 0, WAITING_MODE = 0,
IMAGE_MODE = 1, IMAGE_MODE = 1,
TRANSFER_MODE = 2, TRANSFER_MODE = 2,
PENDINGSTOP_MODE = 3, PENDINGSTOP_MODE = 3,

View File

@ -130,6 +130,14 @@ void hwDmacIrq(int n)
if(psHu16(DMAC_STAT+2) & (1<<n))cpuTestDMACInts(); 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'. // Write 'size' bytes to memory address 'addr' from 'data'.
__ri bool hwMFIFOWrite(u32 addr, const u128* data, uint qwc) __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((dmacRegs.rbor.ADDR & 15) == 0);
pxAssume((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 // 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 // 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 // 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) { __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) {
switch (id) { switch (id) {
case TAG_REFE: // Refe - Transfer Packet According to ADDR field case TAG_REFE: // Refe - Transfer Packet According to ADDR field
dma.tadr += 16;
//End Transfer //End Transfer
return true; return true;
case TAG_CNT: // CNT - Transfer QWC following the tag. case TAG_CNT: // CNT - Transfer QWC following the tag.
// Set MADR to QW afer tag, and set TADR to QW following the data. // Set MADR to QW afer tag, and set TADR to QW following the data.
dma.madr = dma.tadr + 16; dma.tadr += 16;
dma.tadr = dma.madr + (dma.qwc << 4); dma.madr = dma.tadr;
//dma.tadr = dma.madr + (dma.qwc << 4);
return false; return false;
case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
@ -267,6 +278,33 @@ __ri bool hwDmacSrcChainWithStack(DMACh& dma, int id) {
return false; 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) bool hwDmacSrcChain(DMACh& dma, int id)
{ {
u32 temp; u32 temp;
@ -280,7 +318,7 @@ bool hwDmacSrcChain(DMACh& dma, int id)
case TAG_CNT: // CNT - Transfer QWC following the tag. case TAG_CNT: // CNT - Transfer QWC following the tag.
// Set MADR to QW after the tag, and TADR to QW following the data. // Set MADR to QW after the tag, and TADR to QW following the data.
dma.madr = dma.tadr + 16; dma.madr = dma.tadr + 16;
dma.tadr = dma.madr + (dma.qwc << 4); dma.tadr = dma.madr;
return false; return false;
case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR case TAG_NEXT: // Next - Transfer QWC following tag. TADR = ADDR
@ -305,3 +343,4 @@ bool hwDmacSrcChain(DMACh& dma, int id)
return false; return false;
} }

View File

@ -42,21 +42,6 @@ void SaveStateBase::ipuDmaFreeze()
Freeze(IPU1Status); 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() static __fi void ipuDmacSrcChain()
{ {
switch (IPU1Status.ChainMode) switch (IPU1Status.ChainMode)
@ -82,7 +67,7 @@ static __fi void ipuDmacSrcChain()
break; break;
case TAG_END: // end case TAG_END: // end
ipu1dma.tadr = ipu1dma.madr; //ipu1dma.tadr = ipu1dma.madr;
IPU1Status.DMAFinished = true; IPU1Status.DMAFinished = true;
break; break;
} }
@ -136,15 +121,12 @@ static __fi int IPU1chain() {
ipu1dma.qwc -= qwc; ipu1dma.qwc -= qwc;
totalqwc += qwc; totalqwc += qwc;
} }
if( ipu1dma.qwc == 0)
{
//Update TADR etc //Update TADR etc
if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain(); 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 if( ipu1dma.qwc == 0)
IPU1Status.InProgress = false; IPU1Status.InProgress = false;
} //If we still have data the commands should pull this across when need be.
return totalqwc; return totalqwc;
} }
@ -238,7 +220,8 @@ int IPU1dma()
break; break;
case TAG_CNT: // cnt 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); IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16);
//ipu1dma.tadr = ipu1dma.madr + (ipu1dma.qwc * 16); //ipu1dma.tadr = ipu1dma.madr + (ipu1dma.qwc * 16);
// Set the taddr to the next tag // Set the taddr to the next tag
@ -262,7 +245,7 @@ int IPU1dma()
case TAG_END: // end case TAG_END: // end
// do not change tadr // do not change tadr
ipu1dma.madr = ipu1dma.tadr + 16; ipu1dma.madr = ipu1dma.tadr + 16;
ipu1dma.tadr += 16; //ipu1dma.tadr += 16;
IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16); IPU_LOG("Tag should end on %x", ipu1dma.madr + ipu1dma.qwc * 16);
break; break;

View File

@ -86,7 +86,7 @@ int _SPR0chain()
__fi void SPR0chain() __fi void SPR0chain()
{ {
CPU_INT(DMAC_FROM_SPR, _SPR0chain() / BIAS); CPU_INT(DMAC_FROM_SPR, _SPR0chain() * BIAS);
spr0ch.qwc = 0; spr0ch.qwc = 0;
} }
@ -102,7 +102,7 @@ void _SPR0interleave()
SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", SPR_LOG("SPR0 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
spr0ch.qwc, tqwc, sqwc, spr0ch.madr, spr0ch.sadr); 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) while (qwc > 0)
{ {
@ -290,13 +290,14 @@ int _SPR1chain()
SPR1transfer(pMem, spr1ch.qwc); SPR1transfer(pMem, spr1ch.qwc);
spr1ch.madr += spr1ch.qwc * 16; spr1ch.madr += spr1ch.qwc * 16;
hwDmacSrcTadrInc(spr1ch);
return (spr1ch.qwc); return (spr1ch.qwc);
} }
__fi void SPR1chain() __fi void SPR1chain()
{ {
CPU_INT(DMAC_TO_SPR, _SPR1chain() / BIAS); CPU_INT(DMAC_TO_SPR, _SPR1chain() * BIAS);
spr1ch.qwc = 0; spr1ch.qwc = 0;
} }
@ -310,7 +311,7 @@ void _SPR1interleave()
if (tqwc == 0) tqwc = qwc; if (tqwc == 0) tqwc = qwc;
SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx", SPR_LOG("SPR1 interleave size=%d, tqwc=%d, sqwc=%d, addr=%lx sadr=%lx",
spr1ch.qwc, tqwc, sqwc, spr1ch.madr, spr1ch.sadr); 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) while (qwc > 0)
{ {
spr1ch.qwc = std::min(tqwc, qwc); spr1ch.qwc = std::min(tqwc, qwc);

View File

@ -52,6 +52,7 @@ static __fi bool WriteEEtoFifo()
sif1.fifo.write((u32*)ptag, writeSize << 2); sif1.fifo.write((u32*)ptag, writeSize << 2);
sif1dma.madr += writeSize << 4; sif1dma.madr += writeSize << 4;
hwDmacSrcTadrInc(sif1dma);
sif1.ee.cycles += writeSize; // fixme : BIAS is factored in above sif1.ee.cycles += writeSize; // fixme : BIAS is factored in above
sif1dma.qwc -= writeSize; sif1dma.qwc -= writeSize;
@ -114,8 +115,8 @@ static __fi bool ProcessEETag()
break; break;
case TAG_CNT: case TAG_CNT:
sif1dma.madr = sif1dma.tadr + 16; sif1dma.tadr += 16;
sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); sif1dma.madr = sif1dma.tadr;
break; break;
case TAG_NEXT: case TAG_NEXT:
@ -132,7 +133,7 @@ static __fi bool ProcessEETag()
case TAG_END: case TAG_END:
sif1.ee.end = true; sif1.ee.end = true;
sif1dma.madr = sif1dma.tadr + 16; sif1dma.madr = sif1dma.tadr + 16;
sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4); //sif1dma.tadr = sif1dma.madr + (sif1dma.qwc << 4);
break; break;
default: default:

View File

@ -155,9 +155,9 @@ bool _VIF1chain()
vif1ch.qwc, vif1ch.madr, vif1ch.tadr); vif1ch.qwc, vif1ch.madr, vif1ch.tadr);
if (vif1.vifstalled) 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 else
return VIF1transfer(pMem, vif1ch.qwc * 4); return VIF1transfer(pMem, vif1ch.qwc * 4, false);
} }
__fi void vif1SetupTransfer() __fi void vif1SetupTransfer()
@ -490,7 +490,7 @@ void dmaVIF1()
if(vif1ch.chcr.MOD == CHAIN_MODE && vif1.dmamode != VIF_NORMAL_TO_MEM_MODE) if(vif1ch.chcr.MOD == CHAIN_MODE && vif1.dmamode != VIF_NORMAL_TO_MEM_MODE)
{ {
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)) 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)); 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() static __fi bool mfifoVIF1rbTransfer()
{ {
u32 maddr = dmacRegs.rbor.ADDR; u32 maddr = dmacRegs.rbor.ADDR;
u32 msize = dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16; 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; u32 *src;
bool ret; bool ret;
if(mfifoqwc == 0) 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))
{ {
@ -48,6 +73,8 @@ static __fi bool mfifoVIF1rbTransfer()
SPR_LOG("Split MFIFO"); SPR_LOG("Split MFIFO");
/* it does, so first copy 's1' bytes from 'addr' to 'data' */ /* it does, so first copy 's1' bytes from 'addr' to 'data' */
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;
@ -56,10 +83,9 @@ static __fi bool mfifoVIF1rbTransfer()
else else
ret = VIF1transfer(src, s1); ret = VIF1transfer(src, s1);
vif1ch.madr = qwctag(vif1ch.madr);
if (ret) 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]' */ /* and second copy 's2' bytes from 'maddr' to '&data[s1]' */
vif1ch.madr = maddr; vif1ch.madr = maddr;
@ -67,13 +93,12 @@ static __fi bool mfifoVIF1rbTransfer()
if (src == NULL) return false; if (src == NULL) return false;
VIF1transfer(src, ((mfifoqwc << 2) - s1)); VIF1transfer(src, ((mfifoqwc << 2) - s1));
} }
vif1ch.madr = qwctag(vif1ch.madr);
} }
else else
{ {
SPR_LOG("Direct MFIFO"); SPR_LOG("Direct MFIFO");
vif1ch.madr = qwctag(vif1ch.madr);
/* 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;
@ -83,8 +108,6 @@ static __fi bool mfifoVIF1rbTransfer()
else else
ret = VIF1transfer(src, mfifoqwc << 2); ret = VIF1transfer(src, mfifoqwc << 2);
vif1ch.madr = qwctag(vif1ch.madr);
} }
return ret; return ret;
} }
@ -99,13 +122,14 @@ 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)) vif1ch.madr <= (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16))
{ {
//Need to exit on mfifo locations, if the madr is matching the madr of spr, we dont have any data left :( if(vif1ch.madr == (dmacRegs.rbor.ADDR + dmacRegs.rbsr.RMSK + 16)) DevCon.Warning("Edge VIF1");
u16 startqwc = vif1ch.qwc;
mfifoVIF1rbTransfer(); mfifoVIF1rbTransfer();
vifqwc -= startqwc - vif1ch.qwc;
if(QWCinVIFMFIFO(vif1ch.madr) == 0) vif1.inprogress |= 0x10;
//vifqwc -= startqwc - vif1ch.qwc;
} }
else else
@ -124,8 +148,6 @@ static __fi void mfifo_VIF1chain()
} }
} }
int NextTADR = 0; //Bodge for Clock Tower 3 (see below)
void mfifoVIF1transfer(int qwc) void mfifoVIF1transfer(int qwc)
{ {
tDMA_TAG *ptag; tDMA_TAG *ptag;
@ -134,11 +156,15 @@ void mfifoVIF1transfer(int qwc)
if (qwc > 0) if (qwc > 0)
{ {
vifqwc += qwc; //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); 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 (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 vif1Regs.stat.FQC = 0x10; // FQC=16
} }
@ -147,8 +173,9 @@ void mfifoVIF1transfer(int qwc)
return; return;
} }
if (vif1ch.qwc == 0 && vifqwc > 0) if (vif1ch.qwc == 0)
{ {
vif1ch.tadr = qwctag(vif1ch.tadr);
ptag = dmaGetAddr(vif1ch.tadr, false); ptag = dmaGetAddr(vif1ch.tadr, false);
if (vif1ch.chcr.TTE) if (vif1ch.chcr.TTE)
@ -169,12 +196,14 @@ void mfifoVIF1transfer(int qwc)
} }
else 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 //ret = VIF1transfer((u32*)ptag + 2, 2); //Transfer Tag
} }
if (!ret && vif1.irqoffset) if (!ret && vif1.irqoffset)
{ {
vif1.inprogress &= ~1;
return; //IRQ set by VIFTransfer return; //IRQ set by VIFTransfer
} //else vif1.vifstalled = false; } //else vif1.vifstalled = false;
@ -186,46 +215,13 @@ void mfifoVIF1transfer(int qwc)
vif1ch.unsafeTransfer(ptag); vif1ch.unsafeTransfer(ptag);
vif1ch.madr = ptag[1]._u32; 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", 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); ptag[1]._u32, ptag[0]._u32, vif1ch.qwc, ptag->ID, vif1ch.madr, vif1ch.tadr, vifqwc, spr0ch.madr);
switch (ptag->ID) vif1.done |= hwDmacSrcChainWithStack(vif1ch, 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;
}
if (vif1ch.chcr.TIE && ptag->IRQ) if (vif1ch.chcr.TIE && ptag->IRQ)
{ {
@ -233,8 +229,14 @@ void mfifoVIF1transfer(int qwc)
vif1.done = true; 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; g_vifCycles = 0;
VIF_LOG("vif mfifo interrupt"); VIF_LOG("vif mfifo interrupt");
if(vif1.inprogress & 0x10)
if(NextTADR != 0 && vif1ch.qwc == 0)
{ {
// Clock Tower 3 Note! FireMFIFOEmpty();
/* If the DMA starts the transfer then hammers the TADR to see when the transfer has finished(as clock tower does) if(!(vif1.done && vif1ch.qwc == 0))return;
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 */ if (dmacRegs.ctrl.MFD != MFD_VIF1)
vif1ch.tadr = NextTADR; {
NextTADR = 0; DevCon.Warning("Not in VIF MFIFO mode! Stopping VIF MFIFO");
return;
} }
if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2) if(GSTransferStatus.PTH2 == STOPPED_MODE && gifRegs.stat.APATH == GIF_APATH2)
@ -269,7 +271,11 @@ void vifMFIFOInterrupt()
if (schedulepath3msk & 0x10) Vif1MskPath3(); 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) //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 //Simulated GS transfer time done, clear the flags
@ -285,6 +291,7 @@ void vifMFIFOInterrupt()
if (vif1.irq && vif1.tag.size == 0) if (vif1.irq && vif1.tag.size == 0)
{ {
SPR_LOG("VIF MFIFO Code Interrupt detected");
vif1Regs.stat.INT = true; vif1Regs.stat.INT = true;
hwIntcIrq(INTC_VIF1); hwIntcIrq(INTC_VIF1);
--vif1.irq; --vif1.irq;
@ -299,28 +306,19 @@ void vifMFIFOInterrupt()
if (vif1.done == false || vif1ch.qwc) if (vif1.done == false || vif1ch.qwc)
{ {
switch(vif1.inprogress & 1) switch(vif1.inprogress & 1)
{ {
case 0: //Set up transfer 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; vif1.inprogress |= 0x10;
} CPU_INT(DMAC_MFIFO_VIF, 4 );
vif1Regs.stat.FQC = 0;
return; return;
} }
mfifoVIF1transfer(0); mfifoVIF1transfer(0);
CPU_INT(DMAC_MFIFO_VIF, 4);
return;
case 1: //Transfer data case 1: //Transfer data
mfifo_VIF1chain(); mfifo_VIF1chain();
//Sanity check! making sure we always have non-zero values //Sanity check! making sure we always have non-zero values
@ -330,18 +328,6 @@ void vifMFIFOInterrupt()
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.vifstalled = false;
vif1.done = 1; vif1.done = 1;
g_vifCycles = 0; 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) if(SIGNAL_IMR_Pending == true)
{ {
DevCon.Warning("Path 2 Paused (At start)"); //DevCon.Warning("Path 2 Paused (At start)");
vif1.vifstalled = true; vif1.vifstalled = true;
return 0; return 0;
} }

View File

@ -25,7 +25,7 @@
// Doesn't stall if the next vifCode is the Mark command // Doesn't stall if the next vifCode is the Mark command
_vifT bool runMark(u32* &data) { _vifT bool runMark(u32* &data) {
if (((vifXRegs.code >> 24) & 0x7f) == 0x7) { 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; // No Stall?
} }
return 1; // Stall return 1; // Stall
@ -145,6 +145,7 @@ _vifT static __fi bool vifTransfer(u32 *data, int size, bool TTE) {
vifXch.madr +=(transferred << 4); vifXch.madr +=(transferred << 4);
vifXch.qwc -= transferred; vifXch.qwc -= transferred;
if(vifXch.chcr.STR)hwDmacSrcTadrInc(vifXch);
} }
if (!vifXch.qwc && !vifX.irqoffset) if (!vifXch.qwc && !vifX.irqoffset)

View File

@ -901,21 +901,35 @@ __fi int GIFPath::CopyTag(const u128* pMem128, u32 size)
//For huge chunks we may have delay problems, so we need to stall it till the interrupt, else we get desync (Lemmings) //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; if(size > 8) GSTransferStatus.PTH3 = PENDINGSTOP_MODE;
else GSTransferStatus.PTH3 = STOPPED_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; 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(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 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); //GIF_LOG("Path3 end EOP %x NLOOP %x Status %x", tag.EOP, nloop, GSTransferStatus.PTH3);
gifch.madr += size * 16; gifch.madr += size * 16;
gifch.qwc -= size; 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(VIF0_ASR1);
EasyCase(VIF1_CHCR); EasyCase(VIF1_CHCR);
EasyCase(VIF1_MADR);
EasyCase(VIF1_QWC); EasyCase(VIF1_QWC);
EasyCase(VIF1_TADR); EasyCase(VIF1_TADR);
EasyCase(VIF1_ASR0); EasyCase(VIF1_ASR0);