GBA hardware timers

3use crate::apu::Apu;
4use crate::dma::DmaState;
5use crate::interrupts::{InterruptRegisters, InterruptType};
6use crate::scheduler::{Scheduler, SchedulerEvent};
7use bincode::{Decode, Encode};
8use jgenesis_common::num::GetBit;
9use std::{array, cmp};
11#[derive(Debug, Clone, Encode, Decode)]
12struct Timer {
13    idx: u8,
14    enabled: bool,
15    counter: u16,
16    reload: u16,
17    clock_shift: u8,
18    cascading: bool,
19    irq_enabled: bool,
20    pending_reload_write: Option<u16>,
21    pending_control_write: Option<u16>,
22    just_enabled: bool,
23}
24
25impl Timer {
26    fn new(idx: u8) -> Self {
27        Self {
28            idx,
29            enabled: false,
30            counter: 0,
31            reload: 0,
32            clock_shift: 0,
33            cascading: false,
34            irq_enabled: false,
35            pending_reload_write: None,
36            pending_control_write: None,
37            just_enabled: false,
38        }
39    }
40
41    fn tick(
42        &mut self,
43        prev_overflowed: bool,
44        prev_cycles: u64,
45        current_cycles: u64,
46        apu: &mut Apu,
47        interrupts: &mut InterruptRegisters,
48    ) -> bool {
49        if !self.enabled {
50            self.apply_pending_writes(apu);
51            return false;
52        }
53
54        if self.just_enabled {
55            self.just_enabled = false;
56            self.counter = self.reload;
57            self.apply_pending_writes(apu);
58
59            return false;
60        }
61
62        let increment: u64 = if self.cascading {
63            prev_overflowed.into()
64        } else {
65            (current_cycles >> self.clock_shift) - (prev_cycles >> self.clock_shift)
66        };
67
68        let mut overflowed;
69        (self.counter, overflowed) = self.counter.overflowing_add(increment as u16);
70        overflowed |= increment >= u64::from(u16::MAX);
71
72        if overflowed {
73            self.counter = self.reload;
74
75            if self.irq_enabled {
76                interrupts.set_flag(InterruptType::TIMER[self.idx as usize], current_cycles);
77            }
78        }
79
80        self.apply_pending_writes(apu);
81
82        overflowed
83    }
84
85    fn apply_pending_writes(&mut self, apu: &mut Apu) {
86        if let Some(reload) = self.pending_reload_write.take() {
87            self.apply_reload_write(reload);
88        }
89
90        if let Some(control) = self.pending_control_write.take() {
91            self.apply_control_write(control);
92        }
93
94        if self.idx <= 1 {
95            let frequency = (self.enabled && !self.cascading).then(|| {
96                let increments_per_overflow = 0x10000 - u32::from(self.reload);
97                let cycles_per_overflow = increments_per_overflow << self.clock_shift;
98                (crate::GBA_CLOCK_SPEED as f64) / f64::from(cycles_per_overflow)
99            });
100            apu.notify_timer_frequency_update(self.idx, frequency);
101        }
102    }
103
104    fn apply_reload_write(&mut self, value: u16) {
105        self.reload = value;
106
107        log::trace!("TM{}CNT_L write: {value:04X} (reload value)", self.idx);
108    }
109
110    fn apply_control_write(&mut self, value: u16) {
111        const CLOCK_SHIFTS: [u8; 4] = [
112            0,  // Divider 1 (16777216 Hz)
113            6,  // Divider 64 (262144 Hz)
114            8,  // Divider 256 (65536 Hz)
115            10, // Divider 1024 (16384 Hz)
116        ];
117
118        self.clock_shift = CLOCK_SHIFTS[(value & 3) as usize];
119        self.cascading = self.idx != 0 && value.bit(2);
120        self.irq_enabled = value.bit(6);
121
122        let prev_enabled = self.enabled;
123        self.enabled = value.bit(7);
124
125        self.just_enabled = !prev_enabled && self.enabled;
126
127        log::trace!("TM{}CNT_H write: {value:04X}", self.idx);
128        log::trace!("  Prescaler divider: {}", 1 << self.clock_shift);
129        log::trace!("  Cascading: {}", self.cascading);
130        log::trace!("  IRQ enabled: {}", self.irq_enabled);
131        log::trace!("  Timer enabled: {}", self.enabled);
132    }
133
134    fn read_control(&self) -> u16 {
135        let divider_bits = if self.clock_shift == 0 { 0 } else { self.clock_shift / 2 - 2 };
136
137        u16::from(divider_bits)
138            | (u16::from(self.cascading) << 2)
139            | (u16::from(self.irq_enabled) << 6)
140            | (u16::from(self.enabled) << 7)
141    }
142
143    fn next_event_cycles(&self, cycles: u64) -> Option<u64> {
144        if self.pending_reload_write.is_some()
145            || self.pending_control_write.is_some()
146            || self.just_enabled
147        {
148            // Force an update on the next cycle after register writes
149            return Some(cycles + 1);
150        }
151
152        if !self.enabled || self.cascading {
153            // Disabled timers never overflow, and cascading timers can only overflow when another
154            // timer overflows
155            return None;
156        }
157
158        let increments_until_overflow = 0x10000 - u64::from(self.counter);
159        let mut cycles_until_overflow = increments_until_overflow << self.clock_shift;
160        cycles_until_overflow -= cycles & ((1 << self.clock_shift) - 1);
161
162        Some(cycles + cycles_until_overflow)
163    }
164}
165
166#[derive(Debug, Clone, Encode, Decode)]
167pub struct Timers {
168    timers: [Timer; 4],
169    cycles: u64,
170    next_overflow_cycles: u64,
171}
172
173impl Timers {
174    pub fn new() -> Self {
175        Self {
176            timers: array::from_fn(|i| Timer::new(i as u8)),
177            cycles: 0,
178            next_overflow_cycles: u64::MAX,
179        }
180    }
181
182    pub fn step_to(
183        &mut self,
184        cycles: u64,
185        apu: &mut Apu,
186        dma: &mut DmaState,
187        interrupts: &mut InterruptRegisters,
188        scheduler: &mut Scheduler,
189    ) {
190        if cycles < self.next_overflow_cycles {
191            return;
192        }
193
194        self.step_to_internal(cycles, apu, dma, interrupts, scheduler);
195    }
196
197    fn step_to_internal(
198        &mut self,
199        cycles: u64,
200        apu: &mut Apu,
201        dma: &mut DmaState,
202        interrupts: &mut InterruptRegisters,
203        scheduler: &mut Scheduler,
204    ) {
205        while self.cycles < cycles {
206            let tick_cycles = cmp::min(self.next_overflow_cycles, cycles);
207
208            let mut overflowed = false;
209            for (i, timer) in self.timers.iter_mut().enumerate() {
210                overflowed = timer.tick(overflowed, self.cycles, tick_cycles, apu, interrupts);
211
212                if overflowed && i <= 1 {
213                    apu.handle_timer_overflow(i, tick_cycles, dma);
214                }
215            }
216
217            self.cycles = tick_cycles;
218            self.update_next_overflow_cycles(scheduler);
219        }
220    }
221
222    fn update_next_overflow_cycles(&mut self, scheduler: &mut Scheduler) {
223        match self.timers.iter().filter_map(|timer| timer.next_event_cycles(self.cycles)).min() {
224            Some(next_overflow_cycles) => {
225                self.next_overflow_cycles = next_overflow_cycles;
226                scheduler
227                    .insert_or_update(SchedulerEvent::TimerOverflow, self.next_overflow_cycles);
228            }
229            None => {
230                self.next_overflow_cycles = u64::MAX;
231                scheduler.remove(SchedulerEvent::TimerOverflow);
232            }
233        }
234    }
235
236    pub fn read_register(
237        &mut self,
238        address: u32,
239        cycles: u64,
240        apu: &mut Apu,
241        dma: &mut DmaState,
242        interrupts: &mut InterruptRegisters,
243        scheduler: &mut Scheduler,
244    ) -> u16 {
245        let timer_idx = (address >> 2) & 3;
246
247        if !address.bit(1) {
248            self.step_to_internal(cycles, apu, dma, interrupts, scheduler);
249            log::trace!(
250                "Timer read {address:08X} at cycles {cycles}, counter {:04X}",
251                self.timers[timer_idx as usize].counter
252            );
253            self.timers[timer_idx as usize].counter
254        } else {
255            self.timers[timer_idx as usize].read_control()
256        }
257    }
258
259    #[allow(clippy::too_many_arguments)]
260    pub fn write_register(
261        &mut self,
262        address: u32,
263        value: u16,
264        cycles: u64,
265        apu: &mut Apu,
266        dma: &mut DmaState,
267        interrupts: &mut InterruptRegisters,
268        scheduler: &mut Scheduler,
269    ) {
270        log::trace!("Timer write {address:08X} {value:04X} at cycles {cycles}");
271
272        self.step_to_internal(cycles, apu, dma, interrupts, scheduler);
273
274        let timer_idx = (address >> 2) & 3;
275
276        if !address.bit(1) {
277            self.timers[timer_idx as usize].pending_reload_write = Some(value);
278        } else {
279            self.timers[timer_idx as usize].pending_control_write = Some(value);
280        }
281
282        self.update_next_overflow_cycles(scheduler);
283    }
284
285    #[allow(clippy::too_many_arguments)]
286    pub fn write_register_byte(
287        &mut self,
288        address: u32,
289        value: u8,
290        cycles: u64,
291        apu: &mut Apu,
292        dma: &mut DmaState,
293        interrupts: &mut InterruptRegisters,
294        scheduler: &mut Scheduler,
295    ) {
296        log::trace!("Timer byte write {address:08X} {value:02X} at cycles {cycles}");
297
298        self.step_to_internal(cycles, apu, dma, interrupts, scheduler);
299
300        let timer_idx = (address >> 2) & 3;
301
302        if !address.bit(1) {
303            let mut reload_bytes = self.timers[timer_idx as usize].reload.to_le_bytes();
304            reload_bytes[(address & 1) as usize] = value;
305            self.timers[timer_idx as usize].pending_reload_write =
306                Some(u16::from_le_bytes(reload_bytes));
307        } else {
308            let mut control_bytes = self.timers[timer_idx as usize].read_control().to_le_bytes();
309            control_bytes[(address & 1) as usize] = value;
310            self.timers[timer_idx as usize].pending_control_write =
311                Some(u16::from_le_bytes(control_bytes));
312        }
313
314        self.update_next_overflow_cycles(scheduler);
315    }
316}