Skip to content
Snippets Groups Projects
timer.rs 3.07 KiB
Newer Older
  • Learn to ignore specific revisions
  • João Magalhães's avatar
    João Magalhães committed
    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 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: u8) {
            self.div_clock += cycles as u16;
    
            while self.div_clock >= 256 {
    
                self.div = self.div.wrapping_add(1);
    
    João Magalhães's avatar
    João Magalhães committed
                self.div_clock -= 256;
    
            if self.tima_enabled {
                self.tima_clock += cycles as u16;
    
                while self.tima_clock >= self.tima_ratio {
    
    João Magalhães's avatar
    João Magalhães committed
                    // 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;
                    }
    
    João Magalhães's avatar
    João Magalhães committed
                    // otherwise uses the normal add operation
                    // and increments the TIMA value by one
                    else {
                        self.tima = self.tima.wrapping_add(1);
                    }
    
    João Magalhães's avatar
    João Magalhães committed
                    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,
    
    João Magalhães's avatar
    João Magalhães committed
                _ => {
                    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),
                    }
    
    João Magalhães's avatar
    João Magalhães committed
                    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);
    
    
    impl Default for Timer {
        fn default() -> Self {
            Self::new()
        }
    }