From 647e61c73acadb40773eedbb2d1e4c754709047f Mon Sep 17 00:00:00 2001 From: refractionpcsx2 Date: Thu, 14 Sep 2023 12:51:29 +0100 Subject: [PATCH] IPU: Adjust DMA timings, improve internal calling [SAVEVERSION+] --- pcsx2/IPU/IPU.cpp | 20 +++++------ pcsx2/IPU/IPU.h | 4 +-- pcsx2/IPU/IPU_Fifo.cpp | 19 +++++----- pcsx2/IPU/IPU_MultiISA.cpp | 34 +++++++++++++++--- pcsx2/IPU/IPUdma.cpp | 73 +++++++++++++++++++------------------- pcsx2/IPU/IPUdma.h | 10 ++++-- pcsx2/SaveState.h | 2 +- 7 files changed, 94 insertions(+), 68 deletions(-) diff --git a/pcsx2/IPU/IPU.cpp b/pcsx2/IPU/IPU.cpp index 3c745277758d66..036397dc31cf38 100644 --- a/pcsx2/IPU/IPU.cpp +++ b/pcsx2/IPU/IPU.cpp @@ -27,6 +27,7 @@ alignas(16) tIPU_cmd ipu_cmd; alignas(16) tIPU_BP g_BP; alignas(16) decoder_t decoder; +IPUStatus IPUCoreStatus; static void (*IPUWorker)(); @@ -92,15 +93,8 @@ void tIPU_cmd::clear() __fi void IPUProcessInterrupt() { - if (ipuRegs.ctrl.BUSY && !CommandExecuteQueued) + if (ipuRegs.ctrl.BUSY) IPUWorker(); - - if (ipuRegs.ctrl.BUSY && !IPU1Status.DataRequested && !(cpuRegs.interrupt & 1 << IPU_PROCESS)) - { - CPU_INT(IPU_PROCESS, ProcessedData ? ProcessedData : 64); - } - else - ProcessedData = 0; } ///////////////////////////////////////////////////////// @@ -112,6 +106,9 @@ void ipuReset() std::memset(&ipuRegs, 0, sizeof(ipuRegs)); std::memset(&g_BP, 0, sizeof(g_BP)); std::memset(&decoder, 0, sizeof(decoder)); + IPUCoreStatus.DataRequested = false; + IPUCoreStatus.WaitingOnIPUFrom= false; + IPUCoreStatus.WaitingOnIPUTo = false; decoder.picture_structure = FRAME_PICTURE; //default: progressive...my guess:P @@ -149,6 +146,7 @@ bool SaveStateBase::ipuFreeze() Freeze(coded_block_pattern); Freeze(decoder); Freeze(ipu_cmd); + Freeze(IPUCoreStatus); return IsOkay(); } @@ -471,7 +469,6 @@ __fi void IPUCMD_WRITE(u32 val) { // don't process anything if currently busy //if (ipuRegs.ctrl.BUSY) Console.WriteLn("IPU BUSY!"); // wait for thread - ProcessedData = 0; ipuRegs.ctrl.ECD = 0; ipuRegs.ctrl.SCD = 0; ipu_cmd.clear(); @@ -538,9 +535,10 @@ __fi void IPUCMD_WRITE(u32 val) // Have a short delay immitating the time it takes to run IDEC/BDEC, other commands are near instant. // Mana Khemia/Metal Saga start IDEC then change IPU0 expecting there to be a delay before IDEC sends data. - if (!CommandExecuteQueued && (ipu_cmd.CMD == SCE_IPU_IDEC || ipu_cmd.CMD == SCE_IPU_BDEC)) + if (ipu_cmd.CMD == SCE_IPU_IDEC || ipu_cmd.CMD == SCE_IPU_BDEC) { - CommandExecuteQueued = true; + IPUCoreStatus.WaitingOnIPUFrom = false; + IPUCoreStatus.WaitingOnIPUTo = false; CPU_INT(IPU_PROCESS, 64); } else diff --git a/pcsx2/IPU/IPU.h b/pcsx2/IPU/IPU.h index 2b180d87a6966f..c135c8290ce64e 100644 --- a/pcsx2/IPU/IPU.h +++ b/pcsx2/IPU/IPU.h @@ -132,7 +132,7 @@ struct alignas(16) tIPU_BP { // be possible -- so if the fill fails we'll only return 0 if we don't have enough // remaining bits in the FIFO to fill the request. // Used to do ((FP!=0) && (BP + bits) <= 128) if we get here there's defo not enough data now though - + IPUCoreStatus.WaitingOnIPUTo = true; return false; } @@ -293,8 +293,6 @@ extern bool EnableFMV; alignas(16) extern tIPU_cmd ipu_cmd; extern uint eecount_on_last_vdec; -extern bool CommandExecuteQueued; -extern u32 ProcessedData; extern void ipuReset(); diff --git a/pcsx2/IPU/IPU_Fifo.cpp b/pcsx2/IPU/IPU_Fifo.cpp index 8c73ab149526e7..d0a39aac15dbdc 100644 --- a/pcsx2/IPU/IPU_Fifo.cpp +++ b/pcsx2/IPU/IPU_Fifo.cpp @@ -40,7 +40,7 @@ void IPU_Fifo_Input::clear() writepos = 0; // Because the FIFO is drained it will request more data immediately - IPU1Status.DataRequested = true; + IPUCoreStatus.DataRequested = true; if (ipu1ch.chcr.STR && cpuRegs.eCycle[4] == 0x9999) { @@ -91,9 +91,7 @@ int IPU_Fifo_Input::write(const u32* pMem, int size) g_BP.IFC += transfer_size; if (g_BP.IFC == 8) - IPU1Status.DataRequested = false; - - CPU_INT(IPU_PROCESS, transfer_size * BIAS); + IPUCoreStatus.DataRequested = false; return transfer_size; } @@ -104,7 +102,7 @@ int IPU_Fifo_Input::read(void *value) if (g_BP.IFC <= 1) { // IPU FIFO is empty and DMA is waiting so lets tell the DMA we are ready to put data in the FIFO - IPU1Status.DataRequested = true; + IPUCoreStatus.DataRequested = true; if(ipu1ch.chcr.STR && cpuRegs.eCycle[4] == 0x9999) { @@ -142,7 +140,7 @@ int IPU_Fifo_Output::write(const u32 *value, uint size) ipuRegs.ctrl.OFC += transfer_size; if(ipu0ch.chcr.STR) - IPU_INT_FROM(ipuRegs.ctrl.OFC * BIAS); + IPU_INT_FROM(1); return transfer_size; } @@ -181,12 +179,13 @@ void WriteFIFO_IPUin(const mem128_t* value) IPU_LOG( "WriteFIFO/IPUin <- 0x%08X.%08X.%08X.%08X", value->_u32[0], value->_u32[1], value->_u32[2], value->_u32[3]); //committing every 16 bytes - if( ipu_fifo.in.write(value->_u32, 1) == 0 ) + if( ipu_fifo.in.write(value->_u32, 1) > 0 ) { - if (ipuRegs.ctrl.BUSY && !CommandExecuteQueued) + if (ipuRegs.ctrl.BUSY && IPUCoreStatus.WaitingOnIPUTo) { - CommandExecuteQueued = false; - CPU_INT(IPU_PROCESS, 8); + IPUCoreStatus.WaitingOnIPUFrom = false; + IPUCoreStatus.WaitingOnIPUTo = false; + CPU_INT(IPU_PROCESS, 2 * BIAS); } } } diff --git a/pcsx2/IPU/IPU_MultiISA.cpp b/pcsx2/IPU/IPU_MultiISA.cpp index 86faebf846a979..c49db385231f60 100644 --- a/pcsx2/IPU/IPU_MultiISA.cpp +++ b/pcsx2/IPU/IPU_MultiISA.cpp @@ -1010,6 +1010,7 @@ __ri static bool mpeg2sliceIDEC() // IPU0 isn't ready for data, so let's wait for it to be if ((!ipu0ch.chcr.STR || ipuRegs.ctrl.OFC || ipu0ch.qwc == 0) && ipu_cmd.pos[1] <= 2) { + IPUCoreStatus.WaitingOnIPUFrom = true; return false; } macroblock_8& mb8 = decoder.mb8; @@ -1123,6 +1124,8 @@ __ri static bool mpeg2sliceIDEC() if (ready_to_decode == true) { ready_to_decode = false; + IPUCoreStatus.WaitingOnIPUFrom = false; + IPUCoreStatus.WaitingOnIPUTo = false; CPU_INT(IPU_PROCESS, 64); // Should probably be much higher, but myst 3 doesn't like it right now. ipu_cmd.pos[1] = 2; return false; @@ -1134,6 +1137,7 @@ __ri static bool mpeg2sliceIDEC() if (decoder.ipu0_data != 0) { // IPU FIFO filled up -- Will have to finish transferring later. + IPUCoreStatus.WaitingOnIPUFrom = true; ipu_cmd.pos[1] = 2; return false; } @@ -1141,6 +1145,7 @@ __ri static bool mpeg2sliceIDEC() mbaCount = 0; if (read) { + IPUCoreStatus.WaitingOnIPUFrom = true; ipu_cmd.pos[1] = 3; return false; } @@ -1308,6 +1313,7 @@ __fi static bool mpeg2_slice() // IPU0 isn't ready for data, so let's wait for it to be if ((!ipu0ch.chcr.STR || ipuRegs.ctrl.OFC || ipu0ch.qwc == 0) && ipu_cmd.pos[0] <= 3) { + IPUCoreStatus.WaitingOnIPUFrom = true; return false; } @@ -1514,6 +1520,8 @@ __fi static bool mpeg2_slice() { ipu_cmd.pos[0] = 3; ready_to_decode = false; + IPUCoreStatus.WaitingOnIPUFrom = false; + IPUCoreStatus.WaitingOnIPUTo = false; CPU_INT(IPU_PROCESS, 64); // Should probably be much higher, but myst 3 doesn't like it right now. return false; } @@ -1525,6 +1533,7 @@ __fi static bool mpeg2_slice() if (decoder.ipu0_data != 0) { // IPU FIFO filled up -- Will have to finish transferring later. + IPUCoreStatus.WaitingOnIPUFrom = true; ipu_cmd.pos[0] = 3; return false; } @@ -1532,6 +1541,7 @@ __fi static bool mpeg2_slice() mbaCount = 0; if (read) { + IPUCoreStatus.WaitingOnIPUFrom = true; ipu_cmd.pos[0] = 4; return false; } @@ -1801,12 +1811,20 @@ __ri static bool ipuCSC(tIPU_CMD_CSC csc) if (csc.OFM) { ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]); - if (ipu_cmd.pos[1] < 32) return false; + if (ipu_cmd.pos[1] < 32) + { + IPUCoreStatus.WaitingOnIPUFrom = true; + return false; + } } else { ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb32) + 4 * ipu_cmd.pos[1], 64 - ipu_cmd.pos[1]); - if (ipu_cmd.pos[1] < 64) return false; + if (ipu_cmd.pos[1] < 64) + { + IPUCoreStatus.WaitingOnIPUFrom = true; + return false; + } } ipu_cmd.pos[0] = 0; @@ -1834,12 +1852,20 @@ __ri static bool ipuPACK(tIPU_CMD_CSC csc) if (csc.OFM) { ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*) & decoder.rgb16) + 4 * ipu_cmd.pos[1], 32 - ipu_cmd.pos[1]); - if (ipu_cmd.pos[1] < 32) return false; + if (ipu_cmd.pos[1] < 32) + { + IPUCoreStatus.WaitingOnIPUFrom = true; + return false; + } } else { ipu_cmd.pos[1] += ipu_fifo.out.write(((u32*)g_ipu_indx4) + 4 * ipu_cmd.pos[1], 8 - ipu_cmd.pos[1]); - if (ipu_cmd.pos[1] < 8) return false; + if (ipu_cmd.pos[1] < 8) + { + IPUCoreStatus.WaitingOnIPUFrom = true; + return false; + } } ipu_cmd.pos[0] = 0; diff --git a/pcsx2/IPU/IPUdma.cpp b/pcsx2/IPU/IPUdma.cpp index c3f33be299b7ee..378308378270d9 100644 --- a/pcsx2/IPU/IPUdma.cpp +++ b/pcsx2/IPU/IPUdma.cpp @@ -19,16 +19,12 @@ #include "IPU/IPUdma.h" #include "IPU/IPU_MultiISA.h" -IPUStatus IPU1Status; -bool CommandExecuteQueued; -u32 ProcessedData; +IPUDMAStatus IPU1Status; void ipuDmaReset() { IPU1Status.InProgress = false; IPU1Status.DMAFinished = true; - CommandExecuteQueued = false; - ProcessedData = 0; } bool SaveStateBase::ipuDmaFreeze() @@ -37,7 +33,6 @@ bool SaveStateBase::ipuDmaFreeze() return false; Freeze(IPU1Status); - Freeze(CommandExecuteQueued); return IsOkay(); } @@ -83,11 +78,18 @@ void IPU1dma() return; } - if (IPU1Status.DataRequested == false) + if (IPUCoreStatus.DataRequested == false) { // IPU isn't expecting any data, so put it in to wait mode. cpuRegs.eCycle[4] = 0x9999; CPU_SET_DMASTALL(DMAC_TO_IPU, true); + + // Shouldn't Happen. + if (IPUCoreStatus.WaitingOnIPUTo) + { + IPUCoreStatus.WaitingOnIPUTo = false; + CPU_INT(IPU_PROCESS, 4 * BIAS); + } return; } @@ -127,26 +129,22 @@ void IPU1dma() if (IPU1Status.InProgress) totalqwc += IPU1chain(); - //Do this here to prevent double settings on Chain DMA's - if((totalqwc == 0 && g_BP.IFC < 8) || (IPU1Status.DMAFinished && !IPU1Status.InProgress)) + // Nothing has been processed except maybe a tag, or the DMA is ending + if(totalqwc == 0 || (IPU1Status.DMAFinished && !IPU1Status.InProgress) || IPUCoreStatus.DataRequested) { totalqwc = std::max(4, totalqwc) + tagcycles; IPU_INT_TO(totalqwc * BIAS); } else { - IPU1Status.DataRequested = false; - - if (!(IPU1Status.DMAFinished && !IPU1Status.InProgress)) - { - cpuRegs.eCycle[4] = 0x9999;//IPU_INT_TO(2048); + cpuRegs.eCycle[4] = 0x9999; CPU_SET_DMASTALL(DMAC_TO_IPU, true); - } - else - { - totalqwc = std::max(4, totalqwc) + tagcycles; - IPU_INT_TO(totalqwc * BIAS); - } + } + + if (IPUCoreStatus.WaitingOnIPUTo && g_BP.IFC >= 1) + { + IPUCoreStatus.WaitingOnIPUTo = false; + CPU_INT(IPU_PROCESS, totalqwc * BIAS); } IPU_LOG("Completed Call IPU1 DMA QWC Remaining %x Finished %d In Progress %d tadr %x", ipu1ch.qwc, IPU1Status.DMAFinished, IPU1Status.InProgress, ipu1ch.tadr); @@ -156,8 +154,12 @@ void IPU0dma() { if(!ipuRegs.ctrl.OFC) { - if(!CommandExecuteQueued) + // This shouldn't happen. + if (IPUCoreStatus.WaitingOnIPUFrom) + { + IPUCoreStatus.WaitingOnIPUFrom = false; IPUProcessInterrupt(); + } CPU_SET_DMASTALL(DMAC_FROM_IPU, true); return; } @@ -168,6 +170,12 @@ void IPU0dma() if ((!(ipu0ch.chcr.STR) || (cpuRegs.interrupt & (1 << DMAC_FROM_IPU))) || (ipu0ch.qwc == 0)) { DevCon.Warning("How??"); + // This shouldn't happen. + if (IPUCoreStatus.WaitingOnIPUFrom) + { + IPUCoreStatus.WaitingOnIPUFrom = false; + CPU_INT(IPU_PROCESS, ipuRegs.ctrl.OFC * BIAS); + } return; } @@ -195,11 +203,12 @@ void IPU0dma() if (!ipu0ch.qwc) IPU_INT_FROM(readsize * BIAS); - if (ipuRegs.ctrl.BUSY && !CommandExecuteQueued) + CPU_SET_DMASTALL(DMAC_FROM_IPU, true); + + if (ipuRegs.ctrl.BUSY && IPUCoreStatus.WaitingOnIPUFrom) { - CommandExecuteQueued = false; - CPU_SET_DMASTALL(DMAC_FROM_IPU, true); - IPUProcessInterrupt(); + IPUCoreStatus.WaitingOnIPUFrom = false; + CPU_INT(IPU_PROCESS, readsize * BIAS); } } @@ -259,29 +268,19 @@ __fi void dmaIPU1() // toIPU IPU1Status.DMAFinished = false; } } - - if(IPU1Status.DataRequested) - IPU1dma(); - else - cpuRegs.eCycle[4] = 0x9999; } else // Normal Mode { IPU_LOG("Setting up IPU1 Normal mode"); IPU1Status.InProgress = true; IPU1Status.DMAFinished = true; - - if (IPU1Status.DataRequested) - IPU1dma(); - else - cpuRegs.eCycle[4] = 0x9999; } + + IPU1dma(); } void ipuCMDProcess() { - CommandExecuteQueued = false; - ProcessedData = 0; IPUProcessInterrupt(); } diff --git a/pcsx2/IPU/IPUdma.h b/pcsx2/IPU/IPUdma.h index 9f7db0f37e6ffc..f8065af891d38d 100644 --- a/pcsx2/IPU/IPUdma.h +++ b/pcsx2/IPU/IPUdma.h @@ -17,10 +17,15 @@ #include "IPU.h" -struct IPUStatus { +struct IPUDMAStatus { bool InProgress; bool DMAFinished; +}; + +struct IPUStatus { bool DataRequested; + bool WaitingOnIPUFrom; + bool WaitingOnIPUTo; }; extern void ipuCMDProcess(); @@ -33,4 +38,5 @@ extern void IPU0dma(); extern void IPU1dma(); extern void ipuDmaReset(); -extern IPUStatus IPU1Status; +extern IPUDMAStatus IPU1Status; +extern IPUStatus IPUCoreStatus; diff --git a/pcsx2/SaveState.h b/pcsx2/SaveState.h index 13d363f006bc28..722b0916712847 100644 --- a/pcsx2/SaveState.h +++ b/pcsx2/SaveState.h @@ -37,7 +37,7 @@ enum class FreezeAction // [SAVEVERSION+] // This informs the auto updater that the users savestates will be invalidated. -static const u32 g_SaveVersion = (0x9A40 << 16) | 0x0000; +static const u32 g_SaveVersion = (0x9A41 << 16) | 0x0000; // the freezing data between submodules and core