Add basic destination chain transfer mode support for DMAch8.

This commit is contained in:
Jean-Philip Desjardins 2018-05-29 13:42:26 -04:00
parent 900893d4a6
commit 7c3460ace5
2 changed files with 57 additions and 1 deletions

View File

@ -130,7 +130,14 @@ void CChannel::Execute()
break;
case 0x01:
case 0x03: //FFXII uses 3 here, assuming source chain mode
ExecuteSourceChain();
if(m_number == CDMAC::CHANNEL_ID_FROM_SPR)
{
ExecuteDestinationChain();
}
else
{
ExecuteSourceChain();
}
break;
default:
assert(0);
@ -469,6 +476,43 @@ void CChannel::ExecuteSourceChain()
}
}
void CChannel::ExecuteDestinationChain()
{
assert(m_number == CDMAC::CHANNEL_ID_FROM_SPR);
while(m_CHCR.nSTR == 1)
{
assert(m_nQWC == 0);
auto tag = make_convertible<DMAtag>(m_dmac.FetchDMATag(m_dmac.m_D8_SADR | 0x80000000));
m_dmac.m_D8_SADR += 0x10;
assert(tag.irq == 0);
switch(tag.id)
{
case DMATAG_DST_CNT:
case DMATAG_DST_END:
m_nMADR = tag.addr;
m_nQWC = tag.qwc;
break;
default:
assert(false);
break;
}
uint32 recv = m_receive(m_nMADR, m_nQWC, m_CHCR.nDIR, false);
assert(recv == m_nQWC);
m_nMADR += recv * 0x10;
m_nQWC -= recv;
if(tag.id == DMATAG_DST_END)
{
ClearSTR();
}
}
}
void CChannel::SetReceiveHandler(const DmaReceiveHandler& handler)
{
m_receive = handler;

View File

@ -34,6 +34,17 @@ namespace Dmac
DMATAG_DST_END = 7,
};
struct DMAtag : public convertible<uint64>
{
unsigned int qwc : 16;
unsigned int reserved : 10;
unsigned int pce : 2;
unsigned int id : 3;
unsigned int irq : 1;
unsigned int addr : 32;
};
static_assert(sizeof(DMAtag) == sizeof(uint64), "Size of DMAtag struct must be 8 bytes.");
enum CHCR_DIR
{
CHCR_DIR_TO = 0,
@ -66,6 +77,7 @@ namespace Dmac
void ExecuteNormal();
void ExecuteInterleave();
void ExecuteSourceChain();
void ExecuteDestinationChain();
void SetReceiveHandler(const DmaReceiveHandler&);
CHCR m_CHCR;