#pragma once #include "common/bitfield.h" #include "types.h" #include class StateWrapper; class System; class InterruptController; class Timers { public: Timers(); ~Timers(); void Initialize(System* system, InterruptController* interrupt_controller); void Reset(); bool DoState(StateWrapper& sw); void SetGate(u32 timer, bool state); void DrawDebugStateWindow(); // dot clock/hblank/sysclk div 8 bool IsUsingExternalClock(u32 timer) const { return m_states[timer].external_counting_enabled; } void AddTicks(u32 timer, TickCount ticks); void Execute(TickCount sysclk_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 UpdateDowncount(); System* m_system = nullptr; InterruptController* m_interrupt_controller = nullptr; std::array m_states{}; u32 m_sysclk_div_8_carry = 0; // partial ticks for timer 3 with sysclk/8 };