fix timers
This commit is contained in:
parent
03faea6ca9
commit
45a1aae05f
|
@ -64,11 +64,10 @@ impl GPU {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CPU {
|
impl CPU {
|
||||||
pub fn advance_gpu_clock(&mut self, steps: u8) {
|
pub fn advance_gpu_clock(&mut self, steps: usize) {
|
||||||
let lcdc = self.get_lcdc();
|
let lcdc = self.get_lcdc();
|
||||||
if lcdc.enable {
|
if lcdc.enable {
|
||||||
let real_steps = (steps as usize) * 4;
|
self.gpu.mode_clock += steps;
|
||||||
self.gpu.mode_clock += real_steps;
|
|
||||||
match self.gpu.mode {
|
match self.gpu.mode {
|
||||||
DrawMode::HBlank => {
|
DrawMode::HBlank => {
|
||||||
// mode 0: hblank
|
// mode 0: hblank
|
||||||
|
|
|
@ -1,15 +1,15 @@
|
||||||
use self::{gpu::GPU, memory::Memory};
|
use self::{gpu::GPU, memory::Memory, timer::Timers};
|
||||||
use crate::{
|
use crate::{
|
||||||
util::{clear_bit, get_bit},
|
util::{clear_bit, get_bit},
|
||||||
verbose_println,
|
verbose_println,
|
||||||
};
|
};
|
||||||
use minifb::Window;
|
use minifb::Window;
|
||||||
use std::{mem::transmute, time::Duration};
|
|
||||||
|
|
||||||
pub mod gpu;
|
pub mod gpu;
|
||||||
mod instructions;
|
mod instructions;
|
||||||
pub mod memory;
|
pub mod memory;
|
||||||
mod opcodes;
|
mod opcodes;
|
||||||
|
mod timer;
|
||||||
|
|
||||||
#[derive(PartialEq)]
|
#[derive(PartialEq)]
|
||||||
pub(crate) enum Flags {
|
pub(crate) enum Flags {
|
||||||
|
@ -32,12 +32,13 @@ pub struct CPU {
|
||||||
window: Window,
|
window: Window,
|
||||||
gpu: GPU,
|
gpu: GPU,
|
||||||
halted: bool,
|
halted: bool,
|
||||||
|
timers: Timers,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hz
|
// Hz
|
||||||
const CLOCK_SPEED: f64 = 4.194304 * 1000000.;
|
const CLOCK_SPEED: usize = 4194304;
|
||||||
const SPEEDUP: f64 = 1.;
|
const SPEEDUP: f64 = 1.;
|
||||||
const FF04_SPEED: f64 = 16384.;
|
// const FF04_SPEED: f64 = 16384.;
|
||||||
|
|
||||||
impl CPU {
|
impl CPU {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
|
@ -57,6 +58,7 @@ impl CPU {
|
||||||
window,
|
window,
|
||||||
gpu: GPU::new(enable_tile_window),
|
gpu: GPU::new(enable_tile_window),
|
||||||
halted: false,
|
halted: false,
|
||||||
|
timers: Timers::init(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,32 +93,6 @@ impl CPU {
|
||||||
self.increment_timers(cycles);
|
self.increment_timers(cycles);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn increment_timers(&mut self, cycles: u8) {
|
|
||||||
let secs = (cycles * 4) as f64 / CLOCK_SPEED;
|
|
||||||
self.advance_gpu_clock(cycles);
|
|
||||||
|
|
||||||
self.memory.set(
|
|
||||||
0xFF04,
|
|
||||||
self.memory
|
|
||||||
.get(0xFF04)
|
|
||||||
.wrapping_add((FF04_SPEED * secs) as u8),
|
|
||||||
);
|
|
||||||
let (timer_enabled, timer_rate) = self.timer_scale();
|
|
||||||
if timer_enabled {
|
|
||||||
let (val, wrap) = self
|
|
||||||
.memory
|
|
||||||
.get(0xFF05)
|
|
||||||
.overflowing_add((secs * timer_rate as f64) as u8);
|
|
||||||
if wrap {
|
|
||||||
self.memory.set(0xFF05, self.memory.get(0xFF06));
|
|
||||||
self.memory.set(0xFF0F, set(self.memory.get(0xFF0F), 2));
|
|
||||||
} else {
|
|
||||||
self.memory.set(0xFF05, val);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
spin_sleep::sleep(Duration::from_secs_f64(secs / SPEEDUP));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn next_opcode(&mut self) -> u8 {
|
fn next_opcode(&mut self) -> u8 {
|
||||||
let opcode = self.memory.get(self.reg.pc);
|
let opcode = self.memory.get(self.reg.pc);
|
||||||
self.reg.pc = self.reg.pc.wrapping_add(0x1);
|
self.reg.pc = self.reg.pc.wrapping_add(0x1);
|
||||||
|
@ -171,18 +147,6 @@ impl CPU {
|
||||||
self.reg.pc = addr;
|
self.reg.pc = addr;
|
||||||
self.memory.ime = false;
|
self.memory.ime = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn timer_scale(&self) -> (bool, usize) {
|
|
||||||
let timer_control = self.memory.get(0xFF07);
|
|
||||||
let timer_enable = get_bit(timer_control, 2);
|
|
||||||
let timer_rate = match (get_bit(timer_control, 1), get_bit(timer_control, 0)) {
|
|
||||||
(true, true) => 256,
|
|
||||||
(true, false) => 64,
|
|
||||||
(false, true) => 16,
|
|
||||||
(false, false) => 1024,
|
|
||||||
};
|
|
||||||
(timer_enable, timer_rate)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
|
|
63
src/processor/timer.rs
Normal file
63
src/processor/timer.rs
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
processor::{CLOCK_SPEED, CPU, SPEEDUP},
|
||||||
|
util::{get_bit, set_bit},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) struct Timers {
|
||||||
|
div_counter: usize,
|
||||||
|
tima_counter: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Timers {
|
||||||
|
pub(super) fn init() -> Self {
|
||||||
|
Self {
|
||||||
|
div_counter: 0,
|
||||||
|
tima_counter: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CPU {
|
||||||
|
pub(super) fn increment_timers(&mut self, machine_cycles: u8) {
|
||||||
|
let clock_cycles = (machine_cycles as usize) * 4;
|
||||||
|
|
||||||
|
self.advance_gpu_clock(clock_cycles);
|
||||||
|
|
||||||
|
self.timers.div_counter += clock_cycles;
|
||||||
|
let div_diff = (self.timers.div_counter / 256) as u8;
|
||||||
|
self.timers.div_counter = self.timers.div_counter % 256;
|
||||||
|
self.memory
|
||||||
|
.set(0xFF04, self.memory.get(0xFF04).wrapping_add(div_diff));
|
||||||
|
|
||||||
|
let (timer_enabled, timer_rate) = self.timer_scale();
|
||||||
|
if timer_enabled {
|
||||||
|
self.timers.tima_counter += clock_cycles;
|
||||||
|
let tima_diff = (self.timers.tima_counter / timer_rate) as u8;
|
||||||
|
self.timers.tima_counter = self.timers.tima_counter % timer_rate;
|
||||||
|
let (val, wrap) = self.memory.get(0xFF05).overflowing_add(tima_diff);
|
||||||
|
if wrap {
|
||||||
|
self.memory.set(0xFF05, self.memory.get(0xFF06));
|
||||||
|
self.memory.set(0xFF0F, set_bit(self.memory.get(0xFF0F), 2));
|
||||||
|
} else {
|
||||||
|
self.memory.set(0xFF05, val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let secs = clock_cycles as f64 / CLOCK_SPEED as f64;
|
||||||
|
spin_sleep::sleep(Duration::from_secs_f64(secs / SPEEDUP));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn timer_scale(&self) -> (bool, usize) {
|
||||||
|
let timer_control = self.memory.get(0xFF07);
|
||||||
|
let timer_enable = get_bit(timer_control, 2);
|
||||||
|
let timer_rate = match (get_bit(timer_control, 1), get_bit(timer_control, 0)) {
|
||||||
|
(true, true) => 256,
|
||||||
|
(true, false) => 64,
|
||||||
|
(false, true) => 16,
|
||||||
|
(false, false) => 1024,
|
||||||
|
};
|
||||||
|
(timer_enable, timer_rate)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue