From db364d0e95292c3a705189b456876120be84a409 Mon Sep 17 00:00:00 2001 From: Connor McLaughlin Date: Wed, 11 Jan 2023 18:58:25 +1000 Subject: [PATCH] Timers: Convert to namespace --- src/core/bus.cpp | 4 +- src/core/gpu.cpp | 26 ++--- src/core/gpu.h | 1 - src/core/system.cpp | 10 +- src/core/timers.cpp | 145 ++++++++++++++++++++-------- src/core/timers.h | 106 ++++---------------- src/frontend-common/common_host.cpp | 2 +- 7 files changed, 145 insertions(+), 149 deletions(-) diff --git a/src/core/bus.cpp b/src/core/bus.cpp index f9c01610d..534b3ed30 100644 --- a/src/core/bus.cpp +++ b/src/core/bus.cpp @@ -1249,13 +1249,13 @@ ALWAYS_INLINE static TickCount DoAccessTimers(u32 offset, u32& value) { if constexpr (type == MemoryAccessType::Read) { - value = g_timers.ReadRegister(FIXUP_WORD_OFFSET(size, offset)); + value = Timers::ReadRegister(FIXUP_WORD_OFFSET(size, offset)); value = FIXUP_WORD_READ_VALUE(size, offset, value); return 2; } else { - g_timers.WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value)); + Timers::WriteRegister(FIXUP_WORD_OFFSET(size, offset), FIXUP_WORD_WRITE_VALUE(size, offset, value)); return 0; } } diff --git a/src/core/gpu.cpp b/src/core/gpu.cpp index 3b1277737..51b6e4b84 100644 --- a/src/core/gpu.cpp +++ b/src/core/gpu.cpp @@ -779,7 +779,7 @@ void GPU::UpdateCRTCTickEvent() { // figure out how many GPU ticks until the next vblank or event TickCount lines_until_event; - if (g_timers.IsSyncEnabled(HBLANK_TIMER_INDEX)) + if (Timers::IsSyncEnabled(HBLANK_TIMER_INDEX)) { // when the timer sync is enabled we need to sync at vblank start and end lines_until_event = @@ -794,14 +794,14 @@ void GPU::UpdateCRTCTickEvent() (m_crtc_state.vertical_total - m_crtc_state.current_scanline + m_crtc_state.vertical_display_end) : (m_crtc_state.vertical_display_end - m_crtc_state.current_scanline)); } - if (g_timers.IsExternalIRQEnabled(HBLANK_TIMER_INDEX)) - lines_until_event = std::min(lines_until_event, g_timers.GetTicksUntilIRQ(HBLANK_TIMER_INDEX)); + if (Timers::IsExternalIRQEnabled(HBLANK_TIMER_INDEX)) + lines_until_event = std::min(lines_until_event, Timers::GetTicksUntilIRQ(HBLANK_TIMER_INDEX)); TickCount ticks_until_event = lines_until_event * m_crtc_state.horizontal_total - m_crtc_state.current_tick_in_scanline; - if (g_timers.IsExternalIRQEnabled(DOT_TIMER_INDEX)) + if (Timers::IsExternalIRQEnabled(DOT_TIMER_INDEX)) { - const TickCount dots_until_irq = g_timers.GetTicksUntilIRQ(DOT_TIMER_INDEX); + const TickCount dots_until_irq = Timers::GetTicksUntilIRQ(DOT_TIMER_INDEX); const TickCount ticks_until_irq = (dots_until_irq * m_crtc_state.dot_clock_divider) - m_crtc_state.fractional_dot_ticks; ticks_until_event = std::min(ticks_until_event, std::max(ticks_until_irq, 0)); @@ -835,13 +835,13 @@ void GPU::CRTCTickEvent(TickCount ticks) const TickCount gpu_ticks = SystemTicksToCRTCTicks(ticks, &m_crtc_state.fractional_ticks); m_crtc_state.current_tick_in_scanline += gpu_ticks; - if (g_timers.IsUsingExternalClock(DOT_TIMER_INDEX)) + if (Timers::IsUsingExternalClock(DOT_TIMER_INDEX)) { m_crtc_state.fractional_dot_ticks += gpu_ticks; const TickCount dots = m_crtc_state.fractional_dot_ticks / m_crtc_state.dot_clock_divider; m_crtc_state.fractional_dot_ticks = m_crtc_state.fractional_dot_ticks % m_crtc_state.dot_clock_divider; if (dots > 0) - g_timers.AddTicks(DOT_TIMER_INDEX, dots); + Timers::AddTicks(DOT_TIMER_INDEX, dots); } } @@ -851,8 +851,8 @@ void GPU::CRTCTickEvent(TickCount ticks) const bool old_hblank = m_crtc_state.in_hblank; const bool new_hblank = (m_crtc_state.current_tick_in_scanline >= m_crtc_state.horizontal_sync_start); m_crtc_state.in_hblank = new_hblank; - if (!old_hblank && new_hblank && g_timers.IsUsingExternalClock(HBLANK_TIMER_INDEX)) - g_timers.AddTicks(HBLANK_TIMER_INDEX, 1); + if (!old_hblank && new_hblank && Timers::IsUsingExternalClock(HBLANK_TIMER_INDEX)) + Timers::AddTicks(HBLANK_TIMER_INDEX, 1); UpdateCRTCTickEvent(); return; @@ -868,10 +868,10 @@ void GPU::CRTCTickEvent(TickCount ticks) const bool old_hblank = m_crtc_state.in_hblank; const bool new_hblank = (m_crtc_state.current_tick_in_scanline >= m_crtc_state.horizontal_sync_start); m_crtc_state.in_hblank = new_hblank; - if (g_timers.IsUsingExternalClock(HBLANK_TIMER_INDEX)) + if (Timers::IsUsingExternalClock(HBLANK_TIMER_INDEX)) { const u32 hblank_timer_ticks = BoolToUInt32(!old_hblank) + BoolToUInt32(new_hblank) + (lines_to_draw - 1); - g_timers.AddTicks(HBLANK_TIMER_INDEX, static_cast(hblank_timer_ticks)); + Timers::AddTicks(HBLANK_TIMER_INDEX, static_cast(hblank_timer_ticks)); } while (lines_to_draw > 0) @@ -887,7 +887,7 @@ void GPU::CRTCTickEvent(TickCount ticks) if (prev_scanline < m_crtc_state.vertical_display_start && m_crtc_state.current_scanline >= m_crtc_state.vertical_display_end) { - g_timers.SetGate(HBLANK_TIMER_INDEX, false); + Timers::SetGate(HBLANK_TIMER_INDEX, false); m_crtc_state.in_vblank = false; } @@ -912,7 +912,7 @@ void GPU::CRTCTickEvent(TickCount ticks) m_crtc_state.interlaced_display_field = 0; } - g_timers.SetGate(HBLANK_TIMER_INDEX, new_vblank); + Timers::SetGate(HBLANK_TIMER_INDEX, new_vblank); m_crtc_state.in_vblank = new_vblank; } diff --git a/src/core/gpu.h b/src/core/gpu.h index c6408b3fe..75ac564ec 100644 --- a/src/core/gpu.h +++ b/src/core/gpu.h @@ -21,7 +21,6 @@ class HostDisplay; class GPUTexture; class TimingEvent; -class Timers; namespace Threading { diff --git a/src/core/system.cpp b/src/core/system.cpp index 3c6bd2d67..3b18ac67a 100644 --- a/src/core/system.cpp +++ b/src/core/system.cpp @@ -283,7 +283,7 @@ void System::UpdateOverclock() SPU::CPUClockChanged(); CDROM::CPUClockChanged(); g_gpu->CPUClockChanged(); - g_timers.CPUClocksChanged(); + Timers::CPUClocksChanged(); UpdateThrottlePeriod(); } @@ -1391,7 +1391,7 @@ bool System::Initialize(bool force_software_renderer) CDROM::Initialize(); g_pad.Initialize(); - g_timers.Initialize(); + Timers::Initialize(); SPU::Initialize(); MDEC::Initialize(); g_sio.Initialize(); @@ -1453,7 +1453,7 @@ void System::DestroySystem() g_sio.Shutdown(); MDEC::Shutdown(); SPU::Shutdown(); - g_timers.Shutdown(); + Timers::Shutdown(); g_pad.Shutdown(); CDROM::Shutdown(); g_gpu.reset(); @@ -1658,7 +1658,7 @@ bool System::DoState(StateWrapper& sw, GPUTexture** host_texture, bool update_di if (!sw.DoMarker("Pad") || !g_pad.DoState(sw)) return false; - if (!sw.DoMarker("Timers") || !g_timers.DoState(sw)) + if (!sw.DoMarker("Timers") || !Timers::DoState(sw)) return false; if (!sw.DoMarker("SPU") || !SPU::DoState(sw)) @@ -1744,7 +1744,7 @@ void System::InternalReset() g_gpu->Reset(true); CDROM::Reset(); g_pad.Reset(); - g_timers.Reset(); + Timers::Reset(); SPU::Reset(); MDEC::Reset(); g_sio.Reset(); diff --git a/src/core/timers.cpp b/src/core/timers.cpp index 5ad97669a..c03cd738f 100644 --- a/src/core/timers.cpp +++ b/src/core/timers.cpp @@ -2,37 +2,88 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #include "timers.h" +#include "common/bitfield.h" #include "common/log.h" #include "gpu.h" #include "imgui.h" #include "interrupt_controller.h" #include "system.h" #include "util/state_wrapper.h" +#include +#include Log_SetChannel(Timers); -Timers g_timers; +namespace Timers { +static constexpr u32 NUM_TIMERS = 3; -Timers::Timers() = default; +enum class SyncMode : u8 +{ + PauseOnGate = 0, + ResetOnGate = 1, + ResetAndRunOnGate = 2, + FreeRunOnGate = 3 +}; -Timers::~Timers() = default; +union CounterMode +{ + u32 bits; + + BitField sync_enable; + BitField sync_mode; + BitField reset_at_target; + BitField irq_at_target; + BitField irq_on_overflow; + BitField irq_repeat; + BitField irq_pulse_n; + BitField clock_source; + BitField interrupt_request_n; + BitField reached_target; + BitField reached_overflow; +}; + +struct CounterState +{ + CounterMode mode; + u32 counter; + u32 target; + bool gate; + bool use_external_clock; + bool external_counting_enabled; + bool counting_enabled; + bool irq_done; +}; + +static void UpdateCountingEnabled(CounterState& cs); +static void CheckForIRQ(u32 index, u32 old_counter); +static void UpdateIRQ(u32 index); + +static void AddSysClkTicks(void*, TickCount sysclk_ticks, TickCount ticks_late); + +static TickCount GetTicksUntilNextInterrupt(); +static void UpdateSysClkEvent(); + +static std::unique_ptr s_sysclk_event; + +static std::array s_states{}; +static TickCount s_syclk_ticks_carry = 0; // 0 unless overclocking is enabled +static u32 s_sysclk_div_8_carry = 0; // partial ticks for timer 3 with sysclk/8 +}; // namespace Timers void Timers::Initialize() { - m_sysclk_event = TimingEvents::CreateTimingEvent( - "Timer SysClk Interrupt", 1, 1, - [](void* param, TickCount ticks, TickCount ticks_late) { static_cast(param)->AddSysClkTicks(ticks); }, - this, false); + s_sysclk_event = + TimingEvents::CreateTimingEvent("Timer SysClk Interrupt", 1, 1, &Timers::AddSysClkTicks, nullptr, false); Reset(); } void Timers::Shutdown() { - m_sysclk_event.reset(); + s_sysclk_event.reset(); } void Timers::Reset() { - for (CounterState& cs : m_states) + for (CounterState& cs : s_states) { cs.mode.bits = 0; cs.mode.interrupt_request_n = true; @@ -44,14 +95,14 @@ void Timers::Reset() cs.irq_done = false; } - m_syclk_ticks_carry = 0; - m_sysclk_div_8_carry = 0; + s_syclk_ticks_carry = 0; + s_sysclk_div_8_carry = 0; UpdateSysClkEvent(); } bool Timers::DoState(StateWrapper& sw) { - for (CounterState& cs : m_states) + for (CounterState& cs : s_states) { sw.Do(&cs.mode.bits); sw.Do(&cs.counter); @@ -63,8 +114,8 @@ bool Timers::DoState(StateWrapper& sw) sw.Do(&cs.irq_done); } - sw.Do(&m_syclk_ticks_carry); - sw.Do(&m_sysclk_div_8_carry); + sw.Do(&s_syclk_ticks_carry); + sw.Do(&s_sysclk_div_8_carry); if (sw.IsReading()) UpdateSysClkEvent(); @@ -74,12 +125,28 @@ bool Timers::DoState(StateWrapper& sw) void Timers::CPUClocksChanged() { - m_syclk_ticks_carry = 0; + s_syclk_ticks_carry = 0; +} + +bool Timers::IsUsingExternalClock(u32 timer) +{ + return s_states[timer].external_counting_enabled; +} + +bool Timers::IsSyncEnabled(u32 timer) +{ + return s_states[timer].mode.sync_enable; +} + +bool Timers::IsExternalIRQEnabled(u32 timer) +{ + const CounterState& cs = s_states[timer]; + return (cs.external_counting_enabled && (cs.mode.bits & ((1u << 4) | (1u << 5))) != 0); } void Timers::SetGate(u32 timer, bool state) { - CounterState& cs = m_states[timer]; + CounterState& cs = s_states[timer]; if (cs.gate == state) return; @@ -89,7 +156,7 @@ void Timers::SetGate(u32 timer, bool state) return; if (cs.counting_enabled && !cs.use_external_clock) - m_sysclk_event->InvokeEarly(); + s_sysclk_event->InvokeEarly(); if (state) { @@ -110,9 +177,9 @@ void Timers::SetGate(u32 timer, bool state) UpdateSysClkEvent(); } -TickCount Timers::GetTicksUntilIRQ(u32 timer) const +TickCount Timers::GetTicksUntilIRQ(u32 timer) { - const CounterState& cs = m_states[timer]; + const CounterState& cs = s_states[timer]; if (!cs.counting_enabled) return std::numeric_limits::max(); @@ -127,7 +194,7 @@ TickCount Timers::GetTicksUntilIRQ(u32 timer) const void Timers::AddTicks(u32 timer, TickCount count) { - CounterState& cs = m_states[timer]; + CounterState& cs = s_states[timer]; const u32 old_counter = cs.counter; cs.counter += static_cast(count); CheckForIRQ(timer, old_counter); @@ -135,7 +202,7 @@ void Timers::AddTicks(u32 timer, TickCount count) void Timers::CheckForIRQ(u32 timer, u32 old_counter) { - CounterState& cs = m_states[timer]; + CounterState& cs = s_states[timer]; bool interrupt_request = false; if (cs.counter >= cs.target && (old_counter < cs.target || cs.target == 0)) @@ -170,21 +237,21 @@ void Timers::CheckForIRQ(u32 timer, u32 old_counter) } } -void Timers::AddSysClkTicks(TickCount sysclk_ticks) +void Timers::AddSysClkTicks(void*, TickCount sysclk_ticks, TickCount ticks_late) { - sysclk_ticks = System::UnscaleTicksToOverclock(sysclk_ticks, &m_syclk_ticks_carry); + sysclk_ticks = System::UnscaleTicksToOverclock(sysclk_ticks, &s_syclk_ticks_carry); - if (!m_states[0].external_counting_enabled && m_states[0].counting_enabled) + if (!s_states[0].external_counting_enabled && s_states[0].counting_enabled) AddTicks(0, sysclk_ticks); - if (!m_states[1].external_counting_enabled && m_states[1].counting_enabled) + if (!s_states[1].external_counting_enabled && s_states[1].counting_enabled) AddTicks(1, sysclk_ticks); - if (m_states[2].external_counting_enabled) + if (s_states[2].external_counting_enabled) { - TickCount sysclk_div_8_ticks = (sysclk_ticks + m_sysclk_div_8_carry) / 8; - m_sysclk_div_8_carry = (sysclk_ticks + m_sysclk_div_8_carry) % 8; + TickCount sysclk_div_8_ticks = (sysclk_ticks + s_sysclk_div_8_carry) / 8; + s_sysclk_div_8_carry = (sysclk_ticks + s_sysclk_div_8_carry) % 8; AddTicks(2, sysclk_div_8_ticks); } - else if (m_states[2].counting_enabled) + else if (s_states[2].counting_enabled) { AddTicks(2, sysclk_ticks); } @@ -202,7 +269,7 @@ u32 Timers::ReadRegister(u32 offset) return UINT32_C(0xFFFFFFFF); } - CounterState& cs = m_states[timer_index]; + CounterState& cs = s_states[timer_index]; switch (port_offset) { @@ -215,7 +282,7 @@ u32 Timers::ReadRegister(u32 offset) g_gpu->SynchronizeCRTC(); } - m_sysclk_event->InvokeEarly(); + s_sysclk_event->InvokeEarly(); return cs.counter; } @@ -229,7 +296,7 @@ u32 Timers::ReadRegister(u32 offset) g_gpu->SynchronizeCRTC(); } - m_sysclk_event->InvokeEarly(); + s_sysclk_event->InvokeEarly(); const u32 bits = cs.mode.bits; cs.mode.reached_overflow = false; @@ -256,7 +323,7 @@ void Timers::WriteRegister(u32 offset, u32 value) return; } - CounterState& cs = m_states[timer_index]; + CounterState& cs = s_states[timer_index]; if (timer_index < 2 && cs.external_counting_enabled) { @@ -265,7 +332,7 @@ void Timers::WriteRegister(u32 offset, u32 value) g_gpu->SynchronizeCRTC(); } - m_sysclk_event->InvokeEarly(); + s_sysclk_event->InvokeEarly(); // Strictly speaking these IRQ checks should probably happen on the next tick. switch (port_offset) @@ -344,7 +411,7 @@ void Timers::UpdateCountingEnabled(CounterState& cs) void Timers::UpdateIRQ(u32 index) { - CounterState& cs = m_states[index]; + CounterState& cs = s_states[index]; if (cs.mode.interrupt_request_n || (!cs.mode.irq_repeat && cs.irq_done)) return; @@ -354,12 +421,12 @@ void Timers::UpdateIRQ(u32 index) static_cast(static_cast(InterruptController::IRQ::TMR0) + index)); } -TickCount Timers::GetTicksUntilNextInterrupt() const +TickCount Timers::GetTicksUntilNextInterrupt() { TickCount min_ticks = System::GetMaxSliceTicks(); for (u32 i = 0; i < NUM_TIMERS; i++) { - const CounterState& cs = m_states[i]; + const CounterState& cs = s_states[i]; if (!cs.counting_enabled || (i < 2 && cs.external_counting_enabled) || (!cs.mode.irq_at_target && !cs.mode.irq_on_overflow && (cs.mode.irq_repeat || !cs.irq_done))) { @@ -390,7 +457,7 @@ TickCount Timers::GetTicksUntilNextInterrupt() const void Timers::UpdateSysClkEvent() { - m_sysclk_event->Schedule(GetTicksUntilNextInterrupt()); + s_sysclk_event->Schedule(GetTicksUntilNextInterrupt()); } void Timers::DrawDebugStateWindow() @@ -434,7 +501,7 @@ void Timers::DrawDebugStateWindow() for (u32 i = 0; i < NUM_TIMERS; i++) { - const CounterState& cs = m_states[i]; + const CounterState& cs = s_states[i]; ImGui::PushStyleColor(ImGuiCol_Text, cs.counting_enabled ? ImVec4(1.0f, 1.0f, 1.0f, 1.0f) : ImVec4(0.5f, 0.5f, 0.5f, 1.0f)); ImGui::Text("%u", i); diff --git a/src/core/timers.h b/src/core/timers.h index cd5bb99a8..c8a128c6d 100644 --- a/src/core/timers.h +++ b/src/core/timers.h @@ -2,105 +2,35 @@ // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) #pragma once -#include "common/bitfield.h" #include "types.h" -#include -#include class StateWrapper; -class TimingEvent; -class GPU; +namespace Timers { -class Timers final -{ -public: - Timers(); - ~Timers(); +void Initialize(); +void Shutdown(); +void Reset(); +bool DoState(StateWrapper& sw); - void Initialize(); - void Shutdown(); - void Reset(); - bool DoState(StateWrapper& sw); +void SetGate(u32 timer, bool state); - void SetGate(u32 timer, bool state); +void DrawDebugStateWindow(); - void DrawDebugStateWindow(); +void CPUClocksChanged(); - void CPUClocksChanged(); +// dot clock/hblank/sysclk div 8 +bool IsUsingExternalClock(u32 timer); +bool IsSyncEnabled(u32 timer); - // dot clock/hblank/sysclk div 8 - ALWAYS_INLINE bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; } - ALWAYS_INLINE bool IsSyncEnabled(u32 timer) const { return m_states[timer].mode.sync_enable; } +// queries for GPU +bool IsExternalIRQEnabled(u32 timer); - // queries for GPU - ALWAYS_INLINE bool IsExternalIRQEnabled(u32 timer) const - { - const CounterState& cs = m_states[timer]; - return (cs.external_counting_enabled && (cs.mode.bits & ((1u << 4) | (1u << 5))) != 0); - } +TickCount GetTicksUntilIRQ(u32 timer); - TickCount GetTicksUntilIRQ(u32 timer) const; +void AddTicks(u32 timer, TickCount ticks); - void AddTicks(u32 timer, TickCount ticks); +u32 ReadRegister(u32 offset); +void WriteRegister(u32 offset, u32 value); - u32 ReadRegister(u32 offset); - void WriteRegister(u32 offset, u32 value); - -private: - static constexpr u32 NUM_TIMERS = 3; - - enum class SyncMode : u8 - { - PauseOnGate = 0, - ResetOnGate = 1, - ResetAndRunOnGate = 2, - FreeRunOnGate = 3 - }; - - union CounterMode - { - u32 bits; - - BitField sync_enable; - BitField sync_mode; - BitField reset_at_target; - BitField irq_at_target; - BitField irq_on_overflow; - BitField irq_repeat; - BitField irq_pulse_n; - BitField clock_source; - BitField interrupt_request_n; - BitField reached_target; - BitField reached_overflow; - }; - - struct CounterState - { - CounterMode mode; - u32 counter; - u32 target; - bool gate; - bool use_external_clock; - bool external_counting_enabled; - bool counting_enabled; - bool irq_done; - }; - - void UpdateCountingEnabled(CounterState& cs); - void CheckForIRQ(u32 index, u32 old_counter); - void UpdateIRQ(u32 index); - - void AddSysClkTicks(TickCount sysclk_ticks); - - TickCount GetTicksUntilNextInterrupt() const; - void UpdateSysClkEvent(); - - std::unique_ptr m_sysclk_event; - - std::array m_states{}; - TickCount m_syclk_ticks_carry = 0; // 0 unless overclocking is enabled - u32 m_sysclk_div_8_carry = 0; // partial ticks for timer 3 with sysclk/8 -}; - -extern Timers g_timers; \ No newline at end of file +} // namespace Timers diff --git a/src/frontend-common/common_host.cpp b/src/frontend-common/common_host.cpp index cf22c580f..ea25396d8 100644 --- a/src/frontend-common/common_host.cpp +++ b/src/frontend-common/common_host.cpp @@ -484,7 +484,7 @@ void ImGuiManager::RenderDebugWindows() if (g_settings.debugging.show_cdrom_state) CDROM::DrawDebugWindow(); if (g_settings.debugging.show_timers_state) - g_timers.DrawDebugStateWindow(); + Timers::DrawDebugStateWindow(); if (g_settings.debugging.show_spu_state) SPU::DrawDebugStateWindow(); if (g_settings.debugging.show_mdec_state)