NES TDD

241. Чтение PPUSTATUS сбрасывает переключатель второй записи

Чтение PPUSTATUS ($2002) сбрасывает переключатель второй записи PPU.

Урок 241 из 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_241_ppustatus_read_resets_second_write_toggle.py

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

emulator/ppu/ppu.py

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

PPU.read_register(addr)

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

PPU NES имеет регистры с двойной записью, особенно

$2005 PPUSCROLL
$2006 PPUADDR

Эти регистры используют внутренний переключатель первой/второй записи. В этом курсе это состояние называется:

second_write_toggle

Значение

False -> the next two-write register access is the first write
True  -> the next two-write register access is the second write

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

Чтение $2002 сбрасывает этот переключатель обратно в False.

Почему

Игры обычно читают PPUSTATUS перед записью в PPUSCROLL или PPUADDR, чтобы гарантировать, что PPU снова ожидает первую запись.

Пример

write $23 to $2006
    second_write_toggle = True

read $2002
    second_write_toggle = False

write $20 to $2006
    treated as first write / high byte, not as low byte

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

def read_register(self, addr: int) -> int:
    match addr:
        case 0x2002:
            value = self.status
            self.status &= ~VBLANK_STARTED
            self.second_write_toggle = False
            return value

        case 0x2004:
            return self.oam_data

        case 0x2007:
            return self.data

        case _:
            raise ValueError(...)

Важный инвариант

Чтение $2002 должно возвращать старое значение статуса, а затем применять побочные эффекты.

Побочные эффекты, смоделированные на данный момент

  • сброс VBLANK_STARTED
  • сброс second_write_toggle

Побочные эффекты, которые пока не смоделированы

  • полное поведение защёлки прокрутки
  • тайминг/генерация VBlank
  • поведение NMI

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

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