1. uvm_objection 和 uvm_component 基础
uvm_objection 和 uvm_component 是 uvm 中两大基础类,刚开始学习的时候,对两个东西认识不深,以为它们俩差不多,谁知道它两是一个是“爷爷”,一个是孙子的关系,两者贯穿整个 uvm 验证方法学。至于为什么要划分 uvm_object 和 uvm_component 呢,是因为前辈们在验证的过程中发现,对事情进行分工能降低复杂度,也能提高维护效率。uvm_object 在 uvm 中的地方比较基础,如果按照 OPP 的思想,它是一个最基础( base )没有太多的物理含义,而 uvm_component 是高层次抽象后的,具有物理含义,更像一个“对象”,例如我们前面谈到的 driver or montIor 它们都有自己的意义和功能。
如下图所示,先来整体看一下,uvm 方法学中核心的几个自带类型:
- uvm_void :是始祖类,人如其名,其中不包含任何函数和类
- uvm_obect :
- 比较基础的类,包含一些比较基础的常用函数,如 Copy 函数、Clone 函数、Compare 函数、Print 函数
- 可以在环境任一位置创建和销毁
- uvm_component :
- uvm_component 类继承于 uvm_obect
- uvm 组件类,继承于该类的子类,用于构成 UVM 环境( uvm_tree ),如在系列(一)中已经涉及过的 uvm_driver、uvm_montior 、uvm_env 和 uvm_scoreboard,其他几个组件在后续讲述过程中将会全部涉及。
- 包含一些列方法,如 factory 系列、phase 系列、 report 系列、 hierarchy 系列和全部的 uvm_object 类的方法
a. hierarchy 系列: 可以用于遍历和查找组件成员
b. phase 系列:这是 uvm_component 组件中最重要的函数,如 build_phase,connect_phase 等这些函数为 UVM 默认创建的空函数,需由用户自主填写内容,并按照一定的顺序自动执行。
c. repost 系列:提供了一些列方便的函数,用于输出打印信息
d. factory 系列:用于创建或者覆盖类型或者实例 - uvm_component 的特点是,必须在 build_phase 中实例化,如果在其他地方实例化,会报错
为了构建 uvm_tree 结构,uvm_component 的实例化具有它自己的特色,需要采用 create(最常用)创建, 原码如下:
折叠代码块
//uvm_object
static function T create(string name , uvm_component parent = null, string context="");
//uvm_component
static function T create(string name , uvm_component parent , string context="");
uvm_object 在实例化过程中,可以指定 parent 组件,也可以不指定;但是 uvm_component 在实例化过程中必须指定,只有指定了 parent 组件,该子 compoent 才能成功的挂载于 uvm_tree 中。
uvm_object 与 uvm_component 的区别:
- uvm_component 继承于 uvm_objection,包含一些 uvm_objection 没有的特性和函数,如 phase 系列函数
- uvm_component 必须通过 create 创建,uvm_objection 可以采用 new/create 创建
- uvm_component 存在于验证的整个过程中,其中存在的组任何组件( component )均不会被析构(释放内存空间),uvm_obect 可以在验证的过程中任何时刻被实例化和析构
为了使用 uvm_object 和 uvm_component 自带的函数和机制,我们需要把我们继承类均注册到一张表格中,这张表格主要为了方便替换验证环境中已有的实例或者已注册的类型,我们把这些称为工厂机制(factory ),这个过程称为注册。
简单一句话总结:注册机制是为了更加灵活的配置验证环境
2.uvm_object 类注册:
- uvm_object_utils : 用于把一个直接或者间接派生自 uvm_object 的类注册到 factory;
- uvm_object_param_utils : 用于把一个直接或者间接派生自 uvm_object 的参数化的类注册到 factory
参数化类,形如
class A#(int WIDTF=32) extend uvm_obejct
示例代码如下:
折叠代码块
class regfile extends uvm_reg_file;
`uvm_object_utils(regfile)
function new(input string name="unnamed_regfile");
super.new(name);
endfunction
endclass
uvm_object 类及其成员注册:
- uvm_object_utils_begin : (类) ... uvm_object_utils_end
- uvm_object_param_utils_begin : (类) ... uvm_object_param_utils_end
只有将成员变量注册后,使用 Copy 函数、Clone 函数、Compare 函数、Print 函数才能有效。
常用的变量的注册有以下几种;
折叠代码块
`define uvm_field_int(ARG,FLAG)
`define uvm_field_real(ARG,FLAG)
`define uvm_field_enum(T,ARG,FLAG)
`define uvm_field_object(ARG,FLAG)
`define uvm_field_string(ARG,FLAG)
`define uvm_field_queue_enum(ARG,FLAG)
`define uvm_field_queue_int(ARG,FLAG)
`define uvm_field_queue_object(ARG,FLAG)
注册示例代码如下:
折叠代码块
class my_transaction extends uvm_sequence_item;
rand bit[47:0] dmac;
rand bit[47:0] smac;
rand bit[15:0] ether_type;
rand byte pload[];
rand bit[31:0] crc;
rand bit crc_err;
uvm_object_utils_begin(my_transaction)
uvm_field_int(dmac, UVM_ALL_ON)
uvm_field_int(smac, UVM_ALL_ON)
uvm_field_int(ether_type, UVM_ALL_ON)
uvm_field_array_int(pload, UVM_ALL_ON)
uvm_field_int(crc, UVM_ALL_ON)
uvm_field_int(crc_err, UVM_ALL_ON | UVM_NOPACK)
uvm_object_utils_endfunction new(string name = "my_transaction");
super.new();
endfunction
endclass
3.uvm_component 类注册
- uvm_component_utils: 用于把一个直接或者间接派生自 uvm_component 的类注册到 factory;
- uvm_component_param_utils:用于把一个直接或者间接派生自 uvm_component 的参数化的类注册到 factory
uvm_component 类及其成员注册:
- uvm_component_utils_begin: (类) ... uvm_component_utils_end
- uvm_component_param_utils_begin: (类) ... uvm_component_param_utils_end
只有将 uvm_component 类注册到 factory 后,才能使用一些 component 重要的机制,那为什么要将 comonpent 的成员也注册呢,是为了使用 copy 等函数么?但是对 component 组件进行 copy 等操作意义不大。比较容易想到的问题,复制的组件的父类是谁(专业一点说就是 parent 无法指定),两个相同的组件又有什么用呢,啥用也没有。其实它的最大的意义在于自动使用 config_db 来获取某些变量的值。置于什么是 config_db,可以先理解为一个传递参数的工具,比较形象的比如是 写信者、邮递员和收信者之间传递信件,config_db 就是邮递员,具体细节将在后续讲述。