feat: enable halt and rework timer registers
This commit is contained in:
parent
2bf877d1ec
commit
bce14348f8
|
@ -8,8 +8,7 @@ use super::serial::Serial;
|
||||||
use super::sound::Sound;
|
use super::sound::Sound;
|
||||||
use super::timer::Timer;
|
use super::timer::Timer;
|
||||||
use super::work_ram::{VariableWorkRam, WorkRam};
|
use super::work_ram::{VariableWorkRam, WorkRam};
|
||||||
use anyhow::anyhow;
|
use std::{fs::File, io::Read};
|
||||||
use std::{convert::TryInto, fs::File, io::Read};
|
|
||||||
|
|
||||||
const BOOT_ROM_SIZE: usize = 256;
|
const BOOT_ROM_SIZE: usize = 256;
|
||||||
|
|
||||||
|
@ -124,7 +123,7 @@ impl Bus {
|
||||||
0xFF00 => self.joypad.status.into(),
|
0xFF00 => self.joypad.status.into(),
|
||||||
0xFF01 => self.serial.next,
|
0xFF01 => self.serial.next,
|
||||||
0xFF02 => self.serial.control.into(),
|
0xFF02 => self.serial.control.into(),
|
||||||
0xFF04 => self.timer.divider,
|
0xFF04 => (self.timer.divider >> 8) as u8,
|
||||||
0xFF05 => self.timer.counter,
|
0xFF05 => self.timer.counter,
|
||||||
0xFF06 => self.timer.modulo,
|
0xFF06 => self.timer.modulo,
|
||||||
0xFF07 => self.timer.control.into(),
|
0xFF07 => self.timer.control.into(),
|
||||||
|
|
33
src/cpu.rs
33
src/cpu.rs
|
@ -86,21 +86,20 @@ impl Cpu {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn step(&mut self) -> Cycles {
|
pub fn step(&mut self) -> Cycles {
|
||||||
// if let Some(state) = self.halted() {
|
|
||||||
// use HaltState::*;
|
|
||||||
|
|
||||||
// match state {
|
|
||||||
// ImeSet | NonePending => Cycles::new(4),
|
|
||||||
// SomePending => {
|
|
||||||
// todo!("Implement HALT Bug");
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// };
|
|
||||||
|
|
||||||
if self.reg.pc > 0x100 {
|
if self.reg.pc > 0x100 {
|
||||||
self.log_state().unwrap();
|
self.log_state().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let cycles = match self.halted() {
|
||||||
|
Some(state) => {
|
||||||
|
use HaltState::*;
|
||||||
|
|
||||||
|
match state {
|
||||||
|
ImeSet | NonePending => Cycles::new(4),
|
||||||
|
SomePending => todo!("Implement HALT bug"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {
|
||||||
let opcode = self.fetch();
|
let opcode = self.fetch();
|
||||||
self.inc_pc();
|
self.inc_pc();
|
||||||
|
|
||||||
|
@ -108,6 +107,10 @@ impl Cpu {
|
||||||
let cycles = self.execute(instr);
|
let cycles = self.execute(instr);
|
||||||
|
|
||||||
self.bus.step(cycles);
|
self.bus.step(cycles);
|
||||||
|
cycles
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
self.handle_interrupts();
|
self.handle_interrupts();
|
||||||
|
|
||||||
cycles
|
cycles
|
||||||
|
@ -167,40 +170,35 @@ impl Cpu {
|
||||||
|
|
||||||
if self.ime() {
|
if self.ime() {
|
||||||
let mut req: InterruptFlag = req.into();
|
let mut req: InterruptFlag = req.into();
|
||||||
let mut enabled: InterruptEnable = enabled.into();
|
let enabled: InterruptEnable = enabled.into();
|
||||||
|
|
||||||
let vector = if req.vblank() && enabled.vblank() {
|
let vector = if req.vblank() && enabled.vblank() {
|
||||||
// Handle VBlank Interrupt
|
// Handle VBlank Interrupt
|
||||||
req.set_vblank(false);
|
req.set_vblank(false);
|
||||||
enabled.set_vblank(false);
|
|
||||||
|
|
||||||
// INT 40h
|
// INT 40h
|
||||||
Some(0x40)
|
Some(0x40)
|
||||||
} else if req.lcd_stat() && enabled.lcd_stat() {
|
} else if req.lcd_stat() && enabled.lcd_stat() {
|
||||||
// Handle LCD STAT Interrupt
|
// Handle LCD STAT Interrupt
|
||||||
req.set_lcd_stat(false);
|
req.set_lcd_stat(false);
|
||||||
enabled.set_lcd_stat(false);
|
|
||||||
|
|
||||||
// INT 48h
|
// INT 48h
|
||||||
Some(0x48)
|
Some(0x48)
|
||||||
} else if req.timer() && enabled.timer() {
|
} else if req.timer() && enabled.timer() {
|
||||||
// Handle Timer Interrupt
|
// Handle Timer Interrupt
|
||||||
req.set_timer(false);
|
req.set_timer(false);
|
||||||
enabled.set_timer(false);
|
|
||||||
|
|
||||||
// INT 50h
|
// INT 50h
|
||||||
Some(0x50)
|
Some(0x50)
|
||||||
} else if req.serial() && enabled.serial() {
|
} else if req.serial() && enabled.serial() {
|
||||||
// Handle Serial Interrupt
|
// Handle Serial Interrupt
|
||||||
req.set_serial(false);
|
req.set_serial(false);
|
||||||
enabled.set_serial(false);
|
|
||||||
|
|
||||||
// INT 58h
|
// INT 58h
|
||||||
Some(0x58)
|
Some(0x58)
|
||||||
} else if req.joypad() && enabled.joypad() {
|
} else if req.joypad() && enabled.joypad() {
|
||||||
// Handle Joypad Interrupt
|
// Handle Joypad Interrupt
|
||||||
req.set_joypad(false);
|
req.set_joypad(false);
|
||||||
enabled.set_joypad(false);
|
|
||||||
|
|
||||||
// INT 60h
|
// INT 60h
|
||||||
Some(0x60)
|
Some(0x60)
|
||||||
|
@ -212,7 +210,6 @@ impl Cpu {
|
||||||
Some(register) => {
|
Some(register) => {
|
||||||
// Write the Changes to 0xFF0F and 0xFFFF registers
|
// Write the Changes to 0xFF0F and 0xFFFF registers
|
||||||
self.write_byte(0xFF0F, req.into());
|
self.write_byte(0xFF0F, req.into());
|
||||||
self.write_byte(0xFFFF, enabled.into());
|
|
||||||
|
|
||||||
// Disable all future interrupts
|
// Disable all future interrupts
|
||||||
self.set_ime(false);
|
self.set_ime(false);
|
||||||
|
|
|
@ -594,7 +594,6 @@ impl Instruction {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
println!("Game Boy HALTed in {:?}", halt_state);
|
|
||||||
cpu.halt(halt_state);
|
cpu.halt(halt_state);
|
||||||
|
|
||||||
// Though this can actually last forever
|
// Though this can actually last forever
|
||||||
|
|
64
src/timer.rs
64
src/timer.rs
|
@ -1,62 +1,57 @@
|
||||||
use crate::Cycles;
|
use crate::Cycles;
|
||||||
use crate::LR35902_CLOCK_SPEED;
|
|
||||||
use bitfield::bitfield;
|
use bitfield::bitfield;
|
||||||
|
|
||||||
const DIVIDER_REGISTER_HZ: u32 = 16384;
|
// const DIVIDER_REGISTER_HZ: u32 = 16384;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
pub control: TimerControl,
|
pub control: TimerControl,
|
||||||
pub counter: u8,
|
pub counter: u8,
|
||||||
pub modulo: u8,
|
pub modulo: u8,
|
||||||
pub divider: u8,
|
pub divider: u16,
|
||||||
divider_cycles: Cycles,
|
prev_and_result: Option<u8>,
|
||||||
timer_cycles: Cycles,
|
|
||||||
interrupt: bool,
|
interrupt: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
pub fn step(&mut self, cycles: Cycles) {
|
pub fn step(&mut self, cycles: Cycles) {
|
||||||
self.timer_cycles += cycles;
|
use TimerSpeed::*;
|
||||||
self.divider_cycles += cycles;
|
|
||||||
|
|
||||||
// Divider Register
|
|
||||||
let divider_wait = Cycles::new(LR35902_CLOCK_SPEED / DIVIDER_REGISTER_HZ);
|
|
||||||
let timer_wait = self.timer_cycles();
|
|
||||||
|
|
||||||
if self.divider_cycles >= divider_wait {
|
|
||||||
// The Divider Timer has ticked
|
|
||||||
self.divider_cycles %= divider_wait;
|
|
||||||
|
|
||||||
|
for _ in 0..cycles.into() {
|
||||||
self.divider = self.divider.wrapping_add(1);
|
self.divider = self.divider.wrapping_add(1);
|
||||||
|
|
||||||
|
// Get Bit Position
|
||||||
|
let pos = match self.control.speed() {
|
||||||
|
Hz4096 => 9,
|
||||||
|
Hz262144 => 3,
|
||||||
|
Hz65536 => 5,
|
||||||
|
Hz16384 => 7,
|
||||||
|
};
|
||||||
|
|
||||||
|
let bit = (self.divider >> pos) as u8 & 0x01;
|
||||||
|
let timer_enable = self.control.enabled() as u8;
|
||||||
|
let and_result = bit & timer_enable;
|
||||||
|
|
||||||
|
if let Some(previous) = self.prev_and_result {
|
||||||
|
if previous == 0x01 && and_result == 0x00 {
|
||||||
|
// Falling Edge, increase TIMA Regiser
|
||||||
|
self.increment_tima();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.prev_and_result = Some(and_result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.control.enabled() {
|
fn increment_tima(&mut self) {
|
||||||
if self.timer_cycles >= timer_wait {
|
|
||||||
// The Timer has ticked
|
|
||||||
self.timer_cycles %= timer_wait;
|
|
||||||
|
|
||||||
let (result, did_overflow) = self.counter.overflowing_add(1);
|
let (result, did_overflow) = self.counter.overflowing_add(1);
|
||||||
|
|
||||||
self.counter = if did_overflow {
|
self.counter = if did_overflow {
|
||||||
self.interrupt = true;
|
self.interrupt = true;
|
||||||
self.modulo
|
self.modulo
|
||||||
} else {
|
} else {
|
||||||
result
|
result
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
fn timer_cycles(&self) -> Cycles {
|
|
||||||
let difference = match self.control.speed() {
|
|
||||||
TimerSpeed::Hz4096 => LR35902_CLOCK_SPEED / 4096,
|
|
||||||
TimerSpeed::Hz262144 => LR35902_CLOCK_SPEED / 262144,
|
|
||||||
TimerSpeed::Hz65536 => LR35902_CLOCK_SPEED / 65536,
|
|
||||||
TimerSpeed::Hz16384 => LR35902_CLOCK_SPEED / 16384,
|
|
||||||
};
|
|
||||||
|
|
||||||
Cycles::new(difference)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn interrupt(&self) -> bool {
|
pub fn interrupt(&self) -> bool {
|
||||||
self.interrupt
|
self.interrupt
|
||||||
|
@ -71,12 +66,11 @@ impl Default for Timer {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
control: Default::default(),
|
control: Default::default(),
|
||||||
timer_cycles: Default::default(),
|
|
||||||
divider_cycles: Default::default(),
|
|
||||||
counter: 0,
|
counter: 0,
|
||||||
modulo: 0,
|
modulo: 0,
|
||||||
divider: 0,
|
divider: 0,
|
||||||
interrupt: false,
|
interrupt: false,
|
||||||
|
prev_and_result: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue