#pragma once #include "common/bitfield.h" #include "types.h" #include #include class StateWrapper; class TimingEvent; class GPU; class Timers final { public: Timers(); ~Timers(); void Initialize(); void Shutdown(); void Reset(); bool DoState(StateWrapper& sw); void SetGate(u32 timer, bool state); void DrawDebugStateWindow(); void CPUClocksChanged(); // dot clock/hblank/sysclk div 8 ALWAYS_INLINE bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; } // 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) const; void AddTicks(u32 timer, TickCount ticks); 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 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;