2

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;
name
  • 5,095
  • 5
  • 27
  • 36

3 Answers3

5

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;
Philippe
  • 3,700
  • 1
  • 21
  • 34
2

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.

caveman
  • 1,755
  • 1
  • 14
  • 19
  • Hi, thx for point it out. The others in case statement provide that the res signal is written in every branch. This helps to synthesis tool to prevent from creating the latches. – name Nov 13 '10 at 23:25
2

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.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Thx for the answer. I agree that this is more generic approach which makes it better. The problem is that sel in my case has to be 32 bits wide and I believe that "shift_count := to_integer(sel)" will not work in that case. As you stated the tricky part of this design is to use clever decoders - it's not wise to do 32:1. Do you think that sticking with your design and using sel(5 downto 0) is a good idea? Another thing is if it's good for a performance reasons to have an async rst? Thx. – name Nov 13 '10 at 23:23
  • 1
    This is for an FPGA, right? An FPGA's logic elements have dedicated asynchronous reset inputs to every D flip-flop, so it's not going to cost anything in terms of either performance or LE usage (it may report more *gates* used, but those gates can't be used for any other function). Having a wider `sel` bus shouldn't hurt anything, because the `I + shift_count < 32` test will automatically handle any value of `shift_count` correctly. – Ben Voigt Nov 14 '10 at 06:20
  • "IF I + shift_count < 32 THEN" this is clever! – name Nov 15 '10 at 12:34