mirror of
https://github.com/melonDS-emu/melonDS.git
synced 2025-07-24 14:49:53 -06:00
tremble upon the NDMA implementation
that doesn't do much beyond getting stuck
This commit is contained in:
@ -20,15 +20,9 @@
|
|||||||
#include "NDS.h"
|
#include "NDS.h"
|
||||||
#include "DSi.h"
|
#include "DSi.h"
|
||||||
#include "DMA.h"
|
#include "DMA.h"
|
||||||
#include "NDSCart.h"
|
|
||||||
#include "GPU.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
|
// DMA TIMINGS
|
||||||
//
|
//
|
||||||
|
171
src/DSi.cpp
171
src/DSi.cpp
@ -25,6 +25,7 @@
|
|||||||
#include "sha1/sha1.h"
|
#include "sha1/sha1.h"
|
||||||
#include "Platform.h"
|
#include "Platform.h"
|
||||||
|
|
||||||
|
#include "DSi_NDMA.h"
|
||||||
#include "DSi_I2C.h"
|
#include "DSi_I2C.h"
|
||||||
#include "DSi_SD.h"
|
#include "DSi_SD.h"
|
||||||
|
|
||||||
@ -57,6 +58,9 @@ u32 NWRAMStart[2][3];
|
|||||||
u32 NWRAMEnd[2][3];
|
u32 NWRAMEnd[2][3];
|
||||||
u32 NWRAMMask[2][3];
|
u32 NWRAMMask[2][3];
|
||||||
|
|
||||||
|
u32 NDMACnt[2];
|
||||||
|
DSi_NDMA* NDMAs[8];
|
||||||
|
|
||||||
DSi_SDHost* SDMMC;
|
DSi_SDHost* SDMMC;
|
||||||
DSi_SDHost* SDIO;
|
DSi_SDHost* SDIO;
|
||||||
|
|
||||||
@ -68,6 +72,15 @@ bool Init()
|
|||||||
{
|
{
|
||||||
if (!DSi_I2C::Init()) return false;
|
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);
|
SDMMC = new DSi_SDHost(0);
|
||||||
SDIO = new DSi_SDHost(1);
|
SDIO = new DSi_SDHost(1);
|
||||||
|
|
||||||
@ -78,6 +91,8 @@ void DeInit()
|
|||||||
{
|
{
|
||||||
DSi_I2C::DeInit();
|
DSi_I2C::DeInit();
|
||||||
|
|
||||||
|
for (int i = 0; i < 8; i++) delete NDMAs[i];
|
||||||
|
|
||||||
delete SDMMC;
|
delete SDMMC;
|
||||||
delete SDIO;
|
delete SDIO;
|
||||||
}
|
}
|
||||||
@ -91,6 +106,9 @@ void Reset()
|
|||||||
NDS::ARM9->JumpTo(BootAddr[0]);
|
NDS::ARM9->JumpTo(BootAddr[0]);
|
||||||
NDS::ARM7->JumpTo(BootAddr[1]);
|
NDS::ARM7->JumpTo(BootAddr[1]);
|
||||||
|
|
||||||
|
NDMACnt[0] = 0; NDMACnt[1] = 0;
|
||||||
|
for (int i = 0; i < 8; i++) NDMAs[i]->Reset();
|
||||||
|
|
||||||
DSi_I2C::Reset();
|
DSi_I2C::Reset();
|
||||||
|
|
||||||
SDMMC->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
|
// new WRAM mapping
|
||||||
// TODO: find out what happens upon overlapping slots!!
|
// TODO: find out what happens upon overlapping slots!!
|
||||||
|
|
||||||
@ -872,6 +924,36 @@ u32 ARM9IORead32(u32 addr)
|
|||||||
switch (addr)
|
switch (addr)
|
||||||
{
|
{
|
||||||
case 0x04004010: return 1; // todo
|
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);
|
return NDS::ARM9IORead32(addr);
|
||||||
@ -899,6 +981,35 @@ void ARM9IOWrite32(u32 addr, u32 val)
|
|||||||
{
|
{
|
||||||
switch (addr)
|
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);
|
return NDS::ARM9IOWrite32(addr, val);
|
||||||
@ -950,6 +1061,36 @@ u32 ARM7IORead32(u32 addr)
|
|||||||
case 0x0400021C: return NDS::IF2;
|
case 0x0400021C: return NDS::IF2;
|
||||||
|
|
||||||
case 0x04004008: return 0x80000000; // HAX
|
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)
|
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 0x04000218: NDS::IE2 = (val & 0x7FF7); NDS::UpdateIRQ(1); return;
|
||||||
case 0x0400021C: NDS::IF2 &= ~(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)
|
if (addr >= 0x04004800 && addr < 0x04004A00)
|
||||||
|
@ -38,6 +38,10 @@ void Reset();
|
|||||||
bool LoadBIOS();
|
bool LoadBIOS();
|
||||||
bool LoadNAND();
|
bool LoadNAND();
|
||||||
|
|
||||||
|
void RunNDMAs(u32 cpu);
|
||||||
|
void StallNDMAs();
|
||||||
|
bool NDMAsRunning(u32 cpu);
|
||||||
|
|
||||||
void MapNWRAM_A(u32 num, u8 val);
|
void MapNWRAM_A(u32 num, u8 val);
|
||||||
void MapNWRAM_B(u32 num, u8 val);
|
void MapNWRAM_B(u32 num, u8 val);
|
||||||
void MapNWRAM_C(u32 num, u8 val);
|
void MapNWRAM_C(u32 num, u8 val);
|
||||||
|
301
src/DSi_NDMA.cpp
301
src/DSi_NDMA.cpp
@ -15,3 +15,304 @@
|
|||||||
You should have received a copy of the GNU General Public License along
|
You should have received a copy of the GNU General Public License along
|
||||||
with melonDS. If not, see http://www.gnu.org/licenses/.
|
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));
|
||||||
|
}
|
||||||
|
@ -19,6 +19,78 @@
|
|||||||
#ifndef DSI_NDMA_H
|
#ifndef DSI_NDMA_H
|
||||||
#define 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
|
#endif // DSI_NDMA_H
|
||||||
|
@ -827,6 +827,7 @@ u32 RunFrame()
|
|||||||
if (!(CPUStop & 0x80000000)) DMAs[1]->Run();
|
if (!(CPUStop & 0x80000000)) DMAs[1]->Run();
|
||||||
if (!(CPUStop & 0x80000000)) DMAs[2]->Run();
|
if (!(CPUStop & 0x80000000)) DMAs[2]->Run();
|
||||||
if (!(CPUStop & 0x80000000)) DMAs[3]->Run();
|
if (!(CPUStop & 0x80000000)) DMAs[3]->Run();
|
||||||
|
DSi::RunNDMAs(0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -849,6 +850,7 @@ u32 RunFrame()
|
|||||||
DMAs[5]->Run();
|
DMAs[5]->Run();
|
||||||
DMAs[6]->Run();
|
DMAs[6]->Run();
|
||||||
DMAs[7]->Run();
|
DMAs[7]->Run();
|
||||||
|
DSi::RunNDMAs(1);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1153,6 +1155,7 @@ void GXFIFOStall()
|
|||||||
DMAs[1]->StallIfRunning();
|
DMAs[1]->StallIfRunning();
|
||||||
DMAs[2]->StallIfRunning();
|
DMAs[2]->StallIfRunning();
|
||||||
DMAs[3]->StallIfRunning();
|
DMAs[3]->StallIfRunning();
|
||||||
|
DSi::StallNDMAs();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1367,6 +1370,7 @@ bool DMAsRunning(u32 cpu)
|
|||||||
if (DMAs[cpu+1]->IsRunning()) return true;
|
if (DMAs[cpu+1]->IsRunning()) return true;
|
||||||
if (DMAs[cpu+2]->IsRunning()) return true;
|
if (DMAs[cpu+2]->IsRunning()) return true;
|
||||||
if (DMAs[cpu+3]->IsRunning()) return true;
|
if (DMAs[cpu+3]->IsRunning()) return true;
|
||||||
|
if (DSi::NDMAsRunning(cpu>>2)) return true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,7 +101,7 @@ enum
|
|||||||
IRQ2_DSi_GPIO18_0 = 0,
|
IRQ2_DSi_GPIO18_0 = 0,
|
||||||
IRQ2_DSi_GPIO18_1,
|
IRQ2_DSi_GPIO18_1,
|
||||||
IRQ2_DSi_GPIO18_2,
|
IRQ2_DSi_GPIO18_2,
|
||||||
IRQ2_DSi_Unused35,
|
IRQ2_DSi_Unused3,
|
||||||
IRQ2_DSi_GPIO33_0,
|
IRQ2_DSi_GPIO33_0,
|
||||||
IRQ2_DSi_Headphone,
|
IRQ2_DSi_Headphone,
|
||||||
IRQ2_DSi_PowerButton,
|
IRQ2_DSi_PowerButton,
|
||||||
@ -138,7 +138,6 @@ extern u64 ARM9Timestamp, ARM9Target;
|
|||||||
extern u64 ARM7Timestamp, ARM7Target;
|
extern u64 ARM7Timestamp, ARM7Target;
|
||||||
extern u32 ARM9ClockShift;
|
extern u32 ARM9ClockShift;
|
||||||
|
|
||||||
// hax
|
|
||||||
extern u32 IME[2];
|
extern u32 IME[2];
|
||||||
extern u32 IE[2];
|
extern u32 IE[2];
|
||||||
extern u32 IF[2];
|
extern u32 IF[2];
|
||||||
@ -146,6 +145,8 @@ extern u32 IE2;
|
|||||||
extern u32 IF2;
|
extern u32 IF2;
|
||||||
extern Timer Timers[8];
|
extern Timer Timers[8];
|
||||||
|
|
||||||
|
extern u32 CPUStop;
|
||||||
|
|
||||||
extern u16 PowerControl9;
|
extern u16 PowerControl9;
|
||||||
|
|
||||||
extern u16 ExMemCnt[2];
|
extern u16 ExMemCnt[2];
|
||||||
|
Reference in New Issue
Block a user