Search code examples
logicconcatenationvhdl

VHDL - custom shifter - concatenation input (in defined range) and remaining zeros


I am trying to write my own shifter. It all doesn't matter about the shifter, so please don't recommend me to do shifter by different way. The shifter is here only for demonstration my problem that I've reached.

Here is a piece of shifter description:

 1:   with operand_b select result <=
 2:   operand_a when "0000",
 3:   operand_a(14 downto 0) & '0' when "0001",
 4:   operand_a(13 downto 0) & "00" when "0010",
 5:   operand_a(12 downto 0) & "000" when "0011",
 6:   operand_a(11 downto 0) & "0000" when "0100",
 7:   operand_a(10 downto 0) & "00000" when "0101",
 8:   operand_a(9 downto 0) & "000000" when "0110",
 9:   operand_a(8 downto 0) & "0000000" when "0111",
10:   operand_a(7 downto 0) & "00000000" when "1000",
11:   operand_a(6 downto 0) & "000000000" when "1001",
12:   operand_a(5 downto 0) & "0000000000" when "1010",
13:   operand_a(4 downto 0) & "00000000000" when "1011",
14:   operand_a(3 downto 0) & "000000000000" when "1100",
15:   operand_a(2 downto 0) & "0000000000000" when "1101",
16:   operand_a(1 downto 0) & "00000000000000" when "1110",
17:   operand_a(0) & "000000000000000" when others;

Where operand_b is value used to be shifted by, result is output of the shifter.

As you can see, it is quite bottlenecking. What will happen when we have for instance 64 bit shifter - a lot of useless zeros. I was finding a lot on web how to write that more rationally, but every solution that I tried, like operand_a(13 downto 0) & (others => '0') when "0010" or (15 downto 2 => operand_a(13 downto 0), others => '0') when "0010" or (operand_a(13 downto 0), others => '0') when "0010" doesn't work. Everytime I got a report with some error.

Any solutions, please?

Sorry for my English.


EDIT:

When I replace operand_a(13 downto 0) & "00" when "0010", on the 4th line with:

  • operand_a(13 downto 0) & (others => '0') when "0010", it returns

Can not determine the "others" values in aggregate. (<= also for line 17) Size of concat operation is different than size of the target.

  • (15 downto 2 => operand_a(13 downto 0), others => '0') when "0010", it returns

The type of the element in aggregate does not correspond to any array type.

  • (operand_a(13 downto 0), others => '0') when "0010", it returns

No array or record type can be found that has elements of types matching the aggregate.

  • operand_a(13 downto 0) & (1 downto 0 => '0') when "0010",

This one is working, but isn't here any way to use others?


Solution

  • Value expressions such as (operand_a(13 downto 0), others => '0') should work in IEEE Std 1076-2008.

    Compare 9.3.3.3 Array aggregates, para 1 and 2:

    For an aggregate of a one-dimensional array type, each choice shall specify values of the index type, and the expression of each element association shall be of either the element type or the type of the aggregate. If the type of the expression of an element association is the type of the aggregate, then either the element association shall be positional or the choice shall be a discrete range.

    For an element association with a choice that is a discrete range and an expression of the element type of the aggregate, the value of the expression is the element at each index value in the range.

    to IEEE Std 1076-1993 Array aggregates para 1:

    For an aggregate of a one-dimensional array type, each choice must specify values of the index type, and the expression of each element association must be of the element type. An aggregate of an n-dimensional array type, where n is greater than 1, is written as a one-dimensional aggregate in which the index subtype of the aggregate is given by the first index position of the array type, and the expression specified for each element association is an (n-1)-dimensional array or array aggregate, which is called a subaggregate. A string or bit string literal is allowed as a subaggregate in the place of any aggregate of a one-dimensional array of a character type.

    In -2008 we are allowed to have association elements that are the type of the aggregate (a one-dimensional array type). This allows association of slice names of the same type.

    At the same time -2008 9.3.3.3 para 7 allows the use of the others choice:

    e) As a value expression in an assignment statement, where the target is a declared object (or member thereof), and either the subtype of the target is a fully constrained array subtype or the target is a slice name

    (And the target being a slice name has been added from previous revisions.) The rules for where you can use the others choice require you have context that supplies a subtype constraint.

    So it tells us the VHDL implementation you are using is not -2008 compatible (or is not being used as -2008 compatible).

    This feature is one of generally low priority for implementation in upgrading to -2008 compatibility.

    Should you find your VHDL tool lacking support there are other ways to express your shifter such as:

    SHIFTER:
        process (operand_b, operand_a)
            variable b: integer range 0 to operand_a'HIGH;
        begin
            result <= (others => '0');
            if not is_x(operand_b) then  -- culling meta-values
                b := to_integer(unsigned(operand_b));
                    for i in result'range loop
                        if i = b then
                            result(result'high downto i) <= 
                                    operand_a (operand_a'high - i downto 0);
                        end if;
                    end loop;
            end if;
        end process;
    

    This process is synthesis eligible, because the slice ranges depend on static values including the loop constant, loops are unrolled or parallelized for synthesis. There is an assignment statement for each binary value of operand_b and you rely on optimization in synthesis (which does amazingly well for things like multiplexers and shifters).

    This method works by writing all of result as '0's then writing the portions of operand_a desired to result. It depends on sequential assignment inside the same process (and can be used with a sequential conditional signal assignment in a -2008 compatible implementation) and with if statement or a case statement. (But not a selected signal assignment which depends on same left hand side target).

    The two assignment statements being executed in one process depends on there being a single driver and is supported by synthesis. The last written array element values overwrite earlier array element value writes, there is only one time slot for any particular simulation time in a projected output waveform.