Please! Can Someone Make UVM Easy To Use?: Rich Edelman Raghu Ardeishar Mentor Graphics

Download as pdf or txt
Download as pdf or txt
You are on page 1of 23

Please!

Can someone make


UVM easy to use?
Rich Edelman Raghu Ardeishar
Mentor Graphics

© Accellera Systems Initiative 1


Main Concerns
• Unnecessary use of Parameterized classes
• Confusing sequences
• Config DB issues
• Heavy use of Macros

© Accellera Systems Initiative 2


Parameterized Classes
• Parameterized classes are very powerful
• …but misunderstood
• Not needed in all cases
• Overriding becomes problematic
• Layering UVM makes is harder
• Complicated use model with “factory”
• Use it only when needed

© Accellera Systems Initiative 3


Parameterized Classes
• A couple of examples…
– Class parameterized by value
class classValue #(int V = 3)
int delay = V;
….
endclass

– Class parameterized by type

class classType #(type T = int)


T delay;
….
endclass

• First Principles : Lets look at polymorphism…

© Accellera Systems Initiative 4


Parameterized Classes
• Basic Polymorphism
class classValue;
…. classValue baseclass
endclass
class classValueNew extends classValue
….
endclass
classValueNew
classValue cV = new;
classValueNew cVN = new;

cV = cVN;

• newClassValue is an extension of classValue


• Can be assigned to classValue
– They are type compatible

© Accellera Systems Initiative 5


Parameterized Classes
• Now with value parameters
class classValue (int V = 3); classValue baseclass classValue
….
endclass

classValue #(3) cV3 = new(); classValue#(3) classValue#(4)


classValue #(4) cV4 = new();
Not type
cV3 = cV4; //ERRRRROR compatible

• Not Possible
– Will compile and load
– Will result in a run time Fatal
• cV3 and cV4 are not type compatible

© Accellera Systems Initiative 6


Parameterized Classes
• Now with type parameters
class classType (type T = int); classType baseclass classType
….
endclass

classType #(int) cInt = new(); classType#(int) classType#(integer)


classType #(integer) cInteger = new();
Not type
cInt = cInteger; //ERRRRROR compatible

• Not Possible
– Will compile and load
– Will result in a run time Fatal
• cInt and cInteger are not type compatible

© Accellera Systems Initiative 7


Parameterized Classes
• Do you really need a parameter?
– Only if you need a elaboration time constant
– Most likely you need a dynamic variable
class classValue;
int T = 3;
….
endclass
class classValueNew extends classValue
int T = 4;
….
endclass
classValue cV = new;
classValueNew cVN = new;

cV = cVN;

© Accellera Systems Initiative 8


Parameterized Classes
• Layer on UVM and you raise the level of complication
• Add the factory and you get a perfect storm
• Macros (in parameterized classes) don’t work as
expected
– Or at least as most people expect !!
class packet extends uvm_object ;

• Lets first look at `uvm_object_utils(packet)


…..
endclass
regular UVM classes
class packetD extends packet;
• “p” and “pD” are `uvm_object_utils(packetD)
endclass
type compatible packet p = new();
packetD pD = new();

p = pD; //Works!!
© Accellera Systems Initiative 9
Parameterized Classes
• Util Macros work well in non-param classes
• Use it to register with factory
• Use uvm_top.print_topology() and factory.print() to get
details
virtual function end_of_elaboration_phase(uvm_phase phase) ;
uvm_top.print_topology();
factory.print();
…..
endclass

• Macros (in parameterized classes) will not create all the


necessary routines!!
• Factory override print will NOT show anything!
• To see details you will need to NEED to register MANUALLY

© Accellera Systems Initiative 10


Parameterized Classes
• Don’t use *_param_utils, It will not help
• Write this simple code as shown below
• factory.print() will show overrides

class driverB #(type T = int) extends uvm_driver #(T);


//`uvm_component_param_utils(driverB#(T))

localparam type_name = $sformatf("driverB#(%s)", T::type_name);


typedef uvm_component_registry #(driverB#(T), type_name) type_id;

static function type_id get_type();


return type_id::get();
endfunction
virtual function uvm_object_wrapper get_object_type();
return type_id::get();
endfunction
virtual function string get_type_name();
return type_name;
endfunction
endclass

© Accellera Systems Initiative 11


Parameterized Classes
• But the inherent issues remain…
• driverD2packet and driverD2packetD are not type
compatible
class driverD2 #(type T = uvm_object) extends driverB #(T);
driverB baseclass driverB
…..
endclass

typedef driverD2#(packet) driverD2packet;


typedef driverD2#(packetD) driverD2packetD;
driverD2packet driverD2packetD

Not type
compatible

• driverD2 cannot accept packets of different types w/o


some more work

© Accellera Systems Initiative 12


Parameterized Classes
• Deparameterized the class…
class classType #(type T = int);
T myDelay;
function calcDelay(); class config env_config extends uvm_object
rand int delay;
…. endclass
endclass
class classType;
int myDelay ;
env_config e;
uvm_config_db :: get(…“e”,e);
function new ( );
myDelay = e.delay;
endfunction
….
endclass

• Use uvm_config_db to get the parameter from config objects set


in the environment

© Accellera Systems Initiative 13


Parameterized Tests/Sequences
• Sequences and Parameterization  Not always needed
• Tempting to parameterize tests/sequences based on
bus width, LANES etc
• Will create issues while creating sequences to run on
interfaces with different parameters
• Solution: Instantiate with max possible bus widths and
control individual dimensions using environment
configs

© Accellera Systems Initiative 14


Parameterized Sequences
class test #(Int LANES = 2, int PIPE_BYTES_MAX = 1, int NUM_OF_FUNCTIONS = 1) extends uvm_test;
typedef pcieSeq #(LANES,PIPE_BYTE_MAX,NUM_OF_FUNCTIONS) pcieSeqT;
….
task run_phase;
pcieSeqT pcieSeq = pcieSeqT::type_id…;
pcieSeq.start(sequencer);
endtask
endclass

• Task and sequence have become more complicated to


extend and override
• Cannot run it on agents/sequencers with different
parameters
• Will need to create a new sequence for each variation of
parameters
• Code Bloat

© Accellera Systems Initiative 15


Parameterized test simplified
class env_config extends uvm_object
rand int LANES; env_config
rand int PIPE_BYTE_MAX; class test extends uvm_test;
rand int NUM_OF_FUNCTIONS; int LANES;
endclass int PIPE_BYTE_MAX;
Set env_config in int NUM_OF_FUNCTIONS;
module top; config_db typedef pcieSeq pcieSeqT;
initial begin ….
env_config eC = new(); task run_phase;
randomize(eC) with …; pcieSeqT pcieSeq = pcieSeqT::type_id…;
uvm_config_db #(env_config):: Get env_config env_config eC;
set(uvm_root::get(),“*”,“eC”, eC); uvm_config_db :: get(…“eC”,e);
end
from config_db LANES = eC.LANES;
endmodule PIPE_BYTE_MAX = eC.PIPE_BYTE_MAX;
pcieSeq.start(sequencer);
endtask
Extract properties endclass
from env_config

• Remove parameters from test or sequences


• Use configs to set and retrieve parameters.
• Use the same sequence/test

© Accellera Systems Initiative 16


Config DB …
• Very useful BUT very Often Misused/Misunderstood
• Very useful but expensive during lookups
• Use to set and get interfaces
• Use to set and get configuration objects
• Do not use to set and get integers, strings
• Do not call “get” multiple times eg, in a for/foreach
loop

© Accellera Systems Initiative 17


Config DB …
• Can you get it to work?
– Sure, But it all the effort with paths worth it?
static function void set ( uvm_component cntxt,
string inst_name,
string field_name,
T value)

• Inside a class to set the value:


– uvm_config_db #(type)::set(this,”*.pathname”, “label”,value);
• Outside a class to set the value:
– uvm_config_db #(type)::set(uvm_root::get(),”*.pathname”, “label”,value);
– Inside a class to set the value:
• To get the value
– uvm_config_db #(type)::get(this,””,”label”,value)

© Accellera Systems Initiative 18


Config DB …
• Use unique names for labels
• Avoid variables with same names in different instance paths
• Use “*” for instance names avoiding paths….
– Big Hammer but worthwhile in the long run
– Puts the variable in Global space
uvm_config_db #(virtual interfaceName) ::set (uvm_root::get(),“*”,“pcieIntf1”, pcieIntf1);
uvm_config_db #(virtual interfaceName) ::set (uvm_root::get(),“*”,“pcieIntf2”, pcieIntf2);

• Get the interface


– uvm_config_db #(type)::get(uvm_root::get(),”*”, “pcieIntf1”, pcieIntf);
• Use +UVM_CONFIG_DB_TRACE (simulator command line argument) to
debug set/get issues

© Accellera Systems Initiative 19


Config DB …
• Avoid using automated macros with config_db
• Example: uvm_agent “is_active”
• Mistaken assumption that `uvm_component_utils
implements uvm_config_db::get
• Implement “get” manually in the env or test OR
• Use `uvm_field_enum(uvm_active_passive_enum,
is_active, UVM_ALL_ON)

© Accellera Systems Initiative 20


Finally…Macros!
• To use or not to use? Well, Depends on the macro
• `uvm_do… AVOID
– You don’t need a macro to execute sequences
– They expand into complicated code
– Do the following instead
task sequence::body; task sequence::body;
myItem item; myItem item = myItem::type_id::create(…);
`uvm_do(item) // AVOID start_item(item);
endtask randomize(item);
finish_item(item);
endtask

task sequence::body;
mySeq seq; task sequence::body;
`uvm_do(seq) // AVOID mySeq seq = mySeq::type_id::create(…);
endtask seq.start(…);
endtask

© Accellera Systems Initiative 21


Finally…Macros!
• `uvm_field… AVOID like the Plague
– Implements copy, compare, pack, unpack etc…
– Code bloat and very hard to debug
– Simulators have optimized a lot for performance but still is a
debug issue
– Write the routines manually
– LOT easier to debug
– Refer to “Are OVM and UVM Macros Evil? A Cost-Benefit Analysis” by Adam Erikson

© Accellera Systems Initiative 22


Questions

© Accellera Systems Initiative 23

You might also like