Página 1
Página 1 - Página 2 - Página 3 - Página 4 - Página 5 - Página 6
1a - 1b - 1c - 2a - 2b - 2c -2d -2e - 2f - 3a - 3b - 3c - 4a - 4b - 5 translate this page Partiendo del conocimiento de los Mnemónicos de las instrucciones del 6510 y de algunas de las direcciones de memoria del Commodore 64 vamos realizar una serie de prácticas que nos ayudarán a aprender a programar en este entorno, utilizando como herramienta el ensamblador Turbo Assembler.
Página Cero
Basic ROM
Kernal ROM
VIC II
SID
CIA
A = Acumulador X = Registro X Y = Registro Y Nº 1a.- Alternar blanco y negro en el fondo y el borde
Por Wanja Gayk en GO64! Magazine
* = $2000 ; SYS 8192. INICIO LDA #$00 ; Carga A con #$00, que es el código del color negro. STA $D020 ; Guarda el valor #$00 en la dirección $D020, que corresponde al borde de la pantalla. STA $D021 ; Guarda el valor #$00 en la dirección $D021, que corresponde al fondo de la pantalla. LDA #$01 ; Carga A con #$01, que es el código del color blanco. STA $D020 ; Guarda el valor #$01 en la dirección $D020. STA $D021 ; Guarda el valor #$01 en la dirección $D021. JMP INICIO ; Salta a INICIO produciendo un bucle infinito.
Para entender más: Código de colores
Para aprender más: Cambia los colores. Añade más líneas con otros colores. Sólo cambia el color del borde. Sólo cambia el color del fondo.Otra posible aplicación consiste en:
Nº 1b.- Arco iris
Por Richard_tnd en http://www.redizajn.sk/tnd64/assemble_it.html
* = $1000 ; SYS 4096. SEI ; Prohíbe las interrupciones IRQ, necesario para evitar que la CPU se centre en "otras cosas". BUCLE INC $D020 ; Incrementa el valor de la dirección $D020, que corresponde al borde de la pantalla. Este incremento, junto con un bucle, produce un efecto de colores. LDA $DC01 ; Carga A con el valor de la dirección $DC01 que corresponde al adaptador de interface CIA 1, encargado de leer el teclado y el joystick en el puerto 1. CMP #$EF ; Compara el valor de A con #$EF, que es el código de la tecla ESPACIO o del botón FIRE del joystick en el puerto 1. BNE BUCLE ; Salta a BUCLE hasta que se pulse ESPACIO o FIRE. RTS ; Entonces retorna al BASIC. Para entender más: $DC00 - $DC01
Para aprender más: Incrementa el fondo. Incrementa el borde y el fondo. Haz lo mismo pulsando FIRE en el joystick en el puerto 2 (situado en $DC00 y comparándolo con #$6F).En relación con este programa hemos descubierto una variante que consiste en:
Nº 1c.- Arco iris
Por fermhg, canal #c64 del irc-hispano
* = $1000 ; SYS 4096. SEI ; Prohíbe las interrupciones IRQ, necesario para evitar que la CPU se centre en "otras cosas". BUCLE INC $D020 ; Incrementa el valor de la dirección $D020, que corresponde al borde de la pantalla. Este incremento, junto con un bucle, produce un efecto de colores. LDA #$DF ; Carga A con #$DF, que desactiva el bit 5. STA $DC00 ; Guarda el valor #$DF en la dirección $DC00, que corresponde al adaptador de interface CIA 1, que define un grupo de teclas, entre las cuales está la tecla @. LDA $DC01 ; Carga A con el valor de la dirección $DC01, que corresponde al adaptador de interface CIA 1, encargado de leer ese grupo de teclas. CMP #$BF ; Compara el valor de A con #$BF, que es el código de la tecla @. BNE BUCLE ; Salta a BUCLE hasta que se pulse la tecla @. RTS ; Entonces retorna al BASIC. Para entender más: Keyboard Column Values
Para aprender más: Incrementa el fondo. Incrementa el borde y el fondo. Haz lo mismo pulsando otras teclas.Nº 2a.- Llenado de la pantalla con un caracter
Por John P. Gibbons
* = $1000 ; SYS 4096. LDX #$00 ; Carga X con #$00, que es el valor inicial de un bucle. BUCLE LDA #$24 ; Carga A con #$24 , que corresponde al caracter $. STA $0400,X ; Guarda el valor #$24 en la posición $0400 y siguientes #255 del mapa de memoria de pantalla. STA $0500,X ; Guarda el valor #$24 en la posición $0500 y siguientes #255. STA $0600,X ; Guarda el valor #$24 en la posición $0600 y siguientes #255. STA $0700,X ; Guarda el valor #$24 en la posición $0700 y siguientes #255, con lo que se llenaría toda la pantalla. LDA #$0D ; Carga A con #$0D, que corresponde al color verde claro. STA $D800,X ; Guarda el valor #$0D en la posición $D800 y siguientes #255 del mapa de colores de pantalla. STA $D900,X ; Guarda el valor #$0D en la posición $D900 y siguientes #255. STA $DA00,X ; Guarda el valor #$0D en la posición $DA00 y siguientes #255 STA $DB00,X ; Guarda el valor #$0D en la posición $DB00 y siguientes #255. DEX ; Decrementa el valor de X. BNE LP ; Salta a BUCLE hasta que el valor de X=#$00. RTS ; Entonces retorna al BASIC.
Para entender más: Código de caracteres en pantalla y código de colores
Para aprender más: Cambia los caracteres. Cambia los colores.Una segunda aplicación del anterior programa consiste en:
Nº 2b.- Llenado de la Pantalla con un Caracter
En http://c64.nostalgia.pl/, fermhg, canal #c64 del irc-hispano
* = $1000 ; SYS 4096. LDA #$00 ; Carga A con #$00, que corresponde al byte bajo de la dirección $0400. STA $FB ; Guarda el valor #$00 en la dirección $FB, que es el vector del byte bajo. LDA #$04 ; Carga A con #$04, que corresponde al byte alto de la dirección $0400. STA $FC ; Guarda el valor #$04 en la dirección $FC, que es el vector del byte alto. LDA #"*" ; Carga A con el código del caracter "*". LDY #$00 ; Carga Y con #$00, que es el valor inicial de un bucle. BUCLE STA ($FB),Y ; Guarda el código del carácter * en la posición $0400 y siguientes #1023. INY ; Incrementa el valor de Y. BNE BUCLE ; Salta a BUCLE hasta que el valor de Y=#$00. INC $FC ; Entonces incrementa el valor del byte alto, pasando a las direcciones $0500 y siguientes. LDX $FC ; Carga X con el valor de la dirección $FC. CPX #$08 ; Compara el valor de X con #$08, es decir, con la dirección $0800, que corresponde a la pantalla llena. BNE BUCLE ; Salta a BUCLE hasta que el valor de X=#$08. RTS ; Entonces retorna al BASIC.
Para entender más: Direccionamiento Indirecto Indexado
Para aprender más: Cambia los caracteres. Con el mismo sistema de direccionamiento, introduce el mapa de colores de pantalla dándole color al caracter introducido.Una tercera aplicación del anterior programa consiste en:
Nº 2c.- Limpiar la Pantalla
Por Linus Åkerlund
* = $1000 ; SYS 4096. LDA #$00 ; Carga A con #$00, que es el código del color negro. STA $D020 ; Guarda el valor #$00 en la dirección $D020, que corresponde al borde de la pantalla. STA $D021 ; Guarda el valor #$00 en la dirección $D021, que corresponde al fondo de la pantalla. TAX ; Transfiere el contenido de A al registro X. LDA #$20 ; Carga A con #$20, que corresponde al caracter ESPACIO. BUCLE STA $0400,X ; Guarda el valor #$20 en la posición $0400 y siguientes #255 del mapa de memoria de pantalla. STA $0500,X ; Guarda el valor #$20 en la posición $0500 y siguientes #255. STA $0600,X ; Guarda el valor #$20 en la posición $0600 y siguientes #255. STA $0700,X ; Guarda el valor #$20 en la posición $0700 y siguientes #255. DEX ; Decrementa el valor de X. BNE BUCLE ; Salta a BUCLE hasta que el valor de X=#$00. RTS ; Entonces retorna al BASIC. Para entender más: Código de caracteres en pantalla y código de colores
Para aprender más: Cambia los caracteres. Cambia los colores.Una cuarta aplicación de este tipo de programa consiste en:
Nº 2d.- RVS/ON en toda la pantalla
Por fermhg, canal #c64 del irc-hispano
* = $1000 ; SYS 4096. LDX #$00 ; Carga X con #$00, que es el valor inicial de un bucle. BUCLE LDA $0400,X ; Carga A con el valor de la posición $0400 y siguientes #255 del mapa de memoria de pantalla. EOR #$80 ; Efectúa un OR-exclusive lógico entre A y el byte #$80, lo que genera el caracter en rvs/on. STA $0400,X ; Guarda el código del caracter en rvs/on en misma posición en la que fue cargado. LDA $0500,X ; Carga A con el valor de la posición $0500 y siguientes #255. EOR #$80 ; Efectúa un OR-exclusive lógico entre A y el byte #$80, lo que genera el caracter en rvs/on. STA $0500,X ; Guarda el código del caracter en rvs/on en misma posición en la que fue cargado. LDA $0600,X ; Carga A con el valor de la posición $0600 y siguientes #255. EOR #$80 ; Efectúa un OR-exclusive lógico entre A y el byte #$80, lo que genera el caracter en rvs/on. STA $0600,X ; Guarda el código del caracter en rvs/on en misma posición en la que fue cargado. LDA $0700,X ; Carga A con el valor de la posición $0700 y siguientes #255. EOR #$80 ; Efectúa un OR-exclusive lógico entre A y el byte #$80, lo que genera el caracter en rvs/on. STA $0700,X ; Guarda el código del caracter en rvs/on en misma posición en la que fue cargado. INX ; Incrementa el valor de X. BNE BUCLE ; Salta a BUCLE hasta que X=#$00. RTS ; Entonces retorna al BASIC. Para entender más: Ejecutar un OR es como si sumásemos el valor del número inicial más #128.
Para aprender más: Escribir todos los caracteres y comprobar cuál es dicho caracter en modo rvs/on.Una quinta aplicación del programa consiste en:
Nº 2e.- Limpiar la pantalla
Por Pontus Berg en comp.sys.cbm
* = $1000 ; SYS 4096. LDA #$00 ; Carga A con #$00, que es el código del color negro, que, como veremos, va a afectar tanto a los caracteres que hay en la pantalla como al fondo de la misma. STA $0286 ; Guarda el valor #$00 en la dirección $0286, que es la posición en de página cero extendida encargada de asignar los colores a los caracteres. STA $D021 ; Guarda el valor #$00 en la dirección $D021, que corresponde al fondo de la pantalla. JSR $E544 ; Salta a la subrutina $E544 en ROM, que realiza un CLear Screen en la pantalla. Para entender más: Todo el proceso utilizado en el programa 2c podemos simplificarlo saltando a la subrutina $E544.
Para aprender más: Cambiar colores. Utilizar también el borde de la pantalla.Una sexta aplicación del programa consiste en:
Nº 2f.- Limpiar la pantalla
Por Pontus Berg en comp.sys.cbm
* = $1000 ; SYS 4096. LDA #$0B ; Carga A con #$0B, que en binario es %00001011.. STA $D011 ; Guarda el valor #$0B en $D011, lo que desactiva el bit 4, haciendo que toda la pantalla tome el código del borde de la pantalla. BUCLE LDA #$00 ; Carga A con #$00, que es el código del color negro. STA $D020 ; Guarda el valor #$00 en la dirección $D020, que corresponde al borde de la pantalla siendo, en este caso, la pantalla completa. JMP BUCLE ; Salta a BUCLE, produciendo un bucle sin fin. Esta línea puede ser sustituída por RTS. Para entender más: $D011
Para aprender más: Cambiar colores. Utilizar también el borde de la pantalla. Realizar el siguiente cambio:
BUCLE INC $D020 ; Incrementa el valor de la dirección $D020, que corresponde al borde de la pantalla. Este incremento, junto con un bucle, produce un efecto de colores. JMP BUCLE ; Salta a BUCLE, produciendo un bucle sin fin. Esta línea puede ser sustituída por RTS. Nº 3a.- Convertidor decimal a hexadecimal
Por John P. Gibbons
* = $1000 ; SYS 4096. JSR $AEFD ; Salta a la subrutina en ROM $AEFD, que comprueba la existencia de una coma después de SYS. JSR $AD8A ; Si no está presente genera un mensaje de error (Syntax error) y retorna al BASIC. JSR $B7F7 ; Salta a la subrutina en ROM $B7F7, que convierte el número decimal a binario y lo guarda en forma de byte bajo / byte alto en las direcciones $14 (byte bajo) y $15 (byte alto). LDA $15 ; Carga A con el byte alto. JSR HEX ; Salta a la subrutina HEX, que sacará el contenido de A a la pantalla como dos dígitos hexadecimales. LDA $14 ; Carga A con el byte bajo. HEX PHA ; Guarda en la pila el contenido de A. LSR A ; Desplaza una vez el contenido de A hacia la derecha. LSR A ; Desplaza una vez el contenido de A hacia la derecha. LSR A ; Desplaza una vez el contenido de A hacia la derecha. LSR A ; Desplaza una vez el contenido de A hacia la derecha. En total son 4 veces, con lo que obtenemos los cuatro bits de mayor peso. JSR PUT ; Salta a la subrutina PUT que procesa estos cuatro bits. PLA ; Restaura el valor original de A a partir de la pila. AND #$0F ; AND entre A y el valor %00001111 ($0F) para obtener los cuatro bits de menor peso. PUT CMP #$0A ; Compara estos cuatro bits con el valor #10. BCC GUN ; Si es menor que #10 salta a GUN. ADC #$06 ; Suma #$06 + acarreo (1) al acumulador, sumando en definitiva #$07. Esta suma deja C a cero. GUN ADC #$30 ; Suma #$30 + acarreo (c=0) al acumulador. JMP $FFD2 ; Retorna a través de la subrutina en ROM $FFD2, que saca a pantalla el caracter ASCII cuyo código está en A.
Para entender más: Vamos a hacer un ejemplo con el número 3521, que pasado a binario es el siguiente:0000-1101-1100-0001.
Como vemos, los primeros 4 bits son ceros, por lo tanto su valor en Hexadecimal será también 0.
El segundo grupo de cuatro bits es 1101, que llevado al byte alto quedaría así: 1101-0000.
El programa realiza 4 veces la función LSR atendiendo (0110-1000, 0011-0100, 0001-1010, 0000-1101). Así hemos obtenido el byte 1101. Su valor es 13, con lo que es mayor que #$0A, sumándole #$06 + acarreo, es decir #$07, y sumándole #$30 + acarreo (que para este caso es 0). Entonces #13 + #$07 + #$30 = #$44 (que corresponde a la letra D).
El tercer grupo de bits es 1100, tendría como valor #12, y se le sumaría #$06 + acarreo + #$30, es decir #$07 + #$30. Entonces #12 + #$07 + #$30 = #$43 (que corresponde a la letra C).
El cuarto grupo de bits es 0001, tendría como valor #1, y no se le sumaría #$06 + acarreo ya que es menor que 10, saltando a GUN donde se le sumaría #$30. Entonces #01 + #$30 = #$31 (que corresponde al número 1).
El valor en Hexadecimal de 3521 es DC1.
Para aprender más: Probar con distintos números ejecutando SYS 4096, [número].Otro tipo de aplicación consiste en:
Nº 3b.- Multiplicación
Por arun en comp.sys.cbm, fermhg y _PaCo_, canal #c64 del irc-hispano
* = $1000 ; SYS 4096. LDA #30 ; Carga A con #30, valor del primer multiplicando, que en binario sería %00011110. STA $FB ; Guarda el valor #30 en la dirección $FB. LDA #150 ; Carga A con #150, valor del segundo multiplicando, que en binario sería %10010110. STA $FC ; Guarda el valor #150 en la dirección $FC. ; Ya sabemos que la multiplicación será 150 x 15 = 4500.
LDA #0 ; Carga A con #0, que en binario sería %00000000. LDX #8 ; Carga X con el valor #8, que es el valor inicial de un bucle. ROTAR ROR ; Realiza una rotación de los bits hacia la derecha en A. ROR $FC ; Realiza una rotación de los bits hacia la derecha en $FC. BCC NOSUMA ; Salta a NOSUMA si la bandera de accarreo del byte de $FC está a 0. CLC ; Pone la bandera de acarreo a 0 para poder sumar. ADC $FB ; Suma el contenido de A más el contenido de $FB. NOSUMA DEX ; Decrementa el valor de X. BPL ROTAR ; Salta a ROTAR hasta que el valor de X<0. STA $FB ; Si el resultado de la suma es negativo guarda el valor de A en $FB. RTS ; Retorna al BASIC.
Para entender más: Gracias a _PaCo_ podemos dar una explicación de cuál es el funcionamiento del programa, aunque coincidimos en que es muy difícil de comprender. Suponiendo que los multiplicando son 30 y 150, el programa guarda en $FB el valor %00011110 y en $FC el valor %10010110. Una vez guardados empieza a trabajar con A y la posición $FC de la siguiente manera:
ESTADO ORIGINAL DE A: %00000000
ESTADO ORIGINAL DE LA POSICIÓN $FC: %10010110
8) ROR EN A: %00000000 ; ROR EN LA POSICIÓN $FC: %01001011 ; Acarreo=0 (No suma). Vemos como el bit de acarreo dE A pasa a byte $FC.
7) ROR EN A: %00000000 ; ROR EN LA POSICIÓN $FC: %00100101 ; Acarreo=1 (Sí suma)
SUMA %00000000 + %00011110 = %00011110. Este valor será guardado en A.
6) ROR EN A: %00001111 ; ROR EN LA POSICIÓN $FC: %00010010 ; Acarreo=1 (Sí suma)
SUMA %00001111 + %00011110 = %00101101. Este valor será guardado en A.
5) ROR EN A: %00010110 ; ROR EN LA POSICIÓN $FC: %10001001 ; Acarreo=0 (No suma)
4) ROR EN A: %00001011 ; ROR EN LA POSICIÓN $FC: %01000100 ; Acarreo=1 (Sí suma)
SUMA %00001011 + %00011110 = %00101001. Este valor será guardado en A.
3) ROR EN A: %00010100 ; ROR EN LA POSICIÓN $FC: %10100010 ; Acarreo=0 (No suma)
2) ROR EN A: %00001010 ; ROR EN LA POSICIÓN $FC: %01010001 ; Acarreo=0 (No suma)
1) ROR EN A: %00000101 ; ROR EN LA POSICIÓN $FC: %00101000 ; Acarreo=1 (Sí suma)
SUMA %00000101 + %00011110 = %00100011. Este valor será guardado en A.
0) ROR EN A: %00010001 ; ROR EN LA POSICIÓN $FC: %10010100 ; Acarreo=0 (No suma, y como el valor de X=0 ya termina el programa).
El siguiente proceso será guardar el valor de A en $FB = %00010001 (#17), que sería el byte alto del resultado y el valor de $FC = %10010100 (#148).
Lo que nos queda es imprimir el resultado maunalmente desde el BASIC, de la siguiente manera:
PRINT 256 * PEEK (251) + PEEK (252)
Para aprender más: Probar con distintos multiplicandos para extraer otros productos (recordar que para visualizar el resultado de la multiplicación debemos teclear PRINT 256 * PEEK (251) + PEEK (252).Otro tipo de aplicación consiste en:
Nº 3c.- Calcular el entero de (A+B) / 4
Por Marko Mäkelä en comp.sys.cbm, fermhg, canal #c64 del irc-hispano
* = $1000 ; SYS 4096. LDA #45 ; Carga A con #45, valor del primer sumando, que en binario es %00101101. CLC ; Pone la bandera de acarreo a 0 para poder sumar. ADC #18 ; Suma el valor #45 con #18, que en binario sería %00010010. ; Ya sabemos que el cálculo será: INT (45 + 18) / 4 = 15.
PHP ; Guarda en la pila el contenido del registro de estado. ROR ; Realiza una rotación de los bits hacia la derecha en A. PLP ; Extrae un byte de la pila y lo deja en el registro de estado. ROTAR ROR ; Realiza una rotación de los bits hacia la derecha en A. STA $FB ; Guarda el valor de A en $FB. RTS ; Retorna al BASIC. Para entender más: Cara ROR es como dividir entre 2.
Para aprender más: Probar con distintos sumandos para extraer otros resultados (recordar que para visualizar el resultado de la operación debemos teclear PRINT PEEK (251). Probar a dividir entre 2, entre 8, etc.El programa necesita ejecutar un SYS 4096. Una vez ejecutado hay que utilizar la instrucción PRINT PEEK (251)
Nº 4a.- Visualizar un fichero creado con el Art Studio
Por _PaCo_, canal #c64 del irc-hispanoTodos sabemos la facilidad para crear mapa de bits a todo color con este genial programa...pero ¿cómo hacer para ver el fichero desde el Basic del Commodore o desde C.M.? Carga el fichero MPIC desde tu disquetera o tu datasette, utilizando el parámetro (,1), es decir, que conserve su ubicación original en la memoria.
Ejemplo:
LOAD "nombre mpic",8,1 ó LOAD "nombre mpic",1,1. Una vez cargado, aplica el comando NEW y teclea este simple programa:
*= $1000 ; SYS 4096. INI LDA #59 ; Carga A con #59, que en binario es %00111011, lo que activa los bits 0,1,3,4 y 5. STA $D011 ; Guarda el valor #$59 en la dirección $D011, lo que inicia el modo grafico de 8kb en alta resolución. LDA #216 ; Carga A con #216, que en binario es %11011000, lo que activa los bits 3,4,6 y 7. STA $D016 ; Guarda el valor #216 en la dirección $D016, lo que inicia el modo multicolor. LDA #24 ; Carga A con #24, que en binario es %00011000, lo que activa los bits 3 y 4. STA $D018 ; Guarda el valor #216 en la dirección $D016, lo que selecciona el segundo banco de memoria ($2000-$4000). LDA #151 ; Carga A con #151, que en binario es %10010111, lo que activa los bits 0,1,2,4 y 7. STA $DD00 ; Guarda el valor #151 en la dirección $DD00, lo que selecciona el segmento (página) de $0000-$4000. LDA $4328 ; Carga A con el valor de la dirección $4328. STA $D020 ; Guarda el valor de A en la dirección $D020, que corresponde al borde de la pantalla. LDA $4329 ; Carga A con el valor de la dirección $4329. STA $D021 ; Guarda el valor de A en la dirección $D021, que corresponde al fondo de la pantalla. ; Los valores del color primario se almacenan entre las posiciones $3f40 y $4380.
LDA #$40 ; Carga A con el byte bajo de $3F40. STA $4B ; Guarda el valor de A en la dirección $4B, que es el vector del byte bajo (de dónde leer). LDA #$3F ; Carga A con el byte alto de $3F40. STA $4C ; Guarda el valor de A en la dirección $4C, que es el vector del byte alto (de dónde leer). ; La memoria de pantalla se encuentra entre $0400 y $07E8.
LDA #$00 ; Carga A con el byte bajo de $0400. STA $4D ; Guarda el valor de A en la dirección $4D, que es el vector del byte bajo (destino de datos). LDA #$04 ; Carga A con el byte alto de $0400. STA $4E ; Guarda el valor de A en la dirección $4E, que es el vector del byte alto (destino de datos). ; Queremos mover 1000 (25*40) caracteres, que en hexadeciamal es $03E8.
LDA #$E8 ; Carga A con el byte bajo de $03E8. STA $4F ; Guarda el valor de A en la dirección $4F, que es el vector del byte bajo (usado como contador). LDA #$03 ; Carga A con el byte alto de $03E8. STA $50 ; Guarda el valor de A en la dirección $50, que es el vector del byte alto (usado como contador). JSR TRPTE ; Salta a la subrutina TRPTE que hará el transporte de datos. ; Ahora vamos a transportar el código de color secundario que está almacenado entre $4338 y $4720.
LDA #$38 ; Carga A con el byte bajo de $4338. STA $4B ; Guarda el valor de A en la dirección $4B, que es el vector del byte bajo (de dónde leer). LDA #$43 ; Carga A con el byte alto de $4338. STA $4C ; Guarda el valor de A en la dirección $4C, que es el vector del byte alto (de dónde leer). ; Ponemos el código de color secundario en el VIC-II $D800-$DBE8.
LDA #$00 ; Carga A con el byte bajo de $D800. STA $4D ; Guarda el valor de A en la dirección $4D, que es el vector del byte bajo (destino de datos). LDA #$D8 ; Carga A con el byte alto de $D800. STA $4E ; Guarda el valor de A en la dirección $4E, que es el vector del byte alto (destino de datos). ; Movemos 1000 caracteres, como antes.
LDA #$E8 ; Carga A con el byte bajo de $03E8. STA $4F ; Guarda el valor de A en la dirección $4F, que es el vector del byte bajo (usado como contador). LDA #$03 ; Carga A con el byte alto de $03E8. STA $50 ; Guarda el valor de A en la dirección $50, que es el vector del byte alto (usado como contador). JSR TRPTE ; Salta a la subrutina TRPTE que hará el transporte de datos. JSR TECLA ; Salta a la subrutina TECLA que hará la lectura del teclado. RTS ; Retorna al BASIC. TRPTE INC $50 ; Compensamos con 1 el contador en byte alto. LDX #$00 ; Carga X con #$00, que es el valor inicial de un bucle. BUCLEX LDA ($4B,X) ; Carga A con el modo indirecto indexado con el valor de $4B y $4C, que es el inicio. STA ($4D,X) ; Guarda el valor de A en la dirección $4D y $4E, lo que almacena el valor de A en RAM, siendo el destino. DEC $4F ; Decrementa el vector del byte bajo del contador. BNE SEMOS ; Salta a SEMOS hasta que el valor de X=#$00. DEC $50 ; Si es 0, decrementa el vector del byte alto del contador. BEQ SAMOS ; Si es 0, salta a SAMOS. SEMOS INC $4D ; Si no, seguimos incrementando el vector del byte bajo del destino. BNE CONT ; Salta a CONT hasta que el valor de la dirección $4D sea igual a #$00. INC $4E ; Si es 0 incrementa el vector del byte alto del destino. CONT INC $4B ; Incrementa el vector del byte bajo del inicio. BNE CONT2 ; Salta a CONT2 hasta que sea 0. INC $4C ; .Si es 0, incrementa el vector del byte alto del inicio. CONT2 JMP BUCLEX ; Sata a BUCLEX, y seguimos sumando. SAMOS RTS ; Retorna al BASIC. TECLA LDA #0 ; Carga A con #0. STA $C6 ; Guarda el valor de A en la posición $C6, lo que pone el valor de A en el buffer del teclado. Es una forma de limpiar el buffer antes de proceder a su lectura. VUVE LDA $C6 ; Carga A con el valor del buffer del teclado. BEQ VUVE ; Si aún no se ha pulsado una tecla, volvemos a VUVE. LDA #27 ; Carga A con #27, que en binario es %00011011, lo que activa los bits 0,1,3 y 4. STA $D011 ; Guarda el valor #$27 en la dirección $D011, lo que inicia el modo texto. LDA #21 ; Carga A con #21, que en binario es %00010101, lo que activa los bits 0,2 y 4. STA $D018 ; Guarda el valor #21 en la dirección $D016, lo que selecciona el set de caracteres en Rom. LDA #200 ; Carga A con #200, que en binario es %11001000, lo que activa los bits 3,6 y 4. STA $D016 ; Guarda el valor #200 en la dirección $D016, lo que inicia el modo modo monocolor. LDA #147 ; Carga A con #147, que es como si pulsaramos (SHIFT+CLR+HOME), lo que borra la pantalla. JSR $F1CA ; Salta a la subrutina en ROM $F1CA, que imprime el valor de A, con lo que se borraría la pantalla. RTS ; Retorna al BASIC. Para entender más: VIC II
Para aprender más: Puedes realizar tus propios dibujos con el Art Studio, guardarlos y cargarlos desde este programa en Código Máquina. Aquí tienes un bitmap de ejemplo que deberás cargar primero, seguido de este programa y hacer un sys 4096.Una segunda aplicación del programa consiste en:
Nº 4b.- Visualizar un fichero creado con KOALA
Por Linus Åkerlund
*= $1000 ; SYS 4096. LDA #$00 ; Carga A con #$00, que es el código del color negro. STA $D020 ; Guarda el valor #$00 en la dirección $D020, que corresponde al borde de la pantalla. STA $D021 ; Guarda el valor #$00 en la dirección $D021, que corresponde al fondo de la pantalla. TAX ; Transfiere el contenido de A a X. De esta manera carga X con #$00, que es el valor inicial de un bucle, ahorrando espacio de memoria. COPIA LDA $3F40,X ; Carga A con el valor de la dirección $3F40 y siguientes. STA $0400,X ; Guarda el valor de A en la posición $0400 y siguientes del mapa de memoria de la pantalla. LDA $4040,X ; Carga A con el valor de la dirección $4040 y siguientes. STA $0500,X ; Guarda el valor de A en la posición $0500 y siguientes. LDA $4140,X ; Carga A con el valor de la dirección $4140 y siguientes. STA $0600,X ; Guarda el valor de A en la posición $0600 y siguientes. LDA $4240,X ; Carga A con el valor de la dirección $4240 y siguientes. STA $0700,X ; Guarda el valor de A en la posición $0700 y siguientes. LDA $4328,X ; Carga A con el valor de la dirección $4328 y siguientes. STA $D800,X ; Guarda el valor de A en la posición $D800 y siguientes del mapa de colores de pantalla. LDA $4428,X ; Carga A con el valor de la dirección $4428 y siguientes. STA $D900,X ; Guarda el valor de A en la posición $D800 y siguientes. LDA $4528,X ; Carga A con el valor de la dirección $4528 y siguientes. STA $DA00,X ; Guarda el valor de A en la posición $D800 y siguientes. LDA $4628,X ; Carga A con el valor de la dirección $4628 y siguientes. STA $DB00,X ; Guarda el valor de A en la posición $D800 y siguientes. DEX ; Decrementa el valor de X. BNE COPIA ; Salta a COPIA hasta que el valor de X=#$00. LDA #$3B ; Carga A con #$3B LDX #$18 ; Carga X con #$18 LDY #$18 ; Carga Y con #$18, que determina que el código del bitmap realizado con el KOALA necesariamente debe ensamblarse a partir de la dirección de memoria $2000. STA $D011 ; Guarda el valor de A en la dirección $D011, que selecciona el modo bitmap. STX $D016 ; Guarda el valor de X en la dirección $D016, que selecciona el modo multicolor. STY $D018 ; Guarda el valor de Y en la dirección $D018, que determina que el código del bitmap realizado con el KOALA necesariamente debe ensamblarse a partir de la dirección de memoria $2000. BUCLE JMP BUCLE ; Salta a BUCLE, produciendo un bucle infinito. Para entender más: VIC II. Las imágines KOALA normalmente están cargadas a partir de la posición $6000. Sin embargo este programa está configurado para cargar este tipo de imágenes a partir de la dirección $2000. Para ello debemos realizar un pequeño truco con el monitor del emulador VICE: l "<nombre del archivo>" <2000>
Para aprender más: Puedes descargar imágenes KOALA y reproducirlas con este programa.Nº 5.- Texto y Sonido
Por _PaCo_, canal #c64 del irc-hispano
* = $1000 ; SYS 4096. INICIO LDX #0 ; Carga X con #0. LDA #$0F ; Carga A con #$0F, que en binario es %00001111 y en momdo decimal es 15, lo que activa los bits 0,1,2 y 3. STA $D418 ; Guarda el valor #$0F en la dirección $D418, lo que selecciona el volumen del sonido al máximo (15 es el volumen máximo). JSR CALCPOS ; Salta a la subrutina CALCPOS que calcula el inicio en memoria y final del texto. SIGUE LDX #0 ; Carga X con #0. LDA ($FB,X) ; Carga el valor de la dirección $FB+$FC, que son vectores del lugar donde empieza el siguiente caracter. JSR $FFD2 ; Salta a la subrutina en ROM $FFD2 que saca a pantalla el caracter ASCII cuyo código está en A. JSR SONIDO2 ; Salta a la subrutina SONIDO2, que es la generadora del sonido. JSR INCREMENTA ; Salta a la subrutina INCREMENTA, que incrementa el vector $FA+$FB al siguiente caracter. BNE SIGUE ; Salta a SIGUE si el valor del caracter es distinto de 0. RTS ; Retorna al BASIC. SONIDO2 STA FINALPROG+2 ; Guarda el valor de A al final del programa. Sería mejor usar una dirección de memoria de la página cero, lo que disminuiría en un byte la ejecución dando más velocidad. ; Primera comparación.
CMP #$20 ; Compara A con el valor #$20, que corresponde al caracter ESPACIO. BNE SALTA ; Salta a SALTA si el valor del caracter es distinto de #$20. LDA #$0F ; Carga A con #$0F, que es el valor de retardo variable. STA CONTADOR ; Guarda el valor #$0F en CONTADOR, lo que hará el retardo. JSR RETARDO ; Salta a la subrutina RETARDO, que es un bucle de espera variable. JMP SALIDA ; Salta a SALIDA, al detectar el espacio no genera sonido. ; Segunda comparación.
SALTA CMP #13 ; Compara A con #13, que corresponde al caracter RETURN. BNE SALTA2 ; Salta a SALTA2 si el valor del caracter es distinto de #13. LDA #$20 ; Carga A con #$20, que es el valor de retardo variable. STA CONTADOR ; Guarda el valor #$20 en CONTADOR, lo que hará el retardo. JSR RETARDO ; Salta a la subrutina RETARDO, que es un bucle de espera variable. JMP SALIDA ; Sata a SALIDA, al detectar el RETURN no genera sonido. ; No es ni ESPACIO ni RETURN entonces hay sonido.
SALTA2 LDA #0 ; Carga A con #0. STA $D406 ; Guarda el valor #0 en la dirección $D406, que corresponde al SID generador de envolvente. LDA #3 ; Carga A con #3. STA $D405 ; Guarda el valor #3 en la dirección $D405, que corresponde al SID, ataque/decaimiento 4+4 bits. LDA #180 ; Carga A con #180. STA $D401 ; Guarda el valor #180 en la dirección $D401, que corresponde al SID, control de frecuencia byte alto. LDA #33 ; Carga A con #33. STA $D404 ; Guarda el valor #33 en la dirección $D404, que corresponde al SID, generador de onda, selecciona sierra y acciona el ataque-decaimiento-sostenimiento-relajación. LDA #$08 ; Carga A con #$08. STA CONTADOR ; Guarda el valor #$08 en CONTADOR. JSR RETARDO ; Salta a la subrutina RETARDO, que es un bucle de espera variable. LDA #0 ; Carga A con #0. STA $D404 ; Guarda el valor #0 en el SID, se acabó el sonido. SALIDA LDA FINALPROG+2 ; Carga A con el valor situado en FINALPROG+2. RTS ; Volvemos. RETARDO LDA CONTADOR ; Carga A con el valor del retardo variable situado en CONTADOR. STA FINALPROG ; Guarda dicho valor en FINALPROG. LDA #$00 ; Carga A con #$00. STA FINALPROG+1 ; Guarda el valor #$00 en la posición FINALPROG+1. RETARDO1 DEC FINALPROG+1 ; Decrementa el valor situaldo en la posición FINALPROG+1, lo que genera un bucle de 255 (FF). BNE RETARDO1 ; Salta a RETARDO1 si el valor del caracter es distinto de #$20. DEC FINALPROG ; Decrementa el valor situaldo en FINALPROG, lo que genera un bucle de retardo variable. BNE RETARDO1 ; Salta a RETARDO1 si el valor del caracter es distinto de #$20. RTS ; Volvemos. ; ¿Dónde empieza y acaba el texto?
CALCPOS LDA #<ETIQUETA ; Carga A con el byte bajo de donde empieza el texto. STA $FB ; Guarda el valor de A en la dirección $FB, vector del byte bajo. LDA #>ETIQUETA ; Carga A con el byte alto de donde empieza el texto. STA $FC ; Guarda el valor de A en la dirección $FC, vector del byte alto. LDA #<FINALPROG ; Carga A con el byte bajo de donde acaba el texto. STA $FD ; Guarda el valor de A en la dirección $FD, vector del byte bajo. LDA #>FINALPROG ; Carga A con el byte alto donde acaba el texto. STA $FE ; Guarda el valor de A en la dirección $FE, vector del byte alto. RTS ; Volvemos. INCREMENTA TAY ; Transfiere el contenido dA al registro Y. INC $FB ; Incrementa el valor del vector del byte bajo (inicio). CMP $FD ; el valor es comparado con el vector del byte bajo de final de texto. BEQ COMPARA ; Si es igual, salta a COMPARA. LDA $FB ; Carga A con el vector del byte bajo (inicio). BEQ COMPARA2 ; Si es igual, salta a COMPARA2. JMP SALE ; Sata a SALE, y seguimos sumando. COMPARA LDA $FC ; Carga A con el vector del byte alto (inicio). CMP $FE ; el valor es comparado con el apuntador alto de final de texto. BEQ SALEFIN ; Si es igual, salta a SALEFIN. INC $FB ; Incrementa el vector byte bajo (inicio). JMP SALE ; Sata a SALE, y seguimos sumando. COMPARA2 LDA $FC ; Carga A con el vector del byte alto (inicio). CMP $FE ; el valor es comparado con el vector del byte alto de final de texto. BEQ SALEFIN ; Si es igual, salta a SALEFIN. INC $FC ; Incrementa el vector byte alto (inicio). SALE TYA ; Transfiere el contenido de Y al acumulador . RTS ; Volvemos. SALEFIN LDA #0 ; Carga A con #0. RTS ; Retorna al BASIC. ETIQUETA .TEXT "ESTO ES UNA PRUEBA DE" ; Texto que se imprimirá en pantalla. .TEXT " TEXTO Y BEEP." .BYTE 13 ; El valor #13 corresponde a la tecla RETURN. .TEXT "YA ADMITE 65535" .TEXT " CARACTERES." .BYTE 13,13 .TEXT " NO PODRAS METER" .TEXT " TANTO EN LA RAM " .BYTE 13,13 .TEXT " PERO LA RUTINA " .TEXT " ADMITE TODA LA MEMORIA " .TEXT " ..... " .BYTE 13,13 .TEXT " YA SABES... PON EL TEXTO " .TEXT " QUE QUIERAS Y RECOMPILA" .BYTE 13 .TEXT " EL PROGRAMA. " .BYTE 13,13 .TEXT "..Y LO QUE HAGA FALTA!" .BYTE 13,13,13 .TEXT "OK!" .BYTE 0 ; Indica el final del texto. Cuando encuentra un 0 hace un RTS. FINALPROG .BYTE 0,0,0 ; Guarda 3 bytes para variables. CONTADOR .BYTE 0 ; Aquí se almacena el contador. Para entender más: SID
Para aprender más: Para imprimir otro texto deberemos cambiar los comandos .TEXT. Otra cosa, si queremos cambiar el tiempo de retardo, y así conseguir que la escritura sea más lenta o rápida, hay que cambiar el valor del retardo. También podemos realizar otro sonido cambiando los parámetros del SID.