288. Заглушка регистров APU/аудио
Добавить явное поведение-заглушку для регистров APU/аудио на CpuBus.
Урок 288 из 356 · tests/chapter_06_rom_startup_preparation/test_288_apu_audio_register_noop.py
Файл для обновления
emulator/bus/cpu_bus.pyЗачем нужен этот шаг
Реальные ROM для NES часто обращаются к регистрам APU/аудио при запуске. Аудио выходит за рамки текущего курса, но аварийное завершение при каждом обращении к регистру аудио приводит к тому, что ручные эксперименты с ROM останавливаются раньше, чем можно понаблюдать за поведением CPU/PPU/контроллера.
На этом шаге вводится намеренная заглушка
recognized address + documented out-of-scope behaviorа не полноценная имитация железа.
Что такое APU? APU, или Audio Processing Unit, — это блок железа NES, отвечающий за генерацию звука. CPU управляет им через регистры, отображённые на память.
Минимальный пример
CPU writes $4000
real NES: configure pulse channel audio
this tutorial for now: accept the write and produce no soundРаспространённое заблуждение
"If the emulator accepts APU writes, APU is implemented."Нет. На этом шаге APU/аудио явно признаётся вне рамок курса. Эмулятор лишь избегает аварийного завершения по этим адресам.
Пример предлагаемой реализации
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
...Почему именно эти адреса
$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.Важные исключения
$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.Вне рамок этого шага
- фактическая генерация звука
- таймеры/огибающие/свип/счётчики длины APU
- тайминг IRQ/frame-counter
- OAMDMA $4014
- контроллер $4016
- чтение порта контроллера 2 / расширения по адресу $4017
- общая обработка всех неподдерживаемых адресов ввода-вывода
Запустить этот урок
uv run pytest tests/chapter_06_rom_startup_preparation/test_288_apu_audio_register_noop.py -v