Verilog Scheduling semantics
The Verilog scheduling semantics is used to describe Verilog language element’s behavior and their interaction with each other. This interaction is described for event execution and its scheduling. It is important to note that Verilog is like a parallel programming language in terms of blocks or process executions. Hence, the user should know the guaranteed or indeterminate execution order while using it.
Verilog processes include elements or statements such as always and initial procedural blocks, continuous assignments, asynchronous tasks, modules, and primitives.
Processes are ultimately sensitive to event updates. The terminology of event update describes any change in a variable or net state change. For example, always @(*) is sensitive for all variables or nets used. Any change in variable or net is considered as an event update. Another example could be having multiple initial blocks in the code. The evaluation order of these initial blocks can be arbitrary depending on simulator implementation. Programming Language Interface (PLI) callbacks are used to call a user-defined external routine of a foreign language. Such PLI callbacks are also considered as an event that has to be evaluated.
The Verilog language works on the evaluation and execution of such events. So, it becomes important to understand how these events will be evaluated and executed. The events are scheduled in a particular order to render an event execution systematically.
The design takes some time cycles to respond to the driven variables. The simulator models the actual time for the design description that is commonly known as simulation time. A single time cycle or slot is divided into various regions and that helps out to schedule the events. The scheduling an event terminology describes keeping all such events in an event queue and processing them in the correct order. The simulator executes all the events in the current time slot and then moves to the next time slot. This ensures that simulation always proceeds forward in time.
The events in a simulation time slot are classified as
- NBA (Non-Blocking Assignment)
The active events occur at the current simulation time and can be processed in any order.
Evaluation of active event
- Inputs and update outputs of Verilog primitives
- Right Hand Side (RHS) of all nonblocking assignments and execute to update Left Hand Side (LHS) in the NBA region.
Execution of active events
- Blocking assignments of all modules
- Continuous assignments of all modules
- $display and $finish commands.
The inactive events occur at the current simulation time and shall be processed after processing all the active events. An explicit #0 delay is scheduled in the inactive region of the current time slot.
The non-blocking assignment events are mainly used to update LHS of all nonblocking assignments whose RHS were evaluated in the active region.
The monitor events are processed after processing all active, inactive, and non-blocking assignment events. The $monitor and $strobe system tasks are executed as a part of monitor events.
The future events occur at some future simulation time.
It is important to focus on the situation when multiple processes are triggered simultaneously and how they are going to execute? The IEEE standard does not specify the execution order. Hence, the order of execution is arbitrary.
Let’s understand nondeterminism with the below case:
module non_det; reg data; initial data = 0; initial data = 1; endmodule
In this scenario, since both procedural initial blocks are executed simultaneously, order execution of initial blocks is nondeterministic and the user can not control it.