NES TDD

232. Чтение статуса PPU очищает vblank

Чтение PPUSTATUS очищает флаг VBlank.

Урок 232 из 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_232_ppu_status_read_clears_vblank.py

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

emulator/ppu/ppu.py

Метод для обновления

PPU.read_register(addr)

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

PPUSTATUS по адресу $2002 — не пассивное значение. На реальном оборудовании NES чтение PPUSTATUS возвращает текущий байт состояния и сбрасывает флаг начала VBlank внутри PPU.

Важное поведение

read_register($2002):
    1. save the old status value
    2. clear only VBLANK_STARTED, bit 7
    3. return the old status value

Порядок имеет значение.

Правильно

value = self.status
self.status &= ~VBLANK_STARTED
return value

Неправильно

self.status &= ~VBLANK_STARTED
return self.status

Почему это неправильно

CPU должен иметь возможность наблюдать, что VBlank установлен. Если эмулятор очищает бит 7 перед возвратом, циклы опроса CPU пропустят VBlank.

Побитовый пример

status before read:      0b1110_0000
~VBLANK_STARTED:         0b0111_1111
status after AND:        0b0110_0000

Очищается только бит 7. Попадание спрайта 0 и переполнение спрайтов остаются установленными.

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

def read_register(self, addr: int) -> int:
    match addr:
        case 0x2002:
            value = self.status
            self.status &= ~VBLANK_STARTED
            return value
        case 0x2004:
            return self.oam_data
        case 0x2007:
            return self.data
        case _:
            raise ValueError(...)

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

  • автоматическая установка VBlank из тайминга PPU
  • генерация NMI
  • сканлайны/циклы
  • поведение попадания спрайта 0
  • поведение переполнения спрайтов

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

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