Sunteți pe pagina 1din 37

SystemVerilog Virtual Classes, Methods, Interfaces

Their Use in Verification and UVM

Clifford E. Cummings Heath Chambers


Sunburst Design, Inc. HMC Design Verification

World-class SystemVerilog & UVM Verification Training

Life is too short for bad


March 21-22, 2018 or boring training!
Silicon Valley

SNUG 2018 1 of 36
What's in the Paper? … And Our Agenda

Classes & virtual classes


Methods & virtual methods
Extended & derivative classes
Upcasting & downcasting
Upcasting & downcasting in UVM
Pure virtual methods
Virtual interfaces
Virtual interface usage in UVM More examples and more
detail in the paper
SNUG 2018
Summary & Conclusions 2 of 36
Virtual Classes & Methods
A Brief Introduction
Guideline #1: Class methods should be function and void function.
Only use task when the method consumes simulation time

virtual class handles can be declared and


• virtual classes - cannot be constructed referenced but cannot be new()- ed

• virtual classes can have non-virtual, virtual & pure virtual methods
Virtual class methods are non-virtual by default Only virtual classes can declare pure virtual methods

• Non-virtual classes can only have non-virtual & virtual methods


Fixed during construction and cannot
be changed during simulation
• Non-virtual methods are set when a class object is constructed
• virtual methods can be modified at run-time Accomplished by assigning a derivative
object handle to a base object handle

Guideline #2: Declare SystemVerilog class methods to be virtual methods unless


there is a very good reason to prohibit method polymorphism
SNUG 2018 3 of 36
Assigning Extended & Base Class Handles
Upcasting & Downcasting

SNUG 2018 4 of 36
Sunburst
Upcasting & Downcasting
Assuming Compatible Class Types

"Upcasting is casting to a supertype, while downcasting is casting to a subtype.


Upcasting is always allowed, but downcasting involves a type check
… and can throw a ClassCastException"
From "stackoverflow" reference in the paper

• To paraphrase:
– Any extended or derivative class handle can be assigned to a base class handle

– Only some base class handles can be assigned to an extended class handle
SystemVerilog requires a
type-check for downcasting

We do upcasting and downcasting


very frequently in UVM !
(examples will be shown)
SNUG 2018 5 of 36
Assigning Extended & Base Class Handles
Package with Base & Extended Classes
package test_classes;
class base; base class
bit [7:0] a;
function void showit;
function void seta(bit [7:0] din); $display("BASE(%m): a=%2d", a);
a = din; endfunction
endfunction

function bit [7:0] geta();


return(a);
endfunction Inherits:
endclass • a variable
• seta() method
class ext extends base; ext extended class • geta() method
bit [7:0] data;
function void showit;
function void setdata(bit [7:0] din); $display(" EXT(%m): data=%2d a=%2d",
data = din; data, a);
endfunction endfunction

function bit [7:0] getdata();


return(data);
endfunction What assignments are
Example assignments
endclass legal between base & on the next slides
SNUG 2018
endpackage extended class handles? 6 of 36
Construct A Base Class Object

Handle and bit ...


declarations initial begin
b1 = new(); • Construct the b1 class object
module test; b1.seta(4); • Set the b1 variable a=4
... b1.showit(); • Show the b1.a variable
base b1, b2; ...
ext e1, e2;
bit e1good,
e2good;
b1 null b2 null e1 null e2 null

a =0
=4
showit() (base)
seta()
geta()

BASE(test_classes.base.showit): a= 4
OUTPUT
SNUG 2018 7 of 36
Illegal Casting of Base to Extended Handle
Illegal Downcasting
... ** Error: Illegal assignment …
Handle and bit
// e1 = b1; Types are not assignment compatible
declarations
e1good = $cast(e1, b1);
ILLEGAL $cast
module test; if (!e1good) $display("b1->e1 cast failed");
... ...
base b1, b2; ILLEGAL message
Base handle to extended
ext e1, e2; handle assignment or b1->e1 cast failed
bit e1good, casting is ILLEGAL
e2good;
b1 null b2 null e1 null e2 null

a =4 a =0
showit() (base) data=0
seta() showit() (ext)
geta() e1 would need to reference: seta() e1 is expecting
• e1.data this !!
• e1.setdata() (not available in geta()
the base class) setdata()
• e1.getdata()
getdata()

b1->e1 cast failed


OUTPUT
SNUG 2018 8 of 36
Construct An Extended Class Object

Handle and bit ...


declarations e1 = new(); • Construct the e1 class object
e1.seta(2); • Set the e1 variable a=2
module test; e1.setdata(6); • Set the e1 variable data=6
... e1.showit(); • Show the e1.a & e1.data variables
base b1, b2; ...
ext e1, e2;
bit e1good,
e2good;
b1 null b2 null e1 null e2 null

a =4 a =0
=2
showit() (base) data=0
data=6
seta() showit() (ext)
geta() seta()
geta()
setdata()
getdata()

EXT(test_classes.ext.showit): data= 6 a= 2
OUTPUT
SNUG 2018 9 of 36
Legal Assignment of Extended to Base Handle
Legal Upcasting

Handle and bit ... Extended handle to base handle


declarations b2 = e1; assignment is LEGAL
b2.showit();
module test; ...
... Execute base class
showit() method
base b1, b2;
ext e1, e2;
bit e1good,
e2good;
b1 null b2 null e1 null e2 null

a =4 a =2 a =2
showit() (base) data=6 data=6
seta() showit() (base) showit() (ext)
Two views of the
geta() seta() seta()
same object
geta() geta()
setdata() setdata()
getdata() getdata()

BASE(test_classes.base.showit): a= 2
OUTPUT
SNUG 2018 10 of 36
Re-Construct The Extended Class Object

Handle and bit ...


declarations b2 = e1;
b2.showit();
module test;
• Re-construct the e1 class object
... e1 = new();
• Set the e1 variable a=9
base b1, b2; e1.seta(9);
• The e1 variable keeps data=0
ext e1, e2; e1.showit();
• Show the e1.a & e1.data variables
bit e1good, ...
e2good;
b1 null b2 null e1 null e2 null

a =4 a =2 a =2
=0
=9
showit() (base) data=6 data=6
data=0
seta() showit() (base) showit() (ext)
Re-constructed
geta() seta() seta()
e1 object
geta() geta()
b2 still points to setdata() setdata()
the old e1 object getdata() getdata()

EXT(test_classes.ext.showit): data= 0 a= 9
OUTPUT
SNUG 2018 11 of 36
Illegal Access to Extended Object Methods
From a Base Class Handle NOTE: b2 handle does not have access to
setdata() or getdata() methods
Handle and bit ...
// b2.setdata(9); ** Error: Field/method name
declarations
// m_data = b2.getdata(); (setdata) not in 'b2'
module test; ...
... ** Error: Field/method name
base b1, b2; (getdata) not in 'b2
ext e1, e2;
bit e1good,
e2good;
b1 null b2 null e1 null e2 null

a =4 a =2 a =9
showit() (base) data=6 data=0
seta() showit() (base) showit() (ext)
Re-constructed
geta() seta() seta()
e1 object
geta() geta()
b2 still points to setdata() setdata()
the old e1 object getdata() getdata()

SNUG 2018 12 of 36
Casting-Back Base to Extended Handle
Downcasting Requires a Type-Check
** Error: Illegal assignment …
Handle and bit ... Types are not assignment compatible
declarations // e2 = b2;
e2good = $cast(e2, b2); LEGAL $cast
module test; if (e2good) $display("b2->e2 cast PASSED!");
... e2.showit; LEGAL message
base b1, b2; end
ext e1, e2; endmodule b2->e2 cast PASSED
b2 and e2 point to
bit e1good,
e2good; the same object

b1 null b2 null e1 null e2 null

a =4 a =2 a =9 a =2
showit() (base) data=6 data=0 data=6
seta() showit() (base) showit() (ext) showit() (ext)
geta() seta() seta() seta()
geta() geta() geta()
Two views of the setdata() setdata() setdata()
same object getdata() getdata() getdata()

b2->e2 cast PASSED!


OUTPUT
EXT(test_classes.ext.showit): data= 6 a= 2
SNUG 2018 13 of 36
Full Handle Assignment Example
module test;
... Commented code caused
initial begin compiler errors
b1 = new(); Construct base object
b1.seta(4);
b1.showit();
// e1 = b1; ILLEGAL base class
e1good = $cast(e1, b1); // ILLEGAL $cast to extended class
if (!e1good) $display("b1->e1 cast failed"); $cast operation
e1 = new();
Construct extended object
e1.seta(2);
e1.setdata(6);
e1.showit();
b2 = e1;
Copy extended handle
b2.showit(); to base handle
e1 = new();
e1.seta(9);
e1.showit();
// b2.setdata(9);
// m_data = b2.getdata();
// e2 = b2; LEGAL base class
e2good = $cast(e2, b2); // LEGAL $cast to extended class
if (e2good) $display("b2->e2 cast PASSED!"); $cast operation
e2.showit;
end
SNUG 2018
endmodule 14 of 36
Base & Extended Class Handle Assignments
Assuming Compatible Class Types

• Any extended handle can be assigned to a base handle


– Can be a direct assignment or a $cast-assignment
– Base handles cannot access extended methods and data

• Some base handles can be assigned to extended handles


– Requirements:
• (1) Extended object had to be constructed
• (2) Constructed extended-handle had to be assigned to a base handle
• (3) Base handle must be $cast-back to an extended handle
This is why we care !!
• This technique allows creation of single base-class reference table
Upcasting
– Any extended handle can be stored in the table
Downcasting
– Any stored handle can be restored ($cast) to an extended handle
Used by OVM & UVM
SNUG 2018 15 of 36
User-Defined Transaction Class
uvm_object is the top-level
Derivative of uvm_object base class in UVM

class trans1 extends uvm_sequence_item;


`uvm_object_utils(trans1) uvm_object

logic [15:0] dout;


rand bit [15:0] din; uvm_transaction
rand bit ld, inc, rst_n;
...
function void do_copy(uvm_object rhs); uvm_sequence_item
trans1 tr;
if(!$cast(tr, rhs))
`uvm_fatal("trans1", "FAIL: do_copy() cast"); uvm_sequence trans1
super.do_copy(rhs);
dout = tr.dout;
din = tr.din;
ld = tr.ld; Theuser
usertransaction
transactiontype
typeis
The
inc = tr.inc; a derivative of uvm_object
rst_n = tr.rst_n;
endfunction
...
endclass
SNUG 2018 16 of 36
Transaction Class do_copy() Method
Example Usage from Scoreboard Predictor
The sb_calc_exp() function is
class trans1 extends uvm_sequence_item;
called with trans1 t handle
`uvm_object_utils(trans1)

logic [15:0] dout; The scoreboard predictor has


rand bit [15:0] din; sb_calc_exp() function
rand bit ld, inc, rst_n; function trans1 ... sb_calc_exp (trans1 t);
... ...
function void do_copy(uvm_object rhs); trans1 tr = trans1::type_id::create("tr");
trans1 tr; ...
if(!$cast(tr, rhs)) tr.copy(t);
`uvm_fatal("trans1", "..."); Local trans1 tr object is created
...
super.do_copy(rhs); return(tr);
dout = tr.dout; endfunction All fields of the t object are copied
din = tr.din; to the fields of the local tr object
ld = tr.ld;
inc = tr.inc;
rst_n = tr.rst_n; The sb_calc_exp() function
endfunction returns the tr handle
...
endclass
SNUG 2018 17 of 36
Transaction Class do_copy() Method
Upcasting & Downcasting trans1 t object
with five variables
class trans1 extends uvm_sequence_item;
tr.copy(t); t dout = 0000
`uvm_object_utils(trans1)
din = AAAA
calls …
logic [15:0] dout; ld = 1
do_copy(t); trans1 t object
rand bit [15:0] din; inc = 1
rand bit ld, inc, rst_n; converted to rst_n = 0
Upcast uvm_object rhs
...
function void do_copy(uvm_object rhs);
trans1 tr; rhs dout = 0000
if(!$cast(tr, rhs)) uvm_object rhs din = AAAA
`uvm_fatal("trans1", "..."); Cannot access variables ld = 1
super.do_copy(rhs);
Downcast inc = 1
dout = tr.dout;
Declare trans1 tr handle rst_n = 0
din = tr.din;
ld = tr.ld;
$cast uvm_object rhs
inc = tr.inc;
handle to trans1 tr handle tr dout = 0000
rst_n = tr.rst_n;
endfunction din = AAAA
... Now copy tr signals to ld = 1
endclass local trans1 signals inc = 1
SNUG 2018
rst_n = 0 18 of 36
Upcasting & Downcasting Variable Names
Avoid Confusing Names Previous slide - We named
the local trans1 handle tr
• Many industry examples name the local transaction handle rhs_

• Using rhs_ means that casting is done in the form $cast(rhs_, rhs);
This is confusing and therefore
a poor practice

• Causes fields to be referenced as rhs_.field_1 , …


Easy to confuse the uvm_object rhs handle
with the transaction class rhs_ handle

• Better practice: Use a transaction handle name like tr


Or another name that is visually distinct

Guideline #3: Declare local transaction handles using distinct names such as tr and
avoid local transaction handle names such as rhs_
SNUG 2018 19 of 36
Pure Virtual Methods
SystemVerilog-2009 Enhancement

SNUG 2018 20 of 36
Pure Virtual Methods
Two important purposes
virtual class vc1a;
bit [7:0] a;
pure virtual method
(1) pure virtual methods can only be
pure virtual function void seta(bit [7:0] val);
endclass a method prototype

No method body allowed

No endfunction / endtask allowed

class ex1a extends vc1a;


(2) pure virtual methods must be overridden
virtual function void seta(bit [7:0] val);
in a non-virtual class
a = val;
endfunction
endclass ex1a MUST override seta()
(must provide an implementation)

NOTE: pure keyword is only legal in virtual classes


SNUG 2018 21 of 36
Pure Virtual Methods virtual classes

virtual class vc1a; virtual class vc1b;


bit [7:0] a; bit [7:0] a;
pure virtual method pure virtual method
pure virtual function void seta(bit [7:0] val); pure virtual function void seta(bit [7:0] val);
endclass endclass

virtual class vc2a extends vc1a; virtual class vc2b extends vc1b;
vc2a does NOT override
virtual function void seta(bit [7:0] val);
seta() method
endclass a = val;
endfunction
vc2b DOES override
endclass
seta() method

non-virtual classes

class ex1a extends vc2a; class ex1b extends vc2b;

virtual function void seta(bit [7:0] val); // optional override of seta()


a = val; endclass
endfunction ex1b can OPTIONALLY
endclass ex1a MUST override seta() override seta()
(must provide an implementation)
SNUG 2018 22 of 36
UVM Pure Virtual Method Example
uvm_subscriber - pure write() Method
uvm_subscriber
virtual class uvm_subscriber #(type T=int) extends uvm_component; virtual class
...
pure keyword is only legal
in virtual classes The class parameter type (T) is used
in this method prototype
pure virtual function void write(T t);
No endfunction keyword allowed!
endclass

class tb_cover extends uvm_subscriber #(trans1); User-defined testbench coverage collector


... (non-virtual subclass)
function void write (trans1 t); pure virtual methods must be defined in
Almost exact
Exact samesame prototype
prototype each subclass (non-virtual subclasses)
dout = t.dout; required for write function
din = t.din;
The class parameter type (trans1) must
ld = t.ld;
inc = t.inc; be used in this method prototype
rst_n = t.rst_n;
`uvm_info("tb_cover", "Taking covergroup sample ...", UVM_HIGH)
cg.sample();
endfunction
SNUG 2018
endclass 23 of 36
Pure Virtual Method Usage

• Pure virtual methods serve two important purposes:


Pure virtual methods
– Pure virtual methods can only be a method prototype create a place-holder

– Pure virtual methods must be overridden in a non-virtual class


Imposes the requirement that it must
be overridden in a non-virtual class

Guideline #4: Declare a pure method whenever it is important to force a derivative class
to implement the method, as is done by the uvm_subscriber virtual class

SNUG 2018 24 of 36
Virtual Interfaces
Techniques & Usage

SNUG 2018 25 of 36
Virtual Interface Styles

• VIF styles:
– Pass an interface handle down through class constructors for use by a test
Somewhat straight-forward passing of vif handles Shown in the paper
through constructors, but tedious (not shown in this presentation)

Older OVM style


– Use a wrapper class and config object table to store and retrieve the wrapper
The vif is stored Wrapper class was required by OVM and uses upcasting
in the wrapper and downcasting to store the vif handle

Recommended UVM-style
Typically stored from
– Store the vif handle into the uvm_config_db. Use these methods: top module
uvm_config_db#(virtual dut_if)::set(null, "*", "vif" dif);
uvm_config_db#(virtual dut_if)::get(this, "", "vif" vif);
Typically retrieved by
Simple technique added to UVM (not available in OVM)
driver and monitor
SNUG 2018 26 of 36
Requirements for Virtual Interfaces

• 3 Requirements
– Top module, DUT and real interface to communicate with the DUT
An instantiated copy
of the interface

– You will need a virtual interface to communicate with the test class
A virtual interface handle
declared in a class

– You need a way to tie the real interface to the virtual interface
You need a way to pass a real interface handle
to a virtual interface handle in a class object

SNUG 2018 27 of 36
Interface connections to DUT ports
alu_reg w/ Interface Example
module top; module alu_reg (
logic clk; output logic [15:0] acc_out,
clkgen clkgen (.*); input logic [15:0] din1, din2,
dut_if dif (.*); input op_e opcode,
alu_reg alu_reg (.acc_out(dif.acc_out), .din1(dif.din1), input logic clk, rst_n);
.din2(dif.din2), .opcode(dif.opcode),
.rst_n(dif.rst_n), .*);
... ...
endmodule endmodule

interface dut_if (logic clk); module


din1[15:0] acc_out[15:0]
Hierarchically alu_reg(
connect DUT ports to logic [15:0] acc_out[15:0]; din2[15:0]
internal dut_if signals port-list
logic [15:0] din1[15:0]; opcode
);
logic [15:0] din2[15:0];
op_e opcode;
logic rst_n; alu_reg
clk clk This style is
dif recommended
rst_n
by OVM & UVM
clk_gen
SNUG 2018 28 of 36
OVM-Style - Wrapper Class Needed
The static dif handle cannot be
module top; stored in a class-based table top
...
dut_if dif (clk); A wrapper-class is required to
store the static dif handle
dut_if_wrapper dif_w; get_config_object() will
... Pass the dif handle to the get a umv_object handle
initial begin wrapper constructor (needs to be downcast)
dif_w = new(dif);
set_config_object("*", "dif_w", dif_w, 0);
run_test();
end uvm_object
Store the dif_w handle into the
endmodule To driver & Config Table
uvm_object config table monitor
"dif_w" : dif_w
class dut_if_wrapper extends uvm_object;
virtual dut_if vif; vif handle storage
dif_w
dut_if_wrapper
function new (virtual dut_if nif);
dif dut_if set_config_object()
vif = nif;
endfunction is an upcast operation
This dut_if handle is local to
endclass the function - it cannot be vif
alu_reg
SNUG 2018 nif must be copied to vif 29 of 36
OVM-Style - Driver Gets vif Handle
class tb_driver extends uvm_driver #(trans1); top get_config_object() will
… get a umv_object handle obj
Driver will use vif handle
virtual dut_if vif;
to drive signals to dut_if
… obj is $cast (downcast)
function void build_phase(uvm_phase phase); to wrapper handle w
super.build_phase(phase);
Wrapper w.vif handle is
uvm_object obj;
copied to driver vif
dut_if_wrapper w;
//-------------------------------
if (!get_config_object("dif_w", obj, 0)) uvm_object
`uvm_fatal("NOVIF",{"vif must be set for:", To driver & Config Table
get_full_name(),".vif"}); monitor
if (!$cast(w, obj)) "dif_w" : dif_w
`uvm_fatal("NOVIF",{"bad dif_w handle for",
get_full_name()});
dif_w
vif = w.vif; dut_if_wrapper
endfunction dif dut_if dif_w was upcast to

uvm_object type
endclass
Monitor uses the same technique
to retrieve the vif handle alu_reg
SNUG 2018 30 of 36
UVM-Style - uvm_config_db
The static dif handle to be
module top;
stored in uvm_config_db
...
dut_if dif (clk);
...
initial begin
uvm_config_db#(virtual dut_if)::set(null, "*", "vif", dif);
run_test();
end uvm_config_db#(…)::get(…);
endmodule Store the dif handle into the
uvm_config_db
top
To driver & uvm_config_db
monitor
"vif" : dif

dif dut_if uvm_config_db#(…)::set(…)


type-specific set command
uvm_config_db#(…)::set/get(…) greatly
simplifies storing & retrieving the dif handle alu_reg
SNUG 2018 31 of 36
UVM-Style - Driver Gets uvm_config_db
class tb_driver extends uvm_driver #(trans1);

Driver will use vif handle Get the dif handle that was
virtual dut_if vif;
to drive signals to dut_if stored in the uvm_config_db and

function void build_phase(uvm_phase phase); assign it to the local vif field
super.build_phase(phase);
if (!uvm_config_db#(virtual dut_if)::get(this, "", "vif", vif))
`uvm_fatal("NOVIF", {"vif must be set for: ",
uvm_config_db#(…)::get(…);
get_full_name(), ".vif"});
endfunction
… top
endclass uvm_config_db
To driver &
monitor
"vif" : dif
Much easier than using the
wrapper and downcasting!

dif dut_if

Monitor uses the same technique


to retrieve the vif handle alu_reg
SNUG 2018 32 of 36
UVM config_db Sumary

• The uvm_config_db commands eliminate the need to create a separate


wrapper class to store the static interface handle

• The uvm_config_db also and eliminates the need to do upcasting and


downcasting to save the vif

This is the UVM preferred style


to set and get the vif handle

Guideline #5: Use uvm_config_db#(virtual dut_if)::set(…) and


uvm_config_db#(virtual dut_if)::get(…) commands
to store and retrieve an interface for use by a UVM testbench

SNUG 2018 33 of 36
Summary of Guidelines

Guideline #1: Class methods should be function and void function.


Only use task when the method consumes simulation time

Guideline #2: Declare SystemVerilog class methods to be virtual methods


unless there is a very good reason to prohibit method-polymorphism

Guideline #3: Declare local transaction handles using distinct names such as tr and
avoid local transaction handle names such as rhs_

Guideline #4: Declare a pure method whenever it is important to force a derivative class
to implement the method, as is done by the uvm_subscriber virtual class

Guideline #5: Use uvm_config_db#(virtual dut_if)::set(…) and


uvm_config_db#(virtual dut_if)::get(…) commands
to store and retrieve an interface for use by a UVM testbench

SNUG 2018 34 of 36
Acknowledgements
Thanks!

• John Dickol and Don Mills for their reviews and comments of the paper and
slides

• Jeff Vance for discussions on advanced Virtual Interface techniques

Their patience and efforts greatly improved


the final paper and presentation!!

SNUG 2018 35 of 36
SNUG 2018 36 of 36
SystemVerilog Virtual Classes, Methods, Interfaces
Their Use in Verification and UVM

Clifford E. Cummings Heath Chambers


Sunburst Design, Inc. HMC Design Verification

World-class SystemVerilog & UVM Verification Training

Life is too short for bad


March 21-22, 2018 or boring training!
Silicon Valley

SNUG 2018 37 of 36

S-ar putea să vă placă și