Newer
Older
pub struct Timer {
div: u8,
tima: u8,
tma: u8,
tac: u8,
div_clock: u16,
tima_clock: u16,
tima_enabled: bool,
tima_ratio: u16,
int_tima: bool,
}
impl Timer {
pub fn new() -> Self {
Self {
div: 0,
tima: 0,
tma: 0,
tac: 0x0,
div_clock: 0,
tima_clock: 0,
tima_enabled: false,
tima_ratio: 1024,
int_tima: false,
}
}
pub fn reset(&mut self) {
self.div = 0;
self.tima = 0;
self.tma = 0;
self.tac = 0x0;
self.div_clock = 0;
self.tima_clock = 0;
self.tima_enabled = false;
self.tima_ratio = 1024;
self.int_tima = false;
}
pub fn clock(&mut self, cycles: u16) {
while self.div_clock >= 256 {
while self.tima_clock >= self.tima_ratio {
// in case TIMA value overflows must set the
// interrupt and update the TIMA value to
// the TMA one (reset operation)
if self.tima == 0xff {
self.int_tima = true;
self.tima = self.tma;
}
// otherwise uses the normal add operation
// and increments the TIMA value by one
else {
self.tima = self.tima.wrapping_add(1);
}
}
}
pub fn read(&mut self, addr: u16) -> u8 {
match addr {
// 0xFF04 — DIV: Divider register
0xff04 => self.div,
// 0xFF05 — TIMA: Timer counter
0xff05 => self.tima,
// 0xFF06 — TMA: Timer modulo
0xff06 => self.tma,
// 0xFF07 — TAC: Timer control
0xff07 => self.tac,
_ => {
warnln!("Reding from unknown Timer location 0x{:04x}", addr);
0xff
}
}
pub fn write(&mut self, addr: u16, value: u8) {
match addr {
// 0xFF04 — DIV: Divider register
0xff04 => self.div = 0,
// 0xFF05 — TIMA: Timer counter
0xff05 => self.tima = value,
// 0xFF06 — TMA: Timer modulo
0xff06 => self.tma = value,
// 0xFF07 — TAC: Timer control
0xff07 => {
self.tac = value;
match value & 0x03 {
0x00 => self.tima_ratio = 1024,
0x01 => self.tima_ratio = 16,
0x02 => self.tima_ratio = 64,
0x03 => self.tima_ratio = 256,
value => panic!("Invalid TAC value 0x{:02x}", value),
}
_ => warnln!("Writing to unknown Timer location 0x{:04x}", addr),
pub fn int_tima(&self) -> bool {
self.int_tima
pub fn set_int_tima(&mut self, value: bool) {
self.int_tima = value;
}
impl Default for Timer {
fn default() -> Self {
Self::new()
}
}