SystemVerilog Program Blocks - What, Why and How

Previous: Creating Programs

Assignment of variables inside a program

Before we go into the actual discussion, here are few useful things to note.

First, notice that a simulation time slot can execute multiple events. The order of these events may be arbitrary based on how these events are generated. A race condition between an event generated by a test bench (i.e. a program) and another generated by the DUT (i.e. a module) can be avoided, if we make sure these two events are executed in a known order and are non-interfaring with each other.

Next, note that the only time a race condition can happen is when a program module assigns a value to a module variable (or calls a task or function that does that) at the same time when the module itself is updating the variable. This is because a design module can not assigns a value to a variable local to a program since a design must not be aware of a test bench.

This simplifies the issue a whole lot. Now all that we need to do is to make sure all program variables and all module variables are updated in two different areas of the simulation time slot in a known order.

Luckily for us, such execution ordering within a single time slot can be easily achieved by using blocking assignments (=) for variables local to a program and non-blocking assignments (<=) for updating module variables within a program. This causes various code segments to execute in a pre-determined order.

  • The blocking assignments of all modules are executed in the Active region.
  • The non-blocking assignments within a program are executed in the Non-blocking assignment (NBA) region.
  • The events generated by the blocking assignments within a program block are all executed in one part of the execution, known as the Reactive region.
This is illustrated in the figure below.

So here are the ground rules for assignments within a program.

  • All variables local to a program can only be assigned using blocking assignment.
  • All other variables must be assigned using non-blocking assignments.

Programs and Blocking Tasks

As we mentioned earlier, a module can not call tasks or functions defined within a program, but a program can call a task or function defined within a module or another program. When a program calls a module task that consumes time, the restrcitions on how assignments work within a program vs a module give rise to interesting situations.

To see this, consider the following case.

task mod_task; 
   a = b; 
   #5
   c <= d;
Here, the module task mod_task contains two assignments - the first one is blocking, and the other one is non-blocking. When a module calls this task, both assignments are executed during the Active region. However, when a program calls this task, the first blocking assignment is executed in the Reactive region, where other non-blocking assignments may have changed the value of the right hand side. The second non-blocking assignment always gets executed in the Active region.

$exit()

A system task $exit() forces a program to terminate and exit. A call of $exit() terminates all active processes spawned by the program. Note that, $exit() does not terminate simulation as done by $finish(), it only terminates the program that calls it. A simulation-wide $finish() implicitly terminates all the program.

The Synthesis Question

Are programs synthesizable? The answer to the question lies in another question, since programs are meant for testbenches, do they need to be? Also, constructs such as initial blocks can not be synthesized. So, converting a program to a design module is a formidable task. If you intend to convert a testbench to a design (say, for a test chip), programs are not suited for those purposes.

Previous: Creating Programs

Share/Save/Bookmark



Verification Management
Join Verification Management Group


Book of the Month


From Our Press