Los gráficos son generados mediante un chip propietario llamado el Picture Processing Unit (PPU). Este es uno de los chips que le da a la NES una identidad. Para decirlo de otra manera, cualquiera podría elegir una CPU 6502 de la tienda de hardware, así que ¿por qué es la NES diferente de, digamos, una Apple 2 o una Commodore 64? Bueno, lo que distingue a la NES de otras máquinas son los chips que rodean a la CPU: la PPU y la APU. Estos dan forma a las capacidades gráficas y de audio de la NES respectivamente.

El chip PPU europeo en la placa base de mi NES.
Dicho esto, el PPU renderiza gráficos 2D llamados sprites y fondos, emitiendo el resultado a la señal de video.
Organizando el contenido

Arquitectura de memoria de la PPU
Para renderizar algo en la pantalla, la PPU debe saber qué gráficos dibujar, dónde colocarlos en la pantalla; y cómo dibujarlos (es decir, qué paleta usar).
Para responder a estas preguntas, el PPU viene pre-programado con un mapa de memoria diferente que busca el siguiente tipo de datos:
- Los datos de gráficos se extraen del cartucho del juego, que contiene un chip dedicado llamado Character memory que almacena los dibujos 2D (llamados tiles) organizados en una estructura de datos llamada Pattern Table. La Character memory se materializa en forma de 'Memoria de Solo Lectura' (ROM) o 'Memoria de Acceso Aleatorio' (RAM) dependiendo de si el juego se distribuye con un conjunto inmutable de gráficos o si el procesador debe intervenir, respectivamente.
- El PPU direcciona hasta 8 KB de Character memory organizada en dos grupos de 4 KB cada uno.
- Los metadatos que le dicen al PPU 'dónde' y 'cómo' dibujar los gráficos se encuentran en otras áreas:
- Un separado 2 KB de SRAM se ajusta en la placa base, esta vez dedicada a datos gráficos. Nintendo llama a este espacio Video RAM (VRAM) y almacena dos estructuras de datos llamadas Nametables.
- El PPU incorpora 256 B de DRAM para almacenar la Object Attribute Memory (OAM).
- Por último, la PPU también alberga 4 B de memoria para definir paletas de colores.
No te preocupes por la nueva terminología, el significado de estas estructuras de datos se discute paso a paso en los siguientes párrafos.
Construyendo el frame
Al igual que sus contemporáneos, este chip está diseñado en relación a los monitores CRT. No hay un frame-buffer como tal: la PPU renderizará en sintonía con el haz del CRT, construyendo la imagen al vuelo.
El PPU dibuja frames con una dimensión fija de 256x240 píxeles . Por desgracia, debido a las discrepancias en los estándares de video analógico por todo el mundo, la imagen diferirá en apariencia dependiendo de la región del dispositivo (NTSC o PAL) desde la cual se muestra. En resumen, los televisores NTSC recortarán los bordes superior e inferior para acomodar el overscan (solo ~224 líneas de escaneo son visibles), por lo que estos bordes son considerados 'zonas peligrosas' por los desarrolladores cuando deciden dónde colocar elementos en el juego. Por otro lado, los televisores PAL no recortarán los bordes pero mostrarán barras negras adicionales para llenar la señal más alta (PAL usa 288 líneas de escaneo).
Detrás de las escenas, el frame que produce el PPU está compuesto por dos capas diferentes. Para demostrar cómo funciona, utilizaremos Super Mario Bros.:
Mosaicos

Dos Pattern Tables con múltiples tiles.

Un único mosaico.
Para comenzar, el PPU usa tiles como ingrediente básico para producir sprites y fondos.
La NES define los tiles como mapas básicos de 8x8 píxeles, estos se almacenan en la Character memory (residiendo en el cartucho del juego) y organizados en una gran estructura de datos llamada Pattern Table . Cada tile ocupa 16 B y una Pattern Table alberga 256 tiles . Dado que el PPU direcciona hasta 8 KB de Character memory, puede acceder a hasta dos Pattern Tables.
Dentro de un tile, cada uno de sus píxeles se codifica utilizando un valor de 2 bits, que referencia a uno de cuatro colores de una paleta. Los programadores pueden definir hasta ocho paletas (cuatro para el fondo y las demás para los sprites). Los colores referenciados en cada paleta apuntan a una 'paleta maestra' compuesta de 64 colores , que representa todos los colores que esta consola puede producir. Las paletas se componen de cuatro colores, aunque uno está reservado para transparente.
Para empezar a dibujar algo en la pantalla, los juegos llenan un conjunto de tablas con referencias a tiles en la Character memory. Cada tabla es responsable de una capa (sprite o fondo) del frame. Luego, el PPU lee esas tablas y compone las líneas de escaneo que serán proyectadas por el cañón de CRT.
Ahora explicaré cómo funciona cada capa/tabla y cómo difieren en términos de funcionalidad.
Capa de fondo

Mapa de fondo asignado con la zona seleccionada marcada.
La capa de fondo es un mapa de 512x480 píxeles que contiene tiles estáticos . Recordarás que el frame visible es mucho más pequeño, por lo que el juego decide qué parte de la capa se selecciona para mostrar. Los juegos pueden mover el área visible durante el gameplay, así es como se consigue el Efecto de desplazamiento (Scrolling effect).
Para ahorrar memoria, grupos de cuatro tiles se combinan en mapas de 16x16 píxeles llamados bloques, dentro de los cuales todos los tiles comparten una paleta de colores.
Las Nametables (almacenadas en VRAM) especifican qué tiles mostrar en la capa de fondo. La PPU busca cuatro 1024-byte Nametables, cada uno corresponde a un cuadrante de la capa. Sin embargo, solo hay 2 KB de VRAM disponibles! Como consecuencia, solo se pueden almacenar dos Nametables sin hardware adicional del cartucho. No obstante, las dos restantes aún deben direccionarse en algún lugar: la mayoría de los juegos simplemente apuntan las dos restantes donde están las primeras dos (esto se llama mirroring).
Aunque al principio esta arquitectura pueda parecer defectuosa, fue diseñada para mantener bajos los costes mientras ofrece expandibilidad sencilla: si los juegos necesitaban un fondo más amplio, se podía incluir VRAM extra en el cartucho.
Los últimos bytes de cada Nametable almacenan una tabla de 64 bytes llamada Attribute table, que especifica qué paleta de colores se asigna a cada bloque .
Capa de Sprites
Los sprites son tiles que pueden moverse por la pantalla. También pueden superponerse entre sí o aparecer detrás del fondo. El gráfico visible se decidirá según su valor de prioridad (es el mismo concepto que 'capas' en el software de diseño gráfico tradicional).
La tabla OAM especifica qué tiles serán utilizados como sprites . Además del índice de tiles, cada entrada contiene una posición (x,y) y varios atributos (paleta de color, una prioridad y flip flags). Esta tabla se almacena en una DRAM de 256 bytes en el chip de la PPU.
La tabla OAM puede ser rellenada por la CPU. Sin embargo, en la práctica, esto puede ser muy lento (con el riesgo de corromper el frame si no se realiza a tiempo), por lo que la PPU contiene un pequeño componente llamado Direct Memory Access o 'DMA' el cual puede ser programado (alterando los registros de la PPU) para recuperar la tabla desde WRAM. Con DMA está garantizado que la tabla será cargada cuando el próximo frame sea dibujado, ¡pero hay que tener en cuenta que la CPU será detenida durante la transferencia!
La PPU está limitado a ocho sprites por línea de escaneo y hasta 64 sprites por frame. El límite de líneas de exploración se puede superar gracias a una técnica llamada 'rotación del orden de OAM', donde el juego altera manualmente el orden de las entradas en OAM. Esto hace que la PPU renderice un conjunto de sprites diferente en cada frame, y la velocidad del haz del CRT engañará al usuario para que vea más sprites de los permitidos. Sin embargo, también parecerá que parpadean en la pantalla.
División del fondo

Capa de fondo renderizada resaltando las dos porciones con diferentes valores de desplazamiento definidos. Solo la segunda porción se desplaza cuando Mario se mueve.
Antes de continuar, hay algo que no te he contado aún. Si juegas a Super Mario Bros, notarás que cuando Mario se mueve, la escena se desplaza sin problemas. Sin embargo, también observarás que la parte superior (donde están las estadísticas) permanece estática ¡aunque ambas porciones son parte de la misma capa de fondo! Entonces, ¿qué está pasando aquí? Bueno, el juego está alterando los valores de desplazamiento a mitad del frame para mostrar el supramundo y las estadísticas (que residen en una porción fija del fondo) al mismo tiempo. La NES no proporciona esta característica de manera nativa, pero el juego deduce los tiempos observando el estado de la PPU (manifestado a través de su registro de estado ).
Para lograr esto, los juegos utilizan una técnica llamada Sprite 0 Hit. Super Mario Bros instruye a la PPU para que renderice un sprite ficticio detrás de la moneda, este resulta ser el primer sprite dibujado dentro del frame. Después de que la PPU lo haga, actualiza su registro de estado con un flag que indica que el primer sprite (también conocido como 'sprite 0') ha sido dibujado. Mientras tanto, el juego está constantemente verificando a mitad del frame si el estado del sprite 0 ha sido señalado (también conocido como 'golpeado'), si eso sucede, el juego procede a actualizar la propiedad de desplazamiento de la tabla de fondo para moverlo a donde está Mario.
En general, 'Sprite 0 Hit' es un procedimiento muy delicado, ya que es fácil descoordinar los tiempos (la bandera del sprite 0 no se borra después de sondearla, lo que lleva a positivos 'duplicados' ). Además, como esta rutina se repite indefinidamente, puede ser bastante costosa (en términos de ciclos de CPU) de ejecutar. Por otro lado, mapeadores más recientes asumieron esta función mediante el uso de interrupciones automáticas que se activan cada vez que se alcanza una línea de escaneo arbitraria (una técnica mucho más eficiente), lo que mejoró significativamente las capacidades visuales de Super Mario Bros 3, por ejemplo.
Resultado
Una vez finalizado el frame... ¡es hora de pasar al siguiente!
Sin embargo, la CPU no puede modificar ninguna tabla que esté siendo utilizada por la PPU, de lo contrario, pueden aparecer artefactos en la pantalla. Entonces, cuando se completan todas las líneas de escaneo, la PPU dispara la interrupción de Vertical Blank (V-Blank) en la CPU . Esto notifica al juego que puede comenzar a actualizar las tablas sin romper la imagen presentada. En ese momento el haz del CRT apunta debajo del área visible de la pantalla, dentro del overscan (o borde inferior).
Solo un puñado de registros de la PPU pueden actualizarse fuera de la ventana de V-Blank , lo que explica la capacidad de desplazar la capa de fondo a mitad del frame.
Secretos y Limitaciones
Si crees que habría sido preferible un sistema de frame-buffer con memoria asignada para almacenar el frame completo: los costos de la RAM eran muy altos y el objetivo de la consola era ser asequible. Ahora déjame mostrarte por qué este diseño resultó ser muy eficiente y flexible.
Multidesplazamiento

Super Mario Bros. 2. Configuración de Nametable para desplazamiento vertical (mirroring horizontal).

Super Mario Bros. 3. Mario puede correr y volar, así que la PPU necesita desplazarse diagonalmente. Observa que el borde derecho muestra la paleta de colores incorrecta, mientras que el borde izquierdo tiene una máscara aplicada.
Algunos juegos requieren que el personaje se mueva verticalmente, por lo que el nametable será configurado con Horizontal Mirroring. Otros juegos requieren que el personaje se mueva de izquierda a derecha, en este caso se utiliza el Vertical Mirroring.
Cualquiera de los dos tipos de mirroring permitirá que la PPU actualice los tiles de fondo sin que el usuario lo note: hay mucho espacio para desplazarse mientras se renderizan nuevos tiles a distancia.
Pero ¿qué ocurre si el personaje desea moverse en diagonal? La PPU puede moverse en cualquier dirección, pero sin VRAM extra, los bordes están forzados a compartir la misma paleta de colores (recuerda que los tiles se agrupan en bloques).
Por esta razón, algunos juegos como Super Mario Bros. 3 muestran gráficos anómalos en el borde derecho de la pantalla cuando Mario se mueve (el juego está configurado para desplazarse verticalmente) . Es posible que necesitaran minimizar el coste del hardware por cartucho (ya que este juego ya tiene un potente mapper instalado).
Como un interesante arreglo: la PPU permitía a los desarrolladores aplicar una máscara vertical sobre los tiles, ocultando efectivamente parte del área defectuosa.
Cambio de Tiles

Primeras líneas de exploración.

Últimas líneas de exploración.

Frame actual mostrado al usuario.
Otra especialidad de Super Mario Bros. 3 es la cantidad de gráficos que puede mostrar.
El juego muestra más tiles de fondo de los estrictamente permitidos. ¿Cómo lo hacía? Si sacamos capturas de pantallas en dos momentos diferentes mientras la imagen se está generando, podemos observar que la imagen visualizada está compuesta de dos composiciones diferentes.
Esta es otra de las hechicerías del mapeador MMC3, que no solo se utilizaba para acceder a espacio extra en la ROM de programa, sino que también ensanchaba el espacio de la Character ROM al conectar dos chips de Character memory diferentes. Al comprobar cuál parte de la pantalla está solicitando la PPU, el mapeador redirigirá a uno u otro chip, permitiendo así más mosaicos únicos en la pantalla de los que originalmente se soportaban .
Comportamiento curioso
A lo largo de mi investigación, me encontré con muchos artículos interesantes que explican el comportamiento inusual de la PPU, así que pensé en mencionar algunos aquí:
- A diferencia del VDP de la Master System, que genera colores RGB que luego se codifican en señales NTSC/PAL para la transmisión, la PPU de la NES lo hace todo a la vez . Por lo tanto, no hay una conexión uno a uno entre los colores de la paleta maestra de la PPU y el espacio de color RGB estándar (ampliamente adoptado por la tecnología actual). Esto deja cierto margen para la interpretación y, como consecuencia, varios emuladores mostrarán una paleta diferente.
- Las discrepancias entre paletas RGB son más evidentes con el kit de 'bricolaje' de Tim Worthington que agrega salida de señal RGB a la NES, ya que también implementa un interruptor que elige entre tres paletas predefinidas. .
- La paleta maestra contiene un color 'maldito' (
$0D) que podría estropear la señal de TV NTSC . Bueno, lo que sucede es que algunas televisiones confunden la señal para mostrar ese color con la señal de blanqueo, por lo que podría ocurrir un parpadeo. - El PPU depende de la DRAM para almacenar su OAM. Ahora bien, la DRAM necesita ser refrescada constantemente para evitar la pérdida de datos (a diferencia de la SRAM), y sucede que la PPU no refrescará la DRAM cuando no esté renderizando el frame . Esto se manifiesta durante el blanking vertical. Por esta razón, se desaconseja actualizar la OAM fuera del blanking vertical, ya que el período de no actualización durante el V-blank habrá corrompido parte de la tabla.
- La variante PPU para sistemas PAL no se ve afectada por esto, ya que se refresca durante V-Blank (que dura más en sistemas PAL).

