0% found this document useful (0 votes)
1K views7 pages

Polymorphic Interfaces An Alternative For Systemverilog Interfaces

- Polymorphic interfaces provide an alternative approach to using virtual interfaces for connecting SystemVerilog testbenches to parameterized DUT interfaces. - Virtual interfaces have limitations when used with parameterized interfaces, as the interface type needs to be uniquely defined for each set of parameter values. - The polymorphic interface approach defines an abstract base interface type and concrete subtypes for each parameterization, allowing the testbench to generically work with any parameterized interface through the base type. This provides a more elegant solution than virtual interfaces for sharing parameterized interfaces between the testbench and DUT.

Uploaded by

nvenkatesh485
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1K views7 pages

Polymorphic Interfaces An Alternative For Systemverilog Interfaces

- Polymorphic interfaces provide an alternative approach to using virtual interfaces for connecting SystemVerilog testbenches to parameterized DUT interfaces. - Virtual interfaces have limitations when used with parameterized interfaces, as the interface type needs to be uniquely defined for each set of parameter values. - The polymorphic interface approach defines an abstract base interface type and concrete subtypes for each parameterization, allowing the testbench to generically work with any parameterized interface through the base type. This provides a more elegant solution than virtual interfaces for sharing parameterized interfaces between the testbench and DUT.

Uploaded by

nvenkatesh485
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 7

Polymorphic Interfaces:

An Alternative for SystemVerilog Interfaces


by Shashi Bhutada, Mentor Graphics

INTRODUCTION The next big development in this area was the UVM
The SystemVerilog language is increasing in adoption for (Universal Verification Methodology) Library, which is
advanced verification techniques. This enables the creation an Accellera standard SystemVerilog code-base jointly
of dynamic test environments using SystemVerilog classes developed by multiple EDA Tool vendors and industry
among other things. The SystemVerilog virtual interface leaders. This library simplifies adoption of the object-
has been the primary method for connecting class-based oriented methods that are part of SystemVerilog. Simply
SystemVerilog testbenches with a VHDL or Verilog DUT, put, UVM tames the SystemVerilog behemoth. UVM is
but this construct has certain limitations, especially when largely based on its predecessor OVM (Open Verification
the interface is parameterized. In this article we will Methodology) Library.
discuss some of these limitations and demonstrate an
In a traditional testbench, the user is required to use a
alternative approach called as the Polymorphic Interface.
hardware description language (HDL) to also define the
The recommended approach can also work generically
testbench. Unfortunately, the HDL only allowed creating
wherever one uses virtual interfaces and not just
static design elements. This has many disadvantages
parameterized interfaces.
which include: testbench interfering with design interactions
For the SystemVerilog testbench, we will use OVM causing race conditions, static testbench prevents plug-n-
infrastructure, but this same discussion applies to UVM play, verification reuse meant cut-n-paste of the test code,
testbenches. This article assumes SystemVerilog OVM/ limited coverage of design state space and no metrics of
UVM class and interface syntactical understanding. which states were covered. In an advanced OVM/UVM
testbench a user is required to use ‘class’ syntax and
create dynamic testbench components which do not rely on
SYSTEMVERILOG OVM/UVM TESTBENCH pin-level interactions on the DUT but are at an abstraction
Design demands have grown exponentially over time above the pin-level interaction called as transaction-level
as our fabrication capabilities and geometry sizes have (shown in Figure 1).
dramatically improved. Verification methods can be
advanced with the SystemVerilog language, which provides
a whole gamut of methods. SystemVerilog amalgamates
advanced methods including Object-Oriented Programming
(OOP) by extending a well-known design language: Verilog.
Since it is an IEEE standard and packaged with RTL
simulators, advanced verification is now easily accessible.

The SystemVerilog language can be divided into five Figure 1: Transaction-level versus Pin-level activity
parts. One is an enhancement of Verilog RTL design
constructs that captures design intent more accurately. A typical OVM/UVM testbench (See figure 2) contains a
The other four parts are constructs meant to deliver the stimulus generator that generates transaction, a driver that
advanced verification features: assertions; object oriented converts transactions into pin-level activity, a monitor that
programming (OOP) or the ‘class’ syntax; constrained- transforms pin-level activity back into transaction objects,
random stimulus or automatic stimulus generation; and a coverage collector to measure the transaction activity on
functional coverage. the pins, a predictor that predicts what the expected output
transaction should be based on the stimulus applied, and a
scoreboard that compares observed output transaction with

19
the expected transaction. This approach has the following • Directly setting of the virtual interface handle where
advantages: test does not interfere with design under test, needed via helper function in the class.
dynamic test components are plug-n-play, verification reuse • Package-based global storage for the virtual interface
is possible for a given standard bus interface protocol, handle.
transaction-level code runs typically faster than pin-level • The preferred approach is by saving virtual interface
interaction, larger state space can be covered when using handle into the OVM/UVM configuration database.
constrained random transaction generation, and real In OVM, this requires an extra wrapper class to hold
metrics can be obtained by observing transactions the virtual interface.
around the testbench.
LIMITATIONS WITH
VIRTUAL INTERFACES:
The SystemVerilog virtual interface based
approach to connect the OVM testbench
and the DUT involves passing an interface
handle from the top-level module to the OVM
testbench. In most of the use cases virtual
interfaces work just fine. As we will see in
the example below, virtual interfaces become
difficult to use when it comes to parameterized
interfaces.

To demonstrate the problem, let’s see the


SYSTEMVERILOG INTERFACES example code below which tries to use virtual interfaces:
AND VIRTUAL INTERFACES:
In the OVM/UVM dynamic transaction-level testbench one
class vif_wrapper #(type T=int) extends ovm_object;
needs to ultimately connect with the DUT at different points.
T m;
The driver needs access to design pins to generate the
function new(string name=””);
right pin-activity based on the transaction. Similarly, the
super.new(name);
monitor needs access to design pins to observe pin-activity.
endfunction
Dynamic constructs cannot access static design items
endclass
directly.

SystemVerilog provides the ‘interface’ construct to interface bus_intf #( int aw, int dw, int tp = 8,
encapsulate a set of pins on a DUT. The interfaces typically strinf proc=”ppc”) (
can be design dependent but often they encapsulate //port declarations …
industry standard bus protocols for maximum reuse. A );
SystemVerilog interface is a static construct and resides on
the static side of the testbench. module top
parameter T1=10;
The SystemVerilog language provides the virtual interface parameter T2=T2*2;
construct that allows one to pass the ‘interface’ handle parameter T3=T3*5;
from the static side to the dynamic side. This connects the
class-based dynamic testbench to the static HDL design. bus_intf #( .aw (8), dw (12), .tp (T2), .proc(“arm”) )
Following are the different approaches to pass the interface intf_arm(…);
from static side to the dynamic side: bus_intf #( .aw (16), dw (32), .tp (T3) .proc(“nios”) )
intf_nios(…);

20
POLYMORPHIC INTERFACE:
//One must define unique and correct types The Polymorphic Interface approach provides a very
typedef virtual bus_intf elegant solution for sharing parameterized interfaces.
#( .aw (8), dw (12), .tp (T2), .proc(“arm”) ) This approach is also known as “Abstract/Concrete
vif_arm_t; Class” approach or “Two Kingdoms” approach. This
typedef virtual bus_intf approach involves defining a pure virtual (i.e. “abstract”)
#( .aw (16), dw (32), .tp (T3), .proc(“nios”) ) class and then making it concrete inside the scope of the
vif_nios_t; SystemVerilog interface (or module). The abstract class in
essence provides the “interface” like construct in Java, and
// If using a config object method then one can each concrete class inside the SystemVerilog interface (or
do the following module) provides functionality for the abstract functions in
vif_wrapper #(vif_arm_t) vif_arm; the context of the SystemVerilog interface (or module).
vif_wrapper #(vif_nios_t) vif_nios;
One could have multiple levels of inheritance hierarchy
initial each attached to a different type of SystemVerilog Interface
begin (or module), The OVM testbench will use the abstract
vif_arm=new(); class handle and, via polymorphism, the function calls get
vif_nios=new(); forwarded to the concrete class functions inside the right
vif_arm.m = intf_arm; //Pass the actual interface - hence the name “polymorphic interface.” As
handle interface we have seen, the virtual interface is not polymorphic. In
vif_nios.m = intf_nios; //Pass the actual the example below, the polymorphic interface approach
handle interface elegantly solves the issue with parameterized interfaces.
set_config_object(“*”,”wrapper”,wrapper,0);
run_test(“test”);
end
CREATING POLYMORPHIC INTERFACE:
Following are the steps involved in creating
endmodule
a Polymorphic Interface:

Step 1: Create an abstract or virtual class:


The issue is compounded if we want to define a generic
agent based on the parameterized interface. Each agent
will be instantiated to communicate with two similar but virtual class abstract_c extends ovm_object;
differently parameterized interfaces. As you see above function new(string name);
the interface specialization has to be inside the top due to super.new(name);
the dependencies on the top-level parameters. In such an endfunction
agent, what is the virtual interface handle inside the driver pure virtual task wr_cycle(int addr, int data);
going to look like? It has to be specific to the specialized- pure virtual task rd_cycle(int addr, ref int data);
type of interface it will be communicating through. endclass
package abs_pkg;
Here’s the pseudo code:
`include “ovm_macros.svh”
import ovm_pkg::*;
class driver #(type T = int) extends ovm_driver#(T); `include “abstract_c.svh”
`ovm_component_param_utils(driver #(REQ)) endpackage
transaction item;
virtual intf (…) vif;
endclass

21
Step 2: Define interface (or module) that will contain the
following things apart from regular port/parameter/modport/
import ovm_pkg::*;
task/function declarations:
import test_pkg::*;
• a concrete class that derives from the abstract module top;
class above parameter T1=10;
• a concrete class handle parameter T2=T1*2;
• a utility function to create the concrete class instance parameter T3=T1*5;

bus_intf #( .aw (8), .dw(12), .tp(T2), .proc(“arm”) )


intf_arm();
interface bus_intf #( int aw=8, int dw=8, int tp=8, bus_intf #( .aw (16), .dw(32), .tp(T3), .proc(“nios”) )
string proc=”ppc”) (); intf_nios();
import abs_pkg::*;
class concrete_c extends abstract_c;
function new(string name=””); initial
super.new(name); begin
endfunction set_config_object(“*”,”intf_arm”,
task wr_cycle(int addr, int data); intf_arm.get_concrete_c_inst(),0);
$display(“wr_cycle: accessing %s interface set_config_object(“*”,”intf_nios”,
pins”, proc); intf_nios.get_concrete_c_inst(),0);
endtask run_test(“test”);
task rd_cycle(int addr, ref int data); end
$display(“rd_cycle: accessing %s interface endmodule
pins”, proc);
endtask
endclass Step 4: In the OVM testbench the driver will call utility
functions (like wr_cycle) provided in concrete_c via
concrete_c concrete_inst; abstract_c (polymorphism) to drive the DUT pins:

• declare a handle to the abstract class


function abstract_c get_concrete_c_inst();
• get the configuration object to assign the concrete object
concrete_inst=new(proc);
to the abstract handle
return concrete_inst;
• inside the run function call the utility functions ( such as
endfunction
wr_cycle)
endinterface

class driver #(type T = int, string proc=”ppc”) extends


Step 3: Use the interface in the top level testbench module
ovm_driver#(T);
to connect to the DUT just like you would normally use.
`ovm_component_param_utils(driver #(REQ,proc))
We then add one extra step to create the concrete class
ovm_sequence_item item;
(and add it as a config object) using the utility function
abstract_c api;
we created earlier inside the interface as shown below:
function new(string name, ovm_component p);
super.new(name, p);
endfunction

22
function void build(); function new(string name, ovm_component p);
ovm_object tmp; super.new(name, p);
super.build(); endfunction

if(!get_config_object({“intf_”, proc}, tmp, 0)) begin function void build();


ovm_report_error(“build”, {proc, “ interface super.build();
not found”}); drv = driver#(ovm_sequence_item, proc)
end ::type_id::create(“drv”, this);
else begin sqr = new(“sqr”, this);
if(!$cast(api, tmp)) begin endfunction
ovm_report_error(“build”, {proc, “ interface
incorrect”}); function void connect();
end drv.seq_item_port.connect(sqr.seq_item_export);
end drv.rsp_port.connect(sqr.rsp_export);
endfunction endfunction
endclass
task run();
api.wr_cycle(‘hA1, ‘h5C); class env extends ovm_env;
endtask `ovm_component_utils(env)
agent #(“arm”) arm_agent;
endclass agent #(“nios”) nios_agent;
function new(string name, ovm_component p);
super.new(name, p);
Step 5: There are no changes in how one creates endfunction
the OVM Environment and Test. One can create the
agent with sequencer, driver and monitor. For the driver,
function void build();
specifically, use the one created earlier in step 4 that
super.build();
leverages the polymorphic interface. The agent’s driver will
arm_agent = agent#(“arm”)::type_id::create
now be customized with a different parameter which then
(“arm_agent”, this);
customizes the underlying interface. Here’s the example:
nios_agent = agent#(“nios”)::type_id::create
(“nios_agent”, this);
endfunction
package comp_pkg;
`include “ovm_macros.svh” endclass
import ovm_pkg::*; endpackage
import abs_pkg::*;
`include “driver.svh”
class agent #(string proc=”ppc”) extends ovm_agent; package test_pkg;
`ovm_component_param_utils(agent#(proc)) import ovm_pkg::*;
driver #(ovm_sequence_item, proc) drv; import comp_pkg::*;
ovm_sequencer #(ovm_sequence_item) sqr; `include “ovm_macros.svh”
class test extends ovm_test;
`ovm_component_utils(test)
env e;

23
REFERENCE:
function new(string name, ovm_component p);
super.new(name, p); [1] Rich D., Bromley, J. Abstract BFMs Outshine Virtual
endfunction Interfaces for SystemVerilog Testbenches. DVCon
2008.
function void build(); [2] Baird, M Coverage Driven Verification of an
super.build(); Unmodified DUT within an OVM Testbench. DVCon
e = env::type_id::create(“env”, this); 2010.
endfunction [3] Bromley J. First Reports from the UVM Trenches:
endclass User-friendly, Versatile and Malleable, or Just the
endpackage Emperor’s New Methodology? DVCon 2011

CONCLUSION:
Virtual Interfaces themselves do not have a notion of
polymorphism. The virtual interface is the standard
documented mechanism for communication between
dynamic (OVM/UVM) testbench and the static design under
test. In OVM, the preferred interface-based approach is to
wrap the virtual interface in an object and save the wrapper
into the OVM/UVM configuration database. In UVM, the
virtual interface can be passed into the uvm_config_db
directly without a wrapper class.

As shown in this paper, there are situations, such as


parameterized interfaces, when virtual interface approach
doesn’t work due to limitations in the interface syntax
itself. The Polymorphic Interface (Abstract/concrete
class) approach has the following advantages over virtual
interface:

• It provides a cleaner mechanism to deal with


parameterized interfaces, as shown here.
• It also provides polymorphism with interfaces, hence
the name Polymorphic Interface.
• It gets rid of the extra virtual interface wrapper
completely, when using the preferred the configuration
database, since the approach uses SystemVerilog
class syntax. The concrete class can directly be made
available via OVM/UVM configuration database to the
driver/monitor or any other transactors as needed.

24
Editor: Tom Fitzpatrick
Program Manager: Rebecca Granquist

Wilsonville Worldwide Headquarters


8005 SW Boeckman Rd.
Wilsonville, OR 97070-7777
Phone: 503-685-7000

To subscribe visit:
www.mentor.com/horizons

To view our blog visit:


VERIFICATIONHORIZONSBLOG.COM

You might also like