259. Ppu timing counters
Implement basic PPU timing counters.
Lesson 259 of 356 · tests/chapter_04_ppu_timing_and_vblank/test_259_ppu_timing_counters.py
Reference
https://www.nesdev.org/wiki/PPU_rendering#Line-by-line_timingFile to update
emulator/ppu/ppu.pyConstants to add
PPU_CYCLES_PER_SCANLINE = 341
PPU_SCANLINES_PER_FRAME = 262State to add
cycle: int = 0
scanline: int = 0
frame: int = 0Method to add
PPU.step(cycles: int = 1) -> NoneWhy this step exists
The PPU is a time-based device. Later, VBlank, NMI, rendering, and frame pacing will depend on knowing where the PPU is inside the current frame.
For this step, only add counters
cycle -> position inside the current scanline
scanline -> current scanline inside the frame
frame -> completed frame countInitial timing model
341 PPU cycles per scanline
262 scanlines per frameSuggested implementation example
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 += 1Future compatibility
These tests intentionally check only counter behavior. They do not require exact VBlank/NMI side effects yet. Later steps may add side effects inside PPU.step(), but these counter invariants should remain true.
Out of scope
- VBlank generation
- NMI request
- rendering
- sprite 0 hit
- sprite overflow
- odd-frame cycle skip
Run this lesson
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_259_ppu_timing_counters.py -v