UVM Testbench Top

The UVM testbench top is the highest level of the UVM testbench hierarchy. It’s the starting point for the simulation and acts as the container for all other testbench components. Understanding the testbench top is crucial for setting up and running UVM simulations.

Diagram of UVM Testbench Top

+-----------------------+
|    UVM Testbench Top  |
+-----------------------+
         |
         v
+-----------------------+
|      Environment      |
+-----------------------+
         |
+-----------------------+
|     Agents/Drivers    |
+-----------------------+
         |
+-----------------------+
|      Monitors         |
+-----------------------+
         |
+-----------------------+
|     Scoreboards       |
+-----------------------+
         |
+-----------------------+
|       DUT             |
+-----------------------+

Key Responsibilities of the Testbench Top:

  • Instantiation of Test: The testbench top instantiates the selected test, which in turn creates the environment and other necessary components.
  • Phase Execution: The testbench top initiates the UVM phases, driving the simulation lifecycle.
  • Configuration: It can be used to configure the testbench, such as setting command-line arguments or using the resource database.
  • Simulation Control: It controls the overall simulation flow, including starting and stopping the simulation.

Key Components of UVM Testbench Top

  1. Test Class: Defines the test case and configures the environment.
  2. Environment: Contains the agents, drivers, monitors, and other verification components.
  3. Interface: Connects the DUT with the testbench.
  4. DUT: The design under test.

 

Structure of the Testbench Top:

The testbench top is typically implemented as a SystemVerilog module. It contains the following key elements:

  1. Test Instantiation: An instance of the chosen test class.

  2. UVM Phase Execution: Calls to $uvm_root.run_test(), which starts the UVM simulation.

 

Diagram 1: Basic Testbench Top Structure

+---------------------+
| Testbench Top Module|
+---------------------+
| test test_inst;    | <--- Test Instantiation
|                   |
| initial begin       |
|   run_test();    | <--- Phase Execution
| end               |
+---------------------+

 

UVM Testbench Top Components

1. Test Class

The test class is derived from uvm_test. It defines the test scenario and configures the environment.

class my_test extends uvm_test;
  `uvm_component_utils(my_test)

  function new(string name = "my_test", uvm_component parent = null);
    super.new(name, parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // Instantiate the environment
    env = my_env::type_id::create("env", this);
  endfunction

  task run_phase(uvm_phase phase);
    // Define the test scenario
    phase.raise_objection(this);
    // Test actions
    phase.drop_objection(this);
  endtask
endclass

2. Environment

The environment is derived from uvm_env and contains all the agents, drivers, monitors, and scoreboards.

class my_env extends uvm_env;
  `uvm_component_utils(my_env)

  function new(string name = "my_env", uvm_component parent = null);
    super.new(name, parent);
  endfunction

  virtual function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    // Instantiate agents, drivers, monitors
    agt = my_agent::type_id::create("agt", this);
    scb = my_scoreboard::type_id::create("scb", this);
  endfunction
endclass

3. Interface

The interface connects the DUT with the testbench. It typically defines the signal connections between the two.

interface my_interface();
  logic clk;
  logic reset;
  logic [31:0] addr;
  logic [31:0] data;
  // Other signals
endinterface

4. DUT (Design Under Test)

The DUT is the hardware design that is being tested. It is instantiated within the top-level module.

module top;
  my_interface intf();
  my_dut dut (
    .clk(intf.clk),
    .reset(intf.reset),
    .addr(intf.addr),
    .data(intf.data)
    // Other connections
  );
endmodule

Putting It All Together

In the testbench top, all these components come together to create a coherent verification environment.

module testbench_top;
  import uvm_pkg::*;
  `include "uvm_macros.svh"

  my_interface intf();

  initial begin
    uvm_config_db#(virtual my_interface)::set(null, "env", "vif", intf);
    run_test("my_test");
  end
endmodule

Diagram 2: Testbench Top with Test and Environment

+---------------------+     +---------+     +-------------+
| Testbench Top       |---->| Test    |---->| Environment |
| (testbench_top)     |     | (my_test)|     | (my_env)    |
+---------------------+     +---------+     +-------------+
| run_test("my_test")|     | create()|     |             |
+---------------------+     +---------+     +-------------+

Explanation:

  1. The testbench_top module imports the uvm_pkg and includes the uvm_macros.svh file.
  2. It also imports the package containing the test classes (my_test_pkg in this example).
  3. An instance of the test class (my_test) is declared.
  4. The initial block calls $uvm_root.run_test("my_test"). This is the most important part. It does the following:
    • Creates an instance of the uvm_root component (if it doesn’t already exist).
    • Looks for a registered test with the given name (“my_test”).
    • If found, it creates an instance of the test.
    • The test’s build_phase is executed, which creates the environment and other components.
    • The run-time phases are then executed.

Diagram 3: Detailed View with UVM Phases

+---------------------+     +---------+     +-------------+
| Testbench Top       |---->| Test    |---->| Environment |
| (testbench_top)     |     | (my_test)|     | (my_env)    |
+---------------------+     +---------+     +-------------+
| run_test("my_test")|     | build() |     | build()     |
|                     |     | connect()|     | connect()   |
|                     |     | ...     |     | ...       |
+---------------------+     +---------+     +-------------+
        ^                       |
        |                       |
        +-----------------------+
                UVM Phases

Passing Test Names from the Command Line:

You can pass the test name from the command line using the +UVM_TESTNAME=<test_name> option. This allows you to run different tests without recompiling the testbench.

Example:

vcs +UVM_TESTNAME=another_test testbench_top.sv

Diagram 4: Command Line Test Selection

Command Line: vcs +UVM_TESTNAME=another_test testbench_top.sv

+---------------------+
| Testbench Top       |
| (testbench_top)     |
+---------------------+
| run_test(get_test()| <--- Gets "another_test" from command line
+---------------------+


Key Takeaways:

  • The testbench top is the entry point for UVM simulations.
  • It instantiates the test and initiates the UVM phases.
  • $uvm_root.run_test() is the key function for starting the simulation.
  • Command-line arguments can be used to select which test to run.