Skip to content

Commit

Permalink
Fix APU timer implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
twvd committed Dec 17, 2023
1 parent 87263bc commit 0428387
Showing 1 changed file with 21 additions and 7 deletions.
28 changes: 21 additions & 7 deletions src/snes/apu/timers.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::cell::Cell;

use crate::tickable::Ticks;

use serde::{Deserialize, Serialize};
Expand All @@ -14,7 +16,10 @@ pub struct Timer {
ticks: usize,

/// Counter register (4-bit)
cnt: u8,
cnt: Cell<u8>,

/// Internal (low) part of counter (4-bits)
cnt_low: u8,

/// Divider
div: Ticks,
Expand All @@ -25,24 +30,31 @@ impl Timer {
Self {
top: 0,
ticks: 0,
cnt: 0,
cnt: Cell::new(0),
cnt_low: 0,
div,
}
}

pub fn reset(&mut self) {
self.ticks = 0;
self.cnt = 0;
self.cnt.set(0);
}

pub fn tick(&mut self, ticks: Ticks) {
// This is supposed to be called at the APU frequency,
// the timer will scale down by its divider.

self.ticks += ticks;
if self.ticks / self.div >= usize::from(self.top) {
self.cnt = (self.cnt + 1) & 0x0F;
self.ticks -= self.top * self.div;
while self.ticks >= self.div {
self.ticks -= self.div;
self.cnt_low += 1;
if self.top != 0 {
if self.cnt_low == self.top as u8 {
self.cnt.set((self.cnt.get() + 1) & 0x0F);
self.cnt_low = 0;
}
}
}
}

Expand All @@ -51,6 +63,8 @@ impl Timer {
}

pub fn get_cnt(&self) -> u8 {
self.cnt
let v = self.cnt.get();
self.cnt.set(0);
v
}
}

0 comments on commit 0428387

Please sign in to comment.