cursos:ensamblador:esqueleto_programa

Diferencias

Muestra las diferencias entre dos versiones de la página.

Enlace a la vista de comparación

Ambos lados, revisión anterior Revisión previa
Próxima revisión
Revisión previa
cursos:ensamblador:esqueleto_programa [12-01-2024 14:50] sromerocursos:ensamblador:esqueleto_programa [19-01-2024 11:32] (actual) sromero
Línea 8: Línea 8:
 Para ello, necesitamos saber lo siguiente: Para ello, necesitamos saber lo siguiente:
  
-   - Tener el esqueleto de un programa mínimo, vacío, que no haga nada, al cual podamos añadirle instrucciones para hacer nuestras pruebas. Podremos utilizar un esqueleto de programa similar para cada prueba que queramos realizar.+   - Tener el esqueleto de un programa mínimo, que no haga nada, al cual podamos añadirle instrucciones para hacer nuestras pruebas. Podremos utilizar un esqueleto de programa similar para cada prueba que queramos realizar.
    - Saber cómo ensamblar ese programa para obtener un fichero TAP que podamos probar en un emulador.    - Saber cómo ensamblar ese programa para obtener un fichero TAP que podamos probar en un emulador.
    - Tener alguna forma de imprimir por pantalla para tener un feedback visual en las pruebas que hagamos.    - Tener alguna forma de imprimir por pantalla para tener un feedback visual en las pruebas que hagamos.
Línea 15: Línea 15:
  
 <code z80> <code z80>
-ORG 35000 +    ORG 35000 
-    CALL $0DAF     ; CLS (borrar pantalla)+ 
 +    call $0daf     ; CLS (borrar pantalla)
  
     ; código que queremos probar aqui     ; código que queremos probar aqui
-    RET +    ret 
-END 35000+ 
 +    END 35000
 </code> </code>
  
-A continuación, podemos ensamblar este programa con ''pasmo <nowiki>--</nowiki>tapbas prueba.asm prueba.tapv. Obtendremos un fichero TAP el cual podremos cargar en un emulador.+A continuación, podemos ensamblar este programa con ''pasmo <nowiki>--</nowiki>tapbas prueba.asm prueba.tap''. Obtendremos un fichero TAP el cual podremos cargar en un emulador.
  
-Al ejecutarlo, como lo único que tenemos es un ''RET'', se devolverá el control al BASIC y todo lo que podremos ver en pantalla es un "**0 OK, 40:1**" (o similar) en la parte inferior.+Nótese que las directivas ''ORG'' y ''RET'' están indentadas (4 espacios hacia la derecha). Esto no es necesario para **pasmo** (podríamos situarla al principio de la línea) pero otros assemblers como **sjasmplus** así lo requieren. Es recomendable intentar escribir el código lo más "standard" y compatible posible, así que se recomienda indentar estas directivas. 
 + 
 +Al ejecutarlo, como lo único que tenemos es un ''RET'', se devolverá el control al BASIC y todo lo que podremos ver en pantalla es un "''0 OK, 40:1''" (o similar) en la parte inferior.
  
 \\  \\ 
Línea 38: Línea 42:
  
 <code z80> <code z80>
-ORG 35000+    ORG 35000 
     ; código que queremos probar, como     ; código que queremos probar, como
-    ; por ejemplo, pruebas con CP y JR:+    ; por ejemplo, pruebas con CP y jr:
  
-    LD A, 10 +    ld a, 10 
-    LD B, 20 +    ld b, 20 
-    CP B +    cp b 
-    JR NZ, es_diferente+    jr nz, es_diferente
  
 es_igual: es_igual:
-    ; A = B +    ; A == B 
-    JR fin+    jr fin
  
 es_diferente: es_diferente:
Línea 55: Línea 60:
  
 fin: fin:
-    RET +    ret 
-END 35000+ 
 +    END 35000
 </code> </code>
  
Línea 62: Línea 68:
 Utilizando un emulador que tenga un "**debugger**" o "**depurador**" de Z80 podríamos ejecutar el código paso a paso para ver si se produce el salto o no, pero es posible que en estos momentos iniciales de aprendizaje nos resulte complicado hacer esto. Utilizando un emulador que tenga un "**debugger**" o "**depurador**" de Z80 podríamos ejecutar el código paso a paso para ver si se produce el salto o no, pero es posible que en estos momentos iniciales de aprendizaje nos resulte complicado hacer esto.
  
-Lo que podemos hacer, de una manera muy sencilla, es utilizar referencias visuales, como por ejemplo **llamar a las rutinas de la ROM que permiten imprimir en pantalla**, como ''RST 16'' (o ''RST $10'').+Lo que podemos hacer, de una manera muy sencilla, es utilizar referencias visuales, como por ejemplo **llamar a las rutinas de la ROM que permiten imprimir en pantalla**, como ''rst 16'' (o ''rst $10'').
  
-Veámos cómo funciona ''RST 16'' ensamblando y ejecutando el siguiente programa:+Veámos cómo funciona ''rst 16'' ensamblando y ejecutando el siguiente programa:
  
 <code z80> <code z80>
-ORG 35000+    ORG 35000
  
-    CALL $0DAF     ; CLS (borrar pantalla)+    call $0daf     ; CLS (borrar pantalla)
  
-    LD A, '*' +    ld a, '*' 
-    RST 16         ; Imprimir A en la posicion del cursor+    rst 16         ; Imprimir A en la posicion del cursor
  
-    RET +    ret 
-END 35000+ 
 +    END 35000
 </code> </code>
  
 En el listado hay 3 líneas nuevas añadidas a nuestro "esqueleto vacío de programa". En el listado hay 3 líneas nuevas añadidas a nuestro "esqueleto vacío de programa".
  
-La primera (''CALL $0DAF''), realiza un borrado de pantalla, resetea el cursor a (0,0) y también abre el "canal 2" (la pantalla) para poder imprimir texto.+La primera (''call $0daf''), realiza un borrado de pantalla, resetea el cursor a (0,0) y también abre el "canal 2" (la pantalla) para poder imprimir texto.
  
-Las otras 2 (''LD A, '*''' y ''RST 16'') se utilizan para llamar a una rutina de la ROM que imprime en la posición actual del cursor el carácter que esté en el registro A.+Las otras 2 (''ld a, '*''' y ''rst 16'') se utilizan para llamar a una rutina de la ROM que imprime en la posición actual del cursor el carácter que esté en el registro A.
  
 El resultado de ejecutar el programa de arriba sería: El resultado de ejecutar el programa de arriba sería:
Línea 90: Línea 97:
 \\  \\ 
  
-Podemos imprimir no sólo este carácter, sino todos cuantos deseemos, con sucesivas llamadas a ''RST 16'':+Podemos imprimir no sólo este carácter, sino todos cuantos deseemos, con sucesivas llamadas a ''rst 16'':
  
 <code z80> <code z80>
-ORG 35000+    ORG 35000 
 + 
 +    call $0daf     ; CLS (borrar pantalla)
  
-    CALL $0DAF     ; CLS (borrar pantalla)+    ld a, '*' 
 +    rst 16 
 +    ld a, 'A' 
 +    rst 16 
 +    ld a, 'S' 
 +    rst 16 
 +    ld a, 'M' 
 +    rst 16 
 +    ld a, '*' 
 +    rst 16
  
-    LD A, '*' +    ret
-    RST 16 +
-    LD A, 'A' +
-    RST 16 +
-    LD A, 'S' +
-    RST 16 +
-    LD A, 'M' +
-    RST 16 +
-    LD A, '*' +
-    RST 16+
  
-    RET +    END 35000
-END 35000+
 </code> </code>
  
Línea 116: Línea 124:
 \\  \\ 
  
-Algo muy importante al respecto de ''RST 16'' es que por defecto, imprime en el "CANAL 1", que son las 2 líneas de la parte inferior de la pantalla del Spectrum (donde aparecen los mensajes). Si queremos imprimir en la parte superior de la pantalla, tenemos que "abrir" el "CANAL 2". Esto ya lo hace la rutina CLS de la ROM que estamos usando.+Algo muy importante al respecto de ''rst 16'' es que por defecto, imprime en el "CANAL 1", que son las 2 líneas de la parte inferior de la pantalla del Spectrum (donde aparecen los mensajes). Si queremos imprimir en la parte superior de la pantalla, tenemos que "abrir" el "CANAL 2". Esto ya lo hace la rutina CLS de la ROM que estamos usando.
  
-Si queremos imprimir texto, pero no borrar la pantalla, al quitar el ''CALL $0DAF'' necesitaremos poner en su lugar la siguiente llamada para abrir el CANAL 2:+Si queremos imprimir texto, pero no borrar la pantalla, al quitar el ''call $0daf'' necesitaremos poner en su lugar la siguiente llamada para abrir el CANAL 2:
  
 <code z80> <code z80>
-ORG 35000+    ORG 35000
  
-    LD A, 2 +    ld a, 2 
-    CALL 5633     ; Abrir CANAL 2 para RST+    call 5633     ; Abrir CANAL 2 para RST
 </code> </code>
  
 En cualquier caso, lo habitual es borrar la pantalla con ''CLS'' por lo que se abrirá el canal 2 automáticamente al hacerlo y no necesitaremos hacerlo con la llamada anterior. En cualquier caso, lo habitual es borrar la pantalla con ''CLS'' por lo que se abrirá el canal 2 automáticamente al hacerlo y no necesitaremos hacerlo con la llamada anterior.
  
-Por otra parte, con ''RST 16'' podremos también saltar el cursor a la siguiente línea con el carácter 13:+Por otra parte, con ''rst 16'' podremos también saltar el cursor a la siguiente línea con el carácter 13:
  
 <code z80> <code z80>
-    LD A, 13 +    ld a, 13 
-    RST 16+    rst 16
 </code> </code>
  
 \\  \\ 
 \\  \\ 
-**Aprovechando RST 16 en nuestros programas para depurar:**\\ +**Aprovechando rst 16 en nuestros programas para depurar:**\\ 
  
 Con esta nueva funcionalidad ya podemos poner algo de feedback visual en nuestras pruebas. Volvamos a nuestro ejemplo de comparación, y modifiquémoslo para que imprima "=" si A==B o que imprima "!" si es A!=B (o podríamos haber usado "1" y "2", o cualquier otro valor arbitrario). Con esta nueva funcionalidad ya podemos poner algo de feedback visual en nuestras pruebas. Volvamos a nuestro ejemplo de comparación, y modifiquémoslo para que imprima "=" si A==B o que imprima "!" si es A!=B (o podríamos haber usado "1" y "2", o cualquier otro valor arbitrario).
  
 <code z80> <code z80>
-ORG 35000+    ORG 35000
  
-    CALL $0DAF     ; CLS (borrar pantalla)+    call $0daf     ; CLS (borrar pantalla)
  
-    LD A, 10 +    ld a, 10 
-    LD B, 20 +    ld b, 20 
-    CP B +    cp b 
-    JR NZ, es_diferente+    jr nz, es_diferente
  
 es_igual: es_igual:
     ; A = B     ; A = B
-    LD A, '=' +    ld a, '=' 
-    RST 16 +    rst 16 
-    JR fin+    jr fin
  
 es_diferente: es_diferente:
     ; A != B     ; A != B
-    LD A, '!' +    ld a, '!' 
-    RST 16+    rst 16
  
 fin: fin:
-    RET +    ret 
-END 35000+ 
 +    END 35000
 </code> </code>
  
Línea 173: Línea 182:
 ==== Usar constantes para las rutinas de la ROM ==== ==== Usar constantes para las rutinas de la ROM ====
  
-Si por cuestiones de legibilidad no te gusta ver en el código "Números Mágicos" (como ''CALL $0DAF''), ya que son difíciles de recordar, y hacen el listado ilegible, puedes utilizar directivas EQU para definir constantes más sencillas de leer.+Si por cuestiones de legibilidad no te gusta ver en el código "Números Mágicos" (como ''call $0daf''), ya que son difíciles de recordar, y hacen el listado ilegible, puedes utilizar directivas EQU para definir constantes más sencillas de leer.
  
 Este código es menos legible: Este código es menos legible:
  
 <code z80> <code z80>
-ORG 35000 +    ORG 35000
-    CALL $0DAF     ; Rutina CLS de la ROM+
  
-    LD A, "*" +    call $0daf     ; Rutina CLS de la ROM
-    RST 16+
  
-    RET +    ld a, "*" 
-END 35000+    rst 16 
 + 
 +    ret 
 + 
 +    END 35000
 </code> </code>
  
Línea 191: Línea 202:
  
 <code z80> <code z80>
-ORG 35000 +    ORG 35000 
-    CALL ROM_CLS+ 
 +    call ROM_CLS 
 + 
 +    ld a, "*" 
 +    rst 16
  
-    LD A, "*" +    ret
-    RST 16+
  
-    RET +ROM_CLS EQU $0daf
-END 35000+
  
-ROM_CLS EQU $0DAF+    END 35000
 </code> </code>
  
 Recomendamos encarecidamente definir ''EQU'''s para variables del sistema, rutinas de la ROM, etc. Recomendamos encarecidamente definir ''EQU'''s para variables del sistema, rutinas de la ROM, etc.
  
-De esa forma, cuando revisites tu código más adelante sabrás exáctamente qué hace ese CALL sin la necesidad de haber dejado un comentario.+De esa forma, cuando revisites tu código más adelante sabrás exáctamente qué hace ese call sin la necesidad de haber dejado un comentario.
  
 \\  \\ 
Línea 212: Línea 225:
 Otra opción muy sencilla para tener feedback visual podría ser, en lugar de imprimir caracteres por pantalla, cambiar el color del borde utilizando por ejemplo la rutina de la ROM. Otra opción muy sencilla para tener feedback visual podría ser, en lugar de imprimir caracteres por pantalla, cambiar el color del borde utilizando por ejemplo la rutina de la ROM.
  
-Se puede cambiar el borde cargando en el registro A un valor del 0 al 7 y llamando a la dirección 8859:+Se puede cambiar el borde cargando en el registro A un valor del 0 al 7 y llamando a la dirección $229b:
  
 <code z80> <code z80>
-    LD A, N         ; A = color +    ld a, N         ; A = color 
-    CALL 8859       ; Llamar a la rutina de la ROM+    call $229b      ; Llamar a la rutina de la ROM
 </code> </code>
  
Línea 246: Línea 259:
  
 <code z80> <code z80>
-    LD BC, valor_a_imprimir   ; (0-65535) +    ld bc, valor_a_imprimir   ; (0-65535) 
-    CALL $2D2B +    call $2d2b 
-    CALL $2DE3+    call $2de3
 </code> </code>
  
-La primera rutina (**$2D2B**) sirve para meter el valor de BC en la "pila de la calculadora" de BASIC, y la segunda rutina (**$2DE3**) sirve para imprimir en pantalla el último número introducido en dicha pila.+La primera rutina (**$2d2b**) sirve para meter el valor de BC en la "pila de la calculadora" de BASIC, y la segunda rutina (**$2de3**) sirve para imprimir en pantalla el último número introducido en dicha pila.
  
 Así pues, podemos poner cualquier valor en BC, hacer esas 2 llamadas a la ROM, y lo veremos aparecer en pantalla en la posición del cursor: Así pues, podemos poner cualquier valor en BC, hacer esas 2 llamadas a la ROM, y lo veremos aparecer en pantalla en la posición del cursor:
  
 <code z80> <code z80>
-ORG 40000 +    ORG 40000
-    CALL ROM_CLS+
  
-    LD BC, 1234        ; Queremos imprimir un valor directo +    call ROM_CLS
-    CALL ROM_STACK_BC +
-    CALL ROM_PRINT_FP+
  
-    LD A13 +    ld bc1234        ; Queremos imprimir un valor directo 
-    RST 16             ; Retorno de carro+    call ROM_STACK_BC 
 +    call ROM_PRINT_FP
  
-    LD HL5678        ; Queremos imprimir el valor de HL +    ld a13 
-                       ; No existe "LD BC, HL", asi que hacemos +    rst 16             Retorno de carro
-    LD B, H            B = H y C = L +
-    LD C, L            ; por lo que => BC = HL +
-    CALL ROM_STACK_BC +
-    CALL ROM_PRINT_FP+
  
-    LD A13 +    ld hl5678        ; Queremos imprimir el valor de HL 
-    RST 16             Retorno de carro+                       ; No existe "ld bc, hl", asi que hacemos 
 +    ld b, h            B = H y C = L 
 +    ld c, l            ; por lo que => BC = HL 
 +    call ROM_STACK_BC 
 +    call ROM_PRINT_FP
  
-    LD BC(variable)  Imprimir valor de variable (memoria) +    ld a13 
-    CALL ROM_STACK_BC +    rst 16             Retorno de carro
-    CALL ROM_PRINT_FP+
  
-    LD A13 +    ld bc(variable)  Imprimir valor de variable (memoria) 
-    RST 16             Retorno de carro+    call ROM_STACK_BC 
 +    call ROM_PRINT_FP
  
-    LD BC(RAMTOP)    ; Imprimir valor de RAMTOP (variable sistema) +    ld a13 
-    CALL ROM_STACK_BC +    rst 16             Retorno de carro
-    CALL ROM_PRINT_FP+
  
-    LD A13 +    ld bc(RAMTOP)    ; Imprimir valor de RAMTOP (variable sistema) 
-    RST 16             Retorno de carro+    call ROM_STACK_BC 
 +    call ROM_PRINT_FP
  
-    LD A255 +    ld a13 
-    LD B, 0 +    rst 16             Retorno de carro
-    LD C, A            Imprimir el valor de A (B=0) +
-    CALL ROM_STACK_BC +
-    CALL ROM_PRINT_FP+
  
-    RET+    ld a, 255 
 +    ld b, 0 
 +    ld c, a            ; Imprimir el valor de A (B=0) 
 +    call ROM_STACK_BC 
 +    call ROM_PRINT_FP 
 + 
 +    ret
  
 variable      DEFW 65535 variable      DEFW 65535
  
-RAMTOP        EQU  $5CB2 +RAMTOP        EQU  $5cb2 
-ROM_CLS       EQU  $0DAF +ROM_CLS       EQU  $0daf 
-ROM_STACK_BC  EQU  $2D2B +ROM_STACK_BC  EQU  $2d2b 
-ROM_PRINT_FP  EQU  $2DE3+ROM_PRINT_FP  EQU  $2de3
  
-END 40000+    END 40000
 </code> </code>
  
Línea 320: Línea 334:
 Ahora tenemos la capacidad de realizar cuantas pruebas queramos mediante nuestro "esqueleto de programa" (con ''ORG'', ''RET'' y ''END'') y con la posibilidad de sacar algo de feedback visual por pantalla para nuestras pruebas. Ahora tenemos la capacidad de realizar cuantas pruebas queramos mediante nuestro "esqueleto de programa" (con ''ORG'', ''RET'' y ''END'') y con la posibilidad de sacar algo de feedback visual por pantalla para nuestras pruebas.
  
-Otra cosa interesante que puede verse en el listado anterior es que en el juego de instrucciones del procesador Z80 no existe una instrucción ''LD BCHL''. Necesitamos poner en BC el valor a imprimir por pantalla, así que podemos hacerlo copiando la parte alta de HL en la parte alta de BC (''LD BH'') y después la parte baja de HL en la parte baja de BC (''LD CL''), que resulta en la copia exacta del contenido de HL en BC. Como veremos, en el microprocesador Z80 no podemos utilizar todas las instrucciones con todos los operandos, aunque hay pequeños trucos para saltarse estas limitaciones, como este. +Otra cosa interesante que puede verse en el listado anterior es que en el juego de instrucciones del procesador Z80 no existe una instrucción ''ld bchl''. Necesitamos poner en BC el valor a imprimir por pantalla, así que podemos hacerlo copiando la parte alta de HL en la parte alta de BC (''ld bh'') y después la parte baja de HL en la parte baja de BC (''ld cl''), que resulta en la copia exacta del contenido de HL en BC. Como veremos, en el microprocesador Z80 no podemos utilizar todas las instrucciones con todos los operandos, aunque hay pequeños trucos para saltarse estas limitaciones, como este.
  
 \\  \\ 
Línea 347: Línea 360:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintNum: PrintNum:
-    PUSH AF +    push af 
-    PUSH BC +    push bc 
-    PUSH DE +    push de 
-    PUSH HL +    push hl 
-    CALL $2D2B               ; ROM_STACK_BC +    call $2d2b                    ; ROM_STACK_BC 
-    CALL $2DE3               ; ROM_PRINT_FP +    call $2de3                    ; ROM_PRINT_FP 
-    POP HL +    pop hl 
-    POP DE +    pop de 
-    POP BC +    pop bc 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 368: Línea 381:
 ; PrintNum4digits: Imprime el numero en BC (0-9999). ; PrintNum4digits: Imprime el numero en BC (0-9999).
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-CLS             EQU  $0DAF               ; ROM_CLS +CLS             EQU  $0daf        ; ROM_CLS 
-CLS_COLOR       EQU  $5C8D               ; Variable del Sistema ATTR_P +CLS_COLOR       EQU  $5c8d        ; Variable del Sistema ATTR_P 
-BORDER          EQU  $229B               ; Rutina del borde +BORDER          EQU  $229b        ; Rutina del borde 
-PAUSE           EQU  $1F3D               ; PAUSAR BC/50 segundos (50 => 1s) +PAUSE           EQU  $1f3d        ; PAUSAR BC/50 segundos (50 => 1s) 
-MULT_HLDE       EQU  $30A9               ; Multiplica HL*DE => HL=HL*DE +MULT_HLDE       EQU  $30a9        ; Multiplica HL*DE => HL=HL*DE 
-PIXEL_ADDR2     EQU  $22B1               ; Devuelve direccion de pixel BC +PIXEL_ADDR2     EQU  $22b1        ; Devuelve direccion de pixel BC 
-PrintNum4digits EQU  $1A1B               ; Imprime valor de BC (0-9999)+PrintNum4digits EQU  $1a1b        ; Imprime valor de BC (0-9999)
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-; PrintChar: Hacer desde nuestro programa "CALL PrintChar", es el +; PrintChar: Hacer desde nuestro programa "call PrintChar", es el 
-;            equivalente a hacer un "CALL $0010", es decir, RST 16. +;            equivalente a hacer un "call $0010", es decir, rst 16. 
-;            Es un simple envoltorio de abreviatura (pero ocupa 3 bytes)+;            Es un simple envoltorio de abreviatura para preservar AF.
 ; ;
 ; ENTRADA:   A = caracter a imprimir por pantalla ; ENTRADA:   A = caracter a imprimir por pantalla
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-PrintChar EQU $0010          ; $0010 = RST $10 = RST 16 +PrintChar
-                             ; Podriamos llamar a $15E6 en su lugar +    push af 
-                             ; que es donde llama internamente $0010.+    rst 16 
 +    pop af 
 +    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 393: Línea 408:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintSpace: PrintSpace:
-    PUSH AF +    push af 
-    LD A, ' ' +    ld a, ' ' 
-    RST 16 +    rst 16 
-    POP AF +    pop af 
-    RET+    ret
  
 PrintCR: PrintCR:
-    PUSH AF +    push af 
-    LD A, 13 +    ld a, 13 
-    RST 16 +    rst 16 
-    POP AF +    pop af 
-    RET+    ret
 </code> </code>
  
Línea 410: Línea 425:
  
 <code z80> <code z80>
-ORG 33500 +    ORG 33500 
-    CALL CLS+ 
 +    call CLS
  
-    LD BC, 1234        ; Queremos imprimir un valor directo +    ld bc, 1234            ; Queremos imprimir un valor directo 
-    CALL PrintNum+    call PrintNum
  
-    LD A, 'd' +    ld a, 'd' 
-    CALL PrintChar     ; Imprimir sufijo 'd' despues del numero+    call PrintChar         ; Imprimir sufijo 'd' despues del numero
  
-    CALL PrintCR       ; Salto de linea+    call PrintCR           ; Salto de linea
  
-    LD BC, (variable)  ; Imprimir valor de variable (memoria) +    ld bc, (variable)      ; Imprimir valor de variable (memoria) 
-    CALL PrintNum+    call PrintNum
  
-    RET+    ret
  
 variable      DEFW 65535 variable      DEFW 65535
  
-;; Incluimos nuestra libreria aqui +    ;; Incluimos nuestra libreria aqui 
-INCLUDE "utils.asm"+    INCLUDE "utils.asm"
  
-END 33500+    END 33500
 </code> </code>
  
Línea 444: Línea 460:
 | **CLS** | Limpia la pantalla. Para ello utiliza el valor del atributo que haya alojado en la posición de memoria ''CLS_COLOR''. | | **CLS** | Limpia la pantalla. Para ello utiliza el valor del atributo que haya alojado en la posición de memoria ''CLS_COLOR''. |
 | **CLS_COLOR** | EQU (constante) que apunta a la dirección de la variable del sistema que permite establecer el color deseado al borrar la pantalla, en formato (COLOR_PAPEL*8)+COLOR_TINTA, llamada ''ATTR-P''. | | **CLS_COLOR** | EQU (constante) que apunta a la dirección de la variable del sistema que permite establecer el color deseado al borrar la pantalla, en formato (COLOR_PAPEL*8)+COLOR_TINTA, llamada ''ATTR-P''. |
-| **PrintChar** | Imprime en pantalla, en la posicion actual del cursor, el caracter contenido en A. | +| **PrintChar** | Imprime en pantalla, en la posicion actual del cursor, el caracter contenido en A. Es el equivalente a ''rst 16'' pero salva el valor de AF para que no se modifique en la rutina de la ROM. | 
-| **PrintCR** | Realiza un salto de linea (imprime el caracter 13 o _CR con ''RST 16''). | +| **PrintCR** | Realiza un salto de linea (imprime el caracter 13 o _CR con ''rst 16''). | 
-| **PrintSpace** | Imprime en pantalla, en la posicion actual del cursor, un espacio (con ''RST 16''). |+| **PrintSpace** | Imprime en pantalla, en la posicion actual del cursor, un espacio (con ''rst 16''). |
 | **PrintNum** | Imprime en pantalla, en la posicion actual del cursor, el valor decimal del contenido del registro BC, es decir, valores entre 0 y 65535. Utiliza para ello la pila de la calculadora BASIC, lo cual no es especialmente óptimo. | | **PrintNum** | Imprime en pantalla, en la posicion actual del cursor, el valor decimal del contenido del registro BC, es decir, valores entre 0 y 65535. Utiliza para ello la pila de la calculadora BASIC, lo cual no es especialmente óptimo. |
 | **PrintNum4digits** | Imprime en pantalla, en la posicion actual del cursor, el valor decimal del contenido del registro BC, siempre que este valga entre 0 y 9999. Es la rutina que usa el sistema para imprimir el número de línea de BASIC (''OUT_NUM_1''), no usa la pila de la calculadora y es más rápida que la anterior, pero limitada a 4 digitos. Según nuestras necesidades, podemos usar ''PrintNum'' o ''PrintNum4Digits'', siendo esta última una mejor opción para cualquier cosa cuyo valor esté controlado. | | **PrintNum4digits** | Imprime en pantalla, en la posicion actual del cursor, el valor decimal del contenido del registro BC, siempre que este valga entre 0 y 9999. Es la rutina que usa el sistema para imprimir el número de línea de BASIC (''OUT_NUM_1''), no usa la pila de la calculadora y es más rápida que la anterior, pero limitada a 4 digitos. Según nuestras necesidades, podemos usar ''PrintNum'' o ''PrintNum4Digits'', siendo esta última una mejor opción para cualquier cosa cuyo valor esté controlado. |
Línea 461: Línea 477:
 | **PrintHex** | Imprime en pantalla el valor del registro A en hexadecimal, con el prefijo '$'. Muy útil para ver el valor de un registro de 8 bits. | | **PrintHex** | Imprime en pantalla el valor del registro A en hexadecimal, con el prefijo '$'. Muy útil para ver el valor de un registro de 8 bits. |
 | **PrintHex16** | Imprime en pantalla el valor del registro BC en hexadecimal, con el prefijo '$'. Muy útil para ver el valor de un registro o posición de memoria de 16 bits. | | **PrintHex16** | Imprime en pantalla el valor del registro BC en hexadecimal, con el prefijo '$'. Muy útil para ver el valor de un registro o posición de memoria de 16 bits. |
-| **PrintString** | Imprime una cadena definida en memoria con (por ejemplo con ''DEFB''/''DB'') acabada en **$FF** como último byte (es el indicador de fin de cadena, para ellos se ha definido también una constante _EOS o -End Of String-). Como veremos en el ejemplo, la cadena soporta utilizar códigos de color, posicionamiento en coordenadas (y,x), flash, etc. | +| **PrintString** | Imprime una cadena definida en memoria con (por ejemplo con ''DEFB''/''DB'') acabada en **$ff** como último byte (es el indicador de fin de cadena, para ellos se ha definido también una constante _EOS o -End Of String-). Como veremos en el ejemplo, la cadena soporta utilizar códigos de color, posicionamiento en coordenadas (y,x), flash, etc. | 
-| **PrintNum2digits** | Imprime en la pantalla el valor de A, pero sólo los últimos 2 dígitos (0-99). Es ideal para imprimir valores como números de pantalla, vidas o tiempos, y además no usa la pila de la calculadora BASIC por lo que es mucho más rápida (además sólo imprimir 2 dígitos y del registro de 8 bits A). Para realizar la conversión de valor número a 2 ASCIIs a imprimir, utiliza una rutina auxiliar y después llama a RST 16 para imprimirlos. |+| **PrintNum2digits** | Imprime en la pantalla el valor de A, pero sólo los últimos 2 dígitos (0-99). Es ideal para imprimir valores como números de pantalla, vidas o tiempos, y además no usa la pila de la calculadora BASIC por lo que es mucho más rápida (además sólo imprimir 2 dígitos y del registro de 8 bits A). Para realizar la conversión de valor número a 2 ASCIIs a imprimir, utiliza una rutina auxiliar y después llama a rst 16 para imprimirlos. |
 | **Byte2ASCII_Dec2Digits** | Convierte el valor del registro H en una cadena de texto ASCII de max. 2 caracteres (0-99) decimales, y los devuelve en DE. | | **Byte2ASCII_Dec2Digits** | Convierte el valor del registro H en una cadena de texto ASCII de max. 2 caracteres (0-99) decimales, y los devuelve en DE. |
 | **CursorAt** | Mueve el cursor a las coordenadas de pantalla X,Y especificadas en DE (D=X, E=Y). Es importante que X esté entre 0 y 31 e Y entre 0 y 21 que son los límites del canal 2 (parte superior de la pantalla). | | **CursorAt** | Mueve el cursor a las coordenadas de pantalla X,Y especificadas en DE (D=X, E=Y). Es importante que X esté entre 0 y 31 e Y entre 0 y 21 que son los límites del canal 2 (parte superior de la pantalla). |
Línea 471: Línea 487:
 | **PIXEL_ADDR2** | Punto interno de la rutina de la ROM ''PIXEL_ADDRESS''. Esta rutina recibe en BC las coordenadas de un punto (B=Y en 0-192, C=X en 0-255) y devuelve en HL la dirección de memoria de la celdilla de la VideoRam que contiene en pixel, y en A el número de pixel donde está. | | **PIXEL_ADDR2** | Punto interno de la rutina de la ROM ''PIXEL_ADDRESS''. Esta rutina recibe en BC las coordenadas de un punto (B=Y en 0-192, C=X en 0-255) y devuelve en HL la dirección de memoria de la celdilla de la VideoRam que contiene en pixel, y en A el número de pixel donde está. |
 | **_INK**, **_PAPER**, **_AT**, etc | Constantes (también colores como **_RED**, **_BLUE**, etc) para utilizar como códigos de control en las cadenas. | | **_INK**, **_PAPER**, **_AT**, etc | Constantes (también colores como **_RED**, **_BLUE**, etc) para utilizar como códigos de control en las cadenas. |
-| **_EOS** | Constante para indicar fin de cadena ($FF). |+| **_EOS** | Constante para indicar fin de cadena ($ff). |
 | **_CR** | Constante para indicar fin de línea. | | **_CR** | Constante para indicar fin de línea. |
  
Línea 485: Línea 501:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 CursorAt: CursorAt:
-    PUSH AF +    push af 
-    LD A, _AT       ; Codigo control "AT Y,X" +    ld a, _AT                     ; Codigo control "AT Y,X" 
-    RST 16 +    rst 16 
-    LD AE         ; Y +    ld ae                       ; Y 
-    RST 16 +    rst 16 
-    LD AD         ; X +    ld ad                       ; X 
-    RST 16 +    rst 16 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 ; PrintString: Imprime en la pantalla una cadena acabada en un byte de ; PrintString: Imprime en la pantalla una cadena acabada en un byte de
-; valor $FF usando RST 16.+; valor $ff usando rst 16.
 ; ;
 ; ENTRADA:  DE = Dirección de la cadena a imprimir. ; ENTRADA:  DE = Dirección de la cadena a imprimir.
Línea 504: Línea 520:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintString: PrintString:
-    PUSH AF+    push af
 print_string_loop: print_string_loop:
-    LD A, (DE              ; Leemos el caracter apuntado por DE +    ld a, (de                   ; Leemos el caracter apuntado por DE 
-    CP _EOS                  ; chequeamos si es $FF (fin de cadena) +    CP _EOS                       ; chequeamos si es $ff (fin de cadena) 
-    JR Z, end_print_string   ; Si lo es, se activa el ZEROFLAG => SALIR +    jr z, end_print_string        ; Si lo es, se activa el ZEROFLAG => SALIR 
-    RST 16                   ; No lo es, no hemos saltado, imprimirlo +    rst 16                        ; No lo es, no hemos saltado, imprimirlo 
-    INC DE                   ; Avanzar al siguiente caracter de la cadena +    inc de                        ; Avanzar al siguiente caracter de la cadena 
-    JR print_string_loop     ; Repetir hasta que alguno sea 0 y salgamos+    jr print_string_loop          ; Repetir hasta que alguno sea 0 y salgamos
 end_print_string: end_print_string:
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-; PrintBin: Imprime en la pantalla un valor en binario usando RST 16.+; PrintBin: Imprime en la pantalla un valor en binario usando rst 16.
 ; Añade el prefijo '%' delante del numero impreso. ; Añade el prefijo '%' delante del numero impreso.
 ; ;
Línea 524: Línea 540:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintBin: PrintBin:
-    PUSH AF +    push af 
-    PUSH BC                  ; Preservamos los registros que se usaran+    push bc                       ; Preservamos los registros que se usaran
  
-    LD CA                  ; Guardamos en C copia de A +    ld ca                       ; Guardamos en C copia de A 
-    LD B, 8                  ; Imprimiremos el estado de los 8 bits+    ld b, 8                       ; Imprimiremos el estado de los 8 bits
  
-    LD A, '%' +    ld a, '%' 
-    RST 16                   ; Imprimir prefijo+    rst 16                        ; Imprimir prefijo
  
 printbin_loop: printbin_loop:
-    LD A, '1'                ; Para bit = 1, imprimiremos '1' +    ld a, '1'                     ; Para bit = 1, imprimiremos '1' 
-    BIT 7, C                 ; Chequeamos el estado del bit 7 +    bit 7, c                      ; Chequeamos el estado del bit 7 
-    JR NZ, printbin_es_uno   ; Dejamos A = 255 +    jr nz, printbin_es_uno        ; Dejamos A = 255 
-    LD A, '0'                ; A = '0'+    ld a, '0'                     ; A = '0'
  
 printbin_es_uno: printbin_es_uno:
-    RST 16                   ; Imprimimos (A): contiene '0' o '1' +    rst 16                        ; Imprimimos (A): contiene '0' o '1' 
-    RLC C                    ; Rotamos C a la izq para que podamos +    rlc c                         ; Rotamos C a la izq para que podamos 
-                             ; usar de nuevo el BIT 7 en el bucle +                                  ; usar de nuevo el BIT 7 en el bucle 
-    DJNZ printbin_loop       ; Repetimos 8 veces+    djnz printbin_loop            ; Repetimos 8 veces
  
-    POP BC +    pop bc 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 ; PrintHex: Imprime en la pantalla un numero de 1 byte en hexadecimal. ; PrintHex: Imprime en la pantalla un numero de 1 byte en hexadecimal.
 ; Para ello convierte el valor numérico en una cadena llamando a ; Para ello convierte el valor numérico en una cadena llamando a
-; Byte2ASCII_Hex y luego llama a RST 16 para imprimir cada caracter por+; Byte2ASCII_Hex y luego llama a rst 16 para imprimir cada caracter por
 ; separado. Imprime un $ delante y ESPACIO detrás. ; separado. Imprime un $ delante y ESPACIO detrás.
 ; ;
Línea 560: Línea 576:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintHex: PrintHex:
-    PUSH HL+    push hl
  
-    LD HA                  ; Guardamos A +    ld ha                       ; Guardamos A 
-    LD A, '$' +    ld a, '$' 
-    RST 16                   ; Imprimimos un "$" +    rst 16                        ; Imprimimos un "$" 
-    LD AH                  ; Recuperamos A+    ld ah                       ; Recuperamos A
  
-    PUSH AF +    push af 
-    PUSH DE+    push de
  
-    CALL Byte2ASCII_Hex      ; Convertimos A en Cadena HEX +    call Byte2ASCII_Hex           ; Convertimos A en Cadena HEX 
-    LD HL, Byte2ASCII_output ; HL apunta a la cadena+    ld hl, Byte2ASCII_output      ; HL apunta a la cadena
  
-    LD A, (HL+    ld a, (hl
-    RST 16                   ; Imprimimos primer valor HEX +    rst 16                        ; Imprimimos primer valor HEX 
-    INC HL                   ; Avanzar en la cadena +    inc hl                        ; Avanzar en la cadena 
-    LD A, (HL+    ld a, (hl
-    RST 16                   ; Imprimimos segundo valor HEX+    rst 16                        ; Imprimimos segundo valor HEX
  
-    POP DE +    pop de 
-    POP AF +    pop af 
-    POP HL +    pop hl 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 591: Línea 607:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintHex16: PrintHex16:
-    PUSH AF +    push af 
-    PUSH HL+    push hl
  
-    LD A, '$' +    ld a, '$' 
-    RST 16                   ; Imprimimos un "$"+    rst 16                        ; Imprimimos un "$"
  
-    LD HB +    ld hb 
-    CALL Byte2ASCII_Hex      ; Convertimos A en Cadena HEX +    call Byte2ASCII_Hex           ; Convertimos A en Cadena HEX 
-    LD HL, Byte2ASCII_output ; HL apunta a la cadena +    ld hl, Byte2ASCII_output      ; HL apunta a la cadena 
-    LD A, (HL+    ld a, (hl
-    RST 16                   ; Imprimimos primer valor HEX +    rst 16                        ; Imprimimos primer valor HEX 
-    INC HL                   ; Avanzar en la cadena +    inc hl                        ; Avanzar en la cadena 
-    LD A, (HL+    ld a, (hl
-    RST 16                   ; Imprimimos segundo valor HEX+    rst 16                        ; Imprimimos segundo valor HEX
  
-    LD HC +    ld hc 
-    CALL Byte2ASCII_Hex      ; Convertimos A en Cadena HEX +    call Byte2ASCII_Hex           ; Convertimos A en Cadena HEX 
-    LD HL, Byte2ASCII_output ; HL apunta a la cadena +    ld hl, Byte2ASCII_output      ; HL apunta a la cadena 
-    LD A, (HL+    ld a, (hl
-    RST 16                   ; Imprimimos primer valor HEX +    rst 16                        ; Imprimimos primer valor HEX 
-    INC HL                   ; Avanzar en la cadena +    inc hl                        ; Avanzar en la cadena 
-    LD A, (HL+    ld a, (hl
-    RST 16                   ; Imprimimos segundo valor HEX+    rst 16                        ; Imprimimos segundo valor HEX
  
-    POP HL +    pop hl 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 629: Línea 645:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Byte2ASCII_Hex: Byte2ASCII_Hex:
-    PUSH AF +    push af 
-    PUSH DE +    push de 
-    PUSH HL +    push hl 
-    LD DE, Byte2ASCII_output +    ld de, Byte2ASCII_output 
-    LD AH +    ld ah 
-    CALL B2AHex_Num1 +    call B2AHex_Num1 
-    LD AH +    ld ah 
-    CALL B2AHex_Num2 +    call B2AHex_Num2 
-    JP B2AHex_Exit+    jp B2AHex_Exit
  
 B2AHex_Num1: B2AHex_Num1:
-    RRA +    rra 
-    RRA +    rra 
-    RRA +    rra 
-    RRA+    rra
  
 B2AHex_Num2: B2AHex_Num2:
-    OR $F0 +    or $f0 
-    DAA +    daa 
-    ADD A, $A0 +    add a, $a0 
-    ADC A, $40 +    adc a, $40 
-    LD (DE), A +    ld (de), a 
-    INC DE +    inc de 
-    RET+    ret
  
 B2AHex_Exit: B2AHex_Exit:
-    POP HL +    pop hl 
-    POP DE +    pop de 
-    POP AF +    pop af 
-    RET+    ret
  
 Byte2ASCII_output DB 0, 0 Byte2ASCII_output DB 0, 0
Línea 667: Línea 683:
 ; base 10, pero solo los 2 últimos digitos (0-99). Para ello convierte ; base 10, pero solo los 2 últimos digitos (0-99). Para ello convierte
 ; el valor numerico en una cadena llamando a Byte2ASCII_2Dig y luego ; el valor numerico en una cadena llamando a Byte2ASCII_2Dig y luego
-; llama a RST 16 para imprimir cada caracter por separado.+; llama a rst 16 para imprimir cada caracter por separado.
 ; ;
 ; ENTRADA:  A = valor a "imprimir" en 2 digitos de base 10. ; ENTRADA:  A = valor a "imprimir" en 2 digitos de base 10.
Línea 674: Línea 690:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintNum2digits: PrintNum2digits:
-    PUSH AF +    push af 
-    PUSH DE +    push de 
-    CALL Byte2ASCII_Dec2Digits     ; Convertimos A en Cadena Dec 0-99 +    call Byte2ASCII_Dec2Digits    ; Convertimos A en Cadena Dec 0-99 
-    LD AD +    ld ad 
-    RST 16                         ; Imprimimos primer valor HEX +    rst 16                        ; Imprimimos primer valor HEX 
-    LD AE +    ld ae 
-    RST 16                         ; Imprimimos segundo valor HEX+    rst 16                        ; Imprimimos segundo valor HEX
  
-    POP DE +    pop de 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 698: Línea 714:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Byte2ASCII_Dec2Digits: Byte2ASCII_Dec2Digits:
-    LD D, '0'                      ; Starting from ASCII '0' +    ld d, '0'                     ; Starting from ASCII '0' 
-    DEC D                          ; Because we are inc'ing in the loop +    dec d                         ; Because we are inc'ing in the loop 
-    LD E, 10                       ; Want base 10 please +    ld e, 10                      ; Want base 10 please 
-    AND A                          ; Clear carry flag+    and a                         ; Clear carry flag
  
 dtoa2dloop: dtoa2dloop:
-    INC D                          ; Increase the number of tens +    inc d                         ; Increase the number of tens 
-    SUB E                          ; Take away one unit of ten from A +    sub e                         ; Take away one unit of ten from A 
-    JR NC, dtoa2dloop              ; If A still hasn't gone negative, do another +    jr nc, dtoa2dloop             ; If A still hasn't gone negative, do another 
-    ADD AE                       ; Decreased it too much, put it back +    add ae                      ; Decreased it too much, put it back 
-    ADD A, '0'                     ; Convert to ASCII +    add a, '0'                    ; Convert to ASCII 
-    LD EA                        ; Stick remainder in E +    ld ea                       ; Stick remainder in E 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 719: Línea 735:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintFlags: PrintFlags:
-    PUSH AF +    push af 
-    PUSH BC+    push bc
  
-    PUSH AF            ; Metemos AF en al pila pero sacamos BC +    push af                       ; Metemos AF en al pila pero sacamos BC 
-    POP BC             ; Ahora C contiene el valor de F +    pop bc                        ; Ahora C contiene el valor de F 
-    LD AC +    ld ac 
-    CALL PrintBin +    call PrintBin 
-    POP BC +    pop bc 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 738: Línea 754:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 PrintFlag: PrintFlag:
-    PUSH AF +    push af 
-    PUSH BC+    push bc
  
-    PUSH AF              ; Metemos AF en al pila pero sacamos BC +    push af                       ; Metemos AF en al pila pero sacamos BC 
-    POP BC               ; Ahora C contiene el valor de F +    pop bc                        ; Ahora C contiene el valor de F 
-                         ; y B contiene el antiguo valor A +                                  ; y B contiene el antiguo valor A 
-    LD AC+    ld ac
 loopPrintFlag: loopPrintFlag:
-    RLC A                ; rotamos A veces el bit +    rlc a                         ; rotamos A veces el bit 
-    DJNZ loopPrintFlag+    djnz loopPrintFlag
  
-    AND %00000001        ; Borramos todos los bits menos bit 0 +    and %00000001                 ; Borramos todos los bits menos bit 0 
-    ADD A, '0'           ; Sumamos '0' para obtener ASCII+    add a, '0'                    ; Sumamos '0' para obtener ASCII
  
-    RST 16 +    rst 16 
-    POP BC +    pop bc 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 765: Línea 781:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Wait_For_Key: Wait_For_Key:
-    CALL Wait_For_No_Key +    call Wait_For_No_Key 
-    PUSH AF+    push af
 wait_for_key_loop: wait_for_key_loop:
-    XOR A                        ; A = 0 +    xor a                         ; A = 0 
-    IN A, (254+    in a, ($FE
-    OR 224 +    or %11100000 
-    INC A +    inc a 
-    JR Z, wait_for_key_loop +    jr z, wait_for_key_loop 
-    POP AF +    pop af 
-    LD A, ($5C08               ; Devolver Variable LAST-K en A +    ld a, ($5c08                ; Devolver Variable LAST-K en A 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
Línea 784: Línea 800:
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 Wait_For_No_Key: Wait_For_No_Key:
-    PUSH AF+    push af
 wait_for_no_key_loop: wait_for_no_key_loop:
-    XOR A +    xor a 
-    IN A, ($FE+    in a, ($fe
-    OR 224 +    or %11100000 
-    INC A +    inc a 
-    JR NZ, wait_for_no_key_loop +    jr nz, wait_for_no_key_loop 
-    POP AF +    pop af 
-    RET+    ret
  
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
 ; Constantes definidas para usar con cadenas o RST ; Constantes definidas para usar con cadenas o RST
 ;----------------------------------------------------------------------- ;-----------------------------------------------------------------------
-_EOS        EQU $FF+_EOS        EQU $ff
 _CR         EQU 13 _CR         EQU 13
 _INK        EQU 16 _INK        EQU 16
Línea 835: Línea 851:
 <code z80> <code z80>
 ; Prueba de la libreria "utils.asm" ; Prueba de la libreria "utils.asm"
-ORG 33500+    ORG 33500
  
-    LD A, _BLUE        ; Color para el borde +    ld a, _BLUE        ; Color para el borde 
-    CALL BORDER+    call BORDER
  
-    LD A, _BLUE*8+_WHITE +    ld a, _BLUE*8+_WHITE 
-    LD (CLS_COLOR),   ; Color para CLS (por defecto es $38)+    ld (CLS_COLOR),   ; Color para CLS (por defecto es $38)
  
-    CALL CLS            ; CLS+    call CLS            ; CLS
  
-    LD BC, 50*3 +    ld bc, 50*3 
-    CALL PAUSE          ; Pausar 3 segundos antes de continuar+    call PAUSE          ; Pausar 3 segundos antes de continuar
  
-    LD BC, 65535 +    ld bc, 65535 
-    CALL PrintNum       ; Prueba decimal+    call PrintNum       ; Prueba decimal
  
-    CALL PrintSpace     ; Imprimir espacio+    call PrintSpace     ; Imprimir espacio
  
-    LD A, $F0 +    ld a, $f0 
-    CALL PrintHex       ; Prueba hexadecimal 8+    call PrintHex       ; Prueba hexadecimal 8
  
-    CALL PrintSpace     ; Imprimir espacio+    call PrintSpace     ; Imprimir espacio
  
-    LD BC, $F01A +    ld bc, $f01a 
-    CALL PrintHex16     ; Prueba hexadecimal 16+    call PrintHex16     ; Prueba hexadecimal 16
  
-    CALL PrintSpace     ; Imprimir espacio+    call PrintSpace     ; Imprimir espacio
  
-    LD A, 193           ; o "LD A, %11000001" +    ld a, 193           ; o "ld a, %11000001" 
-    CALL PrintBin       ; Prueba binario+    call PrintBin       ; Prueba binario
  
-    CALL PrintCR +    call PrintCR 
-    CALL PrintCR        ; 2 saltos de linea+    call PrintCR        ; 2 saltos de linea
  
-    LD DE, cadena1 +    ld de, cadena1 
-    CALL PrintString    ; Cadena ("FLAGS y FLAG Z")+    call PrintString    ; Cadena ("FLAGS y FLAG Z")
  
-    CALL PrintFlags     ; Imprimir valor de Flags +    call PrintFlags     ; Imprimir valor de Flags 
-    CALL PrintSpace     ; Imprimir un espacio +    call PrintSpace     ; Imprimir un espacio 
-    LD A, _FLAG_Z +    ld a, _FLAG_Z 
-    CALL PrintFlag      ; Imprimir valor 0/1 FLAG_Z+    call PrintFlag      ; Imprimir valor 0/1 FLAG_Z
  
-    CALL PrintCR +    call PrintCR 
-    CALL PrintCR+    call PrintCR
  
-    LD DE, cadena2 +    ld de, cadena2 
-    CALL PrintString    ; Cadena con saltos de linea+    call PrintString    ; Cadena con saltos de linea
  
-    LD DE, cadena3 +    ld de, cadena3 
-    CALL PrintString    ; Cadena con saltos de linea+    call PrintString    ; Cadena con saltos de linea
  
-    LD DE, cadena4 +    ld de, cadena4 
-    CALL PrintString    ; Cadena con codigos de control+    call PrintString    ; Cadena con codigos de control
  
-    LD D, 25 +    ld d, 25 
-    LD E, 21            ; X = 31, y = 21 +    ld e, 21            ; X = 31, y = 21 
-    CALL CursorAt       ; mover Cursor+    call CursorAt       ; mover Cursor
  
-    LD A, '*' +    ld a, '*' 
-    CALL PrintChar      ; Imprimir '*'+    call PrintChar      ; Imprimir '*'
  
     ; Esperar pulsacion de tecla antes de salir e imprimirla     ; Esperar pulsacion de tecla antes de salir e imprimirla
-    CALL Wait_For_Key +    call Wait_For_Key 
-    CALL PrintChar+    call PrintChar
  
-    RET+    ret
  
-cadena1 DEFB 'FLAGS (F) y ZF: ', $FF+cadena1 DEFB 'FLAGS (F) y ZF: ', $ff
  
 cadena2 DEFB 'Esto es una cadena con salto', _CR, _EOS cadena2 DEFB 'Esto es una cadena con salto', _CR, _EOS
Línea 914: Línea 930:
         DEFB _FLASH, 1, 'FLASH 1', _FLASH, 0, ' FLASH 0', _EOS         DEFB _FLASH, 1, 'FLASH 1', _FLASH, 0, ' FLASH 0', _EOS
  
-; Incluimos nuestra "libreria" de funciones +    ; Incluimos nuestra "libreria" de funciones 
-INCLUDE "utils.asm"+    INCLUDE "utils.asm"
  
-END 33500+    END 33500
 </code> </code>
  
Línea 945: Línea 961:
 No debemos preocuparnos por estos warnings. Pasmo simplemente nos está advirtiendo de que hemos definido unas etiquetas ''EQU'' en el código (como por ejemplo ''_MAGENTA'') que después no hemos usado en ninguna otra parte del programa. Sólo son mensajes informativos para que podamos hacer limpieza de referencias y variables que no se usan en el programa que estamos ensamblando. En nuestro caso, esas variables deben de estar en la librería aunque no las estemos usando en este programa concreto por lo que podemos ignorar los mensajes. No debemos preocuparnos por estos warnings. Pasmo simplemente nos está advirtiendo de que hemos definido unas etiquetas ''EQU'' en el código (como por ejemplo ''_MAGENTA'') que después no hemos usado en ninguna otra parte del programa. Sólo son mensajes informativos para que podamos hacer limpieza de referencias y variables que no se usan en el programa que estamos ensamblando. En nuestro caso, esas variables deben de estar en la librería aunque no las estemos usando en este programa concreto por lo que podemos ignorar los mensajes.
  
-Otro apunte importante sobre nuestro programa de ejemplo es que normalmente, en la mayoría de lenguajes de programación, se suele utilizar 0 (no '0', sino 0) como indicador de final de cadena, pero en nuestro caso hemos preferido usar $FF (asociado a la constante ''_EOS''). Hemos usado este valor porque nuestra cadena puede contener ceros (0) que se usan para desactivar funciones como FLASH o BRIGHT, tal y como muestra el ejemplo en la última línea de la variable ''cadena4''. Si usáramos 0 como indicador de final de cadena, la secuencia "''_FLASH, 0''" marcaría el fin de cadena para la rutina y no se imprimiría el resto.+Otro apunte importante sobre nuestro programa de ejemplo es que normalmente, en la mayoría de lenguajes de programación, se suele utilizar 0 (no '0', sino 0) como indicador de final de cadena, pero en nuestro caso hemos preferido usar $ff (asociado a la constante ''_EOS''). Hemos usado este valor porque nuestra cadena puede contener ceros (0) que se usan para desactivar funciones como FLASH o BRIGHT, tal y como muestra el ejemplo en la última línea de la variable ''cadena4''. Si usáramos 0 como indicador de final de cadena, la secuencia "''_FLASH, 0''" marcaría el fin de cadena para la rutina y no se imprimiría el resto.
  
 Queremos destacar de nuevo que el objetivo de esta librería de funciones es recoger funciones básicas para el desarrollo del curso. En el momento en que nos planteemos desarrollar un juego o una aplicación de calidad profesional, habrá que reescribir esta librería de forma que no funcione mediante llamadas a la ROM. Gracias a tener el código en una librería, siempre podemos reescribir las funciones y hacer que trabajen directamente con la videoRAM, o más óptimas, o más rápidas, o de menor tamaño, y si mantenemos los mismos parámetros de entrada y de salida de cada función, no necesitaremos modificar el código que usa la librería, sólo re-ensamblar el programa. Queremos destacar de nuevo que el objetivo de esta librería de funciones es recoger funciones básicas para el desarrollo del curso. En el momento en que nos planteemos desarrollar un juego o una aplicación de calidad profesional, habrá que reescribir esta librería de forma que no funcione mediante llamadas a la ROM. Gracias a tener el código en una librería, siempre podemos reescribir las funciones y hacer que trabajen directamente con la videoRAM, o más óptimas, o más rápidas, o de menor tamaño, y si mantenemos los mismos parámetros de entrada y de salida de cada función, no necesitaremos modificar el código que usa la librería, sólo re-ensamblar el programa.
Línea 951: Línea 967:
 Por otra parte, no es normal hacer una única librería (un único fichero ''utils.asm'') sino que lo habitual es separar las rutinas de apoyo en diferentes ficheros por funcionalidad (''teclado.asm'', ''graficos.asm'', ''texto.asm'') de forma que podamos incluir en nuestro programa sólo aquellas que necesitemos. Por otra parte, no es normal hacer una única librería (un único fichero ''utils.asm'') sino que lo habitual es separar las rutinas de apoyo en diferentes ficheros por funcionalidad (''teclado.asm'', ''graficos.asm'', ''texto.asm'') de forma que podamos incluir en nuestro programa sólo aquellas que necesitemos.
  
-Cuando hacemos un ''INCLUDE'' de un fichero asm en nuestro programa, el ensamblador "añade" todo el código del fichero en nuestro programa, como si lo hubiéramos incluído manualmente en ese punto. Eso quiere decir que el ensamblador realizará el ensamblado de todo el código y que el ejecutable del programa "engordará" con todo el código incluído. Incluso aunque sólo vayamos a utilizar, por ejemplo, la rutina PrintNum, en el binario resultante estará el código de todas las funciones del fichero ASM incluído, lo que significa que ocupará más y tardará más tiempo en cargar. +Cuando hacemos un ''INCLUDE'' de un fichero asm en nuestro programa, el ensamblador "añade" todo el código del fichero en nuestro programa, como si lo hubiéramos incluído manualmente en ese punto. Eso quiere decir que el ensamblador realizará el ensamblado de todo el código y que el ejecutable del programa "engordará" con todo el código incluído. Incluso aunque sólo vayamos a utilizar, por ejemplo, la rutina PrintNum, en el binario resultante estará el código de todas las funciones del fichero ASM incluído, lo que significa que ocupará más y tardará más tiempo en cargar.
  
 Por eso, esta librería **utils.asm** que contiene múltiples funciones variadas, la utilizaremos para nuestras pruebas, ya que realizando pruebas no nos importará que librería aumente el tamaño final en los menos de 300 bytes que ocupa el código de la librería, pero lo normal es no utilizarla en las versiones finales de nuestros programas o juegos. Además, la librería dista mucho de ser óptima, ya que utiliza rutinas de la ROM para realizar determinadas tareas, y más adelante desarrollaremos nuestras propias rutinas mucho más eficientes. Por eso, esta librería **utils.asm** que contiene múltiples funciones variadas, la utilizaremos para nuestras pruebas, ya que realizando pruebas no nos importará que librería aumente el tamaño final en los menos de 300 bytes que ocupa el código de la librería, pero lo normal es no utilizarla en las versiones finales de nuestros programas o juegos. Además, la librería dista mucho de ser óptima, ya que utiliza rutinas de la ROM para realizar determinadas tareas, y más adelante desarrollaremos nuestras propias rutinas mucho más eficientes.
  • cursos/ensamblador/esqueleto_programa.1705071003.txt.gz
  • Última modificación: 12-01-2024 14:50
  • por sromero