PRÁCTICA 0.b Introducción al lenguaje ensamblador DLX: instrucciones de coma flotante. OBJETIVO El objetivo de esta práctica es la familiarización con las instrucciones de cálculo en coma flotante, analizando la ejecución de programas en un simulador del repertorio DLX. INTRODUCCIÓN TEÓRICA. Para esta práctica se suponen conocidas las características generales de la arquitectura DLX, que fueron presentadas en la práctica 0.a. A continuación se hace un breve repaso a las características de esta arquitectura con respecto a la coma flotante. Para ampliar información se debe recurrir al libro "Arquitectura de Computadores, un Enfoque Cuantitativo" de J. L. Hennessy y D. A.Patterson. Además de los registros de enteros, la arquitectura DLX incorpora un conjunto de registros de coma flotante (FPR) que pueden ser considerados como registros de simple precisión (32 bits) o, según la instrucción, agrupados en pares como registros de doble precisión (64 bits). Estos últimos se denominan F0, F2, ..., F28, F30. Las parejas son fijas, es decir, F0 siempre se empareja con F1, F2 con F3, etc. Es decir, las instrucciones de coma flotante en precisión simple se pueden referir a cada uno de los 32 registros de coma flotante: f0, f1, f2, f3, ... etc. Sin embargo, las instrucciones que trabajan con datos en coma flotante de doble precisión necesitan una pareja de registros para contener cada operando, y se refieren a cada pareja por medio del registro de índice par que incluye, es decir, f0, f2, f4, etc. Es un error que una instrucción de coma flotante en doble precisión tenga como operando un registro de índice par, como f1, f3, ...etc. Las instrucciones en coma flotante se agrupan en dos subconjuntos: las de simple precisión (por ejemplo, lf, sf, addf, ... etc) y las de doble precisión (ld, sd, addd, ... etc). De esta manera, nunca hay ambigüedad cuando un registro operando es par: si la instrucción es de precisión simple, se accede únicamente a ese registro, mientras que si es de doble precisión, accede a una pareja de registros. El siguiente es un ejemplo de programa que utiliza instrucciones de cálculo para datos en coma flotante: 1 .data 0 a: .double 3.14159265358979 x: .double 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 .double 17,18,19,20,21,22,23,24,25,26,27 xtop: .double 28 .align 4 .text 0x100 start: ld add loop: ld multd sd sub bnez nop trap f2,a r1,r0,xtop f0,0(r1) f4,f0,f2 0(r1),f4 r1,r1,#8 r1,loop #6 Consideraciones: .- La definición de datos en coma flotante sigue la sintaxis general del DLX para definición de datos. En especial se usan las palabras reservadas .float y .double para definir datos en coma flotante de precisiones simple y doble respectivamente. .- Obsérvense los valores de carga de los dos segmentos, de código y datos. En concreto, en el segmento de datos se definen 29 datos de precisión doble, lo que supone un total de 29*8 = 232 bytes. Si este valor superara 256 (0x100), el código no podría almacenarse en la posición en la que va en el ejemplo, puesto que caería encima de la zona de datos. .- En los valores iniciales de las variables en coma flotante la parte entera se separa de la fraccionaria con un punto, como en la definición del dato a: .- Se debe tener en cuenta que, como se explicó en la práctica 0.a, el único modo de direccionamiento es el relativo a registro. Esto implica que, en el ejemplo, en la instrucción start: ld f2,a se hace referencia a la posición de memoria a:, no a su dirección. Es decir, el valor que se carga en el registro f2 es 3.14159265358979, no 0 (dirección de a:). Para cargar una constante en un registro, se debe hacer como en la instrucción add r1,r0,xtop Esta instrucción carga el valor de la dirección de xtop (224) en r1 (ya que r0 contiene un 0 siempre). .- Observese que, evidentemente, aunque los datos que procesan las instrucciones estén en coma flotante, sus direcciones son números naturales. En otras palabras, 2 cuando se accede a variables de memoria, aunque estén en coma flotante, para contener las direcciones se utilizan registros de enteros, como en la instrucción loop: ld f0,0(r1) DESARROLLO DE LA PRACTICA Escribir los siguientes programas, y comprobar su correcto funcionamiento. Estos programas serán utilizados en prácticas posteriores. Escribir las versiones para precisiones simple y doble. 1.- Escribir un programa que sume dos vectores de datos en coma flotante. 2.- Escribir un programa que calcule el producto escalar de dos vectores. 3.- Escribir un programa que calcule la suma de dos matrices. 4.- Escribir un programa que calcule la transpuesta de una matriz dada. 5.- Escribir un programa que comprima y otro que descomprima un vector. La compresión y descompresión son operaciones que se realizan sobre vectores la mayoría de cuyas componentes son ceros. La compresión consiste en generar dos vectores a partir del vector inicial, uno con las componentes distintas de cero, y otro con los índices de esas componentes en el vector inicial. La descompresión es la operación inversa. 6.- Escribir un programa que multiplique una matriz por un vector. 7.- Escribir un programa que multiplique dos matrices. 3