aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArisotura <thetotalworm@gmail.com>2019-06-18 22:54:07 +0200
committerArisotura <thetotalworm@gmail.com>2019-06-18 22:54:07 +0200
commitd6bbc6f0f1ede57f0805137617ba670a49f7506f (patch)
treeaccd99c77f4fe5a2baf464dc9795e7c16be1f9b0
parent841122bc51156f3f1d351c47c8ac17af7a605e56 (diff)
tremble upon the NDMA implementation
that doesn't do much beyond getting stuck
-rw-r--r--src/DMA.cpp6
-rw-r--r--src/DSi.cpp171
-rw-r--r--src/DSi.h4
-rw-r--r--src/DSi_NDMA.cpp301
-rw-r--r--src/DSi_NDMA.h74
-rw-r--r--src/NDS.cpp4
-rw-r--r--src/NDS.h5
7 files changed, 556 insertions, 9 deletions
diff --git a/src/DMA.cpp b/src/DMA.cpp
index 2814264..0826d7a 100644
--- a/src/DMA.cpp
+++ b/src/DMA.cpp
@@ -20,15 +20,9 @@
#include "NDS.h"
#include "DSi.h"
#include "DMA.h"
-#include "NDSCart.h"
#include "GPU.h"
-// NOTES ON DMA SHIT
-//
-// * could use optimized code paths for common types of DMA transfers. for example, VRAM
-// have to profile it to see if it's actually worth doing
-
// DMA TIMINGS
//
diff --git a/src/DSi.cpp b/src/DSi.cpp
index abd3bd6..0c9c26c 100644
--- a/src/DSi.cpp
+++ b/src/DSi.cpp
@@ -25,6 +25,7 @@
#include "sha1/sha1.h"
#include "Platform.h"
+#include "DSi_NDMA.h"
#include "DSi_I2C.h"
#include "DSi_SD.h"
@@ -57,6 +58,9 @@ u32 NWRAMStart[2][3];
u32 NWRAMEnd[2][3];
u32 NWRAMMask[2][3];
+u32 NDMACnt[2];
+DSi_NDMA* NDMAs[8];
+
DSi_SDHost* SDMMC;
DSi_SDHost* SDIO;
@@ -68,6 +72,15 @@ bool Init()
{
if (!DSi_I2C::Init()) return false;
+ NDMAs[0] = new DSi_NDMA(0, 0);
+ NDMAs[1] = new DSi_NDMA(0, 1);
+ NDMAs[2] = new DSi_NDMA(0, 2);
+ NDMAs[3] = new DSi_NDMA(0, 3);
+ NDMAs[4] = new DSi_NDMA(1, 0);
+ NDMAs[5] = new DSi_NDMA(1, 1);
+ NDMAs[6] = new DSi_NDMA(1, 2);
+ NDMAs[7] = new DSi_NDMA(1, 3);
+
SDMMC = new DSi_SDHost(0);
SDIO = new DSi_SDHost(1);
@@ -78,6 +91,8 @@ void DeInit()
{
DSi_I2C::DeInit();
+ for (int i = 0; i < 8; i++) delete NDMAs[i];
+
delete SDMMC;
delete SDIO;
}
@@ -91,6 +106,9 @@ void Reset()
NDS::ARM9->JumpTo(BootAddr[0]);
NDS::ARM7->JumpTo(BootAddr[1]);
+ NDMACnt[0] = 0; NDMACnt[1] = 0;
+ for (int i = 0; i < 8; i++) NDMAs[i]->Reset();
+
DSi_I2C::Reset();
SDMMC->Reset();
@@ -279,6 +297,40 @@ bool LoadNAND()
}
+void RunNDMAs(u32 cpu)
+{
+ // TODO: round-robin mode (requires DMA channels to have a subblock delay set)
+
+ if (cpu == 0)
+ {
+ if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+
+ //
+ }
+ else
+ {
+ if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
+
+ //
+ }
+}
+
+void StallNDMAs()
+{
+ // TODO
+}
+
+bool NDMAsRunning(u32 cpu)
+{
+ cpu <<= 2;
+ if (NDMAs[cpu+0]->IsRunning()) return true;
+ if (NDMAs[cpu+1]->IsRunning()) return true;
+ if (NDMAs[cpu+2]->IsRunning()) return true;
+ if (NDMAs[cpu+3]->IsRunning()) return true;
+ return false;
+}
+
+
// new WRAM mapping
// TODO: find out what happens upon overlapping slots!!
@@ -872,6 +924,36 @@ u32 ARM9IORead32(u32 addr)
switch (addr)
{
case 0x04004010: return 1; // todo
+
+ case 0x04004100: return NDMACnt[0];
+ case 0x04004104: return NDMAs[0]->SrcAddr;
+ case 0x04004108: return NDMAs[0]->DstAddr;
+ case 0x0400410C: return NDMAs[0]->TotalLength;
+ case 0x04004110: return NDMAs[0]->BlockLength;
+ case 0x04004114: return NDMAs[0]->SubblockTimer;
+ case 0x04004118: return NDMAs[0]->FillData;
+ case 0x0400411C: return NDMAs[0]->Cnt;
+ case 0x04004120: return NDMAs[1]->SrcAddr;
+ case 0x04004124: return NDMAs[1]->DstAddr;
+ case 0x04004128: return NDMAs[1]->TotalLength;
+ case 0x0400412C: return NDMAs[1]->BlockLength;
+ case 0x04004130: return NDMAs[1]->SubblockTimer;
+ case 0x04004134: return NDMAs[1]->FillData;
+ case 0x04004138: return NDMAs[1]->Cnt;
+ case 0x0400413C: return NDMAs[2]->SrcAddr;
+ case 0x04004140: return NDMAs[2]->DstAddr;
+ case 0x04004144: return NDMAs[2]->TotalLength;
+ case 0x04004148: return NDMAs[2]->BlockLength;
+ case 0x0400414C: return NDMAs[2]->SubblockTimer;
+ case 0x04004150: return NDMAs[2]->FillData;
+ case 0x04004154: return NDMAs[2]->Cnt;
+ case 0x04004158: return NDMAs[3]->SrcAddr;
+ case 0x0400415C: return NDMAs[3]->DstAddr;
+ case 0x04004160: return NDMAs[3]->TotalLength;
+ case 0x04004164: return NDMAs[3]->BlockLength;
+ case 0x04004168: return NDMAs[3]->SubblockTimer;
+ case 0x0400416C: return NDMAs[3]->FillData;
+ case 0x04004170: return NDMAs[3]->Cnt;
}
return NDS::ARM9IORead32(addr);
@@ -899,6 +981,35 @@ void ARM9IOWrite32(u32 addr, u32 val)
{
switch (addr)
{
+ case 0x04004100: NDMACnt[0] = val & 0x800F0000; return;
+ case 0x04004104: NDMAs[0]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004108: NDMAs[0]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x0400410C: NDMAs[0]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004110: NDMAs[0]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004114: NDMAs[0]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004118: NDMAs[0]->FillData = val; return;
+ case 0x0400411C: NDMAs[0]->WriteCnt(val); return;
+ case 0x04004120: NDMAs[1]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004124: NDMAs[1]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004128: NDMAs[1]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x0400412C: NDMAs[1]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004130: NDMAs[1]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004134: NDMAs[1]->FillData = val; return;
+ case 0x04004138: NDMAs[1]->WriteCnt(val); return;
+ case 0x0400413C: NDMAs[2]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004140: NDMAs[2]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004144: NDMAs[2]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004148: NDMAs[2]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x0400414C: NDMAs[2]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004150: NDMAs[2]->FillData = val; return;
+ case 0x04004154: NDMAs[2]->WriteCnt(val); return;
+ case 0x04004158: NDMAs[3]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x0400415C: NDMAs[3]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004160: NDMAs[3]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004164: NDMAs[3]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004168: NDMAs[3]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x0400416C: NDMAs[3]->FillData = val; return;
+ case 0x04004170: NDMAs[3]->WriteCnt(val); return;
}
return NDS::ARM9IOWrite32(addr, val);
@@ -950,6 +1061,36 @@ u32 ARM7IORead32(u32 addr)
case 0x0400021C: return NDS::IF2;
case 0x04004008: return 0x80000000; // HAX
+
+ case 0x04004100: return NDMACnt[1];
+ case 0x04004104: return NDMAs[4]->SrcAddr;
+ case 0x04004108: return NDMAs[4]->DstAddr;
+ case 0x0400410C: return NDMAs[4]->TotalLength;
+ case 0x04004110: return NDMAs[4]->BlockLength;
+ case 0x04004114: return NDMAs[4]->SubblockTimer;
+ case 0x04004118: return NDMAs[4]->FillData;
+ case 0x0400411C: return NDMAs[4]->Cnt;
+ case 0x04004120: return NDMAs[5]->SrcAddr;
+ case 0x04004124: return NDMAs[5]->DstAddr;
+ case 0x04004128: return NDMAs[5]->TotalLength;
+ case 0x0400412C: return NDMAs[5]->BlockLength;
+ case 0x04004130: return NDMAs[5]->SubblockTimer;
+ case 0x04004134: return NDMAs[5]->FillData;
+ case 0x04004138: return NDMAs[5]->Cnt;
+ case 0x0400413C: return NDMAs[6]->SrcAddr;
+ case 0x04004140: return NDMAs[6]->DstAddr;
+ case 0x04004144: return NDMAs[6]->TotalLength;
+ case 0x04004148: return NDMAs[6]->BlockLength;
+ case 0x0400414C: return NDMAs[6]->SubblockTimer;
+ case 0x04004150: return NDMAs[6]->FillData;
+ case 0x04004154: return NDMAs[6]->Cnt;
+ case 0x04004158: return NDMAs[7]->SrcAddr;
+ case 0x0400415C: return NDMAs[7]->DstAddr;
+ case 0x04004160: return NDMAs[7]->TotalLength;
+ case 0x04004164: return NDMAs[7]->BlockLength;
+ case 0x04004168: return NDMAs[7]->SubblockTimer;
+ case 0x0400416C: return NDMAs[7]->FillData;
+ case 0x04004170: return NDMAs[7]->Cnt;
}
if (addr >= 0x04004800 && addr < 0x04004A00)
@@ -1003,6 +1144,36 @@ void ARM7IOWrite32(u32 addr, u32 val)
{
case 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return;
case 0x0400021C: NDS::IF2 &= ~(val & 0x7FF7); NDS::UpdateIRQ(1); return;
+
+ case 0x04004100: NDMACnt[1] = val & 0x800F0000; return;
+ case 0x04004104: NDMAs[4]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004108: NDMAs[4]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x0400410C: NDMAs[4]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004110: NDMAs[4]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004114: NDMAs[4]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004118: NDMAs[4]->FillData = val; return;
+ case 0x0400411C: NDMAs[4]->WriteCnt(val); return;
+ case 0x04004120: NDMAs[5]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004124: NDMAs[5]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004128: NDMAs[5]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x0400412C: NDMAs[5]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004130: NDMAs[5]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004134: NDMAs[5]->FillData = val; return;
+ case 0x04004138: NDMAs[5]->WriteCnt(val); return;
+ case 0x0400413C: NDMAs[6]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x04004140: NDMAs[6]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004144: NDMAs[6]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004148: NDMAs[6]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x0400414C: NDMAs[6]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x04004150: NDMAs[6]->FillData = val; return;
+ case 0x04004154: NDMAs[6]->WriteCnt(val); return;
+ case 0x04004158: NDMAs[7]->SrcAddr = val & 0xFFFFFFFC; return;
+ case 0x0400415C: NDMAs[7]->DstAddr = val & 0xFFFFFFFC; return;
+ case 0x04004160: NDMAs[7]->TotalLength = val & 0x0FFFFFFF; return;
+ case 0x04004164: NDMAs[7]->BlockLength = val & 0x00FFFFFF; return;
+ case 0x04004168: NDMAs[7]->SubblockTimer = val & 0x0003FFFF; return;
+ case 0x0400416C: NDMAs[7]->FillData = val; return;
+ case 0x04004170: NDMAs[7]->WriteCnt(val); return;
}
if (addr >= 0x04004800 && addr < 0x04004A00)
diff --git a/src/DSi.h b/src/DSi.h
index efd533a..32253a7 100644
--- a/src/DSi.h
+++ b/src/DSi.h
@@ -38,6 +38,10 @@ void Reset();
bool LoadBIOS();
bool LoadNAND();
+void RunNDMAs(u32 cpu);
+void StallNDMAs();
+bool NDMAsRunning(u32 cpu);
+
void MapNWRAM_A(u32 num, u8 val);
void MapNWRAM_B(u32 num, u8 val);
void MapNWRAM_C(u32 num, u8 val);
diff --git a/src/DSi_NDMA.cpp b/src/DSi_NDMA.cpp
index 6a524dd..a8055eb 100644
--- a/src/DSi_NDMA.cpp
+++ b/src/DSi_NDMA.cpp
@@ -15,3 +15,304 @@
You should have received a copy of the GNU General Public License along
with melonDS. If not, see http://www.gnu.org/licenses/.
*/
+
+#include <stdio.h>
+#include "NDS.h"
+#include "DSi.h"
+#include "DSi_NDMA.h"
+#include "GPU.h"
+
+
+
+DSi_NDMA::DSi_NDMA(u32 cpu, u32 num)
+{
+ CPU = cpu;
+ Num = num;
+
+ Reset();
+}
+
+DSi_NDMA::~DSi_NDMA()
+{
+}
+
+void DSi_NDMA::Reset()
+{
+ SrcAddr = 0;
+ DstAddr = 0;
+ TotalLength = 0;
+ BlockLength = 0;
+ SubblockTimer = 0;
+ FillData = 0;
+ Cnt = 0;
+
+ StartMode = 0;
+ CurSrcAddr = 0;
+ CurDstAddr = 0;
+ SubblockLength = 0;
+ RemCount = 0;
+ IterCount = 0;
+ TotalRemCount = 0;
+ SrcAddrInc = 0;
+ DstAddrInc = 0;
+
+ Running = false;
+ InProgress = false;
+}
+
+void DSi_NDMA::DoSavestate(Savestate* file)
+{
+ // TODO!
+}
+
+void DSi_NDMA::WriteCnt(u32 val)
+{
+ u32 oldcnt = Cnt;
+ Cnt = val;
+
+ if ((!(oldcnt & 0x80000000)) && (val & 0x80000000)) // checkme
+ {
+ CurSrcAddr = SrcAddr;
+ CurDstAddr = DstAddr;
+ TotalRemCount = TotalLength;
+
+ switch ((Cnt >> 10) & 0x3)
+ {
+ case 0: DstAddrInc = 1; break;
+ case 1: DstAddrInc = -1; break;
+ case 2: DstAddrInc = 0; break;
+ case 3: DstAddrInc = 1; printf("BAD NDMA DST INC MODE 3\n"); break;
+ }
+
+ switch ((Cnt >> 13) & 0x3)
+ {
+ case 0: SrcAddrInc = 1; break;
+ case 1: SrcAddrInc = -1; break;
+ case 2: SrcAddrInc = 0; break;
+ case 3: SrcAddrInc = 0; break; // fill mode
+ }
+
+ StartMode = (Cnt >> 24) & 0x1F;
+ if (StartMode > 0x10) StartMode = 0x10;
+ if (CPU == 1) StartMode |= 0x20;
+
+ if ((StartMode & 0x1F) == 0x10)
+ Start();
+
+ if (StartMode != 0x10 && StartMode != 0x30)
+ printf("UNIMPLEMENTED ARM%d NDMA%d START MODE %02X, %08X->%08X\n", CPU?7:9, Num, StartMode, SrcAddr, DstAddr);
+ }
+}
+
+void DSi_NDMA::Start()
+{
+ if (Running) return;
+
+ if (!InProgress)
+ {
+ RemCount = BlockLength;
+ if (!RemCount)
+ RemCount = 0x1000000;
+ }
+
+ // TODO: how does GXFIFO DMA work with all the block shito?
+ IterCount = RemCount;
+
+ if (IterCount > TotalRemCount)
+ IterCount = TotalRemCount;
+
+ if (Cnt & (1<<12)) CurDstAddr = DstAddr;
+ if (Cnt & (1<<15)) CurSrcAddr = SrcAddr;
+
+ printf("ARM%d NDMA%d %08X %02X %08X->%08X %d bytes\n", CPU?7:9, Num, Cnt, StartMode, CurSrcAddr, CurDstAddr, RemCount*4);
+
+ //IsGXFIFODMA = (CPU == 0 && (CurSrcAddr>>24) == 0x02 && CurDstAddr == 0x04000400 && DstAddrInc == 0);
+
+ // TODO eventually: not stop if we're running code in ITCM
+
+ if (SubblockTimer & 0xFFFF)
+ printf("TODO! NDMA SUBBLOCK TIMER: %08X\n", SubblockTimer);
+
+ if (NDS::DMAsRunning(CPU))
+ Running = 1;
+ else
+ Running = 2;
+
+ InProgress = true;
+ NDS::StopCPU(CPU, 1<<(Num+4));
+}
+
+void DSi_NDMA::Run()
+{
+ if (!Running) return;
+ if (CPU == 0) return Run9();
+ else return Run7();
+}
+
+void DSi_NDMA::Run9()
+{
+ if (NDS::ARM9Timestamp >= NDS::ARM9Target) return;
+
+ Executing = true;
+
+ // add NS penalty for first accesses in burst
+ bool burststart = (Running == 2);
+ Running = 1;
+
+ s32 unitcycles;
+ //s32 lastcycles = cycles;
+
+ bool dofill = ((Cnt >> 13) & 0x3) == 3;
+
+ 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);
+
+ if (dofill)
+ DSi::ARM9Write32(CurDstAddr, FillData);
+ else
+ DSi::ARM9Write32(CurDstAddr, DSi::ARM9Read32(CurSrcAddr));
+
+ CurSrcAddr += SrcAddrInc<<2;
+ CurDstAddr += DstAddrInc<<2;
+ IterCount--;
+ RemCount--;
+ TotalRemCount--;
+
+ if (NDS::ARM9Timestamp >= NDS::ARM9Target) break;
+ }
+
+ Executing = false;
+ Stall = false;
+
+ if (RemCount)
+ {
+ if (IterCount == 0)
+ {
+ Running = 0;
+ NDS::ResumeCPU(0, 1<<(Num+4));
+
+ //if (StartMode == 0x07)
+ // GPU3D::CheckFIFODMA();
+ }
+
+ return;
+ }
+
+ if ((StartMode & 0x1F) == 0x10) // CHECKME
+ Cnt &= ~(1<<31);
+ else if (!(Cnt & (1<<29)))
+ {
+ if (TotalRemCount == 0)
+ Cnt &= ~(1<<31);
+ }
+
+ if (Cnt & (1<<30))
+ NDS::SetIRQ(0, NDS::IRQ_DSi_NDMA0 + Num);
+
+ Running = 0;
+ InProgress = false;
+ NDS::ResumeCPU(0, 1<<(Num+4));
+}
+
+void DSi_NDMA::Run7()
+{
+ if (NDS::ARM7Timestamp >= NDS::ARM7Target) return;
+
+ Executing = true;
+
+ // add NS penalty for first accesses in burst
+ bool burststart = (Running == 2);
+ Running = 1;
+
+ s32 unitcycles;
+ //s32 lastcycles = cycles;
+
+ bool dofill = ((Cnt >> 13) & 0x3) == 3;
+
+ 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;
+
+ if (dofill)
+ DSi::ARM7Write32(CurDstAddr, FillData);
+ else
+ DSi::ARM7Write32(CurDstAddr, DSi::ARM7Read32(CurSrcAddr));
+
+ CurSrcAddr += SrcAddrInc<<2;
+ CurDstAddr += DstAddrInc<<2;
+ IterCount--;
+ RemCount--;
+
+ if (NDS::ARM7Timestamp >= NDS::ARM7Target) break;
+ }
+
+ Executing = false;
+ Stall = false;
+
+ if (RemCount)
+ {
+ if (IterCount == 0)
+ {
+ Running = 0;
+ NDS::ResumeCPU(1, 1<<(Num+4));
+ }
+
+ return;
+ }
+
+ if ((StartMode & 0x1F) == 0x10) // CHECKME
+ Cnt &= ~(1<<31);
+ else if (!(Cnt & (1<<29)))
+ {
+ if (TotalRemCount == 0)
+ Cnt &= ~(1<<31);
+ }
+
+ if (Cnt & (1<<30))
+ NDS::SetIRQ(1, NDS::IRQ_DSi_NDMA0 + Num);
+
+ Running = 0;
+ InProgress = false;
+ NDS::ResumeCPU(1, 1<<(Num+4));
+}
diff --git a/src/DSi_NDMA.h b/src/DSi_NDMA.h
index 6661652..d7b7483 100644
--- a/src/DSi_NDMA.h
+++ b/src/DSi_NDMA.h
@@ -19,6 +19,78 @@
#ifndef DSI_NDMA_H
#define DSI_NDMA_H
-//
+#include "types.h"
+
+class DSi_NDMA
+{
+public:
+ DSi_NDMA(u32 cpu, u32 num);
+ ~DSi_NDMA();
+
+ void Reset();
+
+ void DoSavestate(Savestate* file);
+
+ void WriteCnt(u32 val);
+ void Start();
+
+ void Run();
+
+ void Run9();
+ void Run7();
+
+ bool IsInMode(u32 mode)
+ {
+ return ((mode == StartMode) && (Cnt & 0x80000000));
+ }
+
+ bool IsRunning() { return Running!=0; }
+
+ void StartIfNeeded(u32 mode)
+ {
+ if ((mode == StartMode) && (Cnt & 0x80000000))
+ Start();
+ }
+
+ void StopIfNeeded(u32 mode)
+ {
+ if (mode == StartMode)
+ Cnt &= ~0x80000000;
+ }
+
+ void StallIfRunning()
+ {
+ if (Executing) Stall = true;
+ }
+
+ u32 SrcAddr;
+ u32 DstAddr;
+ u32 TotalLength; // total length, when transferring multiple blocks
+ u32 BlockLength; // length of one transfer
+ u32 SubblockTimer; // optional delay between subblocks (only in round-robin mode)
+ u32 FillData;
+ u32 Cnt;
+
+private:
+ u32 CPU, Num;
+
+ u32 StartMode;
+ u32 CurSrcAddr;
+ u32 CurDstAddr;
+ u32 SubblockLength; // length transferred per run when delay is used
+ u32 RemCount;
+ u32 IterCount;
+ u32 TotalRemCount;
+ u32 SrcAddrInc;
+ u32 DstAddrInc;
+
+ u32 Running;
+ bool InProgress;
+
+ bool Executing;
+ bool Stall;
+
+ bool IsGXFIFODMA;
+};
#endif // DSI_NDMA_H
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 414f87c..e20f62f 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -827,6 +827,7 @@ u32 RunFrame()
if (!(CPUStop & 0x80000000)) DMAs[1]->Run();
if (!(CPUStop & 0x80000000)) DMAs[2]->Run();
if (!(CPUStop & 0x80000000)) DMAs[3]->Run();
+ DSi::RunNDMAs(0);
}
else
{
@@ -849,6 +850,7 @@ u32 RunFrame()
DMAs[5]->Run();
DMAs[6]->Run();
DMAs[7]->Run();
+ DSi::RunNDMAs(1);
}
else
{
@@ -1153,6 +1155,7 @@ void GXFIFOStall()
DMAs[1]->StallIfRunning();
DMAs[2]->StallIfRunning();
DMAs[3]->StallIfRunning();
+ DSi::StallNDMAs();
}
}
@@ -1367,6 +1370,7 @@ bool DMAsRunning(u32 cpu)
if (DMAs[cpu+1]->IsRunning()) return true;
if (DMAs[cpu+2]->IsRunning()) return true;
if (DMAs[cpu+3]->IsRunning()) return true;
+ if (DSi::NDMAsRunning(cpu>>2)) return true;
return false;
}
diff --git a/src/NDS.h b/src/NDS.h
index f87ffed..850e829 100644
--- a/src/NDS.h
+++ b/src/NDS.h
@@ -101,7 +101,7 @@ enum
IRQ2_DSi_GPIO18_0 = 0,
IRQ2_DSi_GPIO18_1,
IRQ2_DSi_GPIO18_2,
- IRQ2_DSi_Unused35,
+ IRQ2_DSi_Unused3,
IRQ2_DSi_GPIO33_0,
IRQ2_DSi_Headphone,
IRQ2_DSi_PowerButton,
@@ -138,7 +138,6 @@ extern u64 ARM9Timestamp, ARM9Target;
extern u64 ARM7Timestamp, ARM7Target;
extern u32 ARM9ClockShift;
-// hax
extern u32 IME[2];
extern u32 IE[2];
extern u32 IF[2];
@@ -146,6 +145,8 @@ extern u32 IE2;
extern u32 IF2;
extern Timer Timers[8];
+extern u32 CPUStop;
+
extern u16 PowerControl9;
extern u16 ExMemCnt[2];