diff --git a/src/processor/memory.rs b/src/processor/memory.rs index 12a992d..7a50f81 100644 --- a/src/processor/memory.rs +++ b/src/processor/memory.rs @@ -1,14 +1,11 @@ +use self::mmio::{Apu, Gpu, Joypad, Serial, Timer}; pub use self::rom::Rom; -use self::{ - interrupts::Interrupt, - mmio::{Apu, Gpu, Joypad, Serial, Timer}, -}; use crate::{processor::SplitRegister, verbose_println, Cpu}; use gilrs::Gilrs; use minifb::{Key, Window}; mod interrupts; -pub use interrupts::Interrupts; +pub use interrupts::{Interrupt, Interrupts}; pub mod mmio; pub(crate) mod rom; @@ -21,7 +18,7 @@ pub struct Memory { ram: [u8; 8192], switchable_ram: [u8; 8192], cpu_ram: [u8; 128], - interrupts: Interrupts, + pub(super) interrupts: Interrupts, pub(super) ime: bool, pub(super) ime_scheduled: u8, dma_addr: u8, diff --git a/src/processor/memory/interrupts.rs b/src/processor/memory/interrupts.rs index f69dc07..90b0540 100644 --- a/src/processor/memory/interrupts.rs +++ b/src/processor/memory/interrupts.rs @@ -74,4 +74,25 @@ impl Interrupts { Interrupt::Joypad => self.flag_register.joypad = status, } } + + pub fn get_next_interrupt(&mut self) -> Option { + if self.enable_register.vblank && self.flag_register.vblank { + self.flag_register.vblank = false; + Some(Interrupt::Vblank) + } else if self.enable_register.lcd_stat && self.flag_register.lcd_stat { + self.flag_register.lcd_stat = false; + Some(Interrupt::LcdStat) + } else if self.enable_register.timer && self.flag_register.timer { + self.flag_register.timer = false; + Some(Interrupt::Timer) + } else if self.enable_register.serial && self.flag_register.serial { + self.flag_register.serial = false; + Some(Interrupt::Serial) + } else if self.enable_register.joypad && self.flag_register.joypad { + self.flag_register.joypad = false; + Some(Interrupt::Joypad) + } else { + None + } + } } diff --git a/src/processor/mod.rs b/src/processor/mod.rs index 55cda48..7010177 100644 --- a/src/processor/mod.rs +++ b/src/processor/mod.rs @@ -1,11 +1,7 @@ -use std::time::Instant; - -use self::memory::Memory; -use crate::{ - util::{clear_bit, get_bit}, - verbose_println, -}; +use self::memory::{Interrupt, Memory}; +use crate::verbose_println; use gilrs::Gilrs; +use std::time::Instant; mod instructions; pub mod memory; @@ -88,37 +84,15 @@ impl Cpu { fn handle_interrupts(&mut self) -> u8 { if self.memory.ime || self.halted { - let req_and_enabled = self.memory.get(0xFF0F) & self.memory.get(0xFFFF); - // all interrupts should last 5 cycles? - if get_bit(req_and_enabled, 0) { - // vblank - self.service_interrupt(0x40); - self.memory - .set(0xFF0F, clear_bit(self.memory.get(0xFF0F), 0)); - 5 - } else if get_bit(req_and_enabled, 1) { - // lcd stat - self.service_interrupt(0x48); - self.memory - .set(0xFF0F, clear_bit(self.memory.get(0xFF0F), 1)); - 5 - } else if get_bit(req_and_enabled, 2) { - // timer - self.service_interrupt(0x50); - self.memory - .set(0xFF0F, clear_bit(self.memory.get(0xFF0F), 2)); - 5 - } else if get_bit(req_and_enabled, 3) { - // serial - self.service_interrupt(0x58); - self.memory - .set(0xFF0F, clear_bit(self.memory.get(0xFF0F), 3)); - 5 - } else if get_bit(req_and_enabled, 4) { - // joypad - self.service_interrupt(0x60); - self.memory - .set(0xFF0F, clear_bit(self.memory.get(0xFF0F), 4)); + if let Some(interrupt) = self.memory.interrupts.get_next_interrupt() { + let interrupt_addr = match interrupt { + Interrupt::Vblank => 0x40, + Interrupt::LcdStat => 0x48, + Interrupt::Timer => 0x50, + Interrupt::Serial => 0x58, + Interrupt::Joypad => 0x60, + }; + self.service_interrupt(interrupt_addr); 5 } else { 0