Skip to content

Commit a6d2ca3

Browse files
committed
1 parent d3364f1 commit a6d2ca3

File tree

2 files changed

+30
-6
lines changed

2 files changed

+30
-6
lines changed

src/core.rs

+12-2
Original file line numberDiff line numberDiff line change
@@ -246,8 +246,7 @@ impl Cpu {
246246
{
247247
loop {
248248
if self.bus.poll_nmi_status() {
249-
todo!("implement NMI interrupt");
250-
// self.interrupt_nmi();
249+
self.interrupt_nmi();
251250
}
252251

253252
callback(self);
@@ -1016,6 +1015,17 @@ impl Cpu {
10161015
self.lsr(mode);
10171016
self.eor(mode);
10181017
}
1018+
1019+
fn interrupt_nmi(&mut self) {
1020+
self.stack_push_u16(self.pc);
1021+
self.stack_push(self.status);
1022+
1023+
self.set_flag(Flag::Interrupt, true);
1024+
1025+
self.bus.tick(2);
1026+
1027+
self.pc = self.mem_read_u16(0xFFFA);
1028+
}
10191029
}
10201030

10211031
#[cfg(test)]

src/ppu.rs

+18-4
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,13 @@ impl Ppu {
6969
self.clock_cycles += cycles;
7070
// each scanline lasts for 341 PPU clock cycles
7171
let scanline = cycles / 341;
72-
if self.scanline < 241 && scanline >= 241 && self
72+
if self.scanline < 241
73+
&& scanline >= 241
74+
&& self
7375
.registers
7476
.control
75-
.contains(ControlRegister::VBLANK_NMI_ENABLE) {
77+
.contains(ControlRegister::VBLANK_NMI_ENABLE)
78+
{
7679
// upon entering scanline 241, PPU triggers NMI interrupt
7780
self.nmi_interrupt = true;
7881
// The VBlank flag of the PPU is set at tick 1 (the second tick) of scanline 241
@@ -96,8 +99,19 @@ impl Ppu {
9699
}
97100

98101
pub fn write_to_ctrl(&mut self, data: u8) {
99-
// TODO: bugzmanov book sets ctrl.bits directly vs recreating .. I hit an error attempting that
100-
self.registers.control = ControlRegister::from_bits_truncate(data);
102+
let before = &self.registers.control;
103+
let after = ControlRegister::from_bits_truncate(data);
104+
105+
// should we toggle an NMI interrupt?
106+
let is_vblank_state = self.registers.status.contains(StatusRegister::VBLANK_FLAG);
107+
let enabled_vblank_nmi = after.contains(ControlRegister::VBLANK_NMI_ENABLE)
108+
&& !before.contains(ControlRegister::VBLANK_NMI_ENABLE);
109+
if is_vblank_state && enabled_vblank_nmi {
110+
self.nmi_interrupt = true;
111+
}
112+
113+
// update the register's value
114+
self.registers.control = after;
101115
}
102116

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

0 commit comments

Comments
 (0)