C64 a Fondo – 6502 vs 6510 Parte 2 – Pinout

Vamos a empezar este estudio comparativo del 6502 vs el 6510 con una descripción del para qué sirve cada patita de estos chips (que básicamente es el pin out). Nos va a servir de guía para poder hablar de las diferencias que tienen estos chips entre sí

Les dejo el link al articulo anterior en la serie, y al final como siempre los links a todos los artículos de la misma.

Parte 1 – El módulo de reloj

Cosas en Común entre el 6502 y el 6510

Ambos chips fueron creados por MOS Technologies y muy utilizados en el final de los 70 y principios de los 80. El 6510 ya no se fabrica más en la actualidad (escribiendo estas notas en Junio del 2023) sobreviviendo sólo en los corazones de millones de Commodore 64 y en los corazones de miles de Commodorianos.

El 6502 todavía sigue siendo muy utilizado teniendo versiones actuales de USM y de WDC siendo la versión actual la 65C02 que agrega algunas instrucciones extras de assembler y baja mucho el consumo eléctrico.

Arquitectura

Ambos procesadores son procesadores de 8 bits y comparten muchísimas cosas en común. La arquitectura interna de estos procesadores es idéntica y está dividida en dos partes una sección con los registros y otra con las operaciones de control, las señales que provocan transferencias de datos están en la sección de control.

Set de instrucciones

El código máquina de ambos procesadores posee las mismas instrucciones de assembler de 6500 con lo que los programas de uno funcionan perfectamente en el otro.

Agrego algunas instrucciones extras del modelo 65C02 (las marcadas con punto en la siguiente tabla) que NO recomiendo usar para poder mantener compatibilidad con el 6510 y el 6502 originales pero que ahorran algunos pasos al no tener, por ejemplo, que pasar por el acumulador para guardar el registro X en el stack con la instrucción PHX. El 65C02 es una versión más moderna del MOS 6502 siendo una ventaja el ser fully static por lo que se puede parar el clock y los registros no pierden sus valores.

Velocidad de Reloj

Los procesadores 6502 y 6510 originales soportan una velocidad de reloj de hasta 1Mhz, teniendo luego el 8502 que soporta hasta 2Mhz (usado en el modo 64 de la Commodore 128)

Registros

La cantidad de registros y la forma de accederlos se mantienen para toda la familia estos son los familiares A, X e Y, el Status Register y el Stack Pointer los 5 de 8 bits y el Program Counter de 16 bits.

Modos de direccionamiento

Ambos chips funcionan de idéntica forma al relacionar la memoria y sus registros presentando modos de direccionamiento diferentes ya sea si uno quiere cargar directamente de memoria, o un número literal al acumulador, en forma indexada los datos y aplicar funciones que trabajan con el acumulador sin tocar memoria.

Bus de Direccionamiento y Bus de Datos

Ambos procesadores poseen 16 líneas de direccionamiento de datos (pines) pudiendo manejar entre memoria y registros de I/O hasta 64Kb (2ˆ16 = 65536 bytes).

Pin-Out y diferencias

Aquí salta a la vista la diferencia más grande ya que el 6510 posee 6 pines adicionales que puede ser utilizados como interfaz de Input/Output para comunicarse con periféricos ya que estos son bidireccionales. 

Para manejar estos pines el 6510 utiliza las direcciones 0 y 1 donde especifica en la cero si son inputs (pone un cero) o output (pone un 1)  y en el dirección 1 los valores de los mismos, ya sea recibidos de un periférico y escritos por el procesador para consumo externo.

Pin-Out 6502

Este chip posee un formato DIP 40 con las siguientes funciones en sus pines

VPB Pin de La B significa Bar o Barra para que este pin se active el voltaje tiene que ser Low o 0v

RDY El pin ready se utiliza para decirle al microprocesador que tiene que frenar y mantener al mismo en el estado actual, para activarlo y que frene el pin espera un estado low. Por ejemplo al recibir un estado Low (o volts) en el pin todas las líneas de output van a mantener los valores de corriente que tenían mostrando qué dirección estaban buscando. 

PHI1 o 01 (OUT) Pin de Salida de Reloj, el mismo es una salida de reloj para conectar a otros dispositivos. El PHI1 es típicamente la señal del PHI2 pero invertida

IRQB Pin de interrupción. Al conectar este pin a 0V, si las interrupciones están habilitadas, el procesador guardará el contenido de los registros actuales y buscará en las posiciones de memoria FFFE y FFFF donde está el vector (otra posición de memoria) que posee la primera instrucción a ejecutar para atender a esta interrupción

MLB El pin de Memory lock se usa para mantener la integridad de las instrucciones Read-Modify-Write en un sistema multiprocesador. Cuando presenta un valor Low o 0 volts indicate que algún otro circuito debe arbitrar el ciclo del bus.

NMIB Pin de interrupción no enmascarable. Al conectar este pin a 0V el procesador guardará el contenido de los registros actuales y buscará en las posiciones de memoria FFFA y FFFB donde está el vector (otra posición de memoria) que posee la primera instrucción a ejecutar para atender a esta interrupción. Este tipo de interrupción es incondicional y siempre será honrada.

SYNC Pin de sincronía El ciclo del procesador donde trae el código de operación (OpCode) se indican con el pin SYNC en high. Cuando el procesador busca un código del operación el pin queda en high y queda high por todo el resto del ciclo

VDD o VCC Pin de Energia. El procesador típicamente trabaja con +5v 

AB0 a AB11 Pines del Bus de Direccionamiento. Son pines bidireccionales que permiten recibir las direcciones de los dispositivos a los cuales comunicarse (memorias, otros chip en la placa, registros de I/O, etc). Al ser un bus de 12 bits direcciona hasta 4096 bytes o desde $0000 hasta $1000 

VSS Pin de Ground, este pin se conecta al common ground del diseño.

DB0 a DB7 Pines del Bus de datos, Este es un bus bidireccional que permite recibir y escribir datos junto con el bit de R/W a memorias y registros de I/O

R/WB Pin de Lectura/Escritura. Este pin indica si el procesador está realizando una lectura o una escritura. Cuando se encuentra en 1 o en estado High el procesador está realizando una lectura cuando está en 0 o estado Low una escritura.

NC  No Connect, este es un pin que no se debe conectar ya que no está conectado a nada dentro del procesador

BE Pin de Bus Enable, cuando este pin esta High los pines de address, data y RW están activos, cuando está low quedan con impedancia alta sacando al procesador del bus.

PHI2 o 02 (OUT) Pin de Salida de Reloj, el mismos es una salida de reloj para conectar a otros dispositivos

SOB Pin de Set Overflow. Este pin cuando recibe un cambio de high a low prende el bit de Overflow en el Status Register del procesador (bit 6). No se uso mucho en el pasado y no se recomienda su uso.

PHI0 o 00 (IN) Pin de entrada de Reloj, Este pin permite conectar un reloj interno al procesador para sincronizarse con otros dispositivos.

RESB Pin de reset, este pin sirve para realizar un reset del procesador cuando se conecte a 0v. El reset tomará 7 ciclos de reloj y buscará en las posiciones de memoria FFFC y FFFD donde está el vector (otra posición de memoria) que posee la primera instrucción a ejecutar. El reset debe ser mantenido en 0v por lo menos durante dos ciclos de reloj para que sea reconocido.

Pin-Out 6510

Pines diferentes al 6502

PHI1 o 01 (IN) Pin de entrada de Reloj, Este pin permite conectar un reloj interno al procesador para sincronizarse con otros dispositivos. En el 6502 era el PHI0 y el 6510 sólo tiene 2 pines con respecto al reloj en lugar de los 3 que posee el 6502.

AEC Pin de Address Enable Control, se comporta de forma similar al pin de Bus Enable del 6502. Cuando este pin esta High los pines de address, data y RW están activos, cuando está low quedan con impedancia alta sacando al procesador del bus. Esto permite desarrollar sistemas con acceso directo a memoria por parte de otros chips o periféricos (DMA).

P0 a P5 Pines de I/o Port. Este procesador en su más marcada diferencia presenta en estos pines 6 conexiones bidireccionales con periféricos como si fuera un pequeño VIA o CIA. Vamos a explorar como funciona en detalle en un futuro artículo y video.

Pines idénticos al 6502

RDY El pin ready se utiliza para decirle al microprocesador que tiene que frenar y mantener al mismo en el estado actual, para activarlo y que frene el pin espera un estado low. Por ejemplo al recibir un estado Low (o volts) en el pin todas las líneas de output van a mantener los valores de corriente que tenían mostrando qué dirección estaban buscando. 

IRQ/ Pin de interrupción. Al conectar este pin a 0V, si las interrupciones están habilitadas, el procesador guardará el contenido de los registros actuales y buscará en las posiciones de memoria FFFE y FFFF donde está el vector (otra posición de memoria) que posee la primera instrucción a ejecutar para atender a esta interrupción

NMI/ Pin de interrupción no enmascarable. Al conectar este pin a 0V el procesador guardará el contenido de los registros actuales y buscará en las posiciones de memoria FFFA y FFFB donde está el vector (otra posición de memoria) que posee la primera instrucción a ejecutar para atender a esta interrupción. Este tipo de interrupción es incondicional y siempre será honrada.

VDD o VCC Pin de Energía. El procesador típicamente trabaja con +5v 

AB0 a AB11 Pines del Bus de Direccionamiento. Son pines bidireccionales que permiten recibir las direcciones de los dispositivos a los cuales comunicarse (memorias, otros chip en la placa, registros de I/O, etc). Al ser un bus de 12 bits direcciona hasta 4096 bytes o desde $0000 hasta $1000 

VSS Pin de Ground, este pin se conecta al common ground del diseño.

DB0 a DB7 Pines del Bus de datos, Este es un bus bidireccional que permite recibir y escribir datos junto con el bit de R/W a memorias y registros de I/O

R/W Pin de Lectura/Escritura. Este pin indica si el procesador está realizando una lectura o una escritura. Cuando se encuentra en 1 o en estado High el procesador está realizando una lectura cuando está en 0 o estado Low una escritura.

PHI2 o 02 (OUT) Pin de Salida de Reloj, el mismos es una salida de reloj para conectar a otros dispositivos

/RES Pin de reset, este pin sirve para realizar un reset del procesador cuando se conecte a 0v. El reset tomará 7 ciclos de reloj y buscará en las posiciones de memoria FFFC y FFFD donde está el vector (otra posición de memoria) que posee la primera instrucción a ejecutar. El reset debe ser mantenido en 0v por lo menos durante dos ciclos de reloj para que sea reconocido

Conectando al 6502 y al 6510

Para poder ver visualmente como es el esquema de conexión de pines de ambos procesadores les dejo un video donde vamos a repasar para que sirve cada pin y como conectarlo a un breadboard para en futuros videos poder programar ambos procesadores.

6502 vs 6510 Chip pin out – Parte 2

Artículos en la serie C64 a Fondo

A continuación el link al próximos artículo en la serie

Parte 3 – Codeando a Mano la Primera Instrucción de Código Máquina

y aquí los links a los artículos anteriores

Introducción

Parte 1 – El módulo de reloj

Referencias

A continuación les dejo algunos links donde profundizar el tema:

Video de la serie 6502 vs 6510 Parte 2 – Pin Out

6502 vs 6510 Chip pin out – Parte 2

W65C02S 8–bit Microprocessor 

6510 MICROPROCESSOR WITH I/O 

Todos los ejemplos de código de los videos los pueden encontrar en:

https://github.com/carlinhocr/6502_vs_6510

Y como siempre la serie de Ben Eater del 6502

Build a 6502 computer | Ben Eater 

C64 a Fondo – 6502 vs 6510 Parte 1 – El módulo de reloj

Vamos a empezar esta serie analizando que es un módulo de reloj o system clock, por qué se usa, como funciona el de la Commodore 64 a grandes rasgos y por qué vamos a usar otro módulo de reloj durante nuestro estudio.

Les dejo el link al articulo anterior en la serie, y al final como siempre los links a todos los artículos de la misma.

Introducción

¿Qué es un módulo de reloj?

Un módulo de reloj es un circuito electrónico que oscila generando una secuencia de pulsos repetitivos que llamaremos señal de reloj, estos pulsos son distribuidos a todos los elementos lógicos que tenemos en nuestra computadora para que se sincronicen.

¿Por qué se usa?

Porque generalmente nuestras computadoras trabajan con lógica sincrónica. Los gates o compuertas lógicas que usamos para operar sobre los datos tienen un tiempo finito de respuesta a los cambios en los inputs que reciben, esto se llama delay de propagación. 

El intervalo entre los pulsos del reloj tiene que ser suficientemente largo como para que los gates y sus salidas se establezcan en valores estables antes de que suceda el próximo pulso de reloj.

Cómo funciona el de la Commodore 64

Bienvenidos al infierno, digo a cómo funciona aproximadamente el reloj de la Commodore 64. Y digo aproximadamente por que en este post no vamos a describir el circuito en detalle pero sí algunos vericuetos interesantes.

Empecemos con un cristal llamado Y1, este nos da una resonancia mecánica desde la cuál vamos a llegar  a través de varios circuitos a los 1 Mhz a los que típicamente corre el 6510.

 

Ahora dependiendo de si la computadora es NTSC o PAL la frecuencia de la señal va a ser de aproximadamente 14,318 Mhz o 17,73 Mhz redondeando. 

A esta señal se conoce como el Color Clock por que al dividir estos números por 4 obtenemos 3.58 Mhz para NTSC y 4.43 Mhz para PAL las cuáles son las señales de carrier responsables de que cómo vemos los colores en nuestros televisores.

Un Circuito integrado conocido como el U31 Dual Voltage Controlled Oscillator nos genera otras frecuencias en 8.18 Mhz para NTSC y 7.88 Mhz para PAL, esta señal se conoce como el Dot Clock y nos dice cuántos píxeles se puede escribir por pantalla en cada refresh de la misma.

NTSC: 59.826Hz (refresh rate) * 520 Pixels * 263 lineas = 8.18MHz

PAL: 50.125Hz (refresh rate) * 504 Pixels * 312 lineas = 7.88MHz

Finalmente llegamos al System Clock que define que es un ciclo de CPU como la Commodore 64 es un máquina de 8 bits esto nos limita a mostrar hasta 8 píxeles por ciclo de CPU por lo que corresponde un ciclo de duración de un octavo de Dot Clock.

NTSC: 8.18MHz / 8 = 1.023MHz

PAL: 7.88MHz / 8 = 0.985Mhz

Llegando al máximo de velocidad de 1Mhz del 6510.

¿Por qué usamos otro reloj en nuestro estudio?

Si utilizáramos un reloj de 1 Mhz sería muy difícil ver que ocurre en la cpu por cada instrucción de nuestro programa. Los instrumentos que usamos para medir no podrían detectar fácilmente la variación de bits o impulsos eléctricos en los pines de address bus y no llegaríamos a comprender que sucede en cada paso. 

Por eso tenemos un reloj que nos permite parar la pelota e ir más lento, tan lento como queramos, inclusive pulsando un botón vamos a ir ciclo por ciclo de reloj e instrucción por instrucción.

Cómo funciona nuestro clock 

Vamos a utilizar el reloj del kit de Ben Eater. Este funciona con tres timer 555 y algunas compuertas and y or, en las referencias les dejo el detalle de como lo arma él en sus videos.

Este reloj nos permite a través de un switch decidir si queremos ir paso a paso cada ciclo de reloj pulsando un botón o usar un potenciómetro para dar la velocidad de las instrucciones.

Cómo Seguimos

Para ver visualmente como funciona el módulo de reloj y cómo corremos el osciloscopio para analizar sus variaciones les dejo el primer video de la serie

6502 vs 6510 Módulo de Reloj Manual – Parte 1

Artículos en la serie C64 a Fondo

A continuación el link al próximo artículo en la serie

Parte 1 – El módulo de reloj

y aquí los links a los artículos anteriores

Introducción

Referencias

A continuación les dejo tres excelentes artículos que hablan en profundidad del reloj de la Commodore 64.

Hardware Basics Part 1 – Tick Tock, know your Clock — Dustlayer

Hardware Basics Part 2 – A Complicated Relationship — Dustlayer

Clock Frequency

Y Cómo construir el módulo de Reloj por Ben Eater.

Clock module 

C64 a fondo – 6502 vs 6510

Hoy los quiero invitar a un viaje al interior de la Commodore 64 y sus chips donde vamos a ver en profundidad detalles de assembler, conexiones y funcionamiento, que me desvelaron desde chico, y creo que agregan mucho a nuestro conocimiento técnico. 

¿Por qué la Commodore? Bueno un poco por amor (un poco bastante ja) y otro por que pienso que es una de las últimas computadoras en las cuáles podemos llegar a entender en profundidad qué es lo que está pasando realmente por dentro cuando ejecutamos un programa, jugamos un juego o tocamos música con el SID. 

Todavía podemos ver los chips, medir las señales en sus patas, mirar donde hay una resistencia o un capacitor y entender por donde pasa la magia desde el programa a la acción.

Cómo conocí la Commodore 64.

Un día caminando por la calle con mi viejo a los 9 años, me recuerdo pidiéndole por enésima vez un Colecovision, el mismo que veía todas las noches en las propagandas de la trasnoche Kenya Sharp con el juego de pitufos. El se paró en el medio de la calle, me miró y me dijo:

¿Y si tuvieras una computadora mejor, que podés programar tus propios juegos?

Así llegó el 10 de Julio de 1987 mi Drean Commodore 64C, y también llegarían muchas horas de juegos de la mano de Commando, Ghost and Goblins, y  terminando en un Zack Mackraken allá por los 16 años. 

También llegaron muchas horas de programación en Basic y los libros de Data Becker (esos blancos y naranjas) con los que siempre me pasaba lo mismo. 

Comenzaba a leer ávido y en detalle esas letras apenas entendibles y pasaba la página 1, 2 (siempre introducciones), 5, 6 (ya empezaban a explicar binario y hexadecimal) e invariablemente en la página 16, ya no entendía nada. 

Que se necesitaba un monitor de código máquina, que tal cartucho, que el diskette (que no se comparaba con mi humilde datasette) y que me daban algún programa de ayuda que consistía en 20 páginas ilegibles con muchas instrucciones DATA que luego de tipearlo terminaban invariablemente en el nefasto:

"ERROR EN LOS DATA".

Luego de esta frustración me iba a Atarilin a conseguir algún juego nuevo de la mano de Carlos y Alejandro, de los que siempre venía alguna palabra de aliento,y volvía a mis 10 minutos de carga del datasette y a jugar un par de horas, la resiliencia de los 11 años.

Esa misma resiliencia me hacía al mes volver a comprar un nuevo libro de Data Becker y volver a empezar el ciclo, así pasaron “Peeks y Pokes para el Commodore 64”, “Gráficos para el Commodore 64”, “64 consejos y trucos” pero nunca llega al soñado “64 interno” considerado sólo para expertos a esa tierna edad.

El retorno del Commodoriano

El año pasado (2022) repasando el libro Make Electronics me tope con los videos de youtube de Ben Eater, un verdadero demente que hizo una computadora sólo con breadboards y utilizando el 6502 como procesador, sus videos muy bien explicados, y la posibilidad de comprar kits con todo lo necesario para armarlos y seguirlos paso a paso me llevo a tirarme de lleno a contestar las preguntas que me torturaban desde chico:

 ¿Cómo funcionaba la Commodore? ¿Cómo cargaba una instrucción desde el código máquina al procesador? ¿Cómo se ejecutaba?

Compré los kits y mientras los esperaba compre una Commodore 64 por mercado libre, la prendo con su fuente original (no lo hagan en sus casas niños si no quieren quemarla) y me daba un hermoso error con todos ceros en la pantalla y un OUT OF MEMORY ERROR.

Lo pensé, decidí quedármela y aprovecharlo como la oportunidad para arreglarla y aprender a fondo cómo funciona por dentro esta computadora.

6502 vs 6510

Y así nace esta serie, donde comparo cómo funciona el procesador 6502 (usado en Apple , Atari, etc) y el 6510 de nuestra querida Commodore 64 que en apariencia son iguales pero tienen sutiles y fundamentales diferencias.

Uso como guía los videos de Ben Eater (Build a 6502 computer | Ben Eater ) agregando estudios del 6510 y la Commodore 64.

Con esta serie de blogspot y videos que armé para acompañarlos y vamos a explorar desde el pin out hasta los registros internos del 6510, pasando por sus puertos de I/O, como cargarle una instrucción en código máquina a mano y llegando hasta conectarle una eeprom con varias instrucciones para que ejecute un programa de nuestra autoría.

Espero me acompañen en este viaje para contestar estas preguntas que me hacía desde pequeño y conocer a fondo estos procesadores.

Siganme en este apasionante viaje empezando por el próximo artículo,

Parte 1 – El módulo de reloj

Artículos en la serie C64 a Fondo

A continuación los links a todos los artículos de la serie

Introducción

Parte 1 – El módulo de reloj

Parte 2 – Pinout 6510 y 6502

Parte 3 – Codeando a Mano la Primera Instrucción de Código Máquina

Parte 4 – Primer Programa desde EEPROM

Parte 5 – I/O Pins del procesador 6510

BASIC – 8 – Animaciones (3)

Con todo lo aprendido en los post anteriores vamos a realizar una pequeña animación. Para ello definiremos 2 sprites, que serán los frames del famosisimo Space Invaders:

El programa que estoy utilizando aquí es C64 Studio, un IDE de programación que entre otras cosas trae un sencillo editor de sprites que me permite exportar los DATA a lineas de BASIC, y lo pueden descargar desde aquí: https://www.georg-rottensteiner.de/en/index.html

Luego cargaremos estos valores a partir de la memoria 12288, que corresponden a los punteros 192 y 193. Para hacer una animación solamente tenemos que implementar un loop FOR, y alternamos estos valores en cada iteración.
La parte interesante que la podemos ver a continuación:

100 for sx = 24 to 255
110 poke v,sx
120 poke 2040,192 + ((sx and 8) / 8)
130 next 

El loop se encuentra entre las lineas 100-130, en la linea 110 se va actualizando la posición y en la linea 120 se especifica que frame mostrar segun esa posición.
El truco aquí esta en “+ ((sx and 8) / 8)”: este código toma el valor 1 o 0 segun el estado del bit 3 en la variable sx.
De esta forma las primeras 8 posiciones tomaran el valor 0, lo que hará que el puntero quede seteado en la posición 192, en las siguientes 8 posiciones quedará en 1, por lo que el puntero sera 193, en las siguientes 8 volverá a 0 … y así indefinidamente.
Si quisiéramos que la animacion se reproduzca mas rápido podemos checkear el estado de los bits de menor peso y si queremos que se reproduzca mas lento chequeamos los bits de mayor peso.
Aqui podemos ver como se ve nuestro alien animado:

y el listado completo a continuación:

10 v=53248 
20 poke v+21,1
30 poke 2040,192
40 for t=12288 to 12414
50 read n
60 poke t,n
70 next
80 poke v+39,1
90 poke v+1,75

100 for sx = 24 to 255
110 poke v,sx
120 poke 2040,192 + ((sx and 8) / 8)
130 next 

150 for sx = 255 to 24 step -1
160 poke v,sx
170 poke 2040,192 + ((sx and 8) / 8)
180 next 

200 goto 100

1000 data 14,7,0,14,7,0,3,12
1010 data 0,3,12,0,15,255,0,15
1020 data 255,0,60,243,192,60,243,192
1030 data 255,255,240,255,255,240,207,255
1040 data 48,207,255,48,204,3,48,204
1050 data 3,48,7,158,0,7,158,0
1060 data 0,0,0,0,0,0,0,0
1070 data 0,0,0,0,0,0,0,1
1080 data 14,7,0,14,7,0,195,12
1090 data 48,195,12,48,207,255,48,207
1100 data 255,48,252,243,240,252,243,240
1110 data 255,255,240,255,255,240,63,255
1120 data 192,63,255,192,28,3,128,28
1130 data 3,128,48,0,192,48,0,192
1140 data 0,0,0,0,0,0,0,0
1150 data 0,0,0,0,0,0,0,1

Y esto es todo por hoy, nos vemos en la próxima entrega!

BASIC – 7 – Sprites (2)

En el post anterior vimos como activar un sprite, como seleccionar el area de memoria que dara la forma a nuestro sprite, y lo posicionamos en la pantalla.
Hoy vamos a darle la forma definitiva, para ello tenemos 2 vias:

  1. Usar un editor de sprites, que nos genere los numeros necesarios
  2. Hacerlo a mano

Hoy vamos a optar por la segunda opción, mas que nada para aprender como se hacía a la antigüa usanza, despues podremos utilizar multitud de programas que nos permiten dibujar comodamente y exportar los datos al formato que deseemos

Los sprites en la C64 poseen un tamaño de 24 x 21 pixels, lo que nos da 3 bytes (24px) por 21 = 63 bytes.
Para definir un sprite “a la antigüa” dibujaremos una cuadricula de 24×21, agrupando en columnas de 8 pixels. Luego pintaremos las casillas con los puntos que componen nuestro gráfico, para finalmente convertir cada grupo de 8 pixels en un byte.
Por ejemplo, aqui tenemos un circulo solido relleno:

Cada grupo de 8 bits los convertimos primero a binario, y luego a decimal (podemos utilizar la calculadora de windows, seteandola en modo programador), de forma que el primer byte es 00000000, que en decimal es “0”, el segundo 01111110 es “126” en decimal, y asi con el resto.
A continuación tenemos el programa completo, con los 63 bytes que definen nuestra “pelota”.

10 v=53248
20 pokev+21,1: rem activamos sprite numero 1
30 poke2040,192: rem direccion de inicio 12288
40 fort=12288to12350 : rem leemos los 63 valores
45 read n
50 poke t,n
60 next
70 pokev+39,1: rem elegimos color blanco
80 pokev,100: rem posicion horizontal 100
90 pokev+1,110: rem posicion vertical 110
100 data 0, 126, 0
110 data 3,255,192
120 data 7,255,224
130 data 31,255,248
140 data 31,255,248
150 data 63,255,252
160 data 127,255,254
170 data 127,255,254
180 data 255,255,255
190 data 255,255,255
210 data 255,255,255
220 data 255,255,255
230 data 255,255,255
240 data 127,255,254
250 data 127,255,254
260 data 63,255,252
270 data 31,255,248
280 data 31,255,248
290 data 7,255,224
300 data 3,255,192
310 data 0, 126, 0

Ademas de poder posicionar nuestro sprite en cualquier parte de la pantalla, tambien podemos elegirle un color, expandirlo al doble a lo ancho, o alto, o ambos.
Para darle un color utilizaremo el registro 39 (v + 39 seria) y un número entre 0 y 15 para especificar que color queremos asignarle

Para expandir a lo ancho tenemos el registro 29, y para expandir a lo alto el registro 23. Cada uno de estos registros son de 8 bits, y cada bit se corresponde con el sprite que queremos expandir, así que por ejemplo, si queremos expandir el sprite 1 a lo ancho deberiamos tipear POKE V+29,1
y si queremos expandir el sprite 8 a lo alto lo hacemos con POKE V+23,128
Aqui podemos ver como jugamos un poco con estos registros:
Y con esto tenemos suficiente por hoy. Nos vemos en el proximo capitulo!

BASIC – 6 – SPRITES (1)

Los sprites en la C64 son objetos que podemos definir como nosotros deseemos, y que se pueden posicionar en cualquier parte de la pantalla. Al ser manejados por hardware no tenemos que preocuparnos por preservar el fondo de pantalla, ni mover bytes, pintarlos ni nada que en otras computadoras es tarea corriente.
La C64 puede manejar hasta 8 sprites, y cada uno de ellos se les puede asignar un color independiente, expandirlos en el eje X o Y, posicionarlos en cualquier parte de la pantalla, y un monton de cosas mas.
Cada sprite tiene un tamaño de 24×21 pixels, y ocupa 63 bytes en memoria

En este pequeño ejemplo vamos a definir un sprite cuadrado (todo con el valor 255, que en binario es 11111111), y vamos a ver como lo podemos mover, expandir y cambiar el color.
Primero vamos a ingresar este programa en la c64, con el que vamos a poder ejemplificar varios conceptos 😀

10 v=53248 
20 poke v+21,1
30 poke 2040,16
40 for t=1024 to 1087
50 poke t,255
60 next
70 poke v,100
80 poke v+1,110

En la primera linea seteamos la variable v con el valor 53248. Este valor corresponde al primer registro de los 46 que posee el chip de video de la C64 (el VIC2). De esta manera solamente tenemos que recordar una posición de memoria, y ciertos registros claves.
El primer registro aparece en la linea 20, el número 21, y corresponde al numero de sprite activo, en este caso el número 1. Luego aparece una dirección de memoria (2040) con el que podemos especificar que segmento de la memoria del VIC2 queremos utilizar para definir la forma de nuestro sprite.

NOTA acerca del direccionamiento de memoria del VIC2:
Si bien el 6510 (el microprocesador de la C64) puede direccionar hasta 64kb de memoria, el VIC2 solo puede direccionar 16kb. Por razones que escapan a esta introducción, el VIC2 se puede configurar para que utilize cualquiera de los 4 bancos de 16Kb, y por defecto cuando encendemos la C64 esta configurado para trabajar en el banco 0 (el bloque de memoria que va de 0 a 16384)

En la dirección de memoria 2040, entonces, podemos especificar el lugar donde se almacenarán los valores que daran forma a nuestro Sprite, en segmentos de 64 bytes. Para nuestro ejemplo utilizamos el valor 16, que multiplicado por 64 nos da … 1024… mhmmm..
Eso lo vimos en un post anterior, en el que imprimíamos en pantalla utilizando POKEs directamente en la dirección de video del VIC2.
La idea de utilizar la memoria de video es mostrar como se va llenando la memoria con los valores que necesita el sprite (lineas 40 – 60), y como podemos modificarlos y ver como se reflejan esas modificaciones en la figura del sprite. Por supuesto que en un juego real no vamos a utilizar esa direccion, porque donde borramos la pantalla o actualizamos cualquier valor se nos rompe el sprite.
Finalmente en las lineas 70 y 80 posicionamos el sprite en pantalla.
Si ejecutamos el programa obtendremos el siguiente resultado (observen como se modifica el sprite cuando altero las 2 primeras lineas de texto en pantalla)

Observese tambien que se ve un puntito que representa el cursor.
En la siguiente entrega ya vamos a darle una forma mejor, y vamos a mostrar el uso de los diferentes registros.

BASIC – 5 – Leer el joystick para mover objetos

En el post anterior vimos como mover un caracter por la pantalla, pero habia algunas limitaciones, como por ejemplo que no podiamos realizar diagonales, y que cada vez que queríamos avanzar debíamos pulsar repetidamente las teclas.

Hoy vamos a hacer el mismo programa, pero controlando la pelota con el joystick conectado en el port 2, pero primero… un poco de teoria.

Para leer las posiciones del joystick tenemos las posiciones de memoria 56321 (port 1) y 56320 (port 2).
los bits 0,1,2,3 corresponden a las direcciones (arriba, abajo, izquierda, derecha) y el bit 4 corresponde al boton de disparo.
Estando el joystick en posicion central, sin pulsar disparo estas direcciones nos devuelven el valor 127, que corresponde a %01111111, y a medida que vamos moviendo el joystick y pulsando el disparo se ponen en 0 los bits correspondientes.
Podemos ver rapidamente como se comportan los valores con un sencillo programita de 3 lineas

20 j=peek(56320)
30 print j
40 goto 20

Copia este programa y cuando lo ejecutes comenzara a imprimir el valor 127. Conecta un joystick al port 2 y veras como varia este valor segun las direcciones que muevas.

Vamos ahora si con el programa de la bola modificado para joystick

10 x = 10: y = 10
20 poke 1024 + (40 * y)+ x, 81
30 j = not(peek(56320)) and 127
40 if j = 0 then 30
50 poke 1024 + (40 * y)+ x, 32
60 dx = -((j and 4) / 4) + ((j and 8) / 8)
70 dy = -(j and 1) + ((j and 2) / 2)
80 x = x + dx: y = y + dy
90 poke 1024 + (40 * y)+ x, 81
100 goto 30

Como es usual, primero definimos en la linea 10 la posicion inicial en pantalla, y a continuacion imprimimos la bola. A continuacion leemos el valor del port 2 y, para poder hacer unas operaciones despues, vamos a invertir los bits, y poner el bit 7 en 0 (con esto lo que logramos es que cuando pulsemos el bit se ponga en 1, en vez de 0)

Las otras lineas interesantes son la 60 / 70, que obtienen el valor dx / dy haciendo unos calculos. La ventaja de hacerlo de esta manera sobre el tradicional chequeo de IFs es que ocupa menos lugar (importantisimo) y que ya nos resuelve la deteccion de diagonales (con estas 2 lineas evitamos 8 lineas de IFs)

En la linea 80 actualizamos las posiciones, luego imprimimos la bola, y vuelta a chequear el valor del port 2.
A continuacion podemos ver la diferencia con el programa anterior

El proximo post vamos a comenzar a utilizar sprites. Hasta la próxima!

BASIC – 4 – Leer el teclado para mover cosas

El BASIC de la C64 nos provee 2 instrucciones para ingresar información desde el teclado:

  1. INPUT : Para casos en los que queremos ingresar un nombre o un valor numérico
  2. GET : para cuando necesitamos detectar solo la pulsación de una tecla

Para lo que queremos hacer ahora vamos a utilizar el comando GET. El modo de uso es muy simple, solo toma como parámetro la variable en la que queremos que coloque el valor de la tecla pulsada.
Con este pequeño ejemplo vemos como funciona:

10 get a$
20 print a$;
30 goto 10

Si ejecutamos aparentemente no realiza nada, pero si pulsamos una tecla aparecera su correspondiente letra en la pantalla. Lo que esta haciendo aqui es un loop infinito en el que lee el valor de la tecla pulsada, lo imprime, y vuelve a leer, asi indefinidamente.
Con todo esto podemos hacer nuestro programita en el que controlamos una bola

10 px% = 10: py% = 10
20 a$ = ""
30 get a$ : if a$="" then 100
40 poke 1024+(py%*40)+px%,32
50 if a$="d" then px%=px%+1
60 if a$="a" then px%=px%-1
70 if a$="s" then py%=py%+1
80 if a$="w" then py%=py%-1
90 poke 1024+(py%*40)+px%,81
100 goto 30

Nuevamente definimos nuestras variables de posición, luego leemos el valor de la tecla pulsada, y si no se detecto ninguna salteamos la parte de código que mueve nuestro personaje.
Esto tal vez no tenga demasiado sentido en este ejemplo, pero en juegos mas complejos esta bueno que si no se pulsa ninguna tecla se puedan hacer otras cosas (no tiene sentido volver a imprimir el personaje en la misma posición)

En las siguientes lineas borramos la bola de la posición anterior (el caracter 32 es el Espacio), comprobamos si se pulsó alguna de las teclas W, A, S, D, e imprimimos la bola en la posición actualizada.
NOTA: se podria optimizar mucho más este ejemplo, pero a efectos didácticos vamos a mantenerlo simple.

Y así es como queda:

Agregando una cola que vaya guardando las posiciones anteriores podemos implementar un juego tipo Nibbles, o cualquier cosa que necesitemos mover por la pantalla

BASIC – 3 – Imprimiendo En Pantalla (2)

Vimos en el post anterior que tenemos 2 formas de imprimir en pantalla: con el comando PRINT tradicional o directamente cargando valores en la memoria de video.

La memoria de video de la C64 se compone (simplificando mucho, para lo que queremos explicar) de una matriz de 40 columnas por 25 filas de caracteres, lo que nos da un total de 1000 caracteres. En cualquiera de estas posiciones podemos imprimir lo que deseemos, simplemente colocando el valor correcto.

La posición de memoria 1024 es el inicio de nuestra memoria de video. En ella se encuentra el caracter que corresponde a la esquina superior izquierda de la pantalla, y a medida que vamos incrementando esta posición los caracteres van llenando la pantalla.


Para muestra, vale este pequeño ejemplo:

10 for x = 0 to 1000
20 poke 1024 + x, 81
30 next

Aqui podemos ver como se va llenando la pantalla, de izquierda a derecha, las 1000 posiciones de la misma.


¿Y si queremos posicionar algo? Es muy sencillo, simplemente con esta formula:

m = 1024 + (40 * py) + px

Donde m es la posición de memoria, px es la columna y py es la fila donde queremos posicionar nuestro gráfico. Con toda esta información podemos escribir un pequeño programita que nos dibuja una pelota rebotando por la pantalla:

10 px% = 10: py% = 10: dx% = 1: dy% = 1
20 poke 1024+(py%*40)+px%,32
30 px% = px% + dx%
40 py% = py% + dy%
50 if px%=39 then dx% = -dx%
60 if px%=0 then dx% = -dx%
70 if py%=24 then dy% = -dy%
80 if py%=0 then dy% = -dy%
90 poke 1024+(py%*40)+px%,81
100 goto 20

px y py son la posición de la pelota; dx y dy su dirección.


Inmediatamente pintamos un espacio, porque si no lo hacemos la pelota nos dejará una estela de pelotas, luego incrementamos la posicion según la dirección en la que está yendo, hacemos las comprobaciones para que no salga de la pantalla, y finalmente imprimimos la pelota… y reinicia el ciclo.

Y el resultado es el siguiente… bueno, mas o menos, la captura de pantallas esta hecha a 15 cuadros (frames) por segundo, lo que hace que la pelota desaparezca un poco.

Partiendo de este código se puede realizar un clon de breakout o similar

En el próximo post vamos a ver como leer el teclado, ycontrolar con WASD nuestra bola

BASIC – 2 – Imprimiendo en pantalla (1)

Para imprimir letras o los simbolos gráficos predefinidos en nuestra C64 tenemos 2 formas de hacerlo:

  1. con el comando PRINT de toda la vida
  2. accediendo directamente a la memoria de video

El comando PRINT nos permite imprimir una cadena de texto que le pasaremos entre comillas dobles
Ej: si tipeamos PRINT “HOLA MUNDO” nos imprime HOLA MUNDO en la pantalla, en la posición del cursor.

Es muy práctico cuando tenemos que imprimir texto, pero se puede llegar a complicar si queremos posicionar algo en la pantalla, ya que el BASIC de la C64 no tiene un comando para posicionar el cursor en la pantalla rapidamente.

Podemos, sin embargo, usar la instruccion SPC(n), que nos genera n espacios. No es exactamente para posicionar, pero podemos utilizarla para este fin en algunos casos, como por ejemplo:

1 rem carretera endiablada
10 x% = 10
20 a% = rnd(0) * 3 - 1
30 x% = x% + a%
40 if (x% > 28) then x% = 28
50 if (x% < 0) then x% = 0
60 print spc(x%); "o      o"
70 goto 20

Este pequeño programita de 7 líneas nos genera una carretera con scroll, como podemos ver en el siguiente video:

El programa es muy simple:
  • Las líneas 10-20 definen posición del camino y dirección que tomará (el signo % al lado de las variables las define como “integer” (o “número entero”, sin decimal), tener en cuenta porque si no por defecto son “float” ( o “número de punto flotante”, es decir, con decimal), y todas las operaciones son más lentas)
  • En la línea 30 ajusta la posición del camino según la dirección al azar que tomó.
  • En las líneas 40 y 50 se realizan comprobaciones para que no se salga de la pantalla.
  • La línea 60 imprime el camino.
  • … y finalmente vuelve a repetir el ciclo desde la línea 20, saltando a este punto con GOTO.

En el próximo post veremos como imprimir accediendo directamente a la memoria de video