Play-/Source/iop/Iop_DmacChannel.cpp

115 lines
2.7 KiB
C++
Raw Permalink Normal View History

#include <assert.h>
2017-02-11 15:00:24 -05:00
#include "string_format.h"
#include "Iop_DmacChannel.h"
#include "Iop_Dmac.h"
#include "Iop_Intc.h"
#include "../states/RegisterStateFile.h"
using namespace Iop;
using namespace Iop::Dmac;
2017-02-11 15:00:24 -05:00
#define STATE_REGS_XML_FORMAT ("iop_dmac/channel_%d.xml")
2018-04-30 21:01:23 +01:00
#define STATE_REGS_CHCR ("CHCR")
#define STATE_REGS_BCR ("BCR")
#define STATE_REGS_MADR ("MADR")
CChannel::CChannel(uint32 baseAddress, unsigned int number, unsigned int intrLine, CDmac& dmac)
2018-04-30 21:01:23 +01:00
: m_dmac(dmac)
, m_number(number)
, m_intrLine(intrLine)
2018-04-30 21:01:23 +01:00
, m_baseAddress(baseAddress)
{
Reset();
}
void CChannel::Reset()
{
m_CHCR <<= 0;
m_BCR <<= 0;
m_MADR = 0;
}
2017-02-11 15:00:24 -05:00
void CChannel::LoadState(Framework::CZipArchiveReader& archive)
{
auto path = string_format(STATE_REGS_XML_FORMAT, m_number);
auto registerFile = CRegisterStateFile(*archive.BeginReadFile(path.c_str()));
m_CHCR <<= registerFile.GetRegister32(STATE_REGS_CHCR);
2018-04-30 21:01:23 +01:00
m_BCR <<= registerFile.GetRegister32(STATE_REGS_BCR);
m_MADR = registerFile.GetRegister32(STATE_REGS_MADR);
2017-02-11 15:00:24 -05:00
}
void CChannel::SaveState(Framework::CZipArchiveWriter& archive)
{
auto path = string_format(STATE_REGS_XML_FORMAT, m_number);
2023-07-23 17:22:18 -04:00
auto registerFile = std::make_unique<CRegisterStateFile>(path.c_str());
2017-02-11 15:00:24 -05:00
registerFile->SetRegister32(STATE_REGS_CHCR, m_CHCR);
2018-04-30 21:01:23 +01:00
registerFile->SetRegister32(STATE_REGS_BCR, m_BCR);
2017-02-11 15:00:24 -05:00
registerFile->SetRegister32(STATE_REGS_MADR, m_MADR);
2023-07-23 17:22:18 -04:00
archive.InsertFile(std::move(registerFile));
2017-02-11 15:00:24 -05:00
}
void CChannel::SetReceiveFunction(const ReceiveFunctionType& receiveFunction)
{
m_receiveFunction = receiveFunction;
}
void CChannel::ResumeDma()
{
if(m_CHCR.tr == 0) return;
2021-04-01 17:22:33 -04:00
assert(m_CHCR.co == 1);
assert(m_receiveFunction);
uint32 address = m_MADR & 0x1FFFFFFF;
2021-04-01 17:22:33 -04:00
uint32 blocksTransfered = m_receiveFunction(m_dmac.GetRam() + address, m_BCR.bs * 4, m_BCR.ba, m_CHCR.dr);
assert(blocksTransfered <= m_BCR.ba);
m_BCR.ba -= blocksTransfered;
m_MADR += (m_BCR.bs * 4) * blocksTransfered;
if(m_BCR.ba == 0)
{
//Trigger interrupt
m_CHCR.tr = 0;
m_dmac.AssertLine(m_intrLine - CIntc::LINE_DMA_BASE);
}
}
uint32 CChannel::ReadRegister(uint32 address)
{
switch(address - m_baseAddress)
{
case REG_MADR:
return m_MADR;
break;
case REG_BCR:
return m_BCR;
break;
case REG_CHCR:
return m_CHCR;
break;
}
return 0;
}
void CChannel::WriteRegister(uint32 address, uint32 value)
{
switch(address - m_baseAddress)
{
case REG_MADR:
m_MADR = value;
break;
case REG_BCR:
m_BCR <<= value;
break;
case REG_BCR + 2:
//Not really cool...
m_BCR.ba = static_cast<uint16>(value);
break;
case REG_CHCR:
m_CHCR <<= value;
if(m_CHCR.tr)
{
ResumeDma();
}
break;
}
}