UVM Tutorial for Candy Lovers – 8. Configurations

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.

Verification Platform
Class Diagram of the Configuration 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
Four Possible Agent Configurations

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_ifs (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:

  1. The base test creates one configuration object (jb_env_cfg) for the verification environment, and two configuration objects (jb_agent_cfg1 and jb_agent_cfg2) for the jelly-bean agents (lines 16 to 18).
  2. The jelly_bean_ifs, which we’ve created in the top module, are retrieved from the configuration database. Then each retrieved interface is assigned to the corresponding agent configuration (lines 20 to 27).
  3. The agent configurations are assigned to the jb_env_cfg (lines 29 and 30).
  4. 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:

  1. The environment class gets its configuration object (jb_env_cfg) from the configuration database (lines 17 to 20).
  2. 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).
  3. A scoreboard is created if the configuration object indicates to do so (lines 27 to 29).
  4. 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:

  1. The agent class gets its configuration object (jb_agent_cfg) from the configuration database (lines 19 to 22).
  2. If the configuration object indicates the agent is active, then the agent creates a sequencer and a driver (lines 24 to 27).
  3. A functional coverage subscriber is created if the configuration object indicates to do so (lines 29 to 31).
  4. 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).
  5. 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.

Sequence Diagram of the Build Phases

I hope this tutorial helped you to understand the UVM configuration process.

Get source code

33 thoughts on “UVM Tutorial for Candy Lovers – 8. Configurations”

  1. 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());

    1. Florian,

      Thanks for your comment. The reason I did not create a jelly_bean_agent_config in the jelly_bean_env_config was that I wanted to control every configuration in the base test.

      1. 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?

  2. 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.

  3. 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.

  4. 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.

    1. uvm_components are used for building “static” verification components, such as drivers, sequencers, monitors, etc. They are created at the build_phase of a simulation and continue to exist until the end of the simulation. On the other hand, uvm_objects 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 the uvm_component.

  5. 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

  6. 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

    1. Let’s say you want to make jb_agent2 passive. The easiest way is probably setting UVM_PASSIVE from a test that extends jelly_bean_base_test.

      class your_test extends jelly_bean_base_test;
         function void build_phase( uvm_phase phase );
            ...
            jb_agent_cfg2.active = UVM_PASSIVE;
         endfunction
         ...
      endclass

      But if you want to use the uvm_config_db, you could do something like this:

      class your_test extends jelly_bean_base_test;
         function void build_phase( uvm_phase phase );
            ...
            uvm_config_db#( uvm_active_passive_enum )::set( .cntxt( this ), 
                                                            .inst_name( "jb_env.jb_agent2" ), 
                                                            .field_name( "active" ), 
                                                            .value( UVM_PASSIVE ) );
         endfunction
         ...
      endclass
       
      class jelly_bean_agent extends uvm_agent;
         uvm_active_passive_enum active; // add this
       
         function void build_phase( uvm_phase phase );
            ...
            if ( ! uvm_config_db#( uvm_active_passive_enum )::get( .cntxt( this ), 
                                                                   .inst_name( "" ), 
                                                                   .field_name( "active" ), 
                                                                   .value( active ) ) ) begin
               `uvm_error( get_name(), "active field not found" )
            end 
         endfunction
         ...
      endclass
      1. 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…

            jb_env_cfg.has_jb_agent2 = 0
        

        … it work

        I tried the second method like that

            uvm_config_db#(bit)::set(.cntxt(this), .inst_name("jb_env_cfg"), .field_name("has_jb_agent2"), .value(0))
        

        or

            uvm_config_db#(bit)::set(.cntxt(this), .inst_name(""), .field_name("jb_env_cfg.has_jb_agent2"), .value(0))
        

        … either of them do not work

        I also tried another way… build a new config class and change the value inside, like below…

            class new_jelly_bean_env_config extends jelly_bean_env_config;
                bit jb_env_cfg.has_jb_agent2 =0;
                ....
            endclass
        

        and write below in test’s build phase

            jelly_bean_env_config::type_id::set_type_override(new_jelly_bean_env_config::get_type());
        

        … it does not work either

        Could you tell me what’s the reason will cause it does not work?

        1. Have you tried this?

          uvm_config_db#(bit)::set(.cntxt(this), .inst_name("*"), .field_name("has_jb_agent2"), .value(0));

          If it works, then most likely there is a discrepancy between the instance path of set() and the instance path of get(). If you can paste how you get(), I might be able to help more.

          1. 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?

          2. From what class do you call get()? Is the class a part of the component hierarchy of your test that calls set()?
            It does not matter whether the jelly_bean_env_cfg is extended from the uvm_component or not. What it matters is that cntxt + inst_name has to match between set() and get().

          3. 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…

            module my_uvm_top
            ...
            my_if     pif_0(.clk(pll_clk),    .reset(reset_n));
            my_if     pif_1(.clk(pll_clk),    .reset(reset_n));
            initial begin
                uvm_config_db#(virtual my_if) ::set(.cntxt(null), .inst_name("uvm_test_top"), .field_name("pif_0"), .value(pif_0));
                uvm_config_db#(virtual my_if) ::set(.cntxt(null), .inst_name("uvm_test_top"), .field_name("pif_1"), .value(pif_1));
                run_test();
            end
            ....
            endmodule
            
            module my_uvm_top2
            ...
            my_if     hst_pif_0(.clk(pll_clk),    .reset(reset_n));
            my_if     hst_pif_1(.clk(pll_clk),    .reset(reset_n));
            my_if     dev_pif_0(.clk(pll_clk),    .reset(reset_n));
            my_if     dev_pif_1(.clk(pll_clk),    .reset(reset_n));
            initial begin
                uvm_config_db#(virtual my_if) ::set(.cntxt(null), .inst_name("uvm_test_top"), .field_name("hst_pif_0"), .value(hst_pif_0));
                uvm_config_db#(virtual my_if) ::set(.cntxt(null), .inst_name("uvm_test_top"), .field_name("hst_pif_1"), .value(hst_pif_1));
                uvm_config_db#(virtual my_if) ::set(.cntxt(null), .inst_name("uvm_test_top"), .field_name("dev_pif_0"), .value(dev_pif_0));
                uvm_config_db#(virtual my_if) ::set(.cntxt(null), .inst_name("uvm_test_top"), .field_name("dev_pif_1"), .value(dev_pif_1));
                run_test();
            end
            ....
            endmodule
            
            class my_env_config extends uvm_object; 
                `uvm_object_utils(my_env_config)  
                bit                     has_tx_agent       = 1;             
                bit                     has_rx_agent       = 1;             
                bit                     has_hst_tx_agent   = 1;             
                bit                     has_hst_rx_agent   = 1;             
                bit                     has_dev_tx_agent   = 1;             
                bit                     has_dev_rx_agent   = 1;             
                bit                     has_tx_sb          = 1;             
                bit                     has_rx_sb          = 1;             
                bit                     has_hst_tx_sb      = 1;             
                bit                     has_hst_rx_sb      = 1;             
                bit                     has_dev_tx_sb      = 1;             
                bit                     has_dev_rx_sb      = 1;             
            
                my_tx_agent_config   tx_agent_cfg[];
                my_rx_agent_config   rx_agent_cfg[];
                my_tx_agent_config   hst_tx_agent_cfg[];
                my_rx_agent_config   hst_rx_agent_cfg[];
                my_tx_agent_config   dev_tx_agent_cfg[];
                my_rx_agent_config   dev_rx_agent_cfg[];
            
                function new (string name = "");    
                    super.new(name);
                endfunction : new
            endclass : my_env_config
            
            class my_test_base extends uvm_test
            ...
            virtual function void build_phase(uvm_phase phase);
               super.build_phase(phase);
               my_env_cfg = my_env_config::type_id::create("my_env_cfg", this);
               my_tx_cfg0 = my_tx_agent_config::type_id::create("my_tx_cfg0",this);
               my_tx_cfg1 = my_tx_agent_config::type_id::create("my_tx_cfg1",this);
               my_rx_cfg0 = my_rx_agent_config::type_id::create("my_rx_cfg0",this);
               my_rx_cfg1 = my_rx_agent_config::type_id::create("my_rx_cfg1",this);
            
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("pif_0"), .value(my_tx_cfg0.pif))) begin
                 `uvm_error("my_test_base", "pif_0 not found")
               end                
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("pif_1"), .value(my_tx_cfg1.pif))) begin
                 `uvm_error("my_test_base", "pif_1 not found")
               end                
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("pif_0"), .value(my_rx_cfg0.pif))) begin
                 `uvm_error("my_test_base", "pif_0 not found")
               end
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("pif_1"), .value(my_rx_cfg1.pif))) begin
                 `uvm_error("my_test_base", "pif_1 not found")
               end
               my_env_cfg.tx_agent_cfg = new[2]; 
               my_env_cfg.rx_agent_cfg = new[2]; 
               my_env_cfg.tx_agent_cfg[0] = my_tx_cfg0;
               my_env_cfg.tx_agent_cfg[1] = my_tx_cfg1;
               my_env_cfg.rx_agent_cfg[0] = my_rx_cfg0;
               my_env_cfg.rx_agent_cfg[1] = my_rx_cfg1;
               uvm_config_db#(my_env_config)::set(.cntxt(this), .inst_name("*"), .field_name("my_env_cfg"), .value(my_env_cfg));
            end
            ...
            endclass
            
            class my_test_base2 extends uvm_test
            ...
            virtual function void build_phase(uvm_phase phase);
               super.build_phase(phase);
               my_env_cfg = my_env_config::type_id::create("my_env_cfg", this);
               my_hst_tx_cfg0 = my_tx_agent_config::type_id::create("my_hst_tx_cfg0",this);
               my_hst_tx_cfg1 = my_tx_agent_config::type_id::create("my_hst_tx_cfg1",this);
               my_hst_rx_cfg0 = my_rx_agent_config::type_id::create("my_hst_rx_cfg0",this);
               my_hst_rx_cfg1 = my_rx_agent_config::type_id::create("my_hst_rx_cfg1",this);
               my_dev_tx_cfg0 = my_tx_agent_config::type_id::create("my_dev_tx_cfg0",this);
               my_dev_tx_cfg1 = my_tx_agent_config::type_id::create("my_dev_tx_cfg1",this);
               my_dev_rx_cfg0 = my_rx_agent_config::type_id::create("my_dev_rx_cfg0",this);
               my_dev_rx_cfg1 = my_rx_agent_config::type_id::create("my_dev_rx_cfg1",this);
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("hst_pif_0"), .value(my_hst_tx_cfg0.pif))) begin
                 `uvm_error("my_test_base", "pif_0 not found")
               end                
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("hst_pif_1"), .value(my_hst_tx_cfg1.pif))) begin
                 `uvm_error("my_test_base", "pif_1 not found")
               end        
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("hst_pif_0"), .value(my_hst_rx_cfg0.pif))) begin
                 `uvm_error("my_test_base", "pif_0 not found")
               end                
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("hst_pif_1"), .value(my_hst_rx_cfg1.pif))) begin
                 `uvm_error("my_test_base", "pif_1 not found")
               end               
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("dev_pif_0"), .value(my_dev_tx_cfg0.pif))) begin
                 `uvm_error("my_test_base", "pif_0 not found")
               end
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("dev_pif_1"), .value(my_dev_tx_cfg1.pif))) begin
                 `uvm_error("my_test_base", "pif_1 not found")
               end
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("dev_pif_0"), .value(my_dev_rx_cfg0.pif))) begin
                 `uvm_error("my_test_base", "pif_0 not found")
               end
               if ( ! uvm_config_db#(virtual my_if)::get(.cntxt(this), .inst_name(""), .field_name("dev_pif_1"), .value(my_dev_rx_cfg1.pif))) begin
                 `uvm_error("my_test_base", "pif_1 not found")
               end
               my_env_cfg.hst_tx_agent_cfg = new[2]; 
               my_env_cfg.hst_rx_agent_cfg = new[2]; 
               my_env_cfg.dev_tx_agent_cfg = new[2]; 
               my_env_cfg.dev_rx_agent_cfg = new[2]; 
               my_env_cfg.hst_tx_agent_cfg[0] = my_hst_tx_cfg0;
               my_env_cfg.hst_tx_agent_cfg[1] = my_hst_tx_cfg1;
               my_env_cfg.hst_rx_agent_cfg[0] = my_hst_rx_cfg0;
               my_env_cfg.hst_rx_agent_cfg[1] = my_hst_rx_cfg1;
               my_env_cfg.dev_tx_agent_cfg[0] = my_dev_tx_cfg0;
               my_env_cfg.dev_tx_agent_cfg[1] = my_dev_tx_cfg1;
               my_env_cfg.dev_rx_agent_cfg[0] = my_dev_rx_cfg0;
               my_env_cfg.dev_rx_agent_cfg[1] = my_dev_rx_cfg1;
               uvm_config_db#(my_env_config)::set(.cntxt(this), .inst_name("*"), .field_name("my_env_cfg"), .value(my_env_cfg));
            end
            ...
            endclass
            
            class my_test_00 extends my_test_base
            ...
            virtual function void build_phase(uvm_phase phase);
                super.build_phase(phase);
                begin
                      uvm_config_db#(bit)::set(.cntxt(this), .inst_name("*"), .field_name("has_hst_tx_agent"), .value(0));
                      uvm_config_db#(bit)::set(.cntxt(this), .inst_name("*"), .field_name("has_hst_rx_agent"), .value(0));
                      uvm_config_db#(bit)::set(.cntxt(this), .inst_name("*"), .field_name("has_dev_tx_agent"), .value(0));
                      uvm_config_db#(bit)::set(.cntxt(this), .inst_name("*"), .field_name("has_dev_rx_agent"), .value(0));
                end
            endfunction
            ...
            endclass
            
            class my_test2_00 extends my_test_base2
            ...
            virtual function void build_phase(uvm_phase phase);
                super.build_phase(phase);
                begin
                      uvm_config_db#(bit)::set(.cntxt(this), .inst_name("*"), .field_name("has_tx_agent"), .value(0));
                      uvm_config_db#(bit)::set(.cntxt(this), .inst_name("*"), .field_name("has_rx_agent"), .value(0));
                end
            endfunction
            ...
            endclass
            
          4. Calling uvm_config_db#(bit)::set() merely stores a value to the configuration database. It does not automatically set the value to the my_env_cfg. You need to call get() to retrieve the value. However, to set the value of the has_hst_tx_agent, it is more natural to do my_env_cfg.has_hst_tx_agent = 0; like you did.

  7. • 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

  8. 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

    1. If you set the inst_name more specifically and change the field_name to "example_vif" in the top module, you should be OK.

      uvm_config_db#( virtual example_if )::set( uvm_root::get(), “Env.agent[0]*, “example_vif”, i_example1_vif );
      uvm_config_db#( virtual example_if )::set( uvm_root::get(), “Env.agent[1]*, “example_vif”, i_example2_vif );
      uvm_config_db#( virtual example_if )::set( uvm_root::get(), “Env.agent[2]*, “example_vif”, i_example3_vif );
      uvm_config_db#( virtual example_if )::set( uvm_root::get(), “Env.agent[3]*, “example_vif”, i_example4_vif );
  9. Hi Keisuke,

    In jelly_bean_scoreboard, Why we need uvm_table_printer? what is the use of uvm_table_printer.

    Thanks,
    Sharath HV

    1. I used the uvm_table_printer to print a jb_tx in a tabular format when sprint() is called (please see jelly_bean_scoreboard in Environment). But you don’t have to use the uvm_table_printer. For example, you can do jb_tx.convert2string() to print the information of jb_tx if you define the function.

  10. 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

Leave a Reply