UVM工厂用于创建UVM对象和组件。 这篇文章将解释使用jelly_beans的UVM工厂(如您所期望的)并揭示工厂幕后发生了些什么。
::type_id
在Transactions和Sequences中,我们定义了jelly_bean_transaction类。 然后,one_jelly_bean_sequence创建了一个jelly_bean_transaction对象,如下所示:
jb_tx = jelly_bean_transaction::type_id::create( .name( "jb_tx" ) );
这是一个众所周知的UVM创建对象的习惯用法,但是这个:: type_id事物是从哪里来的? type_id由jelly_bean_transaction类中使用的`uvm_object_utils(jelly_bean_transaction)宏定义。 uvm_object_utils()宏被进一步细分为以下子宏:
- `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()
下面的伪代码显示了宏如何扩展。
// 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
正如你在第17行看到的那样,type_id只不过是一个uvm_object_registry类型。
::create()
现在我们知道type_id是什么,所以让我们看看type_id后面的:: create()。如果您查看UVM源代码src/base/uvm_registry.svh,您会发现create()是uvm_object_registry类的静态函数。以下序列图显示one_jelly_bean_sequence如何创建jelly_bean_transaction。
- one_jelly_bean_sequence调用jelly_bean_transaction :: type_id :: create()(步骤1和2)
- create()静态函数调用uvm_factory类的create_object_by_type()(步骤3)
- uvm_factory调用find_override_by_type()来检查jelly_bean_transaction类型是否被另一个类覆盖(步骤4)
- 如果未覆盖jelly_bean_transaction类型,则uvm_factory会调用jelly_bean_transaction类的uvm_object_registry的create_object()(步骤5)。稍后我们会看一个被覆盖的案例。
- uvm_object_registry类通过调用new()来创建一个jelly_bean_transaction对象(步骤6)
- jelly_bean_transaction对象返回到one_jelly_bean_sequence(步骤7)
下面显示了工厂相关类的类图。
Type Override
在Tasting中,jelly_bean_test类通过执行以下操作覆盖了使用sugar_free_jelly_bean_transaction的jelly_bean_transaction:
jelly_bean_transaction::type_id::set_type_override(sugar_free_jelly_bean_transaction::get_type());
正如我们前面看到的,jelly_bean_transaction::type_id是一个uvm_object_registry类型。 set_type_override()是uvm_object_registry的另一个静态函数。下面的序列图显示了set_type_override()如何覆盖类型。覆盖一个类型涉及以下步骤:
- 首先,jelly_bean_test调用sugar_free_jelly_bean_transaction :: get_type()来获取sugar_free_jelly_bean_transaction的uvm_object_registry(步骤1,2和3)
- 其次,jelly_bean_test调用set_type_override(),然后调用uvm_factory的set_type_override_by_type()(步骤4和5)
- 最后,uvm_factory创建一个uvm_factory_override对象并将其放入一个覆盖队列(步骤6和7)
然后,当one_jelly_bean_sequence创建jelly_bean_transaction时,将执行以下步骤:
- one_jelly_bean_sequence调用jelly_bean_transaction :: type_id :: create()(步骤8和9)
- create()函数调用uvm_factory的create_object_by_type()(步骤10)
- uvm_factory递归调用find_override_by_type()来确定jelly_bean_transaction的最终类型(步骤11)
- 在我们的场景中,jelly_bean_transaction被sugar_free_jelly_bean_transaction覆盖。因此,uvm_factory调用sugar_free_jelly_bean_transaction的uvm_object_registry的create_object()(步骤12)
- uvm_object_registry通过调用new()来创建一个sugar_free_jelly_bean_transaction(步骤13)
- 返回上述步骤创建的sugar_free_jelly_bean_transaction对象(步骤14)
请注意,one_jelly_bean_sequence调用jelly_bean_transaction::type_id::create(),而不是sugar_free_jelly_bean_transaction :: type_id :: create()来创建无糖jelly bean。工厂负责制造什么类型的软糖。
我希望你现在对UVM工厂有更好的了解。
