Skip to content

Commit

Permalink
Add some delay to SIF transfers from IOP.
Browse files Browse the repository at this point in the history
  • Loading branch information
jpd002 committed Sep 11, 2024
1 parent 9752b30 commit b0f1fce
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 33 deletions.
3 changes: 2 additions & 1 deletion Source/iop/IopBios.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ void CIopBios::Reset(uint32 ramSize, const Iop::SifManPtr& sifMan)
m_sifMan->SetCmdBuffer(sifCmdBufferPtr, sifCmdBufferSize);
}

m_sifMan->GenerateHandlers(m_ram, *m_sysmem);
m_sifMan->PrepareModuleData(m_ram, *m_sysmem);

InitializeModuleStarter();

Expand Down Expand Up @@ -1913,6 +1913,7 @@ uint64 CIopBios::ClockToMicroSec(uint64 clock)
void CIopBios::CountTicks(uint32 ticks)
{
CurrentTime() += ticks;
m_sifMan->CountTicks(ticks);
#ifdef _IOP_EMULATE_MODULES
m_cdvdman->CountTicks(ticks);
m_mcserv->CountTicks(ticks, m_sifMan.get());
Expand Down
71 changes: 46 additions & 25 deletions Source/iop/Iop_SifMan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,6 @@

using namespace Iop;

CSifMan::CSifMan()
: m_sifSetDmaCallbackHandlerPtr(0)
{
}

std::string CSifMan::GetId() const
{
return "sifman";
Expand Down Expand Up @@ -75,46 +70,72 @@ void CSifMan::Invoke(CMIPS& context, unsigned int functionId)
}
}

void CSifMan::GenerateHandlers(uint8* ram, CSysmem& sysMem)
void CSifMan::PrepareModuleData(uint8* ram, CSysmem& sysMem)
{
const uint32 handlerAllocSize = 64;
assert(m_moduleData == nullptr);
assert(m_sifSetDmaCallbackHandlerAddr == 0);

uint32 moduleDataAddr = sysMem.AllocateMemory(sizeof(MODULEDATA), 0, 0);

m_moduleData = reinterpret_cast<MODULEDATA*>(ram + moduleDataAddr);
m_sifSetDmaCallbackHandlerAddr = moduleDataAddr + offsetof(MODULEDATA, sifSetDmaCallbackHandler);

//Assemble handler
{
CMIPSAssembler assembler(reinterpret_cast<uint32*>(ram + m_sifSetDmaCallbackHandlerAddr));

assert(m_sifSetDmaCallbackHandlerPtr == 0);
m_sifSetDmaCallbackHandlerPtr = sysMem.AllocateMemory(handlerAllocSize, 0, 0);
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0xFFF0);
//SP + 0x00 is the space to store A0 by handler
assembler.SW(CMIPS::RA, 0x04, CMIPS::SP);
assembler.SW(CMIPS::S0, 0x08, CMIPS::SP);

CMIPSAssembler assembler(reinterpret_cast<uint32*>(ram + m_sifSetDmaCallbackHandlerPtr));
assembler.ADDU(CMIPS::S0, CMIPS::V0, CMIPS::R0);
assembler.JALR(CMIPS::A1);
assembler.NOP();

assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0xFFF0);
//SP + 0x00 is the space to store A0 by handler
assembler.SW(CMIPS::RA, 0x04, CMIPS::SP);
assembler.SW(CMIPS::S0, 0x08, CMIPS::SP);
assembler.ADDU(CMIPS::V0, CMIPS::S0, CMIPS::R0);

assembler.ADDU(CMIPS::S0, CMIPS::V0, CMIPS::R0);
assembler.JALR(CMIPS::A1);
assembler.NOP();
assembler.LW(CMIPS::S0, 0x08, CMIPS::SP);
assembler.LW(CMIPS::RA, 0x04, CMIPS::SP);
assembler.JR(CMIPS::RA);
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0x0010);

assembler.ADDU(CMIPS::V0, CMIPS::S0, CMIPS::R0);
assert((assembler.GetProgramSize() * 4) <= SIFSETDMACALLBACK_HANDLER_SIZE);
}

assembler.LW(CMIPS::S0, 0x08, CMIPS::SP);
assembler.LW(CMIPS::RA, 0x04, CMIPS::SP);
assembler.JR(CMIPS::RA);
assembler.ADDIU(CMIPS::SP, CMIPS::SP, 0x0010);
m_moduleData->dmaTransferTime = 0;
}

assert((assembler.GetProgramSize() * 4) <= handlerAllocSize);
void CSifMan::CountTicks(int32 ticks)
{
m_moduleData->dmaTransferTime = std::max(0, m_moduleData->dmaTransferTime - ticks);
}

uint32 CSifMan::SifSetDma(uint32 structAddr, uint32 count)
{
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SIFSETDMA "(structAddr = 0x%08X, count = %d);\r\n",
structAddr, count);
//Reset delay regardless of what we're sending
//This doesn't seem to cause harm, but if it does, we could associate a transfer id
//with a time and have SifDmaStat check for a specific transfer id
//This is needed because RenderWare FS code doesn't expect SIF CMD callbacks to
//arrive so quickly
m_moduleData->dmaTransferTime = 0x800;
return count;
}

uint32 CSifMan::SifDmaStat(uint32 transferId)
{
CLog::GetInstance().Print(LOG_NAME, FUNCTION_SIFDMASTAT "(transferId = %X);\r\n",
transferId);
return -1;
if(m_moduleData->dmaTransferTime != 0)
{
return 0;
}
else
{
return -1;
}
}

uint32 CSifMan::SifCheckInit()
Expand All @@ -130,7 +151,7 @@ uint32 CSifMan::SifSetDmaCallback(CMIPS& context, uint32 structAddr, uint32 coun
structAddr, count, callbackPtr, callbackParam);

//Modify context so we can execute the callback function
context.m_State.nPC = m_sifSetDmaCallbackHandlerPtr;
context.m_State.nPC = m_sifSetDmaCallbackHandlerAddr;
context.m_State.nGPR[CMIPS::A0].nV0 = callbackParam;
context.m_State.nGPR[CMIPS::A1].nV0 = callbackPtr;

Expand Down
29 changes: 22 additions & 7 deletions Source/iop/Iop_SifMan.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ namespace Iop
typedef std::function<void(const std::string&)> ModuleResetHandler;
typedef std::function<void(uint32)> CustomCommandHandler;

CSifMan();
CSifMan() = default;
virtual ~CSifMan() = default;

void GenerateHandlers(uint8*, CSysmem&);
void PrepareModuleData(uint8*, CSysmem&);
void CountTicks(int32);

std::string GetId() const override;
std::string GetFunctionName(unsigned int) const override;
Expand All @@ -36,12 +37,26 @@ namespace Iop

virtual uint32 SifSetDma(uint32, uint32);

protected:
virtual uint32 SifDmaStat(uint32);
private:
uint32 SifDmaStat(uint32);
uint32 SifCheckInit();
virtual uint32 SifSetDmaCallback(CMIPS&, uint32, uint32, uint32, uint32);

uint32 m_sifSetDmaCallbackHandlerPtr;
uint32 SifSetDmaCallback(CMIPS&, uint32, uint32, uint32, uint32);

enum
{
SIFSETDMACALLBACK_HANDLER_SIZE = 0x30,
};

struct MODULEDATA
{
uint8 sifSetDmaCallbackHandler[SIFSETDMACALLBACK_HANDLER_SIZE];
int32 dmaTransferTime;
int32 padding[3];
};
static_assert(sizeof(MODULEDATA) == 0x40);

MODULEDATA* m_moduleData = nullptr;
uint32 m_sifSetDmaCallbackHandlerAddr = 0;
};

typedef std::shared_ptr<CSifMan> SifManPtr;
Expand Down

0 comments on commit b0f1fce

Please sign in to comment.