Play-/Source/iop/Iop_Dmacman.cpp
Jean-Philip Desjardins 30568a057d
Some checks failed
Build macOS / build_macos (push) Has been cancelled
Build Android / build_android (apk) (push) Has been cancelled
Build Android / build_android (libretro) (push) Has been cancelled
Build Linux ARM32 / build_linux_arm32 (push) Has been cancelled
Build Linux ARM64 / build_linux_arm64 (push) Has been cancelled
Build Windows Psf / build_windows_psf (off, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows Psf / build_windows_psf (on, x86_64, Visual Studio 16 2019, installer64.nsi, x64) (push) Has been cancelled
Build Windows / build_windows (x86_32, Visual Studio 16 2019, installer32.nsi, win32_msvc2019, Win32) (push) Has been cancelled
Build Windows / build_windows (x86_64, Visual Studio 16 2019, installer64.nsi, win64_msvc2019_64, x64) (push) Has been cancelled
Check Format / run_clangformat (push) Has been cancelled
Build iOS / build_ios (push) Has been cancelled
Build JavaScript / build_js (push) Has been cancelled
Build Linux / build_linux (push) Has been cancelled
Use app_config module.
2025-03-11 16:18:58 -04:00

289 lines
7.5 KiB
C++

#include "Iop_Dmacman.h"
#include "Iop_Dmac.h"
#include "Iop_DmacChannel.h"
#include "Log.h"
#define LOGNAME "iop_dmacman"
using namespace Iop;
#define FUNCTIONID_DMACSETDPCR 14
#define FUNCTIONID_DMACGETDPCR 15
#define FUNCTIONID_DMACSETDPCR2 16
#define FUNCTIONID_DMACGETDPCR2 17
#define FUNCTIONID_DMACSETDPCR3 18
#define FUNCTIONID_DMACGETDPCR3 19
#define FUNCTIONID_DMACREQUEST 28
#define FUNCTIONID_DMACTRANSFER 32
#define FUNCTIONID_DMACCHSETDPCR 33
#define FUNCTIONID_DMACENABLE 34
#define FUNCTIONID_DMACDISABLE 35
#define FUNCTION_DMACSETDPCR "DmacSetDpcr"
#define FUNCTION_DMACGETDPCR "DmacGetDpcr"
#define FUNCTION_DMACSETDPCR2 "DmacSetDpcr2"
#define FUNCTION_DMACGETDPCR2 "DmacGetDpcr2"
#define FUNCTION_DMACSETDPCR3 "DmacSetDpcr3"
#define FUNCTION_DMACGETDPCR3 "DmacGetDpcr3"
#define FUNCTION_DMACREQUEST "DmacRequest"
#define FUNCTION_DMACTRANSFER "DmacTransfer"
#define FUNCTION_DMACCHSETDPCR "DmacChSetDpcr"
#define FUNCTION_DMACENABLE "DmacEnable"
#define FUNCTION_DMACDISABLE "DmacDisable"
#define INVALID_CHANNEL_BASE (-1)
static uint32 GetChannelBase(uint32 channel)
{
switch(channel)
{
case CDmac::CHANNEL_SIO2in:
return CDmac::CH11_BASE;
case CDmac::CHANNEL_SIO2out:
return CDmac::CH12_BASE;
default:
CLog::GetInstance().Warn(LOGNAME, "Unknown channel (%d).\r\n", channel);
assert(false);
return INVALID_CHANNEL_BASE;
}
}
std::string CDmacman::GetId() const
{
return "dmacman";
}
std::string CDmacman::GetFunctionName(unsigned int functionId) const
{
switch(functionId)
{
case FUNCTIONID_DMACSETDPCR:
return FUNCTION_DMACSETDPCR;
case FUNCTIONID_DMACGETDPCR:
return FUNCTION_DMACGETDPCR;
case FUNCTIONID_DMACSETDPCR2:
return FUNCTION_DMACSETDPCR2;
case FUNCTIONID_DMACGETDPCR2:
return FUNCTION_DMACGETDPCR2;
case FUNCTIONID_DMACSETDPCR3:
return FUNCTION_DMACSETDPCR3;
case FUNCTIONID_DMACGETDPCR3:
return FUNCTION_DMACGETDPCR3;
case FUNCTIONID_DMACREQUEST:
return FUNCTION_DMACREQUEST;
case FUNCTIONID_DMACTRANSFER:
return FUNCTION_DMACTRANSFER;
case FUNCTIONID_DMACCHSETDPCR:
return FUNCTION_DMACCHSETDPCR;
case FUNCTIONID_DMACENABLE:
return FUNCTION_DMACENABLE;
case FUNCTIONID_DMACDISABLE:
return FUNCTION_DMACDISABLE;
default:
return "unknown";
break;
}
}
void CDmacman::Invoke(CMIPS& context, unsigned int functionId)
{
switch(functionId)
{
case FUNCTIONID_DMACSETDPCR:
DmacSetDpcr(
context,
context.m_State.nGPR[CMIPS::A0].nV0);
break;
case FUNCTIONID_DMACGETDPCR:
context.m_State.nGPR[CMIPS::V0].nV0 = DmacGetDpcr(
context);
break;
case FUNCTIONID_DMACSETDPCR2:
DmacSetDpcr2(
context,
context.m_State.nGPR[CMIPS::A0].nV0);
break;
case FUNCTIONID_DMACGETDPCR2:
context.m_State.nGPR[CMIPS::V0].nV0 = DmacGetDpcr2(
context);
break;
case FUNCTIONID_DMACSETDPCR3:
DmacSetDpcr3(
context,
context.m_State.nGPR[CMIPS::A0].nV0);
break;
case FUNCTIONID_DMACGETDPCR3:
context.m_State.nGPR[CMIPS::V0].nV0 = DmacGetDpcr3(
context);
break;
case FUNCTIONID_DMACREQUEST:
context.m_State.nGPR[CMIPS::V0].nV0 = DmacRequest(
context,
context.m_State.nGPR[CMIPS::A0].nV0,
context.m_State.nGPR[CMIPS::A1].nV0,
context.m_State.nGPR[CMIPS::A2].nV0,
context.m_State.nGPR[CMIPS::A3].nV0,
context.m_pMemoryMap->GetWord(context.m_State.nGPR[CMIPS::SP].nV0 + 0x10));
break;
case FUNCTIONID_DMACTRANSFER:
DmacTransfer(context, context.m_State.nGPR[CMIPS::A0].nV0);
break;
case FUNCTIONID_DMACCHSETDPCR:
DmacChSetDpcr(
context,
context.m_State.nGPR[CMIPS::A0].nV0,
context.m_State.nGPR[CMIPS::A1].nV0);
break;
case FUNCTIONID_DMACENABLE:
DmacEnable(
context,
context.m_State.nGPR[CMIPS::A0].nV0);
break;
case FUNCTIONID_DMACDISABLE:
DmacDisable(
context,
context.m_State.nGPR[CMIPS::A0].nV0);
break;
default:
CLog::GetInstance().Warn(LOGNAME, "%08X: Unknown function (%d) called.\r\n", context.m_State.nPC, functionId);
break;
}
}
void CDmacman::DmacSetDpcr(CMIPS& context, uint32 value)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACSETDPCR "(value = 0x%08X);\r\n", value);
context.m_pMemoryMap->SetWord(CDmac::DPCR, value);
}
uint32 CDmacman::DmacGetDpcr(CMIPS& context)
{
return context.m_pMemoryMap->GetWord(CDmac::DPCR);
}
void CDmacman::DmacSetDpcr2(CMIPS& context, uint32 value)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACSETDPCR2 "(value = 0x%08X);\r\n", value);
context.m_pMemoryMap->SetWord(CDmac::DPCR2, value);
}
uint32 CDmacman::DmacGetDpcr2(CMIPS& context)
{
return context.m_pMemoryMap->GetWord(CDmac::DPCR2);
}
void CDmacman::DmacSetDpcr3(CMIPS& context, uint32 value)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACSETDPCR3 "(value = 0x%08X);\r\n", value);
context.m_pMemoryMap->SetWord(CDmac::DPCR3, value);
}
uint32 CDmacman::DmacGetDpcr3(CMIPS& context)
{
return context.m_pMemoryMap->GetWord(CDmac::DPCR3);
}
uint32 CDmacman::DmacRequest(CMIPS& context, uint32 channel, uint32 addr, uint32 size, uint32 count, uint32 dir)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACREQUEST "(channel = %d, address = 0x%08X, size = 0x%08X, count = 0x%08X, dir = %d);\r\n",
channel, addr, size, count, dir);
assert(size < 0x10000);
assert(count < 0x10000);
uint32 channelBase = GetChannelBase(channel);
if(channelBase == INVALID_CHANNEL_BASE)
{
CLog::GetInstance().Warn(LOGNAME, "Received " FUNCTION_DMACREQUEST " for invalid channel %d\r\n", channel);
return 0;
}
uint32 bcr = size | (count << 16);
context.m_pMemoryMap->SetWord(channelBase + Dmac::CChannel::REG_MADR, addr);
context.m_pMemoryMap->SetWord(channelBase + Dmac::CChannel::REG_BCR, bcr);
return 1;
}
void CDmacman::DmacTransfer(CMIPS& context, uint32 channel)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACTRANSFER "(channel = %d);\r\n", channel);
auto chcr = make_convertible<Dmac::CChannel::CHCR>(0);
chcr.tr = 1;
chcr.co = 1;
chcr.dr = 1; //Direction?
uint32 channelBase = GetChannelBase(channel);
if(channelBase == INVALID_CHANNEL_BASE)
{
CLog::GetInstance().Warn(LOGNAME, "Received " FUNCTION_DMACTRANSFER " for invalid channel %d\r\n", channel);
return;
}
context.m_pMemoryMap->SetWord(channelBase + Dmac::CChannel::REG_CHCR, chcr);
}
void CDmacman::DmacChSetDpcr(CMIPS& context, uint32 channel, uint32 value)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACCHSETDPCR "(channel = %d, value = 0x%08X);\r\n", channel, value);
uint32 dpcrAddr = GetDPCRAddr(channel);
uint32 dpcr = context.m_pMemoryMap->GetWord(dpcrAddr);
uint32 mask = ~(0x7 << ((channel % 7) * 4));
dpcr = (dpcr & mask) | ((value & 0x7) << ((channel % 7) * 4));
context.m_pMemoryMap->SetWord(dpcrAddr, dpcr | mask);
return;
}
void CDmacman::DmacEnable(CMIPS& context, uint32 channel)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACENABLE "(channel = %d);\r\n", channel);
uint32 dpcrAddr = GetDPCRAddr(channel);
uint32 dpcr = context.m_pMemoryMap->GetWord(dpcrAddr);
uint32 mask = 0x8 << ((channel % 7) * 4);
context.m_pMemoryMap->SetWord(dpcrAddr, dpcr | mask);
return;
}
void CDmacman::DmacDisable(CMIPS& context, uint32 channel)
{
CLog::GetInstance().Print(LOGNAME, FUNCTION_DMACDISABLE "(channel = %d);\r\n", channel);
uint32 dpcrAddr = GetDPCRAddr(channel);
uint32 dpcr = context.m_pMemoryMap->GetWord(dpcrAddr);
uint32 mask = ~(0x8 << ((channel % 7) * 4));
context.m_pMemoryMap->SetWord(dpcrAddr, dpcr & mask);
return;
}
uint32 CDmacman::GetDPCRAddr(uint32 channel)
{
// 0 - 6
if(channel < 7)
{
return CDmac::DPCR;
}
// 7 - 12
else if(channel < 13)
{
return CDmac::DPCR2;
}
// 13 - 15 (i.Link)
else if(channel < 16)
{
return CDmac::DPCR3;
}
return 0;
}