cursos:ensamblador:introduccion

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:introduccion [06-01-2024 14:53] – [Enlaces] sromerocursos:ensamblador:introduccion [24-01-2024 12:40] (actual) – [El Emulador como otra herramienta de desarrollado] sromero
Línea 15: Línea 15:
  
 \\  \\ 
-{{ cursos:ensamblador:basic.gif?640 |Lenguaje BASIC y su intérprete}}+{{ cursos:ensamblador:basic.gif?638 |Lenguaje BASIC y su intérprete.}}
 \\  \\ 
 ;#; ;#;
Línea 24: Línea 24:
  Para muchos, el BASIC del Spectrum es un comienzo prácticamente obligado para programar, pero si queremos realizar programas con la calidad del software comercial no puede ser la herramienta a utilizar. Dejando de lado que sigue siendo una herramienta muy útil para programar en el Spectrum, para muchos llega la hora de dar el siguiente paso.  Para muchos, el BASIC del Spectrum es un comienzo prácticamente obligado para programar, pero si queremos realizar programas con la calidad del software comercial no puede ser la herramienta a utilizar. Dejando de lado que sigue siendo una herramienta muy útil para programar en el Spectrum, para muchos llega la hora de dar el siguiente paso.
  
- Para hacer juegos o programas de calidad comercial en el Spectrum, podemos obviar totalmente el lenguaje BASIC excepto por una serie de comandos que nos serán necesarios para cargar en memoria nuestros programas: comandos como **CLEAR****LOAD "" SCREEN$****LOAD "" CODE****USR****POKE** **DATA**, pueden ser necesarios en el "CARGADOR BASIC" de nuestro programa.+ Para hacer juegos o programas de calidad comercial en el Spectrum, podemos obviar totalmente el lenguaje BASIC excepto por una serie de comandos que nos serán necesarios para cargar en memoria nuestros programas: comandos como ''CLEAR''''LOAD "" SCREEN$''''LOAD "" CODE''''USR''''POKE'' ''DATA'' pueden ser necesarios en el "CARGADOR BASIC" de nuestro programa.
  
- El cargador BASIC es el pequeño programa en BASIC que el Spectrum y autoejecuta cuando tecleamos **LOAD ""**, introducimos una cinta y pulsamos PLAY. El Spectrum carga el pequeño programa en BASIC (el "cargador"), y lo ejecuta. En este cargador es donde introduciremos las pocas líneas de BASIC que necesitaremos para lanzar  nuestro programa, haciendo por ejemplo cosas como borrar la pantalla (CLS), colocar BASIC por debajo de una posición de memoria para poder disponer del resto de la memoria como libre (CLEAR), cargar desde cinta la pantalla de carga del juego (LOAD "" SCREEN$), y cargar el código ensamblado de nuestro juego (LOAD "" CODE) para, por fin, saltar a la ejecución al mismo (RANDOMIZE USR).+ El cargador BASIC es el pequeño programa en BASIC que el Spectrum y autoejecuta cuando tecleamos ''LOAD ""'', introducimos una cinta y pulsamos PLAY. El Spectrum carga el pequeño programa en BASIC (el "cargador"), y lo ejecuta. En este cargador es donde introduciremos las pocas líneas de BASIC que necesitaremos para lanzar  nuestro programa, haciendo por ejemplo cosas como borrar la pantalla (''CLS''), colocar BASIC por debajo de una posición de memoria para poder disponer del resto de la memoria como libre (''CLEAR''), cargar desde cinta la pantalla de carga del juego (''LOAD "" SCREEN$''), y cargar el código ensamblado de nuestro juego (''LOAD "" CODE'') para, por fin, saltar a la ejecución al mismo (''RANDOMIZE USR'').
  
-<code basic+<code sinclairbasic
-10 REM Cargador BASIC de un juego+10 REM Cargador BASIC de un juego.
 15 REM Carga la pantalla del juego desde cinta 15 REM Carga la pantalla del juego desde cinta
 20 REM luego con un POKE oculta el mensaje "Bytes:" 20 REM luego con un POKE oculta el mensaje "Bytes:"
Línea 62: Línea 62:
 Ahora tenemos 2 opciones para utilizar ese "código máquina" en nuestro programa BASIC. Ahora tenemos 2 opciones para utilizar ese "código máquina" en nuestro programa BASIC.
  
-1.- Si el código máquina resultante es pequeño, porque por ejemplo sólo hemos desarrollado una rutina y apenas ocupa unos pocos bytes, podemos introducir los valores del binario obtenido en nuestro programa BASIC con DATA y POKEarlos en memoria en la dirección deseada. Pongamos por ejemplo que pokeamos esta rutina a partir de la dirección de memoria 40000 (desde 40000 hasta 40000+N siendo N el tamaño del bloque código máquina resultante). Ahora, cuando necesitemos llamar a la rutina en medio de nuestro programa BASIC, lo podremos hacer con un **RANDOMIZE USR 40000**.+1.- Si el código máquina resultante es pequeño, porque por ejemplo sólo hemos desarrollado una rutina y apenas ocupa unos pocos bytes, podemos introducir los valores del binario obtenido en nuestro programa BASIC con DATA y POKEarlos en memoria en la dirección deseada. Pongamos por ejemplo que pokeamos esta rutina a partir de la dirección de memoria 40000 (desde 40000 hasta 40000+N siendo N el tamaño del bloque código máquina resultante). Ahora, cuando necesitemos llamar a la rutina en medio de nuestro programa BASIC, lo podremos hacer con un ''RANDOMIZE USR 40000''.
  
-2.- Si por contra el código máquina resultante es grande, porque hemos desarrollado muchas rutinas, pasar estos datos a DATA para POKEarlos es inviable. En ese caso, lo que haríamos sería guardar el bloque de código máquina en cinta justo después de nuestro programa en BASIC. Después, al principio de nuestro programa BASIC cargamos en memoria el bloque de datos de código máquina que va después del mismo en cinta mediante un (por ejemplo) **LOAD "" CODE 40000**. Una vez tenemos el codigo máquina en memoria, tendremos las diferentes rutinas a partir de la dirección 40000, y podremos utilizar RANDOMIZE USR a la dirección de cada una de ellas en memoria (podríamos por ejemplo tener una rutina de borrado de pantalla en la dirección 40000 y una rutina para dibujar un gráfico en 40100).+2.- Si por contra el código máquina resultante es grande, porque hemos desarrollado muchas rutinas, pasar estos datos a DATA para POKEarlos es inviable. En ese caso, lo que haríamos sería guardar el bloque de código máquina en cinta justo después de nuestro programa en BASIC. Después, al principio de nuestro programa BASIC cargamos en memoria el bloque de datos de código máquina que va después del mismo en cinta mediante un (por ejemplo) ''LOAD "" CODE 40000''. Una vez tenemos el codigo máquina en memoria, tendremos las diferentes rutinas a partir de la dirección 40000, y podremos utilizar ''RANDOMIZE USR'' a la dirección de cada una de ellas en memoria (podríamos por ejemplo tener una rutina de borrado de pantalla en la dirección 40000 y una rutina para dibujar un gráfico en 40100).
  
- Es decir: en ambos casos realizamos una rutina o un conjunto de rutinas en ensamblador y mediante un //programa ensamblador//, traducimos el código ASM a código que entiende directamente la máquina (código binario) y lo salvamos en cinta (o si es corto, anotamos sus valores para meterlos en DATAs). Después, al inicio de nuestro programa, introducimos ese código binario en memoria de forma que lo podamos llamar en cualquier momento desde BASIC con RANDOMIZE USR.+ Es decir: en ambos casos realizamos una rutina o un conjunto de rutinas en ensamblador y mediante un //programa ensamblador//, traducimos el código ASM a código que entiende directamente la máquina (código binario) y lo salvamos en cinta (o si es corto, anotamos sus valores para meterlos en DATAs). Después, al inicio de nuestro programa, introducimos ese código binario en memoria de forma que lo podamos llamar en cualquier momento desde BASIC con ''RANDOMIZE USR''.
  
- Esto permite realizar rutinas importantes y críticas en lenguaje ensamblador, y mantener el esqueleto del programa principal en BASIC. Las rutinas creadas en ensamblador son llamadas desde BASIC con la instrucción **USR** ("RANDOMIZE USR x""PRINT USR x"LET A=USR x") en aquellos puntos del programa en que las necesitemos.+ Esto permite realizar rutinas importantes y críticas en lenguaje ensamblador, y mantener el esqueleto del programa principal en BASIC. Las rutinas creadas en ensamblador son llamadas desde BASIC con la instrucción ''USR'' (''RANDOMIZE USR x''''PRINT USR x'' ''LET A=USR x'') en aquellos puntos del programa en que las necesitemos.
  
  Más adelante en este capítulo veremos un ejemplo de cómo realizar el ensamblado de una rutina en ensamblador, su carga en memoria y su utilización desde un programa en BASIC.  Más adelante en este capítulo veremos un ejemplo de cómo realizar el ensamblado de una rutina en ensamblador, su carga en memoria y su utilización desde un programa en BASIC.
Línea 96: Línea 96:
  
 \\  \\ 
-   * Programamos nuestro juego en lenguaje BASIC (siguiendo las reglas especiales que lo diferencien del BASIC estándar del Spectrum) escribiendo el programa en un editor de textos estándar de nuestra plataforma de desarrollo. +   * Programamos nuestro juego en lenguaje BASIC (siguiendo las reglas especiales que lo diferencien del BASIC estándar del Spectrum) escribiendo el programa en un editor de textos estándar de nuestra plataforma de desarrollo. Para ello utilizaremos uno o más ficheros ''.BAS''.
- +
-   * Grabamos el código de nuestro programa como uno o varios ficheros .BAS.+
  
    * Mediante el compilador cruzado, compilamos los ficheros .BAS y obtenemos un fichero binario de código máquina, normalmente con un cargador BASIC incluído al principio del mismo.    * Mediante el compilador cruzado, compilamos los ficheros .BAS y obtenemos un fichero binario de código máquina, normalmente con un cargador BASIC incluído al principio del mismo.
  
-   * Cargamos ese código máquina en nuestro Spectrum o emulador con un simple LOAD "" y el programa se carga y ejecuta como cualquier otro juego comercial.+   * Cargamos ese código máquina en nuestro Spectrum o emulador con un simple ''LOAD ""'' y el programa se carga y ejecuta como cualquier otro juego comercial.
 \\  \\ 
  
- Es una opción muy interesante para quien quiera seguir programando en BASIC y obtener la potencia que el intérprete de BASIC le resta.+ Es una opción muy interesante para quien quiera seguir programando en BASIC y obtener la potencia que el intérprete de BASIC del Spectrum le resta. Para este caso de uso, **ZX Basic** es una excelentísima herramienta que puede producir resultados espectaculares, con una comunidad detrás que crea librerías de funciones para que podamos hacer programas o juegos de calidad comercial.
  
 \\  \\ 
Línea 119: Línea 117:
  
 \\  \\ 
-   * Programamos nuestro juego en lenguaje C escribiendo el programa en un editor de textos estándar de nuestra plataforma de desarrollo.+   * Programamos nuestro juego en lenguaje C escribiendo el programa en un editor de textos estándar de nuestra plataforma de desarrollo. Escribiermos por tanto el código de nuestro programa como uno o varios ficheros ''.C'', con sus ficheros de cabecera ''.H''.
  
-   Grabamos el código de nuestro programa como uno o varios ficheros .C, con sus ficheros de cabecera .H.+   Mediante el compilador cruzado, compilamos los ficheros ''.C'' y obtenemos un fichero binario de código máquinanormalmente con un cargador BASIC incluído al principio del mismo.
  
-   * Mediante el compilador cruzado, compilamos los ficheros .C y obtenemos un fichero binario de código máquina, normalmente con un cargador BASIC incluído al principio del mismo. +   * Cargamos ese código máquina en nuestro Spectrum o emulador con un simple ''LOAD ""'' y el programa se carga y ejecuta como cualquier otro juego comercial.
- +
-   * Cargamos ese código máquina en nuestro Spectrum o emulador con un simple LOAD "" y el programa se carga y ejecuta como cualquier otro juego comercial.+
 \\  \\ 
  
Línea 137: Línea 133:
  Finalmente, la última opción: nos hemos decidido y queremos escribir programas directamente en el lenguaje que comprende la máquina, ya que queremos controlar todo lo que realiza el microprocesador.  Finalmente, la última opción: nos hemos decidido y queremos escribir programas directamente en el lenguaje que comprende la máquina, ya que queremos controlar todo lo que realiza el microprocesador.
  
- Con la opción que hemos elegido, escribiremos el código del programa íntegramente en **lenguaje ensamblador** (//assembler language// en inglés, o ASM para abreviar). Como veremos, el lenguaje ensamblador no es un lenguaje de alto nivel como BASIC o C, con instrucciones comprensibles por los humanos ("PRINT""FOR", etc) sino que utiliza instrucciones de bajo nivel más cercanas a las acciones individuales capaz de realizar el procesador ("LD A, 10""DJNZ address""XOR C", etc).+ Con la opción que hemos elegido, escribiremos el código del programa íntegramente en **lenguaje ensamblador** (//assembler language// en inglés, o ASM para abreviar). Como veremos, el lenguaje ensamblador no es un lenguaje de alto nivel como BASIC o C, con instrucciones comprensibles por los humanos (''PRINT''''FOR'', etc) sino que utiliza instrucciones de bajo nivel más cercanas a las acciones individuales capaz de realizar el procesador (''LD A, 10''''DJNZ bucle''''XOR C'', etc.).
  
  Con BASIC compilado y con C, es el compilador quien transforma cada comando en múltiples instrucciones en código máquina. En el lenguaje ensamblador, la "compilación" (conocida como proceso de ensamblado) del programa en código máquina es una mera traducción ya que cada instrucción en ensamblador se traduce en una instrucción en código máquina.  Con BASIC compilado y con C, es el compilador quien transforma cada comando en múltiples instrucciones en código máquina. En el lenguaje ensamblador, la "compilación" (conocida como proceso de ensamblado) del programa en código máquina es una mera traducción ya que cada instrucción en ensamblador se traduce en una instrucción en código máquina.
Línea 144: Línea 140:
  
 \\  \\ 
-   * Programamos nuestro juego en lenguaje ensamblador escribiendo el programa en un editor de textos estándar de nuestra plataforma de desarrollo.+   * Programamos nuestro juego en lenguaje ensamblador escribiendo el programa en un editor de textos estándar de nuestra plataforma de desarrollo. Escribiremos por tanto el código de nuestro programa como uno o varios ficheros ''.ASM''.
  
-   Grabamos el código de nuestro programa como uno o varios ficheros .ASM.+   Mediante el ensamblador cruzado, ensamblamos los ficheros ''.ASM'' y obtenemos un fichero binario de código máquina, normalmente con un cargador BASIC incluído al principio del mismo.
  
-   * Mediante el ensamblador cruzado, ensamblamos los ficheros .ASM y obtenemos un fichero binario de código máquina, normalmente con un cargador BASIC incluído al principio del mismo. +   * Cargamos ese código máquina en nuestro Spectrum o emulador con un simple ''LOAD ""'' y el programa se carga y ejecuta como cualquier otro juego comercial.
- +
-   * Cargamos ese código máquina en nuestro Spectrum o emulador con un simple LOAD "" y el programa se carga y ejecuta como cualquier otro juego comercial.+
 \\  \\ 
  
Línea 157: Línea 151:
  En ensamblador no tenemos funciones de alto nivel que realicen determinadas tareas por nosotros: no existe PRINT para imprimir cosas por pantalla, si queremos imprimir texto tenemos que imprimir una a una las letras, calculando posiciones, píxeles, colores, y escribiendo en la videomemoria nosotros mismos. Podemos apoyarnos en una serie de rutinas que hay en la ROM del Spectrum (que son las que utiliza BASIC), pero en general, para la mayoría de las tareas, lo tendremos que hacer todo manualmente.  En ensamblador no tenemos funciones de alto nivel que realicen determinadas tareas por nosotros: no existe PRINT para imprimir cosas por pantalla, si queremos imprimir texto tenemos que imprimir una a una las letras, calculando posiciones, píxeles, colores, y escribiendo en la videomemoria nosotros mismos. Podemos apoyarnos en una serie de rutinas que hay en la ROM del Spectrum (que son las que utiliza BASIC), pero en general, para la mayoría de las tareas, lo tendremos que hacer todo manualmente.
  
- Un ejemplo muy sencillo: en BASIC podemos multiplicar 2 números de forma muy simple con el operador "*". En ensamblador, no existe un comando para multiplicar 2 números. No existe dicho comando porque el micro Z80 tiene definida la operación de suma (ADD) y la de resta (SUB), por ejemplo, pero no tiene ninguna instrucción para multiplicar o dividir. Y si queremos multiplicar 2 números, tendremos que hacer una rutina en ensamblador que lo haga (por ejemplo, realizando la multiplicación en base a múltiples sumas) y llamarla cada vez que necesitemos realizar una multiplicación.+ Un ejemplo muy sencillo: en BASIC podemos multiplicar 2 números de forma muy simple con el operador ''*''. En ensamblador, no existe un comando para multiplicar 2 números. No existe dicho comando porque el micro Z80 tiene definida la operación de suma (''ADD'') y la de resta (''SUB''), por ejemplo, pero no tiene ninguna instrucción para multiplicar o dividir. Y si queremos multiplicar 2 números, tendremos que hacer una rutina en ensamblador que lo haga (por ejemplo, realizando la multiplicación en base a múltiples sumas) y llamarla cada vez que necesitemos realizar una multiplicación.
  
 <code z80> <code z80>
 ; Rutina de multiplicación en lenguaje ensamblador: ; Rutina de multiplicación en lenguaje ensamblador:
 ; ;
-MULTIPLICA: Multiplica DE*BC +Mult_HL_DE: Multiplica DE*BC 
-      Entrada:        DE: Multiplicando, +; Entrada:   DE: Multiplicando, 
-                      BC: Multiplicador +           BC: Multiplicador 
-      Salida:         HL: Resultado.+; Salida:    HL: Resultado. 
 +; Modifica:  AF, BC  
 + 
 +Mult_HL_DE: 
 +    ld hl, 0                  ; HL = 0
  
-MULTIPLICA+multhlde_loop
-        LD HL0            ; HL = 0 +    add hlde                ; Sumamos HL = HL + DE 
-MULTI01: +    dec bc 
-        ADD HL, DE          ; Sumamos HL = HL + DE +    ld ab 
-        DEC BC +    or c 
-        LD AB +    jr nzmulthlde_loop      ; Lo repetimos BC veces 
-        OR C +    ret                       ; Volver de la rutina
-        JR NZMULTI01      ; Lo repetimos BC veces +
-        RET                 ; Volver de la rutina+
 </code> </code>
  
Línea 248: Línea 244:
 Por ejemplo, (por citar sólo dos de ellos) tanto **FUSE -Free UNIX Spectrum Emulator-** (en Linux, Windows y Mac), como **ZX Spin** (en Windows) tienen integrado un **debugger** o **depurador** que nos permitirá ejecutar nuestros programas paso a paso. Por ejemplo, (por citar sólo dos de ellos) tanto **FUSE -Free UNIX Spectrum Emulator-** (en Linux, Windows y Mac), como **ZX Spin** (en Windows) tienen integrado un **debugger** o **depurador** que nos permitirá ejecutar nuestros programas paso a paso.
  
-Un debugger es una herramienta que nos permite ver el contenido de los registros del Z80, la posición del "puntero de ejecución" (PC), qué hay en la memoria, y ejecutar instrucciones una a una, paso a paso, y ver qué resultado y cambios producen. El debugger de ZX Spin, accesible en "//Tools > Debugger//" tiene el siguiente aspecto:+Un debugger es una herramienta que nos permite ver el contenido de los registros del Z80, la posición del "puntero de ejecución" (''PC'', de //Program Counter// o //Contador de Programa//), qué hay en la memoria, y ejecutar instrucciones una a una, paso a paso, y ver qué resultado y cambios producen. El debugger de ZX Spin, accesible en "//Tools > Debugger//" tiene el siguiente aspecto:
  
 \\  \\ 
Línea 281: Línea 277:
 ZX Spin tiene incluso un ensamblador integrado que nos permitirá ensamblar programas y ponerlos en memoria directamente desde el emulador, o una opción para cargar bloques de datos binarios desde fichero o guardar porciones de la memoria a fichero, funcionando además bajo Wine en sistemas Linux. ZX Spin tiene incluso un ensamblador integrado que nos permitirá ensamblar programas y ponerlos en memoria directamente desde el emulador, o una opción para cargar bloques de datos binarios desde fichero o guardar porciones de la memoria a fichero, funcionando además bajo Wine en sistemas Linux.
  
-"**Debuggers**" y "**Memory Browsers**" son herramientas valiosísimas para desarrollar, por lo que recomendamos descargar uno para nuestro Sistema Operativo que tenga al menos esas 2 opciones, y avanzar en el curso haciendo uso de ellas y aprendiendo a manejarlas, ya que es una pequeñísima inversión de tiempo que rentabilizaremos rápidamente.+"**Debuggers**" y "**Memory Browsers**" son herramientas valiosísimas para desarrollar, por lo que recomendamos descargar uno para nuestro Sistema Operativo que tenga al menos esas 2 opciones, y avanzar en el curso haciendo uso de ellas y aprendiendo a manejarlas, ya que es una pequeñísima inversión de tiempo que rentabilizaremos rápidamente (en el Anexo 1 de este curso veremos cómo utilizar el depurador/debugger de Fuse).
  
 FUSE y ZX Spin no son los únicos emuladores que contienen este tipo de herramientas, hemos citado estos porque son "clásicos" (de hecho, varios emuladores nuevos han surgido después de ellos que incorporan muchas más opciones, como **ZEsarUX** o **Spectaculator**), pero podemos elegir aquel que mejor conozcamos o que tenga un interfaz más amigable para nosotros. FUSE y ZX Spin no son los únicos emuladores que contienen este tipo de herramientas, hemos citado estos porque son "clásicos" (de hecho, varios emuladores nuevos han surgido después de ellos que incorporan muchas más opciones, como **ZEsarUX** o **Spectaculator**), pero podemos elegir aquel que mejor conozcamos o que tenga un interfaz más amigable para nosotros.
  • cursos/ensamblador/introduccion.1704552838.txt.gz
  • Última modificación: 06-01-2024 14:53
  • por sromero