263. CPU 总线 PRG 写入路由
在 CPU 的 NMI 测试之前,让 CPU 对 PRG 空间的写入经由映射器路由。
第 263 / 356 · tests/chapter_04_ppu_timing_and_vblank/test_263_cpu_bus_prg_write_routing.py
需要更新的文件
emulator/cartridge/mapper_interface.py
emulator/cartridge/mapper000.py
emulator/bus/cpu_bus.py此步骤存在的原因
接下来的 CPU 中断测试需要把 NMI 向量的字节放在
$FFFA = NMI vector low byte
$FFFB = NMI vector high byte这些地址位于 CPU 的 PRG 区域内
$8000-$FFFF在测试 CPU.interrupt_nmi() 之前,我们需要让 CPU 总线在这个地址范围内的写入行为变得明确且安全。
什么是 PRG 写入路由?PRG 写入路由是指 CpuBus 不会直接修改卡带 ROM 的字节。相反,$8000-$FFFF 范围内的写入会被转发给卡带的映射器:
CpuBus.write($8000-$FFFF, value)
-> mapper.write_prg(addr, value)最小示例
CPU writes $8000 = $12
CpuBus calls mapper.write_prg($8000, $12)
Mapper000/NROM ignores it because it has no PRG write registers
Later mappers may treat the same write as a bank-switch command常见误解
写入 $8000 并不意味着 CPU 改变了 ROM 的字节。在真实卡带上,这个范围内的写入通常会被简单板卡忽略,或者被更高级的板卡解释为映射器控制信号。
重要的职责划分
Real cartridge path:
CpuBus.write($8000-$FFFF) -> mapper.write_prg(...)
Tutorial FakeROM path:
CpuBus.write($8000-$FFFF) -> FakeROM.write(addr - $8000, value)FakeROM 路径只是一种测试搭建上的便利手段。它让接下来的中断测试可以在 $FFFA/$FFFB 处安装向量字节,而不必让真正的 Mapper000 PRG ROM 变成可写的。
建议的实现示例
class MapperInterface(Protocol):
def read_prg(self, addr: int) -> int:
...
def write_prg(self, addr: int, value: int) -> None:
...
def read_chr(self, addr: int) -> int:
...
def write_chr(self, addr: int, value: int) -> None:
...
class Mapper000:
def write_prg(self, addr: int, value: int) -> None:
if not (PRG_ROM_START <= addr <= PRG_ROM_END):
raise ValueError(f"Address out of PRG ROM range: {addr:04X}")
# Mapper000/NROM has no writable PRG registers.
# Real hardware ignores writes to PRG ROM space, so we ignore them too.
return
class CpuBus:
def write(self, addr: int, value: int) -> None:
...
if 0x8000 <= addr <= 0xFFFF:
if self.mapper is not None:
self.mapper.write_prg(addr, value)
return
if self.program_rom is not None:
self.program_rom.write(addr - 0x8000, value)
return
raise ValueError(f"Unsupported CPU bus write: {addr:04X}")不在本步骤范围内
- CPU.interrupt_nmi() 的行为
- 由 CPU 消费 PPU 发起的 NMI 请求
- Mapper001/MMC 的存储体切换
- 让真正的 PRG ROM 变为可写
运行本课
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_263_cpu_bus_prg_write_routing.py -v