232. 读取 Ppu 状态会清除 vblank
读取 PPUSTATUS 会清除 VBlank 标志。
第 232 / 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_232_ppu_status_read_clears_vblank.py
要更新的文件
emulator/ppu/ppu.py要更新的方法
PPU.read_register(addr)为什么需要这一步
位于 $2002 的 PPUSTATUS 并非一个被动的值。在真实的 NES 硬件上,读取 PPUSTATUS 会返回当前状态字节,并清除 PPU 内部的 VBlank-started 标志。
重要行为
read_register($2002):
1. save the old status value
2. clear only VBLANK_STARTED, bit 7
3. return the old status value顺序很重要。
正确做法
value = self.status
self.status &= ~VBLANK_STARTED
return value错误做法
self.status &= ~VBLANK_STARTED
return self.status为什么是错误的
CPU 必须能够观察到 VBlank 已被置位。如果模拟器在返回之前就清除了第 7 位,CPU 的轮询循环将会错过 VBlank。
位级示例
status before read: 0b1110_0000
~VBLANK_STARTED: 0b0111_1111
status after AND: 0b0110_0000只有第 7 位会被清除。sprite 0 命中和精灵溢出标志保持不变。
建议实现的伪代码
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(...)不在本步范围内
- 根据 PPU 时序自动设置 VBlank
- NMI 的产生
- 扫描线/周期
- sprite 0 命中行为
- 精灵溢出行为
运行本课
uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_232_ppu_status_read_clears_vblank.py -v