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
.interrupts
.set_interrupt(Interrupt::Timer, timer_return.timer_interrupt);
if timer_return.timer_interrupt {
self.memory.interrupts.set_interrupt(Interrupt::Timer, true);
}
self.memory.apu.tick(steps);

View file

@ -1,6 +1,6 @@
use crate::util::get_bit;
#[derive(Default)]
#[derive(Default, Debug)]
struct InterruptRegister {
vblank: bool,
lcd_stat: bool,
@ -31,6 +31,7 @@ fn bool_to_shifted(input: bool, shift: u8) -> u8 {
(if input { 1 } else { 0 }) << shift
}
#[derive(Debug)]
pub enum Interrupt {
Vblank,
LcdStat,
@ -57,7 +58,7 @@ impl Interrupts {
}
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) {
@ -94,4 +95,12 @@ impl Interrupts {
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,
last_instruction_addr: u16,
halted: bool,
should_halt_bug: bool,
gamepad_handler: Gilrs,
cycle_start: Instant,
}
@ -41,6 +42,7 @@ impl Cpu {
last_instruction: 0x0,
last_instruction_addr: 0x0,
halted: false,
should_halt_bug: false,
gamepad_handler,
cycle_start: Instant::now(),
}
@ -56,10 +58,6 @@ impl Cpu {
return;
}
self.last_instruction_addr = self.reg.pc;
let opcode = self.next_opcode();
self.last_instruction = opcode;
if self.memory.ime_scheduled > 0 {
self.memory.ime_scheduled = self.memory.ime_scheduled.saturating_sub(1);
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!(
"exec {:#4X} from pc: {:#X}",
opcode,
self.last_instruction_addr
);
let cycles = self.run_opcode(opcode);
self.increment_timers(cycles);
self.run_and_increment_timers(opcode);
}
fn next_opcode(&mut self) -> u8 {
@ -82,8 +87,22 @@ impl Cpu {
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 {
if self.memory.ime || self.halted {
if self.memory.ime {
if let Some(interrupt) = self.memory.interrupts.get_next_interrupt() {
let interrupt_addr = match interrupt {
Interrupt::Vblank => 0x40,
@ -98,6 +117,9 @@ impl Cpu {
0
}
} else {
if self.halted && self.memory.interrupts.is_interrupt_queued() {
self.halted = false;
}
0
}
}

View file

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