VHDL de desplazamiento lineal combinacional

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?

Respuestas (1)

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.