NES TDD

245. Переключатель второй записи PPUSCROLL

Реализовать поведение двойной записи PPUSCROLL ($2005) для прокрутки.

Урок 245 из 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_245_ppuscroll_second_write_toggle.py

Реализовать поведение двойной записи PPUSCROLL ($2005) для прокрутки. !! Не торопитесь при реализации этого шага

Ссылки

https://www.nesdev.org/wiki/PPU_registers#PPUSCROLL
https://www.nesdev.org/wiki/PPU_scrolling#$2005_(PPUSCROLL)_first_write_(w_is_0)
https://www.nesdev.org/wiki/PPU_scrolling#$2005_(PPUSCROLL)_second_write_(w_is_1)

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

emulator/ppu/ppu.py

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

PPU.write_register(addr, value)

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

PPUSCROLL — это видимый для CPU регистр по адресу $2005. Как и PPUADDR ($2006), он использует общий переключатель первой/второй записи:

second_write_toggle == False -> first write
second_write_toggle == True  -> second write

Первая запись настраивает горизонтальную прокрутку

value bits 7-3 -> coarse X, stored in temp_vram_addr bits 0-4
value bits 2-0 -> fine X, stored in fine_x

Вторая запись настраивает вертикальную прокрутку

value bits 7-3 -> coarse Y, stored in temp_vram_addr bits 5-9
value bits 2-0 -> fine Y, stored in temp_vram_addr bits 12-14

Важная модель внутреннего регистра

vram_addr           -> v, current VRAM address
temp_vram_addr      -> t, temporary VRAM address
fine_x              -> x, fine horizontal scroll
second_write_toggle -> w, first/second write toggle

Предлагаемый псевдокод реализации, соответствующий стилю явного перемещения битов:

case 0x2005:
    # Keep for old compatibility.
    self.scroll = value

    if not self.second_write_toggle:
        # Reference:
        # https://www.nesdev.org/wiki/PPU_scrolling#$2005_(PPUSCROLL)_first_write_(w_is_0)
        #
        # PPU Scroll first write.
        # Incoming value bits are named ABCDEFGH.
        #
        # fine_x register:
        #     x: FGH <- value: .....FGH
        #
        # In other words, save the last 3 bits as fine horizontal scroll.
        self.fine_x = value & 0b0000_0111

        # temp_vram_addr register:
        #     t: ....... ...ABCDE <- value: ABCDE...
        #
        # In other words, save the upper 5 bits as coarse X in bits 0-4.
        # The mask keeps every temp_vram_addr bit except coarse X.
        self.temp_vram_addr = (
            (self.temp_vram_addr & 0b1111_1111_1110_0000)
            | (value >> 3)
        )

        # w <- 1
        # Next $2005/$2006 write will be treated as the second write.
        self.second_write_toggle = True
    else:
        # Reference:
        # https://www.nesdev.org/wiki/PPU_scrolling#$2005_(PPUSCROLL)_second_write_(w_is_1)
        #
        # PPU Scroll second write.
        # Incoming value bits are named ABCDEFGH.
        #
        # temp_vram_addr register:
        #     t: FGH..AB CDE..... <- value: ABCDEFGH
        #
        # Step 1: keep only untouched bits:
        #     - bit 15
        #     - nametable bits 10-11
        #     - coarse X bits 0-4
        #
        # This clears the vertical scroll destination bits:
        #     - coarse Y bits 5-9
        #     - fine Y bits 12-14
        self.temp_vram_addr = (
            self.temp_vram_addr & 0b1000_1100_0001_1111
        )

        # Step 2: put the last 3 bits into fine Y.
        #     value: .....FGH
        #     FGH << 12 -> bits 12-14
        self.temp_vram_addr = (
            self.temp_vram_addr | ((value & 0b0000_0111) << 12)
        )

        # Step 3: put the upper 5 bits into coarse Y.
        #     value: ABCDE...
        #     (value & 11111000) << 2 -> bits 5-9
        self.temp_vram_addr = (
            self.temp_vram_addr | ((value & 0b1111_1000) << 2)
        )

        # w <- 0
        # The two-write PPUSCROLL sequence is complete.
        self.second_write_toggle = False

Вне рамок

  • копирование битов прокрутки из temp_vram_addr в vram_addr во время рендеринга
  • тайминг строк развёртки/циклов
  • фактический рендеринг фона

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

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