Skip to content

Commit

Permalink
Interrupts: Implement Timer
Browse files Browse the repository at this point in the history
  • Loading branch information
AnnsAnns committed May 25, 2024
1 parent 5f1431e commit 6756eeb
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/cpu/interrupts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const INTERRUPT_FLAG_ADDRESS: u16 = 0xFF0F;
const INTERRUPT_ENABLE_ADDRESS: u16 = 0xFFFF;

impl CPU {
/// Set the interrupt flag for the given interrupt
pub fn set_interrupt_flag(&mut self, interrupt: InterruptTypes) {
let interrupt_flag = self.memory.read_byte(INTERRUPT_FLAG_ADDRESS);
self.memory.write_byte(INTERRUPT_FLAG_ADDRESS, interrupt_flag | (1 << interrupt as u8));
Expand Down
7 changes: 7 additions & 0 deletions src/cpu/step.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,6 +495,13 @@ impl CPU {
FlagState::Unset => self.clear_zero_flag(),
}

// Check whether we need to increase timer
let timer_modulo = self.get_timer_modulo();
let remaining_cycles = self.cycles / timer_modulo;
if remaining_cycles + self.last_step_result.cycles as u64 >= timer_modulo {
self.increment_timer();
}

// Update the last execution time
self.last_execution_time = std::time::Instant::now();
self.cycles += self.last_step_result.cycles as u64;
Expand Down
36 changes: 36 additions & 0 deletions src/cpu/timer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
use super::{interrupts::InterruptTypes, CPU};

const TIMER_COUNTER_ADDRESS: u16 = 0xFF05;
const TIMER_MODULO_ADDRESS: u16 = 0xFF06;

impl CPU {
pub fn increment_timer(&mut self) {
// Check whether FF07 is enabled [Pos 2]
if self.memory.read_byte(0xFF07) & 0b100 == 0 {
return;
}
let previous_val = self.memory.read_byte(TIMER_COUNTER_ADDRESS);
let (new_val, overflow) = previous_val.overflowing_add(1);

if overflow {
log::debug!("Timer overflow - resetting to modulo & setting interrupt flag");
self.memory.write_byte(TIMER_COUNTER_ADDRESS, self.memory.read_byte(TIMER_MODULO_ADDRESS));
self.set_interrupt_flag(InterruptTypes::Timer);
} else {
self.memory.write_byte(TIMER_COUNTER_ADDRESS, new_val);
}
}

/// Get the timer modulo based on the timer speed
pub fn get_timer_modulo(&mut self) -> u64 {
let timer_speed = self.memory.read_byte(0xFF07) & 0b11;

match timer_speed {
0b00 => 256,
0b01 => 4,
0b10 => 16,
0b11 => 64,
_ => panic!("Invalid timer speed"),
}
}
}
5 changes: 4 additions & 1 deletion src/memory/raw_memory_operations.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,10 @@ impl Memory {
0xFF50 => {
log::debug!("Disabling boot rom");
self.boot_rom_enabled = false;
}
},
// DIV register
// https://gbdev.io/pandocs/Timer_and_Divider_Registers.html#ff04--div-divider-register
0xFF04 => self.memory[address as usize] = 0,
// Prevents overwriting of the last 4 bits in FF00 which are mapped to controller input
0xFF00 => {
let prev = self.read_byte(address);
Expand Down

0 comments on commit 6756eeb

Please sign in to comment.