sh4 dmac: more accurate implementation. Fixes sh4_dmac_demo.elf

This commit is contained in:
Flyinghead 2023-03-07 18:38:41 +01:00
parent abcd9d77d4
commit b8d47fe0a8
1 changed files with 87 additions and 19 deletions

View File

@ -121,26 +121,94 @@ static void WriteCHCR(u32 addr, u32 data)
{ {
if (DMAC_CHCR(ch).RS == 4) if (DMAC_CHCR(ch).RS == 4)
{ {
u32 len = DMAC_DMATCR(ch) * 32;
DEBUG_LOG(SH4, "DMAC: Manual DMA ch:%d TS:%d src: %08X dst: %08X len: %08X SM: %d, DM: %d", ch, DMAC_CHCR(ch).TS, DEBUG_LOG(SH4, "DMAC: Manual DMA ch:%d TS:%d src: %08X dst: %08X len: %08X SM: %d, DM: %d", ch, DMAC_CHCR(ch).TS,
DMAC_SAR(ch), DMAC_DAR(ch), DMAC_DMATCR(ch), DMAC_CHCR(ch).SM, DMAC_CHCR(ch).DM); DMAC_SAR(ch), DMAC_DAR(ch), DMAC_DMATCR(ch), DMAC_CHCR(ch).SM, DMAC_CHCR(ch).DM);
verify(DMAC_CHCR(ch).TS == 4); u32 src = DMAC_SAR(ch);
for (u32 ofs = 0; ofs < len; ofs += 4) u32 len = DMAC_DMATCR(ch);
u32 dst = DMAC_DAR(ch);
int srcIncr, dstIncr;
switch (DMAC_CHCR(ch).SM)
{ {
u32 data = ReadMem32_nommu(DMAC_SAR(ch) + ofs); case 1:
WriteMem32_nommu(DMAC_DAR(ch) + ofs, data); srcIncr = 1;
break;
case 2:
srcIncr = -1;
break;
default:
srcIncr = 0;
break;
}
switch (DMAC_CHCR(ch).DM)
{
case 1:
dstIncr = 1;
break;
case 2:
dstIncr = -1;
break;
default:
dstIncr = 0;
break;
} }
switch (DMAC_CHCR(ch).TS)
{
case 0: // 64 bits
srcIncr *= sizeof(u64);
dstIncr *= sizeof(u64);
for (; len != 0; len--)
{
u64 data = addrspace::read64(src);
addrspace::write64(dst, data);
src += srcIncr;
dst += dstIncr;
}
break;
case 1: // 8 bits
for (; len != 0; len--)
{
u8 data = addrspace::read8(src);
addrspace::write8(dst, data);
src += srcIncr;
dst += dstIncr;
}
break;
case 2: // 16 bits
srcIncr *= sizeof(u16);
dstIncr *= sizeof(u16);
for (; len != 0; len--)
{
u16 data = addrspace::read16(src);
addrspace::write16(dst, data);
src += srcIncr;
dst += dstIncr;
}
break;
case 4: // 32-byte block
len *= 32 / sizeof(u32);
[[fallthrough]];
default: // 32 bits
srcIncr *= sizeof(u32);
dstIncr *= sizeof(u32);
for (; len != 0; len--)
{
u32 data = addrspace::read32(src);
addrspace::write32(dst, data);
src += srcIncr;
dst += dstIncr;
}
break;
}
DMAC_CHCR(ch).TE = 1; DMAC_CHCR(ch).TE = 1;
if (DMAC_CHCR(ch).SM == 1) DMAC_SAR(ch) = src;
DMAC_SAR(ch) += len; DMAC_DAR(ch) = dst;
else if (DMAC_CHCR(ch).SM == 2) DMAC_DMATCR(ch) = len;
DMAC_SAR(ch) -= len;
if (DMAC_CHCR(ch).DM == 1)
DMAC_DAR(ch) += len;
else if (DMAC_CHCR(ch).DM == 2)
DMAC_DAR(ch) -= len;
} }
InterruptPend(dmac_itr[ch], DMAC_CHCR(ch).TE); InterruptPend(dmac_itr[ch], DMAC_CHCR(ch).TE);