> 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 - 3d - 3e - 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 Assemble_it

> * = $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 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.- Convertidor decimal a binario
> Por fermhg, canal #c64 del irc-hispano

> * = $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).
> | LDY #$00 | ; Carga Y con #$00, que es el valor inicial de un bucle.
> | LDA $15 | ; Carga A con el byte alto.
> | BEQ UNO | ; Si el valor de $15 es #0, es decir, si el número introducido es menor de 256 salta a UNO.
> BUCLE1 | LDX #$00 | ; Carga X con #$00, que es el valor inicial de un bucle.
> BUCLE2 | ROL | ; Realiza una rotación de los bits hacia la izquierda en A.
> | STA $FB | ; Guarda el valor de A en la dirección $FB.
> | BCC P0 | ; Salta a P0 si el bit de acarreo es 0.
> P1 | LDA #$31 | ; Carga A con #$31, que corresponde al número 1.
> PRINT | JSR $FFD2 | ; Salta a la subrutina en ROM $FFD2 que saca a pantalla el carácter ASCII cuyo código está en A.
> | LDA $FB | ; Carga A con el valor antes guardado para poder seguir rotando.
> | INX | ; Incrementa el valor de X.
> | CPX #08 | ; Compara el valor de X con #08, que son los 8 bits.
> | BNE BUCLE2 | ; Salta a BUCLE2 hasta que el valor de X=#$08.
> UNO | INY | ; Si es menor que #10 salta a GUN.
> | CPY #$02 | ; Suma #$06 + acarreo (1) al acumulador, sumando en definitiva #$07. Esta suma deja C a cero.
> | BEQ FIN | ; Suma #$30 + acarreo (c=0) al acumulador.
> | LDA $14 | ; Carga A con el byte bajo.
> | JMP BUCLE1 | ; Salta a BUCLE1.
> P0 | LDA #$30 | ; Carga A con #$31, que corresponde al número 1.
> | JSR $FFD2 | ; Salta a la subrutina en ROM $FFD2 que saca a pantalla el carácter ASCII cuyo código está en A.
> FIN | RTS | ; Retorna al BASIC.

> Para entender más: El funcionamiento de este pequeño programa es muy sencillo, atendiendo a la instrucción ROL, que lo que hace es ir rotando los bits hacia la izquierda. Entonces BCC aprovecha para leer el bit que queda en el acarreo, con lo que sabemos si se trata de un 0 o un 1. Una vez conocido estos valores sólo queda imprimirlos en pantalla.
> Otro detalle, es que para un número menor de 256 sólo necesitamos 8 bits, por lo que no aparecen los 16 posibles. Sólo en aquellos números mayores de 255 haremos uso de los 16 bits, por eso leemos primero el valor de $15 y luego el de $14.
> Para aprender más: Probar con distintos números ejecutando SYS 4096, [número].

> Nº 3c.- 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: %1 0001001 ; Acarreo=0 (No suma)
> 4) ROR EN A: %00001011 ; ROR EN LA POSICIÓN $FC: %0 1000 100 ; 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: %101000 10 ; Acarreo=0 (No suma)
> 2) ROR EN A: %00001010 ; ROR EN LA POSICIÓN $FC: %0101000 1 ; 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º 3d.- Multiplicación
> Por _PaCo_, canal #c64 del irc-hispano

> * = $1000 |  | ; SYS 4096.
> | LDA INICIO | ; Carga A con el valor de INICIO, que es el primer multiplicando.
> | BEQ SALE | ; Si es 0, salimos, ya que de antemano sabemos que daría como resultado 0.
> | LDA INICIO+1 | ; Carga A con el valor de INICIO+1, que es el segundo multiplicando.
> | BEQ SALE | ; Si es 0, salimos, ya que de antemano sabemos que daría como resultado 0.
> | LDA #0 | ; Carga A con #0.
> | STA DESTINO | ; Guarda el valor #0 en la posición DESTINO.
> | STA DESTINO+1 | ; Guarda el valor #0 en la posición DESTINO+1.
> SUMA | ADC INICIO | ; Sumamos al valor de A el valor de INICIO.
> | BCC SIGUE | ; Salta a SIGUE hasta que el valor de A sea igual a 255.
> | CLC | ; Pone la bandera de acarreo a 0 para poder sumar, es decir, restamos 256 para seguir sumando.
> | INC DESTINO+1 | ; Incrementa el valor de la posición DESTINO+1.
> SIGUE | DEC INICIO+1 | ; Decrementa el valor de la posición INICIO+1.
> | BNE SUMA | ; Salta a SUMA hasta que el valor de la posición INICIO+1 sea igual a #$00.
> SALE | STA DESTINO | ; Guarda el valor de A en la en la posición DESTINO.
> | RTS | ; Retorna al BASIC.
> INICIO | .BYTE 174,4 | ; Estos son los dos multiplicando. Se pueden modificar con POKE [INICIO],valor y POKE [INICIO+1],valor.
> DESTINO | .BYTE 0,0 | ; Aquí estará el resultado.

> Para entender más: Este programa presenta un esquema interesante. Sabemos que 2 x 3 = 6, y sabemos que 2 x 3 es lo mismo que 2 + 2 + 2 = 6. A partir de aquí comentamos el programa anterior de la siguiente manera.
> ESTADO ORIGINAL DE INICIO: #174
> ESTADO ORIGINAL DE INICIO+1: #4
> ESTADO ORIGINAL DE A: #0
> 1) A= #0 + INICIO = #174, DESTINO+1 = #1, INICIO+1 = #3
> 2) A= #174 + INICIO = #348, DESTINO+1 = #1, INICIO+1 = #2
> 3) A= #348 + INICIO = #522 - ACARREO (256) = #266, DESTINO+1 = #1, INICIO+1 = #1
> 4) A= #266 + INICIO = #440 - ACARREO (256) = #184, DESTINO+1 = #2, INICIO+1 = #0
> 5) DESTINO = #184, DESTINO+1 = #2
> Lo que nos queda es imprimir el resultado maunalmente desde el BASIC, de la siguiente manera:
> PRINT 256 * PEEK (DESTINO+1) + PEEK (DESTINO)
> Para aprender más: Probar con distintos multiplicandos para extraer otros resultados (recordar que para visualizar el resultado de la operación debemos teclear PRINT 256 * PEEK (DESTINO+1) + PEEK (DESTINO).

> El programa necesita ejecutar un SYS 4096. Una vez ejecutado hay que utilizar la instrucción PRINT 256 * PEEK (DESTINO+1) + PEEK (DESTINO).

> Otro tipo de aplicación consiste en:

> Nº 3e.- 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-hispano

> Todos 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.