interrupts work properly! and halt bug almost does

This commit is contained in:
Alex Janka 2023-02-24 11:53:44 +11:00
parent f0f194f5d2
commit b574e1b1bf
4 changed files with 44 additions and 13 deletions

View file

@ -226,9 +226,9 @@ impl Cpu {
self.memory.apu.div_apu_tick(); self.memory.apu.div_apu_tick();
} }
self.memory if timer_return.timer_interrupt {
.interrupts self.memory.interrupts.set_interrupt(Interrupt::Timer, true);
.set_interrupt(Interrupt::Timer, timer_return.timer_interrupt); }
self.memory.apu.tick(steps); self.memory.apu.tick(steps);

View file

@ -1,6 +1,6 @@
use crate::util::get_bit; use crate::util::get_bit;
#[derive(Default)] #[derive(Default, Debug)]
struct InterruptRegister { struct InterruptRegister {
vblank: bool, vblank: bool,
lcd_stat: bool, lcd_stat: bool,
@ -31,6 +31,7 @@ fn bool_to_shifted(input: bool, shift: u8) -> u8 {
(if input { 1 } else { 0 }) << shift (if input { 1 } else { 0 }) << shift
} }
#[derive(Debug)]
pub enum Interrupt { pub enum Interrupt {
Vblank, Vblank,
LcdStat, LcdStat,
@ -57,7 +58,7 @@ impl Interrupts {
} }
pub(super) fn get_flag_register(&self) -> u8 { pub(super) fn get_flag_register(&self) -> u8 {
self.flag_register.as_register() 0b11100000 | self.flag_register.as_register()
} }
pub(super) fn set_flag_register(&mut self, data: u8) { pub(super) fn set_flag_register(&mut self, data: u8) {
@ -94,4 +95,12 @@ impl Interrupts {
None None
} }
} }
pub fn is_interrupt_queued(&self) -> bool {
(self.enable_register.vblank && self.flag_register.vblank)
|| (self.enable_register.lcd_stat && self.flag_register.lcd_stat)
|| (self.enable_register.timer && self.flag_register.timer)
|| (self.enable_register.serial && self.flag_register.serial)
|| (self.enable_register.joypad && self.flag_register.joypad)
}
} }

View file

@ -26,6 +26,7 @@ pub struct Cpu {
pub last_instruction: u8, pub last_instruction: u8,
last_instruction_addr: u16, last_instruction_addr: u16,
halted: bool, halted: bool,
should_halt_bug: bool,
gamepad_handler: Gilrs, gamepad_handler: Gilrs,
cycle_start: Instant, cycle_start: Instant,
} }
@ -41,6 +42,7 @@ impl Cpu {
last_instruction: 0x0, last_instruction: 0x0,
last_instruction_addr: 0x0, last_instruction_addr: 0x0,
halted: false, halted: false,
should_halt_bug: false,
gamepad_handler, gamepad_handler,
cycle_start: Instant::now(), cycle_start: Instant::now(),
} }
@ -56,10 +58,6 @@ impl Cpu {
return; return;
} }
self.last_instruction_addr = self.reg.pc;
let opcode = self.next_opcode();
self.last_instruction = opcode;
if self.memory.ime_scheduled > 0 { if self.memory.ime_scheduled > 0 {
self.memory.ime_scheduled = self.memory.ime_scheduled.saturating_sub(1); self.memory.ime_scheduled = self.memory.ime_scheduled.saturating_sub(1);
if self.memory.ime_scheduled == 0 { if self.memory.ime_scheduled == 0 {
@ -67,13 +65,20 @@ impl Cpu {
} }
} }
self.last_instruction_addr = self.reg.pc;
let opcode = self.next_opcode();
if self.should_halt_bug {
self.reg.pc = self.reg.pc.wrapping_sub(0x1);
self.should_halt_bug = false;
}
self.last_instruction = opcode;
verbose_println!( verbose_println!(
"exec {:#4X} from pc: {:#X}", "exec {:#4X} from pc: {:#X}",
opcode, opcode,
self.last_instruction_addr self.last_instruction_addr
); );
let cycles = self.run_opcode(opcode); self.run_and_increment_timers(opcode);
self.increment_timers(cycles);
} }
fn next_opcode(&mut self) -> u8 { fn next_opcode(&mut self) -> u8 {
@ -82,8 +87,22 @@ impl Cpu {
opcode opcode
} }
fn run_and_increment_timers(&mut self, opcode: u8) {
let cycles = self.run_opcode(opcode);
self.increment_timers(cycles);
}
fn halt(&mut self) {
if !self.memory.ime && self.memory.interrupts.is_interrupt_queued() {
// halt bug
self.should_halt_bug = true;
} else {
self.halted = true;
}
}
fn handle_interrupts(&mut self) -> u8 { fn handle_interrupts(&mut self) -> u8 {
if self.memory.ime || self.halted { if self.memory.ime {
if let Some(interrupt) = self.memory.interrupts.get_next_interrupt() { if let Some(interrupt) = self.memory.interrupts.get_next_interrupt() {
let interrupt_addr = match interrupt { let interrupt_addr = match interrupt {
Interrupt::Vblank => 0x40, Interrupt::Vblank => 0x40,
@ -98,6 +117,9 @@ impl Cpu {
0 0
} }
} else { } else {
if self.halted && self.memory.interrupts.is_interrupt_queued() {
self.halted = false;
}
0 0
} }
} }

View file

@ -554,7 +554,7 @@ impl Cpu {
2 2
} }
0x76 => { 0x76 => {
self.halted = true; self.halt();
1 1
} }
0x77 => { 0x77 => {