3) It provides a syntactic
context that specifies execution scheduling in the Reactive region.
The program construct
serves as a clear separator between design and testbench,
and, more importantly, it specifies specialized execution semantics in the
Reactive region for all elements declared within the program. Together with
clocking domains blocks,
the program construct provides for race-free interaction between the design and
the testbench, and enables cycle and transaction
level abstractions.
To avoid the
races inherent in the Verilog event scheduler,
program statements are scheduled to execute in the Reactive region, after all
clocks in the design have triggered and the design has settled to its steady
state. Statements within a
program block that are sensitive to changes (e.g., update events) in design signals
(declared in modules, not program blocks) are scheduled in the Reactive region.
Consider a program block that contains the statement @(clk) S1; where clk is a design signal in some module. Every
transition of signal clk will cause the
statement S1 to be scheduled into the Reactive region. Likewise, initial blocks within
program blocks are scheduled in the Reactive region; in contrast, initial blocks in modules
are scheduled in the Active region. In addition, design signals driven from within the program must be
assigned using nonblocking assignments and are updated in the NBA region. Thus, even signals driven with no delay
are propagated into the design as one event. With this behavior, correct cycle
semantics can be modeled without races; thereby making program-based testbenches compatible with clocked assertions and formal
tools.
Since the
program executes schedules events in
the Reactive region, the clocking domain block construct is very useful to automatically sample the steady-state
values of previous time steps or clock cycles. Programs that read design values
exclusively through clocking domain blocks with non-zero #0 input skews
are insensitive to read-write races. It is important to note that simply
sampling input signals (or setting non-zero #0 skews on clocking domain block inputs) does not eliminate the potential for races. Proper input
sampling only addresses a single clocking domain block. With multiple clocks, the arbitrary order in which overlapping
or simultaneous clocks are processed is still a potential source for races. The
program construct addresses this issue by scheduling its execution in the
Reactive region, after all design events have been processed, including clocks
driven by nonblocking assignments.
16.4.1
Zero-skew clocking domain block races
When a clocking domain block sets both
input and output skews to #0 (see
Section 15.3) then its inputs are sampled (in the
observed region) at the same time as its outputs are driven (in the NBA region). This type of zero explicit #0-delay
processing is a common source of non-determinism that can result in races.
Nonetheless, even in this case, the program minimizes races by means of two mechanisms.
First, by constraining program statements to execute
be scheduled in the Reactive region, after all zero explicit #0-delay
transitions have propagated through the design and the system has reached a
quasi steady state. Second, by requiring design variables or
nets to be modified only via nonblocking assignments.
These two mechanisms reduce the likelihood of a race; nonetheless, a race is
still possible when skews are set to zero explicit #0.
Calling program tasks or
functions from within design modules is illegal and shall result in an error.
This is because the design must not be aware of the testbench.
Programs are allowed to call tasks or functions in other programs or within
design modules. Functions within design modules can be called from a program,
and require no special handling. However, blocking tasks (a task that does not execute in 0
simulation time) within design modules that are called from a
program do require explicit synchronization upon return from the task. That is,
when blocking tasks return to the program code, the program block execution is
automatically postponed until the Reactive region. The copy out of the parameters
happens when the task returns.