Welcome ! This website will help YOU (recent graduates/professionals) learn verification languages like SystemVerilog and UVM. Register for free and access more content !

To create an instance of a class object, we use new() method in SystemVerilog, which can also be used in UVM. But, UVM has introduced the factory concept which essentially means that you can modify or substitute the nature of the components created by the factory without making changes to the testbench. Say, you have written two driver classes, and the environment uses only one of them. By registering both the drivers with the factory, you can ask the factory to substitute the existing driver in environment with the other type. The code needed to achieve this is minimal, and can be written in the test.

factory

So, you have to register all the components that you make with the factory using `uvm_component_utils or `uvm_object_utils, and to make it possible to override a component, you have to use the ::type_id::create() method instead of new() whenever you create an object. See the following example.

 
class my_driver extends uvm_driver;
  `uvm_component_utils (my_driver)
  ...
endclass
 
class my_env extends uvm_env;
  `uvm_component_utils (my_env)
 
  my_driver drv0;
  ...
  virtual function void build_phase (uvm_phase phase);
    super.build_phase (phase);
    drv0 = my_driver::type_id::create ("drv0", this);
  endfunction
endclass
 

Then, you can override these later within the environment/test by calling one of the methods below. Remember that you can print out the configuration using factory.print() within the test.

 
// Override all the objects of a particular type
 
set_type_override_by_type ( uvm_object_wrapper original_type, 
                            uvm_object_wrapper override_type, 
                            bit replace=1);
 
set_type_override_by_name ( string original_type_name,
                            string override_type_name,
                            bit replace=1);
 
// Override a type within a particular instance
 
set_inst_override_by_type (uvm_object_wrapper original_type,
                           uvm_object_wrapper override_type,
                           string full_inst_path);
 
set_inst_override_by_name (string original_type_name,
                           string override_type_name,
                           string full_inst_path);
 

Example

factory override default configuration

To illustrate the example of a factory override, we'll create an environment as shown above with a couple of different drivers, sequences, and data object types. The image shown above is the default configuration.

This is a looong example. Skip to the end by clicking here

Components:
- Agents 
	- my_agent
		1. my_agent_v2 (child)
- Drivers
	base_driver 
	 	1. eth_driver (child)
		2. spi_driver (child)
- Sequencer - my_seqeuncer
- Sequences
	- base_sequence
		1. seq1 (child)
		2. seq2 (child)
		3. seq3 (child)
- Data
	- eth_packet
		- eth_v2_packet (child)

Sequencer within m_agnt2 operate on seq3, while the other two operate on seq1 by default.
example inheritance diagram

Let us first define a base data packet and derive a child class for it.

 
//------------------ eth_packet-----------------------------------
class eth_packet extends uvm_sequence_item;
   `uvm_object_utils (eth_packet)
 
  ...
 
   function new (string name = "eth_packet");
      super.new (name);
      `uvm_info (get_type_name(), "Packet created", UVM_MEDIUM)
   endfunction
endclass   
 
//------------------ eth_v2_packet-----------------------------------
class eth_v2_packet extends eth_packet; 
   `uvm_object_utils (eth_v2_packet)
 
   ...
 
   function new (string name = "eth_v2_packet");
      super.new (name);
   endfunction
endclass  
 

Now let us create a base driver class and extend two more driver classes eth_driver and spi_driver. To show the effect of a factory override, we'll keep these classes to have minimum data and methods.

 
//------------------ base_driver-----------------------------------
 
class base_driver #(type T=eth_packet) extends uvm_driver;
   `uvm_component_utils (base_driver #(T))
 
   T pkt;
 
   function new (string name, uvm_component parent);
      super.new (name, parent);
   endfunction
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      pkt = T::type_id::create ("pkt0");
   endfunction
 
   virtual task run_phase (uvm_phase phase);
      super.run_phase (phase);
      `uvm_info (get_type_name(), $sformatf("Driver running ...with packet of type : %s", pkt.get_type_name()), UVM_MEDIUM)
   endtask
 
endclass
 
//----------------- eth_driver-----------------------------------
 
class eth_driver #(type T=eth_packet) extends base_driver #(T);
   `uvm_component_utils (eth_driver #(T))
 
   function new (string name, uvm_component parent);
      super.new (name, parent);
   endfunction
endclass
 
//----------------- spi_driver-----------------------------------
 
class spi_driver #(type T=eth_packet) extends base_driver #(T); 
   `uvm_component_utils (spi_driver #(T))
 
   function new (string name, uvm_component parent);
      super.new (name, parent);
   endfunction
endclass 
 

Coming to the sequences which will be executed by our sequencer

 
//----------------- base_sequence-----------------------------------
class base_sequence extends uvm_sequence;
  `uvm_object_utils (base_sequence)
endclass
 
//----------------- seq1 -------------------------------------------
class seq1 extends base_eth_sequence;
   `uvm_object_utils (seq1)
  ...
endclass
 
//----------------- seq2 -------------------------------------------
class seq2 extends base_eth_sequence;
   `uvm_object_utils (seq2)
   ...
endclass
 
//----------------- seq3 -------------------------------------------
class seq3 extends base_eth_sequence;
   `uvm_object_utils (seq3)
  ...
endclass
 

We'll create two agents as described below.

 
//----------------- my_agent -------------------------------------------
class my_agent extends uvm_agent;
   `uvm_component_utils (my_agent)
 
   base_driver    m_drv0;
   my_sequencer   m_seqr0;
 
   function new (string name, uvm_component parent);
      super.new (name, parent);
   endfunction
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      m_drv0 = base_driver::type_id::create ("m_drv0", this);
      m_seqr0 = my_sequencer::type_id::create ("m_seqr0", this);
   endfunction
 
   virtual function void connect_phase (uvm_phase phase);
      super.connect_phase (phase);
      m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);
   endfunction
endclass
 
//----------------- my_agent_v2 -------------------------------------------
class my_agent_v2 extends uvm_agent;
   `uvm_component_utils (my_agent_v2)
 
   eth_driver     m_drv0;
   my_sequencer   m_seqr0;
 
   function new (string name, uvm_component parent);
      super.new (name, parent);
   endfunction
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      m_drv0 = eth_driver::type_id::create ("m_drv0", this);
      m_seqr0 = my_sequencer::type_id::create ("m_seqr0", this);
   endfunction
 
   virtual function void connect_phase (uvm_phase phase);
      super.connect_phase (phase);
      m_drv0.seq_item_port.connect (m_seqr0.seq_item_export);
   endfunction
endclass
 

Note that my_agent has base_driver, while my_agent_v2 contains eth_driver. All drivers and sequencers are instantiated within the build_phase () and connected in the connect_phase().

The top container "my_env" is still left.

 
class my_env extends uvm_env ;
   `uvm_component_utils (my_env)
 
   my_agent       m_agnt0; 
   my_agent       m_agnt1; 
   my_agent_v2    m_agnt2;
 
   function new (string name, uvm_component parent);
      super.new (name, parent);
   endfunction : new
 
   virtual function void build_phase (uvm_phase phase);
      super.build_phase (phase);
      m_agnt0 = my_agent::type_id::create ("m_agnt0", this);
      m_agnt1 = my_agent::type_id::create ("m_agnt1", this);
      m_agnt2 = my_agent_v2::type_id::create ("m_agnt2", this);
   endfunction : build_phase
endclass : my_env
 

We have put our components into boxes, and arranged everything. It's time to write the test, and this is where factory override helps. We'll be able to substitute drivers, data packets and sequences by calling a few factory methods.

factory override configuration

Finally !

 
   class feature_test extends base_test;
      `uvm_component_utils (feature_test)
 
      function new (string name, uvm_component parent = null);
         super.new (name, parent);
      endfunction 
 
      virtual function void build_phase (uvm_phase phase);
         super.build_phase (phase); 
 
`ifdef PKT_OVERRIDE
         // Substitute all eth_packets with eth_v2_packet
         set_type_override_by_type (eth_packet::get_type(), eth_v2_packet::get_type());
`endif
 
 
 
// These are the three different styles to override something
 
`ifdef DRV_STYLE1
         // Substitute all instances of base_driver with driver2 
         set_type_override_by_type (base_driver::get_type(), spi_driver::get_type());
`elsif DRV_STYLE2
         // Substitute only eth_driver in agnt2 with spi_driver - by calling the component to be replaced method
         eth_driver::type_id::set_inst_override (spi_driver::get_type(), "m_top_env.m_agnt2.m_drv0", this);
`elsif DRV_STYLE3
         // Substitute base_driver only in agnt0 - by calling the factory method
         factory.set_inst_override_by_type (base_driver::get_type(), eth_driver::get_type(), {get_full_name(), ".m_top_env.m_agnt0.*"});
`endif
 
 
 
// Trying to override a sequence
 
`ifdef SEQ_TYPE
         // Substitute seq1 with seq2
         set_type_override_by_type (seq1::get_type(), seq3::get_type());
`elsif SEQ_INST
         // Substitute seq1 with seq2 only for agnt1
         set_inst_override_by_type ("m_top_env.m_agnt1.m_seqr0.*", seq1::get_type(), seq2::get_type());
`else
`endif
         factory.print();
      endfunction
      // Enter test code for feature here
   endclass
 


Simulation Results

These results are for running the test with defines PKT_OVERRIDE, DRV_STYLE3 and SEQ_INST. Also, note that the factory configuration is shown in the log.

----------------------------------------------------------------
CDNS-UVM-1.1d (14.10-s013)
(C) 2007-2013 Mentor Graphics Corporation
(C) 2007-2013 Cadence Design Systems, Inc.
(C) 2006-2013 Synopsys, Inc.
(C) 2011-2013 Cypress Semiconductor Corp.
----------------------------------------------------------------
UVM_INFO @ 0: reporter [RNTST] Running test feature_test...

#### Factory Configuration (*)

Instance Overrides:

  Requested Type    Override Path                             Override Type
  ----------------  ----------------------------------------  ---------------
  base_driver #(T)  uvm_test_top.m_top_env.m_agnt0.*          eth_driver #(T)
  seq1              uvm_test_top.m_top_env.m_agnt1.m_seqr0.*  seq2

Type Overrides:

  Requested Type    Override Type
  ----------------  ----------------------------------------
  eth_packet        eth_v2_packet

All types registered with the factory: 51 total
(types without type names will not be printed)

  Type Name
  ---------
  base_driver #(T)
  base_eth_sequence
  base_test
  eth_driver #(T)
  eth_packet
  eth_v2_packet
  feature_test
  my_agent
  my_agent_v2
  my_env
  my_sequencer
  reg_test
  seq1
  seq2
  seq3
(*) Types with no associated type name will be printed as 

####

UVM_INFO ./tb/my_pkg.sv(45) @ 0: reporter@@eth_v2_packet [eth_v2_packet] Packet created
UVM_INFO ./tb/my_pkg.sv(45) @ 0: reporter@@eth_v2_packet [eth_v2_packet] Packet created
UVM_INFO ./tb/my_pkg.sv(45) @ 0: reporter@@eth_v2_packet [eth_v2_packet] Packet created
UVM_INFO @ 0: reporter [UVMTOP] UVM testbench topology:
--------------------------------------------------------------
Name                       Type                    Size  Value
--------------------------------------------------------------
uvm_test_top               feature_test            -     @2657
  m_top_env                my_env                  -     @218
    m_agnt0                my_agent                -     @2772
      m_drv0               eth_driver #(T)         -     @2770
        rsp_port           uvm_analysis_port       -     @2963
        seq_item_port      uvm_seq_item_pull_port  -     @2912
      m_seqr0              my_sequencer            -     @2996
        rsp_export         uvm_analysis_export     -     @3054
        seq_item_export    uvm_seq_item_pull_imp   -     @3602
        arbitration_queue  array                   0     -
        lock_queue         array                   0     -
        num_last_reqs      integral                32    'd1
        num_last_rsps      integral                32    'd1
    m_agnt1                my_agent                -     @2751
      m_drv0               base_driver #(T)        -     @3676
        rsp_port           uvm_analysis_port       -     @3773
        seq_item_port      uvm_seq_item_pull_port  -     @3725
      m_seqr0              my_sequencer            -     @3754
        rsp_export         uvm_analysis_export     -     @3859
        seq_item_export    uvm_seq_item_pull_imp   -     @4399
        arbitration_queue  array                   0     -
        lock_queue         array                   0     -
        num_last_reqs      integral                32    'd1
        num_last_rsps      integral                32    'd1
    m_agnt2                my_agent_v2             -     @2802
      m_drv0               eth_driver #(T)         -     @4455
        rsp_port           uvm_analysis_port       -     @4553
        seq_item_port      uvm_seq_item_pull_port  -     @4505
      m_seqr0              my_sequencer            -     @3803
        rsp_export         uvm_analysis_export     -     @4639
        seq_item_export    uvm_seq_item_pull_imp   -     @5179
        arbitration_queue  array                   0     -
        lock_queue         array                   0     -
        num_last_reqs      integral                32    'd1
        num_last_rsps      integral                32    'd1
--------------------------------------------------------------

UVM_INFO ./tb/my_pkg.sv(94) @ 0: uvm_test_top.m_top_env.m_agnt2.m_drv0 [eth_driver #(T)] Driver running ...with packet of type : eth_v2_packet
UVM_INFO ./tb/my_pkg.sv(94) @ 0: uvm_test_top.m_top_env.m_agnt1.m_drv0 [base_driver #(T)] Driver running ...with packet of type : eth_v2_packet
UVM_INFO ./tb/my_pkg.sv(94) @ 0: uvm_test_top.m_top_env.m_agnt0.m_drv0 [eth_driver #(T)] Driver running ...with packet of type : eth_v2_packet
UVM_INFO ./tb/my_pkg.sv(278) @ 0: uvm_test_top.m_top_env.m_agnt2.m_seqr0@@seq3 [seq3] Executing pre_body
UVM_INFO ./tb/my_pkg.sv(250) @ 0: uvm_test_top.m_top_env.m_agnt1.m_seqr0@@seq1 [seq2] Executing pre_body
UVM_INFO ./tb/my_pkg.sv(282) @ 0: uvm_test_top.m_top_env.m_agnt2.m_seqr0@@seq3 [SEQ3] Starting seq3
UVM_INFO ./tb/my_pkg.sv(255) @ 0: uvm_test_top.m_top_env.m_agnt1.m_seqr0@@seq1 [SEQ2] Starting seq2
UVM_INFO ./tb/my_pkg.sv(232) @ 0: uvm_test_top.m_top_env.m_agnt0.m_seqr0@@seq1 [SEQ1] Starting seq1
UVM_INFO ./tb/my_pkg.sv(284) @ 10000: uvm_test_top.m_top_env.m_agnt2.m_seqr0@@seq3 [SEQ3] Ending seq3
UVM_INFO ./tb/my_pkg.sv(257) @ 10000: uvm_test_top.m_top_env.m_agnt1.m_seqr0@@seq1 [SEQ2] Ending seq2
UVM_INFO ./tb/my_pkg.sv(234) @ 10000: uvm_test_top.m_top_env.m_agnt0.m_seqr0@@seq1 [SEQ1] Ending seq1
UVM_INFO ./tb/my_pkg.sv(288) @ 10000: uvm_test_top.m_top_env.m_agnt2.m_seqr0@@seq3 [seq3] Executing post_body
UVM_INFO ./tb/my_pkg.sv(262) @ 10000: uvm_test_top.m_top_env.m_agnt1.m_seqr0@@seq1 [seq2] Executing post_body
UVM_INFO ./tb/my_pkg.sv(292) @ 10000: uvm_test_top.m_top_env.m_agnt2.m_seqr0@@seq3 [seq3] Executing post_start

--- UVM Report catcher Summary ---

Was this article helpful ?

We use cookies to personalize content and ads, to provide social media features and to analyze our traffic. You consent to our cookies if you continue to use our website. To find out more about the cookies we use and how to delete them, see our privacy policy.

  I accept cookies from this site.
Agree
EU Cookie Directive plugin by www.channeldigital.co.uk