221. Cpu bus cartridge integration part1
Добавление опциональной поддержки Cartridge в CpuBus, часть 1.
Урок 221 из 356 · tests/chapter_02_rom_loading/test_221_cpu_bus_cartridge_integration_part1.py
Предварительные условия
- Урок 217 предоставляет
Cartridge. - Уроки 218-219 предоставляют
Mapper000. - Урок 220 предоставляет
create_mapper.
Файл для обновления
emulator/bus/cpu_bus.pyСимволы для обновления
emulator.bus.cpu_bus.CpuBus.cartridge
emulator.bus.cpu_bus.CpuBus.__post_init__Необходимые импорты в этом файле
from emulator.cartridge.cartridge import Cartridge
from emulator.cartridge.mapper_factory import create_mapperЧто реализует эта часть
- CpuBus принимает опциональный картридж
- CpuBus создаёт mapper из этого картриджа в __post_init__
- CpuBus запрещает одновременное подключение program_rom и cartridge
Что эта часть пока НЕ реализует
- чтение CPU из PRG ROM картриджа
Это поведение чтения тестируется во второй части.
Почему этот шаг нужен
Добавление поддержки картриджа имеет две отдельные зоны ответственности
1. construction-time wiring
2. read-time routingРазделение этих зон облегчает изучение материала. Сначала студенты узнают, как шина получает картридж и превращает его в mapper. И только после этого они меняют путь чтения для $8000-$FFFF.
Архитектурная модель
Cartridge
stores PRG ROM, CHR ROM, and mapper number
create_mapper(cartridge)
chooses the correct mapper implementation
Mapper000
translates CPU PRG addresses into PRG ROM offsets
CpuBus
owns routing decisionsВажная граница
CpuBus не должен реализовывать правила зеркалирования Mapper000 напрямую. Он должен создавать или хранить mapper, а затем делегировать чтение PRG вызову mapper.read_prg(addr).
Ожидаемая форма реализации
@dataclass
class CpuBus:
program_rom: Optional[MemoryDevice] = None
cartridge: Optional[Cartridge] = None
ram: RAM = field(default_factory=RAM)
def __post_init__(self):
if self.program_rom is not None and self.cartridge is not None:
raise ValueError("Cannot attach both program_rom and cartridge")
self.mapper = None
if self.cartridge is not None:
self.mapper = create_mapper(self.cartridge)Инварианты
- program_rom remains the writable MemoryDevice seam used by CPU tests
- cartridge and program_rom are mutually exclusive PRG sources
- mapper is always initialized, to None without a cartridge and to the
factory result with one
- Cartridge PRG and CHR bytes reach the mapper unchanged through
create_mapper; CpuBus neither parses nor remaps those bytesРаспространённое заблуждение
Картридж сам по себе не является заменой MemoryDevice для program_rom. Это метаданные плюс полезные данные ROM; create_mapper(cartridge) предоставляет объект, учитывающий адреса, который будет использовать шина.
Вне рамок этого шага
1. Lesson 222 changes the $8000-$FFFF read path.
2. PPU register routing and PPU construction belong to Chapter 3.
3. Mapper writes, CHR/PPU bus routing, and later behavior are not added here.Запустить этот урок
uv run pytest tests/chapter_02_rom_loading/test_221_cpu_bus_cartridge_integration_part1.py -v