218. Mapper000 NROM

创建

218 / 356 · tests/chapter_02_rom_loading/test_218_mapper000_nrom.py

创建 emulator/cartridge/mapper000.py::Mapper000.read_prg,用于 NROM 的 CPU 地址映射。

此步骤存在的原因

NROM-128 将一个 16 KiB 存储体镜像到 $8000-$FFFF;NROM-256 则直接映射 32 KiB。把这种转换保留在映射器中,可以避免 Cartridge 变成硬件行为的载体。它使用了第 217 课暴露出的 PRG 和 CHR 负载。

在此课程边界下的建议实现

from dataclasses import dataclass

PRG_ROM_START = 0x8000
PRG_ROM_END = 0xFFFF
NROM_128_SIZE = 16 * 1024
NROM_256_SIZE = 32 * 1024
CHR_ROM_SIZE = 8 * 1024


@dataclass(frozen=True)
class Mapper000:
    prg_rom: bytes
    chr_rom: bytes

    def read_prg(self, addr: int) -> int:
        if not (PRG_ROM_START <= addr <= PRG_ROM_END):
            raise ValueError(
                f"Address out of PRG ROM range: {addr:04X}"
            )
        if len(self.prg_rom) == NROM_128_SIZE:
            offset = (addr - PRG_ROM_START) % NROM_128_SIZE
        elif len(self.prg_rom) == NROM_256_SIZE:
            offset = addr - PRG_ROM_START
        else:
            raise ValueError(
                "Mapper000 supports only 16KB or 32KB PRG ROM"
            )
        return self.prg_rom[offset]

不变量:只接受 CPU 地址 $8000-$FFFF,且 PRG 必须恰好是 16 或 32 KiB;仅在 16 KiB 情形下做镜像;保持 PRG/CHR 构造函数参数顺序不变。一个常见错误是直接用 CPU 地址索引 prg_rom,或者把这种转换实现在 Cartridge 上。read_chr、PPU 路由、CHR RAM、写入、镜像方式以及存储体切换均不在此步骤范围内。

此步骤范围之外

1. Lesson 219 adds `read_chr` for the PPU-side CHR range.
2. Lesson 220 adds mapper selection.
3. PPU routing, CHR RAM, writes, mirroring, and bank switching come later.

运行本课

uv run pytest tests/chapter_02_rom_loading/test_218_mapper000_nrom.py -v