221. Integración de cartridge en CpuBus, parte 1

Añadir soporte opcional de Cartridge a CpuBus, parte 1.

Lección 221 de 356 · tests/chapter_02_rom_loading/test_221_cpu_bus_cartridge_integration_part1.py

Requisitos previos

  • La lección 217 proporciona Cartridge.
  • Las lecciones 218-219 proporcionan Mapper000.
  • La lección 220 proporciona create_mapper.

Archivo a actualizar

emulator/bus/cpu_bus.py

Símbolos a actualizar

emulator.bus.cpu_bus.CpuBus.cartridge
emulator.bus.cpu_bus.CpuBus.__post_init__

Importaciones necesarias en ese archivo

from emulator.cartridge.cartridge import Cartridge
from emulator.cartridge.mapper_factory import create_mapper

Qué implementa esta parte

  • CpuBus acepta un cartridge opcional
  • CpuBus crea un mapper a partir de ese cartridge en __post_init__
  • CpuBus rechaza adjuntar a la vez program_rom y cartridge

Qué NO implementa todavía esta parte

  • La CPU lee de la PRG ROM del cartridge

Ese comportamiento de lectura se prueba en la parte 2.

Por qué existe este paso

Añadir soporte de cartridge tiene dos responsabilidades separadas

1. construction-time wiring
2. read-time routing

Mantenerlas separadas facilita seguir el tutorial. Los estudiantes aprenden primero cómo el bus recibe un cartridge y lo convierte en un mapper. Solo después cambian la ruta de lectura para $8000-$FFFF.

Modelo de arquitectura

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

Límite importante

CpuBus no debería implementar directamente las reglas de mirroring de Mapper000. Debería crear o mantener un mapper, y después delegar las lecturas de PRG en mapper.read_prg(addr).

Forma de implementación esperada

@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)

Invariantes

- 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

Concepto erróneo habitual

El cartridge no es en sí mismo un reemplazo de MemoryDevice para program_rom. Es metadatos más las cargas útiles de ROM; create_mapper(cartridge) suministra el objeto consciente de direcciones que usará el bus.

Fuera del alcance de este paso

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.

Ejecutar esta lección

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