aboutsummaryrefslogtreecommitdiff
path: root/src/NDS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/NDS.cpp')
-rw-r--r--src/NDS.cpp1228
1 files changed, 1072 insertions, 156 deletions
diff --git a/src/NDS.cpp b/src/NDS.cpp
index 34eccf7..98c2924 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -1,5 +1,5 @@
/*
- Copyright 2016-2017 StapleButter
+ Copyright 2016-2019 StapleButter
This file is part of melonDS.
@@ -21,7 +21,6 @@
#include "Config.h"
#include "NDS.h"
#include "ARM.h"
-#include "CP15.h"
#include "NDSCart.h"
#include "DMA.h"
#include "FIFO.h"
@@ -31,23 +30,55 @@
#include "RTC.h"
#include "Wifi.h"
#include "Platform.h"
+#include "melon_fopen.h"
namespace NDS
{
-// TODO LIST
-// * stick all the variables in a big structure?
-// would make it easier to deal with savestates
+#ifdef DEBUG_CHECK_DESYNC
+u64 dbg_CyclesSys;
+u64 dbg_CyclesARM9;
+u64 dbg_CyclesTimer9;
+u64 dbg_CyclesARM7;
+u64 dbg_CyclesTimer7;
+#endif
+
+// timing notes
+//
+// * this implementation is technically wrong for VRAM
+// each bank is considered a separate region
+// but this would only matter in specific VRAM->VRAM DMA transfers or
+// when running code in VRAM, which is way unlikely
+//
+// bus/basedelay/nspenalty
+//
+// bus types:
+// * 0 / 32-bit: nothing special
+// * 1 / 16-bit: 32-bit accesses split into two 16-bit accesses, second is always sequential
+// * 2 / 8-bit/GBARAM: (presumably) split into multiple 8-bit accesses?
+// * 3 / ARM9 internal: cache/TCM
+//
+// ARM9 always gets 3c nonseq penalty when using the bus (except for mainRAM where the penalty is 7c)
+//
+// ARM7 only gets nonseq penalty when accessing mainRAM (7c as for ARM9)
+//
+// timings for GBA slot and wifi are set up at runtime
+
+u8 ARM9MemTimings[0x40000][4];
+u8 ARM7MemTimings[0x20000][4];
+
+ARMv5* ARM9;
+ARMv4* ARM7;
+
+u32 NumFrames;
+u64 SysClockCycles;
+u64 LastSysClockCycles;
+u32 FrameSysClockCycles;
-ARM* ARM9;
-ARM* ARM7;
-
-/*s32 ARM9Cycles, ARM7Cycles;
-s32 CompensatedCycles;
-s32 SchedCycles;*/
s32 CurIterationCycles;
s32 ARM7Offset;
+int CurCPU;
SchedEvent SchedList[Event_MAX];
u32 SchedListMask;
@@ -57,7 +88,7 @@ u32 CPUStop;
u8 ARM9BIOS[0x1000];
u8 ARM7BIOS[0x4000];
-u8 MainRAM[0x400000];
+u8 MainRAM[MAIN_RAM_SIZE];
u8 SharedWRAM[0x8000];
u8 WRAMCnt;
@@ -82,6 +113,8 @@ u8 PostFlag7;
u16 PowerControl9;
u16 PowerControl7;
+u16 WifiWaitCnt;
+
u16 ARM7BIOSProt;
Timer Timers[8];
@@ -112,10 +145,17 @@ u16 RCnt;
bool Running;
+void DivDone(u32 param);
+void SqrtDone(u32 param);
+void RunTimer(u32 tid, s32 cycles);
+void SetWifiWaitCnt(u16 val);
+void SetGBASlotTimings();
+
+
bool Init()
{
- ARM9 = new ARM(0);
- ARM7 = new ARM(1);
+ ARM9 = new ARMv5();
+ ARM7 = new ARMv4();
DMAs[0] = new DMA(0, 0);
DMAs[1] = new DMA(0, 1);
@@ -159,6 +199,101 @@ void DeInit()
}
+void SetARM9RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq)
+{
+ addrstart >>= 14;
+ addrend >>= 14;
+
+ if (addrend == 0x3FFFF) addrend++;
+
+ int N16, S16, N32, S32;
+ N16 = nonseq;
+ S16 = seq;
+ if (buswidth == 16)
+ {
+ N32 = N16 + S16;
+ S32 = S16 + S16;
+ }
+ else
+ {
+ N32 = N16;
+ S32 = S16;
+ }
+
+ for (u32 i = addrstart; i < addrend; i++)
+ {
+ ARM9MemTimings[i][0] = N16;
+ ARM9MemTimings[i][1] = S16;
+ ARM9MemTimings[i][2] = N32;
+ ARM9MemTimings[i][3] = S32;
+ }
+
+ ARM9->UpdateRegionTimings(addrstart<<14, addrend<<14);
+}
+
+void SetARM7RegionTimings(u32 addrstart, u32 addrend, int buswidth, int nonseq, int seq)
+{
+ addrstart >>= 15;
+ addrend >>= 15;
+
+ if (addrend == 0x1FFFF) addrend++;
+
+ int N16, S16, N32, S32;
+ N16 = nonseq;
+ S16 = seq;
+ if (buswidth == 16)
+ {
+ N32 = N16 + S16;
+ S32 = S16 + S16;
+ }
+ else
+ {
+ N32 = N16;
+ S32 = S16;
+ }
+
+ for (u32 i = addrstart; i < addrend; i++)
+ {
+ ARM7MemTimings[i][0] = N16;
+ ARM7MemTimings[i][1] = S16;
+ ARM7MemTimings[i][2] = N32;
+ ARM7MemTimings[i][3] = S32;
+ }
+}
+
+void InitTimings()
+{
+ // TODO, eventually:
+ // VRAM is initially unmapped. The timings should be those of void regions.
+ // 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).
+
+ // ARM9
+
+ SetARM9RegionTimings(0x00000000, 0xFFFFFFFF, 32, 1 + 3, 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
+
+ // ARM7
+
+ SetARM7RegionTimings(0x00000000, 0xFFFFFFFF, 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
+
+ // handled later: GBA slot, wifi
+}
+
void SetupDirectBoot()
{
u32 bootparams[8];
@@ -189,15 +324,15 @@ void SetupDirectBoot()
ARM9Write32(0x027FFE00+i, tmp);
}
- ARM9Write32(0x027FF800, 0x00001FC2);
- ARM9Write32(0x027FF804, 0x00001FC2);
+ ARM9Write32(0x027FF800, NDSCart::CartID);
+ ARM9Write32(0x027FF804, NDSCart::CartID);
ARM9Write16(0x027FF808, *(u16*)&NDSCart::CartROM[0x15E]);
ARM9Write16(0x027FF80A, *(u16*)&NDSCart::CartROM[0x6C]);
ARM9Write16(0x027FF850, 0x5835);
- ARM9Write32(0x027FFC00, 0x00001FC2);
- ARM9Write32(0x027FFC04, 0x00001FC2);
+ ARM9Write32(0x027FFC00, NDSCart::CartID);
+ ARM9Write32(0x027FFC04, NDSCart::CartID);
ARM9Write16(0x027FFC08, *(u16*)&NDSCart::CartROM[0x15E]);
ARM9Write16(0x027FFC0A, *(u16*)&NDSCart::CartROM[0x6C]);
@@ -205,9 +340,9 @@ void SetupDirectBoot()
ARM9Write16(0x027FFC30, 0xFFFF);
ARM9Write16(0x027FFC40, 0x0001);
- CP15::Write(0x910, 0x0300000A);
- CP15::Write(0x911, 0x00000020);
- CP15::Write(0x100, 0x00050000);
+ ARM9->CP15Write(0x910, 0x0300000A);
+ ARM9->CP15Write(0x911, 0x00000020);
+ ARM9->CP15Write(0x100, 0x00050000);
ARM9->R[12] = bootparams[1];
ARM9->R[13] = 0x03002F7C;
@@ -233,8 +368,12 @@ void SetupDirectBoot()
// checkme
RCnt = 0x8000;
+ NDSCart::SPICnt = 0x8000;
+
SPU::SetBias(0x200);
+ SetWifiWaitCnt(0x0030);
+
ARM7BIOSProt = 0x1204;
SPI_Firmware::SetupDirectBoot();
@@ -245,7 +384,18 @@ void Reset()
FILE* f;
u32 i;
- f = Config::GetConfigFile("bios9.bin", "rb");
+#ifdef DEBUG_CHECK_DESYNC
+ dbg_CyclesSys = 0;
+ dbg_CyclesARM9 = 0;
+ dbg_CyclesTimer9 = 0;
+ dbg_CyclesARM7 = 0;
+ dbg_CyclesTimer7 = 0;
+#endif // DEBUG_CHECK_DESYNC
+
+ SysClockCycles = 0;
+ LastSysClockCycles = 0;
+
+ f = melon_fopen_local("bios9.bin", "rb");
if (!f)
{
printf("ARM9 BIOS not found\n");
@@ -262,7 +412,7 @@ void Reset()
fclose(f);
}
- f = Config::GetConfigFile("bios7.bin", "rb");
+ f = melon_fopen_local("bios7.bin", "rb");
if (!f)
{
printf("ARM7 BIOS not found\n");
@@ -279,7 +429,12 @@ void Reset()
fclose(f);
}
- memset(MainRAM, 0, 0x400000);
+ ARM9->SetClockShift(1);
+ ARM7->SetClockShift(0);
+
+ InitTimings();
+
+ memset(MainRAM, 0, MAIN_RAM_SIZE);
memset(SharedWRAM, 0, 0x8000);
memset(ARM7WRAM, 0, 0x10000);
@@ -289,6 +444,7 @@ void Reset()
ExMemCnt[1] = 0;
memset(ROMSeed0, 0, 2*8);
memset(ROMSeed1, 0, 2*8);
+ SetGBASlotTimings();
IME[0] = 0;
IE[0] = 0;
@@ -302,6 +458,9 @@ void Reset()
PowerControl9 = 0x0001;
PowerControl7 = 0x0001;
+ WifiWaitCnt = 0xFFFF; // temp
+ SetWifiWaitCnt(0);
+
ARM7BIOSProt = 0;
IPCSync9 = 0;
@@ -316,7 +475,6 @@ void Reset()
ARM9->Reset();
ARM7->Reset();
- CP15::Reset();
CPUStop = 0;
@@ -354,9 +512,198 @@ void Stop()
SPU::Stop();
}
-bool LoadROM(const char* path, bool direct)
+bool DoSavestate_Scheduler(Savestate* file)
{
- if (NDSCart::LoadROM(path, direct))
+ // this is a bit of a hack
+ // but uh, your local coder realized that the scheduler list contains function pointers
+ // and that storing those as-is is not a very good idea
+ // unless you want it to crash and burn
+
+ // this is the solution your local coder came up with.
+ // it's gross but I think it's the best solution for this problem.
+ // just remember to add here if you add more event callbacks, kay?
+ // atleast until we come up with something more elegant.
+
+ void (*eventfuncs[])(u32) =
+ {
+ GPU::StartScanline, GPU::StartHBlank, GPU::FinishFrame,
+ SPU::Mix,
+ Wifi::USTimer,
+
+ GPU::DisplayFIFO,
+ NDSCart::ROMPrepareData, NDSCart::ROMEndTransfer,
+ NDSCart::SPITransferDone,
+ SPI::TransferDone,
+ DivDone,
+ SqrtDone,
+
+ NULL
+ };
+
+ int len = Event_MAX;
+ if (file->Saving)
+ {
+ for (int i = 0; i < len; i++)
+ {
+ SchedEvent* evt = &SchedList[i];
+
+ u32 funcid = -1;
+ if (evt->Func)
+ {
+ for (int j = 0; eventfuncs[j]; j++)
+ {
+ if (evt->Func == eventfuncs[j])
+ {
+ funcid = j;
+ break;
+ }
+ }
+ if (funcid == -1)
+ {
+ printf("savestate: VERY BAD!!!!! FUNCTION POINTER FOR EVENT %d NOT IN HACKY LIST. CANNOT SAVE. SMACK STAPLEBUTTER.\n", i);
+ return false;
+ }
+ }
+
+ file->Var32(&funcid);
+ file->Var32((u32*)&evt->WaitCycles);
+ file->Var32(&evt->Param);
+ }
+ }
+ else
+ {
+ for (int i = 0; i < len; i++)
+ {
+ SchedEvent* evt = &SchedList[i];
+
+ u32 funcid;
+ file->Var32(&funcid);
+
+ if (funcid != -1)
+ {
+ for (int j = 0; ; j++)
+ {
+ if (!eventfuncs[j])
+ {
+ printf("savestate: VERY BAD!!!!!! EVENT FUNCTION POINTER ID %d IS OUT OF RANGE. HAX?????\n", j);
+ return false;
+ }
+ if (j == funcid) break;
+ }
+
+ evt->Func = eventfuncs[funcid];
+ }
+ else
+ evt->Func = NULL;
+
+ file->Var32((u32*)&evt->WaitCycles);
+ file->Var32(&evt->Param);
+ }
+ }
+
+ return true;
+}
+
+bool DoSavestate(Savestate* file)
+{
+ file->Section("NDSG");
+
+ file->VarArray(MainRAM, 0x400000);
+ file->VarArray(SharedWRAM, 0x8000);
+ file->VarArray(ARM7WRAM, 0x10000);
+
+ file->VarArray(ExMemCnt, 2*sizeof(u16));
+ file->VarArray(ROMSeed0, 2*8);
+ file->VarArray(ROMSeed1, 2*8);
+
+ file->Var16(&WifiWaitCnt);
+
+ file->VarArray(IME, 2*sizeof(u32));
+ file->VarArray(IE, 2*sizeof(u32));
+ file->VarArray(IF, 2*sizeof(u32));
+
+ file->Var8(&PostFlag9);
+ file->Var8(&PostFlag7);
+ file->Var16(&PowerControl9);
+ file->Var16(&PowerControl7);
+
+ file->Var16(&ARM7BIOSProt);
+
+ file->Var16(&IPCSync9);
+ file->Var16(&IPCSync7);
+ file->Var16(&IPCFIFOCnt9);
+ file->Var16(&IPCFIFOCnt7);
+ IPCFIFO9->DoSavestate(file);
+ IPCFIFO7->DoSavestate(file);
+
+ file->Var16(&DivCnt);
+ file->Var16(&SqrtCnt);
+
+ file->Var32(&CPUStop);
+
+ for (int i = 0; i < 8; i++)
+ {
+ Timer* timer = &Timers[i];
+
+ file->Var16(&timer->Reload);
+ file->Var16(&timer->Cnt);
+ file->Var32(&timer->Counter);
+ file->Var32(&timer->CycleShift);
+ }
+ file->VarArray(TimerCheckMask, 2*sizeof(u8));
+
+ file->VarArray(DMA9Fill, 4*sizeof(u32));
+
+ if (!DoSavestate_Scheduler(file)) return false;
+ file->Var32(&SchedListMask);
+ file->Var32((u32*)&CurIterationCycles);
+ file->Var32((u32*)&ARM7Offset);
+
+ // TODO: save KeyInput????
+ file->Var16(&KeyCnt);
+ file->Var16(&RCnt);
+
+
+ for (int i = 0; i < 8; i++)
+ DMAs[i]->DoSavestate(file);
+
+ file->Var8(&WRAMCnt);
+
+ if (!file->Saving)
+ {
+ // 'dept of redundancy dept'
+ // but we do need to update the mappings
+ MapSharedWRAM(WRAMCnt);
+ }
+
+ if (!file->Saving)
+ {
+ GPU::DisplaySwap(PowerControl9>>15);
+
+ InitTimings();
+ SetGBASlotTimings();
+
+ u16 tmp = WifiWaitCnt;
+ WifiWaitCnt = 0xFFFF;
+ SetWifiWaitCnt(tmp); // force timing table update
+ }
+
+ ARM9->DoSavestate(file);
+ ARM7->DoSavestate(file);
+
+ NDSCart::DoSavestate(file);
+ GPU::DoSavestate(file);
+ SPU::DoSavestate(file);
+ SPI::DoSavestate(file);
+ RTC::DoSavestate(file);
+ Wifi::DoSavestate(file);
+
+ return true;
+}
+
+bool LoadROM(const char* path, const char* sram, bool direct)
+{
+ if (NDSCart::LoadROM(path, sram, direct))
{
Running = true;
return true;
@@ -374,6 +721,12 @@ void LoadBIOS()
Running = true;
}
+void RelocateSave(const char* path, bool write)
+{
+ printf("SRAM: relocating to %s (write=%s)\n", path, write?"true":"false");
+ NDSCart::RelocateSave(path, write);
+}
+
void CalcIterationCycles()
{
@@ -408,64 +761,142 @@ void RunSystem(s32 cycles)
u32 RunFrame()
{
+ FrameSysClockCycles = 0;
+
if (!Running) return 263; // dorp
+ if (CPUStop & 0x40000000) return 263;
GPU::StartFrame();
while (Running && GPU::TotalScanlines==0)
{
- s32 ndscyclestorun;
- s32 ndscycles = 0;
-
// TODO: give it some margin, so it can directly do 17 cycles instead of 16 then 1
CalcIterationCycles();
+ s32 arm9cycles;
- if (CPUStop & 0xFFFF)
+ if (CPUStop & 0x80000000)
+ {
+ // GXFIFO stall
+ // we just run the GPU and the timers.
+ // the rest of the hardware is driven by the event scheduler.
+
+ arm9cycles = GPU3D::CyclesToRunFor();
+ arm9cycles = std::min(CurIterationCycles, arm9cycles);
+ RunTightTimers(0, arm9cycles);
+
+#ifdef DEBUG_CHECK_DESYNC
+ dbg_CyclesARM9 += arm9cycles;
+#endif // DEBUG_CHECK_DESYNC
+ }
+ else if (CPUStop & 0x0FFF)
{
s32 cycles = CurIterationCycles;
+
cycles = DMAs[0]->Run(cycles);
- if (cycles > 0) cycles = DMAs[1]->Run(cycles);
- if (cycles > 0) cycles = DMAs[2]->Run(cycles);
- if (cycles > 0) cycles = DMAs[3]->Run(cycles);
- ndscyclestorun = CurIterationCycles - cycles;
+ if (cycles > 0 && !(CPUStop & 0x80000000))
+ cycles = DMAs[1]->Run(cycles);
+ if (cycles > 0 && !(CPUStop & 0x80000000))
+ cycles = DMAs[2]->Run(cycles);
+ if (cycles > 0 && !(CPUStop & 0x80000000))
+ cycles = DMAs[3]->Run(cycles);
+
+ arm9cycles = CurIterationCycles - cycles;
}
else
{
ARM9->CyclesToRun = CurIterationCycles << 1;
- ARM9->Execute();
- ndscyclestorun = ARM9->Cycles >> 1;
+ CurCPU = 1; ARM9->Execute(); CurCPU = 0;
+ arm9cycles = ARM9->Cycles >> 1;
+ RunTightTimers(0, arm9cycles);
}
- if (CPUStop & 0xFFFF0000)
+ RunLooseTimers(0, arm9cycles);
+ GPU3D::Run(arm9cycles);
+
+ s32 ndscyclestorun = arm9cycles;
+
+ // ARM7Offset > ndscyclestorun means we are too far ahead of the ARM9
+ if (ARM7Offset > ndscyclestorun)
+ {
+ ARM7Offset -= ndscyclestorun;
+ }
+ else
+ if (CPUStop & 0x0FFF0000)
{
s32 cycles = ndscyclestorun - ARM7Offset;
+
cycles = DMAs[4]->Run(cycles);
- if (cycles > 0) cycles = DMAs[5]->Run(cycles);
- if (cycles > 0) cycles = DMAs[6]->Run(cycles);
- if (cycles > 0) cycles = DMAs[7]->Run(cycles);
+ if (cycles > 0)
+ cycles = DMAs[5]->Run(cycles);
+ if (cycles > 0)
+ cycles = DMAs[6]->Run(cycles);
+ if (cycles > 0)
+ cycles = DMAs[7]->Run(cycles);
+
ARM7Offset = -cycles;
}
else
{
ARM7->CyclesToRun = ndscyclestorun - ARM7Offset;
- ARM7->Execute();
+ CurCPU = 2; ARM7->Execute(); CurCPU = 0;
ARM7Offset = ARM7->Cycles - ARM7->CyclesToRun;
+ RunTightTimers(1, ARM7->Cycles);
}
+#ifdef DEBUG_CHECK_DESYNC
+ dbg_CyclesSys += ndscyclestorun;
+#endif // DEBUG_CHECK_DESYNC
+
+ RunLooseTimers(1, ndscyclestorun);
RunSystem(ndscyclestorun);
- //GPU3D::Run(ndscyclestorun);
+
+ SysClockCycles += ndscyclestorun;
+ LastSysClockCycles += ndscyclestorun;
+ FrameSysClockCycles += ndscyclestorun;
+
+ if (CPUStop & 0x40000000)
+ {
+ // checkme: when is sleep mode effective?
+ //CancelEvent(Event_LCD);
+ //GPU::TotalScanlines = 263;
+ break;
+ }
}
+#ifdef DEBUG_CHECK_DESYNC
+ printf("[%08X%08X] ARM9=%ld timer9=%ld, ARM7=%ld timer7=%ld\n",
+ (u32)(dbg_CyclesSys>>32), (u32)dbg_CyclesSys,
+ dbg_CyclesARM9-dbg_CyclesSys,
+ dbg_CyclesTimer9-dbg_CyclesSys,
+ dbg_CyclesARM7-dbg_CyclesSys,
+ dbg_CyclesTimer7-dbg_CyclesSys);
+#endif
+
+ NumFrames++;
+
return GPU::TotalScanlines;
}
void Reschedule()
{
+ s32 oldcycles = CurIterationCycles;
CalcIterationCycles();
- ARM9->CyclesToRun = CurIterationCycles << 1;
- //ARM7->CyclesToRun = CurIterationCycles - ARM7Offset;
- //ARM7->CyclesToRun = (ARM9->Cycles >> 1) - ARM7->Cycles - ARM7Offset;
+ if (CurIterationCycles >= oldcycles)
+ {
+ CurIterationCycles = oldcycles;
+ return;
+ }
+
+ if (CurCPU == 0)
+ {
+ CurIterationCycles = oldcycles;
+ return;
+ }
+
+ if (CurCPU == 1) ARM9->CyclesToRun = CurIterationCycles << 1;
+ else if (CurCPU == 2) ARM7->CyclesToRun = CurIterationCycles - ARM7Offset;
+ // this is all. a reschedule shouldn't happen during DMA or GXFIFO stall.
}
void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 param)
@@ -478,8 +909,14 @@ void ScheduleEvent(u32 id, bool periodic, s32 delay, void (*func)(u32), u32 para
SchedEvent* evt = &SchedList[id];
- if (periodic) evt->WaitCycles += delay;
- else evt->WaitCycles = delay + (ARM9->Cycles >> 1);
+ if (periodic)
+ evt->WaitCycles += delay;
+ else
+ {
+ if (CurCPU == 1) evt->WaitCycles = delay + (ARM9->Cycles >> 1);
+ else if (CurCPU == 2) evt->WaitCycles = delay + ARM7->Cycles;
+ else evt->WaitCycles = delay;
+ }
evt->Func = func;
evt->Param = param;
@@ -525,6 +962,25 @@ void SetKeyMask(u32 mask)
KeyInput |= key_lo | (key_hi << 16);
}
+void SetLidClosed(bool closed)
+{
+ if (closed)
+ {
+ KeyInput |= (1<<23);
+ }
+ else
+ {
+ KeyInput &= ~(1<<23);
+ SetIRQ(1, IRQ_LidOpen);
+ CPUStop &= ~0x40000000;
+ }
+}
+
+void MicInputFrame(s16* data, int samples)
+{
+ return SPI_TSC::MicInputFrame(data, samples);
+}
+
void Halt()
{
@@ -570,6 +1026,49 @@ void MapSharedWRAM(u8 val)
}
+void SetWifiWaitCnt(u16 val)
+{
+ if (WifiWaitCnt == val) return;
+
+ 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);
+}
+
+void SetGBASlotTimings()
+{
+ int curcpu = (ExMemCnt[0] >> 7) & 0x1;
+
+ const int ntimings[4] = {10, 8, 6, 18};
+
+ u16 curcnt = ExMemCnt[curcpu];
+ int ramN = ntimings[curcnt & 0x3];
+ int romN = ntimings[(curcnt>>2) & 0x3];
+ int romS = (curcnt & 0x10) ? 4 : 6;
+
+ // TODO: PHI pin thing?
+
+ if (curcpu == 0)
+ {
+ SetARM9RegionTimings(0x08000000, 0x0A000000, 16, romN + 3, romS);
+ SetARM9RegionTimings(0x0A000000, 0x0B000000, 8, ramN + 3, ramN);
+
+ SetARM7RegionTimings(0x08000000, 0x0A000000, 32, 1, 1);
+ SetARM7RegionTimings(0x0A000000, 0x0B000000, 32, 1, 1);
+ }
+ else
+ {
+ SetARM9RegionTimings(0x08000000, 0x0A000000, 32, 1, 1);
+ SetARM9RegionTimings(0x0A000000, 0x0B000000, 32, 1, 1);
+
+ SetARM7RegionTimings(0x08000000, 0x0A000000, 16, romN, romS);
+ SetARM7RegionTimings(0x0A000000, 0x0B000000, 8, ramN, ramN);
+ }
+}
+
+
void SetIRQ(u32 cpu, u32 irq)
{
IF[cpu] |= (1 << irq);
@@ -614,21 +1113,172 @@ void ResumeCPU(u32 cpu, u32 mask)
CPUStop &= ~mask;
}
+void GXFIFOStall()
+{
+ if (CPUStop & 0x80000000) return;
+
+ CPUStop |= 0x80000000;
+
+ if (CurCPU == 1) ARM9->Halt(2);
+ else
+ {
+ DMAs[0]->StallIfRunning();
+ DMAs[1]->StallIfRunning();
+ DMAs[2]->StallIfRunning();
+ DMAs[3]->StallIfRunning();
+ }
+}
+
+void GXFIFOUnstall()
+{
+ CPUStop &= ~0x80000000;
+}
+
+void EnterSleepMode()
+{
+ if (CPUStop & 0x40000000) return;
+
+ CPUStop |= 0x40000000;
+ ARM7->Halt(2);
+}
+
u32 GetPC(u32 cpu)
{
return cpu ? ARM7->R[15] : ARM9->R[15];
}
+u64 GetSysClockCycles(int num)
+{
+ u64 ret;
+
+ if (num == 0 || num == 2)
+ {
+ if (num == 0) ret = SysClockCycles;
+ else if (num == 2) ret = FrameSysClockCycles;
+
+ if (CurCPU == 1) ret += (ARM9->Cycles >> 1);
+ else if (CurCPU == 2) ret += ARM7->Cycles;
+ }
+ else if (num == 1)
+ {
+ ret = LastSysClockCycles;
+ LastSysClockCycles = 0;
+
+ if (CurCPU == 1)
+ {
+ ret += (ARM9->Cycles >> 1);
+ LastSysClockCycles = -(ARM9->Cycles >> 1);
+ }
+ else if (CurCPU == 2)
+ {
+ ret += ARM7->Cycles;
+ LastSysClockCycles = -ARM7->Cycles;
+ }
+ }
+
+ return ret;
+}
+
+void NocashPrint(u32 ncpu, u32 addr)
+{
+ // addr: u16 flags (TODO: research? libnds doesn't use those)
+ // addr+2: debug string
+
+ addr += 2;
+
+ ARM* cpu = ncpu ? (ARM*)ARM7 : (ARM*)ARM9;
+ u8 (*readfn)(u32) = ncpu ? NDS::ARM7Read8 : NDS::ARM9Read8;
+
+ char output[1024];
+ int ptr = 0;
+
+ for (int i = 0; i < 120 && ptr < 1023; )
+ {
+ char ch = readfn(addr++);
+ i++;
+
+ if (ch == '%')
+ {
+ char cmd[16]; int j;
+ for (j = 0; j < 15; )
+ {
+ char ch2 = readfn(addr++);
+ i++;
+ if (i >= 120) break;
+ if (ch2 == '%') break;
+ cmd[j++] = ch2;
+ }
+ cmd[j] = '\0';
+
+ char subs[64];
+
+ if (cmd[0] == 'r')
+ {
+ if (!strcmp(cmd, "r0")) sprintf(subs, "%08X", cpu->R[0]);
+ else if (!strcmp(cmd, "r1")) sprintf(subs, "%08X", cpu->R[1]);
+ else if (!strcmp(cmd, "r2")) sprintf(subs, "%08X", cpu->R[2]);
+ else if (!strcmp(cmd, "r3")) sprintf(subs, "%08X", cpu->R[3]);
+ else if (!strcmp(cmd, "r4")) sprintf(subs, "%08X", cpu->R[4]);
+ else if (!strcmp(cmd, "r5")) sprintf(subs, "%08X", cpu->R[5]);
+ else if (!strcmp(cmd, "r6")) sprintf(subs, "%08X", cpu->R[6]);
+ else if (!strcmp(cmd, "r7")) sprintf(subs, "%08X", cpu->R[7]);
+ else if (!strcmp(cmd, "r8")) sprintf(subs, "%08X", cpu->R[8]);
+ else if (!strcmp(cmd, "r9")) sprintf(subs, "%08X", cpu->R[9]);
+ else if (!strcmp(cmd, "r10")) sprintf(subs, "%08X", cpu->R[10]);
+ else if (!strcmp(cmd, "r11")) sprintf(subs, "%08X", cpu->R[11]);
+ else if (!strcmp(cmd, "r12")) sprintf(subs, "%08X", cpu->R[12]);
+ else if (!strcmp(cmd, "r13")) sprintf(subs, "%08X", cpu->R[13]);
+ else if (!strcmp(cmd, "r14")) sprintf(subs, "%08X", cpu->R[14]);
+ else if (!strcmp(cmd, "r15")) sprintf(subs, "%08X", cpu->R[15]);
+ }
+ else
+ {
+ if (!strcmp(cmd, "sp")) sprintf(subs, "%08X", cpu->R[13]);
+ else if (!strcmp(cmd, "lr")) sprintf(subs, "%08X", cpu->R[14]);
+ else if (!strcmp(cmd, "pc")) sprintf(subs, "%08X", cpu->R[15]);
+ else if (!strcmp(cmd, "frame")) sprintf(subs, "%u", NumFrames);
+ else if (!strcmp(cmd, "scanline")) sprintf(subs, "%u", GPU::VCount);
+ else if (!strcmp(cmd, "totalclks")) sprintf(subs, "%lu", GetSysClockCycles(0));
+ else if (!strcmp(cmd, "lastclks")) sprintf(subs, "%lu", GetSysClockCycles(1));
+ else if (!strcmp(cmd, "zeroclks"))
+ {
+ sprintf(subs, "");
+ GetSysClockCycles(1);
+ }
+ }
+
+ int slen = strlen(subs);
+ if ((ptr+slen) > 1023) slen = 1023-ptr;
+ strncpy(&output[ptr], subs, slen);
+ ptr += slen;
+ }
+ else
+ {
+ output[ptr++] = ch;
+ if (ch == '\0') break;
+ }
+ }
+
+ output[ptr] = '\0';
+ printf("%s", output);
+}
+
void HandleTimerOverflow(u32 tid)
{
Timer* timer = &Timers[tid];
+ //if ((timer->Cnt & 0x84) != 0x80) return;
timer->Counter += timer->Reload << 16;
if (timer->Cnt & (1<<6))
SetIRQ(tid >> 2, IRQ_Timer0 + (tid & 0x3));
+ //u32 delay = (0x10000 - timer->Reload) << (16 - timer->CycleShift);
+ //delay -= (timer->Counter - timer->Reload) >> timer->CycleShift;
+ //printf("timer%d IRQ: resched %d, reload=%04X cnt=%08X\n", tid, delay, timer->Reload, timer->Counter);
+ //ScheduleEvent(Event_TimerIRQ_0 + tid, true, delay, HandleTimerOverflow, tid);
+
if ((tid & 0x3) == 3)
return;
@@ -666,7 +1316,7 @@ void RunTimer(u32 tid, s32 cycles)
HandleTimerOverflow(tid);
}
-void RunTimingCriticalDevices(u32 cpu, s32 cycles)
+void RunTightTimers(u32 cpu, s32 cycles)
{
register u32 timermask = TimerCheckMask[cpu];
@@ -675,10 +1325,20 @@ void RunTimingCriticalDevices(u32 cpu, s32 cycles)
if (timermask & 0x4) RunTimer((cpu<<2)+2, cycles);
if (timermask & 0x8) RunTimer((cpu<<2)+3, cycles);
- if (cpu == 0)
- {
- GPU3D::Run(cycles);
- }
+#ifdef DEBUG_CHECK_DESYNC
+ if (cpu) dbg_CyclesTimer7 += cycles;
+ else dbg_CyclesTimer9 += cycles;
+#endif // DEBUG_CHECK_DESYNC
+}
+
+void RunLooseTimers(u32 cpu, s32 cycles)
+{
+ register u32 timermask = TimerCheckMask[cpu];
+
+ if (timermask & 0x10) RunTimer((cpu<<2)+0, cycles);
+ if (timermask & 0x20) RunTimer((cpu<<2)+1, cycles);
+ if (timermask & 0x40) RunTimer((cpu<<2)+2, cycles);
+ if (timermask & 0x80) RunTimer((cpu<<2)+3, cycles);
}
@@ -693,6 +1353,16 @@ bool DMAsInMode(u32 cpu, u32 mode)
return false;
}
+bool DMAsRunning(u32 cpu)
+{
+ cpu <<= 2;
+ if (DMAs[cpu+0]->IsRunning()) return true;
+ if (DMAs[cpu+1]->IsRunning()) return true;
+ if (DMAs[cpu+2]->IsRunning()) return true;
+ if (DMAs[cpu+3]->IsRunning()) return true;
+ return false;
+}
+
void CheckDMAs(u32 cpu, u32 mode)
{
cpu <<= 2;
@@ -735,12 +1405,28 @@ void TimerStart(u32 id, u16 cnt)
if ((!curstart) && newstart)
{
timer->Counter = timer->Reload << 16;
+
+ /*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)
- TimerCheckMask[id>>2] |= (1<<(id&0x3));
+ {
+ u32 tmask;
+ if ((cnt & 0x03) == 0)
+ tmask = 0x01 << (id&0x3);
+ else
+ tmask = 0x10 << (id&0x3);
+
+ TimerCheckMask[id>>2] |= tmask;
+ }
else
- TimerCheckMask[id>>2] &= ~(1<<(id&0x3));
+ TimerCheckMask[id>>2] &= ~(0x11 << (id&0x3));
}
@@ -890,7 +1576,7 @@ void debug(u32 param)
// printf("VRAM %c: %02X\n", 'A'+i, GPU::VRAMCNT[i]);
/*FILE*
- shit = fopen("debug/pictochat.bin", "wb");
+ shit = fopen("debug/jam.bin", "wb");
for (u32 i = 0x02000000; i < 0x02400000; i+=4)
{
u32 val = ARM7Read32(i);
@@ -916,11 +1602,17 @@ u8 ARM9Read8(u32 addr)
switch (addr & 0xFF000000)
{
case 0x02000000:
- return *(u8*)&MainRAM[addr & 0x3FFFFF];
+ return *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
case 0x03000000:
- if (SWRAM_ARM9) return *(u8*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask];
- else return 0;
+ if (SWRAM_ARM9)
+ {
+ return *(u8*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask];
+ }
+ else
+ {
+ return 0;
+ }
case 0x04000000:
return ARM9IORead8(addr);
@@ -929,25 +1621,29 @@ u8 ARM9Read8(u32 addr)
return *(u8*)&GPU::Palette[addr & 0x7FF];
case 0x06000000:
+ switch (addr & 0x00E00000)
{
- switch (addr & 0x00E00000)
- {
- case 0x00000000: return GPU::ReadVRAM_ABG<u8>(addr);
- case 0x00200000: return GPU::ReadVRAM_BBG<u8>(addr);
- case 0x00400000: return GPU::ReadVRAM_AOBJ<u8>(addr);
- case 0x00600000: return GPU::ReadVRAM_BOBJ<u8>(addr);
- default: return GPU::ReadVRAM_LCDC<u8>(addr);
- }
+ case 0x00000000: return GPU::ReadVRAM_ABG<u8>(addr);
+ case 0x00200000: return GPU::ReadVRAM_BBG<u8>(addr);
+ case 0x00400000: return GPU::ReadVRAM_AOBJ<u8>(addr);
+ case 0x00600000: return GPU::ReadVRAM_BOBJ<u8>(addr);
+ default: return GPU::ReadVRAM_LCDC<u8>(addr);
}
- return 0;
case 0x07000000:
return *(u8*)&GPU::OAM[addr & 0x7FF];
case 0x08000000:
case 0x09000000:
+ if (ExMemCnt[0] & (1<<7)) return 0xFF; // TODO: proper open bus
//return *(u8*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
//printf("GBA read8 %08X\n", addr);
+ // TODO!!!
+ return 0xFF;
+
+ case 0x0A000000:
+ if (ExMemCnt[0] & (1<<7)) return 0xFF; // TODO: proper open bus
+ // TODO!!!
return 0xFF;
}
@@ -965,11 +1661,17 @@ u16 ARM9Read16(u32 addr)
switch (addr & 0xFF000000)
{
case 0x02000000:
- return *(u16*)&MainRAM[addr & 0x3FFFFF];
+ return *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
case 0x03000000:
- if (SWRAM_ARM9) return *(u16*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask];
- else return 0;
+ if (SWRAM_ARM9)
+ {
+ return *(u16*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask];
+ }
+ else
+ {
+ return 0;
+ }
case 0x04000000:
return ARM9IORead16(addr);
@@ -978,25 +1680,29 @@ u16 ARM9Read16(u32 addr)
return *(u16*)&GPU::Palette[addr & 0x7FF];
case 0x06000000:
+ switch (addr & 0x00E00000)
{
- switch (addr & 0x00E00000)
- {
- case 0x00000000: return GPU::ReadVRAM_ABG<u16>(addr);
- case 0x00200000: return GPU::ReadVRAM_BBG<u16>(addr);
- case 0x00400000: return GPU::ReadVRAM_AOBJ<u16>(addr);
- case 0x00600000: return GPU::ReadVRAM_BOBJ<u16>(addr);
- default: return GPU::ReadVRAM_LCDC<u16>(addr);
- }
+ case 0x00000000: return GPU::ReadVRAM_ABG<u16>(addr);
+ case 0x00200000: return GPU::ReadVRAM_BBG<u16>(addr);
+ case 0x00400000: return GPU::ReadVRAM_AOBJ<u16>(addr);
+ case 0x00600000: return GPU::ReadVRAM_BOBJ<u16>(addr);
+ default: return GPU::ReadVRAM_LCDC<u16>(addr);
}
- return 0;
case 0x07000000:
return *(u16*)&GPU::OAM[addr & 0x7FF];
case 0x08000000:
case 0x09000000:
- //return *(u16*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
- //printf("GBA read16 %08X\n", addr);
+ if (ExMemCnt[0] & (1<<7)) return 0xFFFF; // TODO: proper open bus
+ //return *(u8*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
+ //printf("GBA read8 %08X\n", addr);
+ // TODO!!!
+ return 0xFFFF;
+
+ case 0x0A000000:
+ if (ExMemCnt[0] & (1<<7)) return 0xFFFF; // TODO: proper open bus
+ // TODO!!!
return 0xFFFF;
}
@@ -1014,11 +1720,17 @@ u32 ARM9Read32(u32 addr)
switch (addr & 0xFF000000)
{
case 0x02000000:
- return *(u32*)&MainRAM[addr & 0x3FFFFF];
+ return *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
case 0x03000000:
- if (SWRAM_ARM9) return *(u32*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask];
- else return 0;
+ if (SWRAM_ARM9)
+ {
+ return *(u32*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask];
+ }
+ else
+ {
+ return 0;
+ }
case 0x04000000:
return ARM9IORead32(addr);
@@ -1027,29 +1739,33 @@ u32 ARM9Read32(u32 addr)
return *(u32*)&GPU::Palette[addr & 0x7FF];
case 0x06000000:
+ switch (addr & 0x00E00000)
{
- switch (addr & 0x00E00000)
- {
- case 0x00000000: return GPU::ReadVRAM_ABG<u32>(addr);
- case 0x00200000: return GPU::ReadVRAM_BBG<u32>(addr);
- case 0x00400000: return GPU::ReadVRAM_AOBJ<u32>(addr);
- case 0x00600000: return GPU::ReadVRAM_BOBJ<u32>(addr);
- default: return GPU::ReadVRAM_LCDC<u32>(addr);
- }
+ case 0x00000000: return GPU::ReadVRAM_ABG<u32>(addr);
+ case 0x00200000: return GPU::ReadVRAM_BBG<u32>(addr);
+ case 0x00400000: return GPU::ReadVRAM_AOBJ<u32>(addr);
+ case 0x00600000: return GPU::ReadVRAM_BOBJ<u32>(addr);
+ default: return GPU::ReadVRAM_LCDC<u32>(addr);
}
- return 0;
case 0x07000000:
return *(u32*)&GPU::OAM[addr & 0x7FF];
case 0x08000000:
case 0x09000000:
- //return *(u32*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
- //printf("GBA read32 %08X\n", addr);
+ if (ExMemCnt[0] & (1<<7)) return 0xFFFFFFFF; // TODO: proper open bus
+ //return *(u8*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
+ //printf("GBA read8 %08X\n", addr);
+ // TODO!!!
+ return 0xFFFFFFFF;
+
+ case 0x0A000000:
+ if (ExMemCnt[0] & (1<<7)) return 0xFFFFFFFF; // TODO: proper open bus
+ // TODO!!!
return 0xFFFFFFFF;
}
- printf("unknown arm9 read32 %08X | %08X %08X %08X\n", addr, ARM9->R[15], ARM9->R[12], ARM9Read32(0x027FF820));
+ printf("unknown arm9 read32 %08X | %08X %08X\n", addr, ARM9->R[15], ARM9->R[12]);
return 0;
}
@@ -1058,11 +1774,14 @@ void ARM9Write8(u32 addr, u8 val)
switch (addr & 0xFF000000)
{
case 0x02000000:
- *(u8*)&MainRAM[addr & 0x3FFFFF] = val;
+ *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
return;
case 0x03000000:
- if (SWRAM_ARM9) *(u8*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask] = val;
+ if (SWRAM_ARM9)
+ {
+ *(u8*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask] = val;
+ }
return;
case 0x04000000:
@@ -1072,6 +1791,7 @@ void ARM9Write8(u32 addr, u8 val)
case 0x05000000:
case 0x06000000:
case 0x07000000:
+ // checkme
return;
}
@@ -1083,11 +1803,14 @@ void ARM9Write16(u32 addr, u16 val)
switch (addr & 0xFF000000)
{
case 0x02000000:
- *(u16*)&MainRAM[addr & 0x3FFFFF] = val;
+ *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
return;
case 0x03000000:
- if (SWRAM_ARM9) *(u16*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask] = val;
+ if (SWRAM_ARM9)
+ {
+ *(u16*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask] = val;
+ }
return;
case 0x04000000:
@@ -1101,13 +1824,12 @@ void ARM9Write16(u32 addr, u16 val)
case 0x06000000:
switch (addr & 0x00E00000)
{
- case 0x00000000: GPU::WriteVRAM_ABG<u16>(addr, val); break;
- case 0x00200000: GPU::WriteVRAM_BBG<u16>(addr, val); break;
- case 0x00400000: GPU::WriteVRAM_AOBJ<u16>(addr, val); break;
- case 0x00600000: GPU::WriteVRAM_BOBJ<u16>(addr, val); break;
- default: GPU::WriteVRAM_LCDC<u16>(addr, val); break;
+ case 0x00000000: GPU::WriteVRAM_ABG<u16>(addr, val); return;
+ case 0x00200000: GPU::WriteVRAM_BBG<u16>(addr, val); return;
+ case 0x00400000: GPU::WriteVRAM_AOBJ<u16>(addr, val); return;
+ case 0x00600000: GPU::WriteVRAM_BOBJ<u16>(addr, val); return;
+ default: GPU::WriteVRAM_LCDC<u16>(addr, val); return;
}
- return;
case 0x07000000:
*(u16*)&GPU::OAM[addr & 0x7FF] = val;
@@ -1122,11 +1844,14 @@ void ARM9Write32(u32 addr, u32 val)
switch (addr & 0xFF000000)
{
case 0x02000000:
- *(u32*)&MainRAM[addr & 0x3FFFFF] = val;
- return;
+ *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
+ return ;
case 0x03000000:
- if (SWRAM_ARM9) *(u32*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask] = val;
+ if (SWRAM_ARM9)
+ {
+ *(u32*)&SWRAM_ARM9[addr & SWRAM_ARM9Mask] = val;
+ }
return;
case 0x04000000:
@@ -1140,13 +1865,12 @@ void ARM9Write32(u32 addr, u32 val)
case 0x06000000:
switch (addr & 0x00E00000)
{
- case 0x00000000: GPU::WriteVRAM_ABG<u32>(addr, val); break;
- case 0x00200000: GPU::WriteVRAM_BBG<u32>(addr, val); break;
- case 0x00400000: GPU::WriteVRAM_AOBJ<u32>(addr, val); break;
- case 0x00600000: GPU::WriteVRAM_BOBJ<u32>(addr, val); break;
- default: GPU::WriteVRAM_LCDC<u32>(addr, val); break;
+ case 0x00000000: GPU::WriteVRAM_ABG<u32>(addr, val); return;
+ case 0x00200000: GPU::WriteVRAM_BBG<u32>(addr, val); return;
+ case 0x00400000: GPU::WriteVRAM_AOBJ<u32>(addr, val); return;
+ case 0x00600000: GPU::WriteVRAM_BOBJ<u32>(addr, val); return;
+ default: GPU::WriteVRAM_LCDC<u32>(addr, val); return;
}
- return;
case 0x07000000:
*(u32*)&GPU::OAM[addr & 0x7FF] = val;
@@ -1156,6 +1880,36 @@ void ARM9Write32(u32 addr, u32 val)
printf("unknown arm9 write32 %08X %08X | %08X\n", addr, val, ARM9->R[15]);
}
+bool ARM9GetMemRegion(u32 addr, bool write, MemRegion* region)
+{
+ switch (addr & 0xFF000000)
+ {
+ case 0x02000000:
+ region->Mem = MainRAM;
+ region->Mask = MAIN_RAM_SIZE-1;
+ return true;
+
+ case 0x03000000:
+ if (SWRAM_ARM9)
+ {
+ region->Mem = SWRAM_ARM9;
+ region->Mask = SWRAM_ARM9Mask;
+ return true;
+ }
+ break;
+ }
+
+ if ((addr & 0xFFFFF000) == 0xFFFF0000 && !write)
+ {
+ region->Mem = ARM9BIOS;
+ region->Mask = 0xFFF;
+ return true;
+ }
+
+ region->Mem = NULL;
+ return false;
+}
+
u8 ARM7Read8(u32 addr)
@@ -1174,11 +1928,17 @@ u8 ARM7Read8(u32 addr)
{
case 0x02000000:
case 0x02800000:
- return *(u8*)&MainRAM[addr & 0x3FFFFF];
+ return *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
case 0x03000000:
- if (SWRAM_ARM7) return *(u8*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask];
- else return *(u8*)&ARM7WRAM[addr & 0xFFFF];
+ if (SWRAM_ARM7)
+ {
+ return *(u8*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask];
+ }
+ else
+ {
+ return *(u8*)&ARM7WRAM[addr & 0xFFFF];
+ }
case 0x03800000:
return *(u8*)&ARM7WRAM[addr & 0xFFFF];
@@ -1189,6 +1949,19 @@ u8 ARM7Read8(u32 addr)
case 0x06000000:
case 0x06800000:
return GPU::ReadVRAM_ARM7<u8>(addr);
+
+ case 0x08000000:
+ case 0x09000000:
+ if (!(ExMemCnt[0] & (1<<7))) return 0xFF; // TODO: proper open bus
+ //return *(u8*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
+ //printf("GBA read8 %08X\n", addr);
+ // TODO!!!
+ return 0xFF;
+
+ case 0x0A000000:
+ if (!(ExMemCnt[0] & (1<<7))) return 0xFF; // TODO: proper open bus
+ // TODO!!!
+ return 0xFF;
}
printf("unknown arm7 read8 %08X %08X %08X/%08X\n", addr, ARM7->R[15], ARM7->R[0], ARM7->R[1]);
@@ -1211,11 +1984,17 @@ u16 ARM7Read16(u32 addr)
{
case 0x02000000:
case 0x02800000:
- return *(u16*)&MainRAM[addr & 0x3FFFFF];
+ return *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
case 0x03000000:
- if (SWRAM_ARM7) return *(u16*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask];
- else return *(u16*)&ARM7WRAM[addr & 0xFFFF];
+ if (SWRAM_ARM7)
+ {
+ return *(u16*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask];
+ }
+ else
+ {
+ return *(u16*)&ARM7WRAM[addr & 0xFFFF];
+ }
case 0x03800000:
return *(u16*)&ARM7WRAM[addr & 0xFFFF];
@@ -1224,11 +2003,28 @@ u16 ARM7Read16(u32 addr)
return ARM7IORead16(addr);
case 0x04800000:
- return Wifi::Read(addr);
+ if (addr < 0x04810000)
+ {
+ return Wifi::Read(addr);
+ }
+ break;
case 0x06000000:
case 0x06800000:
return GPU::ReadVRAM_ARM7<u16>(addr);
+
+ case 0x08000000:
+ case 0x09000000:
+ if (!(ExMemCnt[0] & (1<<7))) return 0xFFFF; // TODO: proper open bus
+ //return *(u8*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
+ //printf("GBA read8 %08X\n", addr);
+ // TODO!!!
+ return 0xFFFF;
+
+ case 0x0A000000:
+ if (!(ExMemCnt[0] & (1<<7))) return 0xFFFF; // TODO: proper open bus
+ // TODO!!!
+ return 0xFFFF;
}
printf("unknown arm7 read16 %08X %08X\n", addr, ARM7->R[15]);
@@ -1251,11 +2047,17 @@ u32 ARM7Read32(u32 addr)
{
case 0x02000000:
case 0x02800000:
- return *(u32*)&MainRAM[addr & 0x3FFFFF];
+ return *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)];
case 0x03000000:
- if (SWRAM_ARM7) return *(u32*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask];
- else return *(u32*)&ARM7WRAM[addr & 0xFFFF];
+ if (SWRAM_ARM7)
+ {
+ return *(u32*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask];
+ }
+ else
+ {
+ return *(u32*)&ARM7WRAM[addr & 0xFFFF];
+ }
case 0x03800000:
return *(u32*)&ARM7WRAM[addr & 0xFFFF];
@@ -1264,11 +2066,28 @@ u32 ARM7Read32(u32 addr)
return ARM7IORead32(addr);
case 0x04800000:
- return Wifi::Read(addr) | (Wifi::Read(addr+2) << 16);
+ if (addr < 0x04810000)
+ {
+ return Wifi::Read(addr) | (Wifi::Read(addr+2) << 16);
+ }
+ break;
case 0x06000000:
case 0x06800000:
return GPU::ReadVRAM_ARM7<u32>(addr);
+
+ case 0x08000000:
+ case 0x09000000:
+ if (!(ExMemCnt[0] & (1<<7))) return 0xFFFFFFFF; // TODO: proper open bus
+ //return *(u8*)&NDSCart::CartROM[addr & (NDSCart::CartROMSize-1)];
+ //printf("GBA read8 %08X\n", addr);
+ // TODO!!!
+ return 0xFFFFFFFF;
+
+ case 0x0A000000:
+ if (!(ExMemCnt[0] & (1<<7))) return 0xFFFFFFFF; // TODO: proper open bus
+ // TODO!!!
+ return 0xFFFFFFFF;
}
printf("unknown arm7 read32 %08X | %08X\n", addr, ARM7->R[15]);
@@ -1281,13 +2100,20 @@ void ARM7Write8(u32 addr, u8 val)
{
case 0x02000000:
case 0x02800000:
- *(u8*)&MainRAM[addr & 0x3FFFFF] = val;
+ *(u8*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
return;
case 0x03000000:
- if (SWRAM_ARM7) *(u8*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask] = val;
- else *(u8*)&ARM7WRAM[addr & 0xFFFF] = val;
- return;
+ if (SWRAM_ARM7)
+ {
+ *(u8*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask] = val;
+ return;
+ }
+ else
+ {
+ *(u8*)&ARM7WRAM[addr & 0xFFFF] = val;
+ return;
+ }
case 0x03800000:
*(u8*)&ARM7WRAM[addr & 0xFFFF] = val;
@@ -1312,13 +2138,20 @@ void ARM7Write16(u32 addr, u16 val)
{
case 0x02000000:
case 0x02800000:
- *(u16*)&MainRAM[addr & 0x3FFFFF] = val;
+ *(u16*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
return;
case 0x03000000:
- if (SWRAM_ARM7) *(u16*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask] = val;
- else *(u16*)&ARM7WRAM[addr & 0xFFFF] = val;
- return;
+ if (SWRAM_ARM7)
+ {
+ *(u16*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask] = val;
+ return;
+ }
+ else
+ {
+ *(u16*)&ARM7WRAM[addr & 0xFFFF] = val;
+ return;
+ }
case 0x03800000:
*(u16*)&ARM7WRAM[addr & 0xFFFF] = val;
@@ -1329,8 +2162,12 @@ void ARM7Write16(u32 addr, u16 val)
return;
case 0x04800000:
- Wifi::Write(addr, val);
- return;
+ if (addr < 0x04810000)
+ {
+ Wifi::Write(addr, val);
+ return;
+ }
+ break;
case 0x06000000:
case 0x06800000:
@@ -1347,13 +2184,20 @@ void ARM7Write32(u32 addr, u32 val)
{
case 0x02000000:
case 0x02800000:
- *(u32*)&MainRAM[addr & 0x3FFFFF] = val;
+ *(u32*)&MainRAM[addr & (MAIN_RAM_SIZE - 1)] = val;
return;
case 0x03000000:
- if (SWRAM_ARM7) *(u32*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask] = val;
- else *(u32*)&ARM7WRAM[addr & 0xFFFF] = val;
- return;
+ if (SWRAM_ARM7)
+ {
+ *(u32*)&SWRAM_ARM7[addr & SWRAM_ARM7Mask] = val;
+ return;
+ }
+ else
+ {
+ *(u32*)&ARM7WRAM[addr & 0xFFFF] = val;
+ return;
+ }
case 0x03800000:
*(u32*)&ARM7WRAM[addr & 0xFFFF] = val;
@@ -1364,9 +2208,13 @@ void ARM7Write32(u32 addr, u32 val)
return;
case 0x04800000:
- Wifi::Write(addr, val & 0xFFFF);
- Wifi::Write(addr+2, val >> 16);
- return;
+ if (addr < 0x04810000)
+ {
+ Wifi::Write(addr, val & 0xFFFF);
+ Wifi::Write(addr+2, val >> 16);
+ return;
+ }
+ break;
case 0x06000000:
case 0x06800000:
@@ -1377,6 +2225,51 @@ void ARM7Write32(u32 addr, u32 val)
//printf("unknown arm7 write32 %08X %08X @ %08X\n", addr, val, ARM7->R[15]);
}
+bool ARM7GetMemRegion(u32 addr, bool write, MemRegion* region)
+{
+ switch (addr & 0xFF800000)
+ {
+ case 0x02000000:
+ case 0x02800000:
+ region->Mem = MainRAM;
+ region->Mask = MAIN_RAM_SIZE-1;
+ return true;
+
+ case 0x03000000:
+ // note on this, and why we can only cover it in one particular case:
+ // it is typical for games to map all shared WRAM to the ARM7
+ // then access all the WRAM as one contiguous block starting at 0x037F8000
+ // this case needs a bit of a hack to cover
+ // it's not really worth bothering anyway
+ if (!SWRAM_ARM7)
+ {
+ region->Mem = ARM7WRAM;
+ region->Mask = 0xFFFF;
+ return true;
+ }
+ break;
+
+ case 0x03800000:
+ region->Mem = ARM7WRAM;
+ region->Mask = 0xFFFF;
+ return true;
+ }
+
+ // BIOS. ARM7 PC has to be within range.
+ if (addr < 0x00004000 && !write)
+ {
+ if (ARM7->R[15] < 0x4000 && (addr >= ARM7BIOSProt || ARM7->R[15] < ARM7BIOSProt))
+ {
+ region->Mem = ARM7BIOS;
+ region->Mask = 0x3FFF;
+ return true;
+ }
+ }
+
+ region->Mem = NULL;
+ return false;
+}
+
@@ -1454,7 +2347,7 @@ u8 ARM9IORead8(u32 addr)
return GPU3D::Read8(addr);
}
- printf("unknown ARM9 IO read8 %08X\n", addr);
+ printf("unknown ARM9 IO read8 %08X %08X\n", addr, ARM9->R[15]);
return 0;
}
@@ -1616,6 +2509,8 @@ u32 ARM9IORead32(u32 addr)
case 0x04000130: return (KeyInput & 0xFFFF) | (KeyCnt << 16);
+ case 0x04000180: return IPCSync9;
+
case 0x040001A0: return NDSCart::SPICnt | (NDSCart::ReadSPIData() << 16);
case 0x040001A4: return NDSCart::ROMCnt;
@@ -1651,6 +2546,9 @@ u32 ARM9IORead32(u32 addr)
case 0x040002B8: return SqrtVal[0];
case 0x040002BC: return SqrtVal[1];
+ case 0x04000300: return PostFlag9;
+ case 0x04000304: return PowerControl9;
+
case 0x04100000:
if (IPCFIFOCnt9 & 0x8000)
{
@@ -1690,7 +2588,7 @@ u32 ARM9IORead32(u32 addr)
return GPU3D::Read32(addr);
}
- printf("unknown ARM9 IO read32 %08X\n", addr);
+ printf("unknown ARM9 IO read32 %08X %08X\n", addr, ARM9->R[15]);
return 0;
}
@@ -1770,7 +2668,7 @@ void ARM9IOWrite8(u32 addr, u8 val)
return;
}
- printf("unknown ARM9 IO write8 %08X %02X\n", addr, val);
+ printf("unknown ARM9 IO write8 %08X %02X %08X\n", addr, val, ARM9->R[15]);
}
void ARM9IOWrite16(u32 addr, u16 val)
@@ -1872,6 +2770,7 @@ void ARM9IOWrite16(u32 addr, u16 val)
case 0x04000204:
ExMemCnt[0] = val;
ExMemCnt[1] = (ExMemCnt[1] & 0x007F) | (val & 0xFF80);
+ SetGBASlotTimings();
return;
case 0x04000208: IME[0] = val & 0x1; return;
@@ -1931,7 +2830,7 @@ void ARM9IOWrite16(u32 addr, u16 val)
return;
}
- printf("unknown ARM9 IO write16 %08X %04X %08X\n", addr, val, ARM9->R[14]);
+ printf("unknown ARM9 IO write16 %08X %04X %08X\n", addr, val, ARM9->R[15]);
}
void ARM9IOWrite32(u32 addr, u32 val)
@@ -1983,6 +2882,9 @@ void ARM9IOWrite32(u32 addr, u32 val)
case 0x04000130:
KeyCnt = val >> 16;
return;
+ case 0x04000180:
+ ARM9IOWrite16(addr, val);
+ return;
case 0x04000188:
if (IPCFIFOCnt9 & 0x8000)
@@ -2081,7 +2983,7 @@ void ARM9IOWrite32(u32 addr, u32 val)
return;
}
- printf("unknown ARM9 IO write32 %08X %08X\n", addr, val);
+ printf("unknown ARM9 IO write32 %08X %08X %08X\n", addr, val, ARM9->R[15]);
}
@@ -2126,7 +3028,7 @@ u8 ARM7IORead8(u32 addr)
return SPU::Read8(addr);
}
- printf("unknown ARM7 IO read8 %08X\n", addr);
+ printf("unknown ARM7 IO read8 %08X %08X\n", addr, ARM7->R[15]);
return 0;
}
@@ -2189,6 +3091,8 @@ u16 ARM7IORead16(u32 addr)
case 0x040001C2: return SPI::ReadData();
case 0x04000204: return ExMemCnt[1];
+ case 0x04000206: return WifiWaitCnt;
+
case 0x04000208: return IME[1];
case 0x04000210: return IE[1] & 0xFFFF;
case 0x04000212: return IE[1] >> 16;
@@ -2203,7 +3107,7 @@ u16 ARM7IORead16(u32 addr)
return SPU::Read16(addr);
}
- printf("unknown ARM7 IO read16 %08X %08X\n", addr, ARM9->R[15]);
+ printf("unknown ARM7 IO read16 %08X %08X\n", addr, ARM7->R[15]);
return 0;
}
@@ -2235,6 +3139,8 @@ u32 ARM7IORead32(u32 addr)
case 0x04000134: return RCnt | (KeyCnt & 0xFFFF0000);
case 0x04000138: return RTC::Read();
+ case 0x04000180: return IPCSync7;
+
case 0x040001A0: return NDSCart::SPICnt | (NDSCart::ReadSPIData() << 16);
case 0x040001A4: return NDSCart::ROMCnt;
@@ -2287,7 +3193,7 @@ u32 ARM7IORead32(u32 addr)
return SPU::Read32(addr);
}
- printf("unknown ARM7 IO read32 %08X\n", addr);
+ printf("unknown ARM7 IO read32 %08X %08X\n", addr, ARM7->R[15]);
return 0;
}
@@ -2349,7 +3255,10 @@ void ARM7IOWrite8(u32 addr, u8 val)
return;
case 0x04000301:
- if (val == 0x80) ARM7->Halt(1);
+ val & 0xC0;
+ if (val == 0x40) printf("!! GBA MODE NOT SUPPORTED\n");
+ else if (val == 0x80) ARM7->Halt(1);
+ else if (val == 0xC0) EnterSleepMode();
return;
}
@@ -2359,7 +3268,7 @@ void ARM7IOWrite8(u32 addr, u8 val)
return;
}
- printf("unknown ARM7 IO write8 %08X %02X\n", addr, val);
+ printf("unknown ARM7 IO write8 %08X %02X %08X\n", addr, val, ARM7->R[15]);
}
void ARM7IOWrite16(u32 addr, u16 val)
@@ -2452,6 +3361,10 @@ void ARM7IOWrite16(u32 addr, u16 val)
case 0x04000204:
ExMemCnt[1] = (ExMemCnt[1] & 0xFF80) | (val & 0x007F);
+ SetGBASlotTimings();
+ return;
+ case 0x04000206:
+ SetWifiWaitCnt(val);
return;
case 0x04000208: IME[1] = val & 0x1; return;
@@ -2480,7 +3393,7 @@ void ARM7IOWrite16(u32 addr, u16 val)
return;
}
- printf("unknown ARM7 IO write16 %08X %04X\n", addr, val);
+ printf("unknown ARM7 IO write16 %08X %04X %08X\n", addr, val, ARM7->R[15]);
}
void ARM7IOWrite32(u32 addr, u32 val)
@@ -2521,6 +3434,9 @@ void ARM7IOWrite32(u32 addr, u32 val)
case 0x04000134: RCnt = val & 0xFFFF; return;
case 0x04000138: RTC::Write(val & 0xFFFF, false); return;
+ case 0x04000180:
+ ARM7IOWrite16(addr, val);
+ return;
case 0x04000188:
if (IPCFIFOCnt7 & 0x8000)
{
@@ -2579,7 +3495,7 @@ void ARM7IOWrite32(u32 addr, u32 val)
return;
}
- printf("unknown ARM7 IO write32 %08X %08X\n", addr, val);
+ printf("unknown ARM7 IO write32 %08X %08X %08X\n", addr, val, ARM7->R[15]);
}
}