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.
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