Search code examples
vhdlfpga

How to shift std_logic_vector?


I want shift std_logic_vector.

But this code is has an error:

architecture led_main of testing is
    signal clk_cnt : std_logic_vector(64 DOWNTO 0) := (others => '0');
    signal led_buf : std_logic_vector( 3 downto 0 ) := "0001";
begin
    process(clk)
    begin
        if rising_edge(clk) then
            clk_cnt <= clk_cnt + 1;
            if clk_cnt >= 24999999 then
                led_buf <= led_buf(0) & led_buf(3 downto 1);
            end if;
        end if;
    end process;

    ground <= '0';
end led_main;

I think "0001", "0010", "0100" ...


Solution

  • Your shifter is OK. Actually, it's a rotator.

    But your counter is to big (65 bits) and it doesn't roll over or reset to zero in a proper time. Your current design waits for 25M cycles and then shifts in every cycle from 25M to 2**64.

    More over, you are using a non standard IEEE package to perform arithmetic operations (addition) on std_logic_vector. Please use type unsigned from package numeric_std.

    The needed number of bits for your counter can be obtained by a log2 function like this:

    function log2ceil(arg : positive) return natural is
        variable tmp : positive;
        variable log : natural;
    begin
        if arg = 1 then return 0; end if;
        tmp := 1;
        log := 0;
        while arg > tmp loop
            tmp := tmp * 2;
            log := log + 1;
        end loop;
        return log;
    end function;
    

    Source: https://github.com/VLSI-EDA/PoC/blob/master/src/common/utils.vhdl

    Full code rewrite:

    use IEEE.numeric_std.all;
    
    architecture led_main of testing is
        constant CNT_MAX : positive := 25000000;
        signal clk_cnt : unsigned(log2ceil(CNT_MAX) - 1 downto 0) := (others => '0');
        signal led_buf : std_logic_vector( 3 downto 0 )           := "0001";
    begin
        process(clk)
        begin
            if rising_edge(clk) then
                clk_cnt <= clk_cnt + 1;
                if clk_cnt = (CNT_MAX - 1) then
                    clk_cnt <= (others => '0');
                    led_buf <= led_buf(0) & led_buf(3 downto 1);
                end if;
            end if;
        end process;
    end led_main;
    

    ```