Last Updated: September 9, 2013
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.
::type_id
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.
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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | // 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. // Assuming UVM_OBJECT_MUST_HAVE_CONSTRUCTOR 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(); endfunction virtual function uvm_object_wrapper get_object_type(); return type_id::get(); endfunction // | | // | +--> `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; endfunction // | | // | +--> `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; endfunction // | | // | +--> `uvm_field_utils_begin(T) // | // V function void __m_uvm_field_automation( uvm_object tmp_data__, int what__, string str__ ); begin 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 return; end else __current_scopes=__m_uvm_status_container.m_uvm_cycle_scopes; end 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 end endfunction endclass: jelly_bean_transaction |
As you see on the line 17, the type_id is nothing but a uvm_object_registry type.

::create()
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.

- The
one_jelly_bean_sequencecalls thejelly_bean_transaction::type_id::create()(steps 1 and 2) - The
create()static function calls thecreate_object_by_type()ofuvm_factoryclass (step 3) - The
uvm_factorycallsfind_override_by_type()to check whether thejelly_bean_transactiontype is overridden by another class (step 4) - If the
jelly_bean_transactiontype is not overridden, then theuvm_factorycalls thecreate_object()of theuvm_object_registryof thejelly_bean_transactionclass (step 5). We will look at an overridden case later. - The
uvm_object_registryclass creates ajelly_bean_transactionobject by callingnew()(step 6) - The
jelly_bean_transactionobject is returned to theone_jelly_bean_sequence(step 7)
The class diagram of the factory-related classes is shown below.

Type Override
In Tasting, the jelly_bean_test class overrode the jelly_bean_transaction with a sugar_free_jelly_bean_transaction by doing:
jelly_bean_transaction::type_id::set_type_override(sugar_free_jelly_bean_transaction::get_type()); |
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_testcalls thesugar_free_jelly_bean_transaction::get_type()to get theuvm_object_registryof thesugar_free_jelly_bean_transaction(steps 1, 2, and 3) - Secondly, the
jelly_bean_testcalls theset_type_override(), which in turn calls theset_type_override_by_type()of theuvm_factory(steps 4 and 5) - Lastly, the
uvm_factorycreates auvm_factory_overrideobject 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_sequencecalls thejelly_bean_transaction::type_id::create()(steps 8 and 9) - The
create()function calls thecreate_object_by_type()of theuvm_factory(step 10) - The
uvm_factoryrecursively callsfind_override_by_type()to determine the final type of thejelly_bean_transaction(step 11) - In our scenario, the
jelly_bean_transactionwas overridden by thesugar_free_jelly_bean_transaction. Therefore, theuvm_factorycalls thecreate_object()of theuvm_object_registryof thesugar_free_jelly_bean_transaction(step 12) - The
uvm_object_registrycreates asugar_free_jelly_bean_transactionby callingnew()(step 13) - The
sugar_free_jelly_bean_transactionobject 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.

How do you know and object received is from a certain type. i.e. how to know the actual object type even the object was type-casted?
I am not sure if I fully understand your question, but you could use
$typename( object_handle )system function to check the type of an object. The$typenamereturns a string.Hi Keisuke,
get_type():
“Returns the type-proxy (wrapper) for this object. The uvm_factory’s type-based override
and creation methods take arguments of uvm_object_wrapper.”
What does it mean type-proxy/wrapper of an object ? What is its return value here?
Similary,
get_object_type() & get_object_name() ??
I believe,
get_object_name(), returns -> jelly_bean_transaction (which is the name of the class).
Please can you explain/give a simple example.
Thank You in Advance..!
In UVM, we usually don’t call
newto create a new object.Instead, we ask the wrapper (proxy) of the class to call
new. The UVM factory selects which wrapper to use based on the type/instance override.The
get_typereturns the wrapper instance. Actually there is only one instance per a wrapper type (it is called the singleton). In our case, thejelly_bean_transaction::get_type()returns the singleton object oftype_idtype, which isuvm_object_registry#(jelly_bean_transaction, "jelly_bean_transaction")type.The
get_object_typealso returns the wrapper instance. The difference between theget_typeand theget_object_typeis that the former is a static function and the latter is a non-static function. If you use the`uvm_object_utilsmacro, the implementations of the two functions are the same.The
get_type_namereturns the name of an object type (I assume you are askingget_type_namebecause I cannot find a function calledget_object_name). In our case, it returns"jelly_bean_transaction".Thank You..!
After some background analysis on wrapper classes, I could understand some of it.
Hi Keisuke,
I want to override two classes that one of them is field of the other class. for example class A includes class B.
And I want to override class A with AA and B with BB.
if I use the override factory to override them, only the class A is override by AA and B would not change.
Do you have any idea how to do that?
Regards,
Yousef
Make sure you create an object of B by calling
create(see line 9 below).You should get this when you run:
You can try it on this EDA Playground.
Hi Keisuke,
I am not quite understand the difference between set_type_override and set_type_override_by_type. Would you please tell what is the difference of them?
I think we also have set_type_override_by_name, I think it can not be used for parameterized class. then what is the usage of it?
Best,
Kevin Chen
To answer your question, I wrote a new article. You can use the
set_type_override_by_namefor a parameterized class, but you have to define your owntype_namevariable andget_type_namefunction.what is the difference between new() and create()?
newis the SystemVerilog function that creates an object.createis a UVM function that eventually calls thenewto create a UVM object.`uvm_object_utils marco includes following function
function uvm_object function create(string name = “”)
When a object is created type_id::create() static function is used. So what is the purpose of above function?
The
createfunction implements the virtual function,create, defined in theuvm_objectclass. The default implementation ofuvm_object::clonefunction calls thiscreate, for example.