Diferencias
Muestra las diferencias entre dos versiones de la página.
Ambos lados, revisión anterior Revisión previa Próxima revisión | Revisión previa | ||
cursos:ensamblador:asmz88dk [10-01-2024 09:47] – [Ejemplos varios] sromero | cursos:ensamblador:asmz88dk [21-01-2024 16:52] (actual) – [Enlaces] sromero | ||
---|---|---|---|
Línea 1: | Línea 1: | ||
====== Integración de ASM en Z88DK ====== | ====== Integración de ASM en Z88DK ====== | ||
- | En este capítulo vamos a ver cómo podemos usar ASM dentro del compilador de C más utilizado en Spectrum: el Z88DK. | + | En este capítulo vamos a ver cómo podemos usar ASM dentro del compilador de C más utilizado en Spectrum: el **Z88DK** (//Z88 Development Kit//). |
La idea de hacer programas mixtos en C con pequeñas partes en ASM es la de escribir en ensamblador las partes más críticas o importantes del mismo para acelerar su ejecución. | La idea de hacer programas mixtos en C con pequeñas partes en ASM es la de escribir en ensamblador las partes más críticas o importantes del mismo para acelerar su ejecución. | ||
Línea 15: | Línea 15: | ||
===== Embeber ASM dentro de código C ===== | ===== Embeber ASM dentro de código C ===== | ||
- | Z88DK permite utilizar ASM de diferentes formas. En nuestro caso vamos a ver cómo se "embebe" | + | Z88DK permite utilizar ASM de diferentes formas. En nuestro caso vamos a ver cómo se embebe C en ASM con las directivas |
<code c> | <code c> | ||
Línea 39: | Línea 39: | ||
{ | { | ||
#asm | #asm | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
#endasm | #endasm | ||
} | } | ||
</ | </ | ||
- | No es necesario hacer PUSH y POP de los registros para preservar sus valores porque Z88DK lo hace automáticamente por nosotros. | + | No es necesario hacer '' |
| | ||
Línea 66: | Línea 66: | ||
| | ||
- | < | + | < |
// | // | ||
// Sea parte de nuestro programa en C: | // Sea parte de nuestro programa en C: | ||
Línea 83: | Línea 83: | ||
#asm | #asm | ||
- | | + | |
- | | + | |
; en la pila por el compilador (valor de Y) | ; en la pila por el compilador (valor de Y) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
;;; (ahora hacemos lo que queramos en asm) | ;;; (ahora hacemos lo que queramos en asm) | ||
Línea 103: | Línea 103: | ||
</ | </ | ||
- | Como hemos comentado en un apartado anterior, no tenemos que preocuparnos por hacer PUSH y POP de los registros para preservar su valor dado que Z88DK lo hace automáticamente antes y después de cada #asm y #endasm. | + | Como hemos comentado en un apartado anterior, no tenemos que preocuparnos por hacer '' |
- | El problema es que conforme crece el número de parámetros apilados, es posible que tengamos que hacer malabarismos para almacenarlos, | + | El problema es que conforme crece el número de parámetros apilados, es posible que tengamos que hacer malabarismos para almacenarlos, |
- | < | + | < |
// | // | ||
int Funcion(int x, int y, int z) | int Funcion(int x, int y, int z) | ||
Línea 113: | Línea 113: | ||
#asm | #asm | ||
- | | + | |
- | | + | |
; en la pila por el compilador (z) | ; en la pila por el compilador (z) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
;;; (ahora hacemos lo que queramos en asm) | ;;; (ahora hacemos lo que queramos en asm) | ||
Línea 144: | Línea 144: | ||
La manera de leer bytes (variables de tipo char) pulsados en C es de la misma forma que leemos una palabra de 16 bits, pero ignorando la parte alta. En realidad, como la pila es de 16 bits, el compilador convierte el dato de 8 bits en uno de 16 (rellenando con ceros) y mete en la pila este valor: | La manera de leer bytes (variables de tipo char) pulsados en C es de la misma forma que leemos una palabra de 16 bits, pero ignorando la parte alta. En realidad, como la pila es de 16 bits, el compilador convierte el dato de 8 bits en uno de 16 (rellenando con ceros) y mete en la pila este valor: | ||
- | < | + | < |
// | // | ||
int Funcion(char x, char y) | int Funcion(char x, char y) | ||
Línea 150: | Línea 150: | ||
#asm | #asm | ||
- | | + | |
- | | + | |
; en la pila por el compilador (y) | ; en la pila por el compilador (y) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
; Si hubiera más parámetros, | ; Si hubiera más parámetros, | ||
- | ; "INC HL" para acceder a ellos. Como es el último, no es necesario. | + | ; "inc hl" para acceder a ellos. Como es el último, no es necesario. |
| | ||
;;; (ahora hacemos lo que queramos en asm) | ;;; (ahora hacemos lo que queramos en asm) | ||
Línea 169: | Línea 169: | ||
</ | </ | ||
- | Por ejemplo, veamos nuestra rutina anterior de ClearScreen() permitiendo pasar un parámetro para indicar el carácter a utilizar para el rellenado de la pantalla: | + | Por ejemplo, veamos nuestra rutina anterior de '' |
<code c> | <code c> | ||
Línea 175: | Línea 175: | ||
{ | { | ||
#asm | #asm | ||
- | | + | |
- | | + | |
; en la pila por el compilador (value) | ; en la pila por el compilador (value) | ||
- | | + | |
| | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
#endasm | #endasm | ||
} | } | ||
Línea 191: | Línea 191: | ||
En ocasiones, es posible que incluso tengamos que utilizar variables auxiliares de memoria para guardar datos: | En ocasiones, es posible que incluso tengamos que utilizar variables auxiliares de memoria para guardar datos: | ||
- | < | + | < |
// | // | ||
int Funcion(int x, int y, char z) | int Funcion(int x, int y, char z) | ||
Línea 197: | Línea 197: | ||
#asm | #asm | ||
- | | + | |
- | | + | |
; en la pila por el compilador (z) | ; en la pila por el compilador (z) | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
;;; (ahora hacemos lo que queramos en asm) | ;;; (ahora hacemos lo que queramos en asm) | ||
- | | + | |
valor_x | valor_x | ||
Línea 234: | Línea 234: | ||
===== Devolver parámetros desde funciones escritas en ASM ===== | ===== Devolver parámetros desde funciones escritas en ASM ===== | ||
- | Por contra, para devolver valores no se utiliza la pila dado que no podemos tocarla, ya que el RET volvería | + | Por contra, para devolver valores no se utiliza la pila dado que no podemos tocarla, ya que el '' |
<code c> | <code c> | ||
Línea 249: | Línea 249: | ||
Para aprovechar esta introducción de "uso de ASM en Z88DK", | Para aprovechar esta introducción de "uso de ASM en Z88DK", | ||
- | Como ejemplo de función sin parámetros, | + | Como ejemplo de función sin parámetros, |
<code c> | <code c> | ||
Línea 262: | Línea 262: | ||
#asm | #asm | ||
- | | + | |
.fadescreen_loop1 | .fadescreen_loop1 | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
.fadescreen_loop2 | .fadescreen_loop2 | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
.fadescreen_ink_zero | .fadescreen_ink_zero | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
.fadescreen_paper_zero | .fadescreen_paper_zero | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
#endasm | #endasm | ||
Línea 317: | Línea 317: | ||
</ | </ | ||
- | Un detalle a tener en cuenta, para demostrar esas pequeñas diferencias entre **z80asm** y **pasmo**, es que z80asm utiliza el nmemónico | + | Un detalle a tener en cuenta, para demostrar esas pequeñas diferencias entre **z80asm** y **pasmo**, es que z80asm utiliza el nmemónico |
\\ | \\ | ||
Línea 325: | Línea 325: | ||
En la anterior captura podéis ver el aspecto de uno de los pasos del fundido. | En la anterior captura podéis ver el aspecto de uno de los pasos del fundido. | ||
- | A continuación vamos a ver una rutina que calcula la dirección de un atributo de pantalla dadas las coordenadas X,Y en baja resolución (0-31, 0-23) de un " | + | A continuación vamos a ver una rutina que calcula la dirección de un atributo de pantalla dadas las coordenadas X,Y en baja resolución (0-31, 0-23) de un " |
El cálculo resultante se almacena en HL para que este valor sea devuelto a C, de forma que se asigne como resultado de la llamada. | El cálculo resultante se almacena en HL para que este valor sea devuelto a C, de forma que se asigne como resultado de la llamada. | ||
Línea 342: | Línea 342: | ||
#asm | #asm | ||
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
- | | + | |
#endasm | #endasm | ||
} | } | ||
Línea 366: | Línea 366: | ||
El siguiente ejemplo muestra cómo acceder a variables globales del programa en C desde nuestro código en ASM, utilizando un " | El siguiente ejemplo muestra cómo acceder a variables globales del programa en C desde nuestro código en ASM, utilizando un " | ||
- | < | + | < |
// | // | ||
// Set Border | // Set Border | ||
Línea 377: | Línea 377: | ||
{ | { | ||
#asm | #asm | ||
- | | + | |
- | | + | |
- | | + | |
| | ||
- | | + | |
- | | + | |
- | | + | |
#endasm | #endasm | ||
} | } | ||
Línea 457: | Línea 457: | ||
inc hl | inc hl | ||
pop bc // recuperamos BC | pop bc // recuperamos BC | ||
- | dec bc // Este DEC BC puede hacer BC=0 si los datos | + | dec bc // Este dec bc puede hacer BC=0 si los datos |
// RLE no correctos. Cuidado (mem-smashing). | // RLE no correctos. Cuidado (mem-smashing). | ||
dec bc | dec bc | ||
Línea 474: | Línea 474: | ||
//--- SetRAMBank ------------------------------------------------------ | //--- SetRAMBank ------------------------------------------------------ | ||
// | // | ||
- | // Se mapea el banco (0-7) indicado sobre $C000. | + | // Se mapea el banco (0-7) indicado sobre $c000. |
// | // | ||
// Ojo: en esta función no se deshabilitan las interrupciones y además, | // Ojo: en esta función no se deshabilitan las interrupciones y además, | ||
Línea 488: | Línea 488: | ||
ld b, a | ld b, a | ||
- | ld a, ($5B5C) | + | ld a, ($5b5c) |
and f8h | and f8h | ||
or b | or b | ||
- | ld bc, $7FFD | + | ld bc, $7ffd |
- | ld ($5B5C), a | + | ld ($5b5c), a |
out (c), a ; Realizamos cambio de banco | out (c), a ; Realizamos cambio de banco | ||
# | # | ||
Línea 498: | Línea 498: | ||
</ | </ | ||
- | Con el anterior código podemos mapear uno de los bancos de memoria de 16KB sobre la página que va desde $C000 a $FFFF, pero debido al uso de memoria, variables y estructuras internas que hace Z88DK, debemos seguir una serie de consideraciones. | + | Con el anterior código podemos mapear uno de los bancos de memoria de 16KB sobre la página que va desde $c000 a $ffff, pero debido al uso de memoria, variables y estructuras internas que hace Z88DK, debemos seguir una serie de consideraciones. |
+ | |||
+ | * Todo el código en ejecución debe estar por debajo de $c000, para lo cual es recomendable definir los gráficos al final del " | ||
- | * Todo el código en ejecución debe estar por debajo de $C000, para lo cual es recomendable definir los gráficos al final del " | ||
* Es importantísimo colocar la pila en la memoria baja, mediante la siguiente instrucción (o similar, según la dirección en que queremos colocarla) al principio de nuestro programa: | * Es importantísimo colocar la pila en la memoria baja, mediante la siguiente instrucción (o similar, según la dirección en que queremos colocarla) al principio de nuestro programa: | ||
\\ | \\ | ||
- | < | + | < |
/* Allocate space for the stack */ | /* Allocate space for the stack */ | ||
#pragma output STACKPTR=24500 | #pragma output STACKPTR=24500 | ||
Línea 510: | Línea 511: | ||
\\ | \\ | ||
- | La regla general es asegurarse de que no haya nada importante (para la ejecución de nuestro programa) en el bloque $C000 a $FFFF cuando se haga el cambio: ni la pila, ni código al que debamos acceder. Tan sólo datos que puedan ser intercambiandos de un banco a otro sin riesgo para la ejecución del mismo (por ejemplo, los datos de un nivel de juego en el que ya no estamos). | + | La regla general es asegurarse de que no haya nada importante (para la ejecución de nuestro programa) en el bloque $c000 a $ffff cuando se haga el cambio: ni la pila, ni código al que debamos acceder. Tan sólo datos que puedan ser intercambiandos de un banco a otro sin riesgo para la ejecución del mismo (por ejemplo, los datos de un nivel de juego en el que ya no estamos). |
Línea 520: | Línea 521: | ||
\\ | \\ | ||
- | **[ [[.: | + | **[ [[.: |