Application of Virtual Interface and uvm_config_db


How to connect the DUT to the UVM Testbench..??

In our traditional directed Testbench environments, all the components are “static” in nature & information (data/control) is also exchanged in the form

of signals/wire/net at all levels in the DUT as well as TB.

But this is not the case in the latest “Constrained Random Verification Methodology” like UVM where DUT is static (module based) in nature yet Testbench is class (SystemVerilog OOPs) based. Hence the communication between the DUT and TB can NOT be like the one in traditional Testbenches i.e. port based connection of the DUT ports to the TB ports.

A standard classification of an UVM environment is shown in the figure 1 below:


Figure 1: A Standard Classification of an UVM Environment

In UVM, for this, we utilize the newly introduced SystemVerilog feature called “Virtual Interface”. An “Interface” is a collection of common signals between two entities & the signal direction is governed by the “modports”. 

We can see virtual interface as a handle pointing to the interface instance. Virtual interface acts as a medium to connect the DUT (SystemVerilog/Verilog module based) and the Testbench (SystemVerilog OOPs class based). Testbench access the DUT signals via virtual interface and vice versa.

How it all happens, lets understand using a diagram given below:


Diagram 1: Graphical View of DUT-TB Connection (Source: Cookbook)

As we can see in the diagram that the virtual interface information is provided to the Testbench (Test Class) from the DUT (light pink color coding) which acts as a pointer to the interface instance being used by the DUT. In actual UVM environment, the test class receives this virtual interface information from the DUT and later the test class propagates this virtual interface (interface instance handle) information to the physical component e.g. Driver, Monitor, Scoreboard etc, via a configuration object (dark pink color coding), which in the real sense needs this information to communicate with the DUT. Whole of this process happens by utilizing the “uvm_config_db” API.

In particular, passing the virtual interface from the test class to the hierarchy below utilizes one more UVM concept i.e. “Configuration Object”. I will try to write in more details about it in one of the next upcoming posts.

Placing a Virtual Interface into Configuration Database using uvm_config_db API:

The limitation of OVM was that only integral values, strings & objects (drived from ovm_objects) are allowed to kept inside Configuration Database. Due to this limitations, virtual interface needs to be wrapped into an object before using the config_db APIs.

But this limitation has been removed in UVM and now user can place Virtual Interface, User Defined Types etc directly into the Configuration Database. We can utilize this feature directly and use “set()” and “get()” call to place and retrieve the Virtual Interface to/from Configuration Database.

module top;

 import uvm_pkg::*;

 `include "uvm_macros.svh"

 //// Interface Declaration

 interface dut_if();

 logic data, clock, reset;

 endinterface: dut_if

 //// Interface Instantiation

 dut_if dut_if_inst;

 //// DUT Instantiation

 DUT DUT_inst (.....




 //// Initial Block



    uvm_config_db #(virtual dut_if)::set(null,"*", "dut_vi", dut_if_inst);



endmodule: top

Making the Virtual Interface Available in the Testbench:

A configuration object is created inside the test class & this configuration object contains a virtual interface property. Inside the test class, another uvm_config_db method i.e. uvm_config_db::get() is used to fetch the value of the virtual interface and assign it to configuration object property. This process is shown in the code below:

class my_test extends uvm_test;


 //// Configuration Handle 

 my_config my_config_h;




 //// Build Function

 function void build_phase (uvm_phase phase);


  my_config_h = new();  

        if (!uvm_config_db #(virtual dut_if)::get(this, "", "dut_vi", my_config_h.v_dut_if))            

        `uvm_fatal("FATAL MSG", "Virtual Interface Not Set Properly");

//// Propagating my_config object down to the hierarchy

         uvm_config_db #(my_config)::set(this, "*", "config", my_config_h);

 endfunction: build_phase

endclass: my_test

Assigning Virtual Interface Property into Transactor:

Now in this stage, the physical component i.e. the transactor e.g. Driver, Monitor & Scoreboard etc., which in real sense access the DUT assigns the virtual interface property from the received configuration object from the top i.e. uvm_test (as described above). Lets see the code provide below to make it clear:

class my_driver extends uvm_driver #(my_txn);



 //// Virtual Interface Declaration

   virtual dut_if dut_vi;

 //// Configuration Handle

  my_config my_config_h;

//// Build Function

  function void build_phase (uvm_phase phase);


    if(!uvm_config_db #(my_config)::get(this, "", "config", my_config_h))

     `uvm_fatal("FATAL MSG", "Configuration Object Not Received Properly");


  endfunction: build_phase

//// Connect Function

  function void connect_phase (uvm_phase phase);


  dut_vi = my_config_h.v_dut_if;

  endfunction: connect_phase

 //// Run Task

  task run_phase (uvm_phase phase);




  endtask: run_phase

endclass: my_driver

So this way, we can use Virtual Interface and uvm_config_db APIs to set up the effective communication between DUT and UVM Testbench which provides modularity, high re-usability & better control from the top (uvm_test_top).

 Bạn Có Đam Mê Với Vi Mạch hay Nhúng      -     Bạn Muốn Trau Dồi Thêm Kĩ Năng

Mong Muốn Có Thêm Cơ Hội Trong Công Việc

Và Trở Thành Một Người Có Giá Trị Hơn

Bạn Chưa Biết Phương Thức Nào Nhanh Chóng Để Đạt Được Chúng

Hãy Để Chúng Tôi Hỗ Trợ Cho Bạn. SEMICON  

Lần cập nhật cuối ( Thứ ba, 27 Tháng 7 2021 16:20 )