Estoy diseñando un sumador/multiplicador sintetizable y canalizado de coma flotante de 32 bits como parte de un grupo para una clase en la escuela. Me pusieron a cargo de la re-normalización. Parte de esto es desplazar hacia la izquierda o hacia la derecha un bus 48 que representa la salida de la mantisa. El código que tengo hasta ahora es este
library ieee;
use ieee.std_logic_1164.all;
USE ieee.numeric_std.ALL;
entity renormalizer is
PORT(
enableIN : in std_logic;
signIN : in std_logic;
exponentIN : in std_logic_vector(7 downto 0);
mantissaIN : in std_logic_vector(47 downto 0);
zOUT : out std_logic_vector(31 downto 0)
);
end renormalizer;
architecture behave of renormalizer IS
begin
process(enableIN,signIN,exponentIN,mantissaIN)
variable mantissaHEAD : std_logic_vector(1 downto 0);
variable exponentNORM : std_logic_vector(7 downto 0);
variable exponentONE : std_logic_vector(7 downto 0) := "00000001";
variable exponentNEGONE : std_logic_vector(7 downto 0) := "11111110";
variable exponentCARRY : std_logic_vector(7 downto 0);
begin
mantissaHEAD := mantissaIN(47 downto 46); --First bits of mantissa
case enableIN is
when '0' =>
--Pass things through
zOUT <= signIN & exponentIN & mantissaIN(45 downto 23);
when '1' =>
--Do the normalization
case mantissaHEAD is
--DONT KNOW HOW TO IMPLEMENT THIS
when "00" =>
zOUT <= (others => 'Z')
;
--NUMBER IS RENORMALIZED PASS IT THROUGH
when "01" =>
zOUT <= signIN & exponentIN & mantissaIN(45 downto 23)
;
--THESE BOTTOM TWO DO THE SAME THING
when "10" =>
--SUBTRACT ONE FROM THE EXPONENT AND OUTPUT SHIFTED MANTISSA
exponentNORM(0) := exponentIN(0) xor exponentNEGONE(0) xor '1';
exponentCARRY(0) := (exponentIN(0) and exponentNEGONE(0)) or ('1' and (exponentIN(0) xor exponentNEGONE(0)));
for i in 1 to 7 loop
exponentNORM(i) := exponentIN(i) xor exponentNEGONE(i) xor exponentCARRY(i-1);
exponentCARRY(i) := (exponentIN(i) and exponentNEGONE(i)) or (exponentCARRY(i-1) and (exponentIN(i) xor exponentNEGONE(i)));
end loop;
zOUT <= signIN & exponentNORM & mantissaIN(46 downto 24); --46 downto 24 instead of 45 downto 23
when "11" =>
exponentNORM(0) := exponentIN(0) xor exponentNEGONE(0) xor '1';
exponentCARRY(0) := (exponentIN(0) and exponentNEGONE(0)) or ('1' and (exponentIN(0) xor exponentNEGONE(0)));
for i in 1 to 7 loop
exponentNORM(i) := exponentIN(i) xor exponentNEGONE(i) xor exponentCARRY(i-1);
exponentCARRY(i) := (exponentIN(i) and exponentNEGONE(i)) or (exponentCARRY(i-1) and (exponentIN(i) xor exponentNEGONE(i)));
end loop;
zOUT <= signIN & exponentNORM & mantissaIN(46 downto 24);
when others => zOUT <= (others => 'Z');
end case;
when others => zOUT <= (others => 'Z');
end case;
end process;
end behave;
El código anterior verifica que la mantisa ingresada tenga la forma 01.xxxxxxxxx... (47 hasta 0) antes de establecerla en la salida. Si no es así, cambia la mantisa respectivamente y suma o resta al exponente de cada cambio. Para un cambio a la derecha, esto es trivial, pero para cambiar a la izquierda N veces, no sé cómo implementarlo de forma combinada como parte. de una etapa de tubería. Realmente estoy perdido, si lo estuviera haciendo de manera problemática, continuaría desplazándome hacia la izquierda y verificaría los dos primeros bits de la mantisa después de cada cambio, pero no creo que sea posible sintetizar esto. ¿Podría alguien darme un punto en la dirección correcta y alguna orientación para resolver este problema?
Realmente tiene tres piezas de lógica aquí, un codificador de prioridad que emite la posición del '1' más a la izquierda y una palanca de cambios y un sumador.
Parece un bucle for para el codificador de prioridad, podría hacerlo con sentencias if anidadas, pero un bucle for probablemente sea más limpio.
Idea completamente no probada:
std_logic_vector m (47 downto 0); -- mantissa
std_logic_vector z (47 downto 0) := (others => '0'); -- a load of zeros
integer s range -2 to 45 := 6; -- Or whatever your priority encoder logic gets you, this is the amount to shift
-- left shift, only good if shift > 0
m <= m(47-s downto 0) & z(s -1 downto 0);
También puede encontrar útil el hecho de que ieee.numeric_std tiene definidos los operadores shift_left y shift_right, o incluso el hecho de que sla,sra,sll,srl están definidos para std_logic_vector.
Personalmente, generalmente escribo turnos con concatenación, pero debe tener un poco de cuidado con las cantidades con signo al hacer esto si desea que la extensión del signo sea correcta, solo preferencia personal.