Modulo de Operaciones de Coma Flotante (Plasma)

From Qi-Hardware
Jump to: navigation, search

Daniel Santiago Muñoz 1.0, Andrés Felipe Rodríguez 1.0, Carlos Alfredo Paez .6


Contents

[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

Diagrama de Gantt del proyecto final

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:


Not cientifica.png


  • 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:


Exponente.png


  • 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:


Float 32.png


  • 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:


Exponente(2).png


  • 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:


Biased.png


  • 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.

F-type opcode.png

[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


Inst swc1.png


[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


Inst lwc1.png


[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


Inst fop.png


[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:


Opcode comp.png


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:


Opcode branch.png

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:


Inst comp.png


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.


Inst conv.png


[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


Move inst.png


[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:

FPU Diagrama Con Plasma.png


[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:

Retardos del Proceso


Donde se evidencia que la información extraída se redirecciona hacia los módulos de:

  1. 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
  2. Operaciones : Señales de activación de los procesos de suma/resta, multiplicación/división, conversión, etc...
  3. Condicionales : Activación de un tipo determinado de comparación y posteriormente de la instrucción tipo branch
  4. 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.


Exceptions table.PNG


[edit] Pre-Normalización

Este es un módulo donde:

  1. Se debe decodificar la información de exponente que se encuentra en el respectivo registro con el fin de procesarla
  2. 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
  3. 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
  4. 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
  5. 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
  6. 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:

  1. Decodificar los datos provenientes del banco de registro en tres partes: signo, mantisa y exponente
  2. Hacer la diferencia entre los exponentes de cada operando buscando el número con menor exponente
  3. Desplazar los datos de la mantisa del respectivo registro con menor exponente de manera que se puede realizar la operación
  4. Efectuar la operación teniendo en cuenta las consideraciones del estandar de trabajar con números con signo y no con complemento a dos
  5. 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:

  1. 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
  2. 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
  3. 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
  4. 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:

  1. Detectar si la operación es en simple o en doble precisión, e inicializar acordemente.
  2. Realizar la operación deseada con los valores de mantisa dados.
  3. Observar el resultado y realizar los corriemientos y normalización necesaria para posicionar la mantisa adecuadamente.
  4. 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:

  1. 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
  2. En la ALU de Plasma se carga el reg_source en a_in y la parte inmediata imm en b_in
  3. 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
  4. Se activa una pausa para el flujo de instrucciones durante un ciclo, de manera que se pueda acceder a la memoria de datos
  5. 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
  6. 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
"La simulación hace evidente que en la direccion 000004A0 el dato leído corresponde a CCB16228 (que es la representación del estandar IEEE del número -93.000.000 el cual se inicializó al principio del programa de prueba)"


[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:

  1. 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
  2. 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
  3. Por otro lado con relación al dato, el banco de registros de la FPU carga $f0,
  4. 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
  5. Adicionalmente se debe activar el registro de enable write_byte_enable para poder almacenar el dato
  6. 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
"En la simulación se indica que en la direccion 00000129 el dato almacenado en $f0 correspondiente a CCB16228 (que es la representación del estandar IEEE del número -93.000.000 ) es almacenado 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
  1. 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
  2. En el modulo de signo se obtiene el signo respectivo según la operación efectuada
  3. 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
  4. 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
  5. 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
  6. 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

  1. Si no se da la condición de salto no sucede nada, la secuencia de direcciones sigue igual
  2. 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
  3. 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)

  1. El dato en la dirección rt del banco de registros de plasma se envía hacia la FPU
  2. El multiplexor de la FPU se encarga de direccionar el dato hacia el banco de registros in_data1
  3. Por otro lado se carga la dirección de almacenamiento del banco de registros en in_c

[edit] MFC1

(Señalizado en color rojo)

  1. 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
  2. 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:

  1. Se tomó una instrucción en lenguaje C de una sencilla operacion y se genero su correspondiente .lst
  2. 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
  3. 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)
  4. 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
  5. 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:

  1. 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.
  2. 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.
  3. 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.
  4. 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

  1. Opencores, Plasma MIPS Rhoads, Steve. 2001. Plasma - most MIPS I (TM) opcodes. Opencores. [Online] 2001.
  2. IEEE 754, IEEE coma flotante.
  3. 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. 4.0 4.1 Oriol Arcas Abella, Beehive: an FPGA-based multiprocessor architecture. Master’s Degree in Information Technology final thesis
  5. Sweetman, Dominic. 2007. See MIPS run. San Francisco : Morgan Kaufmann Publishers / Elsevier,2007.
  6. [1], NaN.
Personal tools
Namespaces
Variants
Actions
Navigation
interactive
Toolbox
Print/export