aboutsummaryrefslogtreecommitdiff
path: root/src/NDS.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/NDS.cpp')
-rw-r--r--src/NDS.cpp310
1 files changed, 227 insertions, 83 deletions
diff --git a/src/NDS.cpp b/src/NDS.cpp
index ae45d3d..832661a 100644
--- a/src/NDS.cpp
+++ b/src/NDS.cpp
@@ -167,7 +167,7 @@ u32 SqrtVal[2];
u32 SqrtRes;
u32 KeyInput;
-u16 KeyCnt;
+u16 KeyCnt[2];
u16 RCnt;
bool Running;
@@ -612,7 +612,8 @@ void Reset()
SchedListMask = 0;
KeyInput = 0x007F03FF;
- KeyCnt = 0;
+ KeyCnt[0] = 0;
+ KeyCnt[1] = 0;
RCnt = 0;
NDSCart::Reset();
@@ -715,6 +716,7 @@ bool DoSavestate_Scheduler(Savestate* file)
GPU::StartScanline, GPU::StartHBlank, GPU::FinishFrame,
SPU::Mix,
Wifi::USTimer,
+ RTC::ClockTimer,
GPU::DisplayFIFO,
NDSCart::ROMPrepareData, NDSCart::ROMEndTransfer,
@@ -887,7 +889,7 @@ bool DoSavestate(Savestate* file)
file->Bool32(&LagFrameFlag);
// TODO: save KeyInput????
- file->Var16(&KeyCnt);
+ file->VarArray(KeyCnt, 2*sizeof(u16));
file->Var16(&RCnt);
file->Var8(&WRAMCnt);
@@ -1059,93 +1061,192 @@ void RunSystem(u64 timestamp)
}
}
-template <bool EnableJIT, int ConsoleType>
-u32 RunFrame()
+u64 NextTargetSleep()
{
- FrameStartTimestamp = SysTimestamp;
+ u64 minEvent = UINT64_MAX;
- LagFrameFlag = true;
- bool runFrame = Running && !(CPUStop & 0x40000000);
- if (runFrame)
+ u32 mask = SchedListMask;
+ for (int i = 0; i < Event_MAX; i++)
{
- ARM9->CheckGdbIncoming();
- ARM7->CheckGdbIncoming();
+ if (!mask) break;
+ if (i == Event_SPU || i == Event_RTC)
+ {
+ if (mask & 0x1)
+ {
+ if (SchedList[i].Timestamp < minEvent)
+ minEvent = SchedList[i].Timestamp;
+ }
+ }
- GPU::StartFrame();
+ mask >>= 1;
+ }
- while (Running && GPU::TotalScanlines==0)
- {
- u64 target = NextTarget();
- ARM9Target = target << ARM9ClockShift;
- CurCPU = 0;
+ return minEvent;
+}
+
+void RunSystemSleep(u64 timestamp)
+{
+ u64 offset = timestamp - SysTimestamp;
+ SysTimestamp = timestamp;
- if (CPUStop & 0x80000000)
+ u32 mask = SchedListMask;
+ for (int i = 0; i < Event_MAX; i++)
+ {
+ if (!mask) break;
+ if (i == Event_SPU || i == Event_RTC)
+ {
+ if (mask & 0x1)
{
- // GXFIFO stall
- s32 cycles = GPU3D::CyclesToRunFor();
+ if (SchedList[i].Timestamp <= SysTimestamp)
+ {
+ SchedListMask &= ~(1<<i);
- ARM9Timestamp = std::min(ARM9Target, ARM9Timestamp+(cycles<<ARM9ClockShift));
+ u32 param;
+ if (i == Event_SPU)
+ param = 1;
+ else
+ param = SchedList[i].Param;
+
+ SchedList[i].Func(param);
+ }
}
- else if (CPUStop & 0x0FFF)
+ }
+ else if (mask & 0x1)
+ {
+ if (SchedList[i].Timestamp <= SysTimestamp)
{
- DMAs[0]->Run<ConsoleType>();
- if (!(CPUStop & 0x80000000)) DMAs[1]->Run<ConsoleType>();
- if (!(CPUStop & 0x80000000)) DMAs[2]->Run<ConsoleType>();
- if (!(CPUStop & 0x80000000)) DMAs[3]->Run<ConsoleType>();
- if (ConsoleType == 1) DSi::RunNDMAs(0);
+ SchedList[i].Timestamp += offset;
}
- else
+ }
+
+ mask >>= 1;
+ }
+}
+
+template <bool EnableJIT, int ConsoleType>
+u32 RunFrame()
+{
+ FrameStartTimestamp = SysTimestamp;
+
+ GPU::TotalScanlines = 0;
+
+ LagFrameFlag = true;
+ bool runFrame = Running && !(CPUStop & CPUStop_Sleep);
+ while (Running)
+ {
+ u64 frametarget = SysTimestamp + 560190;
+
+ if (CPUStop & CPUStop_Sleep)
+ {
+ // we are running in sleep mode
+ // we still need to run the RTC during this mode
+ // we also keep outputting audio, so that frontends using audio sync don't skyrocket to 1000+FPS
+
+ while (Running && (SysTimestamp < frametarget))
{
-#ifdef JIT_ENABLED
- if (EnableJIT)
- ARM9->ExecuteJIT();
- else
-#endif
- ARM9->Execute();
+ u64 target = NextTargetSleep();
+ if (target > frametarget)
+ target = frametarget;
+
+ ARM9Timestamp = target << ARM9ClockShift;
+ ARM7Timestamp = target;
+ TimerTimestamp[0] = target;
+ TimerTimestamp[1] = target;
+ GPU3D::Timestamp = target;
+ RunSystemSleep(target);
+
+ if (!(CPUStop & CPUStop_Sleep))
+ break;
}
- RunTimers(0);
- GPU3D::Run();
+ if (SysTimestamp >= frametarget)
+ GPU::BlankFrame();
+ }
+ else
+ {
+ ARM9->CheckGdbIncoming();
+ ARM7->CheckGdbIncoming();
- target = ARM9Timestamp >> ARM9ClockShift;
- CurCPU = 1;
+ if (!(CPUStop & CPUStop_Wakeup))
+ {
+ GPU::StartFrame();
+ }
+ CPUStop &= ~CPUStop_Wakeup;
- while (ARM7Timestamp < target)
+ while (Running && GPU::TotalScanlines==0)
{
- ARM7Target = target; // might be changed by a reschedule
+ u64 target = NextTarget();
+ ARM9Target = target << ARM9ClockShift;
+ CurCPU = 0;
- if (CPUStop & 0x0FFF0000)
+ if (CPUStop & CPUStop_GXStall)
{
- DMAs[4]->Run<ConsoleType>();
- DMAs[5]->Run<ConsoleType>();
- DMAs[6]->Run<ConsoleType>();
- DMAs[7]->Run<ConsoleType>();
- if (ConsoleType == 1) DSi::RunNDMAs(1);
+ // GXFIFO stall
+ s32 cycles = GPU3D::CyclesToRunFor();
+
+ ARM9Timestamp = std::min(ARM9Target, ARM9Timestamp+(cycles<<ARM9ClockShift));
+ }
+ else if (CPUStop & CPUStop_DMA9)
+ {
+ DMAs[0]->Run<ConsoleType>();
+ if (!(CPUStop & CPUStop_GXStall)) DMAs[1]->Run<ConsoleType>();
+ if (!(CPUStop & CPUStop_GXStall)) DMAs[2]->Run<ConsoleType>();
+ if (!(CPUStop & CPUStop_GXStall)) DMAs[3]->Run<ConsoleType>();
+ if (ConsoleType == 1) DSi::RunNDMAs(0);
}
else
{
#ifdef JIT_ENABLED
if (EnableJIT)
- ARM7->ExecuteJIT();
+ ARM9->ExecuteJIT();
else
#endif
- ARM7->Execute();
+ ARM9->Execute();
}
- RunTimers(1);
- }
+ RunTimers(0);
+ GPU3D::Run();
- RunSystem(target);
+ target = ARM9Timestamp >> ARM9ClockShift;
+ CurCPU = 1;
- if (CPUStop & 0x40000000)
- {
- // checkme: when is sleep mode effective?
- CancelEvent(Event_LCD);
- GPU::TotalScanlines = 263;
- break;
+ while (ARM7Timestamp < target)
+ {
+ ARM7Target = target; // might be changed by a reschedule
+
+ if (CPUStop & CPUStop_DMA7)
+ {
+ DMAs[4]->Run<ConsoleType>();
+ DMAs[5]->Run<ConsoleType>();
+ DMAs[6]->Run<ConsoleType>();
+ DMAs[7]->Run<ConsoleType>();
+ if (ConsoleType == 1) DSi::RunNDMAs(1);
+ }
+ else
+ {
+#ifdef JIT_ENABLED
+ if (EnableJIT)
+ ARM7->ExecuteJIT();
+ else
+#endif
+ ARM7->Execute();
+ }
+
+ RunTimers(1);
+ }
+
+ RunSystem(target);
+
+ if (CPUStop & CPUStop_Sleep)
+ {
+ break;
+ }
}
}
+ if (GPU::TotalScanlines == 0)
+ continue;
+
#ifdef DEBUG_CHECK_DESYNC
Log(LogLevel::Debug, "[%08X%08X] ARM9=%ld, ARM7=%ld, GPU=%ld\n",
(u32)(SysTimestamp>>32), (u32)SysTimestamp,
@@ -1154,6 +1255,7 @@ u32 RunFrame()
GPU3D::Timestamp-SysTimestamp);
#endif
SPU::TransferOutput();
+ break;
}
// In the context of TASes, frame count is traditionally the primary measure of emulated time,
@@ -1162,7 +1264,7 @@ u32 RunFrame()
if (LagFrameFlag)
NumLagFrames++;
- if (runFrame)
+ if (Running)
return GPU::TotalScanlines;
else
return 263;
@@ -1276,13 +1378,47 @@ void ReleaseScreen()
}
+void CheckKeyIRQ(u32 cpu, u32 oldkey, u32 newkey)
+{
+ u16 cnt = KeyCnt[cpu];
+ if (!(cnt & (1<<14))) // IRQ disabled
+ return;
+
+ u32 mask = (cnt & 0x03FF);
+ oldkey &= mask;
+ newkey &= mask;
+
+ bool oldmatch, newmatch;
+ if (cnt & (1<<15))
+ {
+ // logical AND
+
+ oldmatch = (oldkey == 0);
+ newmatch = (newkey == 0);
+ }
+ else
+ {
+ // logical OR
+
+ oldmatch = (oldkey != mask);
+ newmatch = (newkey != mask);
+ }
+
+ if ((!oldmatch) && newmatch)
+ SetIRQ(cpu, IRQ_Keypad);
+}
+
void SetKeyMask(u32 mask)
{
u32 key_lo = mask & 0x3FF;
u32 key_hi = (mask >> 10) & 0x3;
+ u32 oldkey = KeyInput;
KeyInput &= 0xFFFCFC00;
KeyInput |= key_lo | (key_hi << 16);
+
+ CheckKeyIRQ(0, oldkey, KeyInput);
+ CheckKeyIRQ(1, oldkey, KeyInput);
}
bool IsLidClosed()
@@ -1301,8 +1437,6 @@ void SetLidClosed(bool closed)
{
KeyInput &= ~(1<<23);
SetIRQ(1, IRQ_LidOpen);
- CPUStop &= ~0x40000000;
- GPU3D::RestartFrame();
}
}
@@ -1467,6 +1601,16 @@ void SetIRQ(u32 cpu, u32 irq)
{
IF[cpu] |= (1 << irq);
UpdateIRQ(cpu);
+
+ if ((cpu == 1) && (CPUStop & CPUStop_Sleep))
+ {
+ if (IE[1] & (1 << irq))
+ {
+ CPUStop &= ~CPUStop_Sleep;
+ CPUStop |= CPUStop_Wakeup;
+ GPU3D::RestartFrame();
+ }
+ }
}
void ClearIRQ(u32 cpu, u32 irq)
@@ -1526,9 +1670,9 @@ void ResumeCPU(u32 cpu, u32 mask)
void GXFIFOStall()
{
- if (CPUStop & 0x80000000) return;
+ if (CPUStop & CPUStop_GXStall) return;
- CPUStop |= 0x80000000;
+ CPUStop |= CPUStop_GXStall;
if (CurCPU == 1) ARM9->Halt(2);
else
@@ -1543,14 +1687,14 @@ void GXFIFOStall()
void GXFIFOUnstall()
{
- CPUStop &= ~0x80000000;
+ CPUStop &= ~CPUStop_GXStall;
}
void EnterSleepMode()
{
- if (CPUStop & 0x40000000) return;
+ if (CPUStop & CPUStop_Sleep) return;
- CPUStop |= 0x40000000;
+ CPUStop |= CPUStop_Sleep;
ARM7->Halt(2);
}
@@ -2017,7 +2161,7 @@ void debug(u32 param)
// printf("VRAM %c: %02X\n", 'A'+i, GPU::VRAMCNT[i]);
FILE*
- shit = fopen("debug/crayon.bin", "wb");
+ shit = fopen("debug/DSfirmware.bin", "wb");
fwrite(ARM9->ITCM, 0x8000, 1, shit);
for (u32 i = 0x02000000; i < 0x02400000; i+=4)
{
@@ -2942,8 +3086,8 @@ u8 ARM9IORead8(u32 addr)
{
case 0x04000130: LagFrameFlag = false; return KeyInput & 0xFF;
case 0x04000131: LagFrameFlag = false; return (KeyInput >> 8) & 0xFF;
- case 0x04000132: return KeyCnt & 0xFF;
- case 0x04000133: return KeyCnt >> 8;
+ case 0x04000132: return KeyCnt[0] & 0xFF;
+ case 0x04000133: return KeyCnt[0] >> 8;
case 0x040001A2:
if (!(ExMemCnt[0] & (1<<11)))
@@ -3079,7 +3223,7 @@ u16 ARM9IORead16(u32 addr)
case 0x0400010E: return Timers[3].Cnt;
case 0x04000130: LagFrameFlag = false; return KeyInput & 0xFFFF;
- case 0x04000132: return KeyCnt;
+ case 0x04000132: return KeyCnt[0];
case 0x04000180: return IPCSync9;
case 0x04000184:
@@ -3221,7 +3365,7 @@ u32 ARM9IORead32(u32 addr)
case 0x04000108: return TimerGetCounter(2) | (Timers[2].Cnt << 16);
case 0x0400010C: return TimerGetCounter(3) | (Timers[3].Cnt << 16);
- case 0x04000130: LagFrameFlag = false; return (KeyInput & 0xFFFF) | (KeyCnt << 16);
+ case 0x04000130: LagFrameFlag = false; return (KeyInput & 0xFFFF) | (KeyCnt[0] << 16);
case 0x04000180: return IPCSync9;
case 0x04000184: return ARM9IORead16(addr);
@@ -3341,10 +3485,10 @@ void ARM9IOWrite8(u32 addr, u8 val)
case 0x0400106D: GPU::GPU2D_B.Write8(addr, val); return;
case 0x04000132:
- KeyCnt = (KeyCnt & 0xFF00) | val;
+ KeyCnt[0] = (KeyCnt[0] & 0xFF00) | val;
return;
case 0x04000133:
- KeyCnt = (KeyCnt & 0x00FF) | (val << 8);
+ KeyCnt[0] = (KeyCnt[0] & 0x00FF) | (val << 8);
return;
case 0x04000188:
@@ -3454,7 +3598,7 @@ void ARM9IOWrite16(u32 addr, u16 val)
case 0x0400010E: TimerStart(3, val); return;
case 0x04000132:
- KeyCnt = val;
+ KeyCnt[0] = val;
return;
case 0x04000180:
@@ -3647,7 +3791,7 @@ void ARM9IOWrite32(u32 addr, u32 val)
return;
case 0x04000130:
- KeyCnt = val >> 16;
+ KeyCnt[0] = val >> 16;
return;
case 0x04000180:
@@ -3800,8 +3944,8 @@ u8 ARM7IORead8(u32 addr)
{
case 0x04000130: return KeyInput & 0xFF;
case 0x04000131: return (KeyInput >> 8) & 0xFF;
- case 0x04000132: return KeyCnt & 0xFF;
- case 0x04000133: return KeyCnt >> 8;
+ case 0x04000132: return KeyCnt[1] & 0xFF;
+ case 0x04000133: return KeyCnt[1] >> 8;
case 0x04000134: return RCnt & 0xFF;
case 0x04000135: return RCnt >> 8;
case 0x04000136: return (KeyInput >> 16) & 0xFF;
@@ -3894,7 +4038,7 @@ u16 ARM7IORead16(u32 addr)
case 0x0400010E: return Timers[7].Cnt;
case 0x04000130: return KeyInput & 0xFFFF;
- case 0x04000132: return KeyCnt;
+ case 0x04000132: return KeyCnt[1];
case 0x04000134: return RCnt;
case 0x04000136: return KeyInput >> 16;
@@ -3986,8 +4130,8 @@ u32 ARM7IORead32(u32 addr)
case 0x04000108: return TimerGetCounter(6) | (Timers[6].Cnt << 16);
case 0x0400010C: return TimerGetCounter(7) | (Timers[7].Cnt << 16);
- case 0x04000130: return (KeyInput & 0xFFFF) | (KeyCnt << 16);
- case 0x04000134: return RCnt | (KeyCnt & 0xFFFF0000);
+ case 0x04000130: return (KeyInput & 0xFFFF) | (KeyCnt[1] << 16);
+ case 0x04000134: return RCnt | (KeyInput & 0xFFFF0000);
case 0x04000138: return RTC::Read();
case 0x04000180: return IPCSync7;
@@ -4068,10 +4212,10 @@ void ARM7IOWrite8(u32 addr, u8 val)
switch (addr)
{
case 0x04000132:
- KeyCnt = (KeyCnt & 0xFF00) | val;
+ KeyCnt[1] = (KeyCnt[1] & 0xFF00) | val;
return;
case 0x04000133:
- KeyCnt = (KeyCnt & 0x00FF) | (val << 8);
+ KeyCnt[1] = (KeyCnt[1] & 0x00FF) | (val << 8);
return;
case 0x04000134:
RCnt = (RCnt & 0xFF00) | val;
@@ -4165,7 +4309,7 @@ void ARM7IOWrite16(u32 addr, u16 val)
case 0x0400010C: Timers[7].Reload = val; return;
case 0x0400010E: TimerStart(7, val); return;
- case 0x04000132: KeyCnt = val; return;
+ case 0x04000132: KeyCnt[1] = val; return;
case 0x04000134: RCnt = val; return;
case 0x04000138: RTC::Write(val, false); return;
@@ -4334,7 +4478,7 @@ void ARM7IOWrite32(u32 addr, u32 val)
TimerStart(7, val>>16);
return;
- case 0x04000130: KeyCnt = val >> 16; return;
+ case 0x04000130: KeyCnt[1] = val >> 16; return;
case 0x04000134: RCnt = val & 0xFFFF; return;
case 0x04000138: RTC::Write(val & 0xFFFF, false); return;