NES TDD

233. Устройство памяти VRAM

Создать простое устройство памяти VRAM.

Урок 233 из 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_233_vram_memory_device.py

Файл для создания

emulator/memory/vram.py

Класс для реализации

VRAM

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

У PPU собственное адресное пространство, отдельное от адресного пространства CPU. RAM CPU — не то место, где обычно живёт состояние фоновой/спрайтовой графики. PPU нужна ориентированная на видео память, к которой он может обращаться через PPUADDR/PPUDATA и, позже, через логику рендеринга.

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

CPU address space: $0000-$FFFF
    handled by CpuBus

PPU address space: $0000-$3FFF
    will be handled by PpuBus

Для этого раннего шага VRAM — простое перезаписываемое хранилище для адресного пространства со стороны PPU. Позже PpuBus решит, как PPU-адреса отображаются в CHR ROM, VRAM таблиц имён, RAM палитры и зеркала.

Почему VRAM отделена от регистров PPU

Регистры PPU, такие как $2006 и $2007, — это видимые для CPU порты управления/данных. Они не являются самой памятью.

Пример потока данных в будущем

CPU writes $20 to $2006
CPU writes $00 to $2006
CPU writes $AA to $2007

Значение

PPU internal address becomes $2000
PPUDATA writes $AA into PPU-side memory at $2000

CPU обращается к регистру $2007, но фактический адрес видеопамяти — это внутренний адрес PPU, а не CPU-адрес $2007.

Текущая область действия

  • VRAM — это MemoryDevice
  • VRAM хранит 0x4000 байт
  • VRAM.read(addr) возвращает сохранённый байт по адресу addr
  • VRAM.write(addr, value) сохраняет только младший байт значения value

Важное разделение ответственности

VRAM не должна применять addr & 0x3FFF. Нормализация/маршрутизация адресов — задача PpuBus, потому что карта адресов PPU принадлежит PpuBus. VRAM — только хранилище.

Предлагаемый псевдокод реализации

from dataclasses import dataclass, field
from emulator.memory.memory_device import MemoryDevice

VRAM_SIZE = 0x4000


@dataclass
class VRAM(MemoryDevice):
    _data: bytearray = field(
        default_factory=lambda: bytearray(VRAM_SIZE),
        init=False,
    )

    def write(self, addr: int, value: int) -> None:
        self._data[addr] = value & 0xFF

    def read(self, addr: int) -> int:
        return self._data[addr]

Вне области действия

  • маршрутизация PpuBus
  • отображение CHR ROM
  • зеркалирование таблиц имён
  • палитра RAM
  • рендеринг

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

uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_233_vram_memory_device.py -v