diff options
Diffstat (limited to 'src/NDS.cpp')
-rw-r--r-- | src/NDS.cpp | 310 |
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; |