From c9a0307878464c13baed2baf808d833ea4860d14 Mon Sep 17 00:00:00 2001 From: iris Date: Fri, 22 May 2026 00:20:17 +0200 Subject: [PATCH] idle skipping works! --- src/backend/Core.cpp | 40 +++++-------------- src/backend/Core.hpp | 7 +--- src/backend/Scheduler.cpp | 9 ++++- src/backend/Scheduler.hpp | 2 + src/backend/core/interpreter/instructions.cpp | 2 + src/backend/core/mmio/PI.cpp | 2 +- src/backend/core/mmio/SI.cpp | 1 - src/frontend/KaizenGui.cpp | 4 +- 8 files changed, 26 insertions(+), 41 deletions(-) diff --git a/src/backend/Core.cpp b/src/backend/Core.cpp index c48f7f4..d674d57 100644 --- a/src/backend/Core.cpp +++ b/src/backend/Core.cpp @@ -96,49 +96,37 @@ void Core::StepRSP(const u32 cpuCycles) { } } +void Core::MaybeIdleSkip() { + if (GetRegs().nextPC == GetRegs().pc) + Scheduler::GetInstance().SkipToNext(); +} + void Core::Run(const float volumeL, const float volumeR) { MMIO &mmio = mem->mmio; bool broken = false; for (int field = 0; field < mmio.vi.numFields; field++) { + Scheduler::GetInstance().HandleEvents(); u32 frameCycles = 0; - for (int i = 0; i < mmio.vi.numHalflines; i++) { - mmio.vi.current = (i << 1) + field; + for (int halfline = 0; halfline < mmio.vi.numHalflines; halfline++) { + mmio.vi.current = (halfline << 1) + field; if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { mmio.mi.InterruptRaise(MI::Interrupt::VI); } - while (cycles < mem->mmio.vi.cyclesPerHalfline) { - if (IsAnythingSkippable()) { - const u32 taken = Scheduler::GetInstance().events.top().time - Scheduler::GetInstance().ticks; - cycles += taken; - frameCycles += taken; - Scheduler::GetInstance().Tick(taken); - isReadingAnyIO = false; - continue; - } + for (int cycles = 0; cycles < mem->mmio.vi.cyclesPerHalfline;) { + Scheduler::GetInstance().HandleEvents(); const u32 taken = StepCPU(); cycles += taken; - if ((broken = breakpoints.contains(regs.nextPC))) - break; - StepRSP(taken); frameCycles += taken; Scheduler::GetInstance().Tick(taken); } - - if (broken) - break; - - cycles -= mmio.vi.cyclesPerHalfline; } - if (broken) - break; - if ((mmio.vi.current & 0x3FE) == mmio.vi.intr) { mmio.mi.InterruptRaise(MI::Interrupt::VI); } @@ -146,13 +134,5 @@ void Core::Run(const float volumeL, const float volumeR) { mmio.ai.Step(frameCycles, volumeL, volumeR); Scheduler::GetInstance().Tick(frameCycles); } - - if (broken) - pause = true; -} - -bool Core::IsAnythingSkippable() { - MMIO &mmio = mem->mmio; - return (mmio.si.status.dmaBusy || mmio.pi.dmaBusy || mmio.pi.ioBusy) && isReadingAnyIO; } } // namespace n64 diff --git a/src/backend/Core.hpp b/src/backend/Core.hpp index 83a8ac5..3777177 100644 --- a/src/backend/Core.hpp +++ b/src/backend/Core.hpp @@ -19,8 +19,7 @@ struct Core { return instance; } - static void SetIdleSkippingStatus(bool v) { GetInstance().isReadingAnyIO = v; } - + static void MaybeIdleSkip(); static Registers &GetRegs() { return GetInstance().regs; } static Mem &GetMem() { return *GetInstance().mem; } @@ -45,7 +44,6 @@ struct Core { bool pause = true; bool romLoaded = false; int slot = 0; - u32 cycles = 0; size_t memSize{}, cpuSize{}, verSize{}; std::string rom; std::set breakpoints{}; @@ -59,8 +57,5 @@ struct Core { #endif Interpreter interpreter; ParallelRDP parallel; - - bool isReadingAnyIO = false; - bool IsAnythingSkippable(); }; } // namespace n64 diff --git a/src/backend/Scheduler.cpp b/src/backend/Scheduler.cpp index 208aedc..bb3db01 100644 --- a/src/backend/Scheduler.cpp +++ b/src/backend/Scheduler.cpp @@ -27,9 +27,16 @@ u64 Scheduler::Remove(const EventType eventType) const { return ret; } +void Scheduler::SkipToNext() { + ticks = events.top().time; +} + void Scheduler::Tick(const u64 t) { - n64::Mem &mem = n64::Core::GetMem(); ticks += t; +} + +void Scheduler::HandleEvents() { + n64::Mem &mem = n64::Core::GetMem(); n64::MI &mi = mem.mmio.mi; n64::SI &si = mem.mmio.si; n64::PI &pi = mem.mmio.pi; diff --git a/src/backend/Scheduler.hpp b/src/backend/Scheduler.hpp index d88d501..51e43d5 100644 --- a/src/backend/Scheduler.hpp +++ b/src/backend/Scheduler.hpp @@ -35,11 +35,13 @@ struct Scheduler { return instance; } + void HandleEvents(); void EnqueueRelative(u64, EventType); void EnqueueAbsolute(u64, EventType); [[nodiscard]] u64 Remove(EventType) const; [[nodiscard]] Event *Find(EventType) const; void Tick(u64 t); + void SkipToNext(); u8 index = 0; u64 ticks = 0; diff --git a/src/backend/core/interpreter/instructions.cpp b/src/backend/core/interpreter/instructions.cpp index 9c79db0..983b8a8 100644 --- a/src/backend/core/interpreter/instructions.cpp +++ b/src/backend/core/interpreter/instructions.cpp @@ -140,6 +140,7 @@ void Interpreter::branch(const bool cond, const s64 address) { regs.delaySlot = true; if (cond) { regs.nextPC = address; + Core::MaybeIdleSkip(); } } @@ -147,6 +148,7 @@ void Interpreter::branch_likely(const bool cond, const s64 address) { if (cond) { regs.delaySlot = true; regs.nextPC = address; + Core::MaybeIdleSkip(); } else { regs.SetPC64(regs.nextPC); } diff --git a/src/backend/core/mmio/PI.cpp b/src/backend/core/mmio/PI.cpp index 43c0a1e..c9eb2b8 100644 --- a/src/backend/core/mmio/PI.cpp +++ b/src/backend/core/mmio/PI.cpp @@ -425,7 +425,6 @@ auto PI::Read(u32 addr) const -> u32 { return wrLen; case 0x04600010: { - Core::SetIdleSkippingStatus(true); u32 value = 0; value |= (dmaBusy << 0); // Is PI DMA active? value |= (ioBusy << 1); // Is PI IO busy? @@ -433,6 +432,7 @@ auto PI::Read(u32 addr) const -> u32 { value |= (mem.mmio.mi.intr.pi << 3); // PI interrupt? return value; } + case 0x04600034: case 0x04600014: return piBsdDom1Lat; case 0x04600018: diff --git a/src/backend/core/mmio/SI.cpp b/src/backend/core/mmio/SI.cpp index f4ff64a..9a35327 100644 --- a/src/backend/core/mmio/SI.cpp +++ b/src/backend/core/mmio/SI.cpp @@ -24,7 +24,6 @@ auto SI::Read(u32 addr) const -> u32 { return 0; case 0x04800018: { - Core::SetIdleSkippingStatus(true); u32 val = 0; val |= status.dmaBusy; val |= (0 << 1); diff --git a/src/frontend/KaizenGui.cpp b/src/frontend/KaizenGui.cpp index dd4f4d8..3d9fb36 100644 --- a/src/frontend/KaizenGui.cpp +++ b/src/frontend/KaizenGui.cpp @@ -442,7 +442,7 @@ void KaizenGui::run() { case SDL_EVENT_WINDOW_RESTORED: minimized = false; break; - default: + default: break; } QueryDevices(e); HandleInput(e); @@ -457,4 +457,4 @@ void KaizenGui::run() { void KaizenGui::LoadTAS(const std::string &path) noexcept { n64::Core::GetInstance().LoadTAS(fs::path(path)); -} \ No newline at end of file +}