Modulo de Operaciones de Coma Flotante (Plasma)
Daniel Santiago Muñoz 1.0, Andrés Felipe Rodríguez 1.0, Carlos Alfredo Paez .6
[edit] Calificación
| Porcentaje | Presentación 20% | Informe 30% | Funcionamiento 50% |
|---|---|---|---|
| 1 Entrega 10% | 1 | 1 | 1 |
| 2 Entrega 30% | 2 | 2 | 0 |
| 3 Entrega 20% | 3 | 3 | 3 |
| 4 Entrega 40% | 5 | 5 | 5
|
[edit] Descripción del Proyecto
Diseño de un modulo especial para Plasma[1] que realize operaciones entre registros tipo coma flotante F-TYPE de MIPS I con base en el estandar IEEE 754[2] con el fin de contribuir al desarrollo de proyectos donde se implementen algoritmos que requieran de mayor precision en sus calculos (Transformadas de Fourier, Raices Cuadradas, Funciones Trigonometricas, entre otros).
Mas información: proyecto similar desarrollado por estudiantes de la Pontifical Catholic University of Rio Grande do Sul[3] y una tesís final relacionada con la modificación de plasma como arquitectura multiprocesador.[4]
[edit] Cronograma
De manera más extensa al cronograma a continuación muestra una serie de objetivos acordes al cronograma con sus respectivas fechas y estado de desarrollo:
| Tarea | Fecha Inicio | Fecha Fin | Estado |
|---|---|---|---|
| Lograr entender la manera como las instrucciones se estan generando y como se establecen las variables mediante el estandar. [Mas Informacion].[5] | Ago 22 | Ago 30 | Terminada |
| Realizar un proceso de diseño del banco de registros para el módulo que sea independiente al del Plasma. | Sep 6 | Sep 17 | Terminada |
| Diseñar los módulos de operaciones y conversión internos. | Sep 1 | Sep 9 | Terminada |
| Hacer una primera integración entre el banco de registros y los módulos internos para así probar el correcto funcionamiento. | Sep 15 | Sep 28 | Terminada |
| 40% del proyecto | |||
| Verificar que la generación de instrucciones no genere conflictos con el diseño del modulo y se pueda realizar tanto redireccionamiento como también el almacenamiento de registros. | Sep 27 | Oct 8 | Terminada |
| Integrar el módulo al Plasma como COP1 y comprobar la inicializacion de registros tipo F por parte del compilador de GCC para la respectiva inicialización del banco de registros propio. | Oct 4 | Oct 29 | Terminada |
| 80% del proyecto | |||
| Probar finalmente la integración del programa mediante herramientas software. | Oct 11 | Nov 5 | Terminada |
| 90% del proyecto | |||
| Preparar un informe de costos y presentación final del proyecto. | Nov 16 | Nov 24 | Terminada |
[edit] Consideraciones Previas
Antes de iniciar a fondo con el desarrollo de este proyecto se deben hacer algunas presiciones:
[edit] Estandar IEEE-754
Es útil aclarar algunos aspectos del estandar IEEE para no generar dudas más adelante durante el desarrollo del proyecto:
- Un número cualquiera puede expresarse mediante notación cientifica, por ejemplo:
- En el estandar dicho número se define de la siguiente manera, donde (s) es el signo, (b) la base (binaria, decimal, etc...), (e) el exponente y (m) la mantisa o significando, esta última por ejemplo sería 2.3546789 para el número del item anterior:
- Por lo tanto se establece que un número en base binaria de coma flotante de presición simple se encuentra definido de la siguiente manera:
- Pero como se puede apreciar el exponente tiene 8 bits, es decir que se pueden tener 256 exponentes distintos para un número. Lo cual hace pensar que al necesitar exponentes negativos el uso de un bit como signo o la expresión del complemento a dos pueden ser poco eficientes, razón por la cual el número se expresa de forma parcial de la siguiente manera, donde (n) es el número de bits del exponente que son 8 en este caso:
- Finalmente, esto se hace para poder generar una codificacion para números como el cero que en este caso tendría signo, Infinito también con signo, NaN[6] o expresiones que no son un número como raices de números negativos o divisiones por cero, números subnormalizados o con un exponente menor al mínimo y finalmente los números normales, tal y como se puede apreciar en la siguiente figura:
- De lo anterior se debe aclarar que la expresión de números normales tiene un uno implícito en el MSB, por lo tanto en el campo (22-0) están los 23 bits menos significativos de la mantisa y por ello se aprecia que se suma un uno a dicha parte, por otro lado en el caso de números subnormalizados dicho uno no esta implícito sino que se expresa directamente en el campo del significando.
- La figura anterior también es útil para evaluar el tipo de número al presentarse desbordamiento tanto en el exponente como en la mantisa, que en el caso del exponente se indica mediante un flag de signed-zero o signed-infinite
| Exponente | Mantisa | |
|---|---|---|
| Desbordamiento | Cuando el valor del exponente es mayor que el máximo permitido el número se expresa como un signed-infinite | Cuando el MSB de la mantisa se encuentra más alla de su posición original (antes de una operación) se debe relocalizar con desplazamiento de la variable hacia la derecha. |
| Subdesbordamiento | Cuando el valor del exponente es menor que el permitido el número se toma como un signed-zero | Cuando al realizar desplazamiento de la mantisa hacia la derecha se pierden datos que estan más alla del LSB |
[edit] Instrucciones Básicas
Como se sabe la arquitectura MIPS posee 4 tipos de instrucciones tipo R, operaciones entre registros, tipo J, saltos, instrucciones tipo F las cuales son las que nos conciernen principalmente en el presente proyecto, y en menor medida las instrucciones tipo I, para operaciones inmediatas , movimiento de datas desde y hacia la memoria y saltos condicionales. Generalmente las instrucciones con punto flotante, tipo F, son ejecutadas mediante el uso de un coprocesador por lo cual la instrucciones se diferencias de las tipo R y poseen la configuración que se muestra en imagen.
[edit] Instrucciones de Carga y Almacenamiento
Sin el manejo de los datos a través del banco de registros independiente al de Plasma no sería posible el funcionamiento de la FPU, a continuación se describen brevemente las instrucciones correspondientes al manejo de memoria.
[edit] SWC1
Como se aprecia a continuación la instrucción se divide en cuatro partes:
- Opcode(31:26) indica el uso del coprocesador 1
- Opcode(25:21) dirección del banco de registros en el cual esta almacenado el valor base de la dirección donde se debe almacenar el dato, corresponde a un registro del procesador que puede ser $fp,$sp o $gp
- Opcode(20:16) dirección del banco de registros del la FPU en donde esta contenido el dato que va a ser almacenado en la memoria de datos
- Opcode(15:0) valor inmediato que debe ser extendido en signo y ser sumado con el valor base para obtener la dirección de memoria de datos en donde se almacena el dato
[edit] LWC1
Para el caso de la carga de datos
- Opcode(31:26) indica el uso del coprocesador 1
- Opcode(25:21) dirección del banco de registros en el cual esta almacenado el valor base de la dirección de donde se debe cargar el dato, corresponde a un registro del procesador que puede ser $fp,$sp o $gp
- Opcode(20:16) dirección del banco de registros del la FPU donde se debe cargar el dato contenido en la memoria de datos
- Opcode(15:0) valor inmediato que debe ser extendido en signo y ser sumado con el valor base para obtener la dirección de memoria de datos en donde se ubica el dato que debe cargarse
[edit] Instrucciones de Operaciones Básicas
Para el manejo de instrucciones básicas la instrucción se define como:
- Opcode(31:26) activación de COP1
- Opcode(25:21) formato de los datos que van a ser operados (para simple 10000) y (para doble 10001)
- Opcode(20:16) dirección del operando secundario
- Opcode(15:11) dirección del operando primario
- Opcode(10:6) dirección del registro destino donde se almacena el resultado
- Opcode(5:0) operación a realizar
[edit] Instrucciones Condicionales
La definición de instrucciones tipo branch en el caso del trabajo con variables tipo f depende de una instrucción anterior definida como comp la cual se encarga de realizar la previa comparación entre los dos registros. En primer lugar se presenta el opcode de este tipo de instrucciones:
El resultado de la comparación se almacena como el registro cc y luego este es usado por la siguiente instrucción que tiene que ser branch, esta se define mediante el siguiente opcode, en donde se distinguen dos tipos de branch, uno que se activa cuando el resultado de la comparación es verdadero y el otro que hace todo lo contario:
Nota: De la misma manera que en el set básico de instruccioens el campo opcode [15:0] u offset se define como el valor que se debe sumar o restar al valor de dirección actual de la memoria de instrucciones.
Finalmente y en resumen, el estandar MIPS define los siguientes tipos de comparaciones posibles entre dos registros:
Como se aprecia en algunos son muy familiares con como EQ que en el caso de trabajar con registros normales se hallaba unido al branch pero tambien existen comparaciones del tipo unordered; estas se presentan cuando por lo menos uno de los dos valores a comparar es del tipo NaN, otras como ordered tratan de considerar entre los dos registros de entrada cual se halla en un orden específico. Esto se expresa de la siguiente manera:
Dados dos números x,y se puede determinar su orden total a partir de varias comparaciones por ejemplo, dados dos datos (x,y) entonces, si (x<y): totalorder(x,y) = TRUE, por otro lado, si (x>y): totalorder(x,y) = FALSE. De manera que la comparación de orden busca encontrar de manera intrinseca que los números esten ordenados de manera sucesiva, en otras palabras para que la comparación sea verdadera x tiene que ser menor que y. Incluyendo que (x o y( un NaN.
[edit] Instrucciones de Conversión
La conversión de datos se da en formato tipo F, donde cvt.d.s sirve para la conversión de precisión doble a simple y cvt.s.d convierte un dato de doble precisión a precisión simple. Para este tipo de instrucciones en el que solo son necesarios dos registros el campo de “ft” siempre se mantiene en 0, “fd” la dirección del registro destino y “fs” es la dirección de el registro donde se encuentra el dato a convertir.
[edit] Instrucciones de Movimiento de Registros
En el estandar MIPS-I existen tres tipos de movimientos entre registros, uno que mueve un dato de un registro punto flotante o otro punto flotante MOVE, otro que mueve un dato del banco de registros de la FPU hacia el banco de registros de Plasma MFC1 y finalmente uno que hace lo contrario, trayendo el dato desde Plasma MTC1. A continuación se muestran los opcodes que relacionan este tipo de operaciones
[edit] Manejo de las instrucciones en Software
|
Por defecto en la instalación de gcc-mips ya se incluye la codificación de los datos inicializados en c en el formato IEEE-754 |
Para apreciar lo que sucede con las instrucciones se realizaron pruebas con un programa sencillo que se prensenta a continuación:
#include "plasma.h" int main(void) { volatile float a,b,c,d,r; a=-93000000; b=1.5; c=10.5; d=100.5; r=2; a+=b; r-=b; c*=b; d/=b; a+=930.45; b-=930.45; c*=930.45; d/=930.45; }
Usando el croscompilador con la siguiente instrucción se obtuvo el resultado en .lst
mips-elf-gcc -I../include -S FPU.c
Observando a continuacion solo la sección que nos interesa.
200: c7808010 lwc1 $f0,-32752(gp) //carga -93.000.000 en el banco de registros 204: 27bdffe8 addiu sp,sp,-24 208: e7a00000 swc1 $f0,0(sp) //almacena -93.000.000 en la pila 20c: c7828014 lwc1 $f2,-32748(gp) 210: c7808018 lwc1 $f0,-32744(gp) 214: e7a20004 swc1 $f2,4(sp) 218: e7a00008 swc1 $f0,8(sp) 21c: c782801c lwc1 $f2,-32740(gp) 220: c7808020 lwc1 $f0,-32736(gp) 224: e7a2000c swc1 $f2,12(sp) 228: e7a00010 swc1 $f0,16(sp) 22c: c7a20000 lwc1 $f2,0(sp) 230: c7a00004 lwc1 $f0,4(sp) 234: c786802c lwc1 $f6,-32724(gp) 238: 46001080 add.s $f2,$f2,$f0 //a+=b; 23c: c7878028 lwc1 $f7,-32728(gp) 240: e7a20000 swc1 $f2,0(sp) 244: c7a00010 lwc1 $f0,16(sp) 248: c7a20004 lwc1 $f2,4(sp) 24c: 00000000 nop 250: 46020001 sub.s $f0,$f0,$f2 //r-=b; 254: e7a00010 swc1 $f0,16(sp) 258: c7a20008 lwc1 $f2,8(sp) 25c: c7a00004 lwc1 $f0,4(sp) 260: 00000000 nop 264: 46001082 mul.s $f2,$f2,$f0 //c*=b; 268: e7a20008 swc1 $f2,8(sp) 26c: c7a4000c lwc1 $f4,12(sp) 270: c7a00004 lwc1 $f0,4(sp) 274: 00000000 nop 278: 46002103 div.s $f4,$f4,$f0 //d/=b; 27c: e7a4000c swc1 $f4,12(sp) 280: c7a00000 lwc1 $f0,0(sp) 284: 00000000 nop 288: 46000021 cvt.d.s $f0,$f0 //conversión de precisión simple a doble 28c: 46260000 add.d $f0,$f0,$f6 //a+=930.45; 290: 46200020 cvt.s.d $f0,$f0 //conversión de precisión doble a simple 294: e7a00000 swc1 $f0,0(sp) 298: c7a20004 lwc1 $f2,4(sp) 29c: 00000000 nop 2a0: 460010a1 cvt.d.s $f2,$f2 2a4: 46261081 sub.d $f2,$f2,$f6 //b-=930.45; 2a8: 462010a0 cvt.s.d $f2,$f2 2ac: e7a20004 swc1 $f2,4(sp) 2b0: c7a00008 lwc1 $f0,8(sp) 2b4: 00000000 nop 2b8: 46000021 cvt.d.s $f0,$f0 2bc: 46260002 mul.d $f0,$f0,$f6 //c*=930.45; 2c0: 46200020 cvt.s.d $f0,$f0 2c4: e7a00008 swc1 $f0,8(sp) 2c8: c7a2000c lwc1 $f2,12(sp) 2cc: 00000000 nop 2d0: 460010a1 cvt.d.s $f2,$f2 2d4: 46261083 div.d $f2,$f2,$f6 //d/=930.45; 2d8: 462010a0 cvt.s.d $f2,$f2 2dc: e7a2000c swc1 $f2,12(sp) 2e0: 03e00008 jr ra
Como se observa además de las operaciones aritméticas básicas se observa otras instrucción de uso exclusivo de como son swc1 y lwc1, además del uso de cvt.s.d y cvt.s.d las cuales son instrucciones usadas para la conversión de datos de simple precisión a doble precisión y viceversa.
Si en vez de usar las variables de tipo float se definen las variables como double se obtiene resultados distintos en lenguaje ensamblador, como podemos observar en el segmento a continuación.
lwc1 $f2,4($fp) nop lwc1 $f3,0($fp) lwc1 $f0,12($fp) nop lwc1 $f1,8($fp) nop add.d $f0,$f2,$f0 swc1 $f0,4($fp) swc1 $f1,0($fp)
Debido a que las variables de tipo double son de precisión doble, utilizan 64 bits en vez de 32, se observa que para cargar los datos se toman en pares de registros,en el par $f2 y $f3 se almacena el primer dato y en el par $f0 y $f1 el segundo dato, por lo tanto al realizar la operación add.d $f0,$f2,$f0 al indicas $f0 se refiere al par de registros $f0 y $f1, y al indicar $f2 se refiere al par $f2, $f3.
[edit] Diagrama de Bloques
Despues de consultar algunos ejemplos sobre la manera de realizar la anexión de un coprocesador al plasma tanto en [3] como en [4] se decide que la mejor manera de implementar el diseño de este proyecto es mediante un banco de datos propio, como se puede apreciar en la siguiente figura:
[edit] Diseño de Modulos de Operaciones Internos
Convención: En todos los diagramas de flujo, la salida de cada cuadro de desición expresa un NO hacia la derecha y un SI hacia abajo.
[edit] Control
El modulo de fpu_control se encarga de decodificar el opcode proveniente de Plasma, esto se puede apreciar de una mejor manera a través del siguiente diagrama:
Donde se evidencia que la información extraída se redirecciona hacia los módulos de:
- Banco de registros: Es el caso de las señales de dirección, fs, ft y fd. Donde se contiene la información del valor actual de un determinado registro
- Operaciones : Señales de activación de los procesos de suma/resta, multiplicación/división, conversión, etc...
- Condicionales : Activación de un tipo determinado de comparación y posteriormente de la instrucción tipo branch
- Datos: Direccion desde y hacia la memoria (interna o externa) de los datos
[edit] Excepción
Este módulo puramente combinacional se encarga de comparar los registros que contienen los operandos de manera previa a la realización de cualquier operación con el fin de revisar si se esta llegando a generar una excepción.
[edit] Pre-Normalización
Este es un módulo donde:
- Se debe decodificar la información de exponente que se encuentra en el respectivo registro con el fin de procesarla
- Se debe hacer la correspondiente operación entre exponentes, esto es: Si los registros se suman o restan se debe hallar el exponente mayor entre ambos, por otro lado si estos se multiplican o dividen se debe hallar el exponente resultante de la suma/resta de ambos
- Se debe verificar que el exponente no haya superado su límite, es decir, si es menor a cero o mayor al límite dado por su tamaño que puede variar entre 256 o 2048 según el tipo de float
- De ser así se debe generar un flag de excepción con el fin de activar el módulo de excepción y evitar que se siga el proceso de la operación pre_exc_zero ó pre_exc_inf corresponden a estas señales
- Por el contrario se debe proseguir con un flag de activación a los módulos de suma/resta o multiplicación/división según corresponda pre_result
- Finalmente, el proceso de finalización sea por post-normalización o por excepción debe inicializar de nuevo este módulo con el fin de continuar el proceso con otros datos
[edit] Suma/Resta
Este módulo debe:
- Decodificar los datos provenientes del banco de registro en tres partes: signo, mantisa y exponente
- Hacer la diferencia entre los exponentes de cada operando buscando el número con menor exponente
- Desplazar los datos de la mantisa del respectivo registro con menor exponente de manera que se puede realizar la operación
- Efectuar la operación teniendo en cuenta las consideraciones del estandar de trabajar con números con signo y no con complemento a dos
- Generar un flag de carry y una señal de finalización add_result ambas necesarias para el módulo de post-normalización
[edit] Postnormalización
En este módulo se deben:
- Efectuar corrimientos respectivos para lograr la normalización efectiva de la mantisa con el correspondiente aumento/disminución de pre_exp_result proveniente del módulo de prenormalización
- Comprobar la que no haya desbordamiento o sub-desbordamiento de alguna de las variables de modo que no se llegen a estados obsoletos, para ello se deben generar los flags de excepción post_exc_zero y post_exc_inf
- Generar los flags de finalización posteriores a la realización de una operación post_result, el cual además es el principal indicador de aceptación de un nuevo dato
- Unir las partes de signo, exponente y mantisa de manera que su salida corresponde al resultado de las operaciones
[edit] Multiplicación y División
Este modulo es el encarga de realizar operaciones de Multiplicación y división para la FPU, para esto en necesario tener en cuenta los casos en los cuales se encuentran resultados como 1X,XXX o 0,XXX los cuales tienen que ser posicionados correctamente para que el formato de la mantisa sea el dado por el estándar IEEE 754, se realiza una normalizacion la cual posiciona la mantisa correctamente y se envía una señal de normalización que se encarga de corregir el exponente en cualquiera de los dos casos, por lo tanto el modulo tiene las siguintes funciones:
- Detectar si la operación es en simple o en doble precisión, e inicializar acordemente.
- Realizar la operación deseada con los valores de mantisa dados.
- Observar el resultado y realizar los corriemientos y normalización necesaria para posicionar la mantisa adecuadamente.
- Entregar la mantisa al los siguientes módulos.
[edit] Simulación
Se en observa la simulación del modulo de multiplicación realizado,a partir del método de diseño anterior. Como se observa consume múltiples ciclos, para observar la máxima duración, a continuación se observa la división de 1.65 sobre 1.9375 este tipo de división exige normalización por lo cual consume mas tiempo que otras operaciones realizadas. Se observa en esta operación una demora de 56 ciclos de reloj, la cual seria la máxima demora observable.
[edit] Conversor
Este modulo se encarga de realizar conversiones entre números flotantes de simple precisión y flotantes de doble precisión, también realiza la conversión de un número flotante de simple precisión a entero. Para la conversión entre simple y doble precisión no se tiene en cuenta el bit de normalización ya que en ambos formatos este bit está implícito. Cuando se convierte de doble precisión a simple, se revisa que el exponente del primero no sobrepase el máximo exponente de la representación de simple precisión. Para la conversión de simple a entero el bit implícito de la mantisa si se tiene en cuenta y se realizan las operaciones que se muestran el el diagrama de flujo.
[edit] Banco de Registros
El banco de registros es el encargado de almacenar los datos que van a ser operados en el modulo requerido por el usuario mediante el opcode, en este se almacenan los valores a operar así como el resultado de la operación, la peculiaridad de el banco de registros para la FPU se encuentra en las operaciones de doble precisión, en el cual se operan valores de 64 bits por lo cual en la salida hay 2 valores de 32 bits cada uno, por la tanto para operar dos valores se tienen cuatro salidas simultaneas de 32bits cada una. Aprovechando las características de la FPGA a usar, se hace uso de la memoria dispersa mediante la función RAM16X1D, ya definida en las librerías, UNISIMS, en las herramientas de sintesis de Xilinx, debido a que esta limitado a 16 datos se usan 2 para cada salida, uno para los registros pares y otro para los impares, de esta manera se logra tener a la salida los dos datos necesarios para las operaciones de doble precisión. En la imagen se observa ademas de los módulos de memoria dispersa se observan dos módulos mas estos modulos a la entrada y salida de la memoria se encargan de direccionar los registros pares e impares, datos y señales de activación de escritura a su modulo de memoria correspondiente y lo mismo a la salida de los modulos de memoria, mediante el uso de multiplexores.
[edit] Funcionamiento del FPU
A continuacion se describe a través de una simulación el funcionamiento de la unidad FPU, se va a tomar como ejemplo de prueba el mismo codigo usado anteriormente para explicar la manera como se hace la codificacion de instrucciones
[edit] Carga y Almacenamiento de Datos
[edit] LWC1
Teniendo en cuenta el programa de prueba a partir de la instrucción:
200: c7808010 lwc1 $f0, -32752(gp)
Comienza la carga de datos de la memoria de datos hacia el banco de registros, proceso que se puede describir en los siguientes pasos:
- En reg_source se carga el dato de dirección base que para las instrucciones en coma flotante estará almacenado en los registros $sp, $fp o como en este caso en $gp, mientras que el valor de OFFSET corresponde al valor inmediato de la instrucción extendido en signo
- En la ALU de Plasma se carga el reg_source en a_in y la parte inmediata imm en b_in
- La suma de los datos que corresponde al valor de dirección entra al memory controller en donde se quitan los dos bits menos significativos de dicho registro resultando en la dirección addr_next
- Se activa una pausa para el flujo de instrucciones durante un ciclo, de manera que se pueda acceder a la memoria de datos
- El dato leído es almacenado en el registro data_r de manera este se puede llevar al reg_dest de la FPU donde mediante la activación del write enable se puede escribir el dato en el banco de registros tipo F finalizando el proceso de carga de datos
- Se debe aclarar que el registro rd de Plasma toma un valor de "000000", valor para el cual se desactiva el write enable del banco de registros de Plasma, con esto se busca que los datos cargados por la FPU no sean almacenados en el banco de registros del procesador
[edit] SWC1
Aunque el proceso de carga trae hacia el banco de registros los valores inicializados por el programa de prueba todo el conjunto de registros del banco no sería suficiente para almacenar gran cantidad de datos, de manera que se tienen que volver a almacenar los datos en una pila la cual se ubica en la memoria de datos, por esta razón como se aprecia en el siguiente fragmento de código se usa el stack pointer $sp:
208 : e7a00000 swc1 $f0,0(sp)
A continuación se describe el proceso de almacenamiento de estos datos:
- Se halla el valor de dirección en la ALU a partir del dato de dirección base contenida en $sp y por supuesto el valor de OFFSET
- El memory controller procesa el valor de dirección dado por la ALU de manera que a la salida de este módulo se tiene el valor de dirección de la memoria de datos
- Por otro lado con relación al dato, el banco de registros de la FPU carga $f0,
- El dato es enviado hacia un multiplexor en donde dependiendo del uso del coprocesador (señal cop1) se carga el registro data_write del memory controller, en este caso se almacena en dicho registro el datos contenido en $f0
- Adicionalmente se debe activar el registro de enable write_byte_enable para poder almacenar el dato
- Finalmente se activa la pausa para retener el flujo de datos (de manera similar a la anterior instrucción) de manera que finalmente con la dirección, el dato y el enable definidos se almacena el dato en la memoria de datos
Como se puede apreciar el proceso descrito hace evidente que el primer dato inicializado se almacena en la parte superior de la pila. Y en general, posteriores instrucciones de almacenamiento que hagan uso el stack pointer $sp indicarán carga de los datos inicializados en software en dicha estructura.
[edit] Operaciones Básicas
Se hacen ahora las operaciones entre datos en formato simple:
238 : 46001080 add.s $f2,$f2,$f0 250 : 46020001 sub.s $f0,$f0,$f2 264 : 46001082 mul.s $f2,$f2,$f0 278 : 46002103 div.s $f4,$f4,$f0
- Se cargan en los registros fs y ft los valores contenidos en la pila y que corresponden a los operandos, se activa una señal de pausa de manera que el el flujo de datos se detiene
- En el modulo de signo se obtiene el signo respectivo según la operación efectuada
- En el modulo de prenormalización los exponentes de los operandos se procesan dependiendo de la operación y adicionalmente se efectuan pruebas de desbordamiento o subdesbordamiento
- En el modulo de operación respectivo se realiza la obtención del valor resultado de mantisa a partir de las mantisas de los operandos
- En el modulo de postnormalización se modifica el valor del exponente y por supuesto la mantisa de tal manera que si hay un bit de carry por ejemplo se debe hacer un corrimiento buscando la normalización del número, por otro lado también se verifica si hay desbordamiento o subdesbordamiento y finalmente se realiza la unión de la mantisa resultado, el exponente y por supuesto el signo
- Al terminar el proceso de suma se desactiva la pausa y el dato resultado se almancena en el bando de registros
[edit] Saltos Condicionales y Movimientos
[edit] Saltos Condicionales
- Si no se da la condición de salto no sucede nada, la secuencia de direcciones sigue igual
- De lo contario, desde la FPU se envian dos señales hacia el módulo pc_new de Plasma, una con el flag de activación para el salto take_branch y otra con la dirección a la cual se debe hacer el salto address_new
- La dirección address_new es producto de la suma entre el valor de la dirección actual pc_current y el valor inmediato que contiene esta instrucción con la supresión de los dos ceros menos significativos
[edit] Movimientos
Como se explicó anteriormente se dan dos clases de movimientos:
[edit] MTC1
(Señalizado en color violeta)
- El dato en la dirección rt del banco de registros de plasma se envía hacia la FPU
- El multiplexor de la FPU se encarga de direccionar el dato hacia el banco de registros in_data1
- Por otro lado se carga la dirección de almacenamiento del banco de registros en in_c
[edit] MFC1
(Señalizado en color rojo)
- El dato en la dirección fs del banco de registros de la FPU se lleva a la entrada del módulo bus_mux de Plasma en donde a partir de la activación dada por el opcode de esta instrucción se escribe en reg_dest_new
- En Plasma la dirección rt_index es cargada en rd_index de manera que esta sea la dirección del banco de registros donde se va a guardar el dato proveniente de la FPU
[edit] Análisis de Rendimiento
A partir de libreria de punto flotante math.c incluida en el conjunto de archivos de Plasma para poder procesar datos en formato tipo flotante con la arquitectura hecha por Steve Rhoads se hizo una comparación de rendimiento con la FPU esto se hace con el fin de evidenciar las ventajas de esta herramienta principalmente en el caso de las operaciones básicas que son las que ocasionan retardos producto de los corrimientos para lograr las normalizaciones. En todos los casos el estudio se va a hacer con base en el tiempo de ejecución.
|
Según consulta hecha al propio Rhoads para el correcto funcionamiento de la libreria math.c se debe ampliar el banco de registros del Plasma de manera que se puedan almacenar y/o cargar los registros tipo F inicializados. De otro modo no se estarían haciendo las operaciones con lo datos correctos, por tal razón se usó la estructura en hardware de la FPU para probar la implementación de math.c |
[edit] Metodología de los Cálculos
Para la el claro entendimiento de los cálculos que se van a presentar a continuación se deben hacer algunas presiciones:
- Se tomó una instrucción en lenguaje C de una sencilla operacion y se genero su correspondiente .lst
- A partir del .lst y de la correspondiente simulación se hizo cuenta del número de instrucciones desde la carga de datos de la memoria de datos hasta que el resultado se almacenara de nuevo en la memoria de datos
- Se agruparon los tipos de instrucciones según su gasto en tiempo, tal es el caso de LW/SW que se demoraban dos ciclos de reloj, las otras en general se efectuaban en un solo ciclo y por último se contaban los ciclos de reloj de la instrucción de la operación específica (caso hardware)
- Se hizo el cálculo del porcentaje que tenía cada tipo de instrucciones en la operación y luego se multiplicó dicho porcentaje por el número de ciclos aproximados por instrucción, dicho valor corresponde al CPI individual por cada tipo de instrucción
- Finalmente se sumaron todos los CPI individuales de manera que se tuviera el CPI de todo el conjunto de instrucciones
[edit] Suma
Para este caso se hicieron varias pruebas hasta encontrar una relación entre el producto del número de instrucciones y las instrucciones totales de cada operación que se acercara más de manera que se tuviera un límite. Por lo tanto para la suma entre los números: a=1.42872329e6 y b=9.31 se tuvieron los siguientes resultados:
| Tipo de Instrucción | No. Ciclos (SW) | No. Ciclos (HW) | % Inst. (SW) | % Inst. (HW) | No. Inst. (SW) | No. Inst. (HW) | CPI (SW) | CPI (HW) |
|---|---|---|---|---|---|---|---|---|
| LW - SW | 2 | 2 | 29.31% | 9.09% | 17 | 7 | 0.5862 | 1.2726 |
| Type-R | 1 | 1 | 44.82% | 18.18% | 26 | 2 | 0.4482 | 0.1818 |
| Type-J | 1 | 1 | 25.86% | 9.09% | 15 | 1 | 0.2586 | 0.0909 |
| Add(HW) | -- | 51 | -- | 9.09% | -- | 1 | -- | 4.6359 |
| TOTAL | 58 | 11 | 1.293 | 6.1812 | ||||
Como se puede ver para estos dos números con una diferencia de 6 cifras significativas el desempeño en hardware es cercano al del software, pero esto puede alterarse tal y como se apreciar en la siguiente tabla donde se compara el número de cifras significativas de diferencia entre los dos operandos y el valor de CPI:
| Dif. Cif. Sig. | # Ciclos | CPI | CPI * I |
|---|---|---|---|
| 1 | 18 | 3.1815 | 35 |
| 2 | 25 | 3.8178 | 42 |
| 3 | 31 | 4.3632 | 48 |
| 4 | 37 | 4.9086 | 54 |
| 5 | 44 | 5.5449 | 61 |
| 6 | 51 | 6.1812 | 68 |
| 7 | 58 | 6.8175 | 75 |
Como se puede apreciar en el valor correspondiente a 7 cifras de diferencia el valor CPI*I es equivalente al de software. De manera que si hay una mayor diferencia entre los exponentes de ambos operandos el proceso de software tiene mejor desempeño que el de hardware. Esto ocurre debido a los corrimientos de uno de los dos operandos en el diseño original que buscan que ambos operandos se encuentren bajo el mismo exponente para poder realizar la operación (suma/resta).
Una posible solución si se requiere trabajar con números con estas diferencias es reemplazar el proceso de corrimientos con una sola instrucción de shift que desplaze el registro con menor exponente un número (n) hacia la derecha en un solo ciclo donde (n) corresponde a la diferencia entre ambos exponentes.
[edit] Resta
De igual manera para la resta se tomaron los datos anteriores dado que estos también hacían parte del ciclo límite. Por lo tanto para la resta entre los números: a=1.42872329e6 y b=9.31 se tuvieron los siguientes resultados:
| Tipo de Instrucción | No. Ciclos (SW) | No. Ciclos (HW) | % Inst. (SW) | % Inst. (HW) | No. Inst. (SW) | No. Inst. (HW) | CPI (SW) | CPI (HW) |
|---|---|---|---|---|---|---|---|---|
| LW - SW | 2 | 2 | 31.88% | 9.09% | 22 | 7 | 0.6376 | 1.2726 |
| Type-R | 1 | 1 | 44.92% | 18.18% | 31 | 2 | 0.4492 | 0.1818 |
| Type-J | 1 | 1 | 23.18% | 9.09% | 16 | 1 | 0.2318 | 0.0909 |
| Sub(HW) | -- | 1 | -- | 9.09% | -- | 69 | -- | 6.2721 |
| TOTAL | 69 | 11 | 1.3186 | 7.8174 | ||||
De manera similar que en el caso de la suma se debe tener en cuenta la diferencia de exponentes entre los operandos para no ocasionar retrasos importantes.
[edit] Multiplicación
Para el caso de la multiplicación se tomaron datos independientes ya que el ciclo de operación no impone mayores retardos. Por lo tanto para la multiplicación entre los números: a=41.694161e6 y b=41.694061e6 se tuvieron los siguientes resultados:
| Tipo de Instrucción | No. Ciclos (SW) | No. Ciclos (HW) | % Inst. (SW) | % Inst. (HW) | No. Inst. (SW) | No. Inst. (HW) | CPI (SW) | CPI (HW) |
|---|---|---|---|---|---|---|---|---|
| LW - SW | 2 | 2 | 18.18% | 63.63% | 12 | 7 | 0.3636 | 1.2726 |
| Type-R | 1 | 1 | 65.15% | 18.18% | 43 | 2 | 0.6515 | 0.1818 |
| Type-J | 1 | 1 | 10.6% | 9.09% | 7 | 1 | 0.106 | 0.0909 |
| MFLO(SW)/Mult(HW) | 30.75 | 33 | 6.06% | 9.09% | 4 | 1 | 1.8634 | 2.9997 |
| TOTAL | 66 | 11 | 2.9845 | 4.545 | ||||
Como se puede analizar para el caso software se usa una gran cantidad de instrucciones tipo-R las cuales corresponden a operaciones condicionales en mayor medida. Y con relación al gasto de tiempo en hardware, se puede decir que es independiente de la diferencia entre cifras significativas. Más por otro lado el rendimiento en software se ve afectado por la instrucción MFLO.
[edit] División
Finalmente para la división se tomaron los mismos datos que en el caso anterior, de manera que la división entre los números: a=41.694161e6 y b=41.694061e6 se tuvo los siguientes resultados:
| Tipo de Instrucción | No. Ciclos (SW) | No. Ciclos (HW) | % Inst. (SW) | % Inst. (HW) | No. Inst. (SW) | No. Inst. (HW) | CPI (SW) | CPI (HW) |
|---|---|---|---|---|---|---|---|---|
| LW - SW | 2 | 2 | 16.09% | 63.63% | 14 | 7 | 0.3218 | 1.2726 |
| Type-R | 1 | 1 | 63.21% | 18.18% | 55 | 2 | 0.6321 | 0.1818 |
| Type-J | 1 | 1 | 13.79% | 9.09% | 12 | 1 | 0.1379 | 0.0909 |
| MFLO(SW)/Div(HW) | 33.1 | 38 | 6.89% | 9.09% | 6 | 1 | 2.1586 | 3.4542 |
| TOTAL | 87 | 11 | 3.2504 | 4.995 | ||||
De manera similar al caso anterior las instrucciones se mantienen independientes a la diferencia de cifras significativas y el desempeño en software se ve afectado de igual manera por las instrucciones MFLO.
[edit] Conclusiones
A continuación se muestra la comparación entre tiempos de ejecución de las operaciones tanto en hardware como en software, considerando que en el caso de la suma y la resta no se tienen condiciones límite sino inferiores frente al desempeño de las mismas operaciones en software:
| SW(us) | HW(us) | |
|---|---|---|
| Suma | 15 | 13.6 |
| Resta | 18.2 | 17.2 |
| Multiplicación | 39.4 | 10 |
| División | 56.6 | 10 |
Finalmente se pueden hacer algunas presiciones finales que comprenden el desarrollo de todo el proyecto:
- La unidad de coma flotante para Plasma funciona entre números con diferencia de exponente menor a 7 para realizar operaciones como sumas o restas de lo contrario debe modificarse como se indicó anteriormente. En el caso de operaciones de mutiplicación y división esto no ocurre.
- El banco de registros tipo F es favorable al manejo de librerias en software para la realización de operaciones entre variables tipo float o double, dado que si se trabaja en Plasma como se dijo anteriormente se debe ampliar el banco de registros.
- El proceso de corrimientos en el diseño en algunas ocasiones para el caso de variables tipo double puede generar una pérdida de precisión de aproximadamente 1e-6 derivada de dichos corrimientos.
- Se puede tomar un modelo más reducido del la unidad si solo se requieren las operaciones ignorando las comparaciones (buscando ahorrar el número de compuertas en el dispositivo).
[edit] Referencias
- ↑ Opencores, Plasma MIPS Rhoads, Steve. 2001. Plasma - most MIPS I (TM) opcodes. Opencores. [Online] 2001.
- ↑ IEEE 754, IEEE coma flotante.
- ↑ 3.0 3.1 Taciano A. Rodolfo, Ney L. V. Calazans, Fernando G. Moraes. Floating Point Hardware for Embedded Processors in FPGAs. 2009 International Conference on Reconfigurable Computing and FPGAs
- ↑ 4.0 4.1 Oriol Arcas Abella, Beehive: an FPGA-based multiprocessor architecture. Master’s Degree in Information Technology final thesis
- ↑ Sweetman, Dominic. 2007. See MIPS run. San Francisco : Morgan Kaufmann Publishers / Elsevier,2007.
- ↑ [1], NaN.
