Search code examples
vhdlfpgamodelsim

Wait until <signal>=1 never true in VHDL simulation


Below is the code that I am running. My question is why doesn't the 3rd wait until trigger in modelsim? The console output is simply GOT HERE. It never gets to the line GOT HERE 2. I would think that having the same wait until <SIGNAL> = 1 twice in a row would be fine because the condition is true both times. I didn't add 'event in there, so I wouldn't think the simulator would need to see the edge. Can anyone explain this behavior?

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity example_wait_failure is
end example_wait_failure;

architecture behave of example_wait_failure is

  signal r_CLK_TB : std_logic := '0';

begin

  r_CLK_TB <= '1' after 20 ns, '0' after 40 ns, '1' after 60 ns;


  p_TEST : process
  begin

    wait until r_CLK_TB = '1';
    report "GOT HERE" severity note;

    wait until r_CLK_TB = '1';
    wait until r_CLK_TB = '1';
    report "GOT HERE 2 " severity note;

  end process p_TEST;

end behave;

Solution

  • The behaviour is in the details of the wait statement (the details of wait that Jim Lewis refers to). The reason is that the wait statements has three parts:

    wait
      [on sensitivity_list]
      [until condition]
      [for time_expression];  -- Only for timeout, and not relevant here
    

    The wait in the relevant code only has an until part, so the sensitivity_list is created according to VHDL standard: "If no sensitivity clause appears, the sensitivity set is constructed according to the following (recursive) rule: ...". The generated sensitivity_list will in this case contain r_CLK_TB.

    The VHDL standard has an example that matches the code precisely, and this states that:

    wait until r_CLK_TB = '1';
    

    is identical to:

    loop
      wait on r_CLK_TB;
      exit when r_CLK_TB = '1';
    end loop;
    

    So even though the wait does not explicitly contain a wait until r_CLK_TB'event (as written in comment), the execution results in waiting until an event on r_CLK_TB in order to pass the first wait in wait on r_CLK_TB. Is that intuitive... judge for yourself ;-)

    So maybe the original code should be changes so:

    wait until r_CLK_TB = '1';
    

    is replaced with:

    if r_CLK_TB /= '1' then
      wait until r_CLK_TB = '1';
    end if;
    

    In this case both "GOT HERE" and "GOT HERE 2" are shown at 20 ns, since the condition of all three constructions will be TRUE here.