1use crate::device::IoHandler;
2use crate::ic::Irq;
3use crate::mmu::{MemRead, MemWrite, Mmu};
4use log::*;
5
6pub struct Timer {
7 irq: Irq,
8 div: u8,
9 div_clocks: usize,
10 tim: u8,
11 tim_clocks: usize,
12 tim_load: u8,
13 ctrl: u8,
14}
15
16impl Timer {
17 pub fn new(irq: Irq) -> Self {
18 Self {
19 irq,
20 div: 0,
21 div_clocks: 0,
22 tim: 0,
23 tim_clocks: 0,
24 tim_load: 0,
25 ctrl: 0,
26 }
27 }
28
29 fn tim_clock_reset(&mut self) {
30 self.tim_clocks = match self.ctrl & 0x3 {
31 0x0 => 1024, 0x1 => 16, 0x2 => 64, 0x3 => 256, _ => unreachable!(),
36 };
37 }
38
39 fn div_clock_reset(&mut self) {
40 self.div_clocks = 256; }
42
43 pub fn step(&mut self, time: usize) {
44 if self.div_clocks < time {
45 self.div = self.div.wrapping_add(1);
46 let rem = time - self.div_clocks;
47 self.div_clock_reset();
48 self.div_clocks -= rem;
49 } else {
50 self.div_clocks -= time;
51 }
52
53 if self.ctrl & 0x04 == 0 {
54 return;
55 }
56
57 if self.tim_clocks < time {
58 let mut rem = time - self.tim_clocks;
59
60 loop {
61 let (tim, of) = self.tim.overflowing_add(1);
62 self.tim = tim;
63 if of {
64 self.tim = self.tim_load;
65 self.irq.timer(true);
66 }
67 self.tim_clock_reset();
68 if rem <= self.tim_clocks {
69 self.tim_clocks -= rem;
70 break;
71 }
72 rem -= self.tim_clocks;
73 }
74 } else {
75 self.tim_clocks -= time;
76 }
77 }
78}
79
80impl IoHandler for Timer {
81 fn on_read(&mut self, _mmu: &Mmu, addr: u16) -> MemRead {
82 info!("Timer read: {:04x}", addr);
83 match addr {
84 0xff04 => MemRead::Replace(self.div),
85 0xff05 => MemRead::Replace(self.tim),
86 0xff06 => MemRead::Replace(self.tim_load),
87 0xff07 => MemRead::Replace(self.ctrl),
88 _ => MemRead::PassThrough,
89 }
90 }
91
92 fn on_write(&mut self, _mmu: &Mmu, addr: u16, value: u8) -> MemWrite {
93 info!("Timer write: {:04x} {:02x}", addr, value);
94 match addr {
95 0xff04 => self.div = 0,
96 0xff05 => self.tim = value,
97 0xff06 => self.tim_load = value,
98 0xff07 => {
99 let old_ctrl = self.ctrl;
100 self.ctrl = value;
101
102 if old_ctrl & 4 == 0 && value & 4 != 0 {
103 debug!("Timer started");
104 self.tim_clock_reset();
105 }
106 }
107 _ => {}
108 }
109 MemWrite::PassThrough
110 }
111}