Programación #8: Variables globales en RAM desde ROM generada con z88dk

Estos conocimientos los adquirí gracias al amigo Utopian, que lo resolvió para poder currarse ROMs de MSX desde z88dk, así que ya tenía el trabajo hecho🙂. Por tanto podéis agradecérselo a él, y esos altares que empezábais a construirme como Dios Supremo de las ROMs con z88dk me parece que se los merecerá él más que yo (encima, el target que él se ha currao para MSX es 200 veces más complejo y petón que el mío para Speccy). Lo que se explica aquí es realmente útil.

Básicamente vamos a explicar cómo instruir a z88dk (en concreto, al ensamblador que tiene por debajo) para que coloque las variables globales en RAM aunque compile todo el código en ROM. Para que os hagáis una idea, nada se crea realmente en el binario generado, símplemente se colocan los punteros a las variables en direcciones de RAM en lugar de reservar espacio en él.

Para ello, lo primero que hacemos es declarar las variables globales (esas que declarábamos fuera de las funciones) como externas (extern). Por ejemplo, para probar, crearemos una variable de char sin signo, otra de entero sin signo, y un array de diez chars. Vamos, esto:

extern unsigned char var1;
extern unsigned int var2;
extern char array [10];

Esto es necesario para que el compilador de C importe los símbolos asociados con las variables, ya que las definiremos en un bloque en lenguaje de ensamblador que esté en un archivo aparte de nuestro código, que llamaremos por ejemplo asmvars.c. En este archivo, primero necesitamos un bloque DEFVARs que es una especie de macro del ensamblador que le dice cómo se llaman las variables y cuantos bytes o words ocupan. O sea, nos vamos al final del código, abrimos una zona #asm y escribimos la macro tal que así:

#asm
    DEFVARS $7000
    {
        _var1   ds.b 1      // var1 ocupa 1 byte
        _var2   ds.w 1      // var2 ocupa 1 word (2 bytes)
        _array  ds.b 10     // array ocupa 10 bytes
    }

Es sencillo: Antes que nada, indicamos que lo siguiente empezará a partir de la dirección $7000 (que cae en RAM). Luego definimos las variables:

  • Primero decimos que var1 ocupará un byte (ds.b 1), porque es un unsigned char.
  • Luego decimos que var2 ocupará un word (ds.w 1), porque es un unsigned int.
  • Luego decimos que array ocupará diez bytes (ds.b 10), porque es un array de 10 char.

Si necesitamos un puntero (por ejemplo un extern usigned char *puntero), tendremos que definirlo como ds.w 1, ya que los punteros son words.

Para terminar, tendremos que especificarle al ensamblador que los símbolos están definidos “fuera” (en realidad no están definidos por ningún defb ni defw ni nada) usando XDEF:

    XDEF _var1
    XDEF _var2
    XDEF _array
#endasm

Y listo. Pillando el mismo ejemplo que ayer le podemos dar valores a las variables en el main. Luego, mirando por ejemplo en Spectaculator usando el debugger (CTRL+ENTER) podemos comprobar que ha puesto los valores a partir de $7000:

main () {
    char i;
    todo_a_negro ();

    var1 = 85;
    var2 = 10000;

    for (i = 0; i < 10; i ++)
        array [i] = i;

    while (1) {
        #asm
            inc a
            out (254),a
        #endasm
    }
}

Recapitulando, ¿Qué nos queda al final?

  • Pues, por un lado, tendremos un archivo test2.c con el código del de ayer más los añadidos y las lineas extern. Estas lineas importan las variables que definiremos en el segundo archivo.
  • Por otro lado, en asmvars.c tenemos un bloque #asm donde definimos la ubicación en RAM de las variables definidas.

Todo esto se compilaría y convertiría a ROM, por tanto, con una linea de comando parecida a:

> zcc +none -vn test2.c asmvars.c -o test2.rom -lndos -zorg=0
> bloat test2.rom

Y con esto y un bizcocho, os dejo la descarga de los archivos y me despido hasta la nueva Bitácora. Mañana a lo mejor os pongo un juego o algo, que esto se está haciendo ya mu aburrío.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: