[UVM源代码研究] uvm中的factory机制(uvm-1.2版)
工厂(factory)机制
工厂机制作为设计模式(design pattern)中的一种并不是uvm独有的,但却作为一个重要的概念被uvm引入实现了。
“工厂”表示一个负责创建其他类型对象的类,工厂决定了我们最终创建的类的类型。
factory机制的实现包含了以下几个步骤:
- 实现factory机制的类必须使用uvm_object/cmponent_utils系列宏进行注册
- 调用set_type_override等override函数对需要创建的类进行覆盖(可选)
- 创建类的时候必须使用::type_id::create方法创建(这样才会执行查找override表创建最终的类型)
下面我们分别对以上3个步骤中涉及到的UVM源代码进行解读。
`uvm_object/component_utils系列宏
我们在使用factory机制的时候,必不可少的一个步骤就是相关类在实现的时候必须使用`uvm_object/component_utils宏进行注册,下面以uvm_object为例讲述一系列的相关宏的具体实现。
src/macros/uvm_object_defines.svh中的源代码
src/macros/uvm_object_defines.svh中的源代码
src/base/uvm_registry.svh中的源代码
将uvm_object/component_utils
宏展开,首先都会调用m_uvm_object_registry_internal/param
宏,这两个宏中都定义了一个参数化的uvm_object_registry类类型type_id,不同的是`m_uvm_object_registry_internal宏多了个参数S,而在定义type_id类型的时候将参数S按内容直接替换为字符串作为参数化的类uvm_object_registry的第二个参数。
`uvm_object/component_utils宏的替换实现
下面我们展示将uvm_object/component_utils
宏按照上面展开的内容在具体的类apb_transfer代码中替换实现。
使用`uvm_object_utils宏实现的代码
将`uvm_object_utils宏展开后的代码
于是我们队`uvm_object_utils宏的实现功能作出如下概括:
-
声明了一个type_id类型
-
定义了静态函数get_type,返回值为type_id类型
-
定义了函数get_object_type,返回值为实际指向type_id类型的uvm_object_wrapper类型
-
定义了create函数,返回值为实际指向apb_transfer类型的uvm_object类型(这就是我们在factory机制中创建对象调用的create函数)
-
定义了静态字符串常量type_name
-
定义了函数get_type_name返回type_name
uvm_object_wrapper类
src/base/uvm_registry.svh中的源代码
我们先看看verification-academy中对uvm_object_wrapper的描述:
The uvm_object_wrapper provides an abstract interface for creating object and component proxies. Instances of these lightweight proxies, representing every uvm_object-based and uvm_component-based object available in the test environment, are registered with the uvm_factory. When the factory is called upon to create an object or component, it finds and delegates the request to the appropriate proxy.
uvm_object_wrapper是个virtual类,也是无法直接实例化的,它的主要作用就是作为在工厂中创建的各种uvm_object/uvm_component的句柄, uvm_object_wrapper相当于工厂机制创建对象时的一个抽象的描述,它可以指向任何一个我们通过工厂机制所创建的对象。
uvm_object_registry
src/base/uvm_registry.svh中的源代码
`m_uvm_object_registry_internal/param宏首先定义了一个uvm_object_registry类类型type_id, create就是uvm_object_registry类中定义的静态方法。
这就是为什么只有通过`uvm_object_utils宏注册了的uvm_object派生类才可以用class_name::type_id::create来创建实例。
191行定义了一个this_type类型作为参数化的uvm_object_registry类型的简写。
233-234行以及253-254行都是获取uvm_factory的唯一实例,目的是调用在uvm_factory中定义的相关方法。
224行定义了一个local和static修饰的this type类型实例me,me可以作为uvm_object_registry以T和Tname为参数的唯一实例,获取方式只有通过get,通过前面的学习我们知道这又是单例模式的一种使用。236行调用uvm_factory中定义的register将me注册,后面会将如何实现注册。
258行调用uvm_factory中的create_object_by_type方法创建实例,并返回一个指向T类型的uvm_object_wrapper句柄,所以需要在259将其cast成T类型,如果cast失败即创建实例失败,则执行260-265行的内容打印相关错误提示信息,直接结束仿真,因为这里调用的是uvm_report_fatal。后面我们会讲create_object_by_type的实现。
uvm_facroty的单例模式实现
uvm_factory是一个virtual类,virtual类是没法被实例化的,所以我们前面讲的创建uvm_factory的实例其实创建的是从其派生而来的uvm_default_factory的唯一实例,所以我们并不是直接调用uvm_factory中的get函数来获取单例,而是借助于uvm_coreservice_t这么个中间类来获取factory实例,严格意义上来讲uvm_coreservice_t 也是个virtual类,其实例也跟uvm_factory/uvm_default_facory一样对应着有一个uvm_default_coreservice_t类。
src/base/uvm_factory.svh中的源代码
src/base/uvm_coreservice.svh中的源代码
使用factory机制创建类实例
create_object_by_type
src/base/uvm_factory.svh中的源代码
这里的1231-1238行是根据输入参数来获取所创建对象的完整hierarchy,即我们使用get_full_name()获取的路径。
1240行清空m_override_info队列,后面的find_override_by_type函数会使用到该队列用于递归查找,所以先要执行清空队列以免影响后续操作。
1242行调用的find_override_by_type就是查看requsted_type这样一个对象对应的数据类型是否有被override过,并返回最终的override后的数据类型。
1244行根据1242行返回的数据类型来创建最终的对象并返回给调用create函数的地方。
所以这里创建对象的核心就是1242行的查找override类型的过程,那这里我们就需要知道如何才能执行override。
override相关的4个函数
src/base/uvm_factory.svh中的源代码
src/base/uvm_fcomponent.svh中的源代码
uvm_factory中根据override的是inst还是type以及override是以类型进行override还是以name进行override细分出了4中override函数。
这四个函数在uvm_compoent中又分别被封装成了4个函数,这样在uvm_component的排上类里可以直接使用,本质上都是通过factory的单例模式调用uvm_factory里定义的这4个函数。
set_type_override_by_type
src/base/uvm_factory.svh中的源代码
我们以set_type_override_by_type为例介绍一下override的其中一种方式,其他3中方式原理类似。
937-945行是判断override的前后数据类型是否为相同类型,相同类型则提示UVM_WARNING
m_types是uvm_factory中定义的联合数组,用来标志创建的数据类型是否有被注册过,没有被注册则返回0,再使用register函数进行注册。
src/base/uvm_factory.svh中的源代码
src/base/uvm_factory.svh中的源代码
956-979行遍历m_type_overrides队列查找original_type是否有被override过,如果有被override过并且replace=0,则直接返回不进行override的注册。否则执行替换的操作并将replaced置1表明将原有的override替换掉了。
这里替换的映射关系是要靠一个uvm_factory_override类来维护的,其中包含了类型替换、名称替换、路径所需要的相关信息,前面遍历的m_type_overrides就是维护映射信息的uvm_factory_override类队列。
982-990行表明如果在遍历队列里没有找到匹配对,则把这次override关联的两个数据类型添加到匹配队列里,而如果执行了override的替换操作(上面replaced=1的情况则不需要添加,因为上面已经替换掉了原有匹配对)。
总结
以上内容就是UVM源代码中关于factory机制实现的部分原理解析,其中省略了不少关键代码解析,有问题欢迎评论区讨论。