289. OAMDMA 4014

Реализовать OAMDMA по адресу CPU $4014.

Урок 289 из 356 · tests/chapter_06_rom_startup_preparation/test_289_oamdma_4014.py

Файл для обновления

emulator/bus/cpu_bus.py

Зачем нужен этот шаг

Реальные игры для NES обычно подготавливают байты спрайтов в памяти CPU, а затем запускают OAMDMA, чтобы скопировать эти байты в OAM PPU. Даже до появления рендеринга спрайтов этот механизм копирования важен, поскольку он позволяет коду запуска реальных ROM продолжать работу и предоставляет будущему рендереру спрайтов реальные данные OAM.

Что такое OAM? OAM означает Object Attribute Memory. Это 256-байтная память спрайтов PPU:

64 sprites * 4 bytes each = 256 bytes

Каждая запись спрайта имеет форму

byte 0: Y position
byte 1: tile index
byte 2: attributes
byte 3: X position

Что такое OAMDMA? OAMDMA — это механизм записи на шине CPU. Запись одного байта по адресу $4014 выбирает страницу памяти CPU и копирует все 256 байтов этой страницы в OAM PPU.

Минимальный пример

CPU writes $02 to $4014

Это означает

copy CPU $0200-$02FF -> PPU.oam[0x00-0xFF]

Пример предлагаемой реализации

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

    # OAMDMA: copy one CPU page into PPU OAM.
    if addr == 0x4014:
        page_start = (value & 0xFF) << 8

        for offset in range(256):
            self.ppu.oam[offset] = self.read(page_start + offset)

        return

    ...

Важная деталь

OAMDMA должен читать данные через CpuBus.read(), а не напрямую из «сырой» RAM. Источник — адресное пространство CPU. Большинство игр используют страницы вроде $0200-$02FF, но использование чтений через шину сохраняет корректность механизма и избавляет от будущих переработок.

Распространённое заблуждение

"OAMDMA means sprites are rendered."

Нет. На этом шаге байты только копируются в PPU.oam. Декодирование/рендеринг спрайтов появится позже.

Поведение при чтении

В рамках этого курса $4014 — это регистр, срабатывающий только на запись. CpuBus.read($4014) пока должен оставаться неподдерживаемым.

Вне рамок этого шага

  • рендеринг спрайтов
  • приоритет спрайтов
  • прозрачность спрайтов
  • sprite 0 hit
  • переполнение спрайтов
  • тайминг задержки DMA в 513/514 циклов CPU
  • контроллер $4016

Запустить этот урок

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