Following three items are essential for getting to the bottom of Verilog execution order.
1) Verilog event queues.
2) Determinism in Verilog.
3) Non determinism in Verilog.
Verilog event queues :
To get a very good idea of the execution order of different statements and assignments, especially the blocking and non-blocking assignments, one has to have a sound comprehension of inner workings of Verilog.
This is where Verilog event queues come into picture. Sometime it is called stratified event queues of Verilog. It is the standard IEEE spec about system Verilog, as to how different events are organized into logically segmented events queues during Verilogsimulation and in what order they get executed.
Figure : Stratified Verilog Event Queues.
As per standard the event queue is logically segmented into four different regions. For sake of simplicity we’re showing the three main event queues. The “Inactive” event queue has been omitted as #0 delay events that it deals with is not a recommended guideline.
As you can see at the top there is ‘active’ event queue. According to the IEEE Verilog spec, events can be scheduled to any of the event queues, but events can be removed only from the “active” event queue. As shown in the image, the ‘active’ event queue holds blocking assignments, continuous assignments. primitive IO updates and $write commands. Within “active” queue all events have same priority, which is why they can get executed in any order and is the source of nondeterminism in Verilog.
There is a separate queue for the LHS update for the nonblocking assignments. As you can see that LHS updates queue is taken up after “active” events have been exhausted, but LHS updates for the nonblocking assignments could re-trigger active events.
Lastly once the looping through the “active” and non blocking LHS update queue has settled down and finished, the “postponed” queue is taken up where $strobe and $monitor commands are executed, again without any particular preference of order.
At the end simulation time is incremented and whole cycle repeats.
Determinism in Verilog.
Based on the event queue diagram above we can make some obvious conclusions about the determinism.
– $strobe and $monitor commands are executed after all the assignment updates for the current simulation unit time have been done, hence $strobe and $monitor command would show the latest value of the variables at the end of the current simulation time.
– Statements within a begin…end block are evaluated sequentially. This means the statements within the begin…end block are executed in the order they appear within the block. The current block execution could get suspended for execution of other active process blocks, but the execution order of any being..end block does not change in any circumstances.
This is not to be confused with the fact that nonblocking assignment LHS update will always happen after the blocking assignments even if blocking assignment appears later in the begin..end order. Take following example.
initial begin
x = 0
y <= 3
z = 8
end
When we refer of execution order of these three assignments.
1) First blocking statement is executed along with other blocking statements which are active in other processes.
2) Secondly for the nonblocking statement only RHS is evaluated, it is crucial to understand that the update to variable ‘y’ by value of ‘3’ doesn’t happen yet. Remember that nonblocking statement execution happens in two stages, first stage is the evaluation of the RHS and second step is update of LHS. Evaluation of RHS of nonblocking statement has same priority as blocking statement execution in general. Hence in our example here, second step is the evaluation of RHS of nonblocking statement and
3) third step is execution of the last blocking statement ‘z = 8’. The last step here will be the update to ‘y’ for the nonblocking statement. As you can see here the begin .. end block maintains the execution order in so far as the within the same priority events.
4) last step would be the update of the LHS for the nonblocking assignment, where ‘y’ will be assigned value of 3.
– One obvious question that comes to mind, having gone through previous example is that what would be the execution order of the nonblocking LHS udpate !! In the previous example we only had one nonblocking statement. What if we had more than one nonblocking statement within the begin..end block. We will look at two variation of this problem. One where two nonblocking assignments are to two different variable and the two nonblocking assignments to same variable !!
First variation.
initial begin
x = 0
y <= 3
z = 8
p <= 6
end
For the above mentioned case, the execution order still follows the order in which statements appear.
1) blocking statement ‘x = 0’ is executed in a single go.
2) RHS of nonblocking assignment ‘y <= 3’ is evaluated and LHS update is scheduled.
3) blocking assignment ‘z = 8’ is executed.
4) RHS of nonblocking assignment ‘p <= 6’ is evaluated and LHS update is scheduled.
5) LHS update from the second nonblocking assignment is carried out.
6) LHS update from the last nonblocking assignment is carried out.
Second variation.
initial begin
x = 0
y <= 3
z = 8
y <= 6
end
For the above mentioned case, the execution order still follows the order in which statements appear.
1) blocking statement ‘x = 0’ is executed in a single go.
2) RHS of nonblocking assignment ‘y <= 3’ is evaluated and LHS update is scheduled.
3) blocking assignment ‘z = 8’ is executed.
4) RHS of nonblocking assignment ‘y <= 6’ is evaluated and LHS update is scheduled.
5) LHS update from the second nonblocking assignment is carried out, ‘y’ is 3 now.
6) LHS update from the last nonblocking assignment is carried out, ‘y’ is 6 now.
Non-determinism in Verilog.
One has to look at the active event queue in the Verilog event queues figure, to get an idea as to where the non-determinism in Verilog stems from. You can see that within the active event queue, items could be executed in any order. This means that blocking assignments, continuous assignments, primitive output updates, and $display command, all could be executed in any random order across all the active processes.
Non-determinism especially bits when race conditions occur. For example we know that blocking assignments across all the active processes will be carried out in random order. This is dandy as long as blocking assignments are happening to different variables. As soon as one make blocking assignments to same variable from different active processes one will run into issues and one can determine the order of execution. Similarly if two active blocking assignments happen to read from and write to the same variable, you’ve a read write race.
We’ll look at Verilog race conditions and overall good coding guidelines in a separate post.
-SS.