11

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;
Russell
  • 3,013
  • 3
  • 24
  • 44

3 Answers3

15

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.

Morten Zilmer
  • 14,466
  • 2
  • 26
  • 47
  • Thank you for the explanation. It is interesting to me that wait on r_CLK_TB is a part of the wait until r_CLK_TB = '1' checking. Let me ask one last question, then I'll check the box :) When looking for positive clock edges you have 2 choices. Assuming you don't use wait until rising_edge(r_CLK_TB) in your normal RTL code you are using wait until r_CLK_TB'event and r_CLK_TB='1'. Are you telling me that wait until r_CLK_TB'event is totally useless here? – Russell Dec 10 '13 at 13:33
  • 2
    In `wait until r_CLK_TB'event and r_CLK_TB='1'`, the `r_CLK_TB'event` will be trivial TRUE once `r_CLK_TB'event and r_CLK_TB='1'` is evaluated, since it is the event that triggers the evaluation as you imply, so the expression can be reduced to `r_CLK_TB='1'`. – Morten Zilmer Dec 10 '13 at 13:50
  • 1
    NEAT. I'm going to start writing all my code like that, just to mess with people :) – Russell Dec 10 '13 at 13:54
3

Homework? Exam?

You need to study the details as to how wait works. Wait always suspends for at least a delta cycle. The wait until only resumes when a signal in the condition changes and the expression is true. So how many transitions to '1' do you need here to get to your second report statement?

How many transitions to '1' do you have with:

signal r_CLK_TB : std_logic := '0';
...
r_CLK_TB <= '1' after 20 ns, '0' after 40 ns, '1' after 60 ns; 

You need to study the details as to how wait works. Wait always suspends for at least a delta cycle. Wait until only resumes when a signal in the condition changes and the expression is true. So how many transitions to '1' do you need here?

What happens if you change r_CLK_TB to the following?

r_CLK_TB <= not r_CLK_TB after 20 ns ; 
Jim Lewis
  • 2,893
  • 8
  • 13
  • Not homework or exam... found this problem at real work! Why does the signal in the wait condition have to change? If the condition wait until r_CLK_TB = '1' was true BEFORE getting to the wait statement, it would simply go right by it, would it not? I would assume that wait until r_CLK_TB'event would look for some transition. I'm afraid I still don't quite understand... – Russell Dec 10 '13 at 03:54
  • I can accept it as "well that's just the way Modelsim behaves" but it doesn't FEEL right to me. :) – Russell Dec 10 '13 at 03:56
  • 2
    It is not just ModelSim, all VHDL simulators do this since this behavior is a language requirement. Another way to think of it is that the signals in the condition form an implicit sensitivity list. I understand your thoughts because many incorrectly see this as a level check, but it is an edge check. The language was designed this way to simplify the check for a process that never suspends (a bad infinite loop)- if the process contains either a wait statement or a process sensitivity list, then it suspends. For testbenches you really have to understand the details of how wait works. – Jim Lewis Dec 15 '13 at 19:34
2

I hang on the same issue.
My possible workaround is to add the global clock to the sensitivity list:

nClk <= NOT nClk AFTER 10 ns;

WAIT ON nClk UNTIL signalToCheck = '1';