rustyboy/src/timer.rs

91 lines
2.6 KiB
Rust

#[derive(Default, Debug)]
pub struct Timer {
tima: u8, // Timer counter, interrupt on overflow
tma: u8,
tac: u8, // 00 = 4096 Hz [10240 ticks], 01 = 262144 Hz [160 ticks], 10 = 65536 Hz [640], 11 = 16384 Hz[2560]. Bit 2 0 = stop, 1 = start
div: u8, // Incremented at speed of 16384Hz
timer_interrupt: bool,
tick_counter: u16,
div_tick_counter: u16,
gb_ticks: u16,
}
const TIMER_SPEED: [u16; 4] = [64, 1, 4, 16];
const TIMER_ENABLE: u8 = (1 << 2);
impl Timer {
pub fn new() -> Timer {
Timer::default()
}
fn timer_clock_tick(&mut self) {
// The div reg will always tick
self.div_tick_counter += 1;
if self.div_tick_counter >= TIMER_SPEED[3] {
self.div = self.div.wrapping_add(1);
self.div_tick_counter -= TIMER_SPEED[3];
}
if (self.tac & TIMER_ENABLE) == TIMER_ENABLE {
// Is timer enabled?
self.tick_counter += 1;
let req_ticks = TIMER_SPEED[(self.tac & 3) as usize];
if self.tick_counter >= req_ticks {
if self.tima == 0xFF {
self.timer_interrupt = true;
self.tima = 0;
} else {
self.tima += 1;
}
self.tick_counter -= req_ticks;
}
}
}
pub fn tick(&mut self, ticks: u16) {
// One tick 1/4.194304MHz on regular speed => 16 gb ticks
self.gb_ticks += ticks;
// If we're in GBC fast mode, we'd require 32 ticks instead of 16
while self.gb_ticks >= 16 {
self.timer_clock_tick();
self.gb_ticks -= 16;
}
}
pub fn write_byte(&mut self, addr: u16, val: u8) {
match addr {
0xFF04 => self.div = 0,
0xFF05 => self.tima = val,
0xFF06 => self.tma = val,
0xFF07 => self.tac = val,
_ => println!("Timer: Write {:02X} to {:04X} unsupported", val, addr),
}
}
pub fn read_byte(&self, addr: u16) -> u8 {
match addr {
0xFF04 => self.div,
0xFF05 => self.tima,
0xFF06 => self.tma,
0xFF07 => self.tac,
_ => {
println!("Timer: Read from {:04X} unsupported", addr);
0
}
}
}
pub fn timer_interrupt(&mut self) -> bool {
// Returns whether or not a vblank interrupt should be done
// Yes, this is polling, and yes, this sucks.\
if self.timer_interrupt {
self.timer_interrupt = false;
true
} else {
false
}
}
}