« Arquitectura de la Nintendo Entertainment System (NES) (index)

Arquitectura de la Nintendo Entertainment System (NES)

Chapter 5: Gráficos


Tabla de contenidos

  1. Organizando el contenido
  2. Construyendo el frame
    1. Mosaicos
    2. Capa de fondo
    3. Capa de Sprites
    4. División del fondo
    5. Resultado
  3. Secretos y Limitaciones
    1. Multidesplazamiento
    2. Cambio de Tiles
    3. Comportamiento curioso

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.

Image
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

Image
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:

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

Image
Dos Pattern Tables con múltiples tiles.

Image
Un único mosaico.

Tiles encontrados en la Character ROM (a efectos de demostración se utiliza una paleta por defecto).

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

Image
Mapa de fondo asignado.

Image
Mapa de fondo asignado con la zona seleccionada marcada.

Mapa de fondo configurado con mirroring vertical, lo que permite un desplazamiento horizontal suave. Sin embargo, solo se puede usar una mitad.

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

Image
Capa de sprite renderizada.

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

Image
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

Image
¡Tachán!

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

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

Image
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

Image
Primeras líneas de exploración.

Image
Últimas líneas de exploración.

Image
Frame actual mostrado al usuario.

Frames hipotéticos renderizados con los tiles disponibles en líneas de exploración específicas.

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í:


Previous: 4. CPU

Next: 6. Audio


Rodrigo Copetti © 2026 RSS Feed

Ir a la edición moderna

Inicio · Escritos · Soporte · Acerca del autor · Acerca del sitio web