DMAC: Improve DMA Stall handling (#3701)

SIF: Implemented SIF0 and SIF1 DMA Stall handling
Cleaned up some of the handling of DMA Stalls on the other channels
This commit is contained in:
refractionpcsx2 2020-09-18 16:23:18 +01:00 committed by GitHub
parent a5cc8efb10
commit 40d02400ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 100 additions and 43 deletions

View File

@ -400,12 +400,12 @@ void GIFdma()
{
// stalled.
// We really need to test this. Pay attention to prevcycles, as it used to trigger GIFchains in the code above. (rama)
//Console.WriteLn("GS Stall Control start Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gifch.madr, psHu32(DMAC_STADR));
//DevCon.Warning("GS Stall Control start Source = %x, Drain = %x\n MADR = %x, STADR = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3,gifch.madr, psHu32(DMAC_STADR));
gif.prevcycles = gif.gscycles;
gifch.tadr -= 16;
gifch.qwc = 0;
hwDmacIrq(DMAC_STALL_SIS);
GifDMAInt(gif.gscycles);
GifDMAInt(128);
gif.gscycles = 0;
return;
}

View File

@ -226,8 +226,9 @@ void IPU0dma()
ipu0ch.qwc -= readsize; // note: qwc is u16
if (dmacRegs.ctrl.STS == STS_fromIPU) // STS == fromIPU
if (dmacRegs.ctrl.STS == STS_fromIPU && ipu0ch.qwc == 0) // STS == fromIPU
{
//DevCon.Warning("fromIPU Stall Control");
dmacRegs.stadr.ADDR = ipu0ch.madr;
switch (dmacRegs.ctrl.STD)
{
@ -271,6 +272,10 @@ __fi void dmaIPU0() // fromIPU
hwDmacIrq(DMAC_FROM_IPU);
}
//if (dmacRegs.ctrl.STS == STS_fromIPU) DevCon.Warning("DMA Stall enabled on IPU0");
if (dmacRegs.ctrl.STS == STS_fromIPU) // STS == fromIPU - Initial settings
dmacRegs.stadr.ADDR = ipu0ch.madr;
IPU_INT_FROM( 64 );

View File

@ -138,7 +138,14 @@ int _SPR0chain()
}
if (spr0ch.qwc == 0 && dmacRegs.ctrl.STS == STS_fromSPR)
{
if (spr0ch.chcr.MOD == NORMAL_MODE || ((spr0ch.chcr.TAG >> 28) & 0x7) == TAG_CNTS)
{
//DevCon.Warning("SPR0 %s Stall Control", spr0ch.chcr.MOD == NORMAL_MODE ? "Normal" : "Chain");
dmacRegs.stadr.ADDR = spr0ch.madr; // Copy MADR to DMAC_STADR stall addr register
}
}
return (partialqwc); // Bus is 1/2 the ee speed
}
@ -188,17 +195,16 @@ void _SPR0interleave()
spr0ch.sadr &= 0x3FFF; // Limited to 16K
spr0ch.madr += (sqwc + spr0ch.qwc) * 16;
}
if (dmacRegs.ctrl.STS == STS_fromSPR)
{
//DevCon.Warning("SPR0 Interleave Stall Control");
dmacRegs.stadr.ADDR = spr0ch.madr; // Copy MADR to DMAC_STADR stall addr register
}
spr0ch.qwc = 0;
}
static __fi void _dmaSPR0()
{
if (dmacRegs.ctrl.STS == STS_fromSPR)
{
DevCon.Warning("SPR0 stall %d", dmacRegs.ctrl.STS);
}
// Transfer Dn_QWC from SPR to Dn_MADR
switch(spr0ch.chcr.MOD)
{
@ -206,7 +212,7 @@ static __fi void _dmaSPR0()
{
if (dmacRegs.ctrl.STS == STS_fromSPR) // STS == fromSPR
{
DevCon.Warning("SPR stall control Normal not implemented");
dmacRegs.stadr.ADDR = spr0ch.madr;
}
SPR0chain();
spr0finished = true;
@ -234,15 +240,13 @@ static __fi void _dmaSPR0()
SPR_LOG("spr0 dmaChain %8.8x_%8.8x size=%d, id=%d, addr=%lx spr=%lx",
ptag[1]._u32, ptag[0]._u32, spr0ch.qwc, ptag->ID, spr0ch.madr, spr0ch.sadr);
if (dmacRegs.ctrl.STS == STS_fromSPR) // STS == fromSPR
{
Console.WriteLn("SPR stall control");
}
switch (ptag->ID)
{
case TAG_CNTS: // CNTS - Transfer QWC following the tag (Stall Control)
if (dmacRegs.ctrl.STS == STS_fromSPR) dmacRegs.stadr.ADDR = spr0ch.madr + (spr0ch.qwc * 16); // Copy MADR to DMAC_STADR stall addr register
if (dmacRegs.ctrl.STS == STS_fromSPR) // STS == fromSPR - Initial Value
{
dmacRegs.stadr.ADDR = spr0ch.madr;
}
break;
case TAG_CNT: // CNT - Transfer QWC following the tag.
@ -270,10 +274,6 @@ static __fi void _dmaSPR0()
//case INTERLEAVE_MODE:
default:
{
if (dmacRegs.ctrl.STS == STS_fromSPR) // STS == fromSPR
{
Console.WriteLn("SPR stall control interleave not implemented");
}
_SPR0interleave();
spr0finished = true;
break;

View File

@ -58,6 +58,13 @@ static __fi bool WriteFifoToEE()
sif0.ee.cycles += readSize; // fixme : BIAS is factored in above
sif0ch.qwc -= readSize;
if (sif0ch.qwc == 0 && dmacRegs.ctrl.STS == STS_SIF0)
{
//DevCon.Warning("SIF0 Stall Control");
if ((sif0ch.chcr.MOD == NORMAL_MODE) || ((sif0ch.chcr.TAG >> 28) & 0x7) == TAG_CNTS)
dmacRegs.stadr.ADDR = sif0ch.madr;
}
return true;
}
@ -105,8 +112,8 @@ static __fi bool ProcessEETag()
case TAG_CNT: break;
case TAG_CNTS:
if (dmacRegs.ctrl.STS == STS_SIF0)
dmacRegs.stadr.ADDR = sif0ch.madr + (sif0ch.qwc * 16);
if (dmacRegs.ctrl.STS == STS_SIF0) // STS == SIF0 - Initial Value
dmacRegs.stadr.ADDR = sif0ch.madr;
break;
case TAG_END:
@ -190,11 +197,6 @@ static __fi void HandleEETransfer()
return;
}
if (dmacRegs.ctrl.STS == STS_SIF0)
{
DevCon.Warning("SIF0 stall control not properly implemented");
}
/*if (sif0ch.qwc == 0)
if (sif0ch.chcr.MOD == NORMAL_MODE)
if (!sif0.ee.end){

View File

@ -23,6 +23,7 @@
_sif sif1;
static bool done = false;
static bool sif1_dma_stall = false;
static __fi void Sif1Init()
{
@ -186,10 +187,6 @@ static __fi void HandleEETransfer()
sif1.ee.busy = false;
return;
}
if (dmacRegs.ctrl.STD == STD_SIF1)
{
DevCon.Warning("SIF1 stall control Not Implemented"); // STD == fromSIF1
}
/*if (sif1ch.qwc == 0)
if (sif1ch.chcr.MOD == NORMAL_MODE)
@ -216,6 +213,21 @@ static __fi void HandleEETransfer()
}
else
{
if (dmacRegs.ctrl.STD == STD_SIF1)
{
if ((sif1ch.chcr.MOD == NORMAL_MODE) || ((sif1ch.chcr.TAG >> 28) & 0x7) == TAG_REFS)
{
//DevCon.Warning("SIF1 Stall Control");
const int writeSize = std::min((s32)sif1ch.qwc, sif1.fifo.sif_free() >> 2);
if ((sif1ch.madr + (writeSize * 16)) > dmacRegs.stadr.ADDR)
{
hwDmacIrq(DMAC_STALL_SIS);
sif1_dma_stall = true;
return;
}
}
//DevCon.Warning("SIF1 stall control Not Implemented"); // STD == fromSIF1
}
if (sif1.fifo.sif_free() > 0)
{
WriteEEtoFifo();
@ -262,6 +274,15 @@ static __fi void Sif1End()
__fi void SIF1Dma()
{
int BusyCheck = 0;
if (sif1_dma_stall)
{
const int writeSize = std::min((s32)sif1ch.qwc, sif1.fifo.sif_free() >> 2);
if ((sif1ch.madr + (writeSize * 16)) > dmacRegs.stadr.ADDR)
return;
}
sif1_dma_stall = false;
Sif1Init();
do
@ -269,7 +290,7 @@ __fi void SIF1Dma()
//I realise this is very hacky in a way but its an easy way of checking if both are doing something
BusyCheck = 0;
if (sif1.ee.busy)
if (sif1.ee.busy && !sif1_dma_stall)
{
if(sif1.fifo.sif_free() > 0 || (sif1.ee.end && sif1ch.qwc == 0))
{

View File

@ -164,7 +164,7 @@ __fi void vif1SetupTransfer()
if (!vif1.done && ((dmacRegs.ctrl.STD == STD_VIF1) && (ptag->ID == TAG_REFS))) // STD == VIF1
{
// there are still bugs, need to also check if gif->madr +16*qwc >= stadr, if not, stall
if ((vif1ch.madr + vif1ch.qwc * 16) >= dmacRegs.stadr.ADDR)
if ((vif1ch.madr + vif1ch.qwc * 16) > dmacRegs.stadr.ADDR)
{
//DevCon.Warning("VIF1 DMA Stall");
// stalled
@ -437,13 +437,6 @@ void dmaVIF1()
g_vif1Cycles = 0;
#ifdef PCSX2_DEVBUILD
if (dmacRegs.ctrl.STD == STD_VIF1)
{
//DevCon.WriteLn("VIF Stall Control Source = %x, Drain = %x", (psHu32(0xe000) >> 4) & 0x3, (psHu32(0xe000) >> 6) & 0x3);
}
#endif
if (vif1ch.qwc > 0) // Normal Mode
{

View File

@ -421,14 +421,50 @@ __fi bool dmacWrite32( u32 mem, mem32_t& value )
{
if (!QueuedDMA.empty()) StartQueuedDMA();
}
#ifdef PCSX2_DEVBUILD
if ((oldvalue & 0x30) != (value & 0x30))
{
DevCon.Warning("32bit Stall Source Changed to %x", (value & 0x30) >> 4);
std::string new_source;
switch ((value & 0x30) >> 4)
{
case 1:
new_source = "SIF0";
break;
case 2:
new_source = "fromSPR";
break;
case 3:
new_source = "fromIPU";
break;
default:
new_source = "None";
break;
}
DevCon.Warning("32bit Stall Source Changed to %s", new_source.c_str());
}
if ((oldvalue & 0xC0) != (value & 0xC0))
{
DevCon.Warning("32bit Stall Destination Changed to %x", (value & 0xC0) >> 4);
std::string new_dest;
switch ((value & 0xC0) >> 6)
{
case 1:
new_dest = "VIF1";
break;
case 2:
new_dest = "GIF";
break;
case 3:
new_dest = "SIF1";
break;
default:
new_dest = "None";
break;
}
DevCon.Warning("32bit Stall Destination Changed to %s", new_dest.c_str());
}
#endif
return false;
}