Question

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;
Was it helpful?

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.

OTHER TIPS

You can use the SRA function without any loops or case statements:

res <= to_stdlogicvector(to_bitvector(di) sra to_integer(sel));

Note that you need to make sel an unsigned, not a std_logic_vector:

sel: in unsigned (31  downto 0);

In case you don't want that, you can still cast sel into an unsigned. You also need to us numeric_bit:

use ieee.numeric_bit.all;

Well from a hardware point of view, to shift right in a single clock a variable number of positions, each bit is a single flip-flop with one of 32 possible values based on a selection. So from that point of view, this is how you do it.

I would make sel == 0 a case and make it a passthrough, though. Logically, that makes more sense than setting everything to zeros.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top