249. Буфер чтения PPUDATA
Реализовать буферизованное чтение PPUDATA ($2007).
Урок 249 из 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_249_ppudata_read_buffer.py
Ссылка
https://www.nesdev.org/wiki/PPU_registers#PPUDATAФайл для обновления
emulator/ppu/ppu.pyСостояние для добавления
ppu_data_buffer: int = 0Почему этот шаг важен
PPUDATA — это не обычный простой регистр. Это видимый для CPU порт в память PPU. Для большинства операций чтения памяти PPU NES возвращает старое значение внутреннего буфера чтения, а затем перезагружает этот буфер из текущего адреса памяти PPU.
Обычное поведение буферизованного чтения
read $2007:
value = ppu_data_buffer
ppu_data_buffer = ppu_bus.read(vram_addr)
vram_addr += increment
return valueЭто означает, что первое чтение обычно возвращает устаревшие/старые данные буфера, а второе чтение возвращает байт, загруженный первым чтением.
Пример
ppu_bus[$2000] = $AA
ppu_bus[$2001] = $BB
ppu_data_buffer = $00
vram_addr = $2000
read $2007 -> returns $00, buffer becomes $AA, vram_addr becomes $2001
read $2007 -> returns $AA, buffer becomes $BB, vram_addr becomes $2002Поле совместимости/отладки
В более старой модели курса поле data было простым значением PPUDATA. Сохраните self.data как поле совместимости/отладки, содержащее значение, возвращённое последним
чтением PPUDATA, но реальное поведение должно использовать
ppu_data_buffer
ppu_bus.read(vram_addr)Предлагаемый псевдокод реализации
@dataclass
class PPU:
...
data: int = 0 # Compatibility/debug: last PPUDATA value
ppu_data_buffer: int = 0
def read_register(self, addr: int) -> int:
match addr:
...
case 0x2007:
value = self.ppu_data_buffer
self.ppu_data_buffer = self.ppu_bus.read(self.vram_addr)
increment = 32 if self.ctrl & CTRL_VRAM_INCREMENT_BY_32 else 1
self.vram_addr = (self.vram_addr + increment) & 0x3FFF
# Preserve old compatibility/debug field.
self.data = value
return self.dataВажное замечание на будущее
Чтение палитры из диапазона $3F00-$3FFF является исключением на реальном оборудовании. Оно возвращает байт палитры немедленно вместо возврата отложенного значения буфера. Это исключение намеренно не реализовано в этом тесте.
Вне рамок
- исключение при чтении палитры
- точность палитровой RAM
- запись в PPUDATA, уже протестированная ранее
Запустить этот урок
uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_249_ppudata_read_buffer.py -v