diff --git a/snes-core/src/cpu/interface.rs b/snes-core/src/cpu/interface.rs index 18520c3..b560546 100644 --- a/snes-core/src/cpu/interface.rs +++ b/snes-core/src/cpu/interface.rs @@ -34,9 +34,9 @@ impl CPU { return false; } if self.registers.is_cpu_waiting_interrupt { - // TODO: check for interrupts here - let (bytes, cycles) = cycles::increment_cycles_while_stopped(); - self.registers.increment_pc(bytes); self.registers.cycles += cycles; + self.check_interrupts(bus); + let (_, cycles) = cycles::increment_cycles_while_stopped(); + self.registers.cycles += cycles; return false; } if self.registers.is_moving { diff --git a/snes-core/src/cpu/vectors.rs b/snes-core/src/cpu/vectors.rs index 3871550..849cf17 100644 --- a/snes-core/src/cpu/vectors.rs +++ b/snes-core/src/cpu/vectors.rs @@ -1,4 +1,4 @@ -use super::{interface::CPU, instructions::{phk::PHK, CPUInstruction, php::PHP, push_common}}; +use super::{instructions::push_common, interface::CPU, internal_registers::RDNMI}; use crate::cpu::bus::Bus; @@ -38,33 +38,40 @@ impl CPU { self.registers.is_cpu_stopped = false; } - fn get_vector_from_interrupts(&self) -> Option { - if self.registers.get_irq_disable_flag() { - return None; - } - Some(Vector::Reset) - } - - fn push_emulation_interrupt(&mut self, bus: &mut Bus) { + fn push_interrupt(&mut self, bus: &mut Bus) { + let pbr = self.registers.pbr; if !self.registers.emulation_mode { - PHK{}.execute(&mut self.registers, bus); + push_common::do_push(&mut self.registers, bus, &[pbr]); } let values = [ (self.registers.pc >> 8) as u8, self.registers.pc as u8, ]; push_common::do_push(&mut self.registers, bus, &values); - PHP{}.execute(&mut self.registers, bus); + let p = self.registers.p; + push_common::do_push(&mut self.registers, bus, &[p]); } - pub fn handle_interrupts(&mut self, bus: &mut Bus) { - self.push_emulation_interrupt(bus); - if let Some(vector) = self.get_vector_from_interrupts() { - let effective_vector = vector.get_base_address(); - self.registers.pc = effective_vector as u16; - self.registers.pbr = (effective_vector >> 16) as u8; + fn handle_interrupt(&mut self, bus: &mut Bus, vector: Vector) { + self.push_interrupt(bus); + let base_address = vector.get_base_address(); + let effective_vector = CPU::get_vector(base_address, bus); + self.registers.pc = effective_vector; + self.registers.pbr = 0x00; + } + + pub fn check_interrupts(&mut self, bus: &mut Bus) { + let rdnmi_byte = bus.read(RDNMI as u32); + if rdnmi_byte >> 7 != 0 { + self.registers.is_cpu_waiting_interrupt = false; + self.handle_interrupt(bus, Vector::NMI); + } + if !self.registers.get_irq_disable_flag() && bus.ppu.is_irq_set { + self.registers.is_cpu_waiting_interrupt = false; + self.handle_interrupt(bus, Vector::IRQ); } } + } diff --git a/snes-core/src/ppu/interface.rs b/snes-core/src/ppu/interface.rs index a07117f..fd11581 100644 --- a/snes-core/src/ppu/interface.rs +++ b/snes-core/src/ppu/interface.rs @@ -3,6 +3,8 @@ use super::registers::PPURegisters; pub struct PPU { framebuffer: Vec, pub registers: PPURegisters, + was_vblank_nmi_set: bool, + pub is_irq_set: bool, } impl PPU { @@ -10,6 +12,8 @@ impl PPU { Self { framebuffer: vec![], registers: PPURegisters::new(), + was_vblank_nmi_set: false, + is_irq_set: false, } } @@ -28,10 +32,12 @@ impl PPU { if self.registers.h_count > 339 { self.registers.h_count = 0; self.registers.v_count += 1; - if self.registers.v_count > 224 { + if self.registers.v_count > 224 && !self.was_vblank_nmi_set { self.registers.vblank_nmi = true; + self.was_vblank_nmi_set = true; } if self.registers.v_count > 261 { + self.was_vblank_nmi_set = false; self.registers.v_count = 0; } }