241. Ppustatus 读取会重置第二次写入开关
读取 PPUSTATUS ($2002) 会重置 PPU 的第二次写入开关。
第 241 / 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_241_ppustatus_read_resets_second_write_toggle.py
要更新的文件
emulator/ppu/ppu.py要更新的方法
PPU.read_register(addr)为什么需要这一步
NES PPU 有一些需要写入两次的寄存器,尤其是
$2005 PPUSCROLL
$2006 PPUADDR这些寄存器使用一个内部的第一次写入/第二次写入开关。在本教程中,该状态被命名为:
second_write_toggle含义
False -> the next two-write register access is the first write
True -> the next two-write register access is the second write重要的 PPUSTATUS 行为
读取 $2002 会将该开关重置回 False。
原因
游戏通常会在写入 PPUSCROLL 或 PPUADDR 之前先读取 PPUSTATUS,以确保 PPU 重新处于等待第一次写入的状态。
示例
write $23 to $2006
second_write_toggle = True
read $2002
second_write_toggle = False
write $20 to $2006
treated as first write / high byte, not as low byte建议的实现伪代码
def read_register(self, addr: int) -> int:
match addr:
case 0x2002:
value = self.status
self.status &= ~VBLANK_STARTED
self.second_write_toggle = False
return value
case 0x2004:
return self.oam_data
case 0x2007:
return self.data
case _:
raise ValueError(...)重要不变量
读取 $2002 应当先返回旧的状态值,然后再施加副作用。
当前已建模的副作用
- 清除 VBLANK_STARTED
- 重置 second_write_toggle
尚未建模的副作用
- 完整的滚动锁存行为
- 时序/VBlank 生成
- NMI 行为
运行本课
uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_241_ppustatus_read_resets_second_write_toggle.py -v