IPU: Adjust DMA timings, improve internal calling

[SAVEVERSION+]
This commit is contained in:
refractionpcsx2 2023-09-14 12:51:29 +01:00
parent 2947e11b9b
commit ae5cd7b3c3
7 changed files with 94 additions and 68 deletions

View File

@ -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

View File

@ -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();

View File

@ -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);
}
}
}

View File

@ -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;

View File

@ -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
if (IPUCoreStatus.WaitingOnIPUTo && g_BP.IFC >= 1)
{
totalqwc = std::max(4, totalqwc) + tagcycles;
IPU_INT_TO(totalqwc * BIAS);
}
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)
{
CommandExecuteQueued = false;
CPU_SET_DMASTALL(DMAC_FROM_IPU, true);
IPUProcessInterrupt();
if (ipuRegs.ctrl.BUSY && IPUCoreStatus.WaitingOnIPUFrom)
{
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();
}

View File

@ -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;

View File

@ -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