UVM Tutorial for Candy Lovers – 8. Configurations

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

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

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

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

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页