Check out IEEE Std 1800-2012 § 3.4 & § 24. For full description about program
blocks.
In a short, incomplete summary, a program
block:
- cannot cannot contain
always
procedures, primitive
instances, module
instances, interface
instances (virtual interface
and port interface
is allowed), or other program
instances.
- specifies scheduling in the Reactive region. This prevents race conditions.
- has an extra system task
$exit
, which terminates the program
instances that calls it.
- The simulation will terminate when all
program
instances have exited.
- is mostly like a
module
block except as stated above.
The idea of a program
block is to create a clear separation between test and design. In earlier versions of SystemVerilog (pre IEEE 1800), instantiation of a class
was often limited to program
blocks. This emphasized the division of test and design. It also made program
blocks vital for verification engineers that that wanted to use object orientated programming in their flow. Since IEEE 1800, a class
can be defined and instantiated almost anywhere. As a result, program
blocks became less sufficient.
Today the opinion of usefulness of a program
block is divided. From the last few conventions I been to, the trend seems to be in favor of abandoning program
blocks. This is because the advantages can be achieved by other methods. Scheduling in the Reactive region can be done with clocking
blocks. A mailbox
, queue([$]
), or associative array ([*]
) can be used for intelligently handling simulation terminate running multiple tests. Personally, I still like using program
blocks and use initial forever
as an always
equivalent when needed. If you are planning to use UVM, then a non-program
blocks test bench might work better for you.
In the end, it really comes down to a methodology preference. It is best to evaluate and try it on your own.