Deep Blue
Deep Blue

Reputation: 303

Why won't VHDL left shifter work?

I'm new to VHDL and I'm trying to write a left shifter that takes in a 32 bit value and a 5 bit value. The left shifter then tries to perform a logical left shift of the 32 bit value by moving out the number of bits specified by the 5 bit number on the left and bringing that many zeros on the right. I can't understand why the array notation isn't working. The result of 1 << 1 produces 20000000 instead of 00000002. Can someone explain where I'm going wrong? Here's the code:

SIGNAL lshiftOutput : STD_LOGIC_VECTOR( 31 downto 0 );

COMPONENT Lshift32
    Port( a : in STD_LOGIC_VECTOR( 31 downto 0 );
          b : in STD_LOGIC_VECTOR( 4 downto 0 );
          lshiftOutput : out STD_LOGIC_VECTOR( 31 downto 0 ) );
END COMPONENT;

PROCESS(  a, b, opcode, adderOutput, subtractOutput, xorOutput, lshiftOutput, rshiftOutput )
BEGIN
    IF opcode = "0000" THEN
        result <= x"00000000";
    ELSIF opcode = "0001" THEN
        result <= adderOutput; 
    ELSIF opcode = "0010" THEN
        result <= subtractOutput; 
    ELSIF opcode = "0011" THEN
        result <= NOT a; 
    ELSIF opcode = "0100" THEN
        result <= a AND b; 
    ELSIF opcode = "0101" THEN
        result <= a OR b; 
    ELSIF opcode = "0110" THEN
        result <= xorOutput; 
    ELSIF opcode = "0111" THEN
        result <= lshiftOutput; 
    ELSIF opcode = "1000" THEN
        result <= rshiftOutput; 
    END IF;
END PROCESS;

LIBRARY ieee;
USE ieee.std_logic_unsigned.ALL;
USE ieee.std_logic_1164.ALL;
USE ieee.numeric_std.ALL;


ENTITY Lshift32 IS
    Port( a : in STD_LOGIC_VECTOR ( 31 downto 0 );
          b : in STD_LOGIC_VECTOR ( 4 downto 0 );
          lshiftOutput : out STD_LOGIC_VECTOR ( 31 downto 0 ) );
END Lshift32;

ARCHITECTURE Lshift32Architecture of Lshift32 IS
BEGIN
    PROCESS( a, b )
    VARIABLE shiftAmount : INTEGER := 0;
    BEGIN
        shiftAmount := to_integer( b(4 downto 0) );
        -- Shift left
        lshiftOutput <= a( 31-shiftAmount downto 0 ) & ( shiftAmount-1 downto 0 => '0' ); 
    END PROCESS;
END Lshift32Architecture;

The test bench for this is:

-- Shift Left -------------------------------------------------------
WAIT FOR 9 ns;
op <= "0111";
-- 1 << 1
input_a <= x"00000001";
input_b <= x"00000001";
WAIT FOR 1 ns;
IF (output /= x"00000002") THEN
    ASSERT false REPORT "1 << 1 has incorrect result" severity error;
END IF;

Upvotes: 0

Views: 234

Answers (1)

user1155120
user1155120

Reputation:

Brian asked that you supply a Minimal, Complete, and Verifiable example, your edited code doesn't do that. And the reason for asking is that it's possible to create an mcve around the portions of your code you originally supplied that does give the right answer:

library ieee;  -- added
use ieee.std_logic_1164.all;  -- added
use ieee.numeric_std_unsigned.all; -- added

entity lshift32 is
    port( a : in std_logic_vector ( 31 downto 0 );
          b : in std_logic_vector ( 4 downto 0 );
          lshiftoutput : out std_logic_vector ( 31 downto 0 ) );
end entity lshift32;

architecture lshift32architecture of lshift32 is
begin
    process( a, b )
    variable shiftamount : integer := 0;
    begin
        shiftamount := to_integer( b(4 downto 0) );
        -- shift left

        lshiftoutput <= a( 31-shiftamount downto 0 ) & ( shiftamount-1 downto 0 => '0' ); 
    end process;
end architecture lshift32architecture;

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std_unsigned.all;

entity lshift32_tb is
end entity;

architecture foo of lshift32_tb is
    signal a:   std_logic_vector (31 downto 0) := (others => '0');
    signal b:   std_logic_vector (4 downto 0)  := (others => '0');
    signal lshiftoutput: std_logic_vector (31 downto 0);
begin

DUT:
    entity work.lshift32
        port map (
            a => a,
            b => b,
            lshiftoutput => lshiftoutput
        );

SIMULIS:
    process
    begin
        wait for 10 ns;
        a(0) <= '1';  -- 1
        b(0) <= '1';  -- 1
        wait for 10 ns;
        wait;
    end process;

ANALYSIS:
    process (lshiftoutput)
    variable shiftamount:   integer;
    begin  
        if now > 0 ns then
            shiftamount := to_integer(b);
            report "ShiftAmount = " & integer'image(shiftamount);
            report "lshiftOutput = " & to_string(lshiftoutput);
        end if;
    end process;
end architecture;

And running the above testbench gives:

ghdl -a --std=08 lshift.vhdl
ghdl -e --std=08 lshift32_tb
ghdl -r lshift32_tb
lshift.vhdl:60:13:@10ns:(report note): ShiftAmount = 1
lshift.vhdl:61:13:@10ns:(report note): lshiftOutput = 00000000000000000000000000000010

And that your execution fails says there's either something wrong with your context clause (use clauses) or something wrong with your testbench.

Note that you are using both none standard package std_logic_unsigned and IEEE standard package numeric_std. You really shouldn't mix and match there can be unexpected consequences.

The package numeric_std_unsigned is available with a VHDL implementation compliant with the IEEE Std 1076-2008 standard. If using a previous version of the VHDL standard you can use package numeric_std and type convert b to unsigned as the expression passed to to_integer.

For the testbench supplied with this answer you'd also find that to_stringfor std_logic_vector is not supplied. Without seeing your entire testbench it could well be functional.

If you want to prove the answer supplied testbench works in a non -2008 revision environment:

function to_string (inp: std_logic_vector) return string is
    variable image_str: string (1 to inp'length);
    alias input_str:  std_logic_vector (1 to inp'length) is inp;
begin
    for i in input_str'range loop
        image_str(i) := character'VALUE(std_ulogic'IMAGE(input_str(i)));
    end loop;
    return image_str;
end function;

The function can be supplied as an architecture declarative item.

Upvotes: 1

Related Questions