注册宏这部分代码,是uvm factory机制中最具有标志性的代码,当看到这部分代码,最直接的反应应该是,该类在声明时,已经将自己这个类型注册到了工厂中。
对于一个宏,要想真正理解它,必须将宏展开,分析其代表的代码。接下来对`uvm_object_utils()宏,`uvm_object_param_utils()宏,`uvm_component_utils()宏,`uvm_component_param_utils()宏进行拆解
一、uvm_object相关的注册宏
1.1 不带参数的object类的注册
当使用uvm_object_utils时,展开会发现调用了其他的宏。
当调用了`uvm_object_utils(T)时,发生了什么?
`uvm_object_utils(T) // 实际调用的是 `uvm_object_utils_begin(T) `uvm_object_utils_end `uvm_object_utils_begin(T) // 实际调用的是 `m_uvm_object_registory_internal(T) `m_uvm_object_create_func(T) `m_uvm_get_type_name_func(T) `uvm_field_utils_begin(T) 因此,uvm_object_utils实际调用的是 `m_uvm_object_registory_internal(T) `m_uvm_object_create_func(T) `m_uvm_get_type_name_func(T) `uvm_field_utils_begin(T) `uvm_object_utils_end ================================================================= // 当需要使用field automation机制时,`uvm_field_int这些宏要放在 // `uvm_field_utils_begin和`uvm_object_utils_end之间 // 所以就不能使用`uvm_object_utils宏,要使用拆开版本 `uvm_object_utils_begin(T) `uvm_field_int(aaa) `uvm_field_int(bbb) `uvm_object_utils_end1.2 带参数的object类的注册
当调用了`uvm_object_param_utils(T)时,发生了什么?
注意,当使用uvm_object_param_utils_begin(T)时,结尾依旧是`uvm_object_utils_end。而不是`uvm_object_param_utils_end
`uvm_object_param_utils(T) // 实际调用的是 `uvm_object_param_utils_begin(T) `uvm_object_utils_end // 实际调用的是 `m_uvm_object_registory_param(T) `m_uvm_object_create_func(T) `uvm_field_utils_begin(T) `uvm_object_utils_end // 当需要使用field automation机制时,`uvm_field_int这些宏要放在 // `uvm_field_param_utils_begin和`uvm_object_utils_end之间 // 所以就不能使用`uvm_object_param_utils宏,要使用拆开版本 `uvm_object_param_utils_begin(T) `uvm_field_int(aaa) `uvm_field_int(bbb) `uvm_object_utils_end当我们拆开uvm_obejct_utils时,会发现其内部调用了其他的宏,uvm_field_utils_begin和uvm_field_int相关的宏,是和field_automation机制相关的,不在本文讨论范围之内。
- 除此之外,我们还可以发现一个规律,uvm_object_utils宏,用于对非参数化类的注册,其使用了`m_uvm_object_registory_internal(T) , `m_uvm_object_create_func(T) , `m_uvm_get_type_name_func(T) 这三个宏
- 而uvm_object_param_utils宏,用于对参数化类的注册,其使用了`m_uvm_object_registory_param(T) , `m_uvm_object_create_func(T) ,不再使用`m_uvm_get_type_name_func(T)宏。只使用了两个宏,这是两种注册方式的一个显著差别。
而`m_uvm_object_registory_internal(T) , `m_uvm_object_create_func(T) , `m_uvm_get_type_name_func(T) , `m_uvm_object_registory_param(T) 这些宏将涉及到factory机制注册的核心。
1.3 和factory机制注册相关的核心宏
1.3.1 `m_uvm_object_registory_internal(T)
这个宏太关键了,m_uvm_object_registry_internal(T, S) 宏主要负责将当前类与 UVM 工厂(Factory)的代理注册机制进行底层绑定。它通过定义类型别名和静态/虚函数,为该类赋予了工厂创建与类型查询的能力。具体做了以下三件事:
1. 定义内部类型别名 type_id:
- 通过 typedef uvm_object_registry#(T, "S") type_id;创建了一个快捷别名。其中 T 是类名,"S" 是该类的字符串形式。这个 uvm_object_registry 就是核心的代理(Wrapper)类,负责向全局工厂注册和创建对象。
2. 定义静态方法 get_type():
- 提供了一个静态函数 get_type(),它会调用 type_id::get() 返回该类在工厂中的单例包装器实例。这允许用户直接通过类名(如 my_object::get_type())来获取类型标识,常用于重载(Override)等操作。
3. 实现虚方法 get_object_type():
- 实现了 UVM 对象自带的虚方法 get_object_type(),同样返回 type_id::get()。这使得在多态场景下,即使面对基类指针或句柄,也能通过实例动态获取其对应的实际工厂类型包装器。
1.3.2 工厂核心注册类 uvm_object_registry#(T, S)
Registry 的本意是登记处、注册表、记录簿。这个类的核心作用就是进行注册。
当在一个object类objA中,使用m_uvm_object_registry_internal(T, S) 宏时,会使用typedef 将uvm_object_registry#(T,S)设置一个别名叫type_id, 于是type_id成为了objA中的一个静态成员。当在objA之外,去访问type_id时,需要使用objA::type_id
在factory机制中,创建,重载,都在使用type_id,也就是uvm_object_registry这个类内部的静态函数,所以这个uvm_object_registry是整个factory机制的核心
1.3.3 uvm_object_registry的父类——uvm_object_wrapper类
首先需要明确,uvm_object_wrapper继承自uvm_void这个空的类,而uvm_object也是继承自uvm_void这个空类,所以uvm_object_wrapper和uvm_object这两个类是并列关系,不存在继承关系,
而且uvm_object_wrapper类的存在是为factory机制设计的,这个类的定义本身就是放在uvm_factory.svh文件中的。
在 SystemVerilog 的参数化类中,参数可以分为两类:
类型参数(Type Parameter):使用 type 关键字声明,传进去的是一个具体的类或数据类型(例如 my_driver、int)。
值参数(Value Parameter):使用具体数据类型(如 string、int)声明,传进去的是一个具体的值或字面量(例如 "my_driver"、8)。
为什么需要传字符串参数?UVM 的 Factory 机制不仅支持通过类型本身(如
my_driver::get_type())来操作,还必须支持通过字符串名字来管理。例如:允许用户在命令行或配置文件中直接用字符串(如 "my_driver")来指定重载或查找类型。允许 Factory 在全局维护一个“字符串名字 $\rightarrow$ 类型注册器”的查找表(Map),实现类似动态语言的反射(Reflection)功能。
二、uvm_component类相关的注册宏
2.1. 不带参数的component类的注册
使用uvm_component_utils时,展开情况和uvm_object_utils类似。
`uvm_component_utils(T) // 实际调用的是 `m_uvm_component_registry_internal(T,T) \ `uvm_type_name_decl(`"T`") \ `uvm_component_utils_begin(T) // 实际调用的是 `uvm_component_utils(T) \ `uvm_field_utils_begin(T) // 当需要使用field automation机制时,`uvm_field_int这些宏要放在 // `uvm_field_utils_begin和`uvm_component_utils_end之间 // 所以就不能使用`uvm_component_utils宏,要使用拆开版本 `uvm_component_utils_begin(T) `uvm_field_int(aaa) `uvm_field_int(bbb) `uvm_component_utils_end2.2. 带参数的component类的注册
`uvm_component_param_utils(T) // 实际调用的是 `m_uvm_component_registry_param(T,T) \ `uvm_component_utils_param_begin(T) // 实际调用的是 `uvm_component_param_utils(T) \ `uvm_field_utils_begin(T) // 当需要使用field automation机制时,`uvm_field_int这些宏要放在 // `uvm_field_utils_begin和`uvm_component_utils_end之间 // 所以就不能使用`uvm_component_utils宏,要使用拆开版本 `uvm_component_param_utils_begin(T) `uvm_field_int(aaa) `uvm_field_int(bbb) `uvm_component_utils_end