From 61db367f31237d7178a33e7ece5fc52b0c03426e Mon Sep 17 00:00:00 2001 From: Franco Colmenarez Date: Sat, 30 Oct 2021 09:13:31 -0500 Subject: [PATCH] Timer implement --- src/bus.rs | 3 +++ src/cpu.rs | 6 ++++++ src/emulator.rs | 2 ++ src/lib.rs | 1 + src/ppu.rs | 11 +++++----- src/timer.rs | 56 +++++++++++++++++++++++++++++++++++++++++++------ 6 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/bus.rs b/src/bus.rs index 3923de9..8030785 100644 --- a/src/bus.rs +++ b/src/bus.rs @@ -7,6 +7,7 @@ use crate::utils::{ use crate::rom::ROM; use crate::ppu::{PPU, LCDStatus, LCDStatusModeFlag}; use crate::cpu::{Interrupt}; +use crate::timer::{TIMER_DIVIDER_REGISTER_ADDRESS}; pub struct AddressRange { begin: u16, @@ -107,6 +108,8 @@ impl Bus { self.data[(WORK_RAM_1.begin() + (address - ECHO_RAM.begin())) as usize] = data; // Copy to the working RAM } else if VIDEO_RAM.in_range(address) { self.data[address as usize] = data; + } else if address == TIMER_DIVIDER_REGISTER_ADDRESS { + self.data[address as usize] = 0x00; } else { self.data[address as usize] = data; } diff --git a/src/cpu.rs b/src/cpu.rs index c0ff92a..63bace6 100644 --- a/src/cpu.rs +++ b/src/cpu.rs @@ -830,6 +830,12 @@ pub enum Opcode { #[derive(Debug, Copy, Clone)] pub struct Cycles(pub usize); +impl Cycles { + pub fn to_t(&self) -> usize { + self.0 * 4 + } +} + pub struct CPU { registers: Registers, cycles: Cycles, diff --git a/src/emulator.rs b/src/emulator.rs index 48ecd95..fd021c3 100644 --- a/src/emulator.rs +++ b/src/emulator.rs @@ -3,6 +3,7 @@ use std::{thread, time}; use crate::cpu::{CPU, Cycles}; use crate::ppu::PPU; use crate::bus::Bus; +use crate::timer::Timer; pub struct Emulator { cpu: CPU, @@ -31,6 +32,7 @@ impl Emulator { while self.cpu.get_cycles().0 <= cpu_cycles.0 { self.cpu.run(&mut self.bus); self.ppu.do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); + Timer::do_cycles(&mut self.bus, self.cpu.get_last_op_cycles()); } } diff --git a/src/lib.rs b/src/lib.rs index 4f76f07..4cc3aa3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,7 @@ pub mod utils; pub mod cpu; pub mod ppu; +pub mod timer; pub mod rom; pub mod bus; pub mod emulator; diff --git a/src/ppu.rs b/src/ppu.rs index 6567395..b2a9450 100644 --- a/src/ppu.rs +++ b/src/ppu.rs @@ -118,11 +118,6 @@ impl PPU { } } - let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS); - PPU::set_lcd_status(bus, LCDStatus::LYCInterrupt, lyc_compare); - if lyc_compare { - bus.set_interrupt(Interrupt::LCDSTAT, true); - } self.increment_cycles(Cycles(1)); // Horizontal scan completed @@ -131,6 +126,12 @@ impl PPU { PPU::set_lcd_y(bus, PPU::get_lcd_y(bus) + 1); + let lyc_compare = PPU::get_lcd_y(bus) == bus.read(LCD_Y_COMPARE_ADDRESS); + if lyc_compare { + PPU::set_lcd_status(bus, LCDStatus::LYCInterrupt, lyc_compare); + bus.set_interrupt(Interrupt::LCDSTAT, true); + } + // Frame completed if PPU::get_lcd_y(bus) > 153 { PPU::set_lcd_y(bus, 0); diff --git a/src/timer.rs b/src/timer.rs index 00b4428..f07e9c4 100644 --- a/src/timer.rs +++ b/src/timer.rs @@ -1,11 +1,55 @@ -const DIVIDER_REGISTER_ADDRESS: u16 = 0xFF04; -const TIMER_COUNTER_ADDRESS: u16 = 0xFF05; -const TIMER_MODULO_ADDRESS: u16 = 0xFF05; -const TIMER_CONTROL_ADDRESS: u16 = 0xFF05; +use crate::cpu::{Interrupt, Cycles}; +use crate::bus::Bus; +use crate::utils::{ + BitIndex, + get_bit, +}; -struct Timer; +pub const TIMER_DIVIDER_REGISTER_ADDRESS: u16 = 0xFF04; +pub const TIMER_COUNTER_ADDRESS: u16 = 0xFF05; +pub const TIMER_MODULO_ADDRESS: u16 = 0xFF06; +pub const TIMER_CONTROL_ADDRESS: u16 = 0xFF07; + +pub struct Timer; impl Timer { - pub fn cycle() { + + pub fn do_cycles(bus: &mut Bus, cycles: Cycles) { + let mut count = 0; + while count < cycles.to_t() { + Timer::cycle(bus); + count += 1; + } + } + + fn cycle(bus: &mut Bus) { + let div = bus.read(TIMER_DIVIDER_REGISTER_ADDRESS); + bus.write(TIMER_DIVIDER_REGISTER_ADDRESS, div.wrapping_add(1)); + + if Timer::is_timer_enabled(bus) { + let tima = bus.read(TIMER_COUNTER_ADDRESS); + let tima_increment = Timer::get_tima_increment(bus); + if tima.checked_add(tima_increment) == None { + bus.write(TIMER_COUNTER_ADDRESS, bus.read(TIMER_MODULO_ADDRESS)); + bus.set_interrupt(Interrupt::Timer, true); + } else { + bus.write(TIMER_COUNTER_ADDRESS, tima.wrapping_add(tima_increment)); + } + } + } + + fn is_timer_enabled(bus: &Bus) -> bool { + get_bit(bus.read(TIMER_CONTROL_ADDRESS), BitIndex::I2) + } + + fn get_tima_increment(bus: &Bus) -> u8 { + let clock_select = bus.read(TIMER_CONTROL_ADDRESS) & 0b0000_0011; + match clock_select { + 0b00 => (4096 as u16 / 1026 as u16 / 4 as u16).to_be_bytes()[1], + 0b01 => (4096 as u16 / 16 as u16 / 4 as u16).to_be_bytes()[1], + 0b10 => (4096 as u16 / 64 as u16 / 4 as u16).to_be_bytes()[1], + 0b11 => (4096 as u16 / 256 as u16 / 4 as u16).to_be_bytes()[1], + _ => 1, + } } }