248. Память OAM и OAMDATA
Реализовать память OAM и поведение OAMADDR/OAMDATA.
Урок 248 из 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_248_oam_memory_and_oamdata.py
Ссылки
https://www.nesdev.org/wiki/PPU_registers#OAMADDR
https://www.nesdev.org/wiki/PPU_registers#OAMDATA
https://www.nesdev.org/wiki/PPU_OAMФайл для обновления
emulator/ppu/ppu.pyСостояние для добавления
OAM_SIZE = 256
oam: bytearray = field(default_factory=lambda: bytearray(OAM_SIZE))Почему этот шаг важен
OAM означает Object Attribute Memory (память атрибутов объектов). Это внутренняя 256-байтовая память спрайтов PPU. PPU рендерит спрайты из OAM, а не напрямую из RAM CPU.
Раскладка спрайта
NES OAM stores 64 sprites.
Each sprite uses 4 bytes.
64 sprites * 4 bytes = 256 bytesБазовая раскладка байтов спрайта
byte 0: Y position
byte 1: tile index
byte 2: attributes
byte 3: X positionВидимые для CPU регистры
$2003 OAMADDR
selects which OAM byte is currently addressed
$2004 OAMDATA
reads/writes OAM at the current OAMADDRВажное поведение для этого шага
- запись в $2003 устанавливает oam_addr
- запись в $2004 сохраняет значение в oam[oam_addr]
- запись в $2004 увеличивает oam_addr с помощью & 0xFF
- чтение $2004 возвращает oam[oam_addr]
Почему OAM не является VRAM в PpuBus
PpuBus обрабатывает адресное пространство PPU, используемое PPUADDR/PPUDATA
$0000-$3FFFOAM — это отдельная внутренняя память спрайтов, доступ к которой осуществляется через OAMADDR/OAMDATA
$2003/$2004Предлагаемый псевдокод реализации
OAM_SIZE = 256
@dataclass
class PPU:
...
oam_addr: int = 0
oam_data: int = 0
oam: bytearray = field(default_factory=lambda: bytearray(OAM_SIZE))
def write_register(self, addr: int, value: int) -> None:
value = value & 0xFF
match addr:
...
case 0x2003:
self.oam_addr = value
case 0x2004:
# Preserve old compatibility/debug field.
self.oam_data = value
# Write to current OAM byte.
self.oam[self.oam_addr] = value
# OAMADDR increments after OAMDATA write.
self.oam_addr = (self.oam_addr + 1) & 0xFF
...
def read_register(self, addr: int) -> int:
match addr:
...
case 0x2004:
self.oam_data = self.oam[self.oam_addr]
return self.oam_dataВне рамок
- OAMDMA по адресу $4014
- оценка спрайтов
- рендеринг спрайтов
- поведение переполнения спрайтов
- поведение попадания спрайта 0
Запустить этот урок
uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_248_oam_memory_and_oamdata.py -v