332. 将 PPU 逻辑名称表渲染为帧缓冲区
将一个所选的逻辑 PPU 名称表渲染为帧缓冲区。
第 332 / 356 · tests/chapter_13_scrolling/test_332_ppu_logical_nametable_to_framebuffer.py
待更新文件
emulator/rendering/ppu_background_renderer.py参考
https://www.nesdev.org/wiki/PPU_nametables此步骤存在的原因
原始辅助函数总是渲染逻辑名称表 $2000。水平滚动还需要相邻的逻辑名称表,因此该辅助函数现在接受以下之一:
$2000, $2400, $2800, $2C00相对于所选基址的内存布局
base + $000-$3BF: 960 visible tile IDs
base + $3C0-$3FF: 64 attribute bytes兼容性
省略 base_nametable_addr 时仍必须渲染 $2000。因此现有调用方无需修改。
镜像边界
渲染通过 PpuBus 请求逻辑地址。PpuBus 仍然负责将这些地址映射到水平或垂直镜像的物理 VRAM。
范围之外
- 选择并组合两个相邻的帧缓冲区
- 不透明度掩码地址选择
- 与 Console 集成
- 垂直视口组合
- pygame
示例实现
# emulator/rendering/ppu_background_renderer.py
# --- NEW LINES: ACCEPTED LOGICAL NAMETABLE BASE ADDRESSES ---
LOGICAL_NAMETABLE_BASE_ADDRS = (
0x2000,
0x2400,
0x2800,
0x2C00,
)
def ppu_background_to_framebuffer(
ppu: PPU,
# --- NEW LINE: OPTIONAL LOGICAL NAMETABLE SELECTION ---
base_nametable_addr: int = BASE_NAMETABLE_ADDR,
) -> Framebuffer:
# --- NEW BLOCK: REJECT NON-NAMETABLE BASE ADDRESSES ---
if base_nametable_addr not in LOGICAL_NAMETABLE_BASE_ADDRS:
raise ValueError(
"Logical nametable base address must be $2000, $2400, $2800, $2C00"
)
nametable_bytes = bytes(
# --- UPDATED LINE: READ FROM THE SELECTED NAMETABLE ---
ppu.ppu_bus.read(base_nametable_addr + offset)
for offset in range(NAMETABLE_SIZE)
)
# --- NEW LINE: DERIVE THE SELECTED ATTRIBUTE-TABLE BASE ---
attribute_table_base = base_nametable_addr + NAMETABLE_SIZE
attribute_table = bytes(
# --- UPDATED LINE: READ THE SELECTED ATTRIBUTE TABLE ---
ppu.ppu_bus.read(attribute_table_base + offset)
for offset in range(ATTR_TABLE_SIZE)
)
...
# Everything remains the same below this point
运行本课
uv run pytest tests/chapter_13_scrolling/test_332_ppu_logical_nametable_to_framebuffer.py -v