|
|||||
Por Fernando García Bienvenido al Lenguaje Ensamblador. Este es, sin duda, el lenguaje
Antes de comenzar conviene resaltar los pros y los contras de este lenguaje:
Pero ahora no te asustes, lo explicaré de otra manera. Si vas a realizar un programa compatible en otros ordenadores, en un espacio de tiempo no muy largo, los lenguajes más apropiados pueden ser el Basic, el C e incluso el Modula. Pero sin embargo, si preparas un programa a medida para un ordenador y dispones de tiempo de sobra, te recomiendo el ensamblador. ¿Por qué? Porque vas a tener la total seguridad de que tu programa, si lo has realizado correctamente, no pueda ir más rápido, que va a ocupar poca memoria y al mismo tiempo la probabilidad de que no se quede "colgado" va a ser altísima.
El ensamblador, dada su complejidad, se utiliza normalmente para realizar rutinas de manejo gráfico, es decir: CAD, Animación, Dibujo, etc., en las que la velocidad juega un papel importantísimo. Lo más normal es que el programa se realice en C y las rutinas más importantes se programen en ensamblador. El caso de los juegos es parecido, aunque con la popularidad del C y su relativa compatibilidad con otros ordenadores hace que el ensamblador quede en segundo término. Vuelvo a repetir que esto no hace al ensamblador un intocable, pues veremos que poco a poco iremos saltándonos estas barreras.
Su característica primordial es el manejo de etiquetas. No te puedes imaginar el trabajo que ahorra el poder "etiquetar", por decirlo de alguna forma, una subrutina o constante y acceder a ella haciendo referencia a su nombre. Si no hubiera etiquetas, los programadores se pasarían la mayoría del tiempo calculando posiciones de memoria en donde colocar las rutinas. Pero el ensamblador tiene más cualidades, que iré describiendo más tarde. El ensamblador consta de dos partes o programas: el Ensamblador y el Linker (también llamado "Linkador"). El ensamblador es el que traduce las instrucciones y directivas (una especie de comandos que facilitan las tareas) dadas por el programa fuente (tu programa) en instrucciones reconocibles por el 68000 (programa objeto). Pero ésto no basta, quedan nucos que atar, como las definiciones, referencias externas, ficheros "include", es decir, una serie de estas directivas que permiten acceder a otros programas fuente. Ahora es donde actúa el Linker. Une los programas ya ensamblados (normalmente no es necesario utilizar dos programas fuentes, pero en el resto de los capítulos lo haremos) y resuelve todas esas directivas a que hacíamos referencia. Otra de las características del Linker es la de transformar los ficheros objeto producidos por el ensamblador en ficheros ejecutables desde CLI o Workbench.
Vamos ahora con el material requerido para poder empezar. El primero y primordial es el ensamblador, de los que existen varios modelos. Si tienes problemas a la hora de conseguirlo, los hay también de dominio público, como el A68k. En cuanto a los comerciales están el Macro Assembler (el que actualmente utilizo), el Lattice C y el Aztec C, entre otros. Excepto el A68k, todos los comerciales ya llevan el Linker incluido.
Otros de los elementos importantes es el editor de textos, en el que has de escribir los programas fuente para más adelante ensamblarlos. Seguramente tendrás desde procesadores (Scribble!, Textcraft, WordPerfect...) hasta editores de texto propiamente dichos (Txed, Cygnus Edit, ED...). Te recomiendo utilizar el que menos ocupe y el más rápido de manejo al leer y salvar, cosa que harás muchas veces. Otra recomendación es la de meter el editor, ensamblador y linker en el disco RAM recuperable (si tienes Workbench 1.3). De esta forma si te quedas colgado podrás empezar de nuevo sin que tu unidad de discos sufra tanto y tengas que perder tiempo. Y por último, pasemos a la librería, es decir, información técnica. Recomiendo como indispensables los cuatro famosos libros técnicos de Amiga, disponibles en librerías técnicas:
Todos ellos contienen la manera de acceder a todas las funciones del sistema operativo: periféricos, coprocesadores, memoria...; en definitiva, todo. También incluyen explicaciones para los lenguajes ensamblador y C. Hay que decir que estos libros son prácticamente imprescindibles, y haremos referencia a ellos en casi todos los capítulos, de aquí en adelante. Estos cuatro libros están en inglés. Otro libro primordial es:
Es una recopilación de tres manuales antiguos en el que se incluyen explicaciones de los diversos comandos del CLI, así como las llamadas a las funciones del AmigaDOS, el sistema operativo del disco. También se explican el ensamblador, el Linker, las estructuras del disco y de los ficheros. Si no estás introducido en todo lo dicho este libro te ayudará enormemente. También está en inglés. Y por último si son pobres tus conocimientos sobre el 68000, sus características e instrucciones, recomiendo el libro:
A continuación explicaré cómo preparar un disco base de trabajo, que contendrá el editor de textos, el ensamblador y el linker. Asimismo, deberá contener una serie de librerías y ficheros "include" (más tarde los veremos) para que se pueda acceder a ellos fácilmente. Una vez formateado el disco y salvados los diversos elementos, se puede fabricar el fichero "Astartup". Este fichero es importantísimo, pues cuando el Linker lo una con nuestro fichero permitirá ejecutar el programa con total seguridad. Para fabricar éste fichero teclea en tu editor de textos el listado 1. (Si lo prefieres puedes teclear el cargador de DATAS del listado 2). Ten mucho cuidado al teclearlo pues tienes que tener en cuenta las mayúsculas y las minúsculas. Cuando lo tengas tecleado y grabado en disco, ejecuta esta línea desde CLI: assem Astartup -o Astartup.obj -i Esta línea ensambla el programa fuente anterior y da como resultado el programa objeto Astartup.obj. Las opciones -o y -i son propias de cada ensamblador. El ejemplo está preparado con el Macro Assembler, cuyo nombre es ASSEM. Si no quieres teclearte todo el listado (aunque sería bueno para ir practicando), puedes teclear directamente el generador de este fichero (listado 2). Tecléalo en AmigaBasic y ejecútalo. El fichero producido es el mismo que el producido por el ensamblador. Este programa permite al ordenador saber desde dónde se ha entrado, si desde el CLI o desde el Workbench. Asimismo sabe concretamente si has añadido algún parámetro (Ejemplo: en "asign c: ram:", c: y ram: son parámetros), su posición, longitud y cantidad. Una vez aclarado todo esto, el ordenador ejecuta el programa y vuelve al DOS (CLI o Workbench). Hay que resaltar las líneas XDEF y XREF. Estas son las llamadas directivas externas, a las que hice referencia en el apartado del ensamblador. Las aclaro a continuación, pues es fundamental su conocimiento:
En el caso del programa anterior, define unas constantes. Por ejemplo los parámetros (parament, paramlen, paramadd, etc.), para que tú accedas a ellos desde el programa principal. Hay más directivas, que en el capítulo siguiente explicaré más detalladamente. He aquí la explicación de cómo el Linker trabaja: junta el Astartup con nuestro programa resolviendo estas definiciones externas. En el primero que realicemos más adelante observarán cómo trabajan estas directivas. Para un completo conocimiento de todas ellas lee el capítulo sobre el Macro Assembler del libro The AmigaDOS Manual. Ahora escribe lo siguiente en el editor de textos y sálvalo en el disco base como "m": assem test -o TEST.obj -i sys:include alink Astartup.obj,TEST.obj to p Estas líneas son las que permiten ensamblar y Linkar nuestro programa fuente. Iré comando por comando:
Para la segunda línea:
Ahora nuestro disco base ya puede ensamblar y "linkar" los programas fuentes que se realicen. Expliquemos ahora cómo es un programa en ensamblador.
Cada línea se compone de cuatro parámetros o campos. Todos estos parámetros tienen que estar al menos separados por un espacio, si no, confundirías al ensamblador. Para ilustrarlo veamos una línea cualquiera: WINDOWS MOVE.L D0,$1000 pone D0 en posición $1000 De izquierda y derecha los parametros son: la etiqueta, la instrucción o mnemónico, los operandos y por último el comentario. En cuanto a la posición de estos parámetros la etiqueta tiene 16 espacios, es decir, dos veces el tabulador, el mnemónico son 8 espacios (1 tabulador), los operandos 16 espacios (2 tabuladores), y por último el comentario ocupa o puede ocupar el resto de la línea. Te recomiendo utilizar los tabuladores pues las veces que se han de pulsar las teclas del cursor son muy pocas. Hay que decir que la etiqueta y el comentario no es necesario que las lleven, sólo en lugares que se necesite. El que estén las líneas en mayúsculas o minúsculas no importa. Escríbelas como más te gusten, pero ten en cuenta que cuanto más claras y concisas, antes podrás corregir los fallos que cometas. El símbolo "*" y lo que haya a continuación serán ignorados por el ensamblador. Se utiliza para dividir visualmente el programa en varias subpartes y así encontrar las rutinas antes. En cuanto a las directivas, éstas pueden ocupar varios de los espacios que hemos comentado (para ello fíjate en las primeras y últimas líneas del Astartup). Para más información consulta el libro The AmigaDOS Manual en la sección del Macro Assembler.
Una vez visto todo acerca del lenguaje ensamblador, el principal material y varias características del ensamblador y del Linker, ya puedes comenzar a hacer pruebas. Ahora prueba a teclear el listado 3 en el editor. Sálvalo como "test" y escribe en CLI: execute m Una vez visto todo acerca del lenguaje ensamblador y del Linker. SI no ha ocurrido ningún error teclea desde el CLI: p Y verás imprimir la siguiente línea: "Esto es el mensaje" Antes de explicar este programa, que tal vez te parezca algo raro la primera vez, veamos algunas características primordiales del Amiga.
Como ya sabes, el Amiga es multitarea (multitasking), es decir, puede ejecutar varios programas o tasks (tareas) a la vez. Eso lleva a la conclusión de que un programa puede insertarse en cualquier parte de la memoria del ordenador (si hay suficiente memoria, por supuesto), y ejecutarlo sin ningún problema. Con esto quiero decir que nunca, nunca, utilices direcciones absolutas. No realices saltos o guardes datos en posiciones fijas. ¿Por qué? Porque cuando vuelvas a cargar el programa tus posiciones de memoria lo más probable será que hayan cambiado, y como estas posiciones son libres, cuando las quiera utilizar el ordenador para ejecutar otra tarea, las destruirá.
Ahora explicaré un tanto por encima cómo se accede a las funciones del Amiga. Habrás oído hablar de las famosas librerías, que como su propio nombre indica, son librerías. ¿De qué? Pues de funciones, que son las rutinas que tiene el sistema operativo y que mantienen vivo al ordenador. Para acceder a estas librerías, hay que abrirlas primero, y a continuación hacer un salto a la función que te interese. Antes de salir del programa has de cerrarla, pues de lo contrario se queda todo en el aire y la posibilidad de que aparezca un "guru" es altísima. Con esto quiero decir que todo lo que abras en el programa lo tienes que cerrar antes de terminar. El acceso a cada función viene definido por una serie de parámetros, por ejemplo la longitud de un nombre, un buffer o bloque de datos, que se inserta en los registros D0, D1, A0 y A1 antes de hacer la llamada a la función. En todos los libros técnicos explicados anteriormente se hace referencia a estos registros. En el programa anterior, la función WRITE sería en realidad así: Longitud de retorno = write (fichero, buffer, longitud)
D0 D1 D2 D3
Por lo tanto para llamar a esta función primero has de poner los parámetros "fichero", "buffer" y "longitud" en los registros que hay debajo de cada parámetro. El primero de ellos en realidad no es un parámetro, sino el resultado de esa función, es decir, si se ha realizado o no, o bien puede ser una posición de memoria, depende de cada función. Si la función se ha ejecutado correctamente, retomará la longitud actual del fichero y la insertará en el registro D0. Si por alguna razón no se ha podido llevar a cabo por algún error, colocará un 0 en el registro D0. En la mayoría de las funciones se devuelve un cero como error, excepto para algunas que devuelven -1. El formato correcto para éstas sería: Resultado = función (argumento)
Registro Registro
Para ver cómo funciona, observa atentamente el ejemplo anterior. Una vez insertados los parámetros en los registros correctos se apunta a la base de la librería que contiene la función y se hace un salto negativo, es decir, tantas posiciones hacia atrás como indica el salto. Si la base de la librería se encuentra en $10000 primero insertamos este lugar en el registro A6 y luego realizamos el salto JMP -$30(A6). Así que el salto exacto es $10000-$30 = $FFFD0. Y en ésta posición es donde hace el salto directo al sistema operativo. Te das cuenta, como he dicho antes, que nunca se hacen saltos a posiciones absolutas, siempre son relativas. Para que esto nunca ocurra el ensamblador utiliza las etiquetas, pues no tienen posiciones definidas. Librerías hay muchas, la tabla 1 muestra cómo varias de ellas se encuentran en ROM, es decir, dentro de tu ordenador. Las restantes están, pueden o deben estar en el disco Workbench, exactamente en el directorio LIBS.
El proceso completo para acceder a una función sería éste:
Por lo tanto las librerías tienen una tabla de saltos, esta tabla de valores se llama offsets (desplazamientos). En el caso del JMP -$30(A6) el offset es el 30. Los offsets de todas las librerías con todos sus registros se encuentran en el libro ROM Kernel Reference Manual Exec, Apéndice D1. Así, por ejemplo, si observar para la función Write (dos.lib.offsets) la línea completa es ésta: 12 0xffd0 -0x0030 Write(file,buffer,lenght) (d1,d2,d3) (He de decir que los offsets correspondientes a estas librerías no son correctos, y hay que añadir $1E bytes a cada función. En la primera función Open en realidad es 0x001E y no -0x0000 como pone). Volviendo a la función anterior la primera cifra es el offset en decimal, el segundo valor es el número en positivo del siguiente valor (el valor positivo de 0030 es ffd0). Por último viene la función con sus parámetros requeridos y los registros a los que corresponde. Si ya conoces la base de la librería, hacia atrás están los offsets de las funciones... ¿Qué es lo que hay de ahí en adelante? Pues las famosas estructuras, que más adelante se explicarán. La completa estructura de una librería (por ejemplo dos.library) es esta:
Ahora que ya conoces, un poco, cómo funciona el Amiga por dentro, explicaré cómo es el programa del listado 3. Primero hay unas serie de directivas como son la TTL (Título), XREF _DOSBase (base de la librería DOS), XREF(_sdin o salida de nuestros mensajes). Si miras atentamente el STARTUP (el programa realizador) en una de sus líneas hace un salto a la subrutina STARTUP (JSR START), si intentas buscarla no está. ¿Dónde está? Pues en nuestro pequeño programa anterior. En realidad ha hecho un puente entre el STARTUP y el nuestro haciendo referencia de el con las directivas XREF START y XDEF START respectivamente. Es el Linker el que se encarga de resolver estos puentes entre los varios programas ensamblados. Una vez vistas estas directivas viene nuestro programa principal que está etiquetado con START (no es casualidad, hicimos referencia a ella anteriormente). Vuelve a mirar el formato de la función Write, y ahora observa el programa nuevo. Primero inserta los parámetros en sus respectivos registros, apunta a la base de la librería y efectúa el salto. Recuerda que antes de acceder a la función tienes que abrir la librería. En el programa no se ve, pero ahora fíjate en el programa STARTUP. En sus primeras líneas verás cómo se hace. Su formato para abrirla es éste:
Un ejemplo de cómo abrir una librería puede verse en el listado 4. Cada vez que accedas a una función de la librería que hayas abierto (dos.library) has de insertar su base en el registro A6 y a continuación hacer el salto. Lo verás claramente en el primer programa. Las tres últimas líneas son también directivas, y sirven para guardar datos de cualqueir tipo, ya sean números como caracteres. En el caso del Macro Assembler, como el de otros, hay tres directivas que reservan datos en memoria y son éstas:
Otra directiva importante es EQU, que tiene su equivalencia en basic en la definición de una constante que nunca perderás. En el ejemplo, Execbase EQU $4 define Execbase con el valor constante $4. Siempre que utilices Execbase estarás utilizando el valor $4. En el listado 5 puede verse el programa anterior modificado, para que tengas completo conocimiento de estas importantes directivas. |
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Envía esta página web a un amigo: Esta opción está desactivada temporalmente, rogamos disculpen las molestias |
|