UVM Tutorial for Candy Lovers – 10. Inside Candy Factory

UVM factory is used to create UVM objects and components. This post will explain the UVM factory using jelly beans (as you expected) and reveal what happens behind the scenes in the factory.


In Transactions and Sequences, we defined the jelly_bean_transaction class. Then the one_jelly_bean_sequence created a jelly_bean_transaction object as follows:

jb_tx = jelly_bean_transaction::type_id::create( .name( "jb_tx" ) );

This is a well-known idiom of the UVM to create an object, but where does this ::type_id thing come from? The type_id is defined by `uvm_object_utils(jelly_bean_transaction) macro used in the jelly_bean_transaction class. The `uvm_object_utils() macro is further broken down into the following sub-macros:

  • `uvm_object_utils_begin()
    • `m_uvm_object_registry_internal()
    • `m_uvm_object_create_func()
    • `m_uvm_get_type_name_func()
    • `m_uvm_field_utils_begin()
  • `uvm_object_utils_end()

The following pseudo code shows how the macro is expanded.

// This pseudo code shows how `uvm_object_utils macro is expanded.
// Assuming UVM_NO_DEPRECATED is defined.
// Consequently assuming UVM_NO_REGISTERED_CONVERTER is defined.
class jelly_bean_transaction extends uvm_sequence_item;
   // `uvm_object_utils(T)
   //  |
   //  +--> `uvm_object_utils_begin(T)
   //  |     |
   //  |     +--> `m_uvm_object_registry_internal(T,T)
   //  |     |
   //  V     V
   typedef uvm_object_registry#( jelly_bean_transaction, "jelly_bean_transaction" ) type_id;
   static function type_id get_type();
     return type_id::get();
   virtual function uvm_object_wrapper get_object_type();
     return type_id::get();
   //  |     |
   //  |     +--> `m_uvm_object_create_func(T)
   //  |     |
   //  V     V
   function uvm_object create( string name = "" );
      jelly_bean_transaction tmp;
      if ( name == "" ) tmp = new();
      else              tmp = new( name );
      return tmp;
   //  |     |
   //  |     +--> `m_uvm_get_type_name_func(T)
   //  |     |
   //  V     V
   const static string type_name = "jelly_bean_transaction";
   virtual function string get_type_name();
     return type_name;
   //  |     |
   //  |     +--> `uvm_field_utils_begin(T)
   //  |
   //  V
   function void __m_uvm_field_automation( uvm_object tmp_data__,
					   int what__,
					   string str__ );
         jelly_bean_transaction local_data__; /* Used for copy and compare */
         typedef jelly_bean_transaction ___local_type____;
         string string_aa_key; /* Used for associative array lookups */
         uvm_object __current_scopes[$];
         if ( what__ inside { UVM_SETINT, UVM_SETSTR, UVM_SETOBJ } ) begin
            if ( __m_uvm_status_container.m_do_cycle_check( this ) ) begin
            end else
         super.__m_uvm_field_automation( tmp_data__, what__, str__ );
         /* Type is verified by uvm_object::compare() */
         if ( tmp_data__ != null )
           /* Allow objects in same hierarchy to be copied/compared */
           if ( ! $cast( local_data__, tmp_data__ ) ) return;
   //  |
   //  +--> `uvm_object_utils_end
endclass: jelly_bean_transaction

As you see on the line 17, the type_id is nothing but a uvm_object_registry type.



Now we know what the type_id is, so let’s look at the ::create() that follows the type_id. If you look at the UVM source code, src/base/uvm_registry.svh, you will find that the create() is a static function of the uvm_object_registry class.
The following sequence diagram shows how the one_jelly_bean_sequence creates a jelly_bean_transaction.

Sequence diagram of creating a jelly_bean_transaction

  • The one_jelly_bean_sequence calls the jelly_bean_transaction::type_id::create() (steps 1 and 2)
  • The create() static function calls the create_object_by_type() of uvm_factory class (step 3)
  • The uvm_factory calls find_override_by_type() to check whether the jelly_bean_transaction type is overridden by another class (step 4)
  • If the jelly_bean_transaction type is not overridden, then the uvm_factory calls the create_object() of the uvm_object_registry of the jelly_bean_transaction class (step 5). We will look at an overridden case later.
  • The uvm_object_registry class creates a jelly_bean_transaction object by calling new() (step 6)
  • The jelly_bean_transaction object is returned to the one_jelly_bean_sequence (step 7)

The class diagram of the factory-related classes is shown below.

Class diagram of the factory-related classes

Type Override

In Tasting, the jelly_bean_test class overrode the jelly_bean_transaction with a sugar_free_jelly_bean_transaction by doing:


As we saw earlier, the jelly_bean_transaction::type_id is a uvm_object_registry type. The set_type_override() is another static function of the uvm_object_registry. The sequence diagram below shows how the set_type_override() overrides a type. Overriding a type involves the following steps:

  • Firstly, the jelly_bean_test calls the sugar_free_jelly_bean_transaction::get_type() to get the uvm_object_registry of the sugar_free_jelly_bean_transaction (steps 1, 2, and 3)
  • Secondly, the jelly_bean_test calls the set_type_override(), which in turn calls the set_type_override_by_type() of the uvm_factory (steps 4 and 5)
  • Lastly, the uvm_factory creates a uvm_factory_override object and put it in an override queue (steps 6 and 7)

Then, when the one_jelly_bean_sequence creates a jelly_bean_transaction, the following steps will be executed:

  • The one_jelly_bean_sequence calls the jelly_bean_transaction::type_id::create() (steps 8 and 9)
  • The create() function calls the create_object_by_type() of the uvm_factory (step 10)
  • The uvm_factory recursively calls find_override_by_type() to determine the final type of the jelly_bean_transaction (step 11)
  • In our scenario, the jelly_bean_transaction was overridden by the sugar_free_jelly_bean_transaction. Therefore, the uvm_factory calls the create_object() of the uvm_object_registry of the sugar_free_jelly_bean_transaction (step 12)
  • The uvm_object_registry creates a sugar_free_jelly_bean_transaction by calling new() (step 13)
  • The sugar_free_jelly_bean_transaction object created at the above step is returned (step 14)

Note that the one_jelly_bean_sequence called the jelly_bean_transaction::type_id::create(), not sugar_free_jelly_bean_transaction::type_id::create() to create a sugar-free jelly bean. The factory took care of what type of jelly bean to create.

I hope you have a better idea of the UVM factory by now.

                                                                          Sequence diagram of type override



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