timer.rsannotatedtimer.rssource168 lines · 4.2 KB · raw

YM2612 timers

3use crate::ym2612::debug::TimerState;
4use bincode::{Decode, Encode};
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7pub enum TimerTickEffect {
8    None,
9    Overflowed,
10}
11
12pub struct TimerControl {
13    pub enabled: bool,
14    pub overflow_flag_enabled: bool,
15    pub clear_overflow_flag: bool,
16}
17
18#[derive(Debug, Clone, Encode, Decode)]
19pub struct TimerA {
20    enabled: bool,
21    enabled_next: bool,
22    overflow_flag_enabled: bool,
23    overflow_flag: bool,
24    interval: u16,
25    counter: u16,
26}
27
28impl TimerA {
29    pub fn new() -> Self {
30        Self {
31            enabled: false,
32            enabled_next: false,
33            overflow_flag_enabled: false,
34            overflow_flag: false,
35            interval: 0,
36            counter: 0,
37        }
38    }
39
40    pub fn tick(&mut self) -> TimerTickEffect {
41        // Timer A counter is 10-bit in actual hardware
42        const OVERFLOW: u16 = 1024;
43
44        if !self.enabled {
45            if self.enabled_next {
46                self.enabled = true;
47                self.counter = self.interval;
48            }
49            return TimerTickEffect::None;
50        }
51
52        self.enabled = self.enabled_next;
53
54        self.counter += 1;
55        if self.counter == OVERFLOW {
56            self.overflow_flag |= self.overflow_flag_enabled;
57            self.counter = self.interval;
58            TimerTickEffect::Overflowed
59        } else {
60            TimerTickEffect::None
61        }
62    }
63
64    pub fn overflow_flag(&self) -> bool {
65        self.overflow_flag
66    }
67
68    pub fn interval(&self) -> u16 {
69        self.interval
70    }
71
72    pub fn write_control(
73        &mut self,
74        TimerControl { enabled, overflow_flag_enabled, clear_overflow_flag }: TimerControl,
75    ) {
76        self.enabled_next = enabled;
77        self.overflow_flag_enabled = overflow_flag_enabled;
78        self.overflow_flag &= !clear_overflow_flag;
79    }
80
81    pub fn write_interval_high(&mut self, value: u8) {
82        self.interval = (self.interval & 3) | (u16::from(value) << 2);
83    }
84
85    pub fn write_interval_low(&mut self, value: u8) {
86        self.interval = (self.interval & !3) | u16::from(value & 3);
87    }
88
89    pub fn to_debug_state(&self) -> TimerState {
90        TimerState {
91            enabled: self.enabled_next,
92            overflow_flag: self.overflow_flag,
93            overflow_flag_enabled: self.overflow_flag_enabled,
94            interval: self.interval,
95        }
96    }
97}
98
99#[derive(Debug, Clone, Encode, Decode)]
100pub struct TimerB {
101    enabled: bool,
102    enabled_next: bool,
103    overflow_flag_enabled: bool,
104    overflow_flag: bool,
105    pub interval: u8,
106    counter: u8,
107    divider: u8,
108}
109
110impl TimerB {
111    // Timer B counter increments once per 16 samples
112    const DIVIDER: u8 = 16;
113
114    pub fn new() -> Self {
115        Self {
116            enabled: false,
117            enabled_next: false,
118            overflow_flag_enabled: false,
119            overflow_flag: false,
120            interval: 0,
121            counter: 0,
122            divider: Self::DIVIDER,
123        }
124    }
125
126    pub fn tick(&mut self) {
127        self.divider -= 1;
128        if self.divider == 0 {
129            self.divider = Self::DIVIDER;
130
131            if self.enabled {
132                let overflowed;
133                (self.counter, overflowed) = self.counter.overflowing_add(1);
134                if overflowed {
135                    self.overflow_flag |= self.overflow_flag_enabled;
136                    self.counter = self.interval;
137                }
138            }
139        }
140
141        if !self.enabled && self.enabled_next {
142            self.counter = self.interval;
143        }
144        self.enabled = self.enabled_next;
145    }
146
147    pub fn overflow_flag(&self) -> bool {
148        self.overflow_flag
149    }
150
151    pub fn write_control(
152        &mut self,
153        TimerControl { enabled, overflow_flag_enabled, clear_overflow_flag }: TimerControl,
154    ) {
155        self.enabled_next = enabled;
156        self.overflow_flag_enabled = overflow_flag_enabled;
157        self.overflow_flag &= !clear_overflow_flag;
158    }
159
160    pub fn to_debug_state(&self) -> TimerState {
161        TimerState {
162            enabled: self.enabled_next,
163            overflow_flag: self.overflow_flag,
164            overflow_flag_enabled: self.overflow_flag_enabled,
165            interval: self.interval.into(),
166        }
167    }
168}