265. Console consumes ppu nmi request
Model Console as the coordinator that consumes PPU NMI requests.
Lesson 265 of 356 · tests/chapter_04_ppu_timing_and_vblank/test_265_console_consumes_ppu_nmi_request.py
References
https://www.nesdev.org/wiki/CPU_interrupts
https://www.nesdev.org/wiki/PPU_registers#Vblank_NMIFile to create
emulator/console.pyWhy this step exists
The emulator now has the two separate mechanisms needed for VBlank NMI
PPU mechanism:
PPU enters VBlank and sets ppu.nmi_requested = True
CPU mechanism:
CPU.interrupt_nmi() pushes PC/status and jumps through $FFFA/$FFFBNow we need a small coordinator that connects those mechanisms without making CPU and PPU depend directly on each other.
What is Console? Console is the future top-level emulated NES machine. Over time it can own and coordinate subsystems such as:
CPU
PPU
cartridge/mapper
controllers
APU/audio
frame steppingAt this stage, Console starts very small. Its first job is only to consume a PPU NMI request and call CPU.interrupt_nmi().
Correct responsibility split
PPU:
produces nmi_requested
CPU:
implements interrupt_nmi()
Console:
connects the PPU signal to the CPU mechanismImportant architecture rule
Do not put PPU ownership inside CPU. The CPU should not ask the PPU whether an NMI is pending. That would create hidden coupling between CPU execution and video hardware.
Minimal implementation example
from dataclasses import dataclass
from emulator.cpu.cpu import CPU
from emulator.ppu.ppu import PPU
@dataclass
class Console:
cpu: CPU
ppu: PPU
def consume_nmi_if_requested(self) -> None:
if not self.ppu.nmi_requested:
return
self.ppu.nmi_requested = False
self.cpu.interrupt_nmi()Future shape, introduced in a later timing test
class Console:
...
def step(self) -> None:
cpu_cycles = self.cpu.step()
self.ppu.step(cpu_cycles * 3)
self.consume_nmi_if_requested()This file does not test Console.step(). CPU/PPU timing integration is tested as a separate step after CPU.step() returns instruction cycles.
Common misconception
Because the PPU causes NMI, it may feel natural to make CPU own PPU. Avoid that. The CPU receives interrupt signals; it should not own the video device.
Out of scope
- CPU/PPU cycle ratio
- Console.step()
- rendering
- controllers
- APU/audio
- exact NMI latency
Run this lesson
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_265_console_consumes_ppu_nmi_request.py -v