Why do we need virtual interfaces in system verilog?

Hello,

Can someone tell me why do we need virtual interfaces. It is not very clear to me after reading about virtual interfaces in number of places in LRM, books etc. Basically I would like to understand what is that that we can’t do with interfaces which we can do with virtual interfaces ?

Can someone explain the background for the introduction of virtual interface in the language?

Thanks,
Madhu

A virtual interface is a pointer to an actual interface in SystemVerilog. It is most often used in classes to provide a connection point to allow classes to access the signals in the interface through the virtual interface pointer.

You can see some examples of how to use virtual interfaces in the UVM Cookbook.

Good luck,
-Tom

Can someone tell me why do we need virtual interfaces

virtual interfaces come into play when using classes to defer at a later stage the definition of the physical interface to the one being worked on in the class.
The other advantage is that a class can be instanced multiple times and connect to different physical interfaces.

25.9 Virtual interfaces
Virtual interfaces provide a mechanism for separating abstract models and test programs from the actual signals that make up the design. A virtual interface allows the same subprogram to operate on different portions of a design and to dynamically control the set of signals associated with the subprogram. Instead of referring to the actual set of signals directly, users are able to manipulate a set of virtual signals. Changes to
the underlying design do not require the code using virtual interfaces to be rewritten. By abstracting the connectivity and functionality of a set of blocks, virtual interfaces promote code reuse.

Ben Cohen http://SystemVerilog.us

Physical interface in not supported in Object Oriented Programming (OOP) Fundamentals.So, This virtual interface concept came into the picture to use signals of interface.

In reply to ben@SystemVerilog.us:

Hi Ben,

Can you please elaborate on what you said above, may be with an example.

Thanks,

In reply to tfitz:

Thanks Tom.

In reply to mseyunni:

Can you please elaborate on what you said above, may be with an example.

virtual interfaces come into play when using classes to defer at a later stage the definition of the physical interface to the one being worked on in the class.
The other advantage is that a class can be instanced multiple times and connect to different physical interfaces.

As mentioned previously, you cannot refer in a class an actual interface. Consider a system with two redundant identical buses. Both may be active, thus serving different DUTs, or they may be redundant for self-checking, where the passive bus has its drivers inactive (i.e., the driver is in monitor/checking mode). Below is such an example.

class mem_agent extends uvm_agent;
    mem_sequencer sequencer;
    mem_driver driver1, driver2; // <--- 2 drivers 
    mem_monitor monitor;
    mem_checker m_checker;

    virtual  mem_if mem_if_1, mem_if2;  // <-- 2 identical interfaces  
...
    extern virtual function void connect_phase(uvm_phase phase);
endclass : mem_agent
function void mem_agent::connect_phase(uvm_phase phase);
 //...
        this.driver1.vif = this.mem_if_1;  // <-- the connection to driver1
        this.driver2.vif = this.mem_if_2;  // <-- the connection to driver2
endfunction : connect_phase

Ben Cohen SystemVerilog.us

Interface signals are static ( Physically available ) & where Class are dynamic and which needed virtual interface to communicate the actual interface signals

In reply to mseyunni:

Hi tfitz,

Does it mean that by declaring the interface as virtual then all classes using that interface will obtain the same values?
For example, driver will put a value on the virtual interface, then the monitor will get the same value also.
Is this the reason why virtual is used for the interface?

Thanks.

Regards,
Reuben

The interface is used to simplify the connection between DUT and Testbench. As the interface can’t be instantiated inside a class or program block, we need a virtual interface to point the physical interface.
So, the virtual interface is a pointer to the actual interface and using virtual interface, a class can point to different physical interfaces, dynamically (at run time).

In reply to Reuben:

Does it mean that by declaring the interface as virtual then all classes using that interface will obtain the same values?
For example, driver will put a value on the virtual interface, then the monitor will get the same value also.

Yes, using virtual interface, it is possible that the data driven by the driver is available to monitor, if the same instance of an interface is passed to both.

In reply to mseyunni:

The question is why you need “virtual interface” in System Verilog.
Well, you dont. You can easily connect module ports to class members by dotting into the module.
You could also 'define the module signal in order to get a single place to change when you change your class based TB to another module.

But people use it because it is a variable that refers to the interface’s dotted net.

virtual Interface_Name foo; can save the name for you, which you can use as a generic foo.

Cheers.
Soummya

In reply to mallick1:

Well, you dont. You can easily connect module ports to class members by dotting into the module.
You could also 'define the module signal in order to get a single place to change when you change your class based TB to another module.

virtual Interface_Name foo; can save the name for you, which you can use as a generic foo.

Can you elaborate on those above?

In reply to mallick1:

Well, you dont. You can easily connect module ports to class members by dotting into the module.

This is the crux of the issue. If you are putting classes in a package, you can’t have hierarchical references (dotted names) inside a package, and even if not using packages, you should not be putting in hierarchical reference inside to make your testbench re-usable. A `define won’t work if several instances of the class needs to connect to different places in the design.

In reply to mseyunni:

Responding to seyunni, you can easily drive a module wire from within a task member of a class as follows

task drive();
@(posedge clk)
dut.signal <= 1;

without needing any virtual interface.

As Dave pointed out earlier, you dont want hierarchical references in your class based tb for reasons he mentioned.

Also mentioned is that vi provides runtime binding, i.e. connections can be made and broken (only to be remade again) at run time (I rarely do). 'defines will fall short.

Soummya

In reply to mallick1:

I disagree with your statement "you can easily drive a module wire from within a task member of a class as follows

task drive();
   @(posedge clk)
      dut.signal <= 1;

Below is an example from my SVA book on verifying assertions. See the task is_illegal;

 
module ld_reg #(SIZE=8) 
    (input logic clk, ld, 
     input logic[SIZE-1:0] d_in, 
     output logic[SIZE-1:0] r_out, d_out,k_out, 
     inout logic[SIZE-1:0] data1, data2, data3); 

    logic a, b=1'b1, oe; // local variable 
    wire[SIZE-1:0] wdata1, wdata2, wdata3;
    always @ (posedge clk) begin : FF_LD
        // The begin statement is only needed
        // if multiple statements in body of always 
        r_out <= d_in;
        // data1 <= d_in; // illegal 
        // line above:  A net is not a legal lvalue in this context
        // wdata1 = d_in; // illegal 
        // line above:  A net is not a legal lvalue in this context
        //assign wdata3 = 'bZ; // illegal 
        assign d_out=oe ? 8'b101_1110 : 'bZ;      
    end : FF_LD
    
    task is_illegal; 
      @ (posedge clk)  
        data1 <= d_in; // Illegal reference to net "data1".
        wdata1 <= d_in; // Illegal reference to net "wdata1".
     endtask  
     
    assign data1 = oe ? 8'b101_0000 : 'bZ; 
    assign k_out=8'b10X_XZZ0;  
endmodule : ld_reg 

I explain in the book the following:
Assignments to inout port or module wire:

  1. Module ports defined as direction inout and internal nets (e.g., wire) can be driven by the continuous “assign” statement inside a module or interface. For example:
    assign data1 = oe ? 8’b101_0000 : 'bZ; // 
    However, the assign onto nets within an always block or task is illegal:
    2)Module ports defined as direction output, inout, and internal nets (e.g., wire) can be driven by a clocking block.
    Ben Cohen
    http://www.systemverilog.us/ ben@systemverilog.us
  • SystemVerilog Assertions Handbook 4th Edition, 2016 ISBN 978-1518681448
  • A Pragmatic Approach to VMM Adoption 2006 ISBN 0-9705394-9-5
  • Using PSL/SUGAR for Formal and Dynamic Verification 2nd Edition, 2004, ISBN 0-9705394-6-0
  • Real Chip Design and Verification Using Verilog and VHDL, 2002 isbn 0-9705394-2-8
  • Component Design by Example ", 2001 ISBN 0-9705394-0-1
  • VHDL Coding Styles and Methodologies, 2nd Edition, 1999 ISBN 0-7923-8474-1
  • VHDL Answers to Frequently Asked Questions, 2nd Edition ISBN 0-7923-8115

In reply to ben@SystemVerilog.us:

Thanks Ben for your input.

The example you are showing has got to do with continuous assign contention and that is true.
If 2 continuous assigns drive the same net, it will go to x in a hurry.

The question asked here has got to do with the question virtual interface existance in the language, at least that is what I am trying to answer.

The port being driven in my example dut.signal, whether driven via a virtual interface or a member of a modport, through a dotted reference, needs to be legally driveable, i.e. needs to be an input wire or NOT a wire.

Soummya

In reply to mallick1:
Your initial statement was “drive a module wire from within a task”
Can’t do that from a task.
You clarified by stating “legally driveable, i.e. needs to be an input wire or NOT a wire.” What about driving an inout port of a module when the state is in the input mode?
Again, you can’t do that from within a task, regardless of where the task is (i.e., in a module or a class instance).
SystemVerilog interface do have wires too.
Ben Cohen SystemVerilog.us

In reply to ben@SystemVerilog.us:

Hi Ben,
You are right.
In my mind, the legally drivable statement covers the wire/reg caveats.

Thanks for your point about inout wire port configured as input.
I am surprised as to why you say this is not drivable from a task. hope you can elaborate
I have been driving inout ports with ff->(reg q)->(inout wire net) all the time.

Soummya

Thanks for your inputs guys. All of them are helpful.
I like what Dave said regarding the disadvantage of using dotting to drive a signal. I was using that before in my testcase, test.env.agt.drv.signal <= 1’b1. But now I think I should not since the test will not become reusable.

In reply to mallick1:
I can’t easily locate where in 1800 those rules are defined. However, with 2 separate simulators, I get the same errors for the following code:


module ld_reg #(SIZE=8) 
    (input logic clk, ld, 
     input logic[SIZE-1:0] d_in, 
     output logic[SIZE-1:0] r_out, d_out,k_out, 
     inout logic[SIZE-1:0] data1, data2, data3); 

    logic a, b=1'b1, oe; // local variable 
    wire[SIZE-1:0] wdata1, wdata2, wdata3;
    always @ (posedge clk) begin : FF_LD
        // The begin statement is only needed
        // if multiple statements in body of always 
        r_out <= d_in;
        data3 <= d_in; // **** illegal LINE 13
        // line above:  A net is not a legal lvalue in this context
        // wdata1 = d_in; // illegal 
        // line above:  A net is not a legal lvalue in this context
        //assign wdata3 = 'bZ; // illegal 
        assign d_out=oe ? 8'b101_1110 : 'bZ;      
    end : FF_LD
    
    task is_illegal; 
      @ (posedge clk)  
        data1 <= d_in; // **** Illegal reference to net "data1". line 23
        wdata1 <= d_in; // Illegal reference to net "wdata1".
     endtask  
     
    // assign data1 = oe ? 8'b101_0000 : 'bZ; 
    assign k_out=8'b10X_XZZ0;  
endmodule : ld_reg 
// COMPILATION RESULTS: 
# ** Error: ld_reg.sv(13):   Illegal reference to net "data3".
# 
# ** Error: ld_reg.sv(23):   Illegal reference to net "data1".
# 
# ** Error: ld_reg.sv(24):   Illegal reference to net "wdata1".

Ben