344. 递减水平 vram 地址
在一份复制的地址上逆转一次水平背景获取递增。
第 344 / 356 · tests/chapter_13_scrolling/test_344_decrement_horizontal_vram_addr.py
要更新的文件
emulator/ppu/ppu.py参考资料
https://www.nesdev.org/wiki/PPU_scrolling#Details为什么需要这一步
点 321-336 会为下一条扫描线预取前两个背景图块。每次图块获取都会推进水平 v,因此在点 1,该地址已经比背景移位寄存器中存储的像素超前了两个图块列:
intended visible coarse X = 5
prefetch tile 5 -> v advances to 6
prefetch tile 6 -> v advances to 7
dot 1:
shifters begin displaying tile 5
v already contains coarse X 7稍后的扫描线记录会复制 v 并将该副本回退两次
7 -> 6 -> 5该辅助函数逆转一次递增。它不是定时的 PPU 操作,而且绝不能让真实的 PPU.vram_addr 向后移动。
正常行为
coarse X 31 -> 30
coarse X 7 -> 6
coarse X 1 -> 0边界行为
coarse X 0 -> 31 and toggle horizontal nametable重要不变量
- 只有粗X以及回绕时的水平命名表可能改变
- 所有垂直字段和无关字段都保持不变
- 递减是已测试的水平递增的逆操作
- 该函数是纯函数,不会修改 PPU
常见误解
NES PPU 不会在渲染期间执行这种递减。它存在的唯一目的,是为现有的高层渲染器把超前于显示的获取地址换算成可见的视口地址。
超出范围
- 从 PPU.step() 调用该辅助函数
- 记录 240 个扫描线位置
- 帧缓冲或不透明度掩码的变更
完整示例实现
# emulator/ppu/ppu.py
# --- NEW BLOCK: REVERSE ONE HORIZONTAL FETCH INCREMENT ---
def decrement_horizontal_vram_addr(vram_addr: int) -> int:
coarse_x = vram_addr & 0b1_1111
if coarse_x == 0:
vram_addr = (
(vram_addr & ~0b1_1111)
| 0b1_1111
)
vram_addr ^= 0b000_01_00000_00000
return vram_addr
return vram_addr - 1运行本课
uv run pytest tests/chapter_13_scrolling/test_344_decrement_horizontal_vram_addr.py -v