265. La consola consume la solicitud NMI de la PPU
Modelar Console como el coordinador que consume las solicitudes NMI de la PPU.
Lección 265 de 356 · tests/chapter_04_ppu_timing_and_vblank/test_265_console_consumes_ppu_nmi_request.py
Referencias
https://www.nesdev.org/wiki/CPU_interrupts
https://www.nesdev.org/wiki/PPU_registers#Vblank_NMIArchivo a crear
emulator/console.pyPor qué existe este paso
El emulador ahora tiene los dos mecanismos separados necesarios para el NMI de VBlank
PPU mechanism:
PPU enters VBlank and sets ppu.nmi_requested = True
CPU mechanism:
CPU.interrupt_nmi() pushes PC/status and jumps through $FFFA/$FFFBAhora necesitamos un pequeño coordinador que conecte esos mecanismos sin hacer que la CPU y la PPU dependan directamente entre sí.
¿Qué es Console? Console es la futura máquina NES emulada de nivel superior. Con el tiempo puede poseer y coordinar subsistemas como:
CPU
PPU
cartridge/mapper
controllers
APU/audio
frame steppingEn esta etapa, Console comienza siendo muy pequeño. Su primer trabajo es solo consumir una solicitud NMI de la PPU y llamar a CPU.interrupt_nmi().
Separación correcta de responsabilidades
PPU:
produces nmi_requested
CPU:
implements interrupt_nmi()
Console:
connects the PPU signal to the CPU mechanismRegla de arquitectura importante
No pongas la propiedad de la PPU dentro de la CPU. La CPU no debería preguntar a la PPU si hay una NMI pendiente. Eso crearía un acoplamiento oculto entre la ejecución de la CPU y el hardware de vídeo.
Ejemplo de implementación mínimo
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()Forma futura, introducida en un paso de temporización posterior
class Console:
...
def step(self) -> None:
cpu_cycles = self.cpu.step()
self.ppu.step(cpu_cycles * 3)
self.consume_nmi_if_requested()Este archivo no prueba Console.step(). La integración de temporización CPU/PPU se prueba como un paso separado después de que CPU.step() devuelva ciclos de instrucción.
Concepto erróneo común
Dado que la PPU causa NMI, puede parecer natural que la CPU posea la PPU. Evita eso. La CPU recibe señales de interrupción; no debería poseer el dispositivo de vídeo.
Fuera de alcance
- Ratio de ciclos CPU/PPU
- Console.step()
- renderizado
- controladores
- APU/audio
- latencia exacta de NMI
Ejecutar esta lección
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_265_console_consumes_ppu_nmi_request.py -v