Search code examples
vhdlprocedure

Procedure in VHDL never returns the value


I have a procedure which is never return the value.

procedure gen_start_impulse (
    signal rising_signal        : out std_logic;                             
    signal carier_clk           : in std_logic;
    constant duration           : in integer)    is                         
variable clk_counter    : integer := 0;
begin 
    if (rising_edge(carier_clk)) then
        if (clk_counter = duration) then
            rising_signal <= '0';
            clk_counter := 0;
        else
            rising_signal <= '1';
            clk_counter := clk_counter + 1;
        end if;
    end if;
end gen_start_impulse;

I am call it here

process (start)
begin
    if (start = '1') then
        gen_start_impulse(start_impulse, clk, 1);           
    end if;
end process;

In testbench start_impulse is uninitialized.

Result of testbench

I don`t understand why in the waveform start_impulse is uninitialized.


Solution

  • Welcome on Stackoverflow. Your question is interesting but it does not really contain enough information to receive a complete answer (a quick look at the help center and especially at the How to create a Minimal, Complete, and Verifiable example section could probably be help you improving it, if you wish).

    Anyway, let's try to guess. Your process resumes each time start changes and, thanks to your if statement, it calls your gen_start_impulse procedure only if the new value of start is '1'. So, just to clarify things, we could probably flatten your model and rewrite your process like this:

    process (start)
        variable clk_counter: integer := 0;
        constant duration: integer := 1;
    begin
        if (start = '1') then
            if (rising_edge(clk)) then
                if (clk_counter = duration) then
                    start_impulse <= '0';
                    clk_counter := 0;
                else
                    start_impulse <= '1';
                    clk_counter := clk_counter + 1;
                end if;
            end if;
        end if;
    end process;
    

    Important note: this is not strictly equivalent to your initial code because in your code the clk_counter variable is re-initialized each time your gen_start_impulse procedure is called while here it keeps its previous value.

    Now, what do you think will happen if start is synchronous? That is, if it changes always just after a rising edge of clk? Simple: the condition of the:

    if (rising_edge(clk)) then
    

    statement is always false and your signal assignments to start_impulse are never executed. This is because start and clk never change simultaneously. There is always at least one simulation step (a "delta-cycle") between them.

    If you design a synchronous system wait or check for rising edges of your clock and then test the other signals, not the opposite. Example:

    procedure gen_start_impulse (
        signal rising_signal        : out std_logic;                             
        signal starter              : in std_logic;
        constant duration           : in integer)    is                         
        variable clk_counter    : integer := 0;
    begin 
        if (starter = '1') then
            if (clk_counter = duration) then
                rising_signal <= '0';
                clk_counter := 0;
            else
                rising_signal <= '1';
                clk_counter := clk_counter + 1;
            end if;
        end if;
    end gen_start_impulse;
    ...
    process (clk)
    begin
        if (rising_edge(clk)) then
            gen_start_impulse(start_impulse, start, 1);           
        end if;
    end process;
    

    Important note: because of the clk_counter variable is re-initialized each time gen_start_impulse procedure is called (see previous note), this will not work as you expect. If you want this to work you will need to rework it a bit, either by completely removing the procedure (why do you need it, by the way?) and using only one synchronous process, or by adding a fourth inout parameter to your procedure for the clk_counter variable ans declaring it as a process variable.