From 40d02400ca004845e21d8656d3d484c090103c6b Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Fri, 18 Sep 2020 16:23:18 +0100 Subject: [PATCH] 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 --- pcsx2/Gif.cpp | 4 ++-- pcsx2/IPU/IPUdma.cpp | 7 ++++++- pcsx2/SPR.cpp | 36 ++++++++++++++++++------------------ pcsx2/Sif0.cpp | 16 +++++++++------- pcsx2/Sif1.cpp | 31 ++++++++++++++++++++++++++----- pcsx2/Vif1_Dma.cpp | 9 +-------- pcsx2/ps2/LegacyDmac.cpp | 40 ++++++++++++++++++++++++++++++++++++++-- 7 files changed, 100 insertions(+), 43 deletions(-) diff --git a/pcsx2/Gif.cpp b/pcsx2/Gif.cpp index ae012984e3..3f812321d3 100644 --- a/pcsx2/Gif.cpp +++ b/pcsx2/Gif.cpp @@ -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; } diff --git a/pcsx2/IPU/IPUdma.cpp b/pcsx2/IPU/IPUdma.cpp index a4a1cbfb05..d6c87fc3a5 100644 --- a/pcsx2/IPU/IPUdma.cpp +++ b/pcsx2/IPU/IPUdma.cpp @@ -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 ); diff --git a/pcsx2/SPR.cpp b/pcsx2/SPR.cpp index f76ba519d3..fd1bd216e3 100644 --- a/pcsx2/SPR.cpp +++ b/pcsx2/SPR.cpp @@ -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; diff --git a/pcsx2/Sif0.cpp b/pcsx2/Sif0.cpp index 9eec28801f..05a814a61b 100644 --- a/pcsx2/Sif0.cpp +++ b/pcsx2/Sif0.cpp @@ -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){ diff --git a/pcsx2/Sif1.cpp b/pcsx2/Sif1.cpp index 69d94c8767..2e7dcd0270 100644 --- a/pcsx2/Sif1.cpp +++ b/pcsx2/Sif1.cpp @@ -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)) { diff --git a/pcsx2/Vif1_Dma.cpp b/pcsx2/Vif1_Dma.cpp index 2b9a399904..e6977269b0 100644 --- a/pcsx2/Vif1_Dma.cpp +++ b/pcsx2/Vif1_Dma.cpp @@ -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 { diff --git a/pcsx2/ps2/LegacyDmac.cpp b/pcsx2/ps2/LegacyDmac.cpp index 01a42a3dcd..905c663a59 100644 --- a/pcsx2/ps2/LegacyDmac.cpp +++ b/pcsx2/ps2/LegacyDmac.cpp @@ -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; }