En el ejemplo anterior ocupamos la instrucción STA (STore Acum) para copiar el valor de A en memoria. Los que estaban atentos se deben haber fijado que al momento de indicar la posición de memoria a ocupar, usamos sólo un byte: 133 para el STA y 212 para indicar la posición de memoria.
1536 133 212 STA 212
Esto nos permitiría escribir en las primeras 255 posiciones de memoria, pero qué pasa si queremos ocupar las posiciones más allá de la 255? La respuesta es simple si se entendió la forma en que el ATARI representa números que requieren más de un byte. Inocentemente podríamos pensar que para escribir en la posición 26628 (L=4, H=104) podriamos usar
1536 133 4 104 STA 260
Pero entonces cómo el 6502 discriminaría si usaremos uno o dos bytes para indicar la dirección?. Lo cierto es que NO discrimina, para el 6502 el codigo de arriba sería interpretado como:
1536 133 4 STA 4 1538 104 PLA
Para resolver este problema, el 6502 tiene un set de instrucciones que ocupa direcciones de 8 bits, y otro set de instrucciones para ocupar direcciones de 16 bits. En el caso del valor 133, se trata de la versión de STA que ocupa 8 bits como dirección
Nota: A estas instrucciones se le llama PAGE-ZERO porque acceden a la primera página de memoria, la página cero, en donde cada página corresponde a 256 bytes. De lo anterior, se deduce que la memoria del atari tiene 256 páginas de 256 bytes cada una = 65536 bytes o 64KBytes.
Entonces, así como existe un STA para direcciones de 8 bits, existe también un STA para direcciones de 16 bits. En este caso y siguiendo la tabla de códigos del 6502 vemos que el 141 corresponde al STA de 16 bits.
Por lo tanto, para escribir STA 26628 el código será
1536 141 4 104 STA 26628
Acceso simple al video
El sistema operativo del Atari mantiene los colores que estamos usando en una zona específica de memoria. Recordemos que en una pantalla normal, se define que hay un color de borde, un color de fondo y distintos colores utilizados para trazar gráficos o texto.
Para este ejemplo usaremos la posición 710 que corresponde al color de fondo de la pantalla. Desde BASIC podemos modificar el valor almacenado en esta posición y el color de la pantalla cambiará.
Por ejemplo, este POKE dejará el fondo en negro
POKE 710, 0
Este ejemplo dejará el fondo en gris
POKE 710, 4
Y este ejemplo dejará el fondo en verde
POKE 710, 214
El cálculo que usa el chip de video para saber de qué color estamos hablando es el siguiente:
Color*16 + Luminosidad
En donde luminosidad y color pueden tomar valores entre 0 y 15. Los alumnos aplicados se darán cuenta de que los 8 bits de la posición 710 se agrupan en un par de valores de 4 bits, en donde los 4 bits menos significativos representan la luminosidad y los 4 bits más significativos representan el color.
bit 76543210 ^^^^^^^^ |||||||| ****|||| <-- color **** <-- luminosidad
Por lo tanto en los ejemplos anteriores el cero corresponde a GRIS con luminosidad CERO. El 4 corresponde a GRIS con luminosidad 4 y el 214 corresponde a VERDE (13) con luminosidad 6 (13*16 + 6).
Un progama simple en Assembler que modifique el color de fondo sería el equivalente al POKE, por lo tanto recurrimos a nuestro amigo STA ahora aplicado a una dirección de 16 bit (710)
El programa equivalente a decir POKE 710, 214 quedaría así:
1536 104 PLA 1537 169 214 LDA #214 1539 141 198 2 STA 710 1542 96 RTS
Es muy similar a lo que ya hemos hecho con la diferencia que ahora usamos el STA de 16 bits para llegar a la dirección 710 (198 + 2*256), y la otra diferencia es que en termino de resultados, por fin vemos algo un poco más atractivo.
10 TRAP 20: FOR I=0 TO 255: READ D: POKE 1536+I, D: NEXT I 20 PRINT USR(1536) 30 DATA 104, 169, 214, 141, 198, 2, 96
Jugando con el color
El programa anterior es bastante estático, porque sólo cambia una vez el color. Podemos modificar un poco el programa para que sean distintos los colores que aparezcan en pantalla.
Para lograrlo podemos usar cualquier valor que vaya cambiando, uno que está a la mano es la posición de memoria 20 que es un contador de frames. Este contador se incrementa una vez por cada frame (refresco) de pantalla. Entonces lo que tendríamos que hacer es tomar el valor del contador y ponerlo en el registro que tiene el color de fondo de la pantalla
1536 104 PLA 1537 165 20 LDA 20 1539 141 192 2 STA 710 1542 71 1 6 JMP 1537 1545 96 RTS
Esta rutina usa una variante del LDA que ya conocemos. En este caso en vez de asignar el valor 20 al registro A, lo que hace es tomar el valor almacenado en la posición de memoria 20, que corresponde al contador de frames.
El LDA que estuvimos usando hasta ahora tenía un signo #, lo que significa que el valor a asignar es el que se indica a continuación, este modo se llama modo inmediato. En cambio el LDA de ahora no tiene signo #, lo que indica que el valor se va a tomar de una dirección de memoria, en este caso corresponde a la dirección de memoria 20 que sólo require 1 byte (Page Zero). El LDA inmediato se codifica como 169, mientras que el LDA que toma el valor de memoria desde la página cero corresponde al 165.
Otra forma de entender la diferencia entre el modo inmediato y el acceso a memoria es el siguiente código BASIC
10 A = 20: REM Modo inmediato 20 A = PEEK(20): REM Lectura de memoria en la posición 20.
En la posición 1542 encontramos una nueva instrucción. Se trata de JMP (JuMP), que es nada más y nada menos que un GO TO. El JMP hará que el 6502 salte a ejecutar la dirección indicada como parámetro. Por lo tanto esta rutina quedará iterando entre la posición 1537 y la 1542 para siempre, o hasta que presionemos RESET o apagemos el computador. La instrucción RTS en 1545 nunca se ejecutará.
Nuestro programa BASIC ahora será:
10 TRAP 20: FOR I=0 TO 255: READ D: POKE 1536+I, D: NEXT I 20 PRINT USR(1536) 30 DATA 104, 165, 20, 141, 198, 2, 76, 1, 6, 96
Ver video con resultado AtariAsmDemo01.
Como muestra el video, se ve una especie de «flash» de colores. Lo que está sucediendo en realidad es que al ir incrementando el contador de frames, va aumentando la luminancia, y cada vez que se traspasa un múltiplo de 16, se va cambiando de color. Por ejemplo entre el 0 y el 15 veremos 15 luminosidades de gris, desde el negro al blanco, luego comienzan las 16 luminosidades de café, etc.
Operaciones booleanas
La rutina que acabamos de hacer también nos puede servir para ver cómo funcionan las operaciones booleanas en el 6502. Por ejemplo si quisieramos que el color siempre se mantuviera y sólo se cambiara la luminosidad, podriamos eliminar todos los bits en donde viene el color y dejar sólo los de la luminosidad.
Manos a la obra:
1536 104 PLA 1537 165 20 LDA 20 1539 41 15 AND #15 1541 9 208 ORA #208 1543 141 192 2 STA 710 1547 71 1 6 JMP 1537 1551 96 RTS
El programa es muy similar a lo que ya teníamos, pero en vez de copiar el valor que obtuvimos del contador de frames directamente en el registro de color, le hacemos un par de modificaciones:
1539 41 15 AND #15 ; En binario es 00001111. Esto elimina los bits del color y deja sólo los de luminancia 1541 8 208 ORA #208 ; Agregamos 11010000 que corresponde a los tonos verdes
Por ejemplo, si el valor leido es 33, que corresponde al color 2, luminosidad 1 (2*16 + 1), estas serían las modificaciones
A = 0010 0001 A = 0000 0001 ; por el AND #15 se eliminaran los 4 bits superiores A = 1101 0001 ; por el ORA #208 se agregarán 4 nuevos bits superiores
Como pueden observar, todas las modificaciones se hicieron sobre el valor almacenado en el registro A, por algo se llama acumulador. Finalmente el valor resultante que quedó en A se deja en el registro de color.
Programa BASIC modificado:
10 TRAP 20: FOR I=0 TO 255: READ D: POKE 1536+I, D: NEXT I 20 PRINT USR(1536) 30 DATA 104, 165, 20, 41, 15, 9, 208, 141, 198, 2, 76, 1, 6, 96
Ver video con resultado AtariAsmDemo02.
Como podrán ver en el video, después de ejecutarlo la primera vez con el color verde/amarillo, le cambio el valor del color en el ORA para que use otro color.