Program Block in System Verilog

SystemVerilog introduced the program block to address the needs of testbench development. It provides a dedicated context for writing verification code that interacts with the design under test (DUT). While similar in structure to the traditional module, the program block serves a specific purpose and has distinct characteristics.

This article explores the program block, its features, and how it differs from the module block, with examples to illustrate its usage.

What is a Program Block?

A program block in SystemVerilog is a construct designed specifically for testbenches. It encapsulates verification logic, ensuring a clear separation between testbench code and the DUT. The program block introduces synchronization semantics to avoid race conditions between the testbench and the design.

Key Features of the Program Block

  1. Verification Context: Dedicated for writing testbenches and verifying DUT behavior.
  2. It can’t contain always block, modules, interfaces or other programs.
  3. Non-blocking assignments are not allowed inside program block.
  4. Automatic Scheduling: Provides a built-in mechanism to avoid race conditions by scheduling procedural statements in the Reactive region of the SystemVerilog event queue.
  5. One-Time Execution: Designed to execute procedural code only once, making it ideal for stimulus generation.

Syntax

program program_name;
    // Declarations
    // Procedural code
endprogram

Example: Comparing Program and Module

Design (DUT):

In this example we create a design module where we initialize the value of y. We will write the testbench first with program block and then with module block. After then, we will compare the output of both.

module design_ex(output logic [3:0] y);
  
  initial begin
    y <= 4'h2;
  end

endmodule

Testbench with Program Block:

program design_tb(input logic[3:0] y);

    initial begin
       
      $display("y = %0h", y);
      
    end
endprogram

module top();
  logic [3:0] y;
  
  //instantiate design
  design_ex dut(.y(y));
  
  //instatntiate testbench
  design_tb test_bench(.y(y));
  
endmodule

Output:

y = 2

When we are using testbench with program block, we are getting output as 2.

Testbench with module Block:

Now let’s try the testbench with module block.

module design_tb(input logic[3:0] y);

    initial begin
       
      $display("y = %0h", y);
      
    end
endmodule

module top();
  logic [3:0] y;
  
  //instantiate design
  design_ex dut(.y(y));
  
  //instatntiate testbench
  design_tb test_bench(.y(y));
  
endmodule

Output:

y = x

Here we are getting value of y is x because of race condition.

So, The program block in System Verilog offers a structured and race-free environment for writing verification logic, making it a powerful tool for modern testbenches. While similar in structure to a module, the program block is tailored for verification tasks, offering synchronization and preventing race conditions with the DUT.