From d2bff7c1870c031a4d21ccacb05be4fe0080e76e Mon Sep 17 00:00:00 2001 From: Arisotura Date: Tue, 29 Jun 2021 20:49:43 +0200 Subject: [PATCH] make some progress --- src/DMA.cpp | 352 +++++++++++++++++++++++++++++++++++++++++++++- src/DMA.h | 12 +- src/DMA_Timings.h | 12 +- 3 files changed, 365 insertions(+), 11 deletions(-) diff --git a/src/DMA.cpp b/src/DMA.cpp index c471d5a7..8f1eaf40 100644 --- a/src/DMA.cpp +++ b/src/DMA.cpp @@ -21,6 +21,7 @@ #include "DSi.h" #include "DMA.h" #include "GPU.h" +#include "DMA_Timings.h" @@ -94,8 +95,8 @@ void DMA::DoSavestate(Savestate* file) file->Var32(&CurDstAddr); file->Var32(&RemCount); file->Var32(&IterCount); - file->Var32(&SrcAddrInc); - file->Var32(&DstAddrInc); + file->Var32((u32*)&SrcAddrInc); + file->Var32((u32*)&DstAddrInc); file->Var32(&Running); file->Bool32(&InProgress); @@ -182,10 +183,349 @@ void DMA::Start() else*/ Running = 2; + // safety measure + MRAMBurstTable = DMATiming::MRAMDummy; + InProgress = true; NDS::StopCPU(CPU, 1<> 14; + u32 dst_id = CurDstAddr >> 14; + + if (Cnt & (1<<26)) // 32-bit + { + src_n = NDS::ARM9MemTimings[src_id][6]; + src_s = NDS::ARM9MemTimings[src_id][7]; + dst_n = NDS::ARM9MemTimings[dst_id][6]; + dst_s = NDS::ARM9MemTimings[dst_id][7]; + } + else // 16-bit + { + src_n = NDS::ARM9MemTimings[src_id][4]; + src_s = NDS::ARM9MemTimings[src_id][5]; + dst_n = NDS::ARM9MemTimings[dst_id][4]; + dst_s = NDS::ARM9MemTimings[dst_id][5]; + } + + u32 src_rgn = NDS::ARM9Regions[src_id]; + u32 dst_rgn = NDS::ARM9Regions[dst_id]; + + src_mainram = (src_rgn == NDS::Mem9_MainRAM); + sameregion = ((src_rgn & dst_rgn) != 0); + } + else + { + u32 src_id = CurSrcAddr >> 15; + u32 dst_id = CurDstAddr >> 15; + + if (Cnt & (1<<26)) // 32-bit + { + src_n = NDS::ARM7MemTimings[src_id][2]; + src_s = NDS::ARM7MemTimings[src_id][3]; + dst_n = NDS::ARM7MemTimings[dst_id][2]; + dst_s = NDS::ARM7MemTimings[dst_id][3]; + } + else // 16-bit + { + src_n = NDS::ARM7MemTimings[src_id][0]; + src_s = NDS::ARM7MemTimings[src_id][1]; + dst_n = NDS::ARM7MemTimings[dst_id][0]; + dst_s = NDS::ARM7MemTimings[dst_id][1]; + } + + u32 src_rgn = NDS::ARM7Regions[src_id]; + u32 dst_rgn = NDS::ARM7Regions[dst_id]; + + src_mainram = (src_rgn == NDS::Mem7_MainRAM); + sameregion = ((src_rgn & dst_rgn) != 0); + } + + // +} + +u32 DMA::UnitTimings9_16(bool burststart) +{ + u32 src_id = CurSrcAddr >> 14; + u32 dst_id = CurDstAddr >> 14; + + u32 src_rgn = NDS::ARM9Regions[src_id]; + u32 dst_rgn = NDS::ARM9Regions[dst_id]; + + u32 src_n, src_s, dst_n, dst_s; + src_n = NDS::ARM9MemTimings[src_id][4]; + src_s = NDS::ARM9MemTimings[src_id][5]; + dst_n = NDS::ARM9MemTimings[dst_id][4]; + dst_s = NDS::ARM9MemTimings[dst_id][5]; + + u32 ret = 0; + + if (src_rgn == NDS::Mem9_MainRAM) + { + if (dst_rgn == NDS::Mem9_MainRAM) + return 16; + + if (SrcAddrInc > 0) + { + if (burststart || MRAMBurstTable[MRAMBurstCount] == 0) + { + MRAMBurstCount = 0; + + if (dst_rgn == NDS::Mem9_GBAROM) + { + if (dst_s == 4) + MRAMBurstTable = DMATiming::MRAMRead16Bursts[1]; + else + MRAMBurstTable = DMATiming::MRAMRead16Bursts[2]; + } + else + MRAMBurstTable = DMATiming::MRAMRead16Bursts[0]; + } + + ret = MRAMBurstTable[MRAMBurstCount++]; + return ret; + } + else + { + ret += ((CurSrcAddr & 0x1F) == 0x1E) ? 7 : 8; + ret += burststart ? dst_n : dst_s; + return ret; + } + } + else if (dst_rgn == NDS::Mem9_MainRAM) + { + if (DstAddrInc > 0) + { + if (burststart || MRAMBurstTable[MRAMBurstCount] == 0) + { + MRAMBurstCount = 0; + + if (src_rgn == NDS::Mem9_GBAROM) + { + if (src_s == 4) + MRAMBurstTable = DMATiming::MRAMWrite16Bursts[1]; + else + MRAMBurstTable = DMATiming::MRAMWrite16Bursts[2]; + } + else + MRAMBurstTable = DMATiming::MRAMWrite16Bursts[0]; + } + + ret = MRAMBurstTable[MRAMBurstCount++]; + return ret; + } + else + { + ret += burststart ? src_n : src_s; + ret += 7; + return ret; + } + } + else if (src_rgn & dst_rgn) + { + return src_n + dst_n + 1; + } + else + { + if (burststart) + return src_n + dst_n; + else + return src_s + dst_s; + } + + + +#if 0 + if (src_rgn == NDS::Mem9_MainRAM) + { + // for main RAM: sequential timings only work with incrementing addresses + // read bursts have a maximum length of 119 halfwords, then 119 halfwords, then 2 halfwords, and so on + // (this is probably a hardware glitch) + + if (SrcAddrInc > 0) + { + if (burststart || BurstCount >= 240) + BurstCount = 0; + + // note: one of the cycles of the first unit seems to transfer over to the next unit + // we approximate this by attributing all the cycles to the first unit + + if (BurstCount == 0 || BurstCount == 119 || BurstCount == 238) + ret += src_n-1; + //else if (BurstCount == 1 || BurstCount == 120 || BurstCount == 239) + // ret += src_s + 1; + else + ret += src_s; + + BurstCount++; + } + else + { + ret += src_n; + if ((CurSrcAddr & 0x1F) == 0x1E) ret--; + } + + // main RAM reads can parallelize with writes to another region + //ret--; + } + else if (src_rgn == NDS::Mem9_GBAROM) + { + // for GBA ROM: sequential timings always work, except for the last halfword + // of every 0x20000 byte block + + ret += (burststart || ((CurSrcAddr & 0x1FFFF) == 0x1FFFE)) ? src_n : src_s; + } + else + { + // for other regions: nonseq/sequential timings are the same + + ret += src_s; + } + + if (dst_rgn == NDS::Mem9_MainRAM) + { + // for main RAM: sequential timings only work with incrementing addresses + // write bursts have a maximum length of 120 halfwords + + if (DstAddrInc > 0) + { + if (burststart || BurstCount >= 120) + BurstCount = 0; + + ret += (BurstCount == 0) ? dst_n-1 : dst_s; + + BurstCount++; + } + else + { + ret += dst_n-1; + } + } + else if (dst_rgn == NDS::Mem9_GBAROM) + { + // for GBA ROM: sequential timings always work, except for the last halfword + // of every 0x20000 byte block + + ret += (burststart || ((CurDstAddr & 0x1FFFF) == 0x1FFFE)) ? dst_n : dst_s; + } + else + { + // for other regions: nonseq/sequential timings are the same + + ret += dst_s; + } +#endif + + return ret; +} + +u32 DMA::UnitTimings9_32(bool burststart) +{ + u32 src_id = CurSrcAddr >> 14; + u32 dst_id = CurDstAddr >> 14; + + u32 src_rgn = NDS::ARM9Regions[src_id]; + u32 dst_rgn = NDS::ARM9Regions[dst_id]; + + u32 src_n, src_s, dst_n, dst_s; + src_n = NDS::ARM9MemTimings[src_id][6]; + src_s = NDS::ARM9MemTimings[src_id][7]; + dst_n = NDS::ARM9MemTimings[dst_id][6]; + dst_s = NDS::ARM9MemTimings[dst_id][7]; + + if (src_rgn & dst_rgn) + { + return src_n + dst_n; + } + + u32 ret = 0; + ret=1; +#if 0 + if (src_rgn == NDS::Mem9_MainRAM) + { + // for main RAM: sequential timings only work with incrementing addresses + // read bursts have a maximum length of 118 words + + if (SrcAddrInc > 0) + { + if (burststart || BurstCount >= 118) + BurstCount = 0; + + ret += (BurstCount == 0) ? src_n : src_s; + + BurstCount++; + } + else + { + ret += src_n; + if ((CurSrcAddr & 0x1F) == 0x1C) ret--; + } + + // main RAM reads can parallelize with writes to another region + ret--; + } + else if (src_rgn == NDS::Mem9_GBAROM) + { + // for GBA ROM: sequential timings always work, except for the last halfword + // of every 0x20000 byte block + + ret += (burststart || ((CurSrcAddr & 0x1FFFF) == 0x1FFFC)) ? src_n : src_s; + } + else + { + // for other regions: nonseq/sequential timings are the same + + ret += src_s; + } + + if (dst_rgn == NDS::Mem9_MainRAM) + { + // for main RAM: sequential timings only work with incrementing addresses + // write bursts have a maximum length of 80 words + + if (DstAddrInc > 0) + { + if (burststart || BurstCount >= 80) + BurstCount = 0; + + ret += (BurstCount == 0) ? dst_n : dst_s; + + BurstCount++; + } + else + { + ret += dst_n; + } + } + else if (dst_rgn == NDS::Mem9_GBAROM) + { + // for GBA ROM: sequential timings always work, except for the last halfword + // of every 0x20000 byte block + + ret += (burststart || ((CurDstAddr & 0x1FFFF) == 0x1FFFC)) ? dst_n : dst_s; + } + else + { + // for other regions: nonseq/sequential timings are the same + + ret += dst_s; + } +#endif + return ret; +} + template void DMA::Run9() { @@ -224,7 +564,9 @@ void DMA::Run9() while (IterCount > 0 && !Stall) { - NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift); + //NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift); + NDS::ARM9Timestamp += (UnitTimings9_16(burststart) << NDS::ARM9ClockShift); + burststart = false; if (ConsoleType == 1) DSi::ARM9Write16(CurDstAddr, DSi::ARM9Read16(CurSrcAddr)); @@ -284,7 +626,9 @@ void DMA::Run9() while (IterCount > 0 && !Stall) { - NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift); + //NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift); + NDS::ARM9Timestamp += (UnitTimings9_32(burststart) << NDS::ARM9ClockShift); + burststart = false; if (ConsoleType == 1) DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr)); diff --git a/src/DMA.h b/src/DMA.h index b86796d3..2853d122 100644 --- a/src/DMA.h +++ b/src/DMA.h @@ -34,6 +34,11 @@ public: void WriteCnt(u32 val); void Start(); + void CalculateTimings(u32& burststart, u32& unit); + + u32 UnitTimings9_16(bool burststart); + u32 UnitTimings9_32(bool burststart); + template void Run(); @@ -78,8 +83,8 @@ private: u32 CurDstAddr; u32 RemCount; u32 IterCount; - u32 SrcAddrInc; - u32 DstAddrInc; + s32 SrcAddrInc; + s32 DstAddrInc; u32 CountMask; u32 Running; @@ -89,6 +94,9 @@ private: bool Stall; bool IsGXFIFODMA; + + u32 MRAMBurstCount; + u8* MRAMBurstTable; }; #endif diff --git a/src/DMA_Timings.h b/src/DMA_Timings.h index a09ef77a..1d86750a 100644 --- a/src/DMA_Timings.h +++ b/src/DMA_Timings.h @@ -43,7 +43,9 @@ namespace DMATiming // setting. Timings are such that the nonseq setting only matters for the first // access, and minor edge cases (like the last of a 0x20000-byte block). -u8 MRAMRead16Bursts[][] = +u8 MRAMDummy[1] = {0}; + +u8 MRAMRead16Bursts[][256] = { // main RAM to regular 16bit or 32bit bus (similar) {7, 3, 2, 2, 2, 2, 2, 2, 2, 2, @@ -117,7 +119,7 @@ u8 MRAMRead16Bursts[][] = 0}, }; -u8 MRAMRead32Bursts[][] = +u8 MRAMRead32Bursts[][256] = { // main RAM to regular 16bit bus {9, 4, 3, 3, 3, 3, 3, 3, 3, 3, @@ -176,7 +178,7 @@ u8 MRAMRead32Bursts[][] = 0}, }; -u8 MRAMWrite16Bursts[][] = +u8 MRAMWrite16Bursts[][256] = { // regular 16bit or 32bit bus to main RAM (similar) {8, 2, 2, 2, 2, 2, 2, 2, 2, 2, @@ -207,7 +209,7 @@ u8 MRAMWrite16Bursts[][] = 0}, }; -u8 MRAMWrite32Bursts[][] = +u8 MRAMWrite32Bursts[][256] = { // regular 16bit bus to main RAM {9, 4, 4, 4, 4, 4, 4, 4, 4, 4, @@ -236,7 +238,7 @@ u8 MRAMWrite32Bursts[][] = {16, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0}, -} +}; }