Search code examples
vhdlbit-shift

Designing a Combinational Shift Operator in VHDL


Here is my problem: I need to design a 16 bit left/right logical/arithmetic shift component using combinational logic from scratch (except using std_logic_vector and std_logic).

Here is what I have:

library ieee;
use ieee.std_logic_1164.all;

entity Shift16 is
    port
    (
        -- Input ports
        I       : in std_logic_vector(15 downto 0);
        Shift   : in std_logic_vector(3 downto 0);

        -- Sel(1) == 0 -> Logical ; Sel(0) == Left
        Sel : in std_logic_vector(1 downto 0);

        -- Output ports
        O       : out std_logic_vector(15 downto 0)
    );
end Shift16;

architecture Struct of Shift16 is
component Mux16to1 is
    port (I :   in std_logic_vector(15 downto 0);
            S   :   in std_logic_vector(3 downto 0);
            O   :   out std_logic);
end component;

component Mux2to1_16 is
    port
    ( A, B : in  std_logic_vector(15 downto 0); S : in  std_logic;
      Q : out std_logic_vector(15 downto 0) );
end component;

signal OLeft, ORight : std_logic_vector(15 downto 0);

signal PadVal   : std_logic;

type gen_signal is array (15 downto 0) of std_logic_vector(15 downto 0);

signal leftPad, rightPad : gen_signal;

begin

    process (I, Sel)
    begin
        if (Sel(0) = '0') then -- logical
            PadVal <= '0';
        else 
            PadVal <= I(15); -- aritmetic
        end if;

        for j in 15 downto 0 loop
            for k in j downto 0 loop
                leftPad(j, k) <= I(15-j);
                rightPad(j, k) <= PadVal;
            end loop;

            for k in 15 downto j+1 loop 
                leftPad(j, k) <= PadVal;
                rightPad(j, k) <= I(15-j);
            end loop;
        end loop;
    end process;



    muxarr_left_shift: for index in 15 downto 0 generate
    begin  
        mux: Mux16to1 port map (leftPad(index), Shift, OLeft(index));
    end generate;

    muxarr_right_shift: for index in 15 downto 0 generate
    begin
        mux: Mux16to1 port map (rightPad(index), Shift, ORight(index));
    end generate;   

    OutputMux: Mux2to1_16 port map (ORight, OLeft, Sel(1), O);

end Struct;

The Mux components are exactly what they seem like, just my custom version.

My original idea was to use 16 16-to-1 Muxs and wire them up so the shift amount is the select on each one. This would be very fast, but for some reason the code does not compile.

I think I also over complicated this and I am not sure what I can do to do better..

The compiling error is: Error (10382): VHDL error at Shl16.vhd(52): index of object of array type gen_signal must have 1 dimensions


Solution

  • I think you should change:

        for j in 15 downto 0 loop
            for k in j downto 0 loop
                leftPad(j, k) <= I(15-j);
                rightPad(j, k) <= PadVal;
            end loop;
    
            for k in 15 downto j+1 loop 
                leftPad(j, k) <= PadVal;
                rightPad(j, k) <= I(15-j);
            end loop;
        end loop;
    

    to

        for j in 15 downto 0 loop
            for k in j downto 0 loop
                leftPad(j)(k) <= I(15-j);
                rightPad(j)(k) <= PadVal;
            end loop;
    
            for k in 15 downto j+1 loop
                leftPad(j)(k) <= PadVal;
                rightPad(j)(k) <= I(15-j);
            end loop;
        end loop;
    

    because your type declaration.

    type gen_signal is array (15 downto 0) of std_logic_vector(15 downto 0);
    

    P/s: If you wanna keep assignment in loop, please change type to :

    type gen_signal is array (15 downto 0, 15 downto 0) of std_logic;
    

    But i don't think it's suitable for your portmap. So,you should use above method. I checked first method with Questasim 10.0b.

    P/S (again): I read carefully your code and found:

    process (I, Sel)
    

    Sensitive list may not suitable for loop except you wanna latch. I think you should split to 2 process.