mirror of
https://github.com/jpd002/Play-.git
synced 2025-04-28 21:57:57 +03:00

DMAC channel IDs don't necessarily match the interrupt line which is asserted on DMA finish.
115 lines
2.7 KiB
C++
115 lines
2.7 KiB
C++
#include <assert.h>
|
|
#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;
|
|
|
|
#define STATE_REGS_XML_FORMAT ("iop_dmac/channel_%d.xml")
|
|
#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)
|
|
: m_dmac(dmac)
|
|
, m_number(number)
|
|
, m_intrLine(intrLine)
|
|
, m_baseAddress(baseAddress)
|
|
{
|
|
Reset();
|
|
}
|
|
|
|
void CChannel::Reset()
|
|
{
|
|
m_CHCR <<= 0;
|
|
m_BCR <<= 0;
|
|
m_MADR = 0;
|
|
}
|
|
|
|
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);
|
|
m_BCR <<= registerFile.GetRegister32(STATE_REGS_BCR);
|
|
m_MADR = registerFile.GetRegister32(STATE_REGS_MADR);
|
|
}
|
|
|
|
void CChannel::SaveState(Framework::CZipArchiveWriter& archive)
|
|
{
|
|
auto path = string_format(STATE_REGS_XML_FORMAT, m_number);
|
|
auto registerFile = new CRegisterStateFile(path.c_str());
|
|
registerFile->SetRegister32(STATE_REGS_CHCR, m_CHCR);
|
|
registerFile->SetRegister32(STATE_REGS_BCR, m_BCR);
|
|
registerFile->SetRegister32(STATE_REGS_MADR, m_MADR);
|
|
archive.InsertFile(registerFile);
|
|
}
|
|
|
|
void CChannel::SetReceiveFunction(const ReceiveFunctionType& receiveFunction)
|
|
{
|
|
m_receiveFunction = receiveFunction;
|
|
}
|
|
|
|
void CChannel::ResumeDma()
|
|
{
|
|
if(m_CHCR.tr == 0) return;
|
|
assert(m_CHCR.co == 1);
|
|
assert(m_receiveFunction);
|
|
uint32 address = m_MADR & 0x1FFFFFFF;
|
|
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)
|
|
{
|
|
assert(m_CHCR.tr == 0);
|
|
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;
|
|
}
|
|
}
|