Documente Academic
Documente Profesional
Documente Cultură
MAESTRA EN INGENIERA
ESPECIALIDAD: MECATRNICA
REPORTE DE PRCTICA: 04
En todo nmero de punto flotante se distinguen tres componentes: Signo: indica el signo del nmero (0 = positivo, 1 = negativo) Mantisa: contiene la magnitud del nmero (en binario puro) Exponente: contiene el valor de la potencia de la base (sesgado) La base queda implcita y es comn a todos los nmeros, la ms usada es 2. Dado que un mismo nmero puede tener varias representaciones, los nmeros suelen estar normalizados. Un nmero est normalizado si tiene la forma 1.xx2xx. Los nmeros normalizados en base 2 tienen siempre un 1 a la izquierda, ste suele quedar implcito. (1) El estndar IEEE 754 especifica tres formatos de precisin:
SIGNO 1 BIT
SIGNO 1 BIT
EXPONENTE 11 BITS
MANTISA 52 BITS
SIGNO 1 BIT
EXPONENTE 15 BITS
DESARROLLO Para llevar a cabo la suma de dos nmeros de punto flotante se siguen los pasos enlistados a continuacin: 1. Se comparan los exponentes de los dos nmeros y realizan operaciones de corrimiento hacia la derecha del menor, incrementando en 1 a su exponente, hasta que sea igual que el mayor. 2. Se suman las fracciones. 3. Se normaliza el resultado de la suma, haciendo los corrimientos necesarios a la mantisa e incrementando el exponente de la suma, esto en caso necesario. 4. Se redondea la suma en caso de que los dgitos sean diferentes a los bits utilizados por los operandos originales. La comparacin de los exponentes se lleva a cabo mediante una resta, por lo que fue necesario implementar una ALU (figura 2).
S2 0 0 0 0 1 1 1 1
S1 0 0 1 1 0 0 1 1
S0 0 1 0 1 0 1 0 1
X(LE) A A AND B A OR B A A A A A
Y(AE) 0 0 0 0 B B 0 1
C0(CE) 0 0 0 0 0 1 1 0
Para el primer paso, se realiza una resta de los exponentes, utilizando la diferencia como sumando para el menor exponente y como el nmero de corrimientos hechos a la mantisa para tener ahora dos cantidades normalizadas con el mismo exponente. Al hacer los corrimientos, se toma en cuenta el bit oculto, el cual qued implcito en la primera normalizacin para el nmero de punto flotante y ahora pasar a tomar el valor de 0. En caso de que los exponentes originalmente sean iguales, no se realizar corrimiento en las mantisas, ni suma en los exponentes. La seleccin del nmero con menor mantisa se hizo mediante un multiplexor genrico 2 a 1, de 8 bits para el exponente y 23 bits para la mantisa. En el segundo paso, se suman las mantisas (que ahora tienen el mismo exponente). Si se generara overflow en esta suma, se hara un nuevo corrimiento para normalizar el resultado de la suma, tomando en cuenta el bit implcito de la mantisa para introducirlo como primer bit del corrimiento hacia la derecha; adems, se incrementara el exponente en 1. Dentro del diseo que realiza los corrimientos, se implement una comparacin la cual revisa que el nmero de corrimientos sea menor que el nmero de bits de la mantisa, y en caso contrario hace un redondeo, poniendo el bit menos significativo en 1. RESULTADOS Una vez realizado el diseo completo, se comprob su funcionalidad utilizando un testbench, en el que se guardan los dos operandos de punto flotante para ser sumados. Como primera prueba se hizo la suma de los nmeros 0.25 y 100, los cuales en notacin de punto flotante (precisin sencilla) se representan respectivamente de la siguiente manera:
SIGNO 0 SIGNO 0 EXPONENTE 0111 1101 EXPONENTE 1000 0101 MANTISA 00000000000000000000000 MANTISA 10010000000000000000000
La diferencia entre los exponentes es de 8, por lo que al exponente menor se le sumar 8, y se harn 8 corrimientos a la mantisa. Quedando la siguiente suma: +
= SIGNO 0 0 0 EXPONENTE 1000 0101 1000 0101 1000 0101 MANTISA 00000001000000000000000 10010000000000000000000 10010001000000000000000
El exponente del resultado qued igual ya que no fue necesario volver a normalizar el resultado. El resultado final es mostrado en la figura 3.
Prueba de otra suma: 9.75 + 22.4375 9.7510 = 1001.112 x 20 = 1.001112 x 23 Exponente: 3 + 127 = 13010 = 100000102 22.437510 = 10110.01112 x 20 = 1.011001112 x 24 Exponente: 4 + 127 = 13110 = 100000112
SIGNO 0 SIGNO 0
Al restar los exponentes, la diferencia es 1, por lo que se suma 1 al exponente menor y se hace un corrimiento a la mantisa correspondiente; quedando la siguiente suma: +
= SIGNO 0 0 0 EXPONENTE 1000 0011 1000 0011 1000 0011 MANTISA 10011100000000000000000 01100111000000000000000 00000011000000000000000
En la mantisa del resultado hubo un overflow, por lo que al resultado se le hace un corrimiento y se incrementa el exponente, quedando como resultado normalizado:
SIGNO 0 EXPONENTE 1000 0100 MANTISA 00000001100000000000000
Agrupando los bits del resultado en conjuntos de 4 bits: 0100 0010 0000 0000 1100 0000 0000 0000 Que equivale en hexadecimal: 4 2 0 0 C 0 0 0 El resultado de la suma en punto flotante es: 1.0000000112 x 2132, que al regresarlo a notacin de nmero real, se obtiene: 1.0000000112 x 25 = 100000.00112 x 20 = 32.187510, el cual es el resultado de la suma. 9.75 + 22.4375 = 32.1875 Utilizando otro testbench en el que se agruparon el bit de signo, exponente y mantisa en un vector de 32 bits, se obtiene la forma de onda mostrada en la figura 4, en la cual se puede apreciar el valor del resultado en hexadecimal obtenido anteriormente (4200C000h)
CONCLUSIONES El diseo se facilit al haber definido claramente los pasos a seguir, programando as un bloque o grupo de bloques que se encargaran de las funciones necesarias en cada paso. Esta implementacin se realiz tambin tomando en cuenta la caracterstica de flexibilidad en lo que se refiere al nmero de bits utilizados para mantisa y exponente, en otras palabras, para usar otro tipo de precisin. El enfoque utilizado fue seleccionado a conveniencia y facilidad segn el circuito diseado, tomando como recurso final el enfoque estructural, y definiendo cada bloque utilizado de ambas maneras, estructural y comportamental. REFERENCIAS
(1)
B. Parhami: Computer Arithmetic: Algorithms and Hardware Design, Ed. Oxford. (Diapositivas: http://www.fdi.ucm.es/profesor/mozos/AEC/aritm_pf.PDF)
Archivo: LE.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity LE is port( -- DECLARACION DE PUERTOS S : in STD_LOGIC_VECTOR(2 downto 0); ai : in STD_LOGIC; bi : in STD_LOGIC; Xi : out STD_LOGIC );
end LE;
architecture LE_arq of LE is begin -- BLOQUE LE (LOGIC EXTENDER) PARA ALU Xi <= ai when (S = "000") else (ai and bi) when (S = "001") else (ai or bi) when (S = "010") else not(ai) when (S = "011") else ai; end LE_arq;
Archivo: CE.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity CE is port( -- DECLARACION DE PUERTOS S : in STD_LOGIC_VECTOR(2 downto 0); C0 : out STD_LOGIC );
end CE;
architecture CE_arq of CE is begin C0 <= '1' when (S = "101" or S = "110") else '0'; -- BLOQUE DE ACARREO DE ENTRADA PARA ALU end CE_arq;
Archivo: FA.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity FA is port( -- DECLARACION DE PUERTOS Xi : in STD_LOGIC; Yi : in STD_LOGIC; Ci : in STD_LOGIC; Co : out STD_LOGIC; Sum : out STD_LOGIC );
end FA;
architecture FA_arq of FA is begin -- BLOQUE FA (FULL ADDER) PARA ALU Sum <= Xi xor Yi xor Ci; Co <= (Xi and Yi) or (Ci and (Xi xor Yi)); end FA_arq;
Archivo: ALU1BIT.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity ALU1BIT is port( -- DECLARACION DE PUERTOS S : in STD_LOGIC_VECTOR(2 downto 0); ai : in STD_LOGIC; bi : in STD_LOGIC; ci : in STD_LOGIC; co : out STD_LOGIC; f : out STD_LOGIC ); end ALU1BIT; architecture ALU1BIT_arq of ALU1BIT is -- SEALES INTERMEDIAS signal xi, yi: std_logic; begin -- BLOQUE DE 1 BIT PARA LA ALU LE01: entity work.LE (LE_arq) port map (S, ai, bi, xi); AE01: entity work.AE (AE_arq) port map (S, bi, yi); FA01: entity work.FA (FA_arq) port map (xi, yi, ci, co, f); end ALU1BIT_arq;
Archivo: ALU.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity ALU is generic( LONGITUD: positive := 8 -- AQUI SE DEFINE LA CANTIDAD DE BITS DE LA ALU ); port( -- DECLARACION DE PUERTOS S : in STD_LOGIC_VECTOR(2 downto 0); A : in STD_LOGIC_VECTOR(LONGITUD-1 downto 0); B : in STD_LOGIC_VECTOR(LONGITUD-1 downto 0); OvF : out STD_LOGIC; F : out STD_LOGIC_VECTOR(LONGITUD-1 downto 0) ); end ALU; architecture ALU_arq of ALU is -- SEALES INTERMEDIAS signal C: std_logic_vector(LONGITUD downto 0); begin -- BLOQUE DE ACARREO DE ENTRADA (CE) CE01: entity work.CE (CE_arq) port map (S, C(0)); BLOQUE_GEN: for I in 0 to LONGITUD-1 generate -- GENERA LOS BLOQUES DE LA ALU POR CADA BIT ALU1: entity work.ALU1BIT (ALU1BIT_arq) port map (S, A(I),B(I),C(I),C(I+1),F(I)); end generate BLOQUE_GEN; -- SEAL DE OVERFLOW OvF <= C(LONGITUD); end ALU_arq;
Archivo: MUX.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity MUX is generic( LONGITUD: positive := 8 -- CANTIDAD DE BITS DEL MUX 2 A 1 ); port( -- DECLARACION DE PUERTOS s : in STD_LOGIC; A : in STD_LOGIC_VECTOR(LONGITUD-1 downto 0); B : in STD_LOGIC_VECTOR(LONGITUD-1 downto 0); Y : out STD_LOGIC_VECTOR(LONGITUD-1 downto 0) ); end MUX; architecture MUX_arq of MUX is begin Y <= A when (s = '0') else -- MULTIPLEXOR 2 A 1 B when (s = '1'); end MUX_arq;
Archivo: RSHIFT.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIAS UTILIZADAS use IEEE.STD_LOGIC_UNSIGNED.all; use ieee.std_logic_arith.all; entity RSHIFT is generic( BITS: integer := 8 -- CANTIDAD DE BITS DEL DATO ); port( -- DECLARACION DE PUERTOS entrada : in STD_LOGIC_VECTOR(BITS-1 downto 0); shift: in STD_LOGIC_VECTOR(BITS-1 downto 0); -- CANTIDAD DE CORRIMIENTOS b0: in STD_LOGIC; salida : out STD_LOGIC_VECTOR(BITS-1 downto 0) ); end RSHIFT; architecture RSHIFT_arq of RSHIFT is signal temp,temp2: STD_LOGIC_VECTOR(BITS-1 downto 0); signal int: integer range 0 to 255; begin -- AGREGA UNA SERIE DE ...000b0 temp <= (entrada and (not(entrada))) + b0; -- CONVIERTE A ENTERO EL DATO DE ENTRADA PARA EL CORRIMIENTO int <= (conv_integer(shift)); -- CONCATENA LOS DATOS PARA HACER UN CORRIMIENTO -- Y REVISA SI HAY UNDERFLOW PARA HACER UN REDONDEO temp2 <= temp(int-1 downto 0) & entrada(BITS-1 downto int) when (int > 1 and int<BITS) else temp(BITS-1 downto 0); -- ASIGNA EL VALOR DE LA SALIDA -- SI SE HACE SOLO 1 CORRIMIENTO, SE CONCATENA EL BIT DE ENTRADA EN LA PARTE ALTA -- SI SE HACEN 0 CORRIMIENTOS, LA SALIDA ES IGUAL A LA ENTRADA salida <= temp2 when (int > 1) else b0&entrada(BITS-1 downto 1) when (int = 1) else entrada when (int = 0); end RSHIFT_arq;;
Archivo: RESTAEXP.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity RESTAEXP is generic( LONG: integer := 8 -- CANTIDAD DE BITS DEL DATO ); port( -- DECLARACION DE PUERTOS A : in STD_LOGIC_VECTOR(LONG-1 downto 0); B : in STD_LOGIC_VECTOR(LONG-1 downto 0); C : out STD_LOGIC_VECTOR(LONG-1 downto 0); SEL1: out STD_LOGIC ); end RESTAEXP; architecture RESTAEXP_arq of RESTAEXP is signal ov1, ov2: std_logic; signal f1,f2: std_logic_vector(LONG-1 downto 0); begin -- RESTA USANDO ALU. S = 101 -- SE HACE LA RESTA A-B Y B-A, Y SELECCIONA EL VALOR ABSOLUTO DE LA DIFERENCIA SUB1: entity work.ALU (ALU_arq) port map ("101",A,B,ov1,f1); SUB2: entity work.ALU (ALU_arq) port map ("101",B,A,ov2,f2); C <= f1 when (ov1 = '1') else f2 when (ov2 = '1'); SEL1 <= ov1; end RESTAEXP_arq;
Archivo: PASO1.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity PASO1 is generic( BFRA: positive := 23 -- BITS DE LA FRACCION ); port( -- DECLARACION DE PUERTOS mant1a : in STD_LOGIC_VECTOR(BFRA-1 downto 0); mant2a : in STD_LOGIC_VECTOR(BFRA-1 downto 0); exp1a : in STD_LOGIC_VECTOR(7 downto 0); exp2a : in STD_LOGIC_VECTOR(7 downto 0); expo : out STD_LOGIC_VECTOR(7 downto 0); mantisa : out STD_LOGIC_VECTOR(BFRA-1 downto 0) ); end PASO1; architecture PASO1_arq of PASO1 is -- SEALES INTERMEDIAS signal diferencia,expaa,expb0,expa0,expa1: std_logic_vector(7 downto 0); signal mantaa,mantb0,manta0,mants,diferencib,shf2: std_logic_vector(BFRA-1 downto 0); signal sel1,ov1,ov2,ov3,ov4,ov5,ov6,na,nb: std_logic; signal na1, nb1, nc1, shf1,ov2a,ov3a,ov4a,b0: std_logic_vector(7 downto 0); begin
-- PASO 1: -- RESTA DE EXPONENTES RE01: entity work.RESTAEXP (RESTAEXP_arq) port map (exp1a, exp2a, diferencia, sel1); -- SELECCION DEL MENOR EXPONENTE, LO GUARDA EN expaa. AL EXPONENTE MAYOR LO GUARDA EN expb0 -- A LA MANTISA DE MENOR EXPONENTE LA GUARDA EN mantaa, LA MAYOR EN mantb0 SE01: entity work.MUX (MUX_arq) generic map (LONGITUD => 8) port map (sel1,exp1a,exp2a,expaa); SE02: entity work.MUX (MUX_arq) generic map (LONGITUD => 8) port map (sel1,exp2a,exp1a,expb0); SE03: entity work.MUX (MUX_arq) generic map (LONGITUD => BFRA) port map (sel1,mant1a,mant2a,mantaa); SE04: entity work.MUX (MUX_arq) generic map (LONGITUD => BFRA) port map (sel1,mant2a,mant1a,mantb0); -- SUMA. MENOR EXPONENTE + DIFERENCIA Y LO GUARDA EN expa0. (S = 100) AD01: entity work.ALU (ALU_arq) port map ("100",expaa,diferencia,ov1,expa0); -- REALIZA CORRIMIENTO AL NUMERO CON MENOR EXPONENTE Y LO GUARDA EN manta0 diferencib <= "000000000000000"&diferencia; SH01: entity work.RSHIFT (RSHIFT_arq) generic map (BITS => BFRA) port map (mantaa,diferencib,'1',manta0); -- LO SIGUIENTE SE UTILIZARA AL NORMALIZAR LA SUMA DE MANTISAS na <= '1'; nb <= '1' when (diferencia = "00000000") else '0'; na1 <= "0000000"&na; nb1 <= "0000000"&nb; -- PASO 2: -- SUMA LAS MANTISAS NORMALIZADAS CON EL MISMO EXPONENTE Y GUARDA EN mants. (S = 100) AD02: entity work.ALU (ALU_arq) generic map (LONGITUD => BFRA) port map ("100",manta0,mantb0,ov2,mants); ov2a <= "0000000"&ov2; -- PASO 3: -- SUMA LAS N PARA HACER LA NORMALIZACION DE LA SUMA AD03: entity work.ALU (ALU_arq) port map ("100",na1,nb1,ov3,nc1); AD04: entity work.ALU (ALU_arq) port map ("100",nc1,ov2a,ov4,b0); ov3a <= "0000000"&nc1(1); ov4a <= "0000000"&b0(1); AD05: entity work.ALU (ALU_arq) port map ("100",ov3a,ov4a,ov5,shf1); -- CORRIMIENTO PARA NORMALIZAR (EL PASO 4 SE HACE DENTRO DEL CORRIMIENTO) shf2 <= "000000000000000"&shf1; SH02: entity work.RSHIFT (RSHIFT_arq) generic map (BITS => BFRA) port map (mants,shf2,b0(0),mantisa); -- AJUSTA EL NUEVO EXPONENTE AD06: entity work.ALU (ALU_arq) port map ("100",expa0,"00000001",ov6,expa1); expo <= expa1 when (shf1 = "00000001") else expa0; end PASO1_arq;;
Archivo: Testbench.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity Testbench is port( -- DECLARACION DE PUERTOS exponente : out STD_LOGIC_VECTOR(7 downto 0); mantisa : out STD_LOGIC_VECTOR(22 downto 0) ); end Testbench; architecture Testbench_arq of Testbench is signal a, b: std_logic_vector(31 downto 0); begin -- DEFINICION DE LOS SUMANDOS EN NOTACION DE PUNTO FLOTANTE -- PRECISION SENCILLA (1 BIT SIGNO, 8 BITS EXPONENTE, 23 BITS MANTISA) a <= '0'&"01111101"&"00000000000000000000000"; b <= '0'&"10000101"&"10010000000000000000000"; -- INSTANCIA DEL SUMADOR DE NUMEROS DE PUNTO FLOTANTE SUMA: entity work.PASO1 (PASO1_arq) port map (a(22 downto 0),b(22 downto 0),a(30 downto 23), b(30 downto 23), exponente, mantisa); end Testbench_arq;
Archivo: Testbench2.vhd
library IEEE; use IEEE.STD_LOGIC_1164.all; -- LIBRERIA UTILIZADA entity Testbench is port( -- DECLARACION DE PUERTOS resultado : out STD_LOGIC_VECTOR(31 downto 0) ); end Testbench; architecture Testbench_arq of Testbench is signal a, b: std_logic_vector(31 downto 0); signal exponente: std_logic_vector(7 downto 0); signal mantisa: std_logic_vector(22 downto 0); begin -- DEFINICION DE LOS SUMANDOS EN NOTACION DE PUNTO FLOTANTE -- PRECISION SENCILLA (1 BIT SIGNO, 8 BITS EXPONENTE, 23 BITS MANTISA) a <= '0'&"10000010"&"00111000000000000000000"; b <= '0'&" 10000011"&"01100111000000000000000"; -- INSTANCIA DEL SUMADOR DE NUMEROS DE PUNTO FLOTANTE SUMA: entity work.PASO1 (PASO1_arq) port map (a(22 downto 0),b(22 downto 0),a(30 downto 23), b(30 downto 23), exponente, mantisa); resultado <= '0'&exponente&mantisa; end Testbench_arq;