Arquitectura de la Nintendo 64

Un análisis práctico por Rodrigo Copetti

Traducido por Rodrigo Copetti

Esto es una traducción voluntaria del artículo original. Si encuentra algún error, por favor ayude a mejorarla. ¡Gracias!

Si utiliza herramientas de accesibilidad o algún navegador antiguo, cambie a la edición "clásica".




Imágenes de apoyo

Modelo

Image
La Nintendo 64.
Lanzada el 23/06/1996 en Japón, el 29/09/1996 en América y el 01/03/1997 en Europa

Motherboard

Image
Motherboard
Mostrando la revisión 'NUS-CPU-03'.
Las versiones posteriores redujeron el número de chips requeridos para codificar el audio y video.
El conector de 'Disk Drive' se encuentra en el otra cara
Image
Motherboard con partes importantes etiquetadas

Diagrama

Image
Diagrama de arquitectura

Una breve introducción

El objetivo de Nintendo era dar a los jugadores los mejores gráficos posibles, para llevar a cabo esta tarea, se asociaron con uno de los mayores expertos en gráficos de la industria para producir el chip definitivo.

El resultado fue una bonita consola para toda la familia… y un manual de instrucciones de 500 páginas para los desarrolladores.

No te preocupes, te prometo que este artículo no va a ser tan largo como el manual… ¡Disfrútalo!


CPU

Los orígenes del procesador principal de la Nintendo 64 comienzan con el MIPS R4000, la nueva CPU de vanguardia de MIPS. Lanzada en 1991, la novedad más aparente del R4000 fue la inclusión de capacidades de 64 bits, resultado de ampliar el tamaño de los buses, registros y unidades de cálculo para manipular los valores de 64 bits con eficiencia. Los desarrolladores, por otra parte, accedieron estas capacidades a través del nuevo set de instrucciones MIPS III. En general, el R4000 ha permitido que nuevas aplicaciones puedan manejar porciones de datos más grandes sin consumir ciclos adicionales.

Para su consola de próxima generación, Nintendo investigó la posibilidad de llevar hardware industrial a las consolas domésticas. A diferencia de Sony, que poseía una gran cantidad de componentes internos y solo necesitaba un proveedor de MIPS CPUs, Nintendo se asoció directamente con los propietarios de MIPS (y muchas estaciones de trabajo gráficas) para diseñar todo su ecosistema. Esa compañía era Silicon Graphics (SGI).

Dentro de la sede de SGI, el R4000 era un producto costoso (alrededor de $400 [1]), lo que lo hacía inviable para una consola de videojuegos. Sin embargo, Nintendo no quería abandonar sus funcionalidades más avanzadas, así que se decidieron por una variante de gama baja llamada R4300i, de la cual NEC fue capaz de proveerla como segunda fuente.

Al final, la CPU elegida de Nintendo y SGI fue la NEC VR4300 corriendo a 93.75 MHz [2]. Esta es una versión compatible con el código binario del MIPS R4300i que incluye [3]:

También se incluye en este paquete una Floating-point unit o ‘FPU’ (unidad de coma flotante) de 64 bits. La VR4300 la identifica como un co-procesador (CP1) aunque la unidad está instalada junto a la ALU (unidad aritmética) y solo se accede a ella a través de esa unidad, con lo que no hay co-procesamiento de por si. De todas maneras, la FPU contiene un banco de registros dedicado y acelerará las operaciones con números de coma flotante de 64 y 32 bits. Por último, esta unidad sigue el estándar IEEE754.

Simplificando el acceso a la memoria

La manera en la que la RAM está ensamblada sigue la arquitectura de memoria unificada (o ‘UMA’, del inglés ‘Unified-memory Architecture’) donde toda la RAM disponible se centraliza en un solo lugar y cualquier otro componente que requiera RAM accederá a esta ubicación compartida. El componente que arbitra su acceso es, en este caso, la GPU.

La razón por la cual se eligió este diseño es por el ahorro considerable en costes de producción, mientras que por otro lado, incrementa la contención de acceso si no se gestiona adecuadamente.

¿Sin controlador de DMA?

Debido a la arquitectura de memoria unificada, la CPU ya no tiene acceso directo a la RAM, por lo que la GPU también proporciona la funcionalidad DMA (‘Direct Memory Access’).

Diseño de la memoria

Aparte de la UMA, la estructura de la RAM es un poco complicada, así que trataré de explicarlo en términos simples. Aquí va…

El sistema contiene físicamente 4,5 MB de RAM, sin embargo, está conectado usando un bus de datos de 9 bits donde el 9º bit está reservado para la GPU (explico más en la sección ‘Gráficos’). Como consecuencia, cada componente excepto la GPU sólo encontrará hasta 4 MB.

Image
Organización de la memoria en este sistema. Asumo que la velocidad del CPU-RCP bus es la velocidad de reloj del RCP o la de la CPU, pero aún no he conseguido confirmarlo.

El tipo de memoria RAM instalada en la placa se llama Rambus DRAM (RDRAM) [4], este fue otro diseño que compitió con SDRAM para convertirse en el siguiente estándar. RDRAM está conectada en serie (donde las transferencias se hacen de un bit a la vez) mientras que SDRAM utiliza una conexión paralela (transfiere múltiples bits a la vez).

Latencia y velocidad

La latencia de la RDRAM es directamente proporcional al número de bancos instalados [5], por lo que en este caso, con la cantidad de RAM que tiene este sistema, la latencia resultante es importante (se ha informado que está alrededor de los 640 ns [6]). Esto se compensa con una alta velocidad de reloj de 250 MHz (~2.6 veces más rápida que la CPU) aplicada en los bancos de memoria. Nintendo afirmó que la RDRAM puede proporcionar una transferencia de datos de alta velocidad de 500 MB/s para leer o escribir datos consecutivos.

Además, Nintendo eligió los bancos de memoria uPD488170L de NEC para su placa base [7]. Estos chips utilizan una tecnología denominada ‘Rambus Signaling Logic’ que duplica la tasa de transferencia [8]. Esto puede explicar por qué algunas fuentes afirman que la tasa ‘efectiva’ de memoria es de 500 MHz.

Dejando espacio para mejoras

Curiosamente, la cantidad de RAM disponible en esta consola se puede ampliar instalando el accesorio Expansion Pak: Una caja pequeña de aspecto elegante que agrega otros 4,5 MB. Mientras que este accesorio permaneció opcional para algunos juegos (y la mayoría no hicieron uso de él), ciertos títulos como Donkey Kong 64 o The Legend of Zelda: Majora’s Mask fueron diseñados con la expansión como un requisito, y mostrarían una pantalla de error sin él.

Image
El Expansion Pak [9], un accesorio opcional vendido por separado (a veces incluido con el juego que lo requiere).
Image
El Jumper Pak [10]. En ausencia del Expansion Pak, este debe estar presente para terminar el bus RDRAM.

Curiosamente, el bus de RAM debe ser terminado, por lo que la consola siempre se vende con un terminador (llamado Jumper Pak) instalado en el lugar del Expansion Pak. Ahora, podría preguntarse, ¿qué pasaría si encendemos la consola sin ningún Pak instalado? Literalmente nada, ¡te quedas con una pantalla en blanco!

Gestión de memoria

El VR4300 incluye otro procesador llamado System Control Coprocessor (CP0) que contiene una Unidad de gestión de memoria (o MMU, del inglés) y un Translation Lookaside Buffer (TLB), el primero controla como la memoria es organizada y almacenada en el caché. El VR4300 puede acceder hasta 4 GB de direcciones de memoria de 32 bit, pero como ya hemos observado, no tenemos 4 GB de RAM en esta consola (incluso después de considerar la I/O mapeada en memoria). Por lo tanto, la MMU se hace cargo del direccionamiento de memoria y provee un útil mapeado de memoria donde la memoria física se espeja (mirror) varias veces. Como consecuencia, las ubicaciones de memoria se tratan como ‘direcciones virtuales’ (en vez de ’direcciones físicas). Además, el TLB permite a desarrolladores poder definir sus propios mapeado de memoria en algunos espejos sin (considerable) bajas de rendimiento.

Al principio, esto puede parecer innecesario, pero cada espejo (también llamado ‘segmento’) está conectado a diferentes circuitos (por ejemplo, el caché L1, memoria sin caché y el TLB), así los desarrolladores pueden optimizar su uso seleccionando el segmento más apropiado para la tarea.

Algunos segmentos están hechos para diferenciar ubicaciones ‘kernel’ de las ubicaciones ‘usuario’ por razones de seguridad. La N64 siempre opera en modo ‘kernel’. Asimismo, el segmento ‘kernel sin TLB almacenado en caché’ (llamado ‘KSEG0’) es el más común para juegos.

La MMU también puede funcionar en modo de 64 bits, donde las direcciones de memoria son de 40 bits. Esto significa que el espacio de direcciones virtual incluye 1 TB de direcciones… ¡Pero no creo que la Nintendo 64 se aproveche de esto!


Gráficos

Lo que se ve en la pantalla está producido por un inmenso chip diseñado por Silicon Graphics llamado Reality Co-Processor que corre a 62,5 MHz. Este paquete contiene un montón de circuitería así que no te preocupes si te resulta difícil de seguir, el sub-sistema de gráficos tiene una arquitectura muy compleja.

Este diseño se basa en la filosofía de que la GPU no debe ser una ‘simple’ rasterizadora como en el caso de la competencia. Por el contrario, debe ser capaz de acelerar los cálculos geometricos (aliviando la carga de la CPU) y para ello, es necesario más circuitería.

Arquitectura

Este chip está dividido en tres módulos principales, dos de los cuales se utilizan para el procesamiento de gráficos:

Reality Signal Processor

Image
Arquitectura del Reality Signal Processor (RSP).

También conocido como RSP, es simplemente otro paquete con una CPU compuesto por:

  • La Scalar Unit: Otra versión derivada y reducida del MIPS R4000. Esta vez, sólo implementa un subconjunto del set MIPS III, por lo que carece de muchas funciones de propósito general (por ejemplo, interrupciones y excepciones), la extensión de 64 bits, multiplicación y división.
  • La Vector Unit: Un co-procesador que realiza operaciones vectoriales con 32 registros de 128 bits. Cada registro está separado en ocho partes para operar ocho vectores de 16 bits a la vez (al igual que las instrucciones SIMD en las CPUs convencionales). Como puede ver, este componente hace el trabajo duro para la Scalar Unit.
  • El System Control: Otro co-procesador que cubre las funciones de DMA y controla su módulo vecino, el RDP (más sobre esto en breve).

Para operar este módulo, la CPU almacena en la RAM una serie de comandos llamados Display list junto con los datos que serán manipulados, luego el RSP lee dicha lista y aplica las operaciones requeridas sobre los datos. La funcionalidad disponible incluye transformaciones geométricas (como la proyección en perspectiva), clipping e iluminación.

Esto parece sencillo, pero ¿cómo realiza estas operaciones? Bueno, aquí está la parte interesante: A diferencia de su competencia (la PS1 y la Sega Saturn), el motor de la geometría no es fijo. En su lugar, el RSP contiene un poco de memoria (4 KB para instrucciones y 4 KB para datos) para almacenar microcode [11], un pequeño programa, con no más de 1000 instrucciones, que implementa la tubería de gráficos. En otras palabras, dirige a la Scalar Unit sobre como debe operar nuestros gráficos. La CPU envía microcode mientras el programa se encuentra en ejecución.

Nintendo proporcionó diferentes microcódigos para escoger [12] y, similar a los modos de fondo de la SNES, cada uno balancea los recursos de manera diferente.

Reality Display Processor

Image
Arquitectura del Reality Display Processor (RDP).

Una vez que el RSP termine de procesar los datos de nuestros polígonos, empezará a enviar comandos de rasterización al siguiente módulo, el RDP, para dibujar el frame. Estos comandos se envían por un bus dedicado llamado XBUS o por la RAM principal.

El RDP es otro procesador (esta vez con funcionalidad fija) que incluye múltiples motores utilizados para rasterizar vectores, mapear las texturas a nuestros polígonos, mezclar colores y componer el nuevo frame.

Este puede procesar triángulos o rectángulos como primitivos, el último es útil para dibujar sprites. La tubería de rasterización del RDP contiene los siguientes bloques:

  • Un Rasteriser: Convierte primitivos (hechos de vértices) a píxeles.
  • Una Texture Unit: Procesa texturas usando 4 KB de memoria dedicada (llamada ‘TMEM’) por lo que permite hasta ocho tiles para ser usadas para la textura. Puede realizar las siguientes operaciones sobre ellas:
    • Bilinear filtering: Mapea la textura 2D seleccionada sobre la figura 3D y la suaviza para evitar áreas pixeladas (causado por sobremuestreo).
      • Un filtro ‘completo’ requiere cuatro puntos para aplicar la interpolación, sin embargo, esta consola sólo utiliza tres (interpolación triangular) lo que produce algunas anomalías. Por lo tanto, ciertas texturas tendrán que ser ‘adaptadas’ de antemano.
    • Mip-Mapping: Selecciona automáticamente una versión reducida de la textura dependiendo de su nivel de detalle. Esto evita computar grandes texturas que se verían lejos de la cámara y con ello prevenir el ‘aliasing’ (causado por submuestreo).
      • Si se activa, la N64 mapea las texturas usando trilinear filtering en su lugar. Este nuevo algoritmo también interpolará entre mipmaps para suavizar los cambios repentinos en el nivel de detalle.
    • Perspective correction: Algoritmo escogido para mapear texturas en triángulos. A diferencia de otros algoritmos de mapeo inverso, este tiene en cuenta el valor de profundidad de cada primitiva, logrando mejores resultados.
  • Un Color Combiner: Mezcla e interpola múltiples capas de colores (por ejemplo, para aplicar shaders).
  • Un Blender: Mezcla píxeles sobre el actual frame-buffer para aplicar translucidez, anti-aliasing, niebla o dithering. También realiza z-buffering (más sobre esto en adelante).
  • Una Memory interface: Utilizada por los bloques anteriores para leer y enviar el frame-buffer procesado a la RAM y/o llenar el TMEM.

La RDP proporciona cuatro modos de operación, cada uno combina estos bloques de forma diferente para optimizar operaciones específicas.

Dado que este módulo requiere actualizar constantemente el frame-buffer, la RAM se maneja de forma diferente: ¿Te acuerdas del inusual ‘byte’ de 9 bits? El noveno bit se utiliza para los cálculos relacionados con el frame-buffer (z-buffering y el antialiasing) y sólo se puede acceder a él a través de la Memory interface.

Pasos restantes

El frame que se obtiene debe ser enviado al Video Encoder para visualizarlo en pantalla (el DMA y el Video Interface son esenciales para llevar a cabo esto).

En teoría, las capacidades máximas son una profundidad de color de 24 bits (16,8 millones de colores) y una resolución de 720x576 (o 640x480 en la región NTSC). En la práctica no se utilizan todos, ya que hacer uso de las capacidades máximas puede ser muy costoso en términos de recursos, por lo que los programadores tenderán a utilizar cifras más bajas para proveer suficientes recursos a otros servicios.

Demostración rápida

Pongamos todas las explicaciones anteriores en perspectiva. Para ello tomaré prestado el Super Mario 64 de Nintendo para demostrar, en pocas palabras, cómo se forma un frame:

Procesamiento de vértices

Image
Vista primitiva de nuestra escena. Para ahorrar polígonos, algunos caracteres se modelan con sprites (cuadriláteros)

Inicialmente, nuestros modelos 3D se encuentran en la ROM del cartucho, pero para mantener un ancho de banda constante, necesitamos copiarlos primero a la RAM. En algunos casos, los datos se pueden encontrar ya comprimidos en el cartucho, por lo que la CPU tendrá que descomprimirlo antes de utilizarlo.

Una vez hecho esto, es hora de construir una escena usando nuestros modelos. la CPU podría hacerlo por sí misma pero esto tardaría toda una vida, así que la tarea se delega al RCP. La CPU se limitará a enviar órdenes al RCP, esto se hace llevando a cabo las siguientes tareas:

  1. Componer la Display List que contiene las operaciones a realizar por el RSP y almacenarla en la RAM.
  2. Apuntar al RSP donde se encuentra la Display List.
  3. Enviar el microcode al RSP para poner en marcha la Scalar Unit.

Seguidamente, el RSP comenzará a realizar las tareas y el resultado será enviado al RDP en forma de comandos de rasterización.

Procesamiento de píxeles

Image
Frame renderizado (Tachán!).

Hasta ahora hemos logrado procesar nuestros datos y aplicar algunos efectos sobre ellos, pero todavía tenemos que:

  • Rasterizar vectores, aplicar texturas y otros efectos.
  • Mostrar un frame-buffer en pantalla.

Como puedes adivinar, estas tareas serán realizadas por el RDP. Para que esto funcione, las texturas deben ser copiadas desde la RAM a el TMEM usando el DMA.

El RDP tiene un motor fijo pero permite seleccionar un modo de funcionamiento en base a la tarea que se llevará a cabo, ayudando a mejorar el framerate.

Una vez que el RDP termine de procesar los datos, escribirá el mapa de bits resultante en el frame-buffer que se encuentra dentro de la RAM. Una vez terminado, la CPU debe transferir el nuevo frame a la Video Interface (VI), preferiblemente usando el DMA, que a su vez la enviará al Video Encoder para su visualización.

Diseños

He aquí algunos ejemplos de personajes previamente diseñados en dos dimensionas para la Super Nintendo, pero que han sido rediseñados para la nueva era de tres dimensiones. Los modelos son interactivos así que os animo a que les echéis un vistazo.

3D model
The Legend of Zelda: Ocarina of Time (1998).
704 triángulos.
WireframeSuperficieTexturado
3D model
Kirby 64: The Crystal Shards (2000).
516 triángulos.

Una solución moderna al problema de superficies visibles

Si has leído sobre las consolas anteriores, probablemente estás al tanto del interminable problema sobre la visibilidad de superficies y tal vez pienses que la única solución disponible es el ‘ordenamiento de polígonos’. Bueno, por primera vez en esta serie, el RDP presenta una solución basada en hardware llamada Z-buffering. En pocas palabras, el RDP asigna un nuevo buffer llamado Z-Buffer en la memoria. Este tiene las mismas dimensiones que un frame-buffer, pero en lugar de almacenar los valores RGB (rojo, verde y azul), cada entrada contiene la profundidad del píxel más cercano con respecto a la cámara (llamado ‘z-value’).

Una vez que el RDP rasteriza los vectores, el z-value del nuevo píxel se compara con el valor respectivo en el Z-buffer. Si el nuevo píxel contiene un z-value más pequeño, esto significa que el nuevo píxel se posiciona delante del anterior, por lo que el nuevo valor se escribirá el frame-buffer y z-buffer. De lo contrario, el píxel se descarta.

En general, el nuevo algoritmo es muy beneficioso: Los programadores ya no tienen que preocuparse por implementar métodos para ordenar polígonos basados en software que tienden a consumir bastantes recursos de la CPU. Sin embargo, el Z-buffer no previene procesar geometría innecesaria (eventualmente descartada o sobrescrita, que consumen recursos de todas maneras). Para ello, el motor del juego puede optar por incluir un algoritmo de ‘occlusion culling’ para descartar la geometría, que no será visible, lo antes posible.

Secretos y limitaciones

Es evidente que SGI invirtió mucha tecnología en este sistema. Sin embargo, esta sigue siendo una consola para el hogar y como tal, debe mantener un bajo coste. Por ahí, ciertas decisiones se convirtieron en retos para los programadores:

Atascos en la tubería

Debido al gran número de componentes y operaciones en la tubería de gráficos, el RCP terminó siendo muy susceptible a burbujas de segmentación: Una situación indeseable caracterizada por subcomponentes que se mantienen inactivos durante bastante tiempo porque los datos requeridos se retrasan en llegar.

Esto siempre se manifestará en una degradación del rendimiento y depende del programador para evitarlos. Aunque para facilitar las cosas, algunas CPUs como la Scalar Unit implementan una característica llamada Bypassing que permite ejecutar instrucciones similares a un ritmo más rapido, esto se consigue evitando etapas de ejecución que pueden ser omitidas.

Por ejemplo, si tenemos que computar múltiples instrucciones ADD (suma) a la vez, no hay necesidad de escribir el resultado de la suma en el registro destinatario y luego leerlo de nuevo para ejecutar el siguiente ADD. En su lugar, se puede usar el mismo registro intermediario para llevar al cabo todas las adiciones y al final, enviar el resultado al registro destinatario una vez que el último ADD se completa.

Memoria de texturas

El RDP usa 4 KB de TMEM (‘Texture Memory’) como única unidad para procesar las texturas. Desafortunadamente, en la práctica 4 KB resultaron ser insuficientes para las texturas de alta resolución. Además, si se utiliza el mipmapping, la cantidad de memoria disponible se reduce a la mitad.

Como resultado, algunos juegos utilizan colores sólidos con sombreado Gouraud (como Super Mario 64) mientras que otros hacen uso de texturas precalculadas (por ejemplo, cuando hay que mezclar varias capas).

La salida de video universal

Nintendo siguió usando la salida ‘universal’ llamada Multi Out como su predecesor, pero desafortunadamente, ¡ya no transmite más la señal RGB!. Esto me suena a otra medida para ahorrar costes, ya que la misma señal no se había aprovechado en la consola anterior.

Las buenas noticias son que los tres canales pueden ser reconstruidos en las primeras revisiones de la consola mediante la soldadura de algunos cables y la instalación de un amplificador de señal (que tiende a ser barato). Esto es debido a que el conversor de digital a analógico de video transmite una señal RGB al codificador de video. Sin embargo, las revisiones posteriores de la placa base combinaron los dos chips, así que la única solución disponible es de sobrepasar el video DAC y el codificador con algún chip especializado que pueda exponer la señal RGB.


Audio

Antes de entrar en detalles, definamos los dos extremos del subsistema de audio de la N64:

Dicho esto, ¿cómo conectamos ambos? Las consolas normalmente incluyen un chip de audio dedicado que hace ese trabajo por nosotros. Desafortunadamente, la Nintendo 64 no tiene dicho chip dedicado, por lo que esta tarea se distribuye a través de estos componentes:

Los datos resultantes, como era de esperar, contienen los waveforms. Estos se envían al bloque de Audio Interface o ‘AI’ que los transferirá al Digital-to-Analog converter. La waveform resultante contiene dos canales (ya que nuestro sistema es estéreo) con una resolución de 16-bits cada uno.

Image
Resumen de cómo se tiende a programar el motor de audio.

Repertorio musical

Es hora de echar un vistazo a las bandas sonoras hechas para la N64. La verdad es que hay demasiados buenos ejemplos para mencionar todos en este artículo, así que os dejo algunos que me llamaron la atención:

The Legend of Zelda: Majora’s Mask (2000).
La música de este juego está ligada a su atmósfera intimidante.
Bomberman Hero (1998).
Este juego tiene una agradable y única banda sonora de estilo house.

Secretos y limitaciones

Debido a este diseño, las limitaciones de este sistema dependerán de la implementación:

Por estas razones, los jugadores pueden llegar a notar que los ports de N64 contienen música de menor calidad o repetitiva. Un método para superar esta limitación consistía en implementar un secuenciador en software que pudiera ‘construir’ los samples mientras el juego se ejecutaba, esto requiere un banco de sonidos (similar a la música MIDI).


Sistema operativo

Al igual que la PS1 y Saturn, los juegos de N64 hablan directamente con el hardware. Sin embargo, no hay rutinas de la BIOS disponibles para simplificar algunas operaciones. Como sustituto, los juegos incorporan un pequeño sistema operativo que proporciona una buena cantidad de abstracción para manejar eficientemente la CPU, la GPU y el I/O.

Este no es el Sistema Operativo de escritorio convencional que podemos imaginar al principio, es sólo un micro-kernel con el menor tamaño posible que proporciona la siguiente funcionalidad:

En general, estas funciones son críticas para organizar las tareas de audio, video y la lógica del juego. Todas deben funcionar al mismo tiempo.

El kernel se inserta automáticamente al utilizar librerías de Nintendo. Además, si los programadores deciden no incluir alguna de las librerías, la porción respectiva del kernel se quita para evitar desperdiciar el espacio del cartucho.

Proceso de arranque

A diferencia de los anteriores sistemas basados en cartuchos, la Nintendo 64 sigue un sofisticado proceso de arranque para preparar todo su hardware antes de que se ejecute el juego. Esto se ejecuta tan pronto como el usuario enciende la consola y es muy similar a sus contemporáneos basados en CD que incluyen una BIOS o una IPL.

Estas rutinas también se denominan Initial Program Load (IPL) y funcionan de la siguiente manera [13] [14]:

  1. El usuario enciende la consola.
  2. El PIF-NUS (un chip separado en la placa madre) somete la CPU principal a un reinicio infinito hasta que el PIF-NUS valide el chip CIC encontrado en el cartucho del juego.
    • El PIF-NUS y el chip del CIC se explican en más detalle en la sección de I/O y Antipiratería, respectivamente.
  3. Si el proceso de verificación terminó con éxito, la CPU inicia la ejecución en 0xBFC00000. Esta dirección apunta a una ROM interna dentro del PIF-NUS, en particular, la primera etapa de arranque llamada IPL1.
  4. IPL1 inicializa parte del hardware (registros de la CPU, la interfaz paralela y el RCP) y copia la siguiente etapa (IPL2) de la ROM interna a la memoria del RSP para una ejecución más rápida. Luego, redirige allí la ejecución.
  5. IPL2 copia el primer megabyte de la ROM del juego en la memoria RSP, lo verifica (usando PIF) y lo ejecuta. Este bloque contiene la siguiente etapa del arranque denominada IPL3.
  6. IPL3 inicializa la RDRAM y el caché de la CPU. Después, inicia el sistema operativo (es decir, la memoria virtual y los vectores de excepción), configura el estado del programa (es decir, el puntero de pila o ‘stack pointer’) y finalmente invoca la rutina inicial del juego.

Como IPL3 se encuentra en el cartucho del juego, no todos los juegos empaquetan el mismo código. Presumiblemente, las variantes están correlacionadas con la variante del chip CIC incluido en el cartucho.


E/S

Como ya sabéis, el I/O no está conectado directamente a la CPU, así que el tercer módulo del RCP (que no he mencionado hasta ahora) sirve como interfaz I/O. Básicamente, se comunica con la CPU, los controladores, el cartucho de juego y los DAC de Audio/Video.

Accesorios

El mando de Nintendo 64 incluye un conector para enchufar accesorios. Ejemplos de accesorios comerciales incluyen:

Todos los accesorios conectados al mando son manejados por el PIF-NUS, un bloque relativamente desconocido que también controla la seguridad. El RCP se comunica al PIF utilizando un Bus de serie ‘muy lento’ (citado del manual de programación).


Juegos

Nintendo se aferró al cartucho como medio para el almacenamiento y como consecuencia, los juegos disfrutaron de mayores anchos de banda (un promedio de 5 MB/s según Nintendo) mientras que costaban más de fabricar. El cartucho más grande que hubo en el mercado tiene 64 MB.

Dentro de los cartuchos, los fabricantes pueden incluir memoria adicional (en forma de EEPROM, flash o SRAM con una batería) para guardar partidas. Sin embargo, no es un requerimiento estricto ya que algunos accesorios también podían ser usados para almacenar las partidas.

Los cartuchos se comunican al RCP utilizando un bus dedicado de 16 bits llamado Bus Paralelo (PBUS) o ‘Interfaz Paralela’ (PI).

Kit de Desarrollo

En general, el desarrollo se realizó principalmente en C y ensamblador, este último a menudo era necesario para lograr un mejor rendimiento. Mientras que hemos visto que este sistema ofrece operaciones de 64 bits, las nuevas instrucciones rara vez fueron usadas ya que, en la práctica, las instrucciones de 32 bits fueron más rápidas de ejecutar (dado que la R4300i/VR4300 viene con un bus de datos de 32 bits).

Por otra parte, las librerías en SDK oficial contenían varias capas de abstracciones para comandar el RCP. Por ejemplo, las estructuras en C como la Graphics Binary Interface o ‘GBI’ se diseñaron para ensamblar las listas de visualización necesarias más fácilmente. Lo mismo se aplica a las funciones de audio (su estructura se llamaba Audio Binary Interface o ‘ABI’).

En cuanto al uso de microcode, Nintendo proporcionó varias opciones de microcode fijo para elegir. Sin embargo, en el caso que los desarrolladores quieran modificarlo, se verían con una ardua tarea: Las instrucciones de la Scalar Unit no estaban inicialmente documentadas, aunque luego, Nintendo cambió de posición y SGI finalmente publicó cierta documentación para habilitar el desarrollo de nuevo microcode.

Image
Una SGI Indy que encontré en el Centre for Computing History (Cambridge, Reino Unido) cuando visité en agosto de 2024. En comparación, este ordenador alberga una CPU MIPS R4400, la sucesor del R4000 (en resumidas cuentas, años luz por delante del VR4300).

El hardware utilizado para el desarrollo incluía estaciones de trabajo suministradas por SGI [15], como la máquina Indy que venía con una placa extra llamada U64 que contiene el hardware y I/O de la consola. También se suministraron herramientas para ordenadores con Windows instalado [16].

Otras herramientas proporcionadas por terceros consistían en cartuchos con un largo cable que se conectaba a la estación de trabajo. Este cartucho se insertaba en una Nintendo 64 común, pero incluía un circuito interno para redirigir los comandos de lectura de la consola a la RAM de la estación de trabajo. El proceso de depuración (o ‘debugging’) se llevó a cabo transfiriendo una copia del juego a la RAM y una vez que la consola fuera encendida, comenzaría a leer desde ahí.

El medio alternativo

Adicionalmente, el PBUS se ramifica a otro conector en la parte inferior de la placa base de la N64. Esto estaba destinado a ser utilizado por la Nintendo 64 Disk Drive (64DD) aún inédita. Esta era una especie de ‘piso adicional’ que contiene un lector de disco magnético proprietario [17]. Sus discos contienen hasta 64 MB de capacidad. Aunque solo se lanzó en Japón, la unidad de disco abrió la puerta a un medio alternativo (y más barato) para distribuir juegos.

Image
La Nintendo 64 Disk Drive [18].
Lanzada el 01/12/1999 en Japón.
Image
La 64DD conectado a la consola [19].

El medio magnético es más lento que los cartuchos, con velocidades de transferencia de hasta 1 MB/seg, aunque más rápidos que los lectores de 4X CD-ROM. Los discos son de doble-cara y operan a una ‘Velocidad Angular Constante’ (como el posterior miniDVD). El área legible más pequeña se llama ‘bloque’ y es la mitad de un círculo concéntrico.

El lector no incluye un búfer de memoria, así que los bits leídos son almacenados en RDRAM para ejecución. Para abordar el aumento de la necesidad de memoria, Nintendo incluyó el RAM Expansion Pak con el 64DD también. Al hacerlo, también estandarizó el espacio de RAM extendido para que todos los juegos de 64DD pudieran aprovecharlo.

Además, partes del disco se pueden reescribir para permitir el almacenamiento de partidas, la cantidad de área disponible para escritura depende del tipo de disco usado (Nintendo proporcionó siete tipos). Del lado del software, los datos del juego son estructurados con un sistema de archivos llamado ‘Multi File System’ (MFS) que Nintendo proveyó en su SDK. Los juegos pueden acceder los datos del disco utilizando el sistema de archivo o a nivel de bloque, el último requiere otra librería llamada ‘Leo’ que proporciona funciones de bajo nivel.

El Disk Drive también alberga una ROM interna (denominada “DDROM”) que almacena el código que ejecuta la N64 para arrancar el disco y mostrar la animación de bienvenida. Esto funciona como una nueva etapa del IPL añadida encima del proceso de arranque tradicional. La ROM también almacena fuentes (Latín y Kanji) y algunos sonidos. Esta ROM solo se encuentra en la version ‘retail’ del 64DD, ya que las unidades de desarrollo usaban programas externos cargados a través del kit de desarrollo.


Anti-piratería / Region Lock

El sistema antipiratería es una continuación del CIC de la SNES. Como sabéis, la detección de piratería y el ‘region lock’ son posibles gracias al chip CIC (que debe estar presente en cada cartucho de juego autorizado) [20], la Nintendo 64 mejoró este sistema requiriendo que diferentes juegos tuvieran una variante específica del CIC. Esto es para asegurarse de que el cartucho no era una falsificación o contenía un clon del CIC. El PIF realiza comprobaciones por medio de checksums al inicio y durante la ejecución del juego para supervisar el CIC instalado en el cartucho.

Si por alguna razón el PIF considera que el cartucho insertado no es válido, este congela la ejecución del juego.

El region-lock se realizaba alterando ligeramente la forma del cartucho entre las diferentes regiones para que el usuario no pudiera insertar físicamente el juego en una N64 de una región diferente.

En general, no hubo demasiada preocupación por la piratería gracias al uso del cartucho como medio, aunque los precios de los juegos eran tres veces más altos que aquellos basados en CD.

Puertos sin utilizar

Por muy tonto que parezca, Nintendo dejó una ‘puerta’ abierta: El puerto del Disk Drive.

Image
El Doctor V64 conectado a la consola [21].
Image
El V64 visto desde atrás, mostrando conectores especiales para A/V.

Algunas compañías, mediante ingeniería inversa, estudiaron la interfaz para desarrollar hardware propietario; algunos de estos productos llegaron a preocupar a Nintendo debido a sus capacidades para ejecutar juegos piratas.

Supongo que vale la pena mencionar el Doctor v64, este dispositivo tiene la misma forma que el Disk Drive pero incluye una unidad de CD-ROM.

Esta expansión puede grabar el contenido del cartucho a un CD, y lo opuesto (leer la ROM desde un CD) también es posible.

Emulación

Cuando yo era niño solía jugar a algunos juegos de Nintendo 64 en una máquina Pentium II usando un emulador, no funcionaba tan mal, pero años más tarde me pregunté cómo narices era capaz de emular una máquina de 64 bits tan tranquilamente si, entre muchas cosas, mi PC apenas tenía la suficiente RAM para mantener la tarjeta gráfica integrada con vida.

La verdad es que, mientras que reproducir la arquitectura de esta consola puede ser un tarea bastante difícil, cosas como el microcode dan una pista de lo que la consola está intentando hacer, y cómo los emuladores no tienen que ser precisos, pueden aplicar suficientes optimizaciones para proporcionar más rendimiento a cambio de una emulación idéntica.

Otro ejemplo son las instrucciones de 64 bits, ya que los juegos apenas las utilizaron, la velocidad de emulación raras veces empeora cuando se lleva a cabo en un ordenador de 32 bits.


Eso es todo amigos

Image
Mi N64 compartida en la casa de un amigo.
Mientras que yo solo quería la consola para este artículo, mi colega siempre soñó por un N64 DD, así que compramos un set muy completo (pero caro) compuesto por una N64 japonesa con un DD y así evitamos gastar demasiado individualmente. Después, le instalé el N64RGB para que podamos conectarlo a una TV moderna; y el resultado es una buena unidad de entretenimiento (¡y tema de conversación!).

Debo decir que este artículo puede ser el más largo que he escrito, pero espero que al menos te haya sido de interés.

Probablemente me tome los siguientes días para ordenar algunas cosas en la web en lugar de empezar a escribir el siguiente artículo.

¡Hasta la próxima!
Rodrigo


Contribuir

Este artículo forma parte de la serie de Arquitectura de consolas. Si te ha resultado interesante, por favor considere donar. Tu contribución se usará para tener mas herramientas y recursos que ayudarán a mejorar la calidad de los actuales artículos y próximos.

Donate with PayPal
Become a Patreon

También puedes comprar la edición eBook en inglés. Trato las ganancias como donaciones.

Image

Esta es la lista de herramientas adquiridas o interesantes a adquirir:

### Interesting hardware to get (ordered by priority)

- Any Dev kit (only if found at a reasonable price)

De alternativa, puedes ayudar sugiriendo cambios y/o agregando traducciones.


Copyright and permissions

This work is licensed under a Creative Commons Attribution 4.0 International License. You may use it for your work at no cost, even for commercial purposes. But you have to respect the license and reference the article properly. Please take a look at the following guidelines and permissions:

Article information and referencing

For any referencing style, you can use the following information:

For instance, to use with BibTeX:

@misc{copetti-nintendo64,
    url = {https://www.copetti.org/writings/consoles/nintendo-64/},
    title = {Nintendo 64 Architecture - A Practical Analysis},
    author = {Rodrigo Copetti},
    year = {2019}
}

or a IEEE style citation:

[1]R. Copetti, "Nintendo 64 Architecture - A Practical Analysis", Copetti.org, 2019. [Online]. Available: https://www.copetti.org/writings/consoles/nintendo-64/. [Accessed: day- month- year].
Special use in multimedia (Youtube, Twitch, etc)

I only ask that you at least state the author’s name, the title of the article and the URL of the article, using any style of choice.

You don’t have to include all the information in the same place if it’s not feasible. For instance, if you use the article’s imagery in a Youtube video, you may state either the author’s name or URL of the article at the bottom of the image, and then include the complete reference in the video description. In other words, for any resource used from this website, let your viewers know where it originates from.

This is a very nice example because the channel shows this website directly and their viewers know where to find it. In fact, I was so impressed with their content and commentary that I gave them an interview 🙂.

Appreciated additions

If this article has significantly contributed to your work, I would appreciate it if you could dedicate an acknowledgement section, just like I do with the people and communities that helped me.

This is of course optional and beyond the requirements of the CC license, but I think it’s a nice detail that makes us, the random authors on the net, feel part of something bigger.

Third-party publishing

If you are interested in publishing this article on a third-party website, please get in touch.

If you have translated an article and wish to publish it on a third-party website, I tend to be open about it, but please contact me first.


Fuentes / Sigue leyendo

Anti-Piratería

Audio / Vídeo

Bonus

CPU

Juegos

Sistema Operativo

Fotografía


Rodrigo Copetti

Rodrigo Copetti

Espero que hayas disfrutado este artículo, si quieres saber más sobre el autor entra aquí y si quieres ayudarlo entra aquí

rsslinkedintwittergithub facebookreddit