Skip to content

Commit

Permalink
Implemented STAT LYC == LY interrupt
Browse files Browse the repository at this point in the history
  • Loading branch information
velllu committed Jan 12, 2024
1 parent 0e82ea1 commit 6690ad9
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 40 deletions.
4 changes: 4 additions & 0 deletions src/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,16 @@ pub mod bus {
}

pub mod gpu {
pub const IF: u16 = 0xFF0F;
pub const LCDC: u16 = 0xFF40;
pub const STAT: u16 = 0xFF41;
pub const SCY: u16 = 0xFF42;
pub const SCX: u16 = 0xFF43;
pub const LY: u16 = 0xFF44;
pub const LYC: u16 = 0xFF45;
pub const OBP0: u16 = 0xFF48;
pub const OBP1: u16 = 0xFF49;
pub const IE: u16 = 0xFFFF;
}

pub mod display {
Expand Down
88 changes: 48 additions & 40 deletions src/interrupts.rs
Original file line number Diff line number Diff line change
@@ -1,54 +1,62 @@
use crate::{common::Bit, GameBoy};

struct Interrupts {
vblank: bool,
lcd: bool,
timer: bool,
serial: bool,
joypad: bool,
use crate::{
common::Bit,
consts::gpu::{IE, IF, LY, LYC, STAT},
GameBoy,
};

#[derive(Debug, PartialEq)]
pub enum Interrupt {
/// https://gbdev.io/pandocs/STAT.html?highlight=ff41#ff41--stat-lcd-status
/// This will get triggered if:
/// - STAT.3: Just entered PPU mode 0 (TODO)
/// - STAT.4: Just entered PPU mode 1 (TODO)
/// - STAT.5: Just entered PPU mode 2 (TODO)
/// - STAT.6: LYC == LY
Stat,
}

impl From<u8> for Interrupts {
fn from(value: u8) -> Self {
Self {
vblank: value.get_bit(0),
lcd: value.get_bit(1),
timer: value.get_bit(2),
serial: value.get_bit(3),
joypad: value.get_bit(4),
impl GameBoy {
pub(crate) fn execute_interrupts(&mut self) {
if !self.flags.ime {
return;
}
}
}

impl From<Interrupts> for u8 {
fn from(value: Interrupts) -> Self {
let mut result: u8 = 0;
let stat = self.bus[STAT];
if stat.get_bit(6) && self.bus[LYC] == self.bus[LY] {
self.execute_interrupt(Interrupt::Stat);
}
}

result.set_bit(0, value.vblank);
result.set_bit(1, value.lcd);
result.set_bit(2, value.timer);
result.set_bit(3, value.serial);
result.set_bit(4, value.joypad);
fn execute_interrupt(&mut self, interrupt: Interrupt) {
// We don't want to call the same interrupt twice
if let Some(previous_interrupt) = &self.previous_interrupt {
if *previous_interrupt == interrupt {
return;
}
}

result
}
}
// The bit corresponding to the correct interrupt, both in Interrupt Enable, and
// Interrupt Flag bytes
let if_bit: u8 = match interrupt {
Interrupt::Stat => 1,
};

impl GameBoy {
pub(crate) fn execute_interrupts(&mut self) {
if !self.flags.ime {
// We can only execute an interrupt if it's turned on in the Interrupt Enable and
// Interrupt Flag bytes
if self.bus[IE].get_bit(if_bit) && self.bus[IF].get_bit(if_bit) {
return;
}

let is_enabled: Interrupts = self.bus[0xFFFF].into();
let mut value: Interrupts = self.bus[0xFF0F].into();
let return_address: u16 = match interrupt {
Interrupt::Stat => 0x48,
};

// TODO: Make code DRYer
if is_enabled.vblank && value.vblank {
self.call(0x40);
self.call(return_address);

value.vblank = false;
self.bus[0xFF0F] = value.into();
}
let mut input_flags = self.bus[IF];
input_flags.set_bit(if_bit, false);
self.bus[IF] = input_flags;

self.previous_interrupt = Some(interrupt);
}
}
7 changes: 7 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use common::merge_two_u8s_into_u16;
use consts::bus::ROM_SIZE;
use flags::Flags;
use gpu::states::Gpu;
use interrupts::Interrupt;
use registers::Registers;

mod bus;
Expand All @@ -24,6 +25,10 @@ pub struct GameBoy {
pub registers: Registers,
pub flags: Flags,
pub gpu: Gpu,

/// This is needed because we cannot fire the same interrupt twice in a row, so we
/// have to keep track of the last one
previous_interrupt: Option<Interrupt>,
}

impl GameBoy {
Expand All @@ -33,6 +38,7 @@ impl GameBoy {
registers: Registers::new(),
flags: Flags::new(),
gpu: Gpu::new(),
previous_interrupt: None,
})
}

Expand All @@ -42,6 +48,7 @@ impl GameBoy {
registers: Registers::new(),
flags: Flags::new(),
gpu: Gpu::new(),
previous_interrupt: None,
}
}

Expand Down

0 comments on commit 6690ad9

Please sign in to comment.