319. Clear sprite zero hit pre render

Clear sprite 0 hit at the simplified pre-render boundary.

Lesson 319 of 356 · tests/chapter_11_sprite_zero_hit/test_319_clear_sprite_zero_hit_pre_render.py

File to update

emulator/ppu/ppu.py

Why this step exists

Sprite 0 hit is PPUSTATUS bit 6. Games can use it as a timing signal by waiting for the flag to transition through this lifecycle:

visible frame overlap -> sprite 0 hit becomes set
pre-render boundary   -> sprite 0 hit becomes clear
next visible frame    -> sprite 0 hit may become set again

Before implementing overlap detection or setting the flag, this step establishes the clear/reset invariant. Without this reset, a future sprite 0 hit could remain set forever and break games that wait for the flag to clear before waiting for the next hit.

Current timing model

The project currently advances timing at scanline transitions. Therefore this step clears the flag when scanline 261 begins. Exact hardware dot timing is a future accuracy refinement.

Example implementation fragment

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

    # --- NEW BLOCK: CLEAR SPRITE 0 HIT FOR THE NEXT FRAME ---
    self.status &= ~SPRITE_ZERO_HIT
    # --- END NEW BLOCK ---

Important invariant

Reading PPUSTATUS clears VBlank bit 7, but it must not clear sprite 0 hit bit 6. Only the pre-render lifecycle event clears sprite 0 hit in the current model.

Current manual ROM policy

Continue using MarioBros.nes for current manual checks. Super Mario Bros. validation is deferred until overlap detection and timed hit-setting are implemented.

Out of scope

  • detecting sprite 0/background overlap
  • setting sprite 0 hit
  • fixed/fake scanline hits
  • sprite overflow
  • Console changes
  • rendering changes
  • Super Mario Bros. validation

Run this lesson

uv run pytest tests/chapter_11_sprite_zero_hit/test_319_clear_sprite_zero_hit_pre_render.py -v