263. Enrutamiento de escritura PRG en el bus de la CPU
Enrutar escrituras en el espacio PRG de la CPU a través del mapper antes de las pruebas de NMI de la CPU.
Lección 263 de 356 · tests/chapter_04_ppu_timing_and_vblank/test_263_cpu_bus_prg_write_routing.py
Archivos a actualizar
emulator/cartridge/mapper_interface.py
emulator/cartridge/mapper000.py
emulator/bus/cpu_bus.pyPor qué existe este paso
La siguiente prueba de interrupción de la CPU necesitará colocar los bytes del vector NMI en
$FFFA = NMI vector low byte
$FFFB = NMI vector high byteEsas direcciones se encuentran dentro del área PRG de la CPU
$8000-$FFFFAntes de probar CPU.interrupt_nmi(), necesitamos que el comportamiento de escritura del bus de la CPU en ese rango sea explícito y seguro.
¿Qué es el enrutamiento de escritura PRG? El enrutamiento de escritura PRG significa que CpuBus no modifica directamente los bytes de la ROM del cartucho. En su lugar, las escrituras en $8000-$FFFF se reenvían al mapper del cartucho:
CpuBus.write($8000-$FFFF, value)
-> mapper.write_prg(addr, value)Ejemplo mínimo
CPU writes $8000 = $12
CpuBus calls mapper.write_prg($8000, $12)
Mapper000/NROM ignores it because it has no PRG write registers
Later mappers may treat the same write as a bank-switch commandConcepto erróneo común
Escribir en $8000 no significa que la CPU cambie bytes de la ROM. En cartuchos reales, las escrituras en este rango normalmente son ignoradas por placas simples o interpretadas como señales de control del mapper por placas más avanzadas.
Separación importante
Real cartridge path:
CpuBus.write($8000-$FFFF) -> mapper.write_prg(...)
Tutorial FakeROM path:
CpuBus.write($8000-$FFFF) -> FakeROM.write(addr - $8000, value)La ruta FakeROM es solo una conveniencia para la configuración de pruebas. Permite que las próximas pruebas de interrupciones instalen bytes de vector en $FFFA/$FFFB sin hacer que la PRG ROM real de Mapper000 sea escribible.
Ejemplos de implementación sugeridos
class MapperInterface(Protocol):
def read_prg(self, addr: int) -> int:
...
def write_prg(self, addr: int, value: int) -> None:
...
def read_chr(self, addr: int) -> int:
...
def write_chr(self, addr: int, value: int) -> None:
...
class Mapper000:
def write_prg(self, addr: int, value: int) -> None:
if not (PRG_ROM_START <= addr <= PRG_ROM_END):
raise ValueError(f"Address out of PRG ROM range: {addr:04X}")
# Mapper000/NROM has no writable PRG registers.
# Real hardware ignores writes to PRG ROM space, so we ignore them too.
return
class CpuBus:
def write(self, addr: int, value: int) -> None:
...
if 0x8000 <= addr <= 0xFFFF:
if self.mapper is not None:
self.mapper.write_prg(addr, value)
return
if self.program_rom is not None:
self.program_rom.write(addr - 0x8000, value)
return
raise ValueError(f"Unsupported CPU bus write: {addr:04X}")Fuera de alcance
- Comportamiento de CPU.interrupt_nmi()
- Consumo de la solicitud NMI de la PPU por la CPU
- Conmutación de bancos Mapper001/MMC
- Hacer que la PRG ROM real sea escribible
Ejecutar esta lección
uv run pytest tests/chapter_04_ppu_timing_and_vblank/test_263_cpu_bus_prg_write_routing.py -v