Virtual Interfaces and Monitors

Let’s extend the code from previous blog post and introduce virtual interfaces and monitors.

Virtual Interfaces

In the simplest of words Virtual Interface is a pointer to an actual physical interface in the design. That’s why the namesake. That begs the question, why do I need a virtual interface ? The answer is, you really don’t. As you saw in my previous example, you can stimulate a design’s inputs using a UVM testbench without needing a virtual interface. However, having a virtual interface will benefit your testbench and it’s architecture.

Consider virtual interfaces to be the bridges that connect the physical design’s inputs and outputs to the abstract world of classes and software. “Classes” in systemverilog are objects which are created when the constructor is called. It would just be weird for classes to have access to the real physical interfaces; that sort of explains why it’s illegal for classes to have physical interfaces. A virtual(or abstract) pointer/handle to the actual interface makes more sense for software. With virtual interfaces, you could do fancy stuff like having different instances of the same class point to different physical interfaces. Of course, this adds to re-usability of your classes (think agents/monitors).

Monitors

I am clubbing monitors with virtual interfaces mostly because the most obvious use of virtual interfaces is in Monitors (One can argue the same with Drivers too, I will visit Drivers sometime later). Monitors are probably the simplest of UVM components in most testbenches. The primary idea of having a monitor is to look at the signals on the design’s physical interface. Monitors can then add functionality based on the observed signals. In most testbenches, monitors send data to the Scoreboard via analysis ports. Why do we need monitors ? The answer is related to re-use of these monitors across standard interfaces in the design. Can you build a testbench without monitors ? Of course you can, but the testbench wouldn’t be too useful outside of a very specific use case.

In this simple proof of concept example, the monitor uses a virtual interface, and is simply going to print out signals it sees on the interface.

Design and it’s interface

I am reusing the same simple DUT, and adding an interface.

interface sq_if();
  logic [7:0] a;
  logic [15:0] sq_out;
  
  modport to_DUT (input a, output sq_out);
endinterface

module square(sq_if i1);

  always_comb begin
    i1.sq_out = i1.a*i1.a;
    $display("Inside RTL:: time = %0d, a=%0d, square=%0d", $time, i1.a, i1.sq_out);
  end
   
endmodule

Set the virtual interface

The “top” has code that associates the physical interface with it’s virtual counterpart. The physical interface is instantiated just like a module. The path to this physical interface is then passed to the virtual interface in the uvm_config_db. (If you aren’t aware of what the config_db is, think of it as a database where you can store values and retrieve values from anywhere in your testbench). This virtual interface can be retrieved from the config_db in other testbench components as required.

import uvm_pkg::*;

`include "sq_if.sv"
`include "sq_mon.sv"
`include "sq_test.sv"

module top;
  bit [7:0] a;
  bit [15:0] square_out;
  
  sq_if i_sq_if();

  square sq_i(i_sq_if.to_DUT);
  
  initial begin
    uvm_config_db #(virtual sq_if)::set(null,"uvm_test_top","sq_if", i_sq_if);
    run_test("sq_test");
  end
    
endmodule

A simple Monitor

The monitor retrieves the virtual interface from the config_db. It proceeds to print the value of the signals every time the input changes.

class sq_mon extends uvm_monitor;
  `uvm_component_utils(sq_mon)
  
  function new(string name, uvm_component parent=null);
    super.new(name,parent);   
  endfunction
  
  virtual task run_phase(uvm_phase phase);
    
    virtual sq_if vif0;  
    uvm_config_db #(virtual sq_if)::get(null,"uvm_test_top","sq_if",vif0);
    
    forever begin
      @ vif0.a ;
      $display("Inside Monitor:: time = %0d, vif0.a=%0d, vif0.square=%0d", $time, vif0.a, vif0.sq_out);
    end
    
  endtask
  
endclass

The Test

The test too retrieves the virtual interface from the config_db. This is only required because the test uses this to drive the DUT’s inputs.

The test also includes a handle and a constructor to the monitor. The test use UVM’s “build_phase” to construct the monitor. UVM phase mechanism divides the testbench into sequential parts and helps organize and architect the testbench better. Think of the build_phase as a function where all components of the testbench are created before jumping into the actual simulation (which happens in the run_phase).

class sq_test extends uvm_test;
  `uvm_component_utils(sq_test)
 
  function new(string name, uvm_component parent);
    super.new(name, parent);
  endfunction
  
  virtual sq_if vif0;
  
  virtual function void build_phase(uvm_phase phase);
    sq_mon mon1;
    
    uvm_config_db #(virtual sq_if)::get(null,"uvm_test_top","sq_if",vif0);
    mon1 = sq_mon::type_id::create("mon1", this);
  endfunction
    
  task run_phase(uvm_phase phase);

    $display("Test's Run Phase.");
    phase.raise_objection(this);
    #1; 
    vif0.a = 9;
    #1;
    vif0.a = 15;
    phase.drop_objection(this);
        
  endtask
  
endclass

Output

UVM_INFO @ 0: reporter [RNTST] Running test sq_test...
Inside RTL:: time = 0, a=x, square=x
Test's Run Phase.
Inside RTL:: time = 1, a=9, square=81
Inside Monitor:: time = 1, vif0.a=9, vif0.square=81
Inside RTL:: time = 2, a=15, square=225
Inside Monitor:: time = 2, vif0.a=15, vif0.square=225

Conclusion

There we have it. We created a virtual interface and used it to correctly capture the stimulus and response in the monitor. We used the uvm_config_db, and also made use of the build_phase.

Comparing this testbench to it’s predecessor in the previous post, we have added more abstraction, structure and re-usability. We are yet to add Drivers, Agents and Scoreboards. We will get there eventually.

References

https://verificationacademy.com/forums/systemverilog/why-do-we-need-virtual-interfaces-system-verilog

Leave a comment