Search code examples
vhdlfpgacircuithdl

Universal shift arithmetic right in VHDL


I am designing universal shift arithmetic operator. Is there a better way to achieve it besides using the 32bit multiplexer (decoder) in a way presented bellow?

ENTITY isra IS 
PORT (
  clk:    in std_logic;
  rst:    in std_logic;
  di:     in std_logic_vector (31 downto 0);
  sel:    in std_logic_vector (31  downto 0);
  res:    out std_logic_vector (31 downto 0) := (others => '0')
);
END isra;


PROCESS
  BEGIN
    WAIT UNTIL clk'EVENT AND clk = '1';
    IF rst = '1' THEN
      res <= (others => '0');
    ELSE
    CASE sel IS
        when X"00000001"  => res <= to_stdlogicvector(to_bitvector(a) sra 1);
        when X"00000002"  => res <= to_stdlogicvector(to_bitvector(a) sra 2);
        ...
        when X"0000001F"  => res <= to_stdlogicvector(to_bitvector(a) sra 31);
        when others => res <= (others => '0');
    END CASE;
END IF;
END PROCESS;

Solution

  • Use indexing?

    PROCESS
      VARIABLE shift_count : INTEGER RANGE 0 TO 31;
    BEGIN
      IF rst = '1' THEN
        res <= (others => '0');
      ELSIF RISING_EDGE(clk) THEN
        shift_count := to_integer(sel);
        FOR I IN 0 TO 31 LOOP
          IF I + shift_count < 32 THEN
            res(I) <= din(I + shift_count);
          ELSE
            res(I) <= din(31); -- for logical shift right, use '0' instead
          END IF;
        END LOOP;
      END IF;
    END PROCESS;
    

    This version is much easier to parameterize into a generic.

    Remember that VHDl is a behavioral description, it doesn't specify a mux. The compiler can generate different designs depending on whether you optimize for size, speed, allow pipelining, etc.

    Note that 5 2:1 muxes can implement this in a far smaller area than a single 32:1 mux. If this isn't the block that limits your clock rate, that might be preferable.

    Also note that your sel input is far too wide, it only needs to be 5 bits.