344. Decrementar la dirección horizontal de vram

Revertir un incremento de fetch de fondo horizontal sobre una dirección copiada.

Lección 344 de 356 · tests/chapter_13_scrolling/test_344_decrement_horizontal_vram_addr.py

Archivo a actualizar

emulator/ppu/ppu.py

Referencias

https://www.nesdev.org/wiki/PPU_scrolling#Details

Por qué existe este paso

Los dots 321-336 precargan los dos primeros tiles de fondo para el siguiente scanline. Cada fetch de tile avanza la v horizontal, así que en el dot 1 la dirección ya está dos columnas de tiles por delante de los píxeles almacenados en los registros de desplazamiento de fondo:

intended visible coarse X = 5
prefetch tile 5 -> v advances to 6
prefetch tile 6 -> v advances to 7

dot 1:
    shifters begin displaying tile 5
    v already contains coarse X 7

El registro de scanline posterior copiará v y rebobinará esa copia dos veces

7 -> 6 -> 5

Este auxiliar revierte un incremento. No es una operación de la PPU temporizada, y nunca debe mover hacia atrás el PPU.vram_addr real.

Comportamiento normal

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

Comportamiento en el límite

coarse X 0 -> 31 and toggle horizontal nametable

Invariantes importantes

  • solo pueden cambiar la X gruesa y, al desbordarse, la nametable horizontal
  • cualquier campo vertical o no relacionado permanece sin cambios
  • el decremento es el inverso del incremento horizontal probado
  • la función es pura y no modifica la PPU

Concepto erróneo común

La PPU de la NES no realiza este decremento durante el renderizado. Existe solo para traducir la dirección de fetch adelantada respecto a la visualización en una dirección de viewport visible para el renderizador de alto nivel existente.

Fuera de alcance

  • invocar el auxiliar desde PPU.step()
  • registrar 240 posiciones de scanline
  • cambios en el framebuffer o en la máscara de opacidad

Implementación de ejemplo completa

# emulator/ppu/ppu.py

# --- NEW BLOCK: REVERSE ONE HORIZONTAL FETCH INCREMENT ---
def decrement_horizontal_vram_addr(vram_addr: int) -> int:
    coarse_x = vram_addr & 0b1_1111

    if coarse_x == 0:
        vram_addr = (
            (vram_addr & ~0b1_1111)
            | 0b1_1111
        )
        vram_addr ^= 0b000_01_00000_00000
        return vram_addr

    return vram_addr - 1

Ejecutar esta lección

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