Skip to main content

gb/mmio/
timer.rs

1//! Divider and timer (`DIV`, `TIMA`, `TMA`, `TAC`).
2
3use bitfield_struct::{bitenum, bitfield};
4use voladdress::{Safe, VolAddress};
5
6/// Timer input clock: the `TAC` clock-select field (bits 1-0).
7#[bitenum(all = false)]
8#[repr(u8)]
9#[derive(Clone, Copy, Debug, PartialEq, Eq)]
10pub enum TimerClock {
11    /// 4096 Hz.
12    Hz4096 = 0b00,
13    /// 262144 Hz.
14    Hz262144 = 0b01,
15    /// 65536 Hz.
16    Hz65536 = 0b10,
17    /// 16384 Hz.
18    #[fallback]
19    Hz16384 = 0b11,
20}
21
22/// Timer control (`TAC`).
23///
24/// | Bit | Field | Access | Meaning |
25/// |-----|-------|--------|---------|
26/// | 7-3 | —        |     | Unused. |
27/// | 2   | `enable` | R/W | Run the timer (TIMA increments). |
28/// | 1-0 | `clock`  | R/W | Input clock that drives TIMA. |
29#[bitfield(u8)]
30#[derive(PartialEq, Eq)]
31pub struct TimerCtrl {
32    /// Input clock that drives TIMA.
33    #[bits(2)]
34    pub clock: TimerClock,
35    /// Run the timer (TIMA increments).
36    pub enable: bool,
37    #[bits(5)]
38    __: u8,
39}
40
41/// Divider: reads the upper byte of the divider, any write resets it to 0.
42pub const DIV: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0xFF04) };
43/// Timer counter.
44pub const TIMA: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0xFF05) };
45/// Timer modulo (reload value on overflow).
46pub const TMA: VolAddress<u8, Safe, Safe> = unsafe { VolAddress::new(0xFF06) };
47/// Timer control: enable and input clock select.
48pub const TAC: VolAddress<TimerCtrl, Safe, Safe> = unsafe { VolAddress::new(0xFF07) };
49
50const _: () = {
51    assert!(TimerCtrl::new().with_enable(true).into_bits() == 0b0000_0100);
52    assert!(TimerCtrl::new().with_clock(TimerClock::Hz16384).into_bits() == 0b0000_0011);
53};