mirror of https://github.com/PCSX2/pcsx2.git
- 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:
parent
55084dfc1a
commit
96ef86f560
|
@ -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);
|
||||||
|
|
||||||
|
|
149
pcsx2/Gif.cpp
149
pcsx2/Gif.cpp
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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,
|
||||||
|
|
45
pcsx2/Hw.cpp
45
pcsx2/Hw.cpp
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
||||||
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
|
//Update TADR etc
|
||||||
|
if(IPU1Status.DMAMode == DMA_MODE_CHAIN) ipuDmacSrcChain();
|
||||||
|
|
||||||
|
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;
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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))
|
||||||
{
|
{
|
||||||
|
|
|
@ -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");
|
vif1.inprogress |= 0x10;
|
||||||
vifqwc = 0;
|
CPU_INT(DMAC_MFIFO_VIF, 4 );
|
||||||
if((vif1.inprogress & 0x10) == 0)
|
|
||||||
{
|
|
||||||
hwDmacIrq(DMAC_MFIFO_EMPTY);
|
|
||||||
vif1.inprogress |= 0x10;
|
|
||||||
}
|
|
||||||
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;
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue