Play-/Source/iop/Iop_Dmac.cpp

309 lines
7.4 KiB
C++
Raw Normal View History

#include <assert.h>
2019-08-17 13:51:31 -04:00
#include <cstring>
#include "Iop_Dmac.h"
#include "Iop_Intc.h"
#include "../states/RegisterStateFile.h"
2025-03-11 12:48:26 -04:00
#include "Log.h"
#define LOG_NAME ("iop_dmac")
2018-04-30 21:01:23 +01:00
#define STATE_REGS_XML ("iop_dmac/regs.xml")
#define STATE_REGS_DPCR ("DPCR")
2020-07-13 20:15:31 +02:00
#define STATE_REGS_DPCR2 ("DPCR2")
2021-05-21 16:35:24 +02:00
#define STATE_REGS_DPCR3 ("DPCR3")
2018-04-30 21:01:23 +01:00
#define STATE_REGS_DICR ("DICR")
2017-02-11 15:00:24 -05:00
using namespace Iop;
using namespace Iop::Dmac;
2018-04-30 21:01:23 +01:00
CDmac::CDmac(uint8* ram, CIntc& intc)
: m_ram(ram)
, m_intc(intc)
2021-06-08 21:56:18 +02:00
, m_channelSpu0(CH4_BASE, CHANNEL_SPU0, Iop::CIntc::LINE_DMA_SPU0, *this)
, m_channelSpu1(CH7_BASE, CHANNEL_SPU1, Iop::CIntc::LINE_DMA_SPU1, *this)
, m_channelDev9(CH8_BASE, CHANNEL_DEV9, Iop::CIntc::LINE_DMA_DEV9, *this)
2021-06-08 21:56:18 +02:00
, m_channelSio2In(CH11_BASE, CHANNEL_SIO2in, Iop::CIntc::LINE_DMA_SIO2in, *this)
, m_channelSio2Out(CH12_BASE, CHANNEL_SIO2out, Iop::CIntc::LINE_DMA_SIO2out, *this)
{
memset(m_channel, 0, sizeof(m_channel));
2020-03-15 14:59:54 -04:00
m_channel[CHANNEL_SPU0] = &m_channelSpu0;
m_channel[CHANNEL_SPU1] = &m_channelSpu1;
2021-01-24 19:35:35 -05:00
m_channel[CHANNEL_DEV9] = &m_channelDev9;
//Not enabled, only used for testing purposes
//m_channel[CHANNEL_SIO2in] = &m_channelSio2In;
//m_channel[CHANNEL_SIO2out] = &m_channelSio2Out;
Reset();
}
void CDmac::Reset()
{
m_DPCR = 0;
2020-07-13 20:15:31 +02:00
m_DPCR2 = 0;
2021-05-21 16:35:24 +02:00
m_DPCR3 = 0;
m_DICR = 0;
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
{
CChannel* channel(m_channel[i]);
if(!channel) continue;
channel->Reset();
}
}
void CDmac::SetReceiveFunction(unsigned int channelId, const CChannel::ReceiveFunctionType& handler)
{
assert(channelId < MAX_CHANNEL);
if(channelId >= MAX_CHANNEL) return;
CChannel* channel(m_channel[channelId]);
if(channel)
{
channel->SetReceiveFunction(handler);
}
}
unsigned int CDmac::GetChannelIdFromAddress(uint32 address)
{
unsigned int channelId = -1;
if(address >= DMAC_ZONE2_START)
{
channelId = (address - DMAC_ZONE2_START) / 0x10;
channelId += 7;
}
else if(address >= CH0_BASE && address < DPCR)
{
channelId = (address - DMAC_ZONE1_START) / 0x10;
}
return channelId;
}
CChannel* CDmac::GetChannelFromAddress(uint32 address)
{
unsigned int channelId = GetChannelIdFromAddress(address);
assert(channelId < MAX_CHANNEL);
if(channelId >= MAX_CHANNEL) return NULL;
return m_channel[channelId];
}
void CDmac::ResumeDma(unsigned int channelIdx)
{
auto channel = m_channel[channelIdx];
assert(channel != nullptr);
2021-05-21 18:14:39 +02:00
if(channel == nullptr)
{
CLog::GetInstance().Warn(LOG_NAME, "Trying to resume DMA for channel %d, but the channel is not implemented.\r\n",
channelIdx);
return;
}
channel->ResumeDma();
}
void CDmac::AssertLine(unsigned int line)
{
if(line < 7)
{
m_DICR |= 1 << (line + 24);
}
m_intc.AssertLine(CIntc::LINE_DMAC);
m_intc.AssertLine(CIntc::LINE_DMA_BASE + line);
}
uint8* CDmac::GetRam()
{
return m_ram;
}
uint32 CDmac::ReadRegister(uint32 address)
{
#ifdef _DEBUG
LogRead(address);
#endif
switch(address)
{
case DPCR:
return m_DPCR;
break;
2020-07-13 20:15:31 +02:00
case DPCR2:
return m_DPCR2;
break;
2021-05-21 16:35:24 +02:00
case DPCR3:
return m_DPCR3;
break;
case DICR:
return m_DICR;
break;
default:
2018-04-30 21:01:23 +01:00
{
CChannel* channel(GetChannelFromAddress(address));
if(channel)
{
2018-04-30 21:01:23 +01:00
return channel->ReadRegister(address);
}
2021-05-21 18:14:39 +02:00
else
{
CLog::GetInstance().Warn(LOG_NAME, "Unknown DMA channel register read at 0x%08X.\r\n",
address);
}
2018-04-30 21:01:23 +01:00
}
break;
}
return 0;
}
uint32 CDmac::WriteRegister(uint32 address, uint32 value)
{
#ifdef _DEBUG
LogWrite(address, value);
#endif
switch(address)
{
case DPCR:
m_DPCR = value;
break;
2020-07-13 20:15:31 +02:00
case DPCR2:
m_DPCR2 = value;
break;
2021-05-21 16:35:24 +02:00
case DPCR3:
m_DPCR3 = value;
break;
case DICR:
m_DICR &= 0xFF000000;
m_DICR |= value;
m_DICR &= ~(value & 0xFF000000);
break;
default:
2018-04-30 21:01:23 +01:00
{
CChannel* channel(GetChannelFromAddress(address));
if(channel)
{
2018-04-30 21:01:23 +01:00
channel->WriteRegister(address, value);
}
2021-05-21 18:14:39 +02:00
else
{
CLog::GetInstance().Warn(LOG_NAME, "Unknown DMA channel register write at 0x%08X.\r\n",
address);
}
2018-04-30 21:01:23 +01:00
}
break;
}
return 0;
}
2017-02-11 15:00:24 -05:00
void CDmac::LoadState(Framework::CZipArchiveReader& archive)
{
{
auto registerFile = CRegisterStateFile(*archive.BeginReadFile(STATE_REGS_XML));
m_DPCR = registerFile.GetRegister32(STATE_REGS_DPCR);
2020-07-13 20:15:31 +02:00
m_DPCR2 = registerFile.GetRegister32(STATE_REGS_DPCR2);
2021-05-21 16:35:24 +02:00
m_DPCR3 = registerFile.GetRegister32(STATE_REGS_DPCR3);
2017-02-11 15:00:24 -05:00
m_DICR = registerFile.GetRegister32(STATE_REGS_DICR);
}
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
{
auto channel = m_channel[i];
if(!channel) continue;
channel->LoadState(archive);
}
}
void CDmac::SaveState(Framework::CZipArchiveWriter& archive)
{
{
2023-07-23 17:22:18 -04:00
auto registerFile = std::make_unique<CRegisterStateFile>(STATE_REGS_XML);
2017-02-11 15:00:24 -05:00
registerFile->SetRegister32(STATE_REGS_DPCR, m_DPCR);
2020-07-13 20:15:31 +02:00
registerFile->SetRegister32(STATE_REGS_DPCR2, m_DPCR2);
2021-05-21 16:35:24 +02:00
registerFile->SetRegister32(STATE_REGS_DPCR3, m_DPCR3);
2017-02-11 15:00:24 -05:00
registerFile->SetRegister32(STATE_REGS_DICR, m_DICR);
2023-07-23 17:22:18 -04:00
archive.InsertFile(std::move(registerFile));
2017-02-11 15:00:24 -05:00
}
for(unsigned int i = 0; i < MAX_CHANNEL; i++)
{
auto channel = m_channel[i];
if(!channel) continue;
channel->SaveState(archive);
}
}
void CDmac::LogRead(uint32 address)
{
switch(address)
{
case DPCR:
CLog::GetInstance().Print(LOG_NAME, "= DPCR.\r\n");
break;
2021-05-21 16:35:24 +02:00
case DPCR2:
CLog::GetInstance().Print(LOG_NAME, "= DPCR2.\r\n");
break;
case DPCR3:
CLog::GetInstance().Print(LOG_NAME, "= DPCR3.\r\n");
break;
case DICR:
CLog::GetInstance().Print(LOG_NAME, "= DICR.\r\n");
break;
default:
2018-04-30 21:01:23 +01:00
{
unsigned int channelId = GetChannelIdFromAddress(address);
unsigned int registerId = address & 0xF;
switch(registerId)
{
2018-04-30 21:01:23 +01:00
case CChannel::REG_MADR:
CLog::GetInstance().Print(LOG_NAME, "ch%02d: = MADR.\r\n", channelId);
break;
case CChannel::REG_CHCR:
CLog::GetInstance().Print(LOG_NAME, "ch%02d: = CHCR.\r\n", channelId);
break;
default:
2018-05-24 12:59:15 -04:00
CLog::GetInstance().Warn(LOG_NAME, "Read an unknown register 0x%08X.\r\n",
2018-05-25 12:26:07 -04:00
address);
2018-04-30 21:01:23 +01:00
break;
}
2018-04-30 21:01:23 +01:00
}
break;
}
}
void CDmac::LogWrite(uint32 address, uint32 value)
{
switch(address)
{
case DPCR:
CLog::GetInstance().Print(LOG_NAME, "DPCR = 0x%08X.\r\n", value);
break;
2021-05-21 16:35:24 +02:00
case DPCR2:
CLog::GetInstance().Print(LOG_NAME, "DPCR2 = 0x%08X.\r\n", value);
break;
case DPCR3:
CLog::GetInstance().Print(LOG_NAME, "DPCR3 = 0x%08X.\r\n", value);
break;
case DICR:
CLog::GetInstance().Print(LOG_NAME, "DICR = 0x%08X.\r\n", value);
break;
default:
2018-04-30 21:01:23 +01:00
{
unsigned int channelId = GetChannelIdFromAddress(address);
unsigned int registerId = address & 0xF;
switch(registerId)
{
2018-04-30 21:01:23 +01:00
case CChannel::REG_MADR:
CLog::GetInstance().Print(LOG_NAME, "ch%02d: MADR = 0x%08X.\r\n", channelId, value);
break;
case CChannel::REG_BCR:
CLog::GetInstance().Print(LOG_NAME, "ch%02d: BCR = 0x%08X.\r\n", channelId, value);
break;
case CChannel::REG_BCR + 2:
CLog::GetInstance().Print(LOG_NAME, "ch%02d: BCR.ba = 0x%08X.\r\n", channelId, value);
break;
case CChannel::REG_CHCR:
CLog::GetInstance().Print(LOG_NAME, "ch%02d: CHCR = 0x%08X.\r\n", channelId, value);
break;
default:
2018-05-24 12:59:15 -04:00
CLog::GetInstance().Warn(LOG_NAME, "Wrote 0x%08X to unknown register 0x%08X.\r\n",
2018-05-25 12:26:07 -04:00
value, address);
2018-04-30 21:01:23 +01:00
break;
}
2018-04-30 21:01:23 +01:00
}
break;
}
}