260. Generación de VBlank de la PPU a partir de la temporización

Implementa la generación de VBlank a partir de la temporización de la PPU.

Lección 260 de 356 · tests/chapter_04_ppu_timing_and_vblank/test_260_ppu_vblank_generation_from_timing.py

Referencia

https://www.nesdev.org/wiki/PPU_rendering#Line-by-line_timing
https://www.nesdev.org/wiki/PPU_registers#PPUSTATUS

Archivo a modificar

emulator/ppu/ppu.py

Constantes a añadir

PPU_VBLANK_START_SCANLINE = 241
PPU_PRE_RENDER_SCANLINE = 261

Por qué existe este paso

Muchos programas de NES esperan a VBlank antes de escribir en la memoria de la PPU. Habitualmente sondean PPUSTATUS ($2002) hasta que el bit 7 se activa.

Comportamiento conceptual para este paso del tutorial

when the PPU enters scanline 241:
    set PPUSTATUS bit 7, VBLANK_STARTED

when the PPU enters scanline 261, the pre-render scanline:
    clear PPUSTATUS bit 7

Esto proporciona a las ROMs una señal básica de fotograma sin implementar todavía el renderizado completo.

Ejemplo de implementación sugerida

PPU_VBLANK_START_SCANLINE = 241
PPU_PRE_RENDER_SCANLINE = 261

def step(self, cycles: int = 1) -> None:
    for _ in range(cycles):
        self.cycle += 1

        if self.cycle >= PPU_CYCLES_PER_SCANLINE:
            self.cycle = 0
            self.scanline += 1

            if self.scanline >= PPU_SCANLINES_PER_FRAME:
                self.scanline = 0
                self.frame += 1

            # Simplified scanline-level timing event.
            if self.scanline == PPU_VBLANK_START_SCANLINE:
                self.status |= VBLANK_STARTED

            if self.scanline == PPU_PRE_RENDER_SCANLINE:
                self.status &= ~VBLANK_STARTED

Simplificación importante

Esto no es una temporización de la PPU exacta por dot. En el hardware real, los cambios de estado ocurren en dots/ciclos concretos de la PPU, habitualmente modelados en torno al dot/ciclo 1 de la línea de barrido correspondiente. Por ahora, este tutorial usa un comportamiento de entrada de línea de barrido porque el objetivo es enseñar el concepto de fotograma/VBlank antes de la precisión total por ciclo.

Fuera de los objetivos del tutorial por ahora

  • temporización de VBlank precisa por dot/ciclo
  • salto de ciclo en fotograma impar
  • renderizado de píxeles durante las líneas de barrido visibles
  • sprite 0 hit
  • desbordamiento de sprites
  • generación de NMI/gestión de interrupciones de la CPU

Ejecutar esta lección

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