fix: allow for the ppu to modify interrupt flags
This commit is contained in:
parent
f45c2439c1
commit
f365633c1e
42
src/bus.rs
42
src/bus.rs
|
@ -1,7 +1,7 @@
|
|||
use super::cartridge::Cartridge;
|
||||
use super::high_ram::HighRam;
|
||||
use super::instruction::Cycles;
|
||||
use super::interrupt::Interrupt;
|
||||
use super::interrupt::{Interrupt, InterruptFlag};
|
||||
use super::ppu::Ppu;
|
||||
use super::serial::Serial;
|
||||
use super::sound::Sound;
|
||||
|
@ -118,7 +118,7 @@ impl Bus {
|
|||
0xFF01 => self.serial.next,
|
||||
0xFF02 => self.serial.control.into(),
|
||||
0xFF07 => self.timer.control.into(),
|
||||
0xFF0F => self.interrupt.flag.into(),
|
||||
0xFF0F => self.interrupt_flag().into(),
|
||||
0xFF11 => self.sound.ch1.sound_duty.into(),
|
||||
0xFF12 => self.sound.ch1.vol_envelope.into(),
|
||||
0xFF14 => self.sound.ch1.freq_hi.into(),
|
||||
|
@ -203,7 +203,7 @@ impl Bus {
|
|||
0xFF01 => self.serial.next = byte,
|
||||
0xFF02 => self.serial.control = byte.into(),
|
||||
0xFF07 => self.timer.control = byte.into(),
|
||||
0xFF0F => self.interrupt.flag = byte.into(),
|
||||
0xFF0F => self.set_interrupt_flag(byte),
|
||||
0xFF11 => self.sound.ch1.sound_duty = byte.into(),
|
||||
0xFF12 => self.sound.ch1.vol_envelope = byte.into(),
|
||||
0xFF13 => self.sound.ch1.freq_lo = byte.into(),
|
||||
|
@ -251,3 +251,39 @@ impl Bus {
|
|||
self.write_byte(addr, (word & 0x00FF) as u8);
|
||||
}
|
||||
}
|
||||
|
||||
impl Bus {
|
||||
fn interrupt_flag(&self) -> InterruptFlag {
|
||||
// Read the current Interrupt status from the PPU
|
||||
let ppu_vblank = self.ppu.interrupt.vblank();
|
||||
let ppu_lcd_stat = self.ppu.interrupt.lcd_stat();
|
||||
|
||||
// We actually don't care about what the InterruptFlag currently says
|
||||
// about vblank and lcd_stat, because the PPU has the more accurate
|
||||
// knowledge about what state these interrupt flags are in.
|
||||
|
||||
// In order to have the PPU be the source of truth
|
||||
// (and accounting for the fact that we aren't able to update)
|
||||
// the interrupt flag register 0xFF0F in the method, we can
|
||||
// mask over those two interruptss
|
||||
|
||||
// Copy the Interrupt Flag register 0xFF0F
|
||||
let mut flag = self.interrupt.flag;
|
||||
flag.set_vblank(ppu_vblank);
|
||||
flag.set_lcd_stat(ppu_lcd_stat);
|
||||
|
||||
flag
|
||||
}
|
||||
|
||||
fn set_interrupt_flag(&mut self, byte: u8) {
|
||||
// Update the Interrupt register 0xFF0F
|
||||
self.interrupt.flag = byte.into();
|
||||
|
||||
let vblank = self.interrupt.flag.vblank();
|
||||
let lcd_stat = self.interrupt.flag.lcd_stat();
|
||||
|
||||
// Update the PPU's internal tracking of the interrupt register 0xFF0F
|
||||
self.ppu.interrupt.set_vblank(vblank);
|
||||
self.ppu.interrupt.set_lcd_stat(lcd_stat);
|
||||
}
|
||||
}
|
||||
|
|
28
src/ppu.rs
28
src/ppu.rs
|
@ -5,6 +5,7 @@ const GB_WIDTH: usize = 160;
|
|||
const GB_HEIGHT: usize = 144;
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Ppu {
|
||||
pub interrupt: Interrupt,
|
||||
pub lcd_control: LCDControl,
|
||||
pub monochrome: Monochrome,
|
||||
pub pos: ScreenPosition,
|
||||
|
@ -60,6 +61,7 @@ impl Ppu {
|
|||
self.pos.line_y += 1;
|
||||
|
||||
let next_mode = if self.pos.line_y >= 144 {
|
||||
self.interrupt.set_vblank(true);
|
||||
Mode::VBlank
|
||||
} else {
|
||||
Mode::OamScan
|
||||
|
@ -138,6 +140,7 @@ impl Ppu {
|
|||
impl Default for Ppu {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
interrupt: Interrupt::default(),
|
||||
lcd_control: Default::default(),
|
||||
monochrome: Default::default(),
|
||||
pos: Default::default(),
|
||||
|
@ -149,6 +152,31 @@ impl Default for Ppu {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Interrupt {
|
||||
_vblank: bool,
|
||||
_lcd_stat: bool,
|
||||
}
|
||||
|
||||
impl Interrupt {
|
||||
pub fn vblank(&self) -> bool {
|
||||
self._vblank
|
||||
}
|
||||
|
||||
pub fn set_vblank(&mut self, enabled: bool) {
|
||||
self._vblank = enabled;
|
||||
}
|
||||
|
||||
pub fn lcd_stat(&self) -> bool {
|
||||
self._lcd_stat
|
||||
}
|
||||
|
||||
pub fn set_lcd_stat(&mut self, enabled: bool) {
|
||||
self._lcd_stat = enabled;
|
||||
}
|
||||
}
|
||||
|
||||
bitfield! {
|
||||
pub struct LCDStatus(u8);
|
||||
impl Debug;
|
||||
|
|
Loading…
Reference in New Issue