aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt1
-rw-r--r--src/CP15.cpp30
-rw-r--r--src/DMA.cpp466
-rw-r--r--src/DMA.h12
-rw-r--r--src/DMA_Timings.h245
-rw-r--r--src/DSi.cpp2
-rw-r--r--src/NDS.cpp210
-rw-r--r--src/NDS.h35
8 files changed, 785 insertions, 216 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 54d0899..1f5d00b 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -15,6 +15,7 @@ add_library(core STATIC
CP15.cpp
CRC32.cpp
DMA.cpp
+ DMA_Timings.h
DSi.cpp
DSi_AES.cpp
DSi_Camera.cpp
diff --git a/src/CP15.cpp b/src/CP15.cpp
index 56c9830..f30ed9e 100644
--- a/src/CP15.cpp
+++ b/src/CP15.cpp
@@ -225,7 +225,8 @@ void ARMv5::UpdatePURegion(u32 n)
usermask |= 0x40;
}
- //printf("PU region %d: %08X-%08X, user=%02X priv=%02X\n", n, start<<12, end<<12, usermask, privmask);
+ printf("PU region %d: %08X-%08X, user=%02X priv=%02X\n", n, start<<12, end<<12, usermask, privmask);
+ printf("%08X/%08X\n", PU_DataRW, PU_CodeRW);
for (u32 i = start; i < end; i++)
{
@@ -233,7 +234,7 @@ void ARMv5::UpdatePURegion(u32 n)
PU_PrivMap[i] = privmask;
}
- UpdateRegionTimings(start<<12, end<<12);
+ UpdateRegionTimings(start, end);
}
void ARMv5::UpdatePURegions(bool update_all)
@@ -249,7 +250,7 @@ void ARMv5::UpdatePURegions(bool update_all)
memset(PU_UserMap, mask, 0x100000);
memset(PU_PrivMap, mask, 0x100000);
- UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
+ UpdateRegionTimings(0x00000, 0x100000);
return;
}
@@ -266,16 +267,11 @@ void ARMv5::UpdatePURegions(bool update_all)
// TODO: this is way unoptimized
// should be okay unless the game keeps changing shit, tho
- if (update_all) UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
+ if (update_all) UpdateRegionTimings(0x00000, 0x100000);
}
void ARMv5::UpdateRegionTimings(u32 addrstart, u32 addrend)
{
- addrstart >>= 12;
- addrend >>= 12;
-
- if (addrend == 0xFFFFF) addrend++;
-
for (u32 i = addrstart; i < addrend; i++)
{
u8 pu = PU_Map[i];
@@ -420,7 +416,7 @@ void ARMv5::ICacheInvalidateAll()
void ARMv5::CP15Write(u32 id, u32 val)
{
- //printf("CP15 write op %03X %08X %08X\n", id, val, R[15]);
+ //if(id!=0x704)printf("CP15 write op %03X %08X %08X\n", id, val, R[15]);
switch (id)
{
@@ -520,7 +516,7 @@ void ARMv5::CP15Write(u32 id, u32 val)
return;
case 0x502: // data permissions
- {
+ {printf("SET DATAPERM %08X (%08X %08X)\n", val,PU_DataRW,PU_DataRW ^ val);
u32 diff = PU_DataRW ^ val;
PU_DataRW = val;
for (u32 i = 0; i < 8; i++)
@@ -814,6 +810,12 @@ void ARMv5::DataRead16(u32 addr, u32* val)
void ARMv5::DataRead32(u32 addr, u32* val)
{
+ /*if (!(PU_Map[addr>>12] & 0x01))
+ {printf("addr %08X very bad\n", addr);
+ DataAbort();
+ return;
+ }*/
+
DataRegion = addr;
addr &= ~3;
@@ -908,6 +910,12 @@ void ARMv5::DataWrite16(u32 addr, u16 val)
void ARMv5::DataWrite32(u32 addr, u32 val)
{
+ /*if (!(PU_Map[addr>>12] & 0x02))
+ {printf("addr %08X wr very bad\n", addr);
+ DataAbort();
+ return;
+ }*/
+
DataRegion = addr;
addr &= ~3;
diff --git a/src/DMA.cpp b/src/DMA.cpp
index e7473fb..e601871 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"
@@ -77,6 +78,7 @@ void DMA::Reset()
Running = false;
InProgress = false;
+ MRAMBurstCount = 0;
}
void DMA::DoSavestate(Savestate* file)
@@ -94,12 +96,13 @@ 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);
file->Bool32(&IsGXFIFODMA);
+ file->Var32(&MRAMBurstCount);
}
void DMA::WriteCnt(u32 val)
@@ -125,7 +128,7 @@ void DMA::WriteCnt(u32 val)
case 0x00000000: SrcAddrInc = 1; break;
case 0x00800000: SrcAddrInc = -1; break;
case 0x01000000: SrcAddrInc = 0; break;
- case 0x01800000: SrcAddrInc = 1; printf("BAD DMA SRC INC MODE 3\n"); break;
+ case 0x01800000: SrcAddrInc = 1; break;
}
if (CPU == 0)
@@ -165,6 +168,9 @@ void DMA::Start()
else
IterCount = RemCount;
+ if ((Cnt & 0x01800000) == 0x01800000)
+ CurSrcAddr = SrcAddr;
+
if ((Cnt & 0x00600000) == 0x00600000)
CurDstAddr = DstAddr;
@@ -174,52 +180,386 @@ void DMA::Start()
// TODO eventually: not stop if we're running code in ITCM
- if (NDS::DMAsRunning(CPU))
- Running = 1;
- else
- Running = 2;
+ Running = 2;
+
+ // safety measure
+ MRAMBurstTable = DMATiming::MRAMDummy;
InProgress = true;
NDS::StopCPU(CPU, 1<<Num);
}
-template <int ConsoleType>
-void DMA::Run9()
+u32 DMA::UnitTimings9_16(bool burststart)
{
- if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+ u32 src_id = CurSrcAddr >> 14;
+ u32 dst_id = CurDstAddr >> 14;
- Executing = true;
+ u32 src_rgn = NDS::ARM9Regions[src_id];
+ u32 dst_rgn = NDS::ARM9Regions[dst_id];
- // add NS penalty for first accesses in burst
- bool burststart = (Running == 2);
- Running = 1;
+ 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];
- s32 unitcycles;
- //s32 lastcycles = cycles;
+ if (src_rgn == NDS::Mem9_MainRAM)
+ {
+ if (dst_rgn == NDS::Mem9_MainRAM)
+ return 16;
- if (!(Cnt & (1<<26)))
+ 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];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
+ }
+ else
+ {
+ // TODO: not quite right for GBA slot
+ return (((CurSrcAddr & 0x1F) == 0x1E) ? 7 : 8) +
+ (burststart ? dst_n : dst_s);
+ }
+ }
+ else if (dst_rgn == NDS::Mem9_MainRAM)
{
- if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
+ if (DstAddrInc > 0)
{
- unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][0] + NDS::ARM9MemTimings[CurDstAddr >> 14][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];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
}
else
{
- unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][1] + NDS::ARM9MemTimings[CurDstAddr >> 14][1];
- if ((CurSrcAddr >> 24) == (CurDstAddr >> 24))
- unitcycles++;
+ return (burststart ? src_n : src_s) + 7;
+ }
+ }
+ 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 (burststart)
+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 == NDS::Mem9_MainRAM)
+ {
+ if (dst_rgn == NDS::Mem9_MainRAM)
+ return 18;
+
+ if (SrcAddrInc > 0)
+ {
+ if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
{
- cycles -= 2;
- cycles -= (NDS::ARM9MemTimings[CurSrcAddr >> 14][0] + NDS::ARM9MemTimings[CurDstAddr >> 14][0]);
- cycles += unitcycles;
- }*/
+ MRAMBurstCount = 0;
+
+ if (dst_rgn == NDS::Mem9_GBAROM)
+ {
+ if (dst_s == 8)
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[2];
+ else
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[3];
+ }
+ else if (dst_n == 2)
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[0];
+ else
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[1];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
}
+ else
+ {
+ // TODO: not quite right for GBA slot
+ return (((CurSrcAddr & 0x1F) == 0x1C) ? (dst_n==2 ? 7:8) : 9) +
+ (burststart ? dst_n : dst_s);
+ }
+ }
+ 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 == 8)
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[2];
+ else
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[3];
+ }
+ else if (src_n == 2)
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[0];
+ else
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[1];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
+ }
+ else
+ {
+ return (burststart ? src_n : src_s) + 8;
+ }
+ }
+ 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;
+ }
+}
+
+// TODO: the ARM7 ones don't take into account that the two wifi regions have different timings
+
+u32 DMA::UnitTimings7_16(bool burststart)
+{
+ u32 src_id = CurSrcAddr >> 15;
+ u32 dst_id = CurDstAddr >> 15;
+
+ u32 src_rgn = NDS::ARM7Regions[src_id];
+ u32 dst_rgn = NDS::ARM7Regions[dst_id];
+
+ u32 src_n, src_s, dst_n, dst_s;
+ 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];
+
+ if (src_rgn == NDS::Mem7_MainRAM)
+ {
+ if (dst_rgn == NDS::Mem7_MainRAM)
+ return 16;
+ if (SrcAddrInc > 0)
+ {
+ if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
+ {
+ MRAMBurstCount = 0;
+
+ if (dst_rgn == NDS::Mem7_GBAROM || dst_rgn == NDS::Mem7_Wifi0 || dst_rgn == NDS::Mem7_Wifi1)
+ {
+ if (dst_s == 4)
+ MRAMBurstTable = DMATiming::MRAMRead16Bursts[1];
+ else
+ MRAMBurstTable = DMATiming::MRAMRead16Bursts[2];
+ }
+ else
+ MRAMBurstTable = DMATiming::MRAMRead16Bursts[0];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
+ }
+ else
+ {
+ // TODO: not quite right for GBA slot
+ return (((CurSrcAddr & 0x1F) == 0x1E) ? 7 : 8) +
+ (burststart ? dst_n : dst_s);
+ }
+ }
+ else if (dst_rgn == NDS::Mem7_MainRAM)
+ {
+ if (DstAddrInc > 0)
+ {
+ if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
+ {
+ MRAMBurstCount = 0;
+
+ if (src_rgn == NDS::Mem7_GBAROM || src_rgn == NDS::Mem7_Wifi0 || src_rgn == NDS::Mem7_Wifi1)
+ {
+ if (src_s == 4)
+ MRAMBurstTable = DMATiming::MRAMWrite16Bursts[1];
+ else
+ MRAMBurstTable = DMATiming::MRAMWrite16Bursts[2];
+ }
+ else
+ MRAMBurstTable = DMATiming::MRAMWrite16Bursts[0];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
+ }
+ else
+ {
+ return (burststart ? src_n : src_s) + 7;
+ }
+ }
+ 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;
+ }
+}
+
+u32 DMA::UnitTimings7_32(bool burststart)
+{
+ u32 src_id = CurSrcAddr >> 15;
+ u32 dst_id = CurDstAddr >> 15;
+
+ u32 src_rgn = NDS::ARM7Regions[src_id];
+ u32 dst_rgn = NDS::ARM7Regions[dst_id];
+
+ u32 src_n, src_s, dst_n, dst_s;
+ 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];
+
+ if (src_rgn == NDS::Mem7_MainRAM)
+ {
+ if (dst_rgn == NDS::Mem7_MainRAM)
+ return 18;
+
+ if (SrcAddrInc > 0)
+ {
+ if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
+ {
+ MRAMBurstCount = 0;
+
+ if (dst_rgn == NDS::Mem7_GBAROM || dst_rgn == NDS::Mem7_Wifi0 || dst_rgn == NDS::Mem7_Wifi1)
+ {
+ if (dst_s == 8)
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[2];
+ else
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[3];
+ }
+ else if (dst_n == 2)
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[0];
+ else
+ MRAMBurstTable = DMATiming::MRAMRead32Bursts[1];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
+ }
+ else
+ {
+ // TODO: not quite right for GBA slot
+ return (((CurSrcAddr & 0x1F) == 0x1C) ? (dst_n==2 ? 7:8) : 9) +
+ (burststart ? dst_n : dst_s);
+ }
+ }
+ else if (dst_rgn == NDS::Mem7_MainRAM)
+ {
+ if (DstAddrInc > 0)
+ {
+ if (burststart || MRAMBurstTable[MRAMBurstCount] == 0)
+ {
+ MRAMBurstCount = 0;
+
+ if (src_rgn == NDS::Mem7_GBAROM || src_rgn == NDS::Mem7_Wifi0 || src_rgn == NDS::Mem7_Wifi1)
+ {
+ if (src_s == 8)
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[2];
+ else
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[3];
+ }
+ else if (src_n == 2)
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[0];
+ else
+ MRAMBurstTable = DMATiming::MRAMWrite32Bursts[1];
+ }
+
+ u32 ret = MRAMBurstTable[MRAMBurstCount++];
+ return ret;
+ }
+ else
+ {
+ return (burststart ? src_n : src_s) + 8;
+ }
+ }
+ 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;
+ }
+}
+
+template <int ConsoleType>
+void DMA::Run9()
+{
+ if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+
+ Executing = true;
+
+ // add NS penalty for first accesses in burst
+ bool burststart = (Running == 2);
+ Running = 1;
+
+ if (!(Cnt & (1<<26)))
+ {
while (IterCount > 0 && !Stall)
{
- NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
+ NDS::ARM9Timestamp += (UnitTimings9_16(burststart) << NDS::ARM9ClockShift);
+ burststart = false;
if (ConsoleType == 1)
DSi::ARM9Write16(CurDstAddr, DSi::ARM9Read16(CurSrcAddr));
@@ -236,29 +576,10 @@ void DMA::Run9()
}
else
{
- if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
- {
- unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2];
- }
- else
- {
- unitcycles = NDS::ARM9MemTimings[CurSrcAddr >> 14][3] + NDS::ARM9MemTimings[CurDstAddr >> 14][3];
- if ((CurSrcAddr >> 24) == (CurDstAddr >> 24))
- unitcycles++;
- else if ((CurSrcAddr >> 24) == 0x02)
- unitcycles--;
-
- /*if (burststart)
- {
- cycles -= 2;
- cycles -= (NDS::ARM9MemTimings[CurSrcAddr >> 14][2] + NDS::ARM9MemTimings[CurDstAddr >> 14][2]);
- cycles += unitcycles;
- }*/
- }
-
while (IterCount > 0 && !Stall)
{
- NDS::ARM9Timestamp += (unitcycles << NDS::ARM9ClockShift);
+ NDS::ARM9Timestamp += (UnitTimings9_32(burststart) << NDS::ARM9ClockShift);
+ burststart = false;
if (ConsoleType == 1)
DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr));
@@ -313,32 +634,12 @@ void DMA::Run7()
bool burststart = (Running == 2);
Running = 1;
- s32 unitcycles;
- //s32 lastcycles = cycles;
-
if (!(Cnt & (1<<26)))
{
- if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
- {
- unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][0] + NDS::ARM7MemTimings[CurDstAddr >> 15][0];
- }
- else
- {
- unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][1] + NDS::ARM7MemTimings[CurDstAddr >> 15][1];
- if ((CurSrcAddr >> 23) == (CurDstAddr >> 23))
- unitcycles++;
-
- /*if (burststart)
- {
- cycles -= 2;
- cycles -= (NDS::ARM7MemTimings[CurSrcAddr >> 15][0] + NDS::ARM7MemTimings[CurDstAddr >> 15][0]);
- cycles += unitcycles;
- }*/
- }
-
while (IterCount > 0 && !Stall)
{
- NDS::ARM7Timestamp += unitcycles;
+ NDS::ARM7Timestamp += UnitTimings7_16(burststart);
+ burststart = false;
if (ConsoleType == 1)
DSi::ARM7Write16(CurDstAddr, DSi::ARM7Read16(CurSrcAddr));
@@ -355,29 +656,10 @@ void DMA::Run7()
}
else
{
- if ((CurSrcAddr >> 24) == 0x02 && (CurDstAddr >> 24) == 0x02)
- {
- unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2];
- }
- else
- {
- unitcycles = NDS::ARM7MemTimings[CurSrcAddr >> 15][3] + NDS::ARM7MemTimings[CurDstAddr >> 15][3];
- if ((CurSrcAddr >> 23) == (CurDstAddr >> 23))
- unitcycles++;
- else if ((CurSrcAddr >> 24) == 0x02)
- unitcycles--;
-
- /*if (burststart)
- {
- cycles -= 2;
- cycles -= (NDS::ARM7MemTimings[CurSrcAddr >> 15][2] + NDS::ARM7MemTimings[CurDstAddr >> 15][2]);
- cycles += unitcycles;
- }*/
- }
-
while (IterCount > 0 && !Stall)
{
- NDS::ARM7Timestamp += unitcycles;
+ NDS::ARM7Timestamp += UnitTimings7_32(burststart);
+ burststart = false;
if (ConsoleType == 1)
DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr));
diff --git a/src/DMA.h b/src/DMA.h
index b86796d..17cb618 100644
--- a/src/DMA.h
+++ b/src/DMA.h
@@ -34,6 +34,11 @@ public:
void WriteCnt(u32 val);
void Start();
+ u32 UnitTimings9_16(bool burststart);
+ u32 UnitTimings9_32(bool burststart);
+ u32 UnitTimings7_16(bool burststart);
+ u32 UnitTimings7_32(bool burststart);
+
template <int ConsoleType>
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
new file mode 100644
index 0000000..1d86750
--- /dev/null
+++ b/src/DMA_Timings.h
@@ -0,0 +1,245 @@
+/*
+ Copyright 2016-2021 Arisotura
+
+ This file is part of melonDS.
+
+ melonDS is free software: you can redistribute it and/or modify it under
+ the terms of the GNU General Public License as published by the Free
+ Software Foundation, either version 3 of the License, or (at your option)
+ any later version.
+
+ melonDS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with melonDS. If not, see http://www.gnu.org/licenses/.
+*/
+
+#ifndef DMA_TIMINGS_H
+#define DMA_TIMINGS_H
+
+namespace DMATiming
+{
+
+// DMA timing tables
+//
+// DMA timings on the DS are normally straightforward, except in one case: when
+// main RAM is involved.
+// Main RAM to main RAM is the easy case: 16c/unit in 16bit mode, 18c/unit in 32bit
+// mode.
+// It gets more complicated when transferring from main RAM to somewhere else, or
+// vice versa: main RAM supports burst accesses, but the rules dictating how long
+// bursts can be are weird and inconsistent. Main RAM also supports parallel
+// memory operations, to some extent.
+// I haven't figured out the full logic behind it, let alone how to emulate it
+// efficiently, so for now we will use these tables.
+// A zero denotes the end of a burst pattern.
+//
+// Note: burst patterns only apply when the main RAM address is incrementing.
+// A fixed or decrementing address results in nonsequential accesses.
+//
+// Note about GBA slot/wifi timings: these take into account the sequential timing
+// 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 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,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 7, 3, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 7, 3,
+ 0},
+ // main RAM to GBA/wifi, seq=4
+ {8, 6, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5,
+ 0},
+ // main RAM to GBA/wifi, seq=6
+ {10, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7,
+ 12, 8,
+ 0},
+};
+
+u8 MRAMRead32Bursts[][256] =
+{
+ // main RAM to regular 16bit bus
+ {9, 4, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 9,
+ 0},
+ // main RAM to regular 32bit bus
+ {9, 3, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2,
+ 0},
+ // main RAM to GBA/wifi, seq=4
+ {14, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13, 10, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9,
+ 13,
+ 0},
+ // main RAM to GBA/wifi, seq=6
+ {18, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17, 14, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 17,
+ 0},
+};
+
+u8 MRAMWrite16Bursts[][256] =
+{
+ // regular 16bit or 32bit bus to main RAM (similar)
+ {8, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 0},
+ // GBA/wifi to main RAM, seq=4
+ {10, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5,
+ 0},
+ // GBA/wifi to main RAM, seq=6
+ {9, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7,
+ 0},
+};
+
+u8 MRAMWrite32Bursts[][256] =
+{
+ // regular 16bit bus to main RAM
+ {9, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 0},
+ // regular 32bit bus to main RAM
+ {9, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 0},
+ // GBA/wifi to main RAM, seq=4
+ {15, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10,
+ 0},
+ // GBA/wifi to main RAM, seq=6
+ {16, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 14,
+ 0},
+};
+
+}
+
+#endif // DMA_TIMINGS_H
diff --git a/src/DSi.cpp b/src/DSi.cpp
index 01e501b..d453ee2 100644
--- a/src/DSi.cpp
+++ b/src/DSi.cpp
@@ -1139,7 +1139,7 @@ void Set_SCFG_Clock9(u16 val)
NDS::ARM9Timestamp <<= NDS::ARM9ClockShift;
NDS::ARM9Target <<= NDS::ARM9ClockShift;
- NDS::ARM9->UpdateRegionTimings(0x00000000, 0xFFFFFFFF);
+ NDS::ARM9->UpdateRegionTimings(0x00000, 0x100000);
}
void Set_SCFG_MC(u32 val)
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 00cbad3..8341687 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -71,8 +71,10 @@ namespace NDS
int ConsoleType;
-u8 ARM9MemTimings[0x40000][4];
+u8 ARM9MemTimings[0x40000][8];
+u32 ARM9Regions[0x40000];
u8 ARM7MemTimings[0x20000][4];
+u32 ARM7Regions[0x20000];
ARMv5* ARM9;
ARMv4* ARM7;
@@ -236,14 +238,12 @@ void DeInit()
}
-void SetARM9RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq)
+void SetARM9RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswidth, int nonseq, int seq)
{
- addrstart >>= 14;
- addrend >>= 14;
+ addrstart >>= 2;
+ addrend >>= 2;
- if (addrend == 0x3FFFF) addrend++;
-
- int N16, S16, N32, S32;
+ int N16, S16, N32, S32, cpuN;
N16 = nonseq;
S16 = seq;
if (buswidth == 16)
@@ -257,25 +257,33 @@ void SetARM9RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq,
S32 = S16;
}
+ // nonseq accesses on the CPU get a 3-cycle penalty for all regions except main RAM
+ cpuN = (region == Mem9_MainRAM) ? 0 : 3;
+
for (u32 i = addrstart; i < addrend; i++)
{
- ARM9MemTimings[i][0] = N16;
+ // CPU timings
+ ARM9MemTimings[i][0] = N16 + cpuN;
ARM9MemTimings[i][1] = S16;
- ARM9MemTimings[i][2] = N32;
+ ARM9MemTimings[i][2] = N32 + cpuN;
ARM9MemTimings[i][3] = S32;
+
+ // DMA timings
+ ARM9MemTimings[i][4] = N16;
+ ARM9MemTimings[i][5] = S16;
+ ARM9MemTimings[i][6] = N32;
+ ARM9MemTimings[i][7] = S32;
+
+ ARM9Regions[i] = region;
}
- ARM9->UpdateRegionTimings(addrstart<<14, addrend == 0x40000
- ? 0xFFFFFFFF
- : (addrend<<14));
+ ARM9->UpdateRegionTimings(addrstart<<2, addrend<<2);
}
-void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq)
+void SetARM7RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswidth, int nonseq, int seq)
{
- addrstart >>= 15;
- addrend >>= 15;
-
- if (addrend == 0x1FFFF) addrend++;
+ addrstart >>= 3;
+ addrend >>= 3;
int N16, S16, N32, S32;
N16 = nonseq;
@@ -293,10 +301,13 @@ void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq,
for (u32 i = addrstart; i < addrend; i++)
{
+ // CPU and DMA timings are the same
ARM7MemTimings[i][0] = N16;
ARM7MemTimings[i][1] = S16;
ARM7MemTimings[i][2] = N32;
ARM7MemTimings[i][3] = S32;
+
+ ARM7Regions[i] = region;
}
}
@@ -307,32 +318,32 @@ void InitTimings()
// Similarly for any unmapped VRAM area.
// Need to check whether supporting these timing characteristics would impact performance
// (especially wrt VRAM mirroring and overlapping and whatnot).
+ // Also, each VRAM bank is its own memory region. This would matter when DMAing from a VRAM
+ // bank to another (if this is a thing) for example.
- // ARM9
- // TODO: +3c nonseq waitstate doesn't apply to DMA!
- // but of course mainRAM always gets 8c nonseq waitstate
+ // TODO: check in detail how WRAM works, although it seems to be one region.
// TODO: DSi-specific timings!!
- SetARM9RegionTimings(0x00000000, 0xFFFFFFFF, 32, 1 + 3, 1); // void
+ SetARM9RegionTimings(0x00000, 0x100000, 0, 32, 1, 1); // void
- SetARM9RegionTimings(0xFFFF0000, 0xFFFFFFFF, 32, 1 + 3, 1); // BIOS
- SetARM9RegionTimings(0x02000000, 0x03000000, 16, 8, 1); // main RAM
- SetARM9RegionTimings(0x03000000, 0x04000000, 32, 1 + 3, 1); // ARM9/shared WRAM
- SetARM9RegionTimings(0x04000000, 0x05000000, 32, 1 + 3, 1); // IO
- SetARM9RegionTimings(0x05000000, 0x06000000, 16, 1 + 3, 1); // palette
- SetARM9RegionTimings(0x06000000, 0x07000000, 16, 1 + 3, 1); // VRAM
- SetARM9RegionTimings(0x07000000, 0x08000000, 32, 1 + 3, 1); // OAM
+ SetARM9RegionTimings(0xFFFF0, 0x100000, Mem9_BIOS, 32, 1, 1); // BIOS
+ SetARM9RegionTimings(0x02000, 0x03000, Mem9_MainRAM, 16, 8, 1); // main RAM
+ SetARM9RegionTimings(0x03000, 0x04000, Mem9_WRAM, 32, 1, 1); // ARM9/shared WRAM
+ SetARM9RegionTimings(0x04000, 0x05000, Mem9_IO, 32, 1, 1); // IO
+ SetARM9RegionTimings(0x05000, 0x06000, Mem9_Pal, 16, 1, 1); // palette
+ SetARM9RegionTimings(0x06000, 0x07000, Mem9_VRAM, 16, 1, 1); // VRAM
+ SetARM9RegionTimings(0x07000, 0x08000, Mem9_OAM, 32, 1, 1); // OAM
// ARM7
- SetARM7RegionTimings(0x00000000, 0xFFFFFFFF, 32, 1, 1); // void
+ SetARM7RegionTimings(0x00000, 0x100000, 0, 32, 1, 1); // void
- SetARM7RegionTimings(0x00000000, 0x00010000, 32, 1, 1); // BIOS
- SetARM7RegionTimings(0x02000000, 0x03000000, 16, 8, 1); // main RAM
- SetARM7RegionTimings(0x03000000, 0x04000000, 32, 1, 1); // ARM7/shared WRAM
- SetARM7RegionTimings(0x04000000, 0x04800000, 32, 1, 1); // IO
- SetARM7RegionTimings(0x06000000, 0x07000000, 16, 1, 1); // ARM7 VRAM
+ SetARM7RegionTimings(0x00000, 0x00010, Mem7_BIOS, 32, 1, 1); // BIOS
+ SetARM7RegionTimings(0x02000, 0x03000, Mem7_MainRAM, 16, 8, 1); // main RAM
+ SetARM7RegionTimings(0x03000, 0x04000, Mem7_WRAM, 32, 1, 1); // ARM7/shared WRAM
+ SetARM7RegionTimings(0x04000, 0x04800, Mem7_IO, 32, 1, 1); // IO
+ SetARM7RegionTimings(0x06000, 0x07000, Mem7_VRAM, 16, 1, 1); // ARM7 VRAM
// handled later: GBA slot, wifi
}
@@ -1242,8 +1253,8 @@ void SetWifiWaitCnt(u16 val)
WifiWaitCnt = val;
const int ntimings[4] = {10, 8, 6, 18};
- SetARM7RegionTimings(0x04800000, 0x04808000, 16, ntimings[val & 0x3], (val & 0x4) ? 4 : 6);
- SetARM7RegionTimings(0x04808000, 0x04810000, 16, ntimings[(val>>3) & 0x3], (val & 0x20) ? 4 : 10);
+ SetARM7RegionTimings(0x04800, 0x04808, Mem7_Wifi0, 16, ntimings[val & 0x3], (val & 0x4) ? 4 : 6);
+ SetARM7RegionTimings(0x04808, 0x04810, Mem7_Wifi1, 16, ntimings[(val>>3) & 0x3], (val & 0x20) ? 4 : 10);
}
void SetGBASlotTimings()
@@ -1251,31 +1262,36 @@ void SetGBASlotTimings()
const int ntimings[4] = {10, 8, 6, 18};
const u16 openbus[4] = {0xFE08, 0x0000, 0x0000, 0xFFFF};
- u16 curcnt;
- int ramN, romN, romS;
+ u16 curcpu = (ExMemCnt[0] >> 7) & 0x1;
+ u16 curcnt = ExMemCnt[curcpu];
+ int ramN = ntimings[curcnt & 0x3];
+ int romN = ntimings[(curcnt>>2) & 0x3];
+ int romS = (curcnt & 0x10) ? 4 : 6;
- curcnt = ExMemCnt[0];
- ramN = ntimings[curcnt & 0x3];
- romN = ntimings[(curcnt>>2) & 0x3];
- romS = (curcnt & 0x10) ? 4 : 6;
+ // GBA slot timings only apply on the selected side
- SetARM9RegionTimings(0x08000000, 0x0A000000, 16, romN + 3, romS);
- SetARM9RegionTimings(0x0A000000, 0x0B000000, 8, ramN + 3, ramN);
+ if (curcpu == 0)
+ {
+ SetARM9RegionTimings(0x08000, 0x0A000, Mem9_GBAROM, 16, romN, romS);
+ SetARM9RegionTimings(0x0A000, 0x0B000, Mem9_GBARAM, 8, ramN, ramN);
- curcnt = ExMemCnt[1];
- ramN = ntimings[curcnt & 0x3];
- romN = ntimings[(curcnt>>2) & 0x3];
- romS = (curcnt & 0x10) ? 4 : 6;
+ SetARM7RegionTimings(0x08000, 0x0A000, 0, 32, 1, 1);
+ SetARM7RegionTimings(0x0A000, 0x0B000, 0, 32, 1, 1);
+ }
+ else
+ {
+ SetARM9RegionTimings(0x08000, 0x0A000, 0, 32, 1, 1);
+ SetARM9RegionTimings(0x0A000, 0x0B000, 0, 32, 1, 1);
- SetARM7RegionTimings(0x08000000, 0x0A000000, 16, romN, romS);
- SetARM7RegionTimings(0x0A000000, 0x0B000000, 8, ramN, ramN);
+ SetARM7RegionTimings(0x08000, 0x0A000, Mem7_GBAROM, 16, romN, romS);
+ SetARM7RegionTimings(0x0A000, 0x0B000, Mem7_GBARAM, 8, ramN, ramN);
+ }
// this open-bus implementation is a rough way of simulating the way values
// lingering on the bus decay after a while, which is visible at higher waitstates
// for example, the Cartridge Construction Kit relies on this to determine that
// the GBA slot is empty
- curcnt = ExMemCnt[(ExMemCnt[0]>>7) & 0x1];
GBACart::SetOpenBusDecay(openbus[(curcnt>>2) & 0x3]);
}
@@ -1556,10 +1572,7 @@ void RunTimer(u32 tid, s32 cycles)
{
Timer* timer = &Timers[tid];
- u32 oldcount = timer->Counter;
timer->Counter += (cycles << timer->CycleShift);
- //if (timer->Counter < oldcount)
- // HandleTimerOverflow(tid);
while (timer->Counter >> 26)
{
timer->Counter -= (1 << 26);
@@ -1585,6 +1598,38 @@ void RunTimers(u32 cpu)
TimerTimestamp[cpu] += cycles;
}
+const s32 TimerPrescaler[4] = {0, 6, 8, 10};
+
+u16 TimerGetCounter(u32 timer)
+{
+ RunTimers(timer>>2);
+ u32 ret = Timers[timer].Counter;
+
+ return ret >> 10;
+}
+
+void TimerStart(u32 id, u16 cnt)
+{
+ Timer* timer = &Timers[id];
+ u16 curstart = timer->Cnt & (1<<7);
+ u16 newstart = cnt & (1<<7);
+
+ RunTimers(id>>2);
+
+ timer->Cnt = cnt;
+ timer->CycleShift = 10 - TimerPrescaler[cnt & 0x03];
+
+ if ((!curstart) && newstart)
+ {
+ timer->Counter = timer->Reload << 10;
+ }
+
+ if ((cnt & 0x84) == 0x80)
+ TimerCheckMask[id>>2] |= 0x01 << (id&0x3);
+ else
+ TimerCheckMask[id>>2] &= ~(0x01 << (id&0x3));
+}
+
// matching NDMA modes for DSi
@@ -1673,55 +1718,6 @@ void StopDMAs(u32 cpu, u32 mode)
-
-const s32 TimerPrescaler[4] = {0, 6, 8, 10};
-
-u16 TimerGetCounter(u32 timer)
-{
- RunTimers(timer>>2);
- u32 ret = Timers[timer].Counter;
-
- return ret >> 10;
-}
-
-void TimerStart(u32 id, u16 cnt)
-{
- Timer* timer = &Timers[id];
- u16 curstart = timer->Cnt & (1<<7);
- u16 newstart = cnt & (1<<7);
-
- timer->Cnt = cnt;
- timer->CycleShift = 10 - TimerPrescaler[cnt & 0x03];
-
- if ((!curstart) && newstart)
- {
- timer->Counter = timer->Reload << 10;
-
- /*if ((cnt & 0x84) == 0x80)
- {
- u32 delay = (0x10000 - timer->Reload) << TimerPrescaler[cnt & 0x03];
- printf("timer%d IRQ: start %d, reload=%04X cnt=%08X\n", id, delay, timer->Reload, timer->Counter);
- CancelEvent(Event_TimerIRQ_0 + id);
- ScheduleEvent(Event_TimerIRQ_0 + id, false, delay, HandleTimerOverflow, id);
- }*/
- }
-
- if ((cnt & 0x84) == 0x80)
- {
- u32 tmask;
- //if ((cnt & 0x03) == 0)
- tmask = 0x01 << (id&0x3);
- //else
- // tmask = 0x10 << (id&0x3);
-
- TimerCheckMask[id>>2] |= tmask;
- }
- else
- TimerCheckMask[id>>2] &= ~(0x11 << (id&0x3));
-}
-
-
-
void DivDone(u32 param)
{
DivCnt &= ~0xC000;
@@ -2014,7 +2010,7 @@ u16 ARM9Read16(u32 addr)
(GBACart::SRAMRead(addr+1) << 8);
}
- if (addr) printf("unknown arm9 read16 %08X %08X\n", addr, ARM9->R[15]);
+ //if (addr) printf("unknown arm9 read16 %08X %08X\n", addr, ARM9->R[15]);
return 0;
}
@@ -2075,7 +2071,7 @@ u32 ARM9Read32(u32 addr)
(GBACart::SRAMRead(addr+3) << 24);
}
- printf("unknown arm9 read32 %08X | %08X %08X\n", addr, ARM9->R[15], ARM9->R[12]);
+ //printf("unknown arm9 read32 %08X | %08X %08X\n", addr, ARM9->R[15], ARM9->R[12]);
return 0;
}
@@ -2183,7 +2179,7 @@ void ARM9Write16(u32 addr, u16 val)
return;
}
- if (addr) printf("unknown arm9 write16 %08X %04X\n", addr, val);
+ //if (addr) printf("unknown arm9 write16 %08X %04X\n", addr, val);
}
void ARM9Write32(u32 addr, u32 val)
@@ -2250,7 +2246,7 @@ void ARM9Write32(u32 addr, u32 val)
return;
}
- printf("unknown arm9 write32 %08X %08X | %08X\n", addr, val, ARM9->R[15]);
+ //printf("unknown arm9 write32 %08X %08X | %08X\n", addr, val, ARM9->R[15]);
}
bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region)
diff --git a/src/NDS.h b/src/NDS.h
index 3e7f2b7..33063c1 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -129,6 +129,33 @@ struct Timer
u32 CycleShift;
};
+enum
+{
+ Mem9_ITCM = 0x00000001,
+ Mem9_DTCM = 0x00000002,
+ Mem9_BIOS = 0x00000004,
+ Mem9_MainRAM = 0x00000008,
+ Mem9_WRAM = 0x00000010,
+ Mem9_IO = 0x00000020,
+ Mem9_Pal = 0x00000040,
+ Mem9_OAM = 0x00000080,
+ Mem9_VRAM = 0x00000100,
+ Mem9_GBAROM = 0x00020000,
+ Mem9_GBARAM = 0x00040000,
+
+ Mem7_BIOS = 0x00000001,
+ Mem7_MainRAM = 0x00000002,
+ Mem7_WRAM = 0x00000004,
+ Mem7_IO = 0x00000008,
+ Mem7_Wifi0 = 0x00000010,
+ Mem7_Wifi1 = 0x00000020,
+ Mem7_VRAM = 0x00000040,
+ Mem7_GBAROM = 0x00000100,
+ Mem7_GBARAM = 0x00000200,
+
+ // TODO: add DSi regions!
+};
+
struct MemRegion
{
u8* Mem;
@@ -138,8 +165,10 @@ struct MemRegion
extern int ConsoleType;
extern int CurCPU;
-extern u8 ARM9MemTimings[0x40000][4];
+extern u8 ARM9MemTimings[0x40000][8];
+extern u32 ARM9Regions[0x40000];
extern u8 ARM7MemTimings[0x20000][4];
+extern u32 ARM7Regions[0x20000];
extern u32 NumFrames;
extern u32 NumLagFrames;
@@ -191,8 +220,8 @@ void Stop();
bool DoSavestate(Savestate* file);
-void SetARM9RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq);
-void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq);
+void SetARM9RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswidth, int nonseq, int seq);
+void SetARM7RegionTimings(u32 addrstart, u32 addrend, u32 region, int buswidth, int nonseq, int seq);
// 0=DS 1=DSi
void SetConsoleType(int type);