288. No-op de registro de audio de la apu

Añadir un comportamiento explícito de no-op para los registros de APU/audio en CpuBus.

Lección 288 de 356 · tests/chapter_06_rom_startup_preparation/test_288_apu_audio_register_noop.py

Archivo a actualizar

emulator/bus/cpu_bus.py

Por qué existe este paso

Las ROMs reales del NES suelen acceder a los registros de APU/audio durante el arranque. El audio está fuera del alcance actual de este tutorial, pero fallar en cada acceso a un registro de audio hace que los experimentos manuales con ROMs se detengan antes de poder observar el comportamiento de CPU/PPU/mando.

Este paso enseña un no-op intencionado

recognized address + documented out-of-scope behavior

no una implementación amplia de hardware simulado.

¿Qué es la APU? La APU, o Unidad de Procesamiento de Audio, es el bloque de hardware del NES responsable de generar sonido. La CPU la controla mediante registros mapeados en memoria.

Ejemplo mínimo

CPU writes $4000
    real NES: configure pulse channel audio
    this tutorial for now: accept the write and produce no sound

Concepto erróneo común

"If the emulator accepts APU writes, APU is implemented."

No. En este paso, la APU/audio se reconoce explícitamente como fuera de alcance. El emulador solo evita fallar en esas direcciones.

Ejemplo de implementación sugerida

def read(self, addr: int) -> int:
    ...

    # APU/audio registers are intentionally out of scope.
    if 0x4000 <= addr <= 0x4013:
        return 0
    if addr == 0x4015:
        return 0

    # Controller port 2 / expansion input is also out of scope for now.
    # Returning 0 means "no controller-2 buttons pressed" in this simplified model.
    if addr == 0x4017:
        return 0

    ...

def write(self, addr: int, value: int) -> None:
    ...

    # APU/audio registers are intentionally out of scope.
    if 0x4000 <= addr <= 0x4013:
        return
    if addr == 0x4015:
        return

    # $4017 writes control the APU frame counter on the NES.
    # Audio/APU timing is intentionally out of scope, so this is a no-op.
    if addr == 0x4017:
        return

    ...

Por qué estas direcciones

$4000-$4013
    APU sound-channel registers

$4015
    APU status/control register

$4017
    Writes: APU frame counter register, intentionally no-op for now.
    Reads: controller port 2 / expansion input, intentionally returns 0 for now.

Exclusiones importantes

$4014 is OAMDMA, not audio.
    Writing $02 to $4014 should later copy CPU $0200-$02FF into PPU OAM.
    Do not swallow it as an APU no-op.

$4016 is controller port 1, not audio.
    It will be implemented intentionally in the controller chapter.
    Do not fake it by returning 0 here.

Fuera de alcance

  • generación de sonido real
  • temporizadores/envolventes/barrido/contadores de longitud de la APU
  • temporización de IRQ/contador de fotogramas
  • OAMDMA $4014
  • mando $4016
  • lecturas de entrada de expansión/puerto de mando 2 desde $4017
  • gestión genérica para todas las direcciones de E/S no soportadas

Ejecutar esta lección

uv run pytest tests/chapter_06_rom_startup_preparation/test_288_apu_audio_register_noop.py -v