timer.rsannotatedtimer.rssource145 lines · 3.4 KB · raw
1use crate::interrupts::InterruptRegisters;
2use crate::sm83::InterruptType;
3use bincode::{Decode, Encode};
4use jgenesis_common::num::GetBit;
5
6#[derive(Debug, Clone, Copy, PartialEq, Eq, Encode, Decode)]
7enum ClockSelect {
8    Zero,
9    One,
10    Two,
11    Three,
12}
13
14impl ClockSelect {
15    fn from_byte(byte: u8) -> Self {
16        match byte & 0x3 {
17            0x0 => Self::Zero,
18            0x1 => Self::One,
19            0x2 => Self::Two,
20            0x3 => Self::Three,
21            _ => unreachable!("value & 0x3 is always <= 0x3"),
22        }
23    }
24
25    fn to_bits(self) -> u8 {
26        match self {
27            Self::Zero => 0,
28            Self::One => 1,
29            Self::Two => 2,
30            Self::Three => 3,
31        }
32    }
33
34    fn timer_bit(self) -> u8 {
35        match self {
36            // 4 KHz
37            Self::Zero => 9,
38            // 256 KHz
39            Self::One => 3,
40            // 64 KHz
41            Self::Two => 5,
42            // 16 KHz
43            Self::Three => 7,
44        }
45    }
46}
47
48#[derive(Debug, Clone, Encode, Decode)]
49pub struct GbTimer {
50    timer: u16,
51    enabled: bool,
52    counter: u8,
53    modulo: u8,
54    clock_select: ClockSelect,
55    previous_timer_bit: bool,
56    overflow: bool,
57}
58
59impl GbTimer {
60    pub fn new() -> Self {
61        Self {
62            timer: 0,
63            enabled: false,
64            counter: 0,
65            modulo: 0,
66            clock_select: ClockSelect::Zero,
67            previous_timer_bit: false,
68            overflow: false,
69        }
70    }
71
72    pub fn tick_m_cycle(&mut self, interrupt_registers: &mut InterruptRegisters) {
73        // Full 16-bit timer always ticks, even when the timer is disabled
74        self.timer = self.timer.wrapping_add(4);
75
76        if !self.enabled {
77            return;
78        }
79
80        // Reset counter and flag interrupt if counter increment overflowed on the last M-cycle
81        if self.overflow {
82            self.counter = self.modulo;
83            interrupt_registers.set_flag(InterruptType::Timer);
84            self.overflow = false;
85
86            return;
87        }
88
89        self.check_for_counter_increment();
90    }
91
92    fn check_for_counter_increment(&mut self) {
93        let counter_bit = self.timer.bit(self.clock_select.timer_bit());
94        if self.previous_timer_bit && !counter_bit {
95            let (new_counter, overflow) = self.counter.overflowing_add(1);
96            self.counter = new_counter;
97            self.overflow = overflow;
98        }
99
100        self.previous_timer_bit = counter_bit;
101    }
102
103    pub fn write_div(&mut self) {
104        // Writing any value resets the timer to 0
105        self.timer = 0;
106
107        self.check_for_counter_increment();
108    }
109
110    // DIV: Divider
111    pub fn read_div(&self) -> u8 {
112        // DIV reads out as the highest 8 bits of the internal timer
113        (self.timer >> 8) as u8
114    }
115
116    // TIMA: Timer counter
117    pub fn write_tima(&mut self, value: u8) {
118        self.counter = value;
119    }
120
121    pub fn read_tima(&self) -> u8 {
122        self.counter
123    }
124
125    // TMA: Timer modulo
126    pub fn write_tma(&mut self, value: u8) {
127        self.modulo = value;
128    }
129
130    pub fn read_tma(&self) -> u8 {
131        self.modulo
132    }
133
134    // TAC: Timer control
135    pub fn write_tac(&mut self, value: u8) {
136        self.enabled = value.bit(2);
137        self.clock_select = ClockSelect::from_byte(value);
138
139        self.check_for_counter_increment();
140    }
141
142    pub fn read_tac(&self) -> u8 {
143        0xF8 | (u8::from(self.enabled) << 2) | self.clock_select.to_bits()
144    }
145}