Last Updated: April 4, 2014
This post will give an explanation on UVM configuration objects, since the earlier posts did not cover much on them. The jelly-bean verification platform uses two kinds of configuration objects, jelly_bean_agent_config
and jelly_bean_env_config
. The former configures the jelly_bean_agent
and the latter configures the jelly_bean_env
. The figures below show the verification platform and the class diagram of the configuration-related classes.
Agent Configuration
The jelly_bean_agent_config
class configures the jelly_bean_agent
. The class has two switches; active
and has_jb_fc_sub
(lines 4 and 5). The active
switch controls whether the agent is in active mode or in passive mode. In the active mode, a sequencer (jelly_bean_sequencer
) and a driver (jelly_bean_driver
) will be created. In the passive mode, no sequencer or driver will be created. Similarly, the has_jb_fc_sub
switch controls whether the agent instantiates a functional coverage subscriber (jelly_bean_fc_subscriber
) or not. Based on the values of the switches, the agent will be structured as one of the four possible configurations shown in the figure below. The jelly_bean_agent_config
class also has a handle to the jelly_bean_if
(line 7).
1 2 3 4 5 6 7 8 9 10 11 12 | class jelly_bean_agent_config extends uvm_object; `uvm_object_utils( jelly_bean_agent_config ) uvm_active_passive_enum active = UVM_ACTIVE; bit has_jb_fc_sub = 1; // switch to instantiate a functional coverage subscriber virtual jelly_bean_if jb_if; function new( string name = "" ); super.new( name ); endfunction: new endclass: jelly_bean_agent_config |
Environment Configuration
Similar to the jelly_bean_agent_config
, the jelly_bean_env_config
configures the jelly_bean_env
. The class has four switches to define the structure of the environment (lines 4 to 7). It also has two handles to the jelly_bean_agent_config
; one handle per agent (lines 9 and 10).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class jelly_bean_env_config extends uvm_object; `uvm_object_utils( jelly_bean_env_config ) bit has_jb_agent1 = 1; // switch to instantiate an agent #1 bit has_jb_agent2 = 1; // switch to instantiate an agent #2 bit has_jb_sb1 = 1; // switch to instantiate a scoreboard #1 bit has_jb_sb2 = 1; // switch to instantiate a scoreboard #2 jelly_bean_agent_config jb_agent_cfg1; jelly_bean_agent_config jb_agent_cfg2; function new( string name = "" ); super.new( name ); endfunction: new endclass: jelly_bean_env_config |
Top Module
The top Verilog module instantiates two jelly_bean_if
s (line 6 and 7) and stores them in configuration database (lines 17 to 20). The cntxt
and inst_name
provide the scope information of the virtual interface being stored. Since the top
module is not a uvm_component
, null
is used as the cntxt
. The uvm_test_top
is the name of the top-level uvm_component
instantiated by the run_test()
task of the uvm_root
class.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | module top; import uvm_pkg::*; reg clk; jelly_bean_if jb_if1( clk ); jelly_bean_if jb_if2( clk ); jelly_bean_subsystem dut( jb_if1, jb_if2 ); initial begin clk = 0; #5ns ; forever #5ns clk = ! clk; end initial begin uvm_config_db#( virtual jelly_bean_if )::set ( .cntxt( null ), .inst_name( "uvm_test_top" ), .field_name( "jb_if1" ), .value( jb_if1 ) ); uvm_config_db#( virtual jelly_bean_if )::set ( .cntxt( null ), .inst_name( "uvm_test_top" ), .field_name( "jb_if2" ), .value( jb_if2 ) ); run_test(); end endmodule: top |
Base Test
The base test builds configuration objects as follows:
- The base test creates one configuration object (
jb_env_cfg
) for the verification environment, and two configuration objects (jb_agent_cfg1
andjb_agent_cfg2
) for the jelly-bean agents (lines 16 to 18). - The
jelly_bean_if
s, which we’ve created in thetop
module, are retrieved from the configuration database. Then each retrieved interface is assigned to the corresponding agent configuration (lines 20 to 27). - The agent configurations are assigned to the
jb_env_cfg
(lines 29 and 30). - The
jb_env_cfg
is stored in the configuration database so that the verification environment can get its configuration from the database later (line 32 and 33).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | class jelly_bean_base_test extends uvm_test; `uvm_component_utils( jelly_bean_base_test ) jelly_bean_env jb_env; jelly_bean_env_config jb_env_cfg; jelly_bean_agent_config jb_agent_cfg1; jelly_bean_agent_config jb_agent_cfg2; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); jb_env_cfg = jelly_bean_env_config ::type_id::create( "jb_env_cfg" ); jb_agent_cfg1 = jelly_bean_agent_config::type_id::create( "jb_agent_cfg1" ); jb_agent_cfg2 = jelly_bean_agent_config::type_id::create( "jb_agent_cfg2" ); if ( ! uvm_config_db#( virtual jelly_bean_if )::get ( .cntxt( this ), .inst_name( "" ), .field_name( "jb_if1" ), .value( jb_agent_cfg1.jb_if ) ) ) begin `uvm_error( "jelly_bean_test", "jb_if1 not found" ) end if ( ! uvm_config_db#( virtual jelly_bean_if )::get ( .cntxt( this ), .inst_name( "" ), .field_name( "jb_if2" ), .value( jb_agent_cfg2.jb_if ) ) ) begin `uvm_error( "jelly_bean_test", "jb_if2 not found" ) end jb_env_cfg.jb_agent_cfg1 = jb_agent_cfg1; jb_env_cfg.jb_agent_cfg2 = jb_agent_cfg2; uvm_config_db#( jelly_bean_env_config )::set ( .cntxt( this ), .inst_name( "*" ), .field_name( "jb_env_cfg" ), .value( jb_env_cfg ) ); jb_env = jelly_bean_env::type_id::create( .name( "jb_env" ), .parent( this ) ); endfunction: build_phase endclass: jelly_bean_base_test |
Environment
The verification environment builds itself using its configuration object as follows:
- The environment class gets its configuration object (
jb_env_cfg
) from the configuration database (lines 17 to 20). - If the configuration object indicates the agent #1 to be created, then the environment creates it and stores its configuration (
jb_agent_cfg1
) to the configuration database (lines 23 to 25). - A scoreboard is created if the configuration object indicates to do so (lines 27 to 29).
- The analysis port of the agent and the export of the scoreboard are connected if the both objects are instantiated (lines 47 and 48).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | class jelly_bean_env extends uvm_env; `uvm_component_utils( jelly_bean_env ) jelly_bean_env_config jb_env_cfg; jelly_bean_agent jb_agent1; jelly_bean_agent jb_agent2; jelly_bean_scoreboard jb_sb1; jelly_bean_scoreboard jb_sb2; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); if ( ! uvm_config_db#( jelly_bean_env_config )::get ( .cntxt( this ), .inst_name( "" ), .field_name( "jb_env_cfg" ), .value( jb_env_cfg ) ) ) begin `uvm_error( "jelly_bean_env", "jb_env_cfg not found" ) end if ( jb_env_cfg.has_jb_agent1 ) begin uvm_config_db#( jelly_bean_agent_config )::set ( .cntxt( this ), .inst_name( "jb_agent1*" ), .field_name( "jb_agent_cfg" ), .value( jb_env_cfg.jb_agent_cfg1 ) ); jb_agent1 = jelly_bean_agent::type_id::create( .name( "jb_agent1" ), .parent( this ) ); if ( jb_env_cfg.has_jb_sb1 ) begin jb_sb1 = jelly_bean_scoreboard::type_id::create( .name( "jb_sb1" ), .parent( this ) ); end end if ( jb_env_cfg.has_jb_agent2 ) begin uvm_config_db#( jelly_bean_agent_config )::set ( .cntxt( this ), .inst_name( "jb_agent2*" ), .field_name( "jb_agent_cfg" ), .value( jb_env_cfg.jb_agent_cfg2 ) ); jb_agent2 = jelly_bean_agent::type_id::create( .name( "jb_agent2" ), .parent( this ) ); if ( jb_env_cfg.has_jb_sb2 ) begin jb_sb2 = jelly_bean_scoreboard::type_id::create( .name( "jb_sb2" ), .parent( this ) ); end end endfunction: build_phase function void connect_phase( uvm_phase phase ); super.connect_phase( phase ); if ( jb_env_cfg.has_jb_agent1 && jb_env_cfg.has_jb_sb1 ) jb_agent1.jb_ap.connect( jb_sb1.jb_analysis_export ); if ( jb_env_cfg.has_jb_agent2 && jb_env_cfg.has_jb_sb2 ) jb_agent2.jb_ap.connect( jb_sb2.jb_analysis_export ); endfunction: connect_phase endclass: jelly_bean_env |
Agent
The agent builds itself using its configuration object as follows:
- The agent class gets its configuration object (
jb_agent_cfg
) from the configuration database (lines 19 to 22). - If the configuration object indicates the agent is active, then the agent creates a sequencer and a driver (lines 24 to 27).
- A functional coverage subscriber is created if the configuration object indicates to do so (lines 29 to 31).
- The port of the driver and the export of the sequencer are connected if the agent is active. The virtual interface of the driver is also connected (lines 42 to 45).
- The analysis port of the agent and the analysis export of the functional-coverage subscriber are connected if the functional-coverage subscriber exists (lines 47 to 49).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | class jelly_bean_agent extends uvm_agent; `uvm_component_utils( jelly_bean_agent ) jelly_bean_agent_config jb_agent_cfg; jelly_bean_sequencer jb_seqr; jelly_bean_driver jb_drvr; jelly_bean_monitor jb_mon; jelly_bean_fc_subscriber jb_fc_sub; uvm_analysis_port#( jelly_bean_transaction ) jb_ap; function new( string name, uvm_component parent ); super.new( name, parent ); endfunction: new function void build_phase( uvm_phase phase ); super.build_phase( phase ); if ( ! uvm_config_db#( jelly_bean_agent_config )::get ( .cntxt( this ), .inst_name( "" ), .field_name( "jb_agent_cfg" ), .value( jb_agent_cfg ) ) ) begin `uvm_error( "jelly_bean_agent", "jb_agent_cfg not found" ) end if ( jb_agent_cfg.active == UVM_ACTIVE ) begin jb_seqr = jelly_bean_sequencer::type_id::create( .name( "jb_seqr" ), .parent( this ) ); jb_drvr = jelly_bean_driver ::type_id::create( .name( "jb_drvr" ), .parent( this ) ); end if ( jb_agent_cfg.has_jb_fc_sub ) begin jb_fc_sub = jelly_bean_fc_subscriber::type_id::create( .name( "jb_fc_sub" ), .parent( this ) ); end jb_mon = jelly_bean_monitor::type_id::create( .name( "jb_mon" ), .parent( this ) ); endfunction: build_phase function void connect_phase( uvm_phase phase ); super.connect_phase( phase ); jb_mon.jb_if = jb_agent_cfg.jb_if; jb_ap = jb_mon.jb_ap; if ( jb_agent_cfg.active == UVM_ACTIVE ) begin jb_drvr.seq_item_port.connect( jb_seqr.seq_item_export ); jb_drvr.jb_if = jb_agent_cfg.jb_if; end if ( jb_agent_cfg.has_jb_fc_sub ) begin jb_ap.connect( jb_fc_sub.analysis_export ); end endfunction: connect_phase endclass: jelly_bean_agent |
Sequence Diagram
The following sequence diagram summarizes the configuration process described above.
I hope this tutorial helped you to understand the UVM configuration process.
Thank you for the interesting tutorial, very useful :)!
Concerning the configuration part, I have two questions:
– Is there a reason why you are not “creating” directly the jb_agent_config in the jb_env_cfg ?
– taking it a step further could be to have child variant of the agent and its configuration, so that very similar interfaces could share function and parameters.
Using set_inst_override_by_type function to setup the correct configuration doesn’t seem to work.
Say, if you use in the base test:
set_inst_override_by_type(“*.jb_agent1.*”, jelly_bean_agent_config::get_type(), jelly_bean_child1_agent_config::get_type());
set_inst_override_by_type(“*.jb_agent2.*”, jelly_bean_agent_config::get_type(), jelly_bean_child2_agent_config::get_type());
Florian,
Thanks for your comment. The reason I did not create a
jelly_bean_agent_config
in thejelly_bean_env_config
was that I wanted to control every configuration in the base test.Hi,
Does it matter if i create jelly_bean_agent_config in env or in base test? I was creating the agent config in env and when i did single stepping, i realized that agent’s build_phase is called before *agent_config even though *agent_config ::create is written before agent ::create.
Have you seen this behavior before?
It should not matter as long as
uvm_config_db#(agent_config)::set()
is called before the agent callsuvm_config_db#(agent_config)::get()
.Thank you for this wonderful tutorial ..it was very informative and helpful
Would you please provide the whole source code and compile environment? I am a newbie about UVM and verification. I can’t find the jelly_bean_subsystem and got many compile error when I try it with QuestSim10.1.
Enchanter,
I added a link to download the source code.
Hi Keisuke,
I am new to UVM and i went through the training and started a VIP on OCP 3.0 and your tutorials are very much helpful to understand the flow and usage.
I am just looking for same tutorial with respect to the sequencer and driver communication as well as driver and DUT communication.
Could you please provide the tutorial.
Thanks
Sreeni.
Hi,
Was the figure showing the verification platform was made with Visio?
Regards
Yes, I made it with Visio.
Hi Keisuke, Thanks for the wounderful tutorial on Configuration. It is very useful.
Can you please let me know why configuration class’s are inherited from ovm_object and not from ovm_component. Does it have any side effect if I inherit configuration class from ovm_component.
uvm_component
s are used for building “static” verification components, such as drivers, sequencers, monitors, etc. They are created at thebuild_phase
of a simulation and continue to exist until the end of the simulation. On the other hand,uvm_object
s are “dynamic” data flowing in the verification components. Examples are transactions and sequences. Since a configuration is not a static component (it is passed around to the components), it is not inherited from theuvm_component
.Hi Keisuke San,
Thanks for the very resourceful tutorial on SV UVM.
I have a doubt. As every chapter has a “Get Source Code” button, inorder to the overall picture of the example, which link should I click to download the example pkg?
Thanks,
/Sachin
Hi Sachin,
Actually every “Get source code” button leads you to the same source code repo on GitHub. Please click a button and see the list of available source code.
Hi Keisuke,
Thanks for the wonderful explanation. It is really good to understand for a UVM newbie like me.
Possible to provide a downloadable PDF for this matter above?
I just have 1 question about ‘active’ in jelly_bean_agent_config class.
Instead of initializing that variable (active) at that place to UVM_ACTIVE, how and where to do is using config_db::set call ?
Thanks,
–Sameer
Let’s say you want to make
jb_agent2
passive. The easiest way is probably settingUVM_PASSIVE
from a test that extendsjelly_bean_base_test
.But if you want to use the
uvm_config_db
, you could do something like this:I am a newbie in uvm world,
I want to change the value in environment’s configuration in my current work…
I translate the work in jellybean work will like that…
I tried the first method in my test’s build phase…
… it work
I tried the second method like that
or
… either of them do not work
I also tried another way… build a new config class and change the value inside, like below…
and write below in test’s build phase
… it does not work either
Could you tell me what’s the reason will cause it does not work?
Have you tried this?
If it works, then most likely there is a discrepancy between the instance path of
set()
and the instance path ofget()
. If you can paste how youget()
, I might be able to help more.Hi Keisuke Shimizu,
Thanks for your reply, the line you provided is not work…
I think the jelly_bean_env_cfg.sv is extended from uvm_object not uvm_component,
so I can not find it by “inst_name” from component hierarchies, that’s why I can not set up.
What do you think?
From what class do you call
get()
? Is the class a part of the component hierarchy of your test that callsset()
?It does not matter whether the
jelly_bean_env_cfg
is extended from theuvm_component
or not. What it matters is thatcntxt
+inst_name
has to match betweenset()
andget()
.Hi Keisuke Shimizu,
For my work needed,
I need to turn off hst_tx_agent, hst_rx_agent and dev_tx_agent, dev_rx_agent at my_test_base simulation (here is a single DUT alone)
I need to turn off tx_agent and rx_agent at my_test_base2 simulation (here is two DUTs connect to each others)
As I post before, when I used the code below
my_env_cfg.has_hst_tx_agent = 0;
my_env_cfg.has_hst_rx_agent = 0;
my_env_cfg.has_dev_tx_agent = 0;
my_env_cfg.has_dev_rx_agent = 0;
(in my_test_base.sv)
and used code below
my_env_cfg.has_tx_agent = 0;
my_env_cfg.has_rx_agent = 0;
(in my_test_base2.sv)
it work!
Here is my code setting…
Calling
uvm_config_db#(bit)::set()
merely stores a value to the configuration database. It does not automatically set the value to themy_env_cfg
. You need to callget()
to retrieve the value. However, to set the value of thehas_hst_tx_agent
, it is more natural to domy_env_cfg.has_hst_tx_agent = 0;
like you did.how a run_test can connect a complete enviornment?
This link might help. Basically the (global)
run_test
calls therun_test
ofuvm_root
class, which executes all the phases such asbuild_phase
.• Reason why our sequences and TB components except driver, monitor are at higher level of abstraction i.e at transaction level and not at pin level
Hi Keisuke,
Thanks for the wonderful explanation. I’m new with the UVM and I came across a problem:
I have 4 instances of the same interface in the TOP module and I’ve created an Env (UVC) for that interface. I want to create 4 agents in that Env, each driving one of the interface.
ex:
// in top module:
uvm_config_db#(virtual example_if )::set(uvm_root::get(), “*”, “example1_vif” , i_example1_vif );
uvm_config_db#(virtual example_if )::set(uvm_root::get(), “*”, “example2_vif” , i_example2_vif );
uvm_config_db#(virtual example_if )::set(uvm_root::get(), “*”, “example3_vif” , i_example3_vif );
uvm_config_db#(virtual example_if )::set(uvm_root::get(), “*”, “example4_vif” , i_example4_vif );
// in driver
virtual example_if vif;
uvm_config_db#(virtual example_if )::get(this, “”, “example_vif “, vif)
My problem is how to connect each example1_vif, example2_vif … interfaces to each driver of the four agents.
ex:
agent[0].driver.vif gets example1_vif;
agent[1].driver.vif gets example2_vif;
I basically want to overwrite the “example_vif ” with “example1_vif”, “example2_vif” … depending on the agent number.
Regards,
Adrian
If you set the
inst_name
more specifically and change thefield_name
to"example_vif"
in the top module, you should be OK.Hi Keisuke,
In jelly_bean_scoreboard, Why we need uvm_table_printer? what is the use of uvm_table_printer.
Thanks,
Sharath HV
I used the
uvm_table_printer
to print ajb_tx
in a tabular format whensprint()
is called (please seejelly_bean_scoreboard
in Environment). But you don’t have to use theuvm_table_printer
. For example, you can dojb_tx.convert2string()
to print the information ofjb_tx
if you define the function.what kind of tool do you use to make these uvm diagrams. I have been trying to get the ports dont correctly using plantuml.. unfortunately it is not working as expected. thanks for the help
I used UML Graph for the class diagram and Web Sequence Diagrams for the sequence diagram.
thank you Keisuke Shimizu. These tools are helpful. I am asking about the UVM ports that you have in the following figures. what tool did you use for this figure ? https://i1.wp.com/cluelogic.com/wp-content/uploads/2012/01/agent_config.png
I used Microsoft Visio for this particular figure. I also use draw.io.
Hello keisuke shimizu!
In the sequence diagram will test create agent?
jelly_bean_base_test
createsjelly_bean_env
, which in turn createsjelly_bean_agent
s.