003. CPU 总线到 RAM

让 CPU RAM 地址经由 CpuBus 路由。

3 / 356 · tests/chapter_01_cpu/test_003_cpu_bus_to_ram.py

需要更新的文件

emulator/bus/cpu_bus.py

位置

class CpuBus

参考

https://www.nesdev.org/wiki/CPU_memory_map

此步骤存在的原因

CPU 使用 16 位地址空间,而内部 RAM 只有 0x800 个物理字节。地址 $0000-$1FFF 会将同一块 RAM 重复映射四次。

完整示例实现

from dataclasses import dataclass, field

from emulator.memory.ram import RAM


@dataclass
class CpuBus:
    ram: RAM = field(default_factory=RAM)

    def read(self, addr: int) -> int:
        if 0x0000 <= addr <= 0x1FFF:
            return self.ram.read(addr & 0x07FF)

        raise ValueError(f"Unsupported CPU bus read: {addr:04X}")

    def write(self, addr: int, value: int) -> None:
        if 0x0000 <= addr <= 0x1FFF:
            self.ram.write(addr & 0x07FF, value)
            return

        raise ValueError(f"Unsupported CPU bus write: {addr:04X}")

重要不变量

physical_ram_address = cpu_address & 0x07FF

最小示例

向 CPU 地址 $0800 写入 $42 会改变物理 RAM 中偏移 $0000 处的字节,因此读取 $0000、$0800、$1000 或 $1800 都会看到同一份存储。

常见误解

镜像并不会分配四份 RAM 数组。总线把四个 CPU 地址区间都转换到同一个 RAM 设备上。在这一步中,不受支持的地址会引发 ValueError,而 bytearray 本身会拒绝超出无符号 8 位范围的值。

范围之外

  • 程序 ROM 路由
  • PPU 和手柄寄存器
  • CPU 执行

运行本课

uv run pytest tests/chapter_01_cpu/test_003_cpu_bus_to_ram.py -v