338. Инкремент горизонтальной составляющей vram addr

Инкрементировать горизонтальную составляющую текущего адреса отрисовки v.

Урок 338 из 356 · tests/chapter_13_scrolling/test_338_increment_horizontal_vram_addr.py

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

emulator/ppu/ppu.py

Справочные материалы

https://www.nesdev.org/wiki/PPU_scrolling#Coarse_X_increment
https://www.nesdev.org/wiki/PPU_scrolling#During_rendering

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

Во время выборки фона PPU продвигается за раз на один столбец тайлов шириной 8 пикселей. Текущий адрес отрисовки v хранит как столбец тайлов coarse X, так и выбор горизонтальной таблицы имён:

v: yyy NN YYYYY XXXXX
                   |
                   +-- coarse X, bits 0-4

horizontal nametable selection: bit 10

Нормальное поведение

coarse X 0  -> 1
coarse X 30 -> 31

Поведение на границе

coarse X 31, horizontal nametable 0
    -> coarse X 0, horizontal nametable 1

coarse X 31, horizontal nametable 1
    -> coarse X 0, horizontal nametable 0

Переключение на границе переводит отрисовку через стык между логическими таблицами имён слева и справа. Позже, при чтении этих логических адресов, PpuBus применяет зеркалирование картриджа.

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

  • меняться могут только coarse X и, при переполнении, горизонтальная таблица имён
  • coarse Y, fine Y и вертикальная таблица имён остаются неизменными
  • fine X — отдельная величина и не является аргументом этой операции
  • вспомогательная функция возвращает значение и не мутирует PPU

Распространённое заблуждение

Это не сдвиг на один пиксель. Это продвижение на один столбец тайлов, что соответствует 8 пикселям. Fine X задаёт отдельное смещение 0-7 пикселей внутри первого тайла.

Вне объёма работ

  • вызов вспомогательной функции из PPU.step()
  • выбор точек выборки фона
  • копирование горизонтальных битов t в v
  • вертикальные инкременты
  • отрисовка фреймбуфера

Полный пример реализации

# emulator/ppu/ppu.py

# --- NEW BLOCK: PURE HORIZONTAL v INCREMENT ---
def increment_horizontal_vram_addr(vram_addr: int) -> int:
    # Advance v by one background tile column.
    coarse_x = vram_addr & 0b1_1111

    if coarse_x == 31:
        vram_addr &= ~0b1_1111
        vram_addr ^= 0b100_0000_0000
        return vram_addr

    return vram_addr + 1

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

uv run pytest tests/chapter_13_scrolling/test_338_increment_horizontal_vram_addr.py -v