From c9558ecb4ca582bbacd931e41bb1660b69956e4b Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 26 Nov 2022 09:29:46 +0100 Subject: [PATCH 1/2] CoreTiming: Refactor to class. --- Source/Core/Core/Core.cpp | 5 +- Source/Core/Core/CoreTiming.cpp | 282 +++++++----------- Source/Core/Core/CoreTiming.h | 189 +++++++----- .../Core/DSP/Interpreter/DSPInterpreter.cpp | 3 +- Source/Core/Core/FifoPlayer/FifoPlayer.cpp | 15 +- Source/Core/Core/HW/AudioInterface.cpp | 38 ++- Source/Core/Core/HW/DSP.cpp | 23 +- Source/Core/Core/HW/DSPHLE/DSPHLE.cpp | 3 +- Source/Core/Core/HW/DVD/DVDInterface.cpp | 80 ++--- Source/Core/Core/HW/DVD/DVDThread.cpp | 15 +- Source/Core/Core/HW/EXI/EXI.cpp | 16 +- Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp | 6 +- .../Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp | 28 +- Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp | 5 +- Source/Core/Core/HW/HW.cpp | 5 +- Source/Core/Core/HW/ProcessorInterface.cpp | 22 +- Source/Core/Core/HW/SI/SI.cpp | 35 ++- Source/Core/Core/HW/SI/SI_DeviceGBA.cpp | 15 +- Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp | 11 +- .../Core/Core/HW/SI/SI_DeviceGCController.cpp | 5 +- Source/Core/Core/HW/SystemTimers.cpp | 86 +++--- Source/Core/Core/HW/VideoInterface.cpp | 8 +- Source/Core/Core/HW/WII_IPC.cpp | 21 +- Source/Core/Core/IOS/DI/DI.cpp | 4 +- Source/Core/Core/IOS/ES/ES.cpp | 27 +- Source/Core/Core/IOS/IOS.cpp | 36 ++- Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp | 3 +- Source/Core/Core/Movie.cpp | 11 +- .../CachedInterpreter/CachedInterpreter.cpp | 10 +- Source/Core/Core/PowerPC/GDBStub.cpp | 9 +- .../Core/PowerPC/Interpreter/Interpreter.cpp | 6 +- Source/Core/Core/PowerPC/Jit64/Jit.cpp | 5 +- Source/Core/Core/PowerPC/Jit64/JitAsm.cpp | 2 +- Source/Core/Core/PowerPC/JitArm64/Jit.cpp | 3 +- .../Core/PowerPC/JitArm64/JitArm64_Branch.cpp | 6 +- Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp | 2 +- Source/Core/Core/PowerPC/PowerPC.cpp | 9 +- Source/Core/Core/State.cpp | 3 +- Source/Core/Core/System.cpp | 6 +- Source/Core/Core/System.h | 4 +- Source/Core/DolphinQt/GBAWidget.cpp | 6 +- Source/Core/InputCommon/GCAdapter.cpp | 7 +- Source/Core/VideoCommon/BPStructs.cpp | 4 +- Source/Core/VideoCommon/CommandProcessor.cpp | 12 +- Source/Core/VideoCommon/Fifo.cpp | 11 +- Source/Core/VideoCommon/PixelEngine.cpp | 7 +- Source/UnitTests/Core/CoreTimingTest.cpp | 175 ++++++----- 47 files changed, 718 insertions(+), 566 deletions(-) diff --git a/Source/Core/Core/Core.cpp b/Source/Core/Core/Core.cpp index 097432cc94..17eced199b 100644 --- a/Source/Core/Core/Core.cpp +++ b/Source/Core/Core/Core.cpp @@ -926,8 +926,9 @@ void UpdateTitle(u64 elapsed_ms) // interested. static u64 ticks = 0; static u64 idleTicks = 0; - u64 newTicks = CoreTiming::GetTicks(); - u64 newIdleTicks = CoreTiming::GetIdleTicks(); + auto& core_timing = Core::System::GetInstance().GetCoreTiming(); + u64 newTicks = core_timing.GetTicks(); + u64 newIdleTicks = core_timing.GetIdleTicks(); u64 diff = (newTicks - ticks) / 1000000; u64 idleDiff = (newIdleTicks - idleTicks) / 1000000; diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 261b5b55e6..4d28e65f32 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -26,20 +26,6 @@ namespace CoreTiming { -struct EventType -{ - TimedCallback callback; - const std::string* name; -}; - -struct Event -{ - s64 time; - u64 fifo_order; - u64 userdata; - EventType* type; -}; - // Sort by time, unless the times are the same, in which case sort by the order added to the queue static bool operator>(const Event& left, const Event& right) { @@ -52,45 +38,6 @@ static bool operator<(const Event& left, const Event& right) static constexpr int MAX_SLICE_LENGTH = 20000; -struct CoreTimingState::Data -{ - // unordered_map stores each element separately as a linked list node so pointers to elements - // remain stable regardless of rehashes/resizing. - std::unordered_map event_types; - - // STATE_TO_SAVE - // The queue is a min-heap using std::make_heap/push_heap/pop_heap. - // We don't use std::priority_queue because we need to be able to serialize, unserialize and - // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated - // by the standard adaptor class. - std::vector event_queue; - u64 event_fifo_id; - std::mutex ts_write_lock; - Common::SPSCQueue ts_queue; - - float last_oc_factor; - - s64 idled_cycles; - u32 fake_dec_start_value; - u64 fake_dec_start_ticks; - - // Are we in a function that has been called from Advance() - bool is_global_timer_sane; - - EventType* ev_lost = nullptr; - - size_t registered_config_callback_id; - float config_oc_factor; - float config_oc_inv_factor; - bool config_sync_on_skip_idle; -}; - -CoreTimingState::CoreTimingState() : m_data(std::make_unique()) -{ -} - -CoreTimingState::~CoreTimingState() = default; - static void EmptyTimedCallback(Core::System& system, u64 userdata, s64 cyclesLate) { } @@ -107,104 +54,96 @@ static int DowncountToCycles(CoreTiming::Globals& g, int downcount) return static_cast(downcount * g.last_OC_factor_inverted); } -static int CyclesToDowncount(CoreTiming::CoreTimingState::Data& state, int cycles) +int CoreTimingManager::CyclesToDowncount(int cycles) const { - return static_cast(cycles * state.last_oc_factor); + return static_cast(cycles * m_last_oc_factor); } -EventType* RegisterEvent(const std::string& name, TimedCallback callback) +EventType* CoreTimingManager::RegisterEvent(const std::string& name, TimedCallback callback) { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - // check for existing type with same name. // we want event type names to remain unique so that we can use them for serialization. - ASSERT_MSG(POWERPC, state.event_types.find(name) == state.event_types.end(), + ASSERT_MSG(POWERPC, m_event_types.find(name) == m_event_types.end(), "CoreTiming Event \"{}\" is already registered. Events should only be registered " "during Init to avoid breaking save states.", name); - auto info = state.event_types.emplace(name, EventType{callback, nullptr}); + auto info = m_event_types.emplace(name, EventType{callback, nullptr}); EventType* event_type = &info.first->second; event_type->name = &info.first->first; return event_type; } -void UnregisterAllEvents() +void CoreTimingManager::UnregisterAllEvents() { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - - ASSERT_MSG(POWERPC, state.event_queue.empty(), "Cannot unregister events with events pending"); - state.event_types.clear(); + ASSERT_MSG(POWERPC, m_event_queue.empty(), "Cannot unregister events with events pending"); + m_event_types.clear(); } -void Init() +void CoreTimingManager::Init() { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); - state.registered_config_callback_id = - Config::AddConfigChangedCallback([]() { Core::RunAsCPUThread([]() { RefreshConfig(); }); }); + m_registered_config_callback_id = Config::AddConfigChangedCallback( + [this]() { Core::RunAsCPUThread([this]() { RefreshConfig(); }); }); RefreshConfig(); - state.last_oc_factor = state.config_oc_factor; - g.last_OC_factor_inverted = state.config_oc_inv_factor; - PowerPC::ppcState.downcount = CyclesToDowncount(state, MAX_SLICE_LENGTH); + m_last_oc_factor = m_config_oc_factor; + g.last_OC_factor_inverted = m_config_oc_inv_factor; + PowerPC::ppcState.downcount = CyclesToDowncount(MAX_SLICE_LENGTH); g.slice_length = MAX_SLICE_LENGTH; g.global_timer = 0; - state.idled_cycles = 0; + m_idled_cycles = 0; // The time between CoreTiming being intialized and the first call to Advance() is considered // the slice boundary between slice -1 and slice 0. Dispatcher loops must call Advance() before // executing the first PPC cycle of each slice to prepare the slice length and downcount for // that slice. - state.is_global_timer_sane = true; + m_is_global_timer_sane = true; - state.event_fifo_id = 0; - state.ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback); + m_event_fifo_id = 0; + m_ev_lost = RegisterEvent("_lost_event", &EmptyTimedCallback); } -void Shutdown() +void CoreTimingManager::Shutdown() { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - std::lock_guard lk(state.ts_write_lock); + std::lock_guard lk(m_ts_write_lock); MoveEvents(); ClearPendingEvents(); UnregisterAllEvents(); - Config::RemoveConfigChangedCallback(state.registered_config_callback_id); + Config::RemoveConfigChangedCallback(m_registered_config_callback_id); } -void RefreshConfig() +void CoreTimingManager::RefreshConfig() { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - state.config_oc_factor = + m_config_oc_factor = Config::Get(Config::MAIN_OVERCLOCK_ENABLE) ? Config::Get(Config::MAIN_OVERCLOCK) : 1.0f; - state.config_oc_inv_factor = 1.0f / state.config_oc_factor; - state.config_sync_on_skip_idle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE); + m_config_oc_inv_factor = 1.0f / m_config_oc_factor; + m_config_sync_on_skip_idle = Config::Get(Config::MAIN_SYNC_ON_SKIP_IDLE); } -void DoState(PointerWrap& p) +void CoreTimingManager::DoState(PointerWrap& p) { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); - std::lock_guard lk(state.ts_write_lock); + std::lock_guard lk(m_ts_write_lock); p.Do(g.slice_length); p.Do(g.global_timer); - p.Do(state.idled_cycles); - p.Do(state.fake_dec_start_value); - p.Do(state.fake_dec_start_ticks); + p.Do(m_idled_cycles); + p.Do(m_fake_dec_start_value); + p.Do(m_fake_dec_start_ticks); p.Do(g.fake_TB_start_value); p.Do(g.fake_TB_start_ticks); - p.Do(state.last_oc_factor); - g.last_OC_factor_inverted = 1.0f / state.last_oc_factor; - p.Do(state.event_fifo_id); + p.Do(m_last_oc_factor); + g.last_OC_factor_inverted = 1.0f / m_last_oc_factor; + p.Do(m_event_fifo_id); p.DoMarker("CoreTimingData"); MoveEvents(); - p.DoEachElement(state.event_queue, [&state](PointerWrap& pw, Event& ev) { + p.DoEachElement(m_event_queue, [this](PointerWrap& pw, Event& ev) { pw.Do(ev.time); pw.Do(ev.fifo_order); @@ -221,8 +160,8 @@ void DoState(PointerWrap& p) pw.Do(name); if (pw.IsReadMode()) { - auto itr = state.event_types.find(name); - if (itr != state.event_types.end()) + auto itr = m_event_types.find(name); + if (itr != m_event_types.end()) { ev.type = &itr->second; } @@ -231,7 +170,7 @@ void DoState(PointerWrap& p) WARN_LOG_FMT(POWERPC, "Lost event from savestate because its type, \"{}\", has not been registered.", name); - ev.type = state.ev_lost; + ev.type = m_ev_lost; } } }); @@ -241,19 +180,18 @@ void DoState(PointerWrap& p) // The exact layout of the heap in memory is implementation defined, therefore it is platform // and library version specific. if (p.IsReadMode()) - std::make_heap(state.event_queue.begin(), state.event_queue.end(), std::greater()); + std::make_heap(m_event_queue.begin(), m_event_queue.end(), std::greater()); } // This should only be called from the CPU thread. If you are calling // it from any other thread, you are doing something evil -u64 GetTicks() +u64 CoreTimingManager::GetTicks() const { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); u64 ticks = static_cast(g.global_timer); - if (!state.is_global_timer_sane) + if (!m_is_global_timer_sane) { int downcount = DowncountToCycles(g, PowerPC::ppcState.downcount); ticks += g.slice_length - downcount; @@ -261,24 +199,22 @@ u64 GetTicks() return ticks; } -u64 GetIdleTicks() +u64 CoreTimingManager::GetIdleTicks() const { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - return static_cast(state.idled_cycles); + return static_cast(m_idled_cycles); } -void ClearPendingEvents() +void CoreTimingManager::ClearPendingEvents() { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - state.event_queue.clear(); + m_event_queue.clear(); } -void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata, FromThread from) +void CoreTimingManager::ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata, + FromThread from) { ASSERT_MSG(POWERPC, event_type, "Event type is nullptr, will crash now."); auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); bool from_cpu_thread; @@ -299,11 +235,11 @@ void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata, s64 timeout = GetTicks() + cycles_into_future; // If this event needs to be scheduled before the next advance(), force one early - if (!state.is_global_timer_sane) + if (!m_is_global_timer_sane) ForceExceptionCheck(cycles_into_future); - state.event_queue.emplace_back(Event{timeout, state.event_fifo_id++, userdata, event_type}); - std::push_heap(state.event_queue.begin(), state.event_queue.end(), std::greater()); + m_event_queue.emplace_back(Event{timeout, m_event_fifo_id++, userdata, event_type}); + std::push_heap(m_event_queue.begin(), m_event_queue.end(), std::greater()); } else { @@ -315,36 +251,33 @@ void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata, *event_type->name); } - std::lock_guard lk(state.ts_write_lock); - state.ts_queue.Push(Event{g.global_timer + cycles_into_future, 0, userdata, event_type}); + std::lock_guard lk(m_ts_write_lock); + m_ts_queue.Push(Event{g.global_timer + cycles_into_future, 0, userdata, event_type}); } } -void RemoveEvent(EventType* event_type) +void CoreTimingManager::RemoveEvent(EventType* event_type) { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - - auto itr = std::remove_if(state.event_queue.begin(), state.event_queue.end(), + auto itr = std::remove_if(m_event_queue.begin(), m_event_queue.end(), [&](const Event& e) { return e.type == event_type; }); // Removing random items breaks the invariant so we have to re-establish it. - if (itr != state.event_queue.end()) + if (itr != m_event_queue.end()) { - state.event_queue.erase(itr, state.event_queue.end()); - std::make_heap(state.event_queue.begin(), state.event_queue.end(), std::greater()); + m_event_queue.erase(itr, m_event_queue.end()); + std::make_heap(m_event_queue.begin(), m_event_queue.end(), std::greater()); } } -void RemoveAllEvents(EventType* event_type) +void CoreTimingManager::RemoveAllEvents(EventType* event_type) { MoveEvents(); RemoveEvent(event_type); } -void ForceExceptionCheck(s64 cycles) +void CoreTimingManager::ForceExceptionCheck(s64 cycles) { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); cycles = std::max(0, cycles); @@ -353,55 +286,53 @@ void ForceExceptionCheck(s64 cycles) // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here. // Account for cycles already executed by adjusting the g.slice_length g.slice_length -= DowncountToCycles(g, PowerPC::ppcState.downcount) - static_cast(cycles); - PowerPC::ppcState.downcount = CyclesToDowncount(state, static_cast(cycles)); + PowerPC::ppcState.downcount = CyclesToDowncount(static_cast(cycles)); } } -void MoveEvents() +void CoreTimingManager::MoveEvents() { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - for (Event ev; state.ts_queue.Pop(ev);) + for (Event ev; m_ts_queue.Pop(ev);) { - ev.fifo_order = state.event_fifo_id++; - state.event_queue.emplace_back(std::move(ev)); - std::push_heap(state.event_queue.begin(), state.event_queue.end(), std::greater()); + ev.fifo_order = m_event_fifo_id++; + m_event_queue.emplace_back(std::move(ev)); + std::push_heap(m_event_queue.begin(), m_event_queue.end(), std::greater()); } } -void Advance() +void CoreTimingManager::Advance() { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); MoveEvents(); int cyclesExecuted = g.slice_length - DowncountToCycles(g, PowerPC::ppcState.downcount); g.global_timer += cyclesExecuted; - state.last_oc_factor = state.config_oc_factor; - g.last_OC_factor_inverted = state.config_oc_inv_factor; + m_last_oc_factor = m_config_oc_factor; + g.last_OC_factor_inverted = m_config_oc_inv_factor; g.slice_length = MAX_SLICE_LENGTH; - state.is_global_timer_sane = true; + m_is_global_timer_sane = true; - while (!state.event_queue.empty() && state.event_queue.front().time <= g.global_timer) + while (!m_event_queue.empty() && m_event_queue.front().time <= g.global_timer) { - Event evt = std::move(state.event_queue.front()); - std::pop_heap(state.event_queue.begin(), state.event_queue.end(), std::greater()); - state.event_queue.pop_back(); + Event evt = std::move(m_event_queue.front()); + std::pop_heap(m_event_queue.begin(), m_event_queue.end(), std::greater()); + m_event_queue.pop_back(); evt.type->callback(system, evt.userdata, g.global_timer - evt.time); } - state.is_global_timer_sane = false; + m_is_global_timer_sane = false; // Still events left (scheduled in the future) - if (!state.event_queue.empty()) + if (!m_event_queue.empty()) { g.slice_length = static_cast( - std::min(state.event_queue.front().time - g.global_timer, MAX_SLICE_LENGTH)); + std::min(m_event_queue.front().time - g.global_timer, MAX_SLICE_LENGTH)); } - PowerPC::ppcState.downcount = CyclesToDowncount(state, g.slice_length); + PowerPC::ppcState.downcount = CyclesToDowncount(g.slice_length); // Check for any external exceptions. // It's important to do this after processing events otherwise any exceptions will be delayed @@ -410,13 +341,12 @@ void Advance() PowerPC::CheckExternalExceptions(); } -void LogPendingEvents() +void CoreTimingManager::LogPendingEvents() const { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); - auto clone = state.event_queue; + auto clone = m_event_queue; std::sort(clone.begin(), clone.end()); for (const Event& ev : clone) { @@ -426,26 +356,24 @@ void LogPendingEvents() } // Should only be called from the CPU thread after the PPC clock has changed -void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock) +void CoreTimingManager::AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock) { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); - for (Event& ev : state.event_queue) + for (Event& ev : m_event_queue) { const s64 ticks = (ev.time - g.global_timer) * new_ppc_clock / old_ppc_clock; ev.time = g.global_timer + ticks; } } -void Idle() +void CoreTimingManager::Idle() { auto& system = Core::System::GetInstance(); - auto& state = system.GetCoreTimingState().GetData(); auto& g = system.GetCoreTimingGlobals(); - if (state.config_sync_on_skip_idle) + if (m_config_sync_on_skip_idle) { // When the FIFO is processing data we must not advance because in this way // the VI will be desynchronized. So, We are waiting until the FIFO finish and @@ -454,18 +382,16 @@ void Idle() } PowerPC::UpdatePerformanceMonitor(PowerPC::ppcState.downcount, 0, 0); - state.idled_cycles += DowncountToCycles(g, PowerPC::ppcState.downcount); + m_idled_cycles += DowncountToCycles(g, PowerPC::ppcState.downcount); PowerPC::ppcState.downcount = 0; } -std::string GetScheduledEventsSummary() +std::string CoreTimingManager::GetScheduledEventsSummary() const { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - std::string text = "Scheduled events\n"; text.reserve(1000); - auto clone = state.event_queue; + auto clone = m_event_queue; std::sort(clone.begin(), clone.end()); for (const Event& ev : clone) { @@ -474,52 +400,58 @@ std::string GetScheduledEventsSummary() return text; } -u32 GetFakeDecStartValue() +u32 CoreTimingManager::GetFakeDecStartValue() const { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - return state.fake_dec_start_value; + return m_fake_dec_start_value; } -void SetFakeDecStartValue(u32 val) +void CoreTimingManager::SetFakeDecStartValue(u32 val) { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - state.fake_dec_start_value = val; + m_fake_dec_start_value = val; } -u64 GetFakeDecStartTicks() +u64 CoreTimingManager::GetFakeDecStartTicks() const { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - return state.fake_dec_start_ticks; + return m_fake_dec_start_ticks; } -void SetFakeDecStartTicks(u64 val) +void CoreTimingManager::SetFakeDecStartTicks(u64 val) { - auto& state = Core::System::GetInstance().GetCoreTimingState().GetData(); - state.fake_dec_start_ticks = val; + m_fake_dec_start_ticks = val; } -u64 GetFakeTBStartValue() +u64 CoreTimingManager::GetFakeTBStartValue() const { auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); return g.fake_TB_start_value; } -void SetFakeTBStartValue(u64 val) +void CoreTimingManager::SetFakeTBStartValue(u64 val) { auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); g.fake_TB_start_value = val; } -u64 GetFakeTBStartTicks() +u64 CoreTimingManager::GetFakeTBStartTicks() const { auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); return g.fake_TB_start_ticks; } -void SetFakeTBStartTicks(u64 val) +void CoreTimingManager::SetFakeTBStartTicks(u64 val) { auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); g.fake_TB_start_ticks = val; } +void GlobalAdvance() +{ + Core::System::GetInstance().GetCoreTiming().Advance(); +} + +void GlobalIdle() +{ + Core::System::GetInstance().GetCoreTiming().Idle(); +} + } // namespace CoreTiming diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index 41360598f0..c0a4d53056 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -16,10 +16,13 @@ // inside callback: // ScheduleEvent(periodInCycles - cyclesLate, callback, "whatever") -#include +#include #include +#include +#include #include "Common/CommonTypes.h" +#include "Common/SPSCQueue.h" class PointerWrap; @@ -30,55 +33,31 @@ class System; namespace CoreTiming { -class CoreTimingState -{ -public: - CoreTimingState(); - CoreTimingState(const CoreTimingState&) = delete; - CoreTimingState(CoreTimingState&&) = delete; - CoreTimingState& operator=(const CoreTimingState&) = delete; - CoreTimingState& operator=(CoreTimingState&&) = delete; - ~CoreTimingState(); - - struct Data; - Data& GetData() { return *m_data; } - -private: - std::unique_ptr m_data; -}; - // These really shouldn't be global, but jit64 accesses them directly struct Globals { - s64 global_timer; - int slice_length; - u64 fake_TB_start_value; - u64 fake_TB_start_ticks; - float last_OC_factor_inverted; + s64 global_timer = 0; + int slice_length = 0; + u64 fake_TB_start_value = 0; + u64 fake_TB_start_ticks = 0; + float last_OC_factor_inverted = 0.0f; }; -// CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is -// required to end slice -1 and start slice 0 before the first cycle of code is executed. -void Init(); -void Shutdown(); - typedef void (*TimedCallback)(Core::System& system, u64 userdata, s64 cyclesLate); -// This should only be called from the CPU thread, if you are calling it any other thread, you are -// doing something evil -u64 GetTicks(); -u64 GetIdleTicks(); +struct EventType +{ + TimedCallback callback; + const std::string* name; +}; -void RefreshConfig(); - -void DoState(PointerWrap& p); - -struct EventType; - -// Returns the event_type identifier. if name is not unique, an existing event_type will be -// discarded. -EventType* RegisterEvent(const std::string& name, TimedCallback callback); -void UnregisterAllEvents(); +struct Event +{ + s64 time; + u64 fifo_order; + u64 userdata; + EventType* type; +}; enum class FromThread { @@ -89,47 +68,107 @@ enum class FromThread ANY }; -// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates. -// After the first Advance, the slice lengths and the downcount will be reduced whenever an event -// is scheduled earlier than the current values (when scheduled from the CPU Thread only). -// Scheduling from a callback will not update the downcount until the Advance() completes. -void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0, - FromThread from = FromThread::CPU); +// helpers until the JIT is updated to use the instance +void GlobalAdvance(); +void GlobalIdle(); -// We only permit one event of each type in the queue at a time. -void RemoveEvent(EventType* event_type); -void RemoveAllEvents(EventType* event_type); +class CoreTimingManager +{ +public: + // CoreTiming begins at the boundary of timing slice -1. An initial call to Advance() is + // required to end slice -1 and start slice 0 before the first cycle of code is executed. + void Init(); + void Shutdown(); -// Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends -// the previous timing slice and begins the next one, you must Advance from the previous -// slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an -// Advance() is required to initialize the slice length before the first cycle of emulated -// instructions is executed. -// NOTE: Advance updates the PowerPC downcount and performs a PPC external exception check. -void Advance(); -void MoveEvents(); + // This should only be called from the CPU thread, if you are calling it any other thread, you are + // doing something evil + u64 GetTicks() const; + u64 GetIdleTicks() const; -// Pretend that the main CPU has executed enough cycles to reach the next event. -void Idle(); + void RefreshConfig(); -// Clear all pending events. This should ONLY be done on exit or state load. -void ClearPendingEvents(); + void DoState(PointerWrap& p); -void LogPendingEvents(); + // Returns the event_type identifier. if name is not unique, an existing event_type will be + // discarded. + EventType* RegisterEvent(const std::string& name, TimedCallback callback); + void UnregisterAllEvents(); -std::string GetScheduledEventsSummary(); + // userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from savestates. + // After the first Advance, the slice lengths and the downcount will be reduced whenever an event + // is scheduled earlier than the current values (when scheduled from the CPU Thread only). + // Scheduling from a callback will not update the downcount until the Advance() completes. + void ScheduleEvent(s64 cycles_into_future, EventType* event_type, u64 userdata = 0, + FromThread from = FromThread::CPU); -void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock); + // We only permit one event of each type in the queue at a time. + void RemoveEvent(EventType* event_type); + void RemoveAllEvents(EventType* event_type); -u32 GetFakeDecStartValue(); -void SetFakeDecStartValue(u32 val); -u64 GetFakeDecStartTicks(); -void SetFakeDecStartTicks(u64 val); -u64 GetFakeTBStartValue(); -void SetFakeTBStartValue(u64 val); -u64 GetFakeTBStartTicks(); -void SetFakeTBStartTicks(u64 val); + // Advance must be called at the beginning of dispatcher loops, not the end. Advance() ends + // the previous timing slice and begins the next one, you must Advance from the previous + // slice to the current one before executing any cycles. CoreTiming starts in slice -1 so an + // Advance() is required to initialize the slice length before the first cycle of emulated + // instructions is executed. + // NOTE: Advance updates the PowerPC downcount and performs a PPC external exception check. + void Advance(); + void MoveEvents(); -void ForceExceptionCheck(s64 cycles); + // Pretend that the main CPU has executed enough cycles to reach the next event. + void Idle(); + + // Clear all pending events. This should ONLY be done on exit or state load. + void ClearPendingEvents(); + + void LogPendingEvents() const; + + std::string GetScheduledEventsSummary() const; + + void AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock); + + u32 GetFakeDecStartValue() const; + void SetFakeDecStartValue(u32 val); + u64 GetFakeDecStartTicks() const; + void SetFakeDecStartTicks(u64 val); + u64 GetFakeTBStartValue() const; + void SetFakeTBStartValue(u64 val); + u64 GetFakeTBStartTicks() const; + void SetFakeTBStartTicks(u64 val); + + void ForceExceptionCheck(s64 cycles); + +private: + // unordered_map stores each element separately as a linked list node so pointers to elements + // remain stable regardless of rehashes/resizing. + std::unordered_map m_event_types; + + // STATE_TO_SAVE + // The queue is a min-heap using std::make_heap/push_heap/pop_heap. + // We don't use std::priority_queue because we need to be able to serialize, unserialize and + // erase arbitrary events (RemoveEvent()) regardless of the queue order. These aren't accomodated + // by the standard adaptor class. + std::vector m_event_queue; + u64 m_event_fifo_id = 0; + std::mutex m_ts_write_lock; + Common::SPSCQueue m_ts_queue; + + float m_last_oc_factor = 0.0f; + + s64 m_idled_cycles = 0; + u32 m_fake_dec_start_value = 0; + u64 m_fake_dec_start_ticks = 0; + + // Are we in a function that has been called from Advance() + bool m_is_global_timer_sane = false; + + EventType* m_ev_lost = nullptr; + + size_t m_registered_config_callback_id = 0; + float m_config_oc_factor = 0.0f; + float m_config_oc_inv_factor = 0.0f; + bool m_config_sync_on_skip_idle = false; + + int CyclesToDowncount(int cycles) const; +}; } // namespace CoreTiming diff --git a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp index dfc351a18a..fab26e4b30 100644 --- a/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp +++ b/Source/Core/Core/DSP/Interpreter/DSPInterpreter.cpp @@ -18,6 +18,7 @@ #include "Core/DSP/Interpreter/DSPIntTables.h" #include "Core/HW/Memmap.h" #include "Core/HW/SystemTimers.h" +#include "Core/System.h" namespace DSP::Interpreter { @@ -271,7 +272,7 @@ u16 Interpreter::ReadControlRegister() if (SystemTimers::GetFakeTimeBase() >= state.control_reg_init_code_clear_time) state.control_reg &= ~CR_INIT_CODE; else - CoreTiming::ForceExceptionCheck(50); // Keep checking + Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking } return state.control_reg; } diff --git a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp index e6a3a6e224..a8f8b54a77 100644 --- a/Source/Core/Core/FifoPlayer/FifoPlayer.cpp +++ b/Source/Core/Core/FifoPlayer/FifoPlayer.cpp @@ -23,6 +23,7 @@ #include "Core/Host.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" #include "VideoCommon/BPMemory.h" #include "VideoCommon/CommandProcessor.h" #include "VideoCommon/VideoCommon.h" @@ -508,6 +509,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end) u32 written = start; u32 lastBurstEnd = end - 1; + auto& core_timing = Core::System::GetInstance().GetCoreTiming(); + // Write up to 256 bytes at a time while (written < end) { @@ -515,8 +518,8 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end) { if (CPU::GetState() != CPU::State::Running) break; - CoreTiming::Idle(); - CoreTiming::Advance(); + core_timing.Idle(); + core_timing.Advance(); } u32 burstEnd = std::min(written + 255, lastBurstEnd); @@ -533,7 +536,7 @@ void FifoPlayer::WriteFifo(const u8* data, u32 start, u32 end) m_ElapsedCycles = elapsedCycles; PowerPC::ppcState.downcount -= cyclesUsed; - CoreTiming::Advance(); + core_timing.Advance(); } } @@ -712,11 +715,13 @@ void FifoPlayer::FlushWGP() void FifoPlayer::WaitForGPUInactive() { + auto& core_timing = Core::System::GetInstance().GetCoreTiming(); + // Sleep while the GPU is active while (!IsIdleSet() && CPU::GetState() != CPU::State::PowerDown) { - CoreTiming::Idle(); - CoreTiming::Advance(); + core_timing.Idle(); + core_timing.Advance(); } } diff --git a/Source/Core/Core/HW/AudioInterface.cpp b/Source/Core/Core/HW/AudioInterface.cpp index 48dcfe9323..af2b116117 100644 --- a/Source/Core/Core/HW/AudioInterface.cpp +++ b/Source/Core/Core/HW/AudioInterface.cpp @@ -204,15 +204,16 @@ static void Update(Core::System& system, u64 userdata, s64 cycles_late) return; auto& state = system.GetAudioInterfaceState().GetData(); + auto& core_timing = system.GetCoreTiming(); - const u64 diff = CoreTiming::GetTicks() - state.last_cpu_time; + const u64 diff = core_timing.GetTicks() - state.last_cpu_time; if (diff > state.cpu_cycles_per_sample) { const u32 samples = static_cast(diff / state.cpu_cycles_per_sample); state.last_cpu_time += samples * state.cpu_cycles_per_sample; IncreaseSampleCount(samples); } - CoreTiming::ScheduleEvent(GetAIPeriod() - cycles_late, state.event_type_ai); + core_timing.ScheduleEvent(GetAIPeriod() - cycles_late, state.event_type_ai); } void SetAIDSampleRate(SampleRate sample_rate) @@ -258,7 +259,9 @@ void SetAISSampleRate(SampleRate sample_rate) void Init() { - auto& state = Core::System::GetInstance().GetAudioInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetAudioInterfaceState().GetData(); state.control.hex = 0; SetAISSampleRate(SampleRate::AI48KHz); @@ -269,7 +272,7 @@ void Init() state.last_cpu_time = 0; - state.event_type_ai = CoreTiming::RegisterEvent("AICallback", Update); + state.event_type_ai = core_timing.RegisterEvent("AICallback", Update); } void Shutdown() @@ -285,6 +288,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { const AICR tmp_ai_ctrl(val); + auto& core_timing = system.GetCoreTiming(); auto& state = system.GetAudioInterfaceState().GetData(); if (state.control.AIINTMSK != tmp_ai_ctrl.AIINTMSK) { @@ -321,10 +325,10 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) DEBUG_LOG_FMT(AUDIO_INTERFACE, "{} streaming audio", tmp_ai_ctrl.PSTAT ? "start" : "stop"); state.control.PSTAT = tmp_ai_ctrl.PSTAT; - state.last_cpu_time = CoreTiming::GetTicks(); + state.last_cpu_time = core_timing.GetTicks(); - CoreTiming::RemoveEvent(state.event_type_ai); - CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai); + core_timing.RemoveEvent(state.event_type_ai); + core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai); } // AI Interrupt @@ -340,7 +344,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) DEBUG_LOG_FMT(AUDIO_INTERFACE, "Reset AIS sample counter"); state.sample_counter = 0; - state.last_cpu_time = CoreTiming::GetTicks(); + state.last_cpu_time = core_timing.GetTicks(); } UpdateInterrupts(); @@ -357,28 +361,30 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) mmio->Register(base | AI_SAMPLE_COUNTER, MMIO::ComplexRead([](Core::System& system, u32) { auto& state = system.GetAudioInterfaceState().GetData(); - const u64 cycles_streamed = IsPlaying() ? - (CoreTiming::GetTicks() - state.last_cpu_time) : - state.last_cpu_time; + const u64 cycles_streamed = + IsPlaying() ? (system.GetCoreTiming().GetTicks() - state.last_cpu_time) : + state.last_cpu_time; return state.sample_counter + static_cast(cycles_streamed / state.cpu_cycles_per_sample); }), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { + auto& core_timing = system.GetCoreTiming(); auto& state = system.GetAudioInterfaceState().GetData(); state.sample_counter = val; - state.last_cpu_time = CoreTiming::GetTicks(); - CoreTiming::RemoveEvent(state.event_type_ai); - CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai); + state.last_cpu_time = core_timing.GetTicks(); + core_timing.RemoveEvent(state.event_type_ai); + core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai); })); mmio->Register(base | AI_INTERRUPT_TIMING, MMIO::DirectRead(&state.interrupt_timing), MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { + auto& core_timing = system.GetCoreTiming(); auto& state = system.GetAudioInterfaceState().GetData(); DEBUG_LOG_FMT(AUDIO_INTERFACE, "AI_INTERRUPT_TIMING={:08x} at PC: {:08x}", val, PowerPC::ppcState.pc); state.interrupt_timing = val; - CoreTiming::RemoveEvent(state.event_type_ai); - CoreTiming::ScheduleEvent(GetAIPeriod(), state.event_type_ai); + core_timing.RemoveEvent(state.event_type_ai); + core_timing.ScheduleEvent(GetAIPeriod(), state.event_type_ai); })); } diff --git a/Source/Core/Core/HW/DSP.cpp b/Source/Core/Core/HW/DSP.cpp index b474ea5558..322c947512 100644 --- a/Source/Core/Core/HW/DSP.cpp +++ b/Source/Core/Core/HW/DSP.cpp @@ -194,11 +194,13 @@ DSPEmulator* GetDSPEmulator() void Init(bool hle) { - auto& state = Core::System::GetInstance().GetDSPState().GetData(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetDSPState().GetData(); Reinit(hle); state.event_type_generate_dsp_interrupt = - CoreTiming::RegisterEvent("DSPint", GenerateDSPInterrupt); - state.event_type_complete_aram = CoreTiming::RegisterEvent("ARAMint", CompleteARAM); + core_timing.RegisterEvent("DSPint", GenerateDSPInterrupt); + state.event_type_complete_aram = core_timing.RegisterEvent("ARAMint", CompleteARAM); } void Reinit(bool hle) @@ -432,7 +434,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) // TODO: need hardware tests for the timing of this interrupt. // Sky Crawlers crashes at boot if this is scheduled less than 87 cycles in the future. // Other Namco games crash too, see issue 9509. For now we will just push it to 200 cycles - CoreTiming::ScheduleEvent(200, state.event_type_generate_dsp_interrupt, INT_AID); + system.GetCoreTiming().ScheduleEvent(200, state.event_type_generate_dsp_interrupt, + INT_AID); } })); @@ -486,8 +489,10 @@ static void GenerateDSPInterrupt(Core::System& system, u64 DSPIntType, s64 cycle // CALLED FROM DSP EMULATOR, POSSIBLY THREADED void GenerateDSPInterruptFromDSPEmu(DSPInterruptType type, int cycles_into_future) { - auto& state = Core::System::GetInstance().GetDSPState().GetData(); - CoreTiming::ScheduleEvent(cycles_into_future, state.event_type_generate_dsp_interrupt, type, + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetDSPState().GetData(); + core_timing.ScheduleEvent(cycles_into_future, state.event_type_generate_dsp_interrupt, type, CoreTiming::FromThread::ANY); } @@ -547,13 +552,15 @@ void UpdateAudioDMA() static void Do_ARAM_DMA() { - auto& state = Core::System::GetInstance().GetDSPState().GetData(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetDSPState().GetData(); state.dsp_control.DMAState = 1; // ARAM DMA transfer rate has been measured on real hw int ticksToTransfer = (state.aram_dma.Cnt.count / 32) * 246; - CoreTiming::ScheduleEvent(ticksToTransfer, state.event_type_complete_aram); + core_timing.ScheduleEvent(ticksToTransfer, state.event_type_complete_aram); // Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks if (state.aram_dma.Cnt.dir) diff --git a/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp b/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp index 99d3560d50..3360b951e4 100644 --- a/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp +++ b/Source/Core/Core/HW/DSPHLE/DSPHLE.cpp @@ -10,6 +10,7 @@ #include "Core/CoreTiming.h" #include "Core/HW/DSPHLE/UCodes/UCodes.h" #include "Core/HW/SystemTimers.h" +#include "Core/System.h" namespace DSP::HLE { @@ -234,7 +235,7 @@ u16 DSPHLE::DSP_ReadControlRegister() if (SystemTimers::GetFakeTimeBase() >= m_control_reg_init_code_clear_time) m_dsp_control.DSPInitCode = 0; else - CoreTiming::ForceExceptionCheck(50); // Keep checking + Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(50); // Keep checking } return m_dsp_control.Hex; } diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp index cc743d8220..a689f9d028 100644 --- a/Source/Core/Core/HW/DVD/DVDInterface.cpp +++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp @@ -309,7 +309,8 @@ static u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process) static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector& audio_data, s64 cycles_late) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetDVDInterfaceState().GetData(); // Actual games always set this to 48 KHz // but let's make sure to use GetAISSampleRateDivisor() @@ -330,7 +331,6 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect std::vector temp_pcm(state.pending_samples * 2, 0); ProcessDTKSamples(&temp_pcm, audio_data); - auto& system = Core::System::GetInstance(); SoundStream* sound_stream = system.GetSoundStream(); sound_stream->GetMixer()->PushStreamingSamples(temp_pcm.data(), state.pending_samples); @@ -364,7 +364,7 @@ static void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vect { // There's nothing to read, so using DVDThread is unnecessary. u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT); - CoreTiming::ScheduleEvent(ticks_to_dtk, state.finish_executing_command, userdata); + system.GetCoreTiming().ScheduleEvent(ticks_to_dtk, state.finish_executing_command, userdata); } } @@ -374,7 +374,10 @@ void Init() DVDThread::Start(); - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetDVDInterfaceState().GetData(); + state.DISR.Hex = 0; state.DICVR.Hex = 1; // Disc Channel relies on cover being open when no disc is inserted state.DICMDBUF[0] = 0; @@ -389,15 +392,15 @@ void Init() ResetDrive(false); - state.auto_change_disc = CoreTiming::RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback); - state.eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); - state.insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); + state.auto_change_disc = core_timing.RegisterEvent("AutoChangeDisc", AutoChangeDiscCallback); + state.eject_disc = core_timing.RegisterEvent("EjectDisc", EjectDiscCallback); + state.insert_disc = core_timing.RegisterEvent("InsertDisc", InsertDiscCallback); state.finish_executing_command = - CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); + core_timing.RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback); u64 userdata = PackFinishExecutingCommandUserdata(ReplyType::DTK, DIInterruptType::TCINT); - CoreTiming::ScheduleEvent(0, state.finish_executing_command, userdata); + core_timing.ScheduleEvent(0, state.finish_executing_command, userdata); } // Resets state on the MN102 chip in the drive itself, but not the DI registers exposed on the @@ -557,8 +560,10 @@ static void InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLat // Must only be called on the CPU thread void EjectDisc(EjectCause cause) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); - CoreTiming::ScheduleEvent(0, state.eject_disc); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetDVDInterfaceState().GetData(); + core_timing.ScheduleEvent(0, state.eject_disc); if (cause == EjectCause::User) ExpansionInterface::g_rtc_flags[ExpansionInterface::RTCFlag::EjectButton] = true; } @@ -581,7 +586,8 @@ void ChangeDisc(const std::vector& paths) // Must only be called on the CPU thread void ChangeDisc(const std::string& new_path) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetDVDInterfaceState().GetData(); if (!state.disc_path_to_insert.empty()) { PanicAlertFmtT("A disc is already about to be inserted."); @@ -591,7 +597,7 @@ void ChangeDisc(const std::string& new_path) EjectDisc(EjectCause::User); state.disc_path_to_insert = new_path; - CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.insert_disc); + system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.insert_disc); Movie::SignalDiscChange(new_path); for (size_t i = 0; i < state.auto_disc_change_paths.size(); ++i) @@ -724,7 +730,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii) static void UpdateInterrupts() { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetDVDInterfaceState().GetData(); const bool set_mask = (state.DISR.DEINT & state.DISR.DEINTMASK) != 0 || (state.DISR.TCINT & state.DISR.TCINTMASK) != 0 || (state.DISR.BRKINT & state.DISR.BRKINTMASK) != 0 || @@ -733,7 +740,7 @@ static void UpdateInterrupts() ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, set_mask); // Required for Summoner: A Goddess Reborn - CoreTiming::ForceExceptionCheck(50); + system.GetCoreTiming().ForceExceptionCheck(50); } static void GenerateDIInterrupt(DIInterruptType dvd_interrupt) @@ -876,7 +883,8 @@ static bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_lengt // with the userdata set to the interrupt type. void ExecuteCommand(ReplyType reply_type) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetDVDInterfaceState().GetData(); DIInterruptType interrupt_type = DIInterruptType::TCINT; bool command_handled_by_thread = false; @@ -1214,8 +1222,8 @@ void ExecuteCommand(ReplyType reply_type) if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() && DVDThread::IsInsertedDiscRunning() && !state.auto_disc_change_paths.empty()) { - CoreTiming::ScheduleEvent(force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2, - state.auto_change_disc); + system.GetCoreTiming().ScheduleEvent(force_eject ? 0 : SystemTimers::GetTicksPerSecond() / 2, + state.auto_change_disc); OSD::AddMessage("Changing discs automatically...", OSD::Duration::NORMAL); } else if (force_eject) @@ -1306,17 +1314,18 @@ void ExecuteCommand(ReplyType reply_type) if (!command_handled_by_thread) { // TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this - CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US * - (SystemTimers::GetTicksPerSecond() / 1000000), - state.finish_executing_command, - PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); + system.GetCoreTiming().ScheduleEvent( + MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000), + state.finish_executing_command, + PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); } } void PerformDecryptingRead(u32 position, u32 length, u32 output_address, const DiscIO::Partition& partition, ReplyType reply_type) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetDVDInterfaceState().GetData(); DIInterruptType interrupt_type = DIInterruptType::TCINT; if (state.drive_state == DriveState::ReadyNoReadsMade) @@ -1329,16 +1338,17 @@ void PerformDecryptingRead(u32 position, u32 length, u32 output_address, if (!command_handled_by_thread) { // TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this - CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US * - (SystemTimers::GetTicksPerSecond() / 1000000), - state.finish_executing_command, - PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); + system.GetCoreTiming().ScheduleEvent( + MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000), + state.finish_executing_command, + PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); } } void ForceOutOfBoundsRead(ReplyType reply_type) { - auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetDVDInterfaceState().GetData(); INFO_LOG_FMT(DVDINTERFACE, "Forcing an out-of-bounds disc read."); if (state.drive_state == DriveState::ReadyNoReadsMade) @@ -1348,10 +1358,10 @@ void ForceOutOfBoundsRead(ReplyType reply_type) // TODO: Needs testing to determine if MINIMUM_COMMAND_LATENCY_US is accurate for this const DIInterruptType interrupt_type = DIInterruptType::DEINT; - CoreTiming::ScheduleEvent(MINIMUM_COMMAND_LATENCY_US * - (SystemTimers::GetTicksPerSecond() / 1000000), - state.finish_executing_command, - PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); + system.GetCoreTiming().ScheduleEvent( + MINIMUM_COMMAND_LATENCY_US * (SystemTimers::GetTicksPerSecond() / 1000000), + state.finish_executing_command, + PackFinishExecutingCommandUserdata(reply_type, interrupt_type)); } void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length) @@ -1445,6 +1455,8 @@ void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, u32 output_address, ReplyType reply_type) { + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); auto& state = Core::System::GetInstance().GetDVDInterfaceState().GetData(); // The drive continues to read 1 MiB beyond the last read position when idle. @@ -1456,7 +1468,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti // faster than on real hardware, and if there's too much latency in the wrong // places, the video before the save-file select screen lags. - const u64 current_time = CoreTiming::GetTicks(); + const u64 current_time = core_timing.GetTicks(); const u32 ticks_per_second = SystemTimers::GetTicksPerSecond(); const bool wii_disc = DVDThread::GetDiscType() == DiscIO::Platform::WiiDisc; @@ -1581,7 +1593,7 @@ static void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& parti // should actually happen before reading data from the disc. const double time_after_seek = - (CoreTiming::GetTicks() + ticks_until_completion) / ticks_per_second; + (core_timing.GetTicks() + ticks_until_completion) / ticks_per_second; ticks_until_completion += ticks_per_second * DVDMath::CalculateRotationalLatency( dvd_offset, time_after_seek, wii_disc); diff --git a/Source/Core/Core/HW/DVD/DVDThread.cpp b/Source/Core/Core/HW/DVD/DVDThread.cpp index ea7f31f783..c17b736ca2 100644 --- a/Source/Core/Core/HW/DVD/DVDThread.cpp +++ b/Source/Core/Core/HW/DVD/DVDThread.cpp @@ -102,9 +102,10 @@ DVDThreadState::~DVDThreadState() = default; void Start() { - auto& state = Core::System::GetInstance().GetDVDThreadState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetDVDThreadState().GetData(); - state.finish_read = CoreTiming::RegisterEvent("FinishReadDVDThread", FinishRead); + state.finish_read = system.GetCoreTiming().RegisterEvent("FinishReadDVDThread", FinishRead); state.request_queue_expanded.Reset(); state.result_queue_expanded.Reset(); @@ -305,7 +306,9 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs { ASSERT(Core::IsCPUThread()); - auto& state = Core::System::GetInstance().GetDVDThreadState().GetData(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetDVDThreadState().GetData(); ReadRequest request; @@ -319,13 +322,13 @@ static void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offs u64 id = state.next_id++; request.id = id; - request.time_started_ticks = CoreTiming::GetTicks(); + request.time_started_ticks = core_timing.GetTicks(); request.realtime_started_us = Common::Timer::NowUs(); state.request_queue.Push(std::move(request)); state.request_queue_expanded.Set(); - CoreTiming::ScheduleEvent(ticks_until_completion, state.finish_read, id); + core_timing.ScheduleEvent(ticks_until_completion, state.finish_read, id); } static void FinishRead(Core::System& system, u64 id, s64 cycles_late) @@ -373,7 +376,7 @@ static void FinishRead(Core::System& system, u64 id, s64 cycles_late) "Emulated time including delay: {} us.", request.realtime_done_us - request.realtime_started_us, Common::Timer::NowUs() - request.realtime_started_us, - (CoreTiming::GetTicks() - request.time_started_ticks) / + (system.GetCoreTiming().GetTicks() - request.time_started_ticks) / (SystemTimers::GetTicksPerSecond() / 1000000)); DVDInterface::DIInterruptType interrupt; diff --git a/Source/Core/Core/HW/EXI/EXI.cpp b/Source/Core/Core/HW/EXI/EXI.cpp index 350ed22203..126872634e 100644 --- a/Source/Core/Core/HW/EXI/EXI.cpp +++ b/Source/Core/Core/HW/EXI/EXI.cpp @@ -161,10 +161,11 @@ void Init(const Sram* override_sram) SlotToEXIDevice(Slot::SP1)); state.channels[2]->AddDevice(EXIDeviceType::AD16, 0); + auto& core_timing = system.GetCoreTiming(); state.event_type_change_device = - CoreTiming::RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback); + core_timing.RegisterEvent("ChangeEXIDevice", ChangeDeviceCallback); state.event_type_update_interrupts = - CoreTiming::RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback); + core_timing.RegisterEvent("EXIUpdateInterrupts", UpdateInterruptsCallback); } void Shutdown() @@ -233,11 +234,13 @@ void ChangeDevice(u8 channel, u8 device_num, EXIDeviceType device_type, CoreTiming::FromThread from_thread) { // Let the hardware see no device for 1 second - auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData(); - CoreTiming::ScheduleEvent(0, state.event_type_change_device, + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetExpansionInterfaceState().GetData(); + core_timing.ScheduleEvent(0, state.event_type_change_device, ((u64)channel << 32) | ((u64)EXIDeviceType::None << 16) | device_num, from_thread); - CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device, + core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device, ((u64)channel << 32) | ((u64)device_type << 16) | device_num, from_thread); } @@ -277,8 +280,9 @@ static void UpdateInterruptsCallback(Core::System& system, u64 userdata, s64 cyc void ScheduleUpdateInterrupts(CoreTiming::FromThread from, int cycles_late) { + auto& system = Core::System::GetInstance(); auto& state = Core::System::GetInstance().GetExpansionInterfaceState().GetData(); - CoreTiming::ScheduleEvent(cycles_late, state.event_type_update_interrupts, 0, from); + system.GetCoreTiming().ScheduleEvent(cycles_late, state.event_type_update_interrupts, 0, from); } } // namespace ExpansionInterface diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp index f331f86284..12ba273038 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceIPL.cpp @@ -405,14 +405,16 @@ u32 CEXIIPL::GetEmulatedTime(u32 epoch) ltime = Movie::GetRecordingStartTime(); // let's keep time moving forward, regardless of what it starts at - ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond(); + ltime += + Core::System::GetInstance().GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond(); } else if (NetPlay::IsNetPlayRunning()) { ltime = NetPlay_GetEmulatedTime(); // let's keep time moving forward, regardless of what it starts at - ltime += CoreTiming::GetTicks() / SystemTimers::GetTicksPerSecond(); + ltime += + Core::System::GetInstance().GetCoreTiming().GetTicks() / SystemTimers::GetTicksPerSecond(); } else { diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp index 2e97cc67e6..12d99621fc 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceMemoryCard.cpp @@ -86,11 +86,13 @@ void CEXIMemoryCard::Init() { static_assert(s_et_cmd_done.size() == s_et_transfer_complete.size(), "Event array size differs"); static_assert(s_et_cmd_done.size() == MEMCARD_SLOTS.size(), "Event array size differs"); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); for (Slot slot : MEMCARD_SLOTS) { - s_et_cmd_done[slot] = CoreTiming::RegisterEvent( + s_et_cmd_done[slot] = core_timing.RegisterEvent( fmt::format("memcardDone{}", s_card_short_names[slot]), CmdDoneCallback); - s_et_transfer_complete[slot] = CoreTiming::RegisterEvent( + s_et_transfer_complete[slot] = core_timing.RegisterEvent( fmt::format("memcardTransferComplete{}", s_card_short_names[slot]), TransferCompleteCallback); } @@ -233,8 +235,10 @@ void CEXIMemoryCard::SetupRawMemcard(u16 size_mb) CEXIMemoryCard::~CEXIMemoryCard() { - CoreTiming::RemoveEvent(s_et_cmd_done[m_card_slot]); - CoreTiming::RemoveEvent(s_et_transfer_complete[m_card_slot]); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.RemoveEvent(s_et_cmd_done[m_card_slot]); + core_timing.RemoveEvent(s_et_transfer_complete[m_card_slot]); } bool CEXIMemoryCard::UseDelayedTransferCompletion() const @@ -265,8 +269,10 @@ void CEXIMemoryCard::TransferComplete() void CEXIMemoryCard::CmdDoneLater(u64 cycles) { - CoreTiming::RemoveEvent(s_et_cmd_done[m_card_slot]); - CoreTiming::ScheduleEvent(cycles, s_et_cmd_done[m_card_slot], static_cast(m_card_slot)); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.RemoveEvent(s_et_cmd_done[m_card_slot]); + core_timing.ScheduleEvent(cycles, s_et_cmd_done[m_card_slot], static_cast(m_card_slot)); } void CEXIMemoryCard::SetCS(int cs) @@ -525,8 +531,9 @@ void CEXIMemoryCard::DMARead(u32 addr, u32 size) } // Schedule transfer complete later based on read speed - CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ), - s_et_transfer_complete[m_card_slot], static_cast(m_card_slot)); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent( + size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_READ), + s_et_transfer_complete[m_card_slot], static_cast(m_card_slot)); } // DMA write are preceded by all of the necessary setup via IMMWrite @@ -541,7 +548,8 @@ void CEXIMemoryCard::DMAWrite(u32 addr, u32 size) } // Schedule transfer complete later based on write speed - CoreTiming::ScheduleEvent(size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE), - s_et_transfer_complete[m_card_slot], static_cast(m_card_slot)); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent( + size * (SystemTimers::GetTicksPerSecond() / MC_TRANSFER_RATE_WRITE), + s_et_transfer_complete[m_card_slot], static_cast(m_card_slot)); } } // namespace ExpansionInterface diff --git a/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp b/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp index 6de3d42897..01f9b44354 100644 --- a/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp +++ b/Source/Core/Core/HW/EXI/EXI_DeviceMic.cpp @@ -18,6 +18,7 @@ #include "Core/HW/EXI/EXI.h" #include "Core/HW/GCPad.h" #include "Core/HW/SystemTimers.h" +#include "Core/System.h" namespace ExpansionInterface { @@ -182,13 +183,13 @@ void CEXIMic::SetCS(int cs) void CEXIMic::UpdateNextInterruptTicks() { int diff = (SystemTimers::GetTicksPerSecond() / sample_rate) * buff_size_samples; - next_int_ticks = CoreTiming::GetTicks() + diff; + next_int_ticks = Core::System::GetInstance().GetCoreTiming().GetTicks() + diff; ExpansionInterface::ScheduleUpdateInterrupts(CoreTiming::FromThread::CPU, diff); } bool CEXIMic::IsInterruptSet() { - if (next_int_ticks && CoreTiming::GetTicks() >= next_int_ticks) + if (next_int_ticks && Core::System::GetInstance().GetCoreTiming().GetTicks() >= next_int_ticks) { if (status.is_active) UpdateNextInterruptTicks(); diff --git a/Source/Core/Core/HW/HW.cpp b/Source/Core/Core/HW/HW.cpp index 41a8fd40b5..168b64a0b7 100644 --- a/Source/Core/Core/HW/HW.cpp +++ b/Source/Core/Core/HW/HW.cpp @@ -27,12 +27,13 @@ #include "Core/HW/WII_IPC.h" #include "Core/IOS/IOS.h" #include "Core/State.h" +#include "Core/System.h" namespace HW { void Init(const Sram* override_sram) { - CoreTiming::Init(); + Core::System::GetInstance().GetCoreTiming().Init(); SystemTimers::PreInit(); State::Init(); @@ -79,7 +80,7 @@ void Shutdown() AudioInterface::Shutdown(); State::Shutdown(); - CoreTiming::Shutdown(); + Core::System::GetInstance().GetCoreTiming().Shutdown(); } void DoState(PointerWrap& p) diff --git a/Source/Core/Core/HW/ProcessorInterface.cpp b/Source/Core/Core/HW/ProcessorInterface.cpp index efb324dee2..f55d5ab8b8 100644 --- a/Source/Core/Core/HW/ProcessorInterface.cpp +++ b/Source/Core/Core/HW/ProcessorInterface.cpp @@ -72,11 +72,13 @@ void Init() m_ResetCode = 0; // Cold reset m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI; - toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + toggleResetButton = core_timing.RegisterEvent("ToggleResetButton", ToggleResetButtonCallback); iosNotifyResetButton = - CoreTiming::RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback); + core_timing.RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback); iosNotifyPowerButton = - CoreTiming::RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback); + core_timing.RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) @@ -261,9 +263,12 @@ void ResetButton_Tap() { if (!Core::IsRunning()) return; - CoreTiming::ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY); - CoreTiming::ScheduleEvent(0, iosNotifyResetButton, 0, CoreTiming::FromThread::ANY); - CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond() / 2, toggleResetButton, false, + + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY); + core_timing.ScheduleEvent(0, iosNotifyResetButton, 0, CoreTiming::FromThread::ANY); + core_timing.ScheduleEvent(SystemTimers::GetTicksPerSecond() / 2, toggleResetButton, false, CoreTiming::FromThread::ANY); } @@ -271,7 +276,10 @@ void PowerButton_Tap() { if (!Core::IsRunning()) return; - CoreTiming::ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY); + + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY); } } // namespace ProcessorInterface diff --git a/Source/Core/Core/HW/SI/SI.cpp b/Source/Core/Core/HW/SI/SI.cpp index edd64c69f3..c6766e96e9 100644 --- a/Source/Core/Core/HW/SI/SI.cpp +++ b/Source/Core/Core/HW/SI/SI.cpp @@ -344,8 +344,8 @@ static void RunSIBuffer(Core::System& system, u64 user_data, s64 cycles_late) } else { - CoreTiming::ScheduleEvent(device->TransferInterval() - cycles_late, - state.event_type_tranfer_pending); + system.GetCoreTiming().ScheduleEvent(device->TransferInterval() - cycles_late, + state.event_type_tranfer_pending); } } } @@ -388,10 +388,12 @@ static void DeviceEventCallback(Core::System& system, u64 userdata, s64 cyclesLa static void RegisterEvents() { - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetSerialInterfaceState().GetData(); state.event_type_change_device = - CoreTiming::RegisterEvent("ChangeSIDevice", ChangeDeviceCallback); - state.event_type_tranfer_pending = CoreTiming::RegisterEvent("SITransferPending", RunSIBuffer); + core_timing.RegisterEvent("ChangeSIDevice", ChangeDeviceCallback); + state.event_type_tranfer_pending = core_timing.RegisterEvent("SITransferPending", RunSIBuffer); constexpr std::array event_callbacks = { DeviceEventCallback<0>, @@ -402,20 +404,24 @@ static void RegisterEvents() for (int i = 0; i < MAX_SI_CHANNELS; ++i) { state.event_types_device[i] = - CoreTiming::RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]); + core_timing.RegisterEvent(fmt::format("SIEventChannel{}", i), event_callbacks[i]); } } void ScheduleEvent(int device_number, s64 cycles_into_future, u64 userdata) { - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); - CoreTiming::ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetSerialInterfaceState().GetData(); + core_timing.ScheduleEvent(cycles_into_future, state.event_types_device[device_number], userdata); } void RemoveEvent(int device_number) { - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); - CoreTiming::RemoveEvent(state.event_types_device[device_number]); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + auto& state = system.GetSerialInterfaceState().GetData(); + core_timing.RemoveEvent(state.event_types_device[device_number]); } void Init() @@ -573,7 +579,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) if (tmp_com_csr.TSTART) { if (state.com_csr.TSTART) - CoreTiming::RemoveEvent(state.event_type_tranfer_pending); + system.GetCoreTiming().RemoveEvent(state.event_type_tranfer_pending); state.com_csr.TSTART = 1; RunSIBuffer(system, 0, 0); } @@ -676,7 +682,8 @@ void ChangeDevice(SIDevices device, int channel) static void ChangeDeviceDeterministic(SIDevices device, int channel) { - auto& state = Core::System::GetInstance().GetSerialInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetSerialInterfaceState().GetData(); if (state.channel[channel].has_recent_device_change) return; @@ -696,8 +703,8 @@ static void ChangeDeviceDeterministic(SIDevices device, int channel) // Prevent additional device changes on this channel for one second. state.channel[channel].has_recent_device_change = true; - CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond(), state.event_type_change_device, - channel); + system.GetCoreTiming().ScheduleEvent(SystemTimers::GetTicksPerSecond(), + state.event_type_change_device, channel); } void UpdateDevices() diff --git a/Source/Core/Core/HW/SI/SI_DeviceGBA.cpp b/Source/Core/Core/HW/SI/SI_DeviceGBA.cpp index 537b89af12..29171e17de 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceGBA.cpp +++ b/Source/Core/Core/HW/SI/SI_DeviceGBA.cpp @@ -20,6 +20,7 @@ #include "Core/CoreTiming.h" #include "Core/HW/SI/SI_Device.h" #include "Core/HW/SystemTimers.h" +#include "Core/System.h" namespace SerialInterface { @@ -145,21 +146,24 @@ void GBASockServer::ClockSync() if (!(m_clock_sync = GetNextClock())) return; + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + u32 time_slice = 0; if (m_last_time_slice == 0) { s_num_connected++; - m_last_time_slice = CoreTiming::GetTicks(); + m_last_time_slice = core_timing.GetTicks(); time_slice = (u32)(SystemTimers::GetTicksPerSecond() / 60); } else { - time_slice = (u32)(CoreTiming::GetTicks() - m_last_time_slice); + time_slice = (u32)(core_timing.GetTicks() - m_last_time_slice); } time_slice = (u32)((u64)time_slice * 16777216 / SystemTimers::GetTicksPerSecond()); - m_last_time_slice = CoreTiming::GetTicks(); + m_last_time_slice = core_timing.GetTicks(); char bytes[4] = {0, 0, 0, 0}; bytes[0] = (time_slice >> 24) & 0xff; bytes[1] = (time_slice >> 16) & 0xff; @@ -285,14 +289,15 @@ int CSIDevice_GBA::RunBuffer(u8* buffer, int request_length) } m_last_cmd = static_cast(buffer[0]); - m_timestamp_sent = CoreTiming::GetTicks(); + m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks(); m_next_action = NextAction::WaitTransferTime; return 0; } case NextAction::WaitTransferTime: { - int elapsed_time = static_cast(CoreTiming::GetTicks() - m_timestamp_sent); + int elapsed_time = + static_cast(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent); // Tell SI to ask again after TransferInterval() cycles if (SIDevice_GetGBATransferTime(m_last_cmd) > elapsed_time) return 0; diff --git a/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp index bb9a6d1316..880be78db0 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp +++ b/Source/Core/Core/HW/SI/SI_DeviceGBAEmu.cpp @@ -18,6 +18,7 @@ #include "Core/HW/SystemTimers.h" #include "Core/Host.h" #include "Core/NetPlayProto.h" +#include "Core/System.h" namespace SerialInterface { @@ -30,7 +31,7 @@ CSIDevice_GBAEmu::CSIDevice_GBAEmu(SIDevices device, int device_number) : ISIDevice(device, device_number) { m_core = std::make_shared(m_device_number); - m_core->Start(CoreTiming::GetTicks()); + m_core->Start(Core::System::GetInstance().GetCoreTiming().GetTicks()); m_gbahost = Host_CreateGBAHost(m_core); m_core->SetHost(m_gbahost); ScheduleEvent(m_device_number, GetSyncInterval()); @@ -55,7 +56,7 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length) buffer[0], buffer[1], buffer[2], buffer[3], buffer[4]); #endif m_last_cmd = static_cast(buffer[0]); - m_timestamp_sent = CoreTiming::GetTicks(); + m_timestamp_sent = Core::System::GetInstance().GetCoreTiming().GetTicks(); m_core->SendJoybusCommand(m_timestamp_sent, TransferInterval(), buffer, m_keys); RemoveEvent(m_device_number); @@ -74,7 +75,8 @@ int CSIDevice_GBAEmu::RunBuffer(u8* buffer, int request_length) case NextAction::WaitTransferTime: { - int elapsed_time = static_cast(CoreTiming::GetTicks() - m_timestamp_sent); + int elapsed_time = + static_cast(Core::System::GetInstance().GetCoreTiming().GetTicks() - m_timestamp_sent); // Tell SI to ask again after TransferInterval() cycles if (TransferInterval() > elapsed_time) return 0; @@ -162,7 +164,8 @@ void CSIDevice_GBAEmu::DoState(PointerWrap& p) void CSIDevice_GBAEmu::OnEvent(u64 userdata, s64 cycles_late) { - m_core->SendJoybusCommand(CoreTiming::GetTicks() + userdata, 0, nullptr, m_keys); + m_core->SendJoybusCommand(Core::System::GetInstance().GetCoreTiming().GetTicks() + userdata, 0, + nullptr, m_keys); ScheduleEvent(m_device_number, userdata + GetSyncInterval()); } } // namespace SerialInterface diff --git a/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp b/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp index 88953cd88d..9f0941bd16 100644 --- a/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp +++ b/Source/Core/Core/HW/SI/SI_DeviceGCController.cpp @@ -18,6 +18,7 @@ #include "Core/HW/SystemTimers.h" #include "Core/Movie.h" #include "Core/NetPlayProto.h" +#include "Core/System.h" #include "InputCommon/GCPadStatus.h" namespace SerialInterface @@ -263,12 +264,12 @@ CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status) { m_last_button_combo = temp_combo; if (m_last_button_combo != COMBO_NONE) - m_timer_button_combo_start = CoreTiming::GetTicks(); + m_timer_button_combo_start = Core::System::GetInstance().GetCoreTiming().GetTicks(); } if (m_last_button_combo != COMBO_NONE) { - const u64 current_time = CoreTiming::GetTicks(); + const u64 current_time = Core::System::GetInstance().GetCoreTiming().GetTicks(); if (u32(current_time - m_timer_button_combo_start) > SystemTimers::GetTicksPerSecond() * 3) { if (m_last_button_combo == COMBO_RESET) diff --git a/Source/Core/Core/HW/SystemTimers.cpp b/Source/Core/Core/HW/SystemTimers.cpp index eab06b28d7..ff3b408920 100644 --- a/Source/Core/Core/HW/SystemTimers.cpp +++ b/Source/Core/Core/HW/SystemTimers.cpp @@ -65,6 +65,7 @@ IPC_HLE_PERIOD: For the Wii Remote this is the call schedule: #include "Core/IOS/IOS.h" #include "Core/PatchEngine.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" #include "VideoCommon/Fifo.h" namespace SystemTimers @@ -105,7 +106,8 @@ void DSPCallback(Core::System& system, u64 userdata, s64 cyclesLate) // splits up the cycle budget in case lle is used // for hle, just gives all of the slice to hle DSP::UpdateDSPSlice(static_cast(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate)); - CoreTiming::ScheduleEvent(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate, et_DSP); + system.GetCoreTiming().ScheduleEvent(DSP::GetDSPEmulator()->DSP_UpdateRate() - cyclesLate, + et_DSP); } int GetAudioDMACallbackPeriod() @@ -118,7 +120,7 @@ int GetAudioDMACallbackPeriod() void AudioDMACallback(Core::System& system, u64 userdata, s64 cyclesLate) { DSP::UpdateAudioDMA(); // Push audio to speakers. - CoreTiming::ScheduleEvent(GetAudioDMACallbackPeriod() - cyclesLate, et_AudioDMA); + system.GetCoreTiming().ScheduleEvent(GetAudioDMACallbackPeriod() - cyclesLate, et_AudioDMA); } void IPC_HLE_UpdateCallback(Core::System& system, u64 userdata, s64 cyclesLate) @@ -126,14 +128,15 @@ void IPC_HLE_UpdateCallback(Core::System& system, u64 userdata, s64 cyclesLate) if (SConfig::GetInstance().bWii) { IOS::HLE::GetIOS()->UpdateDevices(); - CoreTiming::ScheduleEvent(s_ipc_hle_period - cyclesLate, et_IPC_HLE); + system.GetCoreTiming().ScheduleEvent(s_ipc_hle_period - cyclesLate, et_IPC_HLE); } } void VICallback(Core::System& system, u64 userdata, s64 cyclesLate) { - VideoInterface::Update(CoreTiming::GetTicks() - cyclesLate); - CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine() - cyclesLate, et_VI); + auto& core_timing = system.GetCoreTiming(); + VideoInterface::Update(core_timing.GetTicks() - cyclesLate); + core_timing.ScheduleEvent(VideoInterface::GetTicksPerHalfLine() - cyclesLate, et_VI); } void DecrementerCallback(Core::System& system, u64 userdata, s64 cyclesLate) @@ -164,7 +167,7 @@ void PatchEngineCallback(Core::System& system, u64 userdata, s64 cycles_late) cycles_pruned += next_schedule; } - CoreTiming::ScheduleEvent(next_schedule, et_PatchEngine, cycles_pruned); + system.GetCoreTiming().ScheduleEvent(next_schedule, et_PatchEngine, cycles_pruned); } void ThrottleCallback(Core::System& system, u64 deadline, s64 cyclesLate) @@ -208,7 +211,7 @@ void ThrottleCallback(Core::System& system, u64 deadline, s64 cyclesLate) } // reschedule 1ms (possibly scaled by emulation_speed) into future on ppc // add 1ms to the deadline - CoreTiming::ScheduleEvent(next_event - cyclesLate, et_Throttle, deadline + 1000); + system.GetCoreTiming().ScheduleEvent(next_event - cyclesLate, et_Throttle, deadline + 1000); } } // namespace @@ -219,34 +222,43 @@ u32 GetTicksPerSecond() void DecrementerSet() { + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + u32 decValue = PowerPC::ppcState.spr[SPR_DEC]; - CoreTiming::RemoveEvent(et_Dec); + core_timing.RemoveEvent(et_Dec); if ((decValue & 0x80000000) == 0) { - CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks()); - CoreTiming::SetFakeDecStartValue(decValue); + core_timing.SetFakeDecStartTicks(core_timing.GetTicks()); + core_timing.SetFakeDecStartValue(decValue); - CoreTiming::ScheduleEvent(decValue * TIMER_RATIO, et_Dec); + core_timing.ScheduleEvent(decValue * TIMER_RATIO, et_Dec); } } u32 GetFakeDecrementer() { - return (CoreTiming::GetFakeDecStartValue() - - (u32)((CoreTiming::GetTicks() - CoreTiming::GetFakeDecStartTicks()) / TIMER_RATIO)); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + return (core_timing.GetFakeDecStartValue() - + (u32)((core_timing.GetTicks() - core_timing.GetFakeDecStartTicks()) / TIMER_RATIO)); } void TimeBaseSet() { - CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks()); - CoreTiming::SetFakeTBStartValue(PowerPC::ReadFullTimeBaseValue()); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.SetFakeTBStartTicks(core_timing.GetTicks()); + core_timing.SetFakeTBStartValue(PowerPC::ReadFullTimeBaseValue()); } u64 GetFakeTimeBase() { - return CoreTiming::GetFakeTBStartValue() + - ((CoreTiming::GetTicks() - CoreTiming::GetFakeTBStartTicks()) / TIMER_RATIO); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + return core_timing.GetFakeTBStartValue() + + ((core_timing.GetTicks() - core_timing.GetFakeTBStartTicks()) / TIMER_RATIO); } s64 GetLocalTimeRTCOffset() @@ -293,7 +305,8 @@ void ChangePPCClock(Mode mode) s_cpu_core_clock = 729000000u; else s_cpu_core_clock = 486000000u; - CoreTiming::AdjustEventQueueTimes(s_cpu_core_clock, previous_clock); + Core::System::GetInstance().GetCoreTiming().AdjustEventQueueTimes(s_cpu_core_clock, + previous_clock); } void Init() @@ -315,32 +328,35 @@ void Init() Common::Timer::GetLocalTimeSinceJan1970() - Config::Get(Config::MAIN_CUSTOM_RTC_VALUE); } - CoreTiming::SetFakeTBStartValue(static_cast(s_cpu_core_clock / TIMER_RATIO) * + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + + core_timing.SetFakeTBStartValue(static_cast(s_cpu_core_clock / TIMER_RATIO) * static_cast(ExpansionInterface::CEXIIPL::GetEmulatedTime( ExpansionInterface::CEXIIPL::GC_EPOCH))); - CoreTiming::SetFakeTBStartTicks(CoreTiming::GetTicks()); + core_timing.SetFakeTBStartTicks(core_timing.GetTicks()); - CoreTiming::SetFakeDecStartValue(0xFFFFFFFF); - CoreTiming::SetFakeDecStartTicks(CoreTiming::GetTicks()); + core_timing.SetFakeDecStartValue(0xFFFFFFFF); + core_timing.SetFakeDecStartTicks(core_timing.GetTicks()); - et_Dec = CoreTiming::RegisterEvent("DecCallback", DecrementerCallback); - et_VI = CoreTiming::RegisterEvent("VICallback", VICallback); - et_DSP = CoreTiming::RegisterEvent("DSPCallback", DSPCallback); - et_AudioDMA = CoreTiming::RegisterEvent("AudioDMACallback", AudioDMACallback); - et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback); - et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback); - et_Throttle = CoreTiming::RegisterEvent("Throttle", ThrottleCallback); + et_Dec = core_timing.RegisterEvent("DecCallback", DecrementerCallback); + et_VI = core_timing.RegisterEvent("VICallback", VICallback); + et_DSP = core_timing.RegisterEvent("DSPCallback", DSPCallback); + et_AudioDMA = core_timing.RegisterEvent("AudioDMACallback", AudioDMACallback); + et_IPC_HLE = core_timing.RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback); + et_PatchEngine = core_timing.RegisterEvent("PatchEngine", PatchEngineCallback); + et_Throttle = core_timing.RegisterEvent("Throttle", ThrottleCallback); - CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerHalfLine(), et_VI); - CoreTiming::ScheduleEvent(0, et_DSP); - CoreTiming::ScheduleEvent(GetAudioDMACallbackPeriod(), et_AudioDMA); - CoreTiming::ScheduleEvent(0, et_Throttle, 0); + core_timing.ScheduleEvent(VideoInterface::GetTicksPerHalfLine(), et_VI); + core_timing.ScheduleEvent(0, et_DSP); + core_timing.ScheduleEvent(GetAudioDMACallbackPeriod(), et_AudioDMA); + core_timing.ScheduleEvent(0, et_Throttle, 0); - CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine); + core_timing.ScheduleEvent(VideoInterface::GetTicksPerField(), et_PatchEngine); if (SConfig::GetInstance().bWii) - CoreTiming::ScheduleEvent(s_ipc_hle_period, et_IPC_HLE); + core_timing.ScheduleEvent(s_ipc_hle_period, et_IPC_HLE); s_emu_to_real_time_ring_buffer.fill(0); } diff --git a/Source/Core/Core/HW/VideoInterface.cpp b/Source/Core/Core/HW/VideoInterface.cpp index db195644cd..a743bd0cae 100644 --- a/Source/Core/Core/HW/VideoInterface.cpp +++ b/Source/Core/Core/HW/VideoInterface.cpp @@ -317,7 +317,8 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) base | VI_HORIZONTAL_BEAM_POSITION, MMIO::ComplexRead([](Core::System& system, u32) { auto& state = system.GetVideoInterfaceState().GetData(); u16 value = static_cast( - 1 + state.h_timing_0.HLW * (CoreTiming::GetTicks() - state.ticks_last_line_start) / + 1 + state.h_timing_0.HLW * + (system.GetCoreTiming().GetTicks() - state.ticks_last_line_start) / (GetTicksPerHalfLine())); return std::clamp(value, 1, state.h_timing_0.HLW * 2); }), @@ -878,7 +879,8 @@ static void EndField(FieldType field, u64 ticks) // Run when: When a frame is scanned (progressive/interlace) void Update(u64 ticks) { - auto& state = Core::System::GetInstance().GetVideoInterfaceState().GetData(); + auto& system = Core::System::GetInstance(); + auto& state = system.GetVideoInterfaceState().GetData(); // Movie's frame counter should be updated before actually rendering the frame, // in case frame counter display is enabled @@ -946,7 +948,7 @@ void Update(u64 ticks) if (!(state.half_line_count & 1)) { - state.ticks_last_line_start = CoreTiming::GetTicks(); + state.ticks_last_line_start = system.GetCoreTiming().GetTicks(); } // Check if we need to assert IR_INT. Note that the granularity of our current horizontal diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index 933ed40c5c..3ebff20a69 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -157,7 +157,8 @@ static void InitState() void Init() { InitState(); - updateInterrupts = CoreTiming::RegisterEvent("IPCInterrupt", UpdateInterrupts); + updateInterrupts = + Core::System::GetInstance().GetCoreTiming().RegisterEvent("IPCInterrupt", UpdateInterrupts); } void Reset() @@ -176,7 +177,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) mmio->Register(base | IPC_PPCCTRL, MMIO::ComplexRead([](Core::System&, u32) { return ctrl.ppc(); }), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { ctrl.ppc(val); // The IPC interrupt is triggered when IY1/IY2 is set and // Y1/Y2 is written to -- even when this results in clearing the bit. @@ -185,25 +186,25 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base) if (ctrl.X1) HLE::GetIOS()->EnqueueIPCRequest(ppc_msg); HLE::GetIOS()->UpdateIPC(); - CoreTiming::ScheduleEvent(0, updateInterrupts, 0); + system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0); })); mmio->Register(base | IPC_ARMMSG, MMIO::DirectRead(&arm_msg), MMIO::InvalidWrite()); mmio->Register(base | PPC_IRQFLAG, MMIO::InvalidRead(), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { ppc_irq_flags &= ~val; HLE::GetIOS()->UpdateIPC(); - CoreTiming::ScheduleEvent(0, updateInterrupts, 0); + system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0); })); mmio->Register(base | PPC_IRQMASK, MMIO::InvalidRead(), - MMIO::ComplexWrite([](Core::System&, u32, u32 val) { + MMIO::ComplexWrite([](Core::System& system, u32, u32 val) { ppc_irq_masks = val; if (ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf? Reset(); HLE::GetIOS()->UpdateIPC(); - CoreTiming::ScheduleEvent(0, updateInterrupts, 0); + system.GetCoreTiming().ScheduleEvent(0, updateInterrupts, 0); })); mmio->Register(base | GPIOB_OUT, MMIO::DirectRead(&g_gpio_out.m_hex), @@ -313,7 +314,8 @@ void GenerateAck(u32 address) ctrl.Y2, ctrl.X1); // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire // after Y2 is seen in the control register. - CoreTiming::ScheduleEvent(100 * SystemTimers::TIMER_RATIO, updateInterrupts); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, + updateInterrupts); } void GenerateReply(u32 address) @@ -324,7 +326,8 @@ void GenerateReply(u32 address) ctrl.Y1, ctrl.Y2, ctrl.X1); // Based on a hardware test, the IPC interrupt takes approximately 100 TB ticks to fire // after Y1 is seen in the control register. - CoreTiming::ScheduleEvent(100 * SystemTimers::TIMER_RATIO, updateInterrupts); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(100 * SystemTimers::TIMER_RATIO, + updateInterrupts); } bool IsReady() diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp index c15a015ee8..cfaa208ad6 100644 --- a/Source/Core/Core/IOS/DI/DI.cpp +++ b/Source/Core/Core/IOS/DI/DI.cpp @@ -113,8 +113,8 @@ void DIDevice::ProcessQueuedIOCtl() auto finished = StartIOCtl(request); if (finished) { - CoreTiming::ScheduleEvent(IPC_OVERHEAD_TICKS, s_finish_executing_di_command, - static_cast(finished.value())); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent( + IPC_OVERHEAD_TICKS, s_finish_executing_di_command, static_cast(finished.value())); return; } } diff --git a/Source/Core/Core/IOS/ES/ES.cpp b/Source/Core/Core/IOS/ES/ES.cpp index ffd75a5db9..afb194fe24 100644 --- a/Source/Core/Core/IOS/ES/ES.cpp +++ b/Source/Core/Core/IOS/ES/ES.cpp @@ -26,6 +26,7 @@ #include "Core/IOS/IOSC.h" #include "Core/IOS/Uids.h" #include "Core/IOS/VersionInfo.h" +#include "Core/System.h" #include "DiscIO/Enums.h" namespace IOS::HLE @@ -103,8 +104,10 @@ ESDevice::ESDevice(Kernel& ios, const std::string& device_name) : Device(ios, de if (Core::IsRunningAndStarted()) { - CoreTiming::RemoveEvent(s_finish_init_event); - CoreTiming::ScheduleEvent(GetESBootTicks(m_ios.GetVersion()), s_finish_init_event); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.RemoveEvent(s_finish_init_event); + core_timing.ScheduleEvent(GetESBootTicks(m_ios.GetVersion()), s_finish_init_event); } else { @@ -114,14 +117,16 @@ ESDevice::ESDevice(Kernel& ios, const std::string& device_name) : Device(ios, de void ESDevice::InitializeEmulationState() { - s_finish_init_event = CoreTiming::RegisterEvent( + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + s_finish_init_event = core_timing.RegisterEvent( "IOS-ESFinishInit", [](Core::System& system, u64, s64) { GetIOS()->GetES()->FinishInit(); }); - s_reload_ios_for_ppc_launch_event = CoreTiming::RegisterEvent( + s_reload_ios_for_ppc_launch_event = core_timing.RegisterEvent( "IOS-ESReloadIOSForPPCLaunch", [](Core::System& system, u64 ios_id, s64) { GetIOS()->GetES()->LaunchTitle(ios_id, HangPPC::Yes); }); s_bootstrap_ppc_for_launch_event = - CoreTiming::RegisterEvent("IOS-ESBootstrapPPCForLaunch", [](Core::System& system, u64, s64) { + core_timing.RegisterEvent("IOS-ESBootstrapPPCForLaunch", [](Core::System& system, u64, s64) { GetIOS()->GetES()->BootstrapPPC(); }); } @@ -397,6 +402,9 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) return false; } + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + // Before launching a title, IOS first reads the TMD and reloads into the specified IOS version, // even when that version is already running. After it has reloaded, ES_Launch will be called // again and the PPC will be bootstrapped then. @@ -417,8 +425,8 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) const u64 required_ios = tmd.GetIOSId(); if (!Core::IsRunningAndStarted()) return LaunchTitle(required_ios, HangPPC::Yes); - CoreTiming::RemoveEvent(s_reload_ios_for_ppc_launch_event); - CoreTiming::ScheduleEvent(ticks, s_reload_ios_for_ppc_launch_event, required_ios); + core_timing.RemoveEvent(s_reload_ios_for_ppc_launch_event); + core_timing.ScheduleEvent(ticks, s_reload_ios_for_ppc_launch_event, required_ios); return true; } @@ -446,8 +454,9 @@ bool ESDevice::LaunchPPCTitle(u64 title_id) m_pending_ppc_boot_content_path = GetContentPath(tmd.GetTitleId(), content); if (!Core::IsRunningAndStarted()) return BootstrapPPC(); - CoreTiming::RemoveEvent(s_bootstrap_ppc_for_launch_event); - CoreTiming::ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event); + + core_timing.RemoveEvent(s_bootstrap_ppc_for_launch_event); + core_timing.ScheduleEvent(ticks, s_bootstrap_ppc_for_launch_event); return true; } diff --git a/Source/Core/Core/IOS/IOS.cpp b/Source/Core/Core/IOS/IOS.cpp index a86ad271b7..4c2da5b577 100644 --- a/Source/Core/Core/IOS/IOS.cpp +++ b/Source/Core/Core/IOS/IOS.cpp @@ -56,6 +56,7 @@ #include "Core/IOS/WFS/WFSI.h" #include "Core/IOS/WFS/WFSSRV.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" #include "Core/WiiRoot.h" namespace IOS::HLE @@ -320,7 +321,7 @@ EmulationKernel::EmulationKernel(u64 title_id) : Kernel(title_id) EmulationKernel::~EmulationKernel() { - CoreTiming::RemoveAllEvents(s_event_enqueue); + Core::System::GetInstance().GetCoreTiming().RemoveAllEvents(s_event_enqueue); } // The title ID is a u64 where the first 32 bits are used for the title type. @@ -410,7 +411,8 @@ bool Kernel::BootstrapPPC(const std::string& boot_content_path) return false; INFO_LOG_FMT(IOS, "BootstrapPPC: {}", boot_content_path); - CoreTiming::ScheduleEvent(ticks, s_event_finish_ppc_bootstrap, dol.IsAncast()); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(ticks, s_event_finish_ppc_bootstrap, + dol.IsAncast()); return true; } @@ -485,9 +487,14 @@ bool Kernel::BootIOS(const u64 ios_title_id, HangPPC hang_ppc, const std::string ResetAndPausePPC(); if (Core::IsRunningAndStarted()) - CoreTiming::ScheduleEvent(GetIOSBootTicks(GetVersion()), s_event_finish_ios_boot, ios_title_id); + { + Core::System::GetInstance().GetCoreTiming().ScheduleEvent( + GetIOSBootTicks(GetVersion()), s_event_finish_ios_boot, ios_title_id); + } else + { FinishIOSBoot(ios_title_id); + } return true; } @@ -720,10 +727,12 @@ void Kernel::ExecuteIPCCommand(const u32 address) return; // Ensure replies happen in order - const s64 ticks_until_last_reply = m_last_reply_time - CoreTiming::GetTicks(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + const s64 ticks_until_last_reply = m_last_reply_time - core_timing.GetTicks(); if (ticks_until_last_reply > 0) result->reply_delay_ticks += ticks_until_last_reply; - m_last_reply_time = CoreTiming::GetTicks() + result->reply_delay_ticks; + m_last_reply_time = core_timing.GetTicks() + result->reply_delay_ticks; EnqueueIPCReply(request, result->return_value, result->reply_delay_ticks); } @@ -734,7 +743,8 @@ void Kernel::EnqueueIPCRequest(u32 address) // Based on hardware tests, IOS takes between 5µs and 10µs to acknowledge an IPC request. // Console 1: 456 TB ticks before ACK // Console 2: 658 TB ticks before ACK - CoreTiming::ScheduleEvent(500_tbticks, s_event_enqueue, address | ENQUEUE_REQUEST_FLAG); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(500_tbticks, s_event_enqueue, + address | ENQUEUE_REQUEST_FLAG); } // Called to send a reply to an IOS syscall @@ -746,7 +756,8 @@ void Kernel::EnqueueIPCReply(const Request& request, const s32 return_value, s64 Memory::Write_U32(request.command, request.address + 8); // IOS also overwrites the command type with the reply type. Memory::Write_U32(IPC_REPLY, request.address); - CoreTiming::ScheduleEvent(cycles_in_future, s_event_enqueue, request.address, from); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(cycles_in_future, s_event_enqueue, + request.address, from); } void Kernel::HandleIPCEvent(u64 userdata) @@ -892,8 +903,11 @@ static void FinishPPCBootstrap(Core::System& system, u64 userdata, s64 cycles_la void Init() { + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + s_event_enqueue = - CoreTiming::RegisterEvent("IPCEvent", [](Core::System& system, u64 userdata, s64) { + core_timing.RegisterEvent("IPCEvent", [](Core::System& system, u64 userdata, s64) { if (s_ios) s_ios->HandleIPCEvent(userdata); }); @@ -901,14 +915,14 @@ void Init() ESDevice::InitializeEmulationState(); s_event_finish_ppc_bootstrap = - CoreTiming::RegisterEvent("IOSFinishPPCBootstrap", FinishPPCBootstrap); + core_timing.RegisterEvent("IOSFinishPPCBootstrap", FinishPPCBootstrap); s_event_finish_ios_boot = - CoreTiming::RegisterEvent("IOSFinishIOSBoot", [](Core::System& system, u64 ios_title_id, + core_timing.RegisterEvent("IOSFinishIOSBoot", [](Core::System& system, u64 ios_title_id, s64) { FinishIOSBoot(ios_title_id); }); DIDevice::s_finish_executing_di_command = - CoreTiming::RegisterEvent("FinishDICommand", DIDevice::FinishDICommandCallback); + core_timing.RegisterEvent("FinishDICommand", DIDevice::FinishDICommandCallback); // Start with IOS80 to simulate part of the Wii boot process. s_ios = std::make_unique(Titles::SYSTEM_MENU_IOS); diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp index ea365ba284..edc5d02ab6 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTEmu.cpp @@ -25,6 +25,7 @@ #include "Core/NetPlayClient.h" #include "Core/NetPlayProto.h" #include "Core/SysConf.h" +#include "Core/System.h" #include "InputCommon/ControllerInterface/ControllerInterface.h" namespace IOS::HLE @@ -339,7 +340,7 @@ void BluetoothEmuDevice::Update() wiimote->Update(); const u64 interval = SystemTimers::GetTicksPerSecond() / Wiimote::UPDATE_FREQ; - const u64 now = CoreTiming::GetTicks(); + const u64 now = Core::System::GetInstance().GetCoreTiming().GetTicks(); if (now - m_last_ticks > interval) { diff --git a/Source/Core/Core/Movie.cpp b/Source/Core/Core/Movie.cpp index eb432bd926..0e16010df2 100644 --- a/Source/Core/Core/Movie.cpp +++ b/Source/Core/Core/Movie.cpp @@ -63,6 +63,7 @@ #include "Core/IOS/USB/Bluetooth/WiimoteDevice.h" #include "Core/NetPlayProto.h" #include "Core/State.h" +#include "Core/System.h" #include "Core/WiiUtils.h" #include "DiscIO/Enums.h" @@ -290,9 +291,12 @@ void InputUpdate() s_currentInputCount++; if (IsRecordingInput()) { + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + s_totalInputCount = s_currentInputCount; - s_totalTickCount += CoreTiming::GetTicks() - s_tickCountAtLastInput; - s_tickCountAtLastInput = CoreTiming::GetTicks(); + s_totalTickCount += core_timing.GetTicks() - s_tickCountAtLastInput; + s_tickCountAtLastInput = core_timing.GetTicks(); } } @@ -1181,7 +1185,8 @@ void LoadInput(const std::string& movie_path) static void CheckInputEnd() { if (s_currentByte >= s_temp_input.size() || - (CoreTiming::GetTicks() > s_totalTickCount && !IsRecordingInputFromSaveState())) + (Core::System::GetInstance().GetCoreTiming().GetTicks() > s_totalTickCount && + !IsRecordingInputFromSaveState())) { EndPlayInput(!s_bReadOnly); } diff --git a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp index a820ae2435..a0496b5437 100644 --- a/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp +++ b/Source/Core/Core/PowerPC/CachedInterpreter/CachedInterpreter.cpp @@ -13,6 +13,7 @@ #include "Core/PowerPC/Jit64Common/Jit64Constants.h" #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" struct CachedInterpreter::Instruction { @@ -109,12 +110,15 @@ void CachedInterpreter::ExecuteOneBlock() void CachedInterpreter::Run() { + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + const CPU::State* state_ptr = CPU::GetStatePtr(); while (CPU::GetState() == CPU::State::Running) { // Start new timing slice // NOTE: Exceptions may change PC - CoreTiming::Advance(); + core_timing.Advance(); do { @@ -126,7 +130,7 @@ void CachedInterpreter::Run() void CachedInterpreter::SingleStep() { // Enter new timing slice - CoreTiming::Advance(); + Core::System::GetInstance().GetCoreTiming().Advance(); ExecuteOneBlock(); } @@ -207,7 +211,7 @@ static bool CheckIdle(u32 idle_pc) { if (PowerPC::ppcState.npc == idle_pc) { - CoreTiming::Idle(); + Core::System::GetInstance().GetCoreTiming().Idle(); } return false; } diff --git a/Source/Core/Core/PowerPC/GDBStub.cpp b/Source/Core/Core/PowerPC/GDBStub.cpp index 775f189bb0..9a9d8f8649 100644 --- a/Source/Core/Core/PowerPC/GDBStub.cpp +++ b/Source/Core/Core/PowerPC/GDBStub.cpp @@ -37,6 +37,7 @@ typedef SSIZE_T ssize_t; #include "Core/PowerPC/Gekko.h" #include "Core/PowerPC/PPCCache.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" namespace GDBStub { @@ -128,7 +129,7 @@ static void UpdateCallback(Core::System& system, u64 userdata, s64 cycles_late) { ProcessCommands(false); if (IsActive()) - CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event); } static u8 ReadByte() @@ -1068,8 +1069,10 @@ static void InitGeneric(int domain, const sockaddr* server_addr, socklen_t serve #endif s_tmpsock = -1; - s_update_event = CoreTiming::RegisterEvent("GDBStubUpdate", UpdateCallback); - CoreTiming::ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + s_update_event = core_timing.RegisterEvent("GDBStubUpdate", UpdateCallback); + core_timing.ScheduleEvent(GDB_UPDATE_CYCLES, s_update_event); s_has_control = true; } diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index ec3d0229b9..2dade57576 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -215,7 +215,7 @@ void Interpreter::SingleStep() auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); // Declare start of new slice - CoreTiming::Advance(); + Core::System::GetInstance().GetCoreTiming().Advance(); SingleStepInner(); @@ -241,12 +241,14 @@ constexpr u32 s_show_steps = 300; // FastRun - inspired by GCemu (to imitate the JIT so that they can be compared). void Interpreter::Run() { + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); while (CPU::GetState() == CPU::State::Running) { // CoreTiming Advance() ends the previous slice and declares the start of the next // one so it must always be called at the start. At boot, we are in slice -1 and must // advance into slice 0 to get a correct slice length before executing any cycles. - CoreTiming::Advance(); + core_timing.Advance(); // we have to check exceptions at branches apparently (or maybe just rfi?) if (Config::Get(Config::MAIN_ENABLE_DEBUGGING)) diff --git a/Source/Core/Core/PowerPC/Jit64/Jit.cpp b/Source/Core/Core/PowerPC/Jit64/Jit.cpp index 285cf3a848..24cc357bd6 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit.cpp @@ -44,6 +44,7 @@ #include "Core/PowerPC/PPCAnalyst.h" #include "Core/PowerPC/PowerPC.h" #include "Core/PowerPC/Profiler.h" +#include "Core/System.h" using namespace Gen; using namespace PowerPC; @@ -205,7 +206,7 @@ bool Jit64::HandleStackFault() // to reset the guard page. // Yeah, it's kind of gross. GetBlockCache()->InvalidateICache(0, 0xffffffff, true); - CoreTiming::ForceExceptionCheck(0); + Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0); m_cleanup_after_stackfault = true; return true; @@ -685,7 +686,7 @@ void Jit64::WriteRfiExitDestInRSCRATCH() void Jit64::WriteIdleExit(u32 destination) { ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(CoreTiming::Idle); + ABI_CallFunction(CoreTiming::GlobalIdle); ABI_PopRegistersAndAdjustStack({}, 0); MOV(32, PPCSTATE(pc), Imm32(destination)); WriteExceptionExit(); diff --git a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp index b55c6f3d01..123e205432 100644 --- a/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/Jit64/JitAsm.cpp @@ -65,7 +65,7 @@ void Jit64AsmRoutineManager::Generate() const u8* outerLoop = GetCodePtr(); ABI_PushRegistersAndAdjustStack({}, 0); - ABI_CallFunction(CoreTiming::Advance); + ABI_CallFunction(CoreTiming::GlobalAdvance); ABI_PopRegistersAndAdjustStack({}, 0); FixupBranch skipToRealDispatch = J(enable_debugging); // skip the sync and compare first time dispatcher_mispredicted_blr = GetCodePtr(); diff --git a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp index 4afd8ac92e..31b4a210e6 100644 --- a/Source/Core/Core/PowerPC/JitArm64/Jit.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/Jit.cpp @@ -24,6 +24,7 @@ #include "Core/PowerPC/JitArm64/JitArm64_RegCache.h" #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/Profiler.h" +#include "Core/System.h" using namespace Arm64Gen; @@ -120,7 +121,7 @@ bool JitArm64::HandleStackFault() Common::UnWriteProtectMemory(m_stack_base + GUARD_OFFSET, GUARD_SIZE); #endif GetBlockCache()->InvalidateICache(0, 0xffffffff, true); - CoreTiming::ForceExceptionCheck(0); + Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0); m_cleanup_after_stackfault = true; return true; diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp index a92bc950ea..b2a2d723bd 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_Branch.cpp @@ -105,7 +105,7 @@ void JitArm64::bx(UGeckoInstruction inst) ARM64Reg WA = gpr.GetReg(); ARM64Reg XA = EncodeRegTo64(WA); - MOVP2R(XA, &CoreTiming::Idle); + MOVP2R(XA, &CoreTiming::GlobalIdle); BLR(XA); gpr.Unlock(WA); @@ -161,7 +161,7 @@ void JitArm64::bcx(UGeckoInstruction inst) // make idle loops go faster ARM64Reg XA = EncodeRegTo64(WA); - MOVP2R(XA, &CoreTiming::Idle); + MOVP2R(XA, &CoreTiming::GlobalIdle); BLR(XA); WriteExceptionExit(js.op->branchTo); @@ -281,7 +281,7 @@ void JitArm64::bclrx(UGeckoInstruction inst) // make idle loops go faster ARM64Reg XA = EncodeRegTo64(WA); - MOVP2R(XA, &CoreTiming::Idle); + MOVP2R(XA, &CoreTiming::GlobalIdle); BLR(XA); WriteExceptionExit(js.op->branchTo); diff --git a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp index 05d3a880d7..3ed2917c34 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitAsm.cpp @@ -172,7 +172,7 @@ void JitArm64::GenerateAsm() FixupBranch Exit = B(CC_NEQ); SetJumpTarget(to_start_of_timing_slice); - MOVP2R(ARM64Reg::X8, &CoreTiming::Advance); + MOVP2R(ARM64Reg::X8, &CoreTiming::GlobalAdvance); BLR(ARM64Reg::X8); // Load the PC back into DISPATCHER_PC (the exception handler might have changed it) diff --git a/Source/Core/Core/PowerPC/PowerPC.cpp b/Source/Core/Core/PowerPC/PowerPC.cpp index 72f6a731eb..eafa547e92 100644 --- a/Source/Core/Core/PowerPC/PowerPC.cpp +++ b/Source/Core/Core/PowerPC/PowerPC.cpp @@ -31,6 +31,7 @@ #include "Core/PowerPC/JitInterface.h" #include "Core/PowerPC/MMU.h" #include "Core/PowerPC/PPCSymbolDB.h" +#include "Core/System.h" namespace PowerPC { @@ -258,8 +259,8 @@ CPUCore DefaultCPUCore() void Init(CPUCore cpu_core) { - s_invalidate_cache_thread_safe = - CoreTiming::RegisterEvent("invalidateEmulatedCache", InvalidateCacheThreadSafe); + s_invalidate_cache_thread_safe = Core::System::GetInstance().GetCoreTiming().RegisterEvent( + "invalidateEmulatedCache", InvalidateCacheThreadSafe); Reset(); @@ -284,8 +285,8 @@ void ScheduleInvalidateCacheThreadSafe(u32 address) { if (CPU::GetState() == CPU::State::Running) { - CoreTiming::ScheduleEvent(0, s_invalidate_cache_thread_safe, address, - CoreTiming::FromThread::NON_CPU); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent( + 0, s_invalidate_cache_thread_safe, address, CoreTiming::FromThread::NON_CPU); } else { diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp index a735dc322f..d06b146aa8 100644 --- a/Source/Core/Core/State.cpp +++ b/Source/Core/Core/State.cpp @@ -39,6 +39,7 @@ #include "Core/Movie.h" #include "Core/NetPlayClient.h" #include "Core/PowerPC/PowerPC.h" +#include "Core/System.h" #include "VideoCommon/FrameDump.h" #include "VideoCommon/OnScreenDisplay.h" @@ -224,7 +225,7 @@ static void DoState(PointerWrap& p) p.DoMarker("PowerPC"); // CoreTiming needs to be restored before restoring Hardware because // the controller code might need to schedule an event if the controller has changed. - CoreTiming::DoState(p); + Core::System::GetInstance().GetCoreTiming().DoState(p); p.DoMarker("CoreTiming"); HW::DoState(p); p.DoMarker("HW"); diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index aa7bc23b0e..16d5086e9f 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -27,7 +27,7 @@ struct System::Impl bool m_audio_dump_started = false; AudioInterface::AudioInterfaceState m_audio_interface_state; - CoreTiming::CoreTimingState m_core_timing_state; + CoreTiming::CoreTimingManager m_core_timing; CoreTiming::Globals m_core_timing_globals; DSP::DSPState m_dsp_state; DVDInterface::DVDInterfaceState m_dvd_interface_state; @@ -87,9 +87,9 @@ AudioInterface::AudioInterfaceState& System::GetAudioInterfaceState() const return m_impl->m_audio_interface_state; } -CoreTiming::CoreTimingState& System::GetCoreTimingState() const +CoreTiming::CoreTimingManager& System::GetCoreTiming() const { - return m_impl->m_core_timing_state; + return m_impl->m_core_timing; } CoreTiming::Globals& System::GetCoreTimingGlobals() const diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index 71e69cd845..bdcd37f75d 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -14,7 +14,7 @@ class AudioInterfaceState; }; namespace CoreTiming { -class CoreTimingState; +class CoreTimingManager; struct Globals; } // namespace CoreTiming namespace DSP @@ -81,7 +81,7 @@ public: void SetAudioDumpStarted(bool started); AudioInterface::AudioInterfaceState& GetAudioInterfaceState() const; - CoreTiming::CoreTimingState& GetCoreTimingState() const; + CoreTiming::CoreTimingManager& GetCoreTiming() const; CoreTiming::Globals& GetCoreTimingGlobals() const; DSP::DSPState& GetDSPState() const; DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const; diff --git a/Source/Core/DolphinQt/GBAWidget.cpp b/Source/Core/DolphinQt/GBAWidget.cpp index f009f4206c..eb868440e5 100644 --- a/Source/Core/DolphinQt/GBAWidget.cpp +++ b/Source/Core/DolphinQt/GBAWidget.cpp @@ -42,10 +42,12 @@ static void RestartCore(const std::weak_ptr& core, std::string_vi auto& info = Config::MAIN_GBA_ROM_PATHS[core_ptr->GetCoreInfo().device_number]; core_ptr->Stop(); Config::SetCurrent(info, rom_path); - if (core_ptr->Start(CoreTiming::GetTicks())) + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + if (core_ptr->Start(core_timing.GetTicks())) return; Config::SetCurrent(info, Config::GetBase(info)); - core_ptr->Start(CoreTiming::GetTicks()); + core_ptr->Start(core_timing.GetTicks()); } }, false); diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 1e91a08eba..1ff134551c 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -33,6 +33,7 @@ #include "Core/HW/SI/SI.h" #include "Core/HW/SI/SI_Device.h" #include "Core/HW/SystemTimers.h" +#include "Core/System.h" #include "InputCommon/GCPadStatus.h" #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION @@ -419,10 +420,12 @@ void Init() if (Core::GetState() != Core::State::Uninitialized && Core::GetState() != Core::State::Starting) { - if ((CoreTiming::GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond()) + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + if ((core_timing.GetTicks() - s_last_init) < SystemTimers::GetTicksPerSecond()) return; - s_last_init = CoreTiming::GetTicks(); + s_last_init = core_timing.GetTicks(); } #if GCADAPTER_USE_LIBUSB_IMPLEMENTATION diff --git a/Source/Core/VideoCommon/BPStructs.cpp b/Source/Core/VideoCommon/BPStructs.cpp index bf0438a74b..a4c381d313 100644 --- a/Source/Core/VideoCommon/BPStructs.cpp +++ b/Source/Core/VideoCommon/BPStructs.cpp @@ -21,6 +21,7 @@ #include "Core/FifoPlayer/FifoRecorder.h" #include "Core/HW/Memmap.h" #include "Core/HW/VideoInterface.h" +#include "Core/System.h" #include "VideoCommon/BPFunctions.h" #include "VideoCommon/BPMemory.h" @@ -324,7 +325,8 @@ static void BPWritten(const BPCmd& bp, int cycles_into_future) if (g_ActiveConfig.bImmediateXFB) { // below div two to convert from bytes to pixels - it expects width, not stride - g_renderer->Swap(destAddr, destStride / 2, destStride, height, CoreTiming::GetTicks()); + g_renderer->Swap(destAddr, destStride / 2, destStride, height, + Core::System::GetInstance().GetCoreTiming().GetTicks()); } else { diff --git a/Source/Core/VideoCommon/CommandProcessor.cpp b/Source/Core/VideoCommon/CommandProcessor.cpp index ada2d02904..f9d47dd2fe 100644 --- a/Source/Core/VideoCommon/CommandProcessor.cpp +++ b/Source/Core/VideoCommon/CommandProcessor.cpp @@ -149,7 +149,8 @@ void Init() s_interrupt_set.Clear(); s_interrupt_waiting.Clear(); - et_UpdateInterrupts = CoreTiming::RegisterEvent("CPInterrupt", UpdateInterrupts_Wrapper); + et_UpdateInterrupts = Core::System::GetInstance().GetCoreTiming().RegisterEvent( + "CPInterrupt", UpdateInterrupts_Wrapper); } u32 GetPhysicalAddressMask() @@ -406,7 +407,7 @@ void GatherPipeBursted() // If the game is running close to overflowing, make the exception checking more frequent. if (fifo.bFF_HiWatermark.load(std::memory_order_relaxed) != 0) - CoreTiming::ForceExceptionCheck(0); + Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0); fifo.CPReadWriteDistance.fetch_add(GPFifo::GATHER_PIPE_SIZE, std::memory_order_seq_cst); @@ -445,7 +446,7 @@ void UpdateInterrupts(u64 userdata) DEBUG_LOG_FMT(COMMANDPROCESSOR, "Interrupt cleared"); ProcessorInterface::SetInterrupt(INT_CAUSE_CP, false); } - CoreTiming::ForceExceptionCheck(0); + Core::System::GetInstance().GetCoreTiming().ForceExceptionCheck(0); s_interrupt_waiting.Clear(); Fifo::RunGpu(); } @@ -453,7 +454,10 @@ void UpdateInterrupts(u64 userdata) void UpdateInterruptsFromVideoBackend(u64 userdata) { if (!Fifo::UseDeterministicGPUThread()) - CoreTiming::ScheduleEvent(0, et_UpdateInterrupts, userdata, CoreTiming::FromThread::NON_CPU); + { + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(0, et_UpdateInterrupts, userdata, + CoreTiming::FromThread::NON_CPU); + } } bool IsInterruptWaiting() diff --git a/Source/Core/VideoCommon/Fifo.cpp b/Source/Core/VideoCommon/Fifo.cpp index a69a83b00f..2166d1a48d 100644 --- a/Source/Core/VideoCommon/Fifo.cpp +++ b/Source/Core/VideoCommon/Fifo.cpp @@ -448,7 +448,8 @@ bool AtBreakpoint() void RunGpu() { - const bool is_dual_core = Core::System::GetInstance().IsDualCoreMode(); + auto& system = Core::System::GetInstance(); + const bool is_dual_core = system.IsDualCoreMode(); // wake up GPU thread if (is_dual_core && !s_use_deterministic_gpu_thread) @@ -462,7 +463,8 @@ void RunGpu() if (s_syncing_suspended) { s_syncing_suspended = false; - CoreTiming::ScheduleEvent(GPU_TIME_SLOT_SIZE, s_event_sync_gpu, GPU_TIME_SLOT_SIZE); + system.GetCoreTiming().ScheduleEvent(GPU_TIME_SLOT_SIZE, s_event_sync_gpu, + GPU_TIME_SLOT_SIZE); } } } @@ -611,7 +613,7 @@ static void SyncGPUCallback(Core::System& system, u64 ticks, s64 cyclesLate) s_syncing_suspended = next < 0; if (!s_syncing_suspended) - CoreTiming::ScheduleEvent(next, s_event_sync_gpu, next); + system.GetCoreTiming().ScheduleEvent(next, s_event_sync_gpu, next); } void SyncGPUForRegisterAccess() @@ -627,7 +629,8 @@ void SyncGPUForRegisterAccess() // Initialize GPU - CPU thread syncing, this gives us a deterministic way to start the GPU thread. void Prepare() { - s_event_sync_gpu = CoreTiming::RegisterEvent("SyncGPUCallback", SyncGPUCallback); + s_event_sync_gpu = + Core::System::GetInstance().GetCoreTiming().RegisterEvent("SyncGPUCallback", SyncGPUCallback); s_syncing_suspended = true; } } // namespace Fifo diff --git a/Source/Core/VideoCommon/PixelEngine.cpp b/Source/Core/VideoCommon/PixelEngine.cpp index af8a7a01c2..3623104c76 100644 --- a/Source/Core/VideoCommon/PixelEngine.cpp +++ b/Source/Core/VideoCommon/PixelEngine.cpp @@ -202,8 +202,8 @@ void Init() s_signal_token_interrupt = false; s_signal_finish_interrupt = false; - et_SetTokenFinishOnMainThread = - CoreTiming::RegisterEvent("SetTokenFinish", SetTokenFinish_OnMainThread); + et_SetTokenFinishOnMainThread = Core::System::GetInstance().GetCoreTiming().RegisterEvent( + "SetTokenFinish", SetTokenFinish_OnMainThread); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) @@ -341,7 +341,8 @@ static void RaiseEvent(int cycles_into_future) // games time to setup any interrupt state cycles = std::max(500, cycles_into_future); } - CoreTiming::ScheduleEvent(cycles, et_SetTokenFinishOnMainThread, 0, from); + Core::System::GetInstance().GetCoreTiming().ScheduleEvent(cycles, et_SetTokenFinishOnMainThread, + 0, from); } // SetToken diff --git a/Source/UnitTests/Core/CoreTimingTest.cpp b/Source/UnitTests/Core/CoreTimingTest.cpp index 83bb06097e..6054fb9381 100644 --- a/Source/UnitTests/Core/CoreTimingTest.cpp +++ b/Source/UnitTests/Core/CoreTimingTest.cpp @@ -49,7 +49,9 @@ public: Config::Init(); SConfig::Init(); PowerPC::Init(PowerPC::CPUCore::Interpreter); - CoreTiming::Init(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.Init(); } ~ScopeInit() { @@ -57,7 +59,9 @@ public: { return; } - CoreTiming::Shutdown(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.Shutdown(); PowerPC::Shutdown(); SConfig::Shutdown(); Config::Shutdown(); @@ -78,7 +82,9 @@ static void AdvanceAndCheck(u32 idx, int downcount, int expected_lateness = 0, s_lateness = expected_lateness; PowerPC::ppcState.downcount = cpu_downcount; // Pretend we executed X cycles of instructions. - CoreTiming::Advance(); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + core_timing.Advance(); EXPECT_EQ(decltype(s_callbacks_ran_flags)().set(idx), s_callbacks_ran_flags); EXPECT_EQ(downcount, PowerPC::ppcState.downcount); @@ -89,25 +95,28 @@ TEST(CoreTiming, BasicOrder) ScopeInit guard; ASSERT_TRUE(guard.UserDirectoryExists()); - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); - CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); - CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + + CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); + CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); + CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); + CoreTiming::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>); + CoreTiming::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>); // Enter slice 0 - CoreTiming::Advance(); + core_timing.Advance(); // D -> B -> C -> A -> E - CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); + core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]); EXPECT_EQ(1000, PowerPC::ppcState.downcount); - CoreTiming::ScheduleEvent(500, cb_b, CB_IDS[1]); + core_timing.ScheduleEvent(500, cb_b, CB_IDS[1]); EXPECT_EQ(500, PowerPC::ppcState.downcount); - CoreTiming::ScheduleEvent(800, cb_c, CB_IDS[2]); + core_timing.ScheduleEvent(800, cb_c, CB_IDS[2]); EXPECT_EQ(500, PowerPC::ppcState.downcount); - CoreTiming::ScheduleEvent(100, cb_d, CB_IDS[3]); + core_timing.ScheduleEvent(100, cb_d, CB_IDS[3]); EXPECT_EQ(100, PowerPC::ppcState.downcount); - CoreTiming::ScheduleEvent(1200, cb_e, CB_IDS[4]); + core_timing.ScheduleEvent(1200, cb_e, CB_IDS[4]); EXPECT_EQ(100, PowerPC::ppcState.downcount); AdvanceAndCheck(3, 400); @@ -140,27 +149,30 @@ TEST(CoreTiming, SharedSlot) ScopeInit guard; ASSERT_TRUE(guard.UserDirectoryExists()); - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", FifoCallback<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", FifoCallback<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", FifoCallback<2>); - CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", FifoCallback<3>); - CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", FifoCallback<4>); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); - CoreTiming::ScheduleEvent(1000, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); - CoreTiming::ScheduleEvent(1000, cb_c, CB_IDS[2]); - CoreTiming::ScheduleEvent(1000, cb_d, CB_IDS[3]); - CoreTiming::ScheduleEvent(1000, cb_e, CB_IDS[4]); + CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", FifoCallback<0>); + CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", FifoCallback<1>); + CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", FifoCallback<2>); + CoreTiming::EventType* cb_d = core_timing.RegisterEvent("callbackD", FifoCallback<3>); + CoreTiming::EventType* cb_e = core_timing.RegisterEvent("callbackE", FifoCallback<4>); + + core_timing.ScheduleEvent(1000, cb_a, CB_IDS[0]); + core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]); + core_timing.ScheduleEvent(1000, cb_c, CB_IDS[2]); + core_timing.ScheduleEvent(1000, cb_d, CB_IDS[3]); + core_timing.ScheduleEvent(1000, cb_e, CB_IDS[4]); // Enter slice 0 - CoreTiming::Advance(); + core_timing.Advance(); EXPECT_EQ(1000, PowerPC::ppcState.downcount); s_callbacks_ran_flags = 0; s_counter = 0; s_lateness = 0; PowerPC::ppcState.downcount = 0; - CoreTiming::Advance(); + core_timing.Advance(); EXPECT_EQ(MAX_SLICE_LENGTH, PowerPC::ppcState.downcount); EXPECT_EQ(0x1FULL, s_callbacks_ran_flags.to_ullong()); } @@ -170,14 +182,17 @@ TEST(CoreTiming, PredictableLateness) ScopeInit guard; ASSERT_TRUE(guard.UserDirectoryExists()); - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + + CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); + CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); // Enter slice 0 - CoreTiming::Advance(); + core_timing.Advance(); - CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]); + core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]); + core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]); AdvanceAndCheck(0, 90, 10, -10); // (100 - 10) AdvanceAndCheck(1, MAX_SLICE_LENGTH, 50, -50); @@ -194,7 +209,10 @@ static void RescheduleCallback(Core::System& system, u64 userdata, s64 lateness) EXPECT_EQ(s_lateness, lateness); if (s_reschedules > 0) - CoreTiming::ScheduleEvent(1000, reinterpret_cast(userdata), userdata); + { + system.GetCoreTiming().ScheduleEvent(1000, reinterpret_cast(userdata), + userdata); + } } } // namespace ChainSchedulingTest @@ -205,19 +223,22 @@ TEST(CoreTiming, ChainScheduling) ScopeInit guard; ASSERT_TRUE(guard.UserDirectoryExists()); - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + + CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); + CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); + CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); CoreTiming::EventType* cb_rs = - CoreTiming::RegisterEvent("callbackReschedule", RescheduleCallback); + core_timing.RegisterEvent("callbackReschedule", RescheduleCallback); // Enter slice 0 - CoreTiming::Advance(); + core_timing.Advance(); - CoreTiming::ScheduleEvent(800, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(1000, cb_b, CB_IDS[1]); - CoreTiming::ScheduleEvent(2200, cb_c, CB_IDS[2]); - CoreTiming::ScheduleEvent(1000, cb_rs, reinterpret_cast(cb_rs)); + core_timing.ScheduleEvent(800, cb_a, CB_IDS[0]); + core_timing.ScheduleEvent(1000, cb_b, CB_IDS[1]); + core_timing.ScheduleEvent(2200, cb_c, CB_IDS[2]); + core_timing.ScheduleEvent(1000, cb_rs, reinterpret_cast(cb_rs)); EXPECT_EQ(800, PowerPC::ppcState.downcount); s_reschedules = 3; @@ -226,14 +247,14 @@ TEST(CoreTiming, ChainScheduling) EXPECT_EQ(2, s_reschedules); PowerPC::ppcState.downcount = 0; - CoreTiming::Advance(); // cb_rs + core_timing.Advance(); // cb_rs EXPECT_EQ(1, s_reschedules); EXPECT_EQ(200, PowerPC::ppcState.downcount); AdvanceAndCheck(2, 800); // cb_c PowerPC::ppcState.downcount = 0; - CoreTiming::Advance(); // cb_rs + core_timing.Advance(); // cb_rs EXPECT_EQ(0, s_reschedules); EXPECT_EQ(MAX_SLICE_LENGTH, PowerPC::ppcState.downcount); } @@ -247,7 +268,7 @@ static void ChainCallback(Core::System& system, u64 userdata, s64 lateness) EXPECT_EQ(CB_IDS[0] + 1, userdata); EXPECT_EQ(0, lateness); - CoreTiming::ScheduleEvent(-1000, s_cb_next, userdata - 1); + system.GetCoreTiming().ScheduleEvent(-1000, s_cb_next, userdata - 1); } } // namespace ScheduleIntoPastTest @@ -261,14 +282,17 @@ TEST(CoreTiming, ScheduleIntoPast) ScopeInit guard; ASSERT_TRUE(guard.UserDirectoryExists()); - s_cb_next = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); - CoreTiming::EventType* cb_chain = CoreTiming::RegisterEvent("callbackChain", ChainCallback); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + + s_cb_next = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); + CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); + CoreTiming::EventType* cb_chain = core_timing.RegisterEvent("callbackChain", ChainCallback); // Enter slice 0 - CoreTiming::Advance(); + core_timing.Advance(); - CoreTiming::ScheduleEvent(1000, cb_chain, CB_IDS[0] + 1); + core_timing.ScheduleEvent(1000, cb_chain, CB_IDS[0] + 1); EXPECT_EQ(1000, PowerPC::ppcState.downcount); AdvanceAndCheck(0, MAX_SLICE_LENGTH, 1000); // Run cb_chain into late cb_a @@ -282,7 +306,7 @@ TEST(CoreTiming, ScheduleIntoPast) Core::UndeclareAsCPUThread(); auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); core_timing_globals.global_timer -= 1000; - CoreTiming::ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU); + core_timing.ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU); core_timing_globals.global_timer += 1000; Core::DeclareAsCPUThread(); AdvanceAndCheck(1, MAX_SLICE_LENGTH, MAX_SLICE_LENGTH + 1000); @@ -290,7 +314,7 @@ TEST(CoreTiming, ScheduleIntoPast) // Schedule directly into the past from the CPU. // This shouldn't happen in practice, but it's best if we don't mess up the slice length and // downcount if we do. - CoreTiming::ScheduleEvent(-1000, s_cb_next, CB_IDS[0]); + core_timing.ScheduleEvent(-1000, s_cb_next, CB_IDS[0]); EXPECT_EQ(0, PowerPC::ppcState.downcount); AdvanceAndCheck(0, MAX_SLICE_LENGTH, 1000); } @@ -300,11 +324,14 @@ TEST(CoreTiming, Overclocking) ScopeInit guard; ASSERT_TRUE(guard.UserDirectoryExists()); - CoreTiming::EventType* cb_a = CoreTiming::RegisterEvent("callbackA", CallbackTemplate<0>); - CoreTiming::EventType* cb_b = CoreTiming::RegisterEvent("callbackB", CallbackTemplate<1>); - CoreTiming::EventType* cb_c = CoreTiming::RegisterEvent("callbackC", CallbackTemplate<2>); - CoreTiming::EventType* cb_d = CoreTiming::RegisterEvent("callbackD", CallbackTemplate<3>); - CoreTiming::EventType* cb_e = CoreTiming::RegisterEvent("callbackE", CallbackTemplate<4>); + auto& system = Core::System::GetInstance(); + auto& core_timing = system.GetCoreTiming(); + + CoreTiming::EventType* cb_a = core_timing.RegisterEvent("callbackA", CallbackTemplate<0>); + CoreTiming::EventType* cb_b = core_timing.RegisterEvent("callbackB", CallbackTemplate<1>); + CoreTiming::EventType* cb_c = core_timing.RegisterEvent("callbackC", CallbackTemplate<2>); + CoreTiming::EventType* cb_d = core_timing.RegisterEvent("callbackD", CallbackTemplate<3>); + CoreTiming::EventType* cb_e = core_timing.RegisterEvent("callbackE", CallbackTemplate<4>); // Overclock Config::SetCurrent(Config::MAIN_OVERCLOCK_ENABLE, true); @@ -312,13 +339,13 @@ TEST(CoreTiming, Overclocking) // Enter slice 0 // Updates s_last_OC_factor. - CoreTiming::Advance(); + core_timing.Advance(); - CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]); - CoreTiming::ScheduleEvent(400, cb_c, CB_IDS[2]); - CoreTiming::ScheduleEvent(800, cb_d, CB_IDS[3]); - CoreTiming::ScheduleEvent(1600, cb_e, CB_IDS[4]); + core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]); + core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]); + core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]); + core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]); + core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]); EXPECT_EQ(200, PowerPC::ppcState.downcount); AdvanceAndCheck(0, 200); // (200 - 100) * 2 @@ -329,13 +356,13 @@ TEST(CoreTiming, Overclocking) // Underclock Config::SetCurrent(Config::MAIN_OVERCLOCK, 0.5f); - CoreTiming::Advance(); + core_timing.Advance(); - CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]); - CoreTiming::ScheduleEvent(400, cb_c, CB_IDS[2]); - CoreTiming::ScheduleEvent(800, cb_d, CB_IDS[3]); - CoreTiming::ScheduleEvent(1600, cb_e, CB_IDS[4]); + core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]); + core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]); + core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]); + core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]); + core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]); EXPECT_EQ(50, PowerPC::ppcState.downcount); AdvanceAndCheck(0, 50); // (200 - 100) / 2 @@ -346,13 +373,13 @@ TEST(CoreTiming, Overclocking) // Try switching the clock mid-emulation Config::SetCurrent(Config::MAIN_OVERCLOCK, 1.0f); - CoreTiming::Advance(); + core_timing.Advance(); - CoreTiming::ScheduleEvent(100, cb_a, CB_IDS[0]); - CoreTiming::ScheduleEvent(200, cb_b, CB_IDS[1]); - CoreTiming::ScheduleEvent(400, cb_c, CB_IDS[2]); - CoreTiming::ScheduleEvent(800, cb_d, CB_IDS[3]); - CoreTiming::ScheduleEvent(1600, cb_e, CB_IDS[4]); + core_timing.ScheduleEvent(100, cb_a, CB_IDS[0]); + core_timing.ScheduleEvent(200, cb_b, CB_IDS[1]); + core_timing.ScheduleEvent(400, cb_c, CB_IDS[2]); + core_timing.ScheduleEvent(800, cb_d, CB_IDS[3]); + core_timing.ScheduleEvent(1600, cb_e, CB_IDS[4]); EXPECT_EQ(100, PowerPC::ppcState.downcount); AdvanceAndCheck(0, 100); // (200 - 100) From daa70533cdb0de0a05b4341b499b4cd88e1a3368 Mon Sep 17 00:00:00 2001 From: "Admiral H. Curtiss" Date: Sat, 26 Nov 2022 10:20:32 +0100 Subject: [PATCH 2/2] CoreTiming: Store Globals in CoreTimingManager. --- Source/Core/Core/CoreTiming.cpp | 98 +++++++------------ Source/Core/Core/CoreTiming.h | 6 ++ .../Core/PowerPC/Interpreter/Interpreter.cpp | 5 +- .../PowerPC/Jit64/Jit_SystemRegisters.cpp | 2 +- .../JitArm64/JitArm64_SystemRegisters.cpp | 2 +- Source/Core/Core/System.cpp | 6 -- Source/Core/Core/System.h | 4 +- Source/UnitTests/Core/CoreTimingTest.cpp | 2 +- 8 files changed, 48 insertions(+), 77 deletions(-) diff --git a/Source/Core/Core/CoreTiming.cpp b/Source/Core/Core/CoreTiming.cpp index 4d28e65f32..4bdd53df31 100644 --- a/Source/Core/Core/CoreTiming.cpp +++ b/Source/Core/Core/CoreTiming.cpp @@ -49,9 +49,9 @@ static void EmptyTimedCallback(Core::System& system, u64 userdata, s64 cyclesLat // // Technically it might be more accurate to call this changing the IPC instead of the CPU speed, // but the effect is largely the same. -static int DowncountToCycles(CoreTiming::Globals& g, int downcount) +int CoreTimingManager::DowncountToCycles(int downcount) const { - return static_cast(downcount * g.last_OC_factor_inverted); + return static_cast(downcount * m_globals.last_OC_factor_inverted); } int CoreTimingManager::CyclesToDowncount(int cycles) const @@ -82,18 +82,15 @@ void CoreTimingManager::UnregisterAllEvents() void CoreTimingManager::Init() { - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - m_registered_config_callback_id = Config::AddConfigChangedCallback( [this]() { Core::RunAsCPUThread([this]() { RefreshConfig(); }); }); RefreshConfig(); m_last_oc_factor = m_config_oc_factor; - g.last_OC_factor_inverted = m_config_oc_inv_factor; + m_globals.last_OC_factor_inverted = m_config_oc_inv_factor; PowerPC::ppcState.downcount = CyclesToDowncount(MAX_SLICE_LENGTH); - g.slice_length = MAX_SLICE_LENGTH; - g.global_timer = 0; + m_globals.slice_length = MAX_SLICE_LENGTH; + m_globals.global_timer = 0; m_idled_cycles = 0; // The time between CoreTiming being intialized and the first call to Advance() is considered @@ -125,19 +122,16 @@ void CoreTimingManager::RefreshConfig() void CoreTimingManager::DoState(PointerWrap& p) { - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - std::lock_guard lk(m_ts_write_lock); - p.Do(g.slice_length); - p.Do(g.global_timer); + p.Do(m_globals.slice_length); + p.Do(m_globals.global_timer); p.Do(m_idled_cycles); p.Do(m_fake_dec_start_value); p.Do(m_fake_dec_start_ticks); - p.Do(g.fake_TB_start_value); - p.Do(g.fake_TB_start_ticks); + p.Do(m_globals.fake_TB_start_value); + p.Do(m_globals.fake_TB_start_ticks); p.Do(m_last_oc_factor); - g.last_OC_factor_inverted = 1.0f / m_last_oc_factor; + m_globals.last_OC_factor_inverted = 1.0f / m_last_oc_factor; p.Do(m_event_fifo_id); p.DoMarker("CoreTimingData"); @@ -187,14 +181,11 @@ void CoreTimingManager::DoState(PointerWrap& p) // it from any other thread, you are doing something evil u64 CoreTimingManager::GetTicks() const { - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - - u64 ticks = static_cast(g.global_timer); + u64 ticks = static_cast(m_globals.global_timer); if (!m_is_global_timer_sane) { - int downcount = DowncountToCycles(g, PowerPC::ppcState.downcount); - ticks += g.slice_length - downcount; + int downcount = DowncountToCycles(PowerPC::ppcState.downcount); + ticks += m_globals.slice_length - downcount; } return ticks; } @@ -214,9 +205,6 @@ void CoreTimingManager::ScheduleEvent(s64 cycles_into_future, EventType* event_t { ASSERT_MSG(POWERPC, event_type, "Event type is nullptr, will crash now."); - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - bool from_cpu_thread; if (from == FromThread::ANY) { @@ -252,7 +240,7 @@ void CoreTimingManager::ScheduleEvent(s64 cycles_into_future, EventType* event_t } std::lock_guard lk(m_ts_write_lock); - m_ts_queue.Push(Event{g.global_timer + cycles_into_future, 0, userdata, event_type}); + m_ts_queue.Push(Event{m_globals.global_timer + cycles_into_future, 0, userdata, event_type}); } } @@ -277,15 +265,13 @@ void CoreTimingManager::RemoveAllEvents(EventType* event_type) void CoreTimingManager::ForceExceptionCheck(s64 cycles) { - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - cycles = std::max(0, cycles); - if (DowncountToCycles(g, PowerPC::ppcState.downcount) > cycles) + if (DowncountToCycles(PowerPC::ppcState.downcount) > cycles) { // downcount is always (much) smaller than MAX_INT so we can safely cast cycles to an int here. - // Account for cycles already executed by adjusting the g.slice_length - g.slice_length -= DowncountToCycles(g, PowerPC::ppcState.downcount) - static_cast(cycles); + // Account for cycles already executed by adjusting the m_globals.slice_length + m_globals.slice_length -= + DowncountToCycles(PowerPC::ppcState.downcount) - static_cast(cycles); PowerPC::ppcState.downcount = CyclesToDowncount(static_cast(cycles)); } } @@ -303,24 +289,23 @@ void CoreTimingManager::MoveEvents() void CoreTimingManager::Advance() { auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); MoveEvents(); - int cyclesExecuted = g.slice_length - DowncountToCycles(g, PowerPC::ppcState.downcount); - g.global_timer += cyclesExecuted; + int cyclesExecuted = m_globals.slice_length - DowncountToCycles(PowerPC::ppcState.downcount); + m_globals.global_timer += cyclesExecuted; m_last_oc_factor = m_config_oc_factor; - g.last_OC_factor_inverted = m_config_oc_inv_factor; - g.slice_length = MAX_SLICE_LENGTH; + m_globals.last_OC_factor_inverted = m_config_oc_inv_factor; + m_globals.slice_length = MAX_SLICE_LENGTH; m_is_global_timer_sane = true; - while (!m_event_queue.empty() && m_event_queue.front().time <= g.global_timer) + while (!m_event_queue.empty() && m_event_queue.front().time <= m_globals.global_timer) { Event evt = std::move(m_event_queue.front()); std::pop_heap(m_event_queue.begin(), m_event_queue.end(), std::greater()); m_event_queue.pop_back(); - evt.type->callback(system, evt.userdata, g.global_timer - evt.time); + evt.type->callback(system, evt.userdata, m_globals.global_timer - evt.time); } m_is_global_timer_sane = false; @@ -328,11 +313,11 @@ void CoreTimingManager::Advance() // Still events left (scheduled in the future) if (!m_event_queue.empty()) { - g.slice_length = static_cast( - std::min(m_event_queue.front().time - g.global_timer, MAX_SLICE_LENGTH)); + m_globals.slice_length = static_cast( + std::min(m_event_queue.front().time - m_globals.global_timer, MAX_SLICE_LENGTH)); } - PowerPC::ppcState.downcount = CyclesToDowncount(g.slice_length); + PowerPC::ppcState.downcount = CyclesToDowncount(m_globals.slice_length); // Check for any external exceptions. // It's important to do this after processing events otherwise any exceptions will be delayed @@ -343,14 +328,11 @@ void CoreTimingManager::Advance() void CoreTimingManager::LogPendingEvents() const { - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - auto clone = m_event_queue; std::sort(clone.begin(), clone.end()); for (const Event& ev : clone) { - INFO_LOG_FMT(POWERPC, "PENDING: Now: {} Pending: {} Type: {}", g.global_timer, ev.time, + INFO_LOG_FMT(POWERPC, "PENDING: Now: {} Pending: {} Type: {}", m_globals.global_timer, ev.time, *ev.type->name); } } @@ -358,21 +340,15 @@ void CoreTimingManager::LogPendingEvents() const // Should only be called from the CPU thread after the PPC clock has changed void CoreTimingManager::AdjustEventQueueTimes(u32 new_ppc_clock, u32 old_ppc_clock) { - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - for (Event& ev : m_event_queue) { - const s64 ticks = (ev.time - g.global_timer) * new_ppc_clock / old_ppc_clock; - ev.time = g.global_timer + ticks; + const s64 ticks = (ev.time - m_globals.global_timer) * new_ppc_clock / old_ppc_clock; + ev.time = m_globals.global_timer + ticks; } } void CoreTimingManager::Idle() { - auto& system = Core::System::GetInstance(); - auto& g = system.GetCoreTimingGlobals(); - if (m_config_sync_on_skip_idle) { // When the FIFO is processing data we must not advance because in this way @@ -382,7 +358,7 @@ void CoreTimingManager::Idle() } PowerPC::UpdatePerformanceMonitor(PowerPC::ppcState.downcount, 0, 0); - m_idled_cycles += DowncountToCycles(g, PowerPC::ppcState.downcount); + m_idled_cycles += DowncountToCycles(PowerPC::ppcState.downcount); PowerPC::ppcState.downcount = 0; } @@ -422,26 +398,22 @@ void CoreTimingManager::SetFakeDecStartTicks(u64 val) u64 CoreTimingManager::GetFakeTBStartValue() const { - auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); - return g.fake_TB_start_value; + return m_globals.fake_TB_start_value; } void CoreTimingManager::SetFakeTBStartValue(u64 val) { - auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); - g.fake_TB_start_value = val; + m_globals.fake_TB_start_value = val; } u64 CoreTimingManager::GetFakeTBStartTicks() const { - auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); - return g.fake_TB_start_ticks; + return m_globals.fake_TB_start_ticks; } void CoreTimingManager::SetFakeTBStartTicks(u64 val) { - auto& g = Core::System::GetInstance().GetCoreTimingGlobals(); - g.fake_TB_start_ticks = val; + m_globals.fake_TB_start_ticks = val; } void GlobalAdvance() diff --git a/Source/Core/Core/CoreTiming.h b/Source/Core/Core/CoreTiming.h index c0a4d53056..737f3889b9 100644 --- a/Source/Core/Core/CoreTiming.h +++ b/Source/Core/Core/CoreTiming.h @@ -137,7 +137,12 @@ public: void ForceExceptionCheck(s64 cycles); + // Directly accessed by the JIT. + Globals& GetGlobals() { return m_globals; } + private: + Globals m_globals; + // unordered_map stores each element separately as a linked list node so pointers to elements // remain stable regardless of rehashes/resizing. std::unordered_map m_event_types; @@ -168,6 +173,7 @@ private: float m_config_oc_inv_factor = 0.0f; bool m_config_sync_on_skip_idle = false; + int DowncountToCycles(int downcount) const; int CyclesToDowncount(int cycles) const; }; diff --git a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp index 2dade57576..f2d7ceef9c 100644 --- a/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp +++ b/Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp @@ -212,10 +212,11 @@ int Interpreter::SingleStepInner() void Interpreter::SingleStep() { - auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + auto& core_timing = Core::System::GetInstance().GetCoreTiming(); + auto& core_timing_globals = core_timing.GetGlobals(); // Declare start of new slice - Core::System::GetInstance().GetCoreTiming().Advance(); + core_timing.Advance(); SingleStepInner(); diff --git a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp index eb2e938648..3629e2deec 100644 --- a/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp @@ -323,7 +323,7 @@ void Jit64::mfspr(UGeckoInstruction inst) RCX64Reg rax = gpr.Scratch(RAX); RCX64Reg rcx = gpr.Scratch(RCX); - auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + auto& core_timing_globals = Core::System::GetInstance().GetCoreTiming().GetGlobals(); MOV(64, rcx, ImmPtr(&core_timing_globals)); // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the diff --git a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp index d93700e742..cc95654b76 100644 --- a/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp +++ b/Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp @@ -307,7 +307,7 @@ void JitArm64::mfspr(UGeckoInstruction inst) // An inline implementation of CoreTiming::GetFakeTimeBase, since in timer-heavy games the // cost of calling out to C for this is actually significant. - auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + auto& core_timing_globals = Core::System::GetInstance().GetCoreTiming().GetGlobals(); MOVP2R(Xg, &core_timing_globals); LDR(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(downcount)); diff --git a/Source/Core/Core/System.cpp b/Source/Core/Core/System.cpp index 16d5086e9f..2b69756d08 100644 --- a/Source/Core/Core/System.cpp +++ b/Source/Core/Core/System.cpp @@ -28,7 +28,6 @@ struct System::Impl AudioInterface::AudioInterfaceState m_audio_interface_state; CoreTiming::CoreTimingManager m_core_timing; - CoreTiming::Globals m_core_timing_globals; DSP::DSPState m_dsp_state; DVDInterface::DVDInterfaceState m_dvd_interface_state; DVDThread::DVDThreadState m_dvd_thread_state; @@ -92,11 +91,6 @@ CoreTiming::CoreTimingManager& System::GetCoreTiming() const return m_impl->m_core_timing; } -CoreTiming::Globals& System::GetCoreTimingGlobals() const -{ - return m_impl->m_core_timing_globals; -} - DSP::DSPState& System::GetDSPState() const { return m_impl->m_dsp_state; diff --git a/Source/Core/Core/System.h b/Source/Core/Core/System.h index bdcd37f75d..1c4c984fed 100644 --- a/Source/Core/Core/System.h +++ b/Source/Core/Core/System.h @@ -15,8 +15,7 @@ class AudioInterfaceState; namespace CoreTiming { class CoreTimingManager; -struct Globals; -} // namespace CoreTiming +} namespace DSP { class DSPState; @@ -82,7 +81,6 @@ public: AudioInterface::AudioInterfaceState& GetAudioInterfaceState() const; CoreTiming::CoreTimingManager& GetCoreTiming() const; - CoreTiming::Globals& GetCoreTimingGlobals() const; DSP::DSPState& GetDSPState() const; DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const; DVDThread::DVDThreadState& GetDVDThreadState() const; diff --git a/Source/UnitTests/Core/CoreTimingTest.cpp b/Source/UnitTests/Core/CoreTimingTest.cpp index 6054fb9381..14731a10e7 100644 --- a/Source/UnitTests/Core/CoreTimingTest.cpp +++ b/Source/UnitTests/Core/CoreTimingTest.cpp @@ -304,7 +304,7 @@ TEST(CoreTiming, ScheduleIntoPast) // the stale value, i.e. effectively half-way through the previous slice. // NOTE: We're only testing that the scheduler doesn't break, not whether this makes sense. Core::UndeclareAsCPUThread(); - auto& core_timing_globals = Core::System::GetInstance().GetCoreTimingGlobals(); + auto& core_timing_globals = core_timing.GetGlobals(); core_timing_globals.global_timer -= 1000; core_timing.ScheduleEvent(0, cb_b, CB_IDS[1], CoreTiming::FromThread::NON_CPU); core_timing_globals.global_timer += 1000;