From dc45688e4f734aa3a918f1ed2f227b7aa26bd6bf Mon Sep 17 00:00:00 2001 From: Rekai Musuka Date: Sun, 21 Mar 2021 03:03:03 -0500 Subject: [PATCH] feat: implement timers --- src/bus.rs | 20 +++++++++--- src/instruction.rs | 28 ++++++++++++++++ src/timer.rs | 80 +++++++++++++++++++++++++++++++++++++++------- 3 files changed, 113 insertions(+), 15 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index 20ba5e0..6b3b030 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -83,13 +83,13 @@ impl Bus { match self.cartridge.as_ref() { Some(cart) => cart.read_byte(addr), - None => panic!("Tried to read from a non-existant cartridge"), + None => panic!("Tried to read from a non-existent cartridge"), } } 0x4000..=0x7FFF => match self.cartridge.as_ref() { // 16KB ROM Bank 01 -> NN (switchable via MB) Some(cart) => cart.read_byte(addr), - None => panic!("Tried to read from a non-existant cartridge"), + None => panic!("Tried to read from a non-existent cartridge"), }, 0x8000..=0x9FFF => { // 8KB Video RAM @@ -98,7 +98,7 @@ impl Bus { 0xA000..=0xBFFF => match self.cartridge.as_ref() { // 8KB External RAM Some(cart) => cart.read_byte(addr), - None => panic!("Tried to read from the external RAM of a non-existant cartridge"), + None => panic!("Tried to read from the external RAM of a non-existent cartridge"), }, 0xC000..=0xCFFF => { // 4KB Work RAM Bank 0 @@ -123,7 +123,9 @@ impl Bus { 0xFF00 => self.joypad.status.into(), 0xFF01 => self.serial.next, 0xFF02 => self.serial.control.into(), + 0xFF04 => self.timer.divider, 0xFF05 => self.timer.counter, + 0xFF06 => self.timer.modulo, 0xFF07 => self.timer.control.into(), 0xFF0F => self.interrupt_flag().into(), 0xFF11 => self.sound.ch1.sound_duty.into(), @@ -210,7 +212,9 @@ impl Bus { 0xFF00 => self.joypad.status = byte.into(), 0xFF01 => self.serial.next = byte, 0xFF02 => self.serial.control = byte.into(), + 0xFF04 => self.timer.divider = 0x00, 0xFF05 => self.timer.counter = byte.into(), + 0xFF06 => self.timer.modulo = byte.into(), 0xFF07 => self.timer.control = byte.into(), 0xFF0F => self.set_interrupt_flag(byte), 0xFF11 => self.sound.ch1.sound_duty = byte.into(), @@ -276,9 +280,12 @@ impl Bus { let vblank = self.ppu.interrupt.vblank(); let lcd_stat = self.ppu.interrupt.lcd_stat(); - // Read the currrent interrupt information from the Joypad + // Read the current interrupt information from the Joypad let joypad = self.joypad.interrupt(); + // Read the current interrupt information from the Timer + let timer = self.timer.interrupt(); + // Copy the Interrupt Flag register 0xFF0F let mut flag = self.interrupt.flag; @@ -286,6 +293,7 @@ impl Bus { flag.set_vblank(vblank); flag.set_lcd_stat(lcd_stat); flag.set_joypad(joypad); + flag.set_timer(timer); flag } @@ -296,6 +304,7 @@ impl Bus { let vblank = self.interrupt.flag.vblank(); let lcd_stat = self.interrupt.flag.lcd_stat(); let joypad = self.interrupt.flag.joypad(); + let timer = self.interrupt.flag.timer(); // Update the PPU's instance of the following interrupts self.ppu.interrupt.set_vblank(vblank); @@ -303,5 +312,8 @@ impl Bus { // Update the Joypad's instance of the following interrupts self.joypad.set_interrupt(joypad); + + // Update the Timer's instance of the following interrupts + self.timer.set_interrupt(timer); } } diff --git a/src/instruction.rs b/src/instruction.rs index 27b7334..219fbfa 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -2146,6 +2146,34 @@ impl std::ops::RemAssign for Cycles { } } +impl std::ops::Sub for Cycles { + type Output = Cycles; + + fn sub(self, rhs: Self) -> Self::Output { + Self(self.0 - rhs.0) + } +} + +impl std::ops::Sub for Cycles { + type Output = Cycles; + + fn sub(self, rhs: u32) -> Self::Output { + Self(self.0 - rhs) + } +} + +impl std::ops::SubAssign for Cycles { + fn sub_assign(&mut self, rhs: Self) { + *self = Self(self.0 - rhs.0); + } +} + +impl std::ops::SubAssign for Cycles { + fn sub_assign(&mut self, rhs: u32) { + *self = Self(self.0 - rhs); + } +} + impl From for Cycles { fn from(num: u32) -> Self { Self(num) diff --git a/src/timer.rs b/src/timer.rs index 6b48b0a..d68848e 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,16 +1,69 @@ +use crate::Cycles; +use crate::LR35902_CLOCK_SPEED; use bitfield::bitfield; -use crate::instruction::Cycles; +const DIVIDER_REGISTER_HZ: u32 = 16384; #[derive(Debug, Clone, Copy)] pub struct Timer { pub control: TimerControl, pub counter: u8, + pub modulo: u8, + pub divider: u8, + divider_cycles: Cycles, + timer_cycles: Cycles, + interrupt: bool, } impl Timer { - pub fn step(&mut self, _cycles: Cycles) { - // + pub fn step(&mut self, cycles: Cycles) { + self.timer_cycles += cycles; + self.divider_cycles += cycles; + + // Divider Register + let divider_wait = Cycles::new(LR35902_CLOCK_SPEED / DIVIDER_REGISTER_HZ); + let timer_wait = self.timer_cycles(); + + if self.divider_cycles >= divider_wait { + // The Divider Timer has ticked + self.divider_cycles %= divider_wait; + + self.divider = self.divider.wrapping_add(1); + } + + if self.control.enabled() { + if self.timer_cycles >= timer_wait { + // The Timer has ticked + self.timer_cycles %= timer_wait; + + let (result, did_overflow) = self.counter.overflowing_add(1); + self.counter = if did_overflow { + self.interrupt = true; + self.modulo + } else { + result + }; + } + } + } + + fn timer_cycles(&self) -> Cycles { + let difference = match self.control.speed() { + TimerSpeed::Hz4096 => LR35902_CLOCK_SPEED / 4096, + TimerSpeed::Hz262144 => LR35902_CLOCK_SPEED / 262144, + TimerSpeed::Hz65536 => LR35902_CLOCK_SPEED / 65536, + TimerSpeed::Hz16384 => LR35902_CLOCK_SPEED / 16384, + }; + + Cycles::new(difference) + } + + pub fn interrupt(&self) -> bool { + self.interrupt + } + + pub fn set_interrupt(&mut self, value: bool) { + self.interrupt = value; } } @@ -18,26 +71,31 @@ impl Default for Timer { fn default() -> Self { Self { control: Default::default(), + timer_cycles: Default::default(), + divider_cycles: Default::default(), counter: 0, + modulo: 0, + divider: 0, + interrupt: false, } } } #[derive(Debug, Clone, Copy)] pub enum TimerSpeed { - Freq4096Hz = 0, - Freq262144Hz = 1, - Freq65536Hz = 2, - Freq16384Hz = 3, + Hz4096 = 0, + Hz262144 = 1, + Hz65536 = 2, + Hz16384 = 3, } impl From for TimerSpeed { fn from(byte: u8) -> Self { match byte { - 0b00 => Self::Freq4096Hz, - 0b01 => Self::Freq262144Hz, - 0b10 => Self::Freq65536Hz, - 0b11 => Self::Freq16384Hz, + 0b00 => Self::Hz4096, + 0b01 => Self::Hz262144, + 0b10 => Self::Hz65536, + 0b11 => Self::Hz16384, _ => unreachable!("{:#04X} is not a valid value for TimerSpeed", byte), } }