A continuación dejo todos los componentes necesarios para entender como hacer reversing a esta parte.
OAM (Object Attribute Memory) – Selección de Paleta
La OAM tiene 544 bytes y define las propiedades de los sprites. Cada sprite en pantalla consume 4 bytes consecutivos:
- Byte 0: Posición X.
- Byte 1: Posición Y.
- Byte 2: Índice del Tile (Puntero a los gráficos en VRAM).
- Byte 3: Atributos del Sprite.
El Byte 3 se estructura a nivel de bits como vhoopppc. Los bits p p p (bits 1, 2 y 3) definen el número de paleta (0 a 7) asignada a ese sprite.
000= Paleta 0001= Paleta 1- (…)
111= Paleta 7
VRAM (Video RAM) – El Índice del Píxel
En VRAM residen los gráficos puros (Tiles). Los sprites estándar usan un formato de 4bpp (4 bits por píxel).
Al leer un Tile, cada píxel se forma apilando 4 bits, lo que permite un valor numérico local del 0 al 15 (0000 a 1111 en binario).
- Valor 0 (
0000): El hardware lo procesa como fondo (transparencia). - Valores 1 a 15 (
0001a1111): Tinta sólida (colores usables).
CGRAM (Color Generator RAM) y el límite de 15 bits
Es la memoria física (512 bytes) que contiene los colores.
- Base de Fondos: Direcciones
$000a$0FF. - Base de Sprites: Direcciones
$100a$1FF.
Las paletas se dividen en bloques de 32 bytes ($20 en hexadecimal). Cada paleta tiene 16 colores (16 * 2 = 32). El programador tiene total libertad para adaptar y sobreescribir esta paleta a su gusto, definiendo qué valores hexadecimales ocupan esos bytes.
El formato RGB555 y el almacenamiento en Memoria (Por qué es FF 7F y no FFFF):
Aunque la memoria dedica 16 bits (2 bytes) a cada color, el sistema solo utiliza 15 bits (5 Azul, 5 Verde, 5 Rojo). El bit 16 es ignorado por hardware y es fijado a 0.
- El valor máximo con los tres canales encendidos (Blanco puro) en binario es:
0111 1111 1111 1111. - En valor hexadecimal absoluto, eso es
$7FFF. - La SNES guarda los datos usando Little Endian (el byte de menor peso se escribe primero). Por lo tanto, el
$7FFFse divide e invierte en memoria guardándose comoFF 7F. Si intentas escribirFFFF, un emulador preciso corregirá el bit 16 automáticamente, devolviéndolo aFF 7F.
Ejemplo de una sub-paleta en Memoria (32 bytes a partir de $100):
100: 00 00 FF 7F 1F 00 E0 03 FF 7F 00 00 00 00 00 00
110: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
En este bloque adaptado por el programador, el Color 0 es 00 00 (transparente), el Color 1 es FF 7F (Blanco Puro), el Color 2 es 1F 00 (Rojo puro) y el Color 3 es E0 03 (Verde puro).
La Fórmula del Hardware (Direccionamiento Físico)
Cuando la PPU va a dibujar un píxel específico de un sprite en pantalla, ejecuta el siguiente cálculo matemático para saber qué bytes exactos leer en la CGRAM:
Dirección CGRAM = Memoria Base + (Paleta OAM * Tamaño Paleta) + (Píxel VRAM * Tamaño Color)
- Memoria Base:
$100(Inicio del bloque de sprites). - Tamaño Paleta:
$20(32 bytes). - Tamaño Color:
2(2 bytes por color).
La fórmula matemática final es:
Dirección = $100 + (Valor ppp * $20) + (Valor Píxel * 2)
Caso Práctico: El cálculo del color en $102
Si tenemos un sprite dibujando texto blanco y queremos saber por qué el emulador altera los valores ubicados específicamente en la dirección $102 y no en la $100, aplicamos el rastro de memoria:
A. Lectura de OAM:
El sprite del texto tiene los bits ppp del Byte 3 configurados en 000.
- Offset de paleta:
0 * $20 = $000.
B. Lectura de VRAM:
La PPU escanea la cuadrícula del Tile y llega al píxel que forma la “tinta” de la letra blanca. El programador dibujó esa letra usando el valor 1 (0001).
- Offset del píxel:
1 * 2 = $002.
C. Cálculo Final (PPU):
- Base:
$100 - Offset OAM:
+ $000 - Offset VRAM:
+ $002 - Dirección Resultante:
$102
La PPU lee los bytes $102 y $103, extrae los valores almacenados (FF 7F) y pinta el píxel blanco en pantalla respetando el límite de 15 bits.
¿Qué pasa con el fondo transparente del texto?
Cuando la PPU lee el píxel que actúa como fondo vacío de la letra en la VRAM, obtiene el valor 0 (0000).
- Base:
$100 - Offset OAM:
+ $000 - Offset VRAM:
0 * 2 = + $000 - Dirección Resultante:
$100
El hardware identifica que el valor del píxel en VRAM es 0. Por arquitectura de la SNES, se aborta la lectura de color para la dirección $100 y renderiza el píxel actual como transparente, dejando ver los gráficos de fondo (Backgrounds) que existan debajo del sprite.