261. Ppu nmi request on vblank

Implement PPU-side NMI request on VBlank.

Lesson 261 of 356 · tests/chapter_04_ppu_timing_and_vblank/test_261_ppu_nmi_request_on_vblank.py

Reference

https://www.nesdev.org/wiki/PPU_registers#PPUCTRL
https://www.nesdev.org/wiki/PPU_registers#Vblank_NMI

File to update

emulator/ppu/ppu.py

State to add

nmi_requested: bool = False

Why this step exists

Many NES games do not poll PPUSTATUS in their main loop. Instead, they enable NMI in PPUCTRL bit 7 and expect the PPU to request an interrupt when VBlank starts.

For this step, only implement the PPU-side signal

if VBlank starts and PPUCTRL bit 7 is set:
    ppu.nmi_requested = True

The CPU does not consume the NMI yet. That is a later integration step.

Suggested implementation example

nmi_requested: bool = False
...
...

if self.scanline == PPU_VBLANK_START_SCANLINE:
    self.status |= VBLANK_STARTED

    if self.ctrl & CTRL_NMI_ENABLE:
        self.nmi_requested = True

Important concept

NMI request is an event produced when VBlank starts. It should not be produced continuously on every cycle of VBlank.

Out of scope

  • CPU interrupt handling
  • reading the NMI vector
  • pushing PC/status to the CPU stack
  • clearing nmi_requested by CPU/system integration
  • enabling NMI during an already-active VBlank
  • dot/cycle-accurate NMI timing

Run this lesson

uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_261_ppu_nmi_request_on_vblank.py -v