Electronic – Proper clock generation for VHDL testbenches

vhdl

In many test benches I see the following pattern for clock generation:

process
begin
    clk <= '0';
    wait for 10 NS;
    clk <= '1';
    wait for 10 NS;
end process;

On other cases I see:

clk <= not clk after 10 ns;

The later is said to be better, because it is scheduled before any process is executed, and thus signals that are changed synchronously to the clk edge are handled properly.
The following sections from the LRM may seem to support this theory:

Page 169: 12.6.4 The simulation cycle
A simulation cycle consists of the following steps:

  • b) Each active explicit signal in the model is updated. (Events may
    occur on signals as a result.)

This should be the signals with a new projected value such as signals delayed by the after.

  • d) For each process P, if P is currently sensitive to a signal S and if
    an event has occurred on S in this simulation cycle, then P resumes.

That would be most of the logic to be simulated

  • e) Each nonpostponed process that has resumed in the current simulation
    cycle is executed until it suspends.

And now all processes that are suspended by a wait for are executed.

TL;DR:

  • Is the after method always superior to the wait for method?
  • Does it help to prevent the problems synchronously set input signals?

Best Answer

The simulator can't really be blamed for sometimes acting like the clock happened right after or right before the input changes, if you assign both clk and inputs using wait for. Asking if one style is superior or inferior to the other is, in a way, the wrong question. You need to specify behaviour in a non-ambiguous way, if you desire a deterministic and non-ambiguous output.

What I've done for years and has worked for me pretty flawlessly (for synchronous designs) is to assign the inputs preceding them with wait until rising_edge(clk) or wait until falling_edge(clk). How you generate the clk becomes unimportant. For simple testbenches the after one-liner does the job nicely and succinctly, but does not offer the flexibility of a process with wait for or wait until statements.

I have a little simple procedure that has served me well:

procedure wait_until_rising_edges(signal clk : in std_logic; n : in integer) is
begin
    for i in 1 to n loop
        wait until rising_edge(clk);
    end loop;
end procedure;

Which I keep in a tb_pkg.vhd that I always use in testbenches.

A use example could be:

some_stim_proc : process
begin
    some_signal <= '0';
    wait_until_rising_edges(clk,900);
    some_signal <= '1';
    wait_until_rising_edges(clk,100);
end process;

Some designers assign their stimulus signals at the opposite edge to what the unit under test is sensitive to. I personally don't like doing this because it is not how the rest of the circuit will simulate, where signals change at the 'trigger' edge. But there is certainly nothing wrong with that approach. The above procedure can also be used for it.