2020-03-15 14:59:54 -04:00
|
|
|
#include "Iop_Dmacman.h"
|
|
|
|
#include "Iop_Dmac.h"
|
|
|
|
#include "Iop_DmacChannel.h"
|
2025-03-11 12:48:26 -04:00
|
|
|
#include "Log.h"
|
2020-03-15 14:59:54 -04:00
|
|
|
|
|
|
|
#define LOGNAME "iop_dmacman"
|
|
|
|
|
|
|
|
using namespace Iop;
|
|
|
|
|
2021-05-17 18:05:54 +02:00
|
|
|
#define FUNCTIONID_DMACSETDPCR 14
|
|
|
|
#define FUNCTIONID_DMACGETDPCR 15
|
|
|
|
#define FUNCTIONID_DMACSETDPCR2 16
|
|
|
|
#define FUNCTIONID_DMACGETDPCR2 17
|
|
|
|
#define FUNCTIONID_DMACSETDPCR3 18
|
|
|
|
#define FUNCTIONID_DMACGETDPCR3 19
|
2020-03-15 14:59:54 -04:00
|
|
|
#define FUNCTIONID_DMACREQUEST 28
|
|
|
|
#define FUNCTIONID_DMACTRANSFER 32
|
2020-07-13 20:16:53 +02:00
|
|
|
#define FUNCTIONID_DMACCHSETDPCR 33
|
|
|
|
#define FUNCTIONID_DMACENABLE 34
|
|
|
|
#define FUNCTIONID_DMACDISABLE 35
|
2020-03-15 14:59:54 -04:00
|
|
|
|
2021-05-17 18:05:54 +02:00
|
|
|
#define FUNCTION_DMACSETDPCR "DmacSetDpcr"
|
|
|
|
#define FUNCTION_DMACGETDPCR "DmacGetDpcr"
|
|
|
|
#define FUNCTION_DMACSETDPCR2 "DmacSetDpcr2"
|
|
|
|
#define FUNCTION_DMACGETDPCR2 "DmacGetDpcr2"
|
|
|
|
#define FUNCTION_DMACSETDPCR3 "DmacSetDpcr3"
|
|
|
|
#define FUNCTION_DMACGETDPCR3 "DmacGetDpcr3"
|
2020-03-15 14:59:54 -04:00
|
|
|
#define FUNCTION_DMACREQUEST "DmacRequest"
|
|
|
|
#define FUNCTION_DMACTRANSFER "DmacTransfer"
|
2020-07-13 20:16:53 +02:00
|
|
|
#define FUNCTION_DMACCHSETDPCR "DmacChSetDpcr"
|
|
|
|
#define FUNCTION_DMACENABLE "DmacEnable"
|
|
|
|
#define FUNCTION_DMACDISABLE "DmacDisable"
|
2020-03-15 14:59:54 -04:00
|
|
|
|
|
|
|
#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:
|
2021-05-21 18:14:39 +02:00
|
|
|
CLog::GetInstance().Warn(LOGNAME, "Unknown channel (%d).\r\n", channel);
|
2020-03-15 14:59:54 -04:00
|
|
|
assert(false);
|
|
|
|
return INVALID_CHANNEL_BASE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CDmacman::GetId() const
|
|
|
|
{
|
|
|
|
return "dmacman";
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string CDmacman::GetFunctionName(unsigned int functionId) const
|
|
|
|
{
|
|
|
|
switch(functionId)
|
|
|
|
{
|
2021-05-17 18:05:54 +02:00
|
|
|
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;
|
2020-03-15 14:59:54 -04:00
|
|
|
case FUNCTIONID_DMACREQUEST:
|
|
|
|
return FUNCTION_DMACREQUEST;
|
|
|
|
case FUNCTIONID_DMACTRANSFER:
|
|
|
|
return FUNCTION_DMACTRANSFER;
|
2020-07-13 20:16:53 +02:00
|
|
|
case FUNCTIONID_DMACCHSETDPCR:
|
|
|
|
return FUNCTION_DMACCHSETDPCR;
|
|
|
|
case FUNCTIONID_DMACENABLE:
|
|
|
|
return FUNCTION_DMACENABLE;
|
|
|
|
case FUNCTIONID_DMACDISABLE:
|
|
|
|
return FUNCTION_DMACDISABLE;
|
2020-03-15 14:59:54 -04:00
|
|
|
default:
|
|
|
|
return "unknown";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CDmacman::Invoke(CMIPS& context, unsigned int functionId)
|
|
|
|
{
|
|
|
|
switch(functionId)
|
|
|
|
{
|
2021-05-17 18:05:54 +02:00
|
|
|
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;
|
2020-03-15 14:59:54 -04:00
|
|
|
case FUNCTIONID_DMACREQUEST:
|
|
|
|
context.m_State.nGPR[CMIPS::V0].nV0 = DmacRequest(
|
2020-04-22 16:24:01 -04:00
|
|
|
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));
|
2020-03-15 14:59:54 -04:00
|
|
|
break;
|
|
|
|
case FUNCTIONID_DMACTRANSFER:
|
|
|
|
DmacTransfer(context, context.m_State.nGPR[CMIPS::A0].nV0);
|
|
|
|
break;
|
2020-07-13 20:16:53 +02:00
|
|
|
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;
|
2020-03-15 14:59:54 -04:00
|
|
|
default:
|
|
|
|
CLog::GetInstance().Warn(LOGNAME, "%08X: Unknown function (%d) called.\r\n", context.m_State.nPC, functionId);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-17 18:05:54 +02:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2020-03-15 14:59:54 -04:00
|
|
|
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",
|
2020-04-22 16:24:01 -04:00
|
|
|
channel, addr, size, count, dir);
|
2020-03-15 14:59:54 -04:00
|
|
|
assert(size < 0x10000);
|
|
|
|
assert(count < 0x10000);
|
2020-04-22 16:24:01 -04:00
|
|
|
|
2020-03-15 14:59:54 -04:00
|
|
|
uint32 channelBase = GetChannelBase(channel);
|
2021-05-21 18:14:39 +02:00
|
|
|
if(channelBase == INVALID_CHANNEL_BASE)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOGNAME, "Received " FUNCTION_DMACREQUEST " for invalid channel %d\r\n", channel);
|
|
|
|
return 0;
|
|
|
|
}
|
2020-03-15 14:59:54 -04:00
|
|
|
|
|
|
|
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);
|
2021-05-21 18:14:39 +02:00
|
|
|
if(channelBase == INVALID_CHANNEL_BASE)
|
|
|
|
{
|
|
|
|
CLog::GetInstance().Warn(LOGNAME, "Received " FUNCTION_DMACTRANSFER " for invalid channel %d\r\n", channel);
|
|
|
|
return;
|
|
|
|
}
|
2020-03-15 14:59:54 -04:00
|
|
|
|
|
|
|
context.m_pMemoryMap->SetWord(channelBase + Dmac::CChannel::REG_CHCR, chcr);
|
|
|
|
}
|
2020-07-13 20:16:53 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2021-05-17 18:05:54 +02:00
|
|
|
// 13 - 15 (i.Link)
|
|
|
|
else if(channel < 16)
|
2020-07-13 20:16:53 +02:00
|
|
|
{
|
2021-05-17 18:05:54 +02:00
|
|
|
return CDmac::DPCR3;
|
2020-07-13 20:16:53 +02:00
|
|
|
}
|
2021-02-20 20:15:10 -05:00
|
|
|
return 0;
|
2020-07-13 20:16:53 +02:00
|
|
|
}
|