From b2c8e6f1b6166e5d47428d462ea90c365513daf1 Mon Sep 17 00:00:00 2001 From: Isaac Marovitz Date: Thu, 14 Dec 2023 10:37:26 -0500 Subject: [PATCH] Timer --- src/main.rs | 1 + src/mmu.rs | 11 +++++-- src/ppu.rs | 1 - src/timer.rs | 88 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 98 insertions(+), 3 deletions(-) create mode 100644 src/timer.rs diff --git a/src/main.rs b/src/main.rs index 967f005..477a712 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,6 +20,7 @@ mod mode; mod registers; mod ppu; mod serial; +mod timer; pub const CLOCK_FREQUENCY: u32 = 4_194_304; pub const STEP_TIME: u32 = 16; diff --git a/src/mmu.rs b/src/mmu.rs index 930a9dc..1ebd26d 100644 --- a/src/mmu.rs +++ b/src/mmu.rs @@ -1,5 +1,6 @@ use bitflags::bitflags; use crate::ppu::PPU; +use crate::timer::Timer; use crate::mode::GBMode; use crate::serial::Serial; @@ -7,6 +8,7 @@ pub struct MMU { rom: Vec, pub ppu: PPU, serial: Serial, + timer: Timer, wram: [u8; 0x8000], hram: [u8; 0x7F], intf: Interrupts, @@ -31,6 +33,7 @@ impl MMU { rom, ppu: PPU::new(mode), serial: Serial::new(), + timer: Timer::new(), wram: [0; 0x8000], hram: [0; 0x7f], intf: Interrupts::empty(), @@ -40,6 +43,10 @@ impl MMU { } pub fn cycle(&mut self, cycles: u32) -> bool { + self.timer.cycle(cycles); + self.intf |= self.timer.interrupts; + self.timer.interrupts = Interrupts::empty(); + let did_draw = self.ppu.cycle(cycles); self.intf |= self.ppu.interrupts; self.ppu.interrupts = Interrupts::empty(); @@ -65,6 +72,7 @@ impl MMU { 0xFF68..=0xFF6B => self.ppu.read(a), 0xFF80..=0xFFFE => self.hram[a as usize - 0xFF80], 0xFF01..=0xFF02 => self.serial.read(a), + 0xFF04..=0xFF07 => self.timer.read(a), 0xFF0F => self.intf.bits(), 0xFF70 => self.wram_bank as u8, 0xFFFF => self.inte.bits(), @@ -90,8 +98,7 @@ impl MMU { // TODO: Joypad 0xFF00 => {}, 0xFF01..=0xFF02 => self.serial.write(a, v), - // TODO: Timer - 0xFF04..=0xFF07 => {}, + 0xFF04..=0xFF07 => self.timer.write(a, v), // TODO: APU 0xFF10..=0xFF3F => {}, 0xFF0F => self.intf = Interrupts::from_bits(v).unwrap(), diff --git a/src/ppu.rs b/src/ppu.rs index 065338d..add3823 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -272,7 +272,6 @@ impl PPU { // Location of Tile Attributes let tile_address = tile_map_base + tile_index_y * 32 + tile_index_x; - // TODO: This seems to be returning the wrong value let tile_index = self.read_ram0(tile_address); // If we're using the secondary address mode, diff --git a/src/timer.rs b/src/timer.rs new file mode 100644 index 0000000..97260da --- /dev/null +++ b/src/timer.rs @@ -0,0 +1,88 @@ +use crate::mmu::Interrupts; + +pub struct Timer { + div: u8, + tima: u8, + tma: u8, + pub interrupts: Interrupts, + enabled: bool, + step: u32, + internal_count: u32, + internal_divider: u32 +} + +impl Timer { + pub fn new() -> Self { + Self { + div: 0x00, + tima: 0x00, + tma: 0x00, + interrupts: Interrupts::empty(), + enabled: false, + step: 256, + internal_count: 0, + internal_divider: 0 + } + } + + pub fn cycle(&mut self, cycles: u32) { + self.internal_divider += cycles; + while self.internal_divider >= 256 { + self.div = self.div.wrapping_add(1); + self.internal_divider -= 256; + } + + if self.enabled { + self.internal_count += cycles; + + while self.internal_count >= self.step { + self.tima = self.tima.wrapping_add(1); + if self.tima == 0x00 { + self.tima = self.tma; + self.interrupts |= Interrupts::TIMER; + } + self.internal_count -= self.step; + } + } + } + + pub fn read(&self, a: u16) -> u8 { + match a { + 0xFF04 => self.div, + 0xFF05 => self.tima, + 0xFF06 => self.tma, + 0xFF07 => { + let mut v = 0xF8; + v |= if self.enabled { 0b0000_0100 } else { 0x00 }; + v |= match self.step { + 1024 => 1, + 16 => 2, + 64 => 3, + _ => panic!("Unknown timer step ({})!", self.step) + }; + + v + }, + _ => panic!("Read to unsupported timer address ({:#06x})!", a), + } + } + + pub fn write(&mut self, a: u16, v: u8) { + match a { + 0xFF04 => self.div = 0x00, + 0xFF05 => self.tima = v, + 0xFF06 => self.tma = v, + 0xFF07 => { + self.enabled = (v & 0b0000_0100) != 0; + self.step = match v & 0b0000_0011 { + 0 => 1024, + 1 => 16, + 2 => 64, + 3 => 256, + _ => panic!("Unknown timer step ({})!", v) + } + }, + _ => panic!("Write to unsupported timer address ({:#06x})!", a), + } + } +} \ No newline at end of file