225. PPU 写寄存器

添加 PPU.write_register(addr, value)。

225 / 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_225_ppu_write_register.py

待更新文件

emulator/ppu/ppu.py

待实现方法

PPU.write_register(addr: int, value: int) -> None

该步骤存在的原因

CPU 通过内存映射 I/O 写入 PPU 寄存器。当 CPU 写入地址 $2000 时,它写入的不是 RAM,而是在更新 PPUCTRL 寄存器。

在这一步中,PPU.write_register 接收的是范围在 $2000-$2007 内的规范化 PPU 寄存器地址。CpuBus 针对 $2008-$3FFF 的镜像将在之后的步骤中实现。

在这个简化阶段可写的寄存器

$2000 -> ctrl
$2001 -> mask
$2003 -> oam_addr
$2004 -> oam_data / OAMDATA port
$2005 -> scroll
$2006 -> addr
$2007 -> data

注意 $2002 被有意排除在外。

$2002 不可写的原因:$2002 是 PPUSTATUS。从 CPU 一侧来看,它是只读的。测试在需要模拟某个状态值时,可以直接设置 ppu.status,但 write_register($2002, value) 应当失败。

单字节策略

PPU 寄存器是 8 位的。目前,写入操作只应保留数值的低字节。这意味着写入 0x123 会存储 0x23。

建议的实现伪代码

def write_register(self, addr: int, value: int) -> None:
    value = value & 0xFF

    match addr:
        case 0x2000:
            self.ctrl = value
        case 0x2001:
            self.mask = value
        case 0x2003:
            self.oam_addr = value
        case 0x2004:
            self.oam_data = value
        case 0x2005:
            self.scroll = value
        case 0x2006:
            self.addr = value
        case 0x2007:
            self.data = value
        case _:
            raise ValueError(...)

未来说明

之后,$2004/OAMDATA 会成为通往内部 OAM 精灵内存的一个端口。到那时,写入 $2004 也可能会使 oam_addr 递增。这个早期测试不应要求在一次 OAMDATA 写入之后 oam_addr 保持不变。

运行本课

uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_225_ppu_write_register.py -v