232. Ppu status read clears vblank
Reading PPUSTATUS clears the VBlank flag.
Lesson 232 of 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_232_ppu_status_read_clears_vblank.py
File to update
emulator/ppu/ppu.pyMethod to update
PPU.read_register(addr)Why this step exists
PPUSTATUS at $2002 is not a passive value. On real NES hardware, reading PPUSTATUS returns the current status byte and clears the VBlank-started flag inside the PPU.
Important behavior
read_register($2002):
1. save the old status value
2. clear only VBLANK_STARTED, bit 7
3. return the old status valueThe order matters.
Correct
value = self.status
self.status &= ~VBLANK_STARTED
return valueIncorrect
self.status &= ~VBLANK_STARTED
return self.statusWhy incorrect
The CPU must be able to observe that VBlank was set. If the emulator clears bit 7 before returning, CPU polling loops will miss VBlank.
Bit-level example
status before read: 0b1110_0000
~VBLANK_STARTED: 0b0111_1111
status after AND: 0b0110_0000Only bit 7 clears. Sprite 0 hit and sprite overflow remain set.
Suggested implementation pseudocode
def read_register(self, addr: int) -> int:
match addr:
case 0x2002:
value = self.status
self.status &= ~VBLANK_STARTED
return value
case 0x2004:
return self.oam_data
case 0x2007:
return self.data
case _:
raise ValueError(...)Out of scope
- automatically setting VBlank from PPU timing
- NMI generation
- scanlines/cycles
- sprite 0 hit behavior
- sprite overflow behavior
Run this lesson
uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_232_ppu_status_read_clears_vblank.py -v