Haciendo juegos en una Atari 2600, parte 2

Bueno, vamos a hacer un juego de Atari 2600. Para ello habrá que aprender algo de informática de bajo nivel y ensamblador para la CPU de esta consola, que usa una variante económica del famoso 6502. Además de algunas cosillas sobre cómo se genera la imagen en tu TV. ¿Preparados?

Carol Shaw, creadora de River Raid entre otros para la Atari 2600

Como muchos sabréis la unidad de medida básica en un ordenador es el bit, que simplemente comunica dos estados: apagado y encendido, 0 y 1. Es enviada con una señal eléctrica y es la base de nuestra informática.

Un byte es un conjunto de 8 bits. Se eligió y popularizó este número en concreto ya que era (por aquel entonces) el tamaño necesario para poder almacenar un carácter ASCII (7 bits de información del carácter y 1 bit de paridad para controlar que la información era correcta).

Para poder manejarnos con la Atari necesitamos aprender dos sistemas de numeración: binario y hexadecimal. A diario usamos la notación decimal, que significa que cada posición tiene 10 posibilidades (de 0 a 9), en binario hay dos (0 ó 1) en hexadecimal hay… ¡16!

Y si el ordenador usa binario, ¿Por qué esta loca quiere que aprendamos a usar hexadecimal? Pues porque aunque no lo parezca, ¡Es más cómodo! Imaginad el siguiente byte:

1010 1001

En hexadecimal sería:

A 9

El binario 1111 equivale a 15 en decimal, por lo que con un solo dígito no podemos representar el valor máximo en decimal.

¡Pero en hexadecimal sí podemos llegar a 15!

Vale, entonces si tenemos 8 bits, podemos escribir un número de 0 a 255 (haced la cuenta en casa). Pero… ¿Cómo leches escribimos un número negativo? En clase poníamos un menos delante y listo, pero aquí solo tenemos esos 8 ceros y unos. Tendremos pues que sacrificar un bit para ello.

Usando este truco podemos tener un número positivo que vaya de 0 a 127 (7 bits) y el resto que va de 128 a 255 lo interpretaremos como negativo usando esta regla:

El número que digamos -256

Ejemplos:

0111 1111 (en binario)

equivale a 127 (en decimal)

1000 0000 (binario)

equivale a 128-256 = -128 (decimal)

1111 1111(binario)

equivale a 255–256 = -1 (decimal)

…¿Qué tal la cabeza?

Ahora que medio entendemos el lío de bits y números vamos a por la CPU. En el caso de la Atari, es una MOS 6507 que va a… ¡1,19 megahercios! Ok, ¿Eso qué significa? Pues que es capaz de ejecutar más de un millón de ciclos por segundo. ¡Suena a mucho! Y lo era, hace décadas.

Entonces, ¿A qué se dedica la CPU en cada uno de esos ciclos? Pues realiza un proceso en bucle tal que así:

  • Busca la siguiente instrucción en la memoria.
  • Decodifica la instrucción.
  • Ejecuta la instrucción.
  • Guarda los resultados.

Recordad que dijimos que el 6502 tiene un bus de direcciones de 16 bit y un bus de datos de 8 bits. Cada patita del chip es un bit: 0 y 1. El bus es algo así como nuestra autopista por la que podemos enviar y recibir información.

El bus de direcciones es solo de escritura. En él escribimos la dirección con la que nos queremos comunicar, es algo así como marcar un número de teléfono.

Normalmente hace referencia a una posición de memoria, pero hay direcciones especiales…

Terminator (CPU 6502) buscando la dirección de memoria de Sarah Connor

El bus de datos es de lectura y escritura, lo que significa que sirve tanto para recibir un dato que nos hayan mandado, como para enviar nosotros datos.

Por ejemplo, si colocamos el bus de direcciones en la posición 0 de memoria y luego escribimos en el bus de datos un 8, la memoria guardará ese 8 ¡Magia!

Y este rollo, ¿De qué sirve? Pues para leer el input del joystick, o guardar las vidas en memoria, o coger los píxeles del sprite del jugador, enviarlos al chip gráfico y que se dibuje en pantalla… todo eso son instrucciones de la CPU usando esos buses.

Ahora conoces matrix.

Después de un tiempo leyendo ensamblador, entenderás esta escena…

Vamos a ver cómo escribimos un programa en ensamblador que nuestra CPU de Atari pueda entender y así hacer jueguitos. El asm tiene un conjunto de mnemónicos (una palabra que representa una instrucción de la CPU). Por ejemplo el mnemónico LDA significia “LoaD Accumulator”.

Si escribimos en nuestro programa:

LDA $1234

Estamos diciendo que queremos leer un dato de la dirección $1234 y guardarlo en el registro A (llamado acumulador). Este dato podría ser la vida del jugador, la cual queremos cargar para luego añadirle una vida.. o quitársela. 😆

Esa instrucción:

LDA $1234

Se convertirá para la CPU en:

ad 34 12

ad es el opcode (código de operación), lo que le dice a la CPU qué instrucción toca ejecutar.

34 12 es el número de dirección partido en 2 bytes. Espera… ¿Por qué está al revés?

El 6502 es little endian, lo que significa que el byte menos significativo va primero. Otros procesadores lo hacen justo al revés, ¡E incluso algunos pueden usar ambos modos!

El orden de los bytes no altera el resultado

¿Y cuánto tarda el LDA en ejecutarse? Contemos:

Un ciclo para leer el opcode, dos para leer el número y otro ciclo más donde coge el valor de la dirección $1234 y lo guarda en el registro A.

Por tanto LDA tarda 4 ciclos.

En la Atari es importante llevar la cuenta de ciclos de la CPU ya que lo que hacemos es comunicarnos directamente con el TIA (El chip gráfico) por lo que es fundamental medir los tiempos entre frames y no pasarnos del límite. Da miedo pero ¡Es parte del reto!

Dicho esto ¡Ya estamos listos para empezar a escribir nuestros primeros programas! Por hoy dejo que repaséis el tocho, pronto vendrá la continuación donde veremos instrucciones, bucles, operaciones aritméticas…

¡Espero que os haya gustado!

One clap, two clap, three clap, forty?

By clapping more or less, you can signal to us which stories really stand out.