Skip to content

Commit

Permalink
feat: work on NMI interrupt support
Browse files Browse the repository at this point in the history
  • Loading branch information
nathanleiby committed Dec 10, 2024
1 parent d3364f1 commit a6d2ca3
Show file tree
Hide file tree
Showing 2 changed files with 30 additions and 6 deletions.
14 changes: 12 additions & 2 deletions src/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -246,8 +246,7 @@ impl Cpu {
{
loop {
if self.bus.poll_nmi_status() {
todo!("implement NMI interrupt");
// self.interrupt_nmi();
self.interrupt_nmi();
}

callback(self);
Expand Down Expand Up @@ -1016,6 +1015,17 @@ impl Cpu {
self.lsr(mode);
self.eor(mode);
}

fn interrupt_nmi(&mut self) {
self.stack_push_u16(self.pc);
self.stack_push(self.status);

self.set_flag(Flag::Interrupt, true);

self.bus.tick(2);

self.pc = self.mem_read_u16(0xFFFA);
}
}

#[cfg(test)]
Expand Down
22 changes: 18 additions & 4 deletions src/ppu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,13 @@ impl Ppu {
self.clock_cycles += cycles;
// each scanline lasts for 341 PPU clock cycles
let scanline = cycles / 341;
if self.scanline < 241 && scanline >= 241 && self
if self.scanline < 241
&& scanline >= 241
&& self
.registers
.control
.contains(ControlRegister::VBLANK_NMI_ENABLE) {
.contains(ControlRegister::VBLANK_NMI_ENABLE)
{
// upon entering scanline 241, PPU triggers NMI interrupt
self.nmi_interrupt = true;
// The VBlank flag of the PPU is set at tick 1 (the second tick) of scanline 241
Expand All @@ -96,8 +99,19 @@ impl Ppu {
}

pub fn write_to_ctrl(&mut self, data: u8) {
// TODO: bugzmanov book sets ctrl.bits directly vs recreating .. I hit an error attempting that
self.registers.control = ControlRegister::from_bits_truncate(data);
let before = &self.registers.control;
let after = ControlRegister::from_bits_truncate(data);

// should we toggle an NMI interrupt?
let is_vblank_state = self.registers.status.contains(StatusRegister::VBLANK_FLAG);
let enabled_vblank_nmi = after.contains(ControlRegister::VBLANK_NMI_ENABLE)
&& !before.contains(ControlRegister::VBLANK_NMI_ENABLE);
if is_vblank_state && enabled_vblank_nmi {
self.nmi_interrupt = true;
}

// update the register's value
self.registers.control = after;
}

pub fn write_to_mask(&mut self, data: u8) {
Expand Down

0 comments on commit a6d2ca3

Please sign in to comment.