2600 - PROGRAMANDO JUEGOS SIN RECURSOS
o "como pudieron hacerlo!!!"
Introduccion
Un poquito de Historia
Hoy en dia existen un sin fin de consolas, computadores y demases aparatos dedicados
al fin de la entretencion casera basados en los videojuegos. En los ultimos a得s
el mercado en este rubro a crecido de forma desmesurada. Aparecen muchas compa張as de
software dedicadas a la creacion de juegos, algunas con innovadoras ideas y otras no
tan originales, contratando programadores brillantes para crear sus engines.
Es tanto el auge que pareciera que cualquiera podria programar un juego... bueno, de hechp
asi es, pero solo algunos pueden hacer un buen juego.
Lo que mucha gente olvida es que no siempre fue tan sencillo programar un juego... talves
ni siquiera saben que la idea, el argumento, el desarrollo y los toques finales muchas veces fueron
la parte facil de todo eso... la verdadera proeza era implementarlo (casi una lucha)
, y llevarlo a la realidad. Me refiero a cuando hacer un juego requeria de una persona con
mucha experiencia, habilidad, imaginacion y MUY MUY MUY BUEN PROGRAMADOR.
El objetivo de este informe es mostrar de forma bastante detallada la arquitectura
de una consola que marco una epoca, el Atari 2600, conocido como el prollecto STELLA dentro del
ambiente de la programacion. Esta consola tuvo un auge muy grande, con decir que desde 1976,
cuando hizo su aparicion, se crearon juegos initerrumpidamente hasta los años
1998-1990. Mucha gente creo su gusto por los juegos de video en esta consola y hasta
marco su vida como futuros programadores, para tratar de imitar lo que veian.
Pero fue el mismo hecho de que se hicieron tantos juegos lo que
provoco la caida de esta en los a得s 83 84 puesto que estos juegos eran de una calidad
bastante deficiente y pobres en sus ideas.
Un aspecto importante de esta consola, que es lo que mostrare en todo el informe, es
la dificultad de programar, literalmente, cualquier juego. Debido a la "sencilles" de
la cosola, el programador debia de tener en mente "TODO" el juego a la hora de implentarlo
pues un cambio de ultima hora podia ser desastroso o imposible en ultima instancia.
Por ultimo, espero que una ves hallan leido esto, se den cuenta de todo el trabajo que
hay detras de un simple juego y no se quejen de que la grafica era mala o el juego
era muy simple.
Especificaciones Tecnicas
El Stella parece ser muy sencillo... de hecho lo es, y este es su hardware
- Procesador 6502
- El TIA (Television Interface Adaptor)
- El PIA (Chip de Funciones varias)
- 6 Puertos de entrada/salida para los Paddles
- 2 Puertos paralelos para Joysticks y Switches
El procesador
El 6502 es un procesador de uso comun muy difundido en la epoca de
finales de los 70 y comienzo de los 80. Muchas maquinas lo usaron (atari,
commodore, etc) y mucha gente se crio con este. Este procesador, a pesar
de sus limitaciones, poseia gran poder.
Posee el 6502 solo 3 registros y con ellos debe hacer todo. Uno de estos
es el registro A (acumulador) que es el registro donde se procesan los
calculos. El set de instrucciones es muy amplio, debido a la gran
cantidad de modos de direccionamiento de este, desde el modo inmediato
hasta el indexado indirecto. Esto va totalmente en contra de
la filosofia de RISC, pero su gran facilidad de programacion
lo hizo favorito de mucha gente y la plataforma perfecta para muchos
de los primero peque得s computadores personales.
Realmente el Stella no usaba un 6502, sino que una variante de este llamado
6507 que se diferenciaba del 6502 en poseer un bus de datos mas pequeño
de solo 13 bits con lo cual podia direccionar hasta 8 Kb. Esto limitaba los
juegos disponibles hasta catridges de 8 Kilos, pero luego la gente aprendio
nuevas tecnicas de hardware, hasta conseguir catriges de 16 y 32 kilos
que corrieran en la misma maquina.
Una de las cosas mas importantes de este procesador es el hecho de que
las instrucciones que afectaban las primeras direcciones hasta la $FF son ejecutadas considerablemente mas rapido que el resto. Esto
es muy importante en este caso, pues como se vera adelante el Stella
manejaba todo el hardeware escribiendo en registros mapeados en estas primeras
direcciones.
La Memoria en el Stella
El espacio de direcciones del Stella consiste en 8 Kb, pues el bus de datos
del 6507 era de 13 bits solamente.
De estos 8 Kb, las primeras direcciones hasta el $08 tienen mapeados registros
de hardware, que fisicamente estan en el TIA, y sirven para controlar casi todo
desde la posicion horizontal de los jugadores hasta el ancho de los sprites.
Despues vienen vienen 128 bytes de ram que van desde el $80 hasta el $FF,
que dan al programador un lugar para sus variables y la pila. Y desde ahi en adelante
el espacio direcciona directamente los catridges de memoria, que contienen
el juego. Estos juegos podian ser tan chicos como 2kb o grandes como 8kb.
El protocolo de television
Para entender realmente el funcionamiento de esta consola hay
que tambien conocer algo de como se formaran las imagenes en la television pues
esto esta muy unido a la programacion en si... mas bien, en eso consiste la mayor
parte de la programacion del juego.
Partamos primero definiendo un "frame". un frame consiste en 262 lineas horizontales
y cada una de ellas consiste en 228 tics de reloj (3.58 Mhz). Esto
quiere decir que cada linea tomara esa cantidad de tics en dibujarse.
La imagen se redibuja de izquierda de arriba hacia abajo a 60 frames por segundo.
El formato de un frame es el siguiente: 3 lineas de sincronia vertical y luego vienen
37 lineas de blanqueo vertical. Luego se dibujan las lineas
que se veran de la television, estas consisten en 192 lineas propiamente tal
y finalmente 30 lineas de Overscan (estas son virtuales, pues como lineas no existen,
sino que son 30*228 tics de reloj que el rayo de electrones demora en volver hasta
la esquina superior izquierda.
Cada Linea de television comienza con 68 tics de blanqueo horizontal
que es el tiempo en que el rayo demora en volver al lado izquierdo de la
pantalla.
El manejo de sincronizacion horizontal es tarea del hardware, pero
todo la sincronizacion vertical corre por cuenta del programador que por
cada frame debe: generar 3 lineas de VSYNC (sincronia vertical) 37 de
VBLANK (blanqueo vertical), 192 lineas para el despliegue
actual y las 30 de overscan.
La imagen de la pantalla se genera de la siguiente manera.
El procesador debe ingresar los datos de la linea que esta
siendo dibujada en el TIA (Television Interface Adapter).
Este chip (donde residia todo el poder grafico de
esta consola, verdadero abuelo de las tarjetas graficas
de hoy) solo puede contener una linea, la actual.
Por esa razon el procesador debe ir "un paso delante"
generando la imagen de la linea. Como un ciclo de
CPU es igual a tres tics del reloj del sistema,
el programador solo tiene 76 ciclos de maquina por
linea (228/3=76) para calcular y dibujar la imagen.
La parte de todo juego que se encarga de toda esta tarea
es conocida como el Kernel.
El resto de las lineas (3 de VSYNC, 37 de VBLANK y 30 de OVERSCAN)
nos daran 5,320 ciclos de maquina (70 lineas *76 ciclos de maquina)
para el resto de la programacion logica del juego.
Esa logica va desde calcular las nuevas posiciones de los jugadores
hasta chequear las entradas de los joysticks y distintos calculos
necesarios.
En el proximo capitulo, lo mas importante de este informe
es una especificacion del chip TIA con sus caracteristicas completas.
TIA (Television Interface Adaptor)
Este chip fue dise帶do para servir de interface
entre el 2600 y el televisor, tomando del bus de datos
de 8bits mandadas por el procesador y convirtiendolas
en se帶les analogas, interpretables para el televisor.
La idea en mente durante su dise得 era la de proveer
una manera eficiente de dibujar un playfield (campo de
juego), y cinco objetos movibles, a saber 2 sprites,
2 misiles y una pelota. Todos estos son creados
manipulando una serie de registros que podian ser
direccionados y escritos por la CPU y cada uno de estos
registros tiene sus propias capacidades y desventajas.
Es el TIA el que se encarga de tomar la informacion
de estos registros y desplegarla en la pantalla.
Ademas los objetos movibles, como los sprites, poseen
un conjunto de registros de posicion mediante los cuales
el TIA "sabe" en que lugar de la pantalla deben ser desplegados.
SIncronizacion con el procesador.
COmo se menciono anteriormente, uno tiene 5,320 ciclos de
maquina al final de cada frame para calcular la logica del
juego y con esto uno debe arreglarselas, pero los ciclos
de ejecucion tienen un largo indefinido. Antes esto
la solucion que existe es la existencia del registro
WSYNC, (wait sync) el cual pone al procesador en estado de
halt hasta que el rayo de electrones a vuelto a la esquina
superior derecha. Esta es una solucion sencilla pero el correcto
uso de ella es de enorme dificultad.
Los Registros
Luminosidad y color:
Para los 7 objetos de un juego (playfield, 2 sprites,
2 misiles y pelota) existen solo 4 registros de 8 bit
para asignarles color y luminosidad, cuatro bit de color
y 3 bits de luminosidad. La asignacion de colores para los
objetos es la siguiente:
Nombre de Registro Objeto coloreado
COLUMP0 P0, M0 (Sprite 0, misil 0)
COLUMP1 P1, M1 (Sprite 1, misil 1)
COLUMPF PF, BL (Playfield, Pelota)
COLUMBK BK (background)
Notese que Sprite y misil comparten color, esto es util
para juegos como combat donde el disparo de cada jugador
coincide con el de el tanque que este controla. :)
Playfield:
El registro PF es usado para crear la ambientacion del juego,
el campo de batalla, los laberintos, bosques, etc. Este
registro de "baja resolucion por asi decirlo" es el patron
que usa el TIA para dibujar la mitad izquierda de la
linea actual. Este registro de 20 bits se subdivide en 3
registro de 4, 8 y 8 bits correspondientemente que definen
los 20 bits izquierdos del campo de juego. El lado derecho
de la pantalla se dibuja automaticamente "clonado" del izquierdo
o reflejado, segun se especifique por el programador escribiendo
en el registro CTLPF (control playfield)
Los Objetos "Movibles"
El 2600 posee cinco objetos graficos, cada uno posisionable
horizontalmente de manera independiente. Cada uno de estos
registros guarda la forma horizontal que tiene el sprite
y que sera desplegada en la linea actual.A cada uno se le
puede asignar una posicion horizontal distinta y moverlos
con respecto a esto con solo escribir en los registros asociados a
los objetos. La posicion vertical de los objetos es tratada
de una manera totalmente distinta a la horizontal. Por ejemplo,
si queremos que la pelota aparesca en el centro del playfield
(por ejemplo en un juego de Pong) y con un ancho de 2 lineas (pixels),
debemos contar hasta llegar a la linea 96, luego escribir en
el registro que activa la pelota, contar 2 lineas y luego
desactivar el registro hasta el siguiente frame.
Misiles (M0, M1)
Estos dos objetos graficos se dibujaran en cualquier linea
de la pantalla con solo escribir un 1 en los registros ENAM0
y ENAM1. Estos objetos se posisionaran desplazados desde el
borde derecho segun el valor en sus registros de posicion,
y el ancho de los misiles se controla con los registros
NUSIZ0 y NUSIZ1 respectivamente. Estos registro guardan ademas
otras propiedades de los misiles.
La Pelota
Este objeto se comporta como los misiles y se activa facilmente
con el registro ENABL. El ancho de la pelota es facilmente
cambiable a 1, 2, 4 u 8 tics con solo escribir en el registro
CTLPF.
Una particularidad existe en este registro. Escribiendo
1 en el registro VDELBL, la pelota demorara una linea mas
en dibujarse que cuando fue activada. La razon de esto es
que para tener mas tiempo de calculo, muchos programas
solo actualizabaan los registros del TIA cada 2 lineas.
Asi, con ese registro, los programas lograban una resolucion
de 1 tic para los movientos de la pelota, mientras que el
escenario y los objetos seguian teniendo una baja resolucion.
Sprites (GP0 y GP1)
Los Sprites (los jugadores) poseen las mismas caracteristicas que los
demas objetos, pero ademas poseen otras mas que los hacen
especialmente utiles. Un sprite se obtiene escribiendo
en un registro de 8 bits (GP0 y GP1) los datos de la forma
del sprite en la linea deseada. Esto permite que el sprite
tenga la forma deseada (menor igual a 8 tics) y puede ser
hasta del tama得 de la pantalla. Basta con poner el sprite
en ENABLED e ir cambiando la forma a medida que se van dibujando
las lineas en la pantalla.
Otra caracteristica importante de los sprites es que pueden
ser reflejados (imagen inversa en izquierda-derecha) con solo
escribir en un registro de 1 bit (REFP0 y REFP1). Esta y la
capacidad de producir diferentes copias de un mismo sprite
con solo escribir en el registro NUSIZ0 o NUSIZ1 son las dos
grandes distinciones con los otros objetos. Ademas, el sprite
y sus copias podian cambiar el ancho, desde 1 a 8 tics de reloj
escribiendo en los mismos registros.
Estos tambien cuentan con retraso vertical, al igual que la
pelota, poniendo un uno en VDELP0 y VDELP1, registros de 1 bit
que podian ser desactivados poniendo un 0 en ellos.
Posicionamiento Horizontal. (RESP0, RESP1, RESM0, RESM1, RESBL)
Cada objeto movible (sprite, misil o pelota) tiene asociado
un STROBE REGISTER el cual al ser
escrito, originara que el objeto sea dibujado en esa posicion
horizontal durante la segunda linea. Si el seteo del registro
ocurre durante el blanqueo vertical, entonces el objeto
sera dibujado junto al borde izquierdo de la pantalla.
Existe un problema. COmo el reloj de la CPU corresponde a
3 tics del sistema, y una escritura a un regristro puede demorar
hasta 5 ciclos de maquina, el movimiento horizontal queda
confinado a intervalos de 15 tics... extremadamente baja
resolucion de movimiento!!!! pero esto puede ser solucionado
conc una tecnica que explicare mas adelante.
Los Misiles ademas tienen otro registro, RESMP0 y RESMP1
que tienen por mision desactivar el misil (esconderlo) y luego
modificar su posicion a la de su sprite asociado para un nuevo
disparo.
Movimiento horizontal.
Esto es una de las cosas mas dificiles (como todo lo demas).
Cada objeto tiene asicoado un registro de desplazamiento
(HMP0, HMP1, HMM0, HMM1, HMPL) de 4 bits, que puede ir desde
-7 a 8 en notacion complemento de dos. Este desplazamiento
puede ser sumado a la posicion horizontal tan solo escribiendo
en el registro HMOVE. Aquellos objetos que no deseen ser
movidos deben tener un 0 en el registro. Ademas, pueden
efectuarse multiples desplazamientos con solo escribir en
HMOVE varias veces.
Por restricciones de hardware, HMOVE debe ser invocado
inmediatamente luego de un WSYNC (wait for sync) para obligar
a que HMOVE ocurra durante el blanqueo horizontal. Esto se debe
a que los registros usados eran muy viejos y por lo tanto
bastante lentos.
Escribiendo en el registro HMCLR se borran todos los movimientos
acumulados.
Colisiones
El TIA puede identificar 15 distintas colisiones entre los
distintos objetos, durante cada scan-line. Estas colisiones
seran guardadas durante el blanqueo horizontal en flip-flop
latch (para que ocurran todas las colisiones que pueden ser
posibles)y luego puedan ser leidas y decodificadas por el
programados leyendo el valor de las colisiones en el
registro de colisiones. Este registro puede ser limpiado
accesando el registro CXCLR.
Puertos de Input
El TIA tiene 6 puertos de input, dividos en dos grupos, 4 Dumped (INPT0-INPT3)
y Latched (INPT4-INPT5).
Los dumped sirven para conectar hasta 4 paddles (controles de perilla). Cuando estos estas
perillas se mueven, cargan un condensador dentro de la consola. Luego el procesador manda
una se帶l al codensador para descargarlo. Midiendo cuanto tiempo se demora el condensador
en descargarse se puede especificar una posicion de un objeto en la pantalla mediante unos
simples calculos.
Los latched estan conectados a los botones de los joystick y sirven para medir cuando estos
son presionados.
El PIA
Este Chip Ofrece muchas funciones utiles para la consola. Entre las mas destacadas
estan dos puertos de entrada de 8 bits, un "timer" programable, y la impresionante cantidad de
128 bytes de ram.
El timer
Este es un timer programable, el cual puede ser seteado para medir eventos de tiempo por el programador.
La utilidad se puede encontrar al tratar de sicronizarse con el TIA
o para la sincronizacion vertical con la pantalla.
Para utilizar este basta escribir un numero en uno de los cuatro registros de timer. Para activar
un timer de 6400 tics, basta escribir un 100 en TIM64T
Intervalo Mnemonico
1 tics TIM1T
8 tics TIM8T
64 tics TIM64T
1024 tics T1024T
Luego de que el timer llega a cero, se mantiene en cero en un ciclo y luego este vuelve a
FF. Esto tiene por objeto saber cuanto tiempo hace que el timer llego a cero.
Memoria RAM
El PIA tiene 128 bytes que se ubican entre las direcciones $80 (hexadecimal) y $FF. Antes de $80
se encuentran mapeados los registros del TIA. Normalmente los datos se ubicaban desde $80 hacia arriba
y la pila desde el $FF hacia abajo esperando que nunca se pisaran uno con el otro.
Puertos de entrada y salida
El stella cuenta con dos puertos de 8 bits cada uno para comunicarse con el exterior. El puerto
B se encuentra mapeado en la memoria como SWTCHB. Cuando uno lo lee, se obtiene un vector con los
estados de los switches de la consola. Esta es la configuracion del mapeo.
Bit Switch Significado
D7 P1 dificultad 0 = amateur (B), 1 = pro (A)
D6 P0 dificultad 0 = amateur (B), 1 = pro(A)
D5/D4 no usado
D3 color - B/N 0 = B/N, 1 = color
D2 no usado
D1 boton select 0 = switch presionado.
D0 boton reset 0 = switch presionado.
El segundo puerto es usado para leer el estado de los joysticks. Ambos son mapeados en el mismo
puerto sin contar con los botnes que son mapeados en los registros INPT4 e INPT5. Esta es la
configuracion del puerto:
Bit Direccion Joystick
D7 derecha D
D6 izquierda D
D5 abajo D
D4 arriba D
D3 derecha I
D2 izquierda I
D1 abajo I
D0 arriba I
Concluciones
Finalmente queria hacer notar lo dificil que era programar para estas maquinas. La dificultad estriba en que el programador debia disenarlo todo en conjunto
pues no podia empezar con los graficos y al final agregar la musica, pues
agregar algo podia destruir toda la sincronizacion con la pantalla, pues muchos
calculos se hacian en el mismo momento en que se dibujaban las lineas. Si no les parece suficientemente dificil, adjunto un muy muy muy facil codigo en assembler que genera una pocas lineas de colores en la pantalla. Ni siquiera tiene musica pero es suficientemente complicado para tener una idea.
![](2600.jpg)
Click Aqui para un ejemplo en assembler de Nick Bensema