240. Alternancia de segunda escritura de ppuaddr
Implementa el comportamiento de dirección de doble escritura de PPUADDR ($2006).
Lección 240 de 356 · tests/chapter_03_ppu_memory_and_graphics_data/test_240_ppuaddr_second_write_toggle.py
Referencia
https://www.nesdev.org/wiki/PPU_registers#PPUADDRArchivo a actualizar
emulator/ppu/ppu.pyEstado a añadir
vram_addr: int = 0
temp_vram_addr: int = 0
second_write_toggle: bool = FalsePor qué existe este paso
PPUADDR es el registro visible para la CPU en $2006. La CPU lo usa para establecer la dirección VRAM interna de la PPU. Esa dirección interna se usa más adelante mediante PPUDATA ($2007) para leer/escribir en la memoria de la PPU.
Idea importante
$2006 no es simplemente un registro de almacenamiento de un byte. Es un puerto de doble escritura.
La CPU escribe la dirección en dos partes
first write -> high byte
second write -> low byteEjemplo
write $20 to $2006
write $00 to $2006Resultado tras ambas escrituras
vram_addr == $2000Modelo importante del registro interno
La primera escritura a $2006 actualiza temp_vram_addr, no vram_addr. La segunda escritura a $2006 completa temp_vram_addr y lo copia en vram_addr.
Por qué second_write_toggle: la PPU debe recordar si la próxima escritura a $2006 es la primera o la segunda. En este tutorial, second_write_toggle significa:
False -> next $2006 write is the first write / high byte
True -> next $2006 write is the second write / low bytePor qué el byte alto se enmascara con 0x3F
El espacio de direcciones de la PPU es de 14 bits
$0000-$3FFFSolo los 6 bits inferiores del byte alto son útiles para este rango de direcciones. Por lo tanto, la primera escritura debería usar:
(value & 0x3F) << 8Pseudocódigo de implementación sugerido
@dataclass
class PPU:
...
addr: int = 0
vram_addr: int = 0
temp_vram_addr: int = 0
second_write_toggle: bool = False
def write_register(self, addr: int, value: int) -> None:
value = value & 0xFF
match addr:
...
case 0x2006:
# Keep old simple register-field behavior for test compatibility.
self.addr = value
if not self.second_write_toggle:
self.temp_vram_addr = (
(self.temp_vram_addr & 0x00FF)
| ((value & 0x3F) << 8)
)
self.second_write_toggle = True
else:
self.temp_vram_addr = (
(self.temp_vram_addr & 0x3F00)
| value
)
self.vram_addr = self.temp_vram_addr
self.second_write_toggle = False
...Fuera de alcance
- escritura de PPUDATA ($2007) a través de PpuBus
- reinicio del toggle de escritura por parte de PPUSTATUS ($2002)
- PPUSCROLL ($2005) usando este mismo toggle
- comportamiento de incremento en 32 de PPUCTRL
Ejecutar esta lección
uv run pytest tests/chapter_03_ppu_memory_and_graphics_data/test_240_ppuaddr_second_write_toggle.py -v