Skip to content
Snippets Groups Projects
timer.rs 2.42 KiB
use crate::warnln;

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 clock(&mut self, cycles: u8) {
        self.div_clock += cycles as u16;
        if self.div_clock >= 256 {
            self.div = self.div.wrapping_add(1);
            self.div_clock = self.div_clock - 256;
        }

        if self.tima_enabled {
            self.tima_clock += cycles as u16;
            if self.tima_clock >= self.tima_ratio {
                if self.tima == 0xff {
                    self.int_tima = true;
                    self.tima = self.tma;
                }

                self.tima = self.tima.wrapping_add(1);
                self.tima_clock = self.tima_clock - self.tima_ratio;
            }
        }
    }

    pub fn read(&mut self, addr: u16) -> u8 {
        match addr & 0x00ff {
            0x04 => self.div,
            0x05 => self.tima,
            0x06 => self.tma,
            0x07 => self.tac,
            _ => {
                warnln!("Reding from unknown Timer location 0x{:04x}", addr);
                0xff
            }
        }
    }

    pub fn write(&mut self, addr: u16, value: u8) {
        match addr & 0x00ff {
            0x04 => self.div = 0,
            0x05 => self.tima = value,
            0x06 => self.tma = value,
            0x07 => {
                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),
                }
                self.tima_enabled = value & 0x04 == 0x04;
            }
            _ => 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;
    }

    pub fn ack_tima(&mut self) {
        self.set_int_tima(false);
    }
}