From 498e2f178b259065608614a5757e385cea4f00f6 Mon Sep 17 00:00:00 2001 From: Arisotura Date: Mon, 30 Oct 2023 17:30:59 +0100 Subject: [PATCH] start refining sleep mode. code still kinda sucks. --- src/DSi.cpp | 8 +- src/NDS.cpp | 266 +++++++++++++++++++++++++++++++++++++--------------- src/NDS.h | 27 ++++++ src/SPU.cpp | 2 +- 4 files changed, 220 insertions(+), 83 deletions(-) diff --git a/src/DSi.cpp b/src/DSi.cpp index 15160b29..17bfb8ff 100644 --- a/src/DSi.cpp +++ b/src/DSi.cpp @@ -959,10 +959,10 @@ void RunNDMAs(u32 cpu) { if (NDS::ARM9Timestamp >= NDS::ARM9Target) return; - if (!(NDS::CPUStop & 0x80000000)) NDMAs[0]->Run(); - if (!(NDS::CPUStop & 0x80000000)) NDMAs[1]->Run(); - if (!(NDS::CPUStop & 0x80000000)) NDMAs[2]->Run(); - if (!(NDS::CPUStop & 0x80000000)) NDMAs[3]->Run(); + if (!(NDS::CPUStop & NDS::CPUStop_GXStall)) NDMAs[0]->Run(); + if (!(NDS::CPUStop & NDS::CPUStop_GXStall)) NDMAs[1]->Run(); + if (!(NDS::CPUStop & NDS::CPUStop_GXStall)) NDMAs[2]->Run(); + if (!(NDS::CPUStop & NDS::CPUStop_GXStall)) NDMAs[3]->Run(); } else { diff --git a/src/NDS.cpp b/src/NDS.cpp index fb7ed20d..763ba59a 100644 --- a/src/NDS.cpp +++ b/src/NDS.cpp @@ -1060,93 +1060,193 @@ void RunSystem(u64 timestamp) } } +u64 NextTargetSleep() +{ + u64 minEvent = UINT64_MAX; + + u32 mask = SchedListMask; + for (int i = 0; i < Event_MAX; i++) + { + if (!mask) break; + if (i == Event_SPU || i == Event_RTC) + { + if (mask & 0x1) + { + if (SchedList[i].Timestamp < minEvent) + minEvent = SchedList[i].Timestamp; + } + } + + mask >>= 1; + } + + return minEvent; +} + +void RunSystemSleep(u64 timestamp) +{ + u64 offset = timestamp - SysTimestamp; + SysTimestamp = timestamp; + + u32 mask = SchedListMask; + for (int i = 0; i < Event_MAX; i++) + { + if (!mask) break; + if (i == Event_SPU || i == Event_RTC) + { + if (mask & 0x1) + { + if (SchedList[i].Timestamp <= SysTimestamp) + { + SchedListMask &= ~(1<>= 1; + } +} + template u32 RunFrame() { FrameStartTimestamp = SysTimestamp; LagFrameFlag = true; - bool runFrame = Running && !(CPUStop & 0x40000000); - if (runFrame) + bool runFrame = Running && !(CPUStop & CPUStop_Sleep); + while (Running) { - ARM9->CheckGdbIncoming(); - ARM7->CheckGdbIncoming(); + u64 frametarget = SysTimestamp + 560190; - GPU::StartFrame(); - - while (Running && GPU::TotalScanlines==0) + if (CPUStop & CPUStop_Sleep) { - u64 target = NextTarget(); - ARM9Target = target << ARM9ClockShift; - CurCPU = 0; + // 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 - if (CPUStop & 0x80000000) + while (Running && (SysTimestamp < frametarget)) { - // GXFIFO stall - s32 cycles = GPU3D::CyclesToRunFor(); + u64 target = NextTargetSleep(); + if (target > frametarget) + target = frametarget; - ARM9Timestamp = std::min(ARM9Target, ARM9Timestamp+(cycles<Run(); - if (!(CPUStop & 0x80000000)) DMAs[1]->Run(); - if (!(CPUStop & 0x80000000)) DMAs[2]->Run(); - if (!(CPUStop & 0x80000000)) DMAs[3]->Run(); - if (ConsoleType == 1) DSi::RunNDMAs(0); - } - else - { -#ifdef JIT_ENABLED - if (EnableJIT) - ARM9->ExecuteJIT(); - else -#endif - ARM9->Execute(); + 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(); - - target = ARM9Timestamp >> ARM9ClockShift; - CurCPU = 1; - - while (ARM7Timestamp < target) - { - ARM7Target = target; // might be changed by a reschedule - - if (CPUStop & 0x0FFF0000) - { - DMAs[4]->Run(); - DMAs[5]->Run(); - DMAs[6]->Run(); - DMAs[7]->Run(); - if (ConsoleType == 1) DSi::RunNDMAs(1); - } - else - { -#ifdef JIT_ENABLED - if (EnableJIT) - ARM7->ExecuteJIT(); - else -#endif - ARM7->Execute(); - } - - RunTimers(1); - } - - RunSystem(target); - - if (CPUStop & 0x40000000) - { - // checkme: when is sleep mode effective? - CancelEvent(Event_LCD); + if (SysTimestamp >= frametarget) GPU::TotalScanlines = 263; - break; + } + else + { + ARM9->CheckGdbIncoming(); + ARM7->CheckGdbIncoming(); + + if (!(CPUStop & CPUStop_Wakeup)) + { + GPU::StartFrame(); + } + CPUStop &= ~CPUStop_Wakeup; + + while (Running && GPU::TotalScanlines==0) + { + u64 target = NextTarget(); + ARM9Target = target << ARM9ClockShift; + CurCPU = 0; + + if (CPUStop & CPUStop_GXStall) + { + // GXFIFO stall + s32 cycles = GPU3D::CyclesToRunFor(); + + ARM9Timestamp = std::min(ARM9Target, ARM9Timestamp+(cycles<Run(); + if (!(CPUStop & CPUStop_GXStall)) DMAs[1]->Run(); + if (!(CPUStop & CPUStop_GXStall)) DMAs[2]->Run(); + if (!(CPUStop & CPUStop_GXStall)) DMAs[3]->Run(); + if (ConsoleType == 1) DSi::RunNDMAs(0); + } + else + { + #ifdef JIT_ENABLED + if (EnableJIT) + ARM9->ExecuteJIT(); + else + #endif + ARM9->Execute(); + } + + RunTimers(0); + GPU3D::Run(); + + target = ARM9Timestamp >> ARM9ClockShift; + CurCPU = 1; + + while (ARM7Timestamp < target) + { + ARM7Target = target; // might be changed by a reschedule + + if (CPUStop & CPUStop_DMA7) + { + DMAs[4]->Run(); + DMAs[5]->Run(); + DMAs[6]->Run(); + DMAs[7]->Run(); + 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) + { + // checkme: when is sleep mode effective? + //CancelEvent(Event_LCD); + //GPU::TotalScanlines = 263; + 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, @@ -1155,15 +1255,17 @@ u32 RunFrame() GPU3D::Timestamp-SysTimestamp); #endif SPU::TransferOutput(); + break; } +printf("FRAME %08X %d %016llX\n", CPUStop, GPU::TotalScanlines, SysTimestamp-FrameStartTimestamp); // In the context of TASes, frame count is traditionally the primary measure of emulated time, // so it needs to be tracked even if NDS is powered off. NumFrames++; if (LagFrameFlag) NumLagFrames++; - if (runFrame) + if (Running) return GPU::TotalScanlines; else return 263; @@ -1302,8 +1404,6 @@ void SetLidClosed(bool closed) { KeyInput &= ~(1<<23); SetIRQ(1, IRQ_LidOpen); - CPUStop &= ~0x40000000; - GPU3D::RestartFrame(); } } @@ -1468,6 +1568,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) @@ -1527,9 +1637,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 @@ -1544,14 +1654,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); } @@ -2018,7 +2128,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) { diff --git a/src/NDS.h b/src/NDS.h index a22c2d8b..de038b2b 100644 --- a/src/NDS.h +++ b/src/NDS.h @@ -123,6 +123,33 @@ enum IRQ2_DSi_MicExt }; +enum +{ + CPUStop_DMA9_0 = (1<<0), + CPUStop_DMA9_1 = (1<<1), + CPUStop_DMA9_2 = (1<<2), + CPUStop_DMA9_3 = (1<<3), + CPUStop_NDMA9_0 = (1<<4), + CPUStop_NDMA9_1 = (1<<5), + CPUStop_NDMA9_2 = (1<<6), + CPUStop_NDMA9_3 = (1<<7), + CPUStop_DMA9 = 0xFFF, + + CPUStop_DMA7_0 = (1<<16), + CPUStop_DMA7_1 = (1<<17), + CPUStop_DMA7_2 = (1<<18), + CPUStop_DMA7_3 = (1<<19), + CPUStop_NDMA7_0 = (1<<20), + CPUStop_NDMA7_1 = (1<<21), + CPUStop_NDMA7_2 = (1<<22), + CPUStop_NDMA7_3 = (1<<23), + CPUStop_DMA7 = (0xFFF<<16), + + CPUStop_Wakeup = (1<<29), + CPUStop_Sleep = (1<<30), + CPUStop_GXStall = (1<<31), +}; + struct Timer { u16 Reload; diff --git a/src/SPU.cpp b/src/SPU.cpp index 3939aef7..8148bac2 100644 --- a/src/SPU.cpp +++ b/src/SPU.cpp @@ -726,7 +726,7 @@ void Mix(u32 dummy) s32 left = 0, right = 0; s32 leftoutput = 0, rightoutput = 0; - if (Cnt & (1<<15)) + if ((Cnt & (1<<15)) && (!dummy)) { s32 ch0 = Channels[0]->DoRun(); s32 ch1 = Channels[1]->DoRun();