Revistas en papel
 Commodore Amiga World Nº0 - 1989
Anterior
MenĂº
Logotipo

El Amiga Me Encanta ha conseguido el permiso por escrito de IDG Comunications España
para ofrecer los artículos de la revista Amiga World España.

LIBRERÍAS EN EL AMIGA Amiga World

Por Fernando Marcos

A unos y a otros va dirigido este artículo. A los primeros para que vean que no es una pérdida de tiempo trabajar con estas ayudas, y para los segundos para demostrar que no es tan fiero el león como lo pintan.

Poca gente sabe lo
que realmente son las
librerías. Para muchos,
son una forma de
complicarse la vida
que tienen los
programadores
profesionales. Para
otros, es sencillamente
algo que no entienden
y que prefieren no
entender.

Pero en primer lugar, la teoría...


Rutinas externas

Siempre, cuando se está diseñando una aplicación seria, surge la pega de que se necesita escribir algo complicado, que podríamos evitar porque ya lo lleva incorporado el sistema operativo, pero que no podemos porque nuestro lenguaje de programación no lo lleva incorporado en su juego de instrucciones.

En previsión de esto, los creadores del Amiga prepararon una serie de ficheros que contienen las descripciones de todas las rutinas incluidas en la ROM para que el virtual programador pueda llamarlas desde su programa con facilidad. Estos ficheros son las librerías. Que no deberían llamarse así, "librerías", sino "bibliotecas", que es la traducción correcta del inglés "library".

Y dado que la mayoría de los que lean esto son programadores habituales de AmigaBasic, en este entorno serán descritas todas las rutinas de ejemplo. Una vez conocidos los fundamentos, el aplicarlos a otro tipo de lenguajes es sumamente sencillo.


Qué se necesita y dónde se consigue

Para seguir este artículo se necesitan una serie de programas y ficheros a los que haré constante referencia, y que son:

     GRAPHICS.BMPA, DOS.BMAP,
     EXEC.BMAP y AMIGABASIC 

Los tres primeros se pueden encontrar en el disco Extras que viene con el Amiga, dentro del directorio BasicDemos. El AmigaBasic está en el directorio principal de este mismo disco. Para poder trabajar con ellos, formatea un disco y copia allí estos ficheros moviendo los iconos de un disco a otro: abre los iconos de los dos discos, cuando salgan selecciona el que quieras copiar con el botón izquierdo y, sin soltarlo, llévalo a la ventana de destino.

Una vez hecho este disco de trabajo, colócalo en la unidad y abre el AmigaBasic. Una vez cargado, podrás empezar a trabajar con librerías.

Como ejemplo, teclea el listado número uno. En él se hace una llamada a una de las rutinas gráficas del sistema, la encargada de trazar líneas en pantalla. Admito que esto ya lo hace el comando LINE, pero de esta forma podrás ver cómo funcionan haciendo algo que ya sabes cómo se hace.

Las líneas clave que explican el funcionamiento del programa son:

     LIBRARY "GRAPHICS.LIBRARY"
     y
     CALL MOVE&(WINDOW(8),50,50)
     CALL DRAW&(WINDOW(8),450,170)

La primera de ellas abre una librería llamada GRAPHICS.LIBRARY. En realidad, lo que se abre es el fichero GHAPHICS.BMAP que antes copiaste al disco de trabajo. Luego veremos en profundidad su formato.

Al abrirlo, se crean variables con el mismo nombre que las rutinas que contiene esa librería. Por ejemplo, al hacer el CALL MOVE& es como si hicieses una llamada a una dirección de memoria contenida en la variable MOVE&. Lo que va entre paréntesis son los parámetros que necesita la rutina para funcionar, y que se colocarán en los registros del microprocesador adecuados. Todo esto lo hace automáticamente el AmigaBasic.

Lo que hacen esas dos líneas es sencillo: mueve el cursor gráfico a la posición (50,50) y luego traza desde allí una línea a la posición (450,170). Esto equivale a la instrucción Basic:

     LINE (50,50)-(450-170)

El parámetro WINDOW(8) es algo muy común en las rutinas gráficas, y prácticamente todas lo llevan. Técnicamente se llama Rastport. Este es el apuntador a la cabecera de la ventana que está activada en ese momento. En este caso, devolverá el Rastport de la ventana del Basic, que es la dirección de memoria donde se almacena su formato, colocación, tipo, etc. Las rutinas gráficas lo necesitan para saber dónde realizar su función. Si no se pone, o se usa una variable inicializada con su valor (xx=rastport), lo más probable es que el ordenador se cuelgue, ya que pueden llegar valores corrompidos (o peor aún, que no lleguen...).

Así que procura recordar esto: el Amiga es un ordenador con una arquitectura tremendamente frágil, por lo que un fallo en el manejo de una librería, un parámetro fuera de rango, un valor que se te olvida colocar, y es casi seguro que tendrás que volver a empezar el programa: el Amiga no perdona. El manejo de las librerías es sencillo pero delicado. Así que aquí no vale escribir "a pelo" y se requiere un mínimo de planificación para poder programar con seguridad.

Las librerías permiten hacer cosas
normalmente "imposibles" a los
programadores en AmigaBasic.

Son terriblemente potentes, pero
también sumamente delicadas, por lo
que un uso inadecuado puede destruir
todo el trabajo.

El empleo de las funciones permite,
además, intercambiar información
con el sistema operativo.


Llamando y escuchando

Voy a comentar otro tipo de llamadas al sistema que aumentan aún más la potencia de este sistema de programación. Hasta el momento, lo único que se podía hacer era mandarle datos al sistema operativo. Ahora explicaré cómo recibir datos útiles de las rutinas que llamemos para poder aprovecharlos en nuestros programas.

Un caso típico es que se necesite memoria para almacenar información. Lo normal es emplear variables, pero es engorroso si, por ejemplo, se quiere guardar y manipular una pantalla o un fichero largo, o cargar sonidos digitalizados (si te interesa esto último tienes un artículo en el número 50 de Commodore World).

El listado número dos es un ejemplo de un programa que reserva memoria para uso posterior. En la variable TAM guardamos la cantidad de memoria que deseamos en bytes. El valor de la variable CUSTOM es un valor definido que indica que la memoria la puede reservar como mejor le venga, en cuanto a colocación dentro de todo el mapa. Con otros valores puedes hacer que reserve toda la memoria disponible o que la reserve en la zona alta, etc.

Es obvioque no se le puede indicar a la rutina dónde quieres que esté la memoria, ya que esa zona puede estar ya ocupada (debido a la gran complejidad de su distribución), por lo que deberá ser el propio ordenador el que seleccione su ubicación y nuestro programa el que se adapte a esa contingencia. Por tanto, al llamar a la rutina, hay que esperar un valor de retorno. Por mi, muy bien, pero al Basic, ¿quién le dice que le van a contestar? ¿Próximo capítulo? ¡No! ¡Ahora mismo!


Funciones

Para eso están las funciones. Son llamadas al sistema operativo con la característica de que devuelven un valor que debe ser leído. Para decirle al AmigaBasic que una determinada rutina debe ser empleada como función se utiliza el comando DECLARE FUNCTION con el formato:

     DECLARE FUNCTION función&LIBRARY

Con esta instrucción se prepara al intérprete para que asigne un espacio al resultado de la rutina. Para recibir el valor sólo tienes que igualar una variable larga entera (del tipo "&") a la función, de esta forma:

     resultado&=RUTINA&(.....

En este caso, la variable resultado& contiene la dirección de memoria donde se ha reservado el bloque. Si por alguna razón esta reserva no ha sido posible (no había memoria suficiente, errores, etc.) la variable devuelve un valor cero.

En otros casos, el contenido de esta variable varía. Para saber qué valores devuelve cada variable, te recomiendo que busques en algún libro especializado los valores que devuelve cada una. Aquí sólo comentaré las más comunes.


Ficheros BMAP

Aquí está la clave de todo el asunto. Dentro de estos ficheros se encuentra toda la información que necesita el programa para saber qué rutinas tiene disponibles y qué parámetros necesita. Se podría pensar que esto es una pérdida de tiempo inútil, ya que podríamos tener documentación de todas ellas y llamarlas directamente (estilo C64). La ventaja de emplear estos "inútiles" ficheros es que si algún día alguien cambia la ROM del Amiga, no será preciso reescribir los programas: bastará con cambiar los ficheros BMAP.

Su formato es muy sencillo. Es así:

     Nombre de la rutina 1.
     Byte cero.
     Incremento a la tabla de saltos en 16 bit.
     n bytes indicando registros empleados.
     Byte cero.
     Nombre de la rutina 2.
     ...

El nombre de la rutina es el nombre que se emplea para llamar a esta rutina (ej: MOVE, DRAW, ALLOC-MEM, etc). El byte cero marca el fin del nombre.

El incremento es la cantidad que hay que sumar a la posición inicial de la ROM para saber dónde es´ta la rutina real. Por ejemplo, si la ROM empieza en la posición $F0000, y el incremento es de $213F, la rutina será llamada a la posición $F213F (en hexadecimal).

Los n bytes que indican los registros son números consecutivos, con un cero al final, que indican en qué registros van los parámetros y en qué orden hay que dárselos. El microprocesador MC68000 que lleva el Amiga tiene 15 registros de 32 bits que se nombran:

     - Registro de datos.
     D0 a D7:
     - Registros de direcciones.
     A0 a A6:
     - Apuntador de pila.
     A7:

El registro A7 no se emplea por ser el apuntador de pila del sistema, y por lo delicado de su uso. Cada uno de los registros restantes tiene un número:

     1: Registro D0
     2: Registro D1
     3: Registro D2
     4: Registro D3
     5: Registro D4
     6: Registro D5
     7: Registro D6
     8: Registro D7
     9: Registro A0
    10: Registro A1
    11: Registro A2
    12: Registro A3
    13: Registro A4
    14 y 15: Registros no accesibles. Uso interno.

De todas formas, todo esto lo ilustra mejor un ejemplo. Supongamos que existe una rutina en la ROM llamada "LINE" que traza una línea entre dos puntos, definidos por (D0,D1) y (D2,D3). También necesita el Rastport, que se pasará en el registro A3. La rutina comienza en la posición $5632 a partir del comienzo de la ROM. El fichero que describiría esta rutina (por ejemplo "RUTINAS.BMAP") sería:

     - Nombre de la rutina.
     "L", "I", "N", "E"
     - Fin de nombre de la rutina.
     CHR$(0)
     - Posición de inicio
     CHR$($56), CHR$($32)
     - Rastport.
     CHR$(12)
     - Registros D1 y D2.
     CHR$(1), CHR$(2).
     - Registros D3 y D4.
     CHR$(3), CHR$(4).
     - Fin de registros.
     CHR$(0).

Si hubiese más rutinas en ese fichero BMAP vendrían a continuación del cero de fin de descripción de rutina (no del cero de fin de nombre). Pero para poder ver esto mucho mejor teclea el listado tres: es un pequeño utilitario llamado BMAP.DUMP que se encarga de tomar un fichero BMAP e imprimir todos sus contenidos, bien por pantalla, bien por impresora. Es de gran utilidad tener un mapa de los registros de cada rutina, porque muchas veces no te acuerdas, por ejemplo, de que la rutina DRAW lleva tres parámetros, etc. De todas formas, aun viendo este volcado, no es posible adivinar qué debe ir en cada registro, por lo que seguirás necesitando un manual del sistema operativo que te explique las necesidades de cada rutina. Te recomiendo el ROM Kernel Reference Manual, que es el original editado por Commodore por ser el que describe con más profundidad todos los recovecos de esta increíble máquina. Para conseguirlo tendrás que buscar un poco, pero mientras podrás seguir leyendo estos estupendos artículos (ejem!!)...

Programa library1.bas
'Llamada a GRAPHICS.LIBRARY.               .83
'(C)f.Marcos 1988                          .119
'(C)Commodore World 1988.                  .813
LIBRARY "graphics.library"                 .332
CALL move&(WINDOW(8),50,50)                .975
CALL draw&(WINDOW(8),450,170)              .871
LIBRARY CLOSE                              .234
               
Numero de lineas: 7
LISTADO 1
Programa: alloc.bas
'Demo de reserva de memoria.                           .839
'Necesita EXEC.BMAP                                    .595
DECLARE FUNCTION AllocMem& LIBRARY                     . 53
'       FreeMem& no devuelve valores.                  .700
LIBRARY "exec.library"                                 .156
PUBLIC&=65537&       'Puede reservar la memoria        .269
'donde quiera en memoria.                              .675
TAM&=    3000&       'Numero de bytes                  .715
'a reservar.                                           .641
BUF& = AllocMem&(TAM&,PUBLIC&)  'Reserva.              .726
IF BUF&=0 THEN       'Mp se ha podido reservar...      .397
PRINT "No puedo reservar memoria!"                     .405
GOTO NoAlloc                                           .311
END IF                                                 .654
PRINT TAM&"bytes reservados en"BUF&                    .391
PRINT "Pulse una tecla para liberar memoria."          .744
WHILE INKEY$="":WEND                                   .865
CALL FreeMem&(BUF&,TAM&)  'Orden de liberar memoria.   .703
NoAlloc:                                               .114
LIBRARY CLOSE                                          .234
PRINT "Programa terminado."                            .821
               
Numero de lineas: 21
LISTADO 2
Programa: Bmap.Dump
'Library Parameters Displayer.                                      . 51
'Ver 2.04 6-12-87 F.Marcos                                          .201
'Hi! guys!!!                                                        .731
'                                                                   .273
CLS:INPUT "BMAP file";bmap$                                         .921
INPUT "(P)antalla o (I)mpresora: ",fi$                              .447
fi$=UCASE$(fi$)                                                     .478
IF fi$="P" THEN sal$="SCRN:"                                        .695
IF fi$="I" THEN sal$="PAR:"                                         .731
IF sal$="" THEN sal$="SCRN:":PRINT "Periferico asumido: pantalla"   .319
OPEN bmap$ FOR INPUT AS 1                                           .309
OPEN sal$ FOR OUTPUT AS 2                                           .158
WHILE NOT EOF(1)                                                    .271
char$=CHR$(32)                                                      .386
WHILE char$<>CHR$(0)                                                .599
PRINT#2,char$;:char$=INPUT$(1,1)                                    .658
WEND:PRINT#2,TAB(25)                                                .952
a$=INPUT$(2,1)                                                      .551
reg=1                                                               .359
WHILE req<>0                                                        .330
reg=ASC(INPUT$(1,1)+CHR$(0))                                        .167
IF reg<>0 THEN GOSUB Conv                                           .727
WEND                                                                . 89
PRINT#2," "                                                         .272
WEND                                                                . 89
CLOSE:END                                                           .404
Conv: IF reg<=8 THEN PRINT#2,"D"MID$(STR$(reg-1),2)", ";:RETURN     .291
PRINT#2,"A"MID$(STR$(reg-9),2)", ";:RETURN                          .200
Numero de lineas: 28
LISTADO 3

Envía esta página web a un amigo:
Esta opción está desactivada temporalmente, rogamos disculpen las molestias

Volver a la página anterior

Al menú principal