An initial or always process blocks (goes to sleep) for a fix period of time when a delay statement is encountered. An example is:
always #50 out = ~out;
The delay is given in the previously specified time units and is rounded to time precision. Both time units and time precision are specified in a `timescale.
When using Verilog-AMS, it is a good practice to set the time units to 1s and then use SI scale factors to specify the delay. In that way the delay is self documenting. For example:
`timescale 1s/1ps ... always #50n out = ~out;
Event statements implement edge triggering. They cause an initial or always process to block until a specified change occurs. For example:
always @(posedge clk) q <= d;
This will update q when the clock transitions from 0 to one.
The event statement blocks until there is an event in its sensitivity list. A sensitivity list is simply a list of expressions separated by commas or the keyword or and an event is change in the value in one of the expressions. For example:
always @(a or b or c or d) y = (a | b) & (~c ^ d);
This situation, where every variable listed in expressions in the statements that follow the event control are given in the sensitivity list, is fairly common and it is easy for the sensitivity list to go out of date when changes are made to those expressions, and so Verilog supports the following shorthand:
always @* y = (a | b) & (~c ^ d);
Any variables that are present in expressions contained in the statement that follows the event control are effectively added to the sensitivity list of the event statement. This is true even if the statement that follows the event control is a composite statement. Thus:
always @* begin y = (a | b) & (~c ^ d); z = (e | f) & (~g ^ h); end
In this example, the sensitivity list effectively includes a, b, c, d, e, f, g, and h.
Event are not limited to being the first statement in an always block. They may be found anywhere in an either an initial or always block. The following assures that vgain is set properly at t=0:
always begin vgain = pow(10, gain/20 - 1.6); @(gain); end
Events can be filtered using the posedge and negedge keywords. posedge filters out events from 1 to 0 transitions and negedge filters out events from 0 to 1 transitions. For example:
always @(posedge clk or negedge resetb) begin if (~resetb) q <= 0; else q <= d; end
When distinguishing edges involving x or z values, effectively puts the 4 possible values into the following order: 0 → x, z, → 1. Thus, any transition from 0 or to 1 is considered a positive edge, any transition from 1 or to 0 is considered a negative edge, and x and z are treated as being the same by posedge and negedge.
If posedge or negedge are applied to multi-bit values, the observe only the least significant bit and ignore changes on any other bit.
The sensitivity list may also used explicitly declared or named events. You trigger a named event using ->:
event update_result; always @update_result result = find_result(x, y, z); initial -> update_result;
This example shows enough to see that result is computed initially as the simulator starts, but it could be updated at any time simply by triggering the update_result event.
In Verilog-AMS, discrete event statements may also contain the cross() analog event function:
always @(cross(V(in_p, in_n), +1)) count = count + 1;
The wait statement implements level-sensitive behavior. It takes an expression and blocks execution until the value of the expression becomes true. If the expression is true when the wait statement is encountered, then no blocking occurs. For example:
for (ch=0; ch <= 11; ch=ch+1) wait(locked) $display("channel %d freq=%fHz", ch, measure_freq(out));