UVM入门和进阶2:核心基类_阶段_配置_消息机制
参考文档链接:https://verificationacademy.com/verification-methodology-reference/uvm/docs_1.2/html/
1 核心基类(uvm_object)
1.1 核心基类指的就是uvm_object
uvm_void
只是一个虚类(virtual class),等待将来继承于他的子类去开垦- 有两类
uvm_object
、uvm_port_base
类继承于uvm_void
- uvm世界里面十大类八大类继承于
uvm_object
除了
uvm_port_base``类以外uvm里面的类都可以溯源到uvm_object类
1.2 uvm_object
uvm_object核心方法:不用自己实现,uvm自动去实现
1 |
|
uvm里面把sv的句柄拷贝和对象拷贝区分成了copy与clone,且同样需要src,dst object
1.3 主要机制:域的自动化(field automation)
域:UVM里任何的成员变量都可以称之为域(field),在sv里面称之为属性property
域的自动化:使得在注册时,声明之后可能会用到的对象拷贝、克隆、打印等操作的成员变量
1.3.2 代码
代码原文
上文代码解释
第一点:开始域自动化声明和结束声明
1 |
|
第二点:域的自动化声明方式:如下添加参与到自动化声明的变量(也是使用宏,提醒一下,宏是不用分号的)
宏函数参考表:P275页 表10.2
1 |
|
补充点:域自动化数据操作宏参数UVM_ALL_ON
:是与之前数据变量对应的,数据操作的一个宏
数据操作宏参考表P276页 表10.3
对于小白来讲默认采取UVM_ALL_ON
或UVM_ALL_DEFAULT
就可以将所有数据操作(copy,compare,print,record,pack)都打开
1.3.3 代码续
调用未定义的copy函数
1 |
|
b1的成员变量都拷贝到b2
SV的copy是自己实现的,uvm不需要
1.3.3 总结
1.4 核心方法之一:拷贝(copy) 默认deepcopy=copy()+do_copy()
- SV里面的copy先做对象的创建再做数据的copy —-> UVM里面的clone
- SV里面的数据copy拷贝 —> UVM里面的copy拷贝即对象已经创建好就进行数据的拷贝
- 默认执行deepcopy即先执行copy()再调用回调函数do_copy(),do_copy()可在类里定义
1 |
|
相同点都会对数据进行复制
graph LR
SV里面的copy先做对象的创建再做数据的copy ---> UVM里面的clone
SV里面的数据copy拷贝 --> UVM里面的copy拷贝即对象已经创建好就进行数据的拷贝
1.4.2 代码
定义ball类,在box类中对ball进行例化
- box类中的成员变量完全拷贝过去了
- 内部成员ball类b的成员变量没有完全拷贝
- 原因:
- 对于color_t 声明时使用
UVM_NOCOPY
不执行拷贝 - 对于diameter从10变成20,因为uvm的拷贝执行了do_copy
- 对于color_t 声明时使用
- 原因:
1.5 核心方法之一:比较(compare)
1 |
|
1.5.2 例子
- 第三点当比较器为空uvm_comparer=null则会使用全局的默认比较器:uvm_default_comparer(详细参考1.6),最大的错误次数为1,只要失败一次就返回
1.7 打印:print()直接打印,spring()返回字符串,do_print()回调
1.7.1
1.7.2 例子
声明了一个uvm_table_printer句柄local_printer
并使用 ;p’p’p’p’p’p’p’p’p’p’p’p’p’p’p’p’p’p’p
- 第一次print,没对打印机printer指定,uvm使用默认uvm_default_printer打印
- 第二次print,指定uvm_default_printer=uvm_default_line_printer,uvm使用uvm_default_line_printer打印
- 第三次print,指定uvm_default_printer=uvm_default_tree_printer,uvm使用uvm_default_tree_printer打印
- 第四次print,配置local_printer
local_printer.knobs.full_name=1
,并指定使用前面使用的local_printer
输出结果
1.8 打包和解包(pack&unpack)
1.8.1
一般在纯粹的UVM环境里是用不到的,一般用不到
把域(标量)打包成一个比特流动态数组
1 |
|
如下:volume-32位、color-32位、box-24位 —->最终打包成32+32+24=88位比特流的数组
1.8.2 为什么这么做
仿真器与FPGA(或其他模型)连接
sim UVM仿真器与FPGA(或其他模型)连接通信,到具体的物理接口上,数据以bitstream形式,通过PCIE/USB/JTAG/UART等协议传输
UVM的pack&unpack是simUVM(软件侧)对数据打包的方法
对应FPGA或SystemC模型或不同语言也是通过相关硬件模块实现
1.6 全局对象
uvm_top为全局的顶层,与其他全局对象处于并列位置
如果不想用默认比较器uvm_default_comparer可以创建一个uvm_comparer
对象
(补充:uvm_factory不要去修改)
1.9 使用到的方法总结
1 |
|
2 phase机制
2.1 概述
解决的问题:
- 例化先后关系
- 例化之前进行配置
- UVM仿真阶段层次化
2.2 执行机制
2.2.1
一共有九个phase,对应九个方法,只有uvm_component具备,即如果你的类型是个组件的话一定会有phase机制
主要用到build, connect, run, report
- 执行顺序自顶向下,从build到final
- 只有run是任务,其他的是函数,函数意味着要立即返回
2.2.2 uvm_phase形参、例子、工厂创建对象的实例
uvm_phase形参用于传入当前phase
执行方法名:
1 |
|
uvm_phase phase指的传入当前phase
工厂机制创建:
1 |
|
this指的是c1或c2的parent,这里是创建这些对象的外部类,对应的topcomp
该例子例化的类结构图
2.2.2.2 执行结果
从结果看,执行顺序:自顶向下(先创建顶层实例,在创建底层实例)
2.3 九个主要phase:run_phase的功能
2.3.1
- 上电
- 复位
- 寄存器配置
- 发送主要测试内容
- 等待DUT完成测试
2.3.2 进一步细分run_phase为12个分支phase
- pre_reset_phase
- reset_phase
- post_reset_phase
- pre_configure_phase
- post_comfigure_phase
- pre_main_phase
- main_phase
- post_main_phase
- pre_shutdown_phase
- shutdown_phase
- post_shutdown_phase
2.3.3 run_phase与12分支phase关系
建议不要使用12个分支phase
当环境中同时存在run_phase与分支phase时:
run_phase和定义的分支会同时运行为两个线程,且两个线程都结束时才进入下一个phase
2.4 UVM编译和运行顺序
run是task所以可以消耗时间
2.5 UVM仿真开始:run_test()
2.5.1
类比SV中仿真开始
方法一:run_test(“xxxx-test”)
方法二:run_test()参数为空,仿真时传递参数
+UVM_TESTNAME=<test_name>
2.5.2 UVM世界的诞生:run_test()
run_test()从uvm_root创建了一个UVM世界,是唯一的顶层
run_test(string test_name=””);源码如下:
先拿到一个coreservice_t
再用拿到的coreservice_t拿到全局顶层top
- 再调用顶层的run_test(test_name)
即run_test(str)调用顶层,顶层top创建test,test再创建下面的哥哥结构
2.5.3 uvm_top承担的责任
uvm_top承担的责任非常重要,但无需我们去实现
- uvm_top是uvm_root类的全局唯一一个实例
- uvm_top是uvm里面例化的任何一个实例的顶层
- 对于component来讲,parent定为null则默认顶层为uvm_top,称为其子组件
- uvm_top控制各个phase的执行顺序
- uvm_top完成使用层次名索引的功能;配置部分都在uvm_top里面
2.5.4 uvm_top调用run_test,uvm_top做了什么
- objection机制是用来控制仿真退出的
- 创建uvm_test_top是为了调用各个组件的phase方法,进行安排
2.6 UVM仿真结束:我们的组件需要至少有一个能够挂起run_phase
2.6.1
控制(实现阻碍仿真退出)仿真退出只有一种方式,就是objection机制
uvm_objection机制实际上就是个计数器,在SV中是semapho旗语
2.6.2 uvm_objection用来实现反停止的方法
2.6.1raise挂起、drop落下
我们一般在run的阶段会把仿真挂起,对各个组件来说至少有一个需要把objection挂起防止uvm退出,如下:
如果uvm在run_phase时没有任何组件挂起,则会直接跳到report阶段
2.6.2.2 例子代码
1 |
|
2.6.2.3 例子代码2:你需要把你的挂起代码放在run_phase()的第一行执行
错误的,直接全部跳过了
你需要把你的挂起代码放在run_phase()的第一行执行
2.6.4 你可以在component、test、sequence中进行挂起操作
3 config机制
3.1 概述
3.1.1
config不同参数来选择:组件类型、组件实例数目、组件之间的连接、组件的运行模式;或是修改更细节的内容
3.1.2 uvm_config_db配置类
可以把一个变量从任何一个层次传递到其他层次,甚至底层组件没有创建也可以传递
可传递内容:
- interface指针(SV中set_interface函数传递的)
- 单一变量或句柄的配置
传递形式(成功返回1,失败返回0):
1 |
|
号对应参数类内容(参考SV第七讲)
由层次索引
- string inst_name没有例化则就直接写空字符串“”
(后面是错误的笔记)先set再创建,就会生成相应设置后的类
3.3 interface传递
3.3.1
SV中使用层次化的interface所以完成传递,即调用每一层的set_interface进行层层传递,非常不好
- 一定要对interface与vitural interface区分开,传递的过程中应该是virtual interface即传递指针
3.3.2 例子代码
下面例子
在build_phase里get vif
在test1的initial中进行set,且set一定要发生在run_test()之前确保了可以成功传递
注意virtual interface
,在软件中都得使用virtual interface
get(this,””,”vif”,vif)前三个参数完成的层次为“root.test.c1.vif”。其中第二个参数代表的时实例名,由于这里还没有进行例化所以用空字符串代替
3.3.3 例子代码续
uvm_config_db里面就是一些关系数组,做了中间的变量存放,通过set,get改变值:
3.4 变量设置
3.4.1 , 3.4.2 例子代码
下面例子
在build_phase里get vif
在test1的initial中进行set,再进行create
3.4.3 例子代码续
3.5 object传递
3.5.1
当变量比较多的时候,一个一个写不方便
可以把这些变量封装到uvm_object类里面,类例化,传递该对象句柄
- 先set再create
3.5.2 例子代码
- 可以父类uvm_oject传递:此时注意get时父类句柄转换为子类
- 可以直接以继承过来的子类进行传递
- set , get 严格类型一致
注意代码void`($cast(cfg, tmp))
把父类句柄转成子类句柄,从而访问子类句柄里的成员变量
3.5.2 例子代码续
类型要完全一致:底层get是父类句柄(uvm_objection)顶层set也得是该父类句柄
3.6 总结与建议
3.6.1 总结
set,get成对出现
类型严格一致
- 路径中的*星号表通配符,意思是任意路径
3.6.1 建议
4 消息管理
4.1 概述
一个好的验证系统应具有消息管理特性:
- 一种标准化的方式打印
- 过滤信息(按重要级别)
- 打印通道
这些特性UVM都有支持,UVM提供一系列丰富的类和方法来生成和过滤消息:
- 消息方法
- 消息处理
- 消息机制
类似的SV中的report package
4.2 消息方法
4.2.1
在UVM环境中或者环境外,只要引入uvm_pkg,均可以通过下面的方法来按照消息的严重级别和冗余度来打印消息
1 |
|
id:消息的名称是什么
message:消息的内容是什么
verbosity:消息的重要性/冗余程度
filename:消息发生时该程序文件的名称(留空就行,一般系统自动添加)
line:消息发生时该程序的行号(留空就行,一般系统自动添加)
4.2.2 verbosity冗余度:UVM_NONE
冗余度:代表消息重要不重要,与我们的直观认识相反
- UVM_NONE:最重要,没有任何bur/filter可以过滤
- UVM_LOW
- UVM_MEDIUM
- UVM_HIGH
- UVM_FULL:更容易被过滤
- UVM_DEBUG:更容易被过滤
4.3 消息处理
4.4.1 处理方式
4.4.2 消息宏
谁提供的这些消息?:uvm_report_object
- 我们可以用组件的方法进行调用
- 使用宏进行调用(更推荐)
1 |
|
对于w,e,f不用传verbosity,他们默认是UVM_LOW,较高等级了
4.4 消息机制
消息处理是uvm_report_handler类完成的
set_max_quit_count
对ERROR消息计数停止上限
4.5 消息处理中的回调函数
回调函数有如下固定形式,在任何地方实现都可以
一般来说一定要定义report_hook,其他看细分要求
4.5.2 例子代码
- build_phase
- set_report_severity_action(UVM_ERROR, UVM_DISPLAY | UVM_CALL_HOOK);//只有error会打印调用回调函数
- set_report_verbosity_level(UVM_LOW);//只有冗余为uvm_low会被打印1
- 此处error2为HIGH则不会打印也不会调用回调函数
4.5.3 回调函数返回值:
report_hook返回值为1时,继续执行分类report_error_hook否则不再继续调用
一般来说一定要定义report_hook
4.5.3 例子代码续
4.5.4 隐藏在后台的uvm_report_handler与uvm_report_server
对每一个组件都有report_handler实例,它们把消息申请到全局的实例report_server
report_server和factory一样的,放在coserver下面
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!