Revistas en papel
 Amiga World Nº17 - Enero 1991
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.


Todo el mundo que
desee programar el
Amiga, debe saber las
estructuras a seguir
en la realización de
ciertas operaciones,
pero primero deberá
conocer
profundamente el
Ensamblador del
68000.
Los cuadernos del
Ensamblador

 

Por F. Javier Rodríguez

Amiga World

 

CAPÍTULO IV


En el capítulo del mes pasado se comenzó a ver la función de las instrucciones que componen el set del 68000, en concreto se vió la función de una instrucción específica: MOVE. Con dicha instrucción (con la que se puede ver la flexibilidad de programación) se podían almacenar datos en memoria, así como leer los mismos e intercambiar el contenido de dos operandos. En este capítulo proseguiremos con el 'funcionamiento' de dichas instrucciones.


Las variantes de MOVE

Las variantes de la instrucción MOVE son tres: MOVEA, MOVEM y MOVEP, las cuales no surgen como prolongación de la anterior instrucción, sino que se trata de tres instrucciones más del Set de instrucciones. Seguramente se preguntarán el porqué de estas instrucciones, ya que la instrucción MOVE es en sí muy flexible.

La principal diferencia entre MOVE y las tres instrucciones variantes es que estas últimas realizan operaciones más específicas y potentes que la instrucción 'madre'. Es muy importante aplicar cada operación a la instrucción que mejor la realice, así como a la que menos tiempo de procesador consuma (ver cuadro 1: 'Ciclos y Tiempos'), por lo cual EL PROGRAMADOR NO HA DE LIMITARSE AL USO DE LA INSTRUCCIÓN MAS COMODA, SINO QUE POR EL CONTRARIO HA DE BUSCAR AQUELLA QUE MEJOR REALICE LA TAREA.

Las diferencias con respecto a MOVE, tanto en la sintaxis como en las operaciones, son las siguientes:

MOVEA: Esta instrucción sólo admite como tamaño de datos la palabra (W) y la doble palabra (L), eliminando la longitud BYTE; mientras que la instrucción MOVE contempla los tres tamaños de datos. El significado de MOVEA es, en inglés, MOVE Adresse (mover dirección) con lo cual se puede visualizar, aunque de forma poco clara, la función que realiza esta instrucción.

En concreto mediante esta instrucción lo que se consigue es cargar un registro de dirección con un valor, sin que la operación afecte el estado del CCR (rebose, negativo, cero). Debido a que las direcciones en el Amiga (concretamente en el 68000) son de 32 bits, no es posible el uso del BYTE como extensión de tamaño; incluso si se utiliza como tamaño la palabra (16 bits) automáticamente se extiende a 32 bits (con extensión de signo). El siguiente ejemplo muestra la sintaxis de ésta instrucción.

     MOVE.W #$6000,A0 ----> A0 = $00006000
     MOVE.L #$6000,A0 ----> A0 = $00006000

MOVEM: Esta quizá sea la instrucción variante de MOVE más potente, ya que mediante ella se pueden mover en una misma operación varios registros. El máximo es de 16 registros (los 8 de dirección mas los 8 de datos). La longitud de tamaño que se puede definir, como en el caso anterior, es de palabra o doble palabra, excluyendo el BYTE.

Quizá ésta sea también la instrucción cuya sintaxis se sale un poco de lo 'común' ya que se compone de varias características particulares. Entre las principales características se encuentra el modo en el que se realiza la selección de los registros que se desean 'mover', ya que puede realizarse en grupos o únicamente los especificados por el programador.

Para ver de una forma más directa esta instrucción, se verán a continuación una serie de ejemplos:

     MOVEM.L A0-A7/D0-D7,$5000

Mediante esta operación se guarda el contenido de todos los registros (tanto de datos, como de direcciones) a partir de la dirección $5000. Para recuperar los valores en los registros se deberá emplear la siguiente sintaxis:

     MOVEM.L $5000,A0-A7/D0-D7

Habrá observado que entre A0 y A7, así como entre D0 y D7 se encuentra un guión; esto significa que se operará con los registros incluidos entre A0 y A7 (ambos incluidos), así como con los registros D0 y D7. También se encuentra otro símbolo que se ve por primera vez en la sintaxis de una instrucción, dicho signo '/' se utiliza para separar los registros de datos o direcciones con los que se va a operar (en caso de que estos no tengan una continuidad en grupo).

     MOVEM.L A0/A3/A6/D0-D5,$5000

Mediante la anterior instrucción se salvan en memoria a partir de la dirección $5000, los registros A0, A3, A6 y los comprendidos entre D0 y D5. Para volver a asignar los valores en los registros se debe realizar la siguiente operación:

     MOVE.L $5000,A0/A3/A5/D0-D5

Como puede ver la instrucción MOVEM es muy potente, ya que para realizar la misma operación con la instrucción MOVE se necesitaría una línea de programa para mover cada uno de los registros (aumentando el tamaño del código, así como disminuyendo la velocidad de programa).

MOVEP: Al igual que la anterior instrucción, esta es bastante potente; también al igual que las dos anteriores sólo permite el trabajo con palabras o dobles palabras. El funcionamiento de ésta instrucción es algo complejo, ya que habría que entrar en temas que, por ahora, sonarían bastante raro; sino desconocido.

Para explicar el funcionamiento de la instrucción MOVEP hay que hacer primero un poco de historia. Al contrario de otros ordenadores, en cuyo set se encuentran instrucciones especiales de I/O (entrada/salida) el 68000 realiza este proceso mediante la instrucción MOVEP y una dirección.

Hay que decir que en la actualidad existen muchos periféricos asíncronos que utilizan los 8 bits, y cuyo funcionamiento se ve reflejado en una determinada posición de memoria (la mayoría de las veces gracias a la controladora del periférico); dicha posición de memoria es la referida anteriormente para la instrucción MOVEP.

El BUS del Amiga posee 16 líneas, sin embargo el periférico de 8 bits puede optar por dos vías, o bien tomar las 8 líneas más significativas o bien las 8 líneas menos significativas; reflejándose en la memoria del ordenador como direcciones pares consecutivas o direcciones impares consecutivas. En cualquier caso el incremento para la siguiente posición de memoria es 2.

Supongamos que A1 contiene la dirección inicial de control del dispositivo, y que D0 contiene el dato a enviar. La forma correcta sería enviar el dato mediante el siguiente esquema:

1) mover el cuarto byte a la dirección contenida en A1

2) mover el tercer byte a la dirección contenida en A1+2

3) mover el segundo byte a la dirección contenida en A1+4

4) mover el primer byte a la dirección contenida en A1+6

Hay que decir que en
la actualidad existen
muchos periféricos
asíncronos que
utilizan los 8 bits, y
cuyo funcionamiento
se ve reflejado en
una determinada
posición de memoria
(la mayoría de las
veces gracias a la
controladora del
periférico); dicha
posición de memoria
es la referida
anteriormente para
la instrucción MOVEP

Pues bien, dicha operación que a simple vista parece necesitar 8 líneas de código fuente, se resuelve mediante la instrucción MOVEP de la siguiente forma:

     MOVEP.L D0,0(A0)

Esta instrucción posee un modo de postincremento automático en el contador de dirección, por lo que se suma 2 al puntero de dirección automáticamente cada vez que se mueve uno de los bytes contenidos en D0.

Probablemente no habrá comprendido el funcionamiento de dicha instrucción en su totalidad, pero de todas formas esta instrucción se verá con más detalla avanzado el curso.


Cuestión de intercambio

Otra de las ventajas que posee el 68000 es que contiene dos instrucciones con las cuales se pueden realizar dos tipos diferentes de intercambios, ya sea entre registros o entre los dos bytes que componen una palabra.

Estos dos modos de operación son muy útiles a la hora de realizar diversas operaciones, además de ahorrar en código y por tanto en velocidad del programa. La primera de dichas instrucciones es equiparable a la siguiente sintaxis del Basic, mediante la cual se intercambian los valores de dos variables:

     C=0:A=5:B=10
     C=A:A=B:B=C

Al final de realizar esta operación, A será igual a 10 y B a 5. Esta operación en Ensamblador es incluso más sencilla, ya que para ella sólo es necesario contar con la instrucción EXG, cuyo tamaño de dato sólo admite como única posibilidad la doble palabra. El equivalente de la anterior operación en Ensamblador será de la siguiente forma:

     MOVE.W #5,D0
     MOVE.W #10,D0
     EXG.L D0,D1

Como resultado se obtendrá para D0 el valor 10, y para D1 el valor D1. Además de con registros de datos, esta instrucción también funciona con registro de direcciones:

     MOVE.W #$5000,A0
     MOVE.W #$6000,A1
     EXG.L A0,A1

Al final de la operación, A0 apuntará a la dirección $6000 y A1 al a dirección $5000. Una restricción, por otro lado evidente, es que no se pueden intercambiar datos en modo directo ya que no tiene ningún sentido sintáctico la siguiente frase:

     10=20 o su equivalente en Ensamblador:
     EXG.L #$10,#$20

Sin embargo si es posible el intercambio de valores contenidos en direcciones indicadas en modo absoluto, es decir sin encontrarse dentro de un registro de direcciones. Como muestra observe el siguiente ejemplo:

     MOVE.W #5,$5000
     MOVE.W #10,$6000
     EXG,L $6000,$5000

Mediante esta sintaxis se intercambian ambas direcciones, es decir en la dirección $5000 se encontrará el valor 10, y en la dirección $6000 el valor 5.

La segunda de las instrucciones capaz de intercambiar un valor es SWAP, aceptando como extensión de tamaño únicamente la palabra.

Esta instrucción es de un nivel diferente a la anterior, ya que no se intercambia el orden de los dos bytes que forman la palabra en cuestión. Para observar el funcionamiento de esta instrucción recurriremos a un nuevo ejemplo:

     MOVE.W #%1111111100000000,D0
     SWAP.w D0

Después de esta operación el valor contenido en D0 será el siguiente #%0000000011111111. Se ha utilizado el formato binario para definir el valor del dato, ya que mediante este formato se observa con una mayor claridad el cambio de los bytes.

Por otro lado el que la instrucción SWAP no pueda trabajar con dobles palabras, no quiere decir que el dato tratado se encuentre definido como una doble palabra; lo único que pasará es que los dos bytes superiores no se verán afectados por la operación:

     MOVE.L #%10101010101010101111111100000000,D0
     SWAP.W D0

Tras la operación, el registro D0 contendrá el siguiente valor:

     D0 = #%10101010101010100000000011111111.        


La aritmética del 68000

Uno de los principales grupos de instrucciones de cualquier procesador, a la hora de programa en Ensamblador, es el grupo de instrucciones aritméticas. Mediante dichas instrucciones se pueden realizar desde sencillas sumas, restas, multiplicaciones y divisiones, hasta analizar complejas sintaxis matemáticas (mediante una programación más compleja). En este sentido el 68000 posee un juego de instrucciones aritméticas bastante potentes y flexibles, sin la necesidad de que el programador deba realizar complejas rutinas para obtener resultados sencillos.

La primera y mas sencilla de este tipo de instrucciones es la encargada de borrar un registro: CLR. Dicha instrucción se puede equiparar a la encargada desde el Basic de poner a 0 una variable. La función de dicha instrucción aunque no lo parezca a simple vista es muy útil; siempre que se utilice de una forma adecuada.

CUADRO 1:

CICLOS Y TIEMPOS

Toda las instrucciones que posee el 68000 precisan un determinado número de ciclos de procesador para realizar su tarea. En cada caso el número de ciclos es distinto, dependiendo de varios factores como por ejemplo modo de operación o complejidad de la instrucción en sí.

Los ciclos de procesador son muy rápido, equivalente en tiempo (y en el cado del procesado 68000) a 8 millones de ciclos por segundo. Después de leer esta cifra pensará que a tal velocidad da igual desperdiciar unos cuantos ciclos de más, utilizando una instrucción en vez de otra. Se equivoca.

En muchas ocasiones este 'desperdicio' de tiempo puede repercutir en segundos y segundos acumulados, un mayor consumo de memoria y tareas mucho más 'lentas'. Como ejemplo decir que la operación 'CLR.W D0' consume menos ciclos que si se realizase mediante 'MOVE.W #$0000,D0'.

El lenguaje Ensamblador es tremendamente rápido, pero no significa que se tenga que descuidar la programación porque 8 millones de ciclos por segundo 'dan para mucho'. El principal problema es que en los programas voluminosos una descuidada programación del código fuente repercute en un mayor consumo de memoria (más del que se puede pensar a simple vista) y por tanto el tiempo utilizado en la realización de las tareas y rutinas será superior.

El principal objetivo de dicha instrucción es eliminar, de un registro en concreto, todo resto resultante de un uso anterior con dicho registro. Esto se debe a que en ocasiones se asignan a los registros de datos Bytes, palabras o dobles palabras. Supongamos que se asigna en el resultante de una operación a D0 en valor #$FFFFAAAA; si este no se borra adecuadamente puede suceder que en una operación posterior sólo se utilicen los dos bytes inferiores, no conteniendo D0 el valor real puesto que queda como 'restos' de la anterior operación los dos Bytes superiores. Veamos el siguiente ejemplo:

     MOVE.L #$FFFFAAAA,$5000
     MOVE.L $5000,D0
     MOVE.L D0,$6000
     MOVE.W #$FFFF,D0
     MOVE.W D0,$6000

En la primera línea de programa se almacena el valor (doble palabra) #$FFFFAAAA en la posición de memoria $6000. A continuación D0 toma el valor contenido en dicha posición de memoria, por lo que D0 también contendrá el valor #$FFFFAAAA, después D0 almacena su valor en la posición de memoria $6000; por lo que dicha posición también contendrá el valor #$FFFFAAAA. Después el registro D0 es utilizado para albergar un nuevo valor (en esta ocasión una palabra, por lo que no son afectados los 2 Bytes superiores). El último paso que se realiza es almacenar el contenido en la posición $6000, y aquí es donde se encuentra el problema.

Para explicar el
funcionamiento
de la
instrucción
MOVEP hay que
hacer primero
un poco de
historia

Si posteriormente se lee el valor de la posición $6000 (como doble palabra), no se corresponderá con el que usted creía haber almacenado, ya que será #$FFFFFFFF y no #$0000FFFF, que sería el que usted esperaba obtener.

El uso de la instrucción CLR es muy sencillo, ya que pone a cero la parte del dato que usted desea borrar:

     CLR.B D0 ----> Borra el byte inferior de D0
     CLR.W D0 ----> Borra la palabra inferior de D0
     CLR.L D0 ----> Borra los 32 bits de D0

Otra forma de realizar este proceso es de la siguiente forma...

     MOVE.B #$00,D0 ---> Borra el byte inferior de D0
     MOVE.W #$0000,D0 ---> Borra la palabra inferior de D0
     MOVE.L #$00000000,D0 ---> Borra los 16 bits de D0

Pero es más lento, y si existe una instrucción encargada de hacerlo (este es el caso) debe utilizarla.

De todas formas podrá utilizar las instrucciones anteriores para realizar las mismas operaciones, ya que ni el ensamblador ni el Linkaje del programa presentarán errores de sintaxis, pero recuerde que siempre que utilice la instrucción adecuada ganará velocidad de programa, además de acostumbrarse a utilizar BIEN el juego de instrucciones.


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