实战》阅读笔记[前3章]"/>
《UVM实战》阅读笔记[前3章]
- 已看章节
- UVM验证环境的搭建
- 只有driver和dut的验证环境
- 增加factory机制
- 加入objection机制
- virtual interface
- 加入transaction
- 加入env
- 加入monitor
- 加入agent
- 加入referrence model
- 加入scoreboard
- 加入sequencer
- 加入test
- UVM基础
- uvm_component和uvm_object
- uvm_object的派生类介绍
- uvm_sequence和uvm_sequencer以及uvm_sequence_item的区别
- uvm_config_db有什么意义
- uvm_object的派生类介绍
- uvm_object相关宏
- uvm_component相关宏
- new构造函数的几种写法
- uvm树形结构
- 为什么最顶层不是uvm_test_top而是uvm_top
- uvm树形结构的相关function
- field_automation
- phase的概念
《UVM实战》–张强编著。
uvm,可以理解为,是systemverilog的一个库,一个插件。集成了框架模板和有用函数。所以,学习uvm的前提是systemverilog基础要好。
有一些个人理解,是猜想,后续会不断迭代完善。
已看章节
- 一个简单的UVM验证平台
- UVM基础
文章开始就提供了一个简单的UVM验证平台。网上有case下载资源,可以跑nc、vcs、modelsim仿真。
UVM验证环境的搭建
刚开始,没找网上case下载资源。基于cadence的irun命令,自己搭建了验证环境:
run:@irun -sv \-f filelist.f \-licqueue \-timescale 1ns/1ps \-uvm \-uvmhome $$UVM_HOME \-input nopack.txt \-access +rwc
clean:@rm -rf INCA_libs *.shm *.log *.key
只有driver和dut的验证环境
- UVM第一条原则是:验证平台中所有的组件应该派生自UVM中的类。
- UVM基类:比如
uvm_component/uvm_object等
;扩展类。比如uvm_driver/uvm_monitor/uvm_sequencer/uvm_scoreboard/uvm_object
等等,还有很多。 - UVM是一个库,里面由各种类和宏组成。所以,UVM验证环境里,首先要加入下述代码
`include "uvm_macros.svh"//这是加载所有uvm宏
import uvm_pkg::*; //这是加载所有uvm类
- 想实现一个功能,首先要确定从哪个类里派生。
uvm_driver
中预先定义好了一个任务,叫做main_phase
,UVM
由phase
来管理验证平台的运行。可以简单认为,实现一个driver
,就是实现uvm_driver::main_phase
这个task
任务。- new构造函数,定义了component的uvm树形结构。跟DUT的verilog实例层次结构是不同的。所以,uvm里有两种层次结构。
- 使用下述命令,可以获取当前UVM树形结构。注意:UVM树形结构是针对component的,所以
get_full_name
函数,只能在component层次代码里调用。
`uvm_info("uvm_componet tree!!!",get_full_name(),UVM_LOW);
增加factory机制
factory
的实现,就是在自定义扩展类的时候,增加一条宏命令`uvm_component_utils
。在调用类的时候,run_test("classname");
。
例如,书中对my_driver
的描述,
利用factory机制,使得top_tb
里的代码段可以很大节省,提高移植性。
my_driver
实例化- 调用
main_phase
- $finish
可以简化为run_test("my_driver");
- 特点:自定义的类,其调用的时候,不需要类的定义、类的实例化等操作。可以直接使用
function
或者task
。 - 所有派生自
uvm_component
及其派生类的类,都应该使用uvm_component_utils
宏 - 派生的driver类里,包含
main_phase
函数,会自动调用执行的。注意要配合objection机制,才能达到期望效果。 - 这一节结合objection一起理解
加入objection机制
- UVM通过
objection
机制,实现验证平台的关闭。 - 每个
phase
中,UVM会检查是否有objection
被提起(raise_objection
),如果有,那么等待这个objection
被撤销(drop_objection
)后停止仿真;如果没有,则马上结束当前phase。 - 这一节结合factory一起理解,
run_test()
理解为创新一个类的实例,并会自动调用main_phase
开始执行。 - raise_objection命令,必须放在第一个消耗仿真时间的语句之前调用。
virtual interface
- 以上代码,driver的信号都是绝对路径,如果改变设计层次结构,会造成移植困难的情况;在此背景下,出现
interface
概念 工作内容
- 定义
interface
,跟module同一级; interface
实例化- 利用
uvm_config_db
机制,set和get两步操作,实现扩展类my_driver
和top_tb的interface
交互。
- set 放在
module top_tb
层次里 - get放在
class my_drivers
层次里。注意引入build_phase
;相对main_phase
,作用是在仿真为0的时刻时执行。
- set 放在
uvm_config_db
就是一个参数化的类,#(参数);跟verilog很像。- 结合上例,看看get的处理方式。
uvm_test_top.i_agt.drv
里在build_phase块里,增加
- 结合上例,看看get的处理方式。
- 定义
if(!uvm_config_db#(virtual my_if)::get(this,"","vif",vif)
`uvm_fatal("my_driver","virtual interface must be set for vif!!!")
解释:
当前实例路径下,vif
标记符合;于是把virtual my_if input_if
连接到该实例路径下的vif
8. 搞半天,就是为了实例化的连线方法。应该是为了利用interface的优势。
补充几句:
1. module里可以声明interface;即类interface的句柄化
2. class里不可以
声明interface;即类interface的句柄化。
3. 类class里,使用的是virtual my_if vif;
加入transaction
- 所有的transaction都必须从
uvm_seqence_item
派生;
加入env
加入monitor
加入agent
加入referrence model
加入scoreboard
加入sequencer
加入test
UVM基础
uvm_component
和uvm_object
uvm_component
继承自uvm_object
;uvm_object
继承自uvm_void
;- 类的层次越高,功能越少。
uvm_component
两大特性
- 树形结构。
- 只有
uvm_component
派生的类,才有节点。 - 类似verilog实例化层次结构,但是不同;所以uvm里有两种层次路径,一种是verilog的实例化层次结构,一种是
uvm_component
的树形结构(每个结点是一个class实例)。 - 为什么只有
uvm_component
才有树形结构,uvm_object
没有? - 个人理解,是
uvm_object
是有生命周期的;uvm_component
没有生命周期。也就是说仿真过程中,uvm_object
在启动后可以finish
;uvm_component
是伴随仿真过程一直要存在的。这也是uvm_component
和uvm_object
的主要区别。 - 原书第二章,就是一步步丰富
uvm_component
的树形结构。 - 下图是一个完整的
uvm_component
树形结构
- 只有
- phase的自动运行
- phase是uvm的factory机制,俗话讲,就是把一些繁琐过程加工成一种方便可重用的宏命令。
- 原书有详细介绍,但当前理解,只需要关注phase执行顺序和几个大的phase定义就可以了。
run_test()
命令,执行的先后顺序依次是:new()-->build_phase-->main_phase
- 树形结构。
- component相对object类,正因为上述的不同点。导致会有一些限制。
- 无法使用uvm_object的clone函数;但是可以使用copy函数。
- 不能在相同父结点下,实例化相同的名字。
uvm_object
的派生类介绍
uvm_sequence_item
- config
- register model
- uvm_phase
- 等等
uvm_sequence和uvm_sequencer,以及uvm_sequence_item的区别?
- sequence是众多
sequence_item
的集合。 sequence_item
流通在uvm_component
之间。- sequence继承自object;而
sequencer
继承自component,需要体现在树形结构里。 - 用户定义的所有transaction
必须
从uvm_sequence_item类派生。 - transaction就是封装了各种协议接口的事务。
uvm_sequence_item
相对transaction,增加了很多实用的成员变量和函数/任务。
sequence的作用,是封装众多的sequence_item。
- sequencer的作用,是调度其中的sequence和driver之间的传输。
uvm_config_db
有什么意义?
- config负责搭建
uvm_component
的行为准则。举例:比如规定driver在读取总线时,地址信号持续几个时钟;片选信号从什么时候开始有效等。 - config和config_db的区别
这里的config,指的是把所有的参数放在一个object中;然后通过config_db的方式设置给所有需要这些参数的component。 config_db机制,主要用于UVM验证平台之间传输参数。set和get函数,都是成对出现的。
- uvm_component(比如interface、monitor)之间传递参数。简单来说,set是寄信;get是收信。
- 第一个参数和第二个参数,指出具体实例名;
第一个参数是uvm_component实例的指针;
第二个参数是相对此实例的路径。 - 第三个参数,设置一个标记(只要唯一就行),方便寄信收信一致性。
- 第四个参数,跟
uvm_config_db
类的参数相关,如下例:
uvm_config_db#(virtual my_if)::set(this,"i_agt.drv","vif",input_if)
第四个参数,就是要传递到uvm_test_top.i_agt.drv
的
uvm_config_db#(virtual my_if)::set(this,"","vif",input_if)
总之。需要注意:
- 路径要一致;
- 第一个参数尽量是this,因为有优先级,层次越高,config_db设置的优先级越高;
- 除了第一个参数带来的优先级问题,还有时间越后,config_db设置的优先级越高。
- 第三个参数,是个ID,就是为了在某一个实例层次下,通过ID精确匹配set和get而已。ID可以很随便,但要保证一一对应。
- 第四个参数,set对应的value;get对应的是变量名称。
- `config_db`支持通配符
- `config_db`第二个参数,如果写错,不会有错误报告的。一般使用`check_config_usage`来检查set和get的匹配情况。其中,`check_config_usage`一定要在`build_phase`之后,因为`config_db`在`build_phase`里执行;一般在`connect_phase`里。
- 仿真工具,也可以用参数命令,实现config_db的功能;但只支持int/string的数据类型。
- `config_db`,需要`set/get`成对出现;后文会有更高级的用法,使用`field_automation`来传递component的参数。
uvm_object的派生类介绍
- uvm_driver
- 主动向sequencer索要
sequence_item
,即transaction。并将sequence_item
的信息驱动到DUT的端口上。 - 相当于完成从transaction到signal端口级别的转换。
- 主动向sequencer索要
- uvm_sequencer
- 负责调度sequence与driver之间的传输。
- uvm_monitor
- 与driver相对。
- 继承自uvm_component,但是基本没有任何扩展功能,就是为了完善UVM验证的树形结构,使验证环境完善而已。
- uvm_scoreboard
- 负责比较referrence model与monitor分别发送过来的数据,根据比较结果判断DUT是否验证成功的工作。
- 继承自uvm_component,但是基本没有任何扩展功能。
- referrence model
- uvm里没有定义这个类,通常定义referrence model继承自uvm_component。
- referrence model,可以用systemverilog或者DPI等接口调用其它语言,来完成与DUT相同的功能。是一个功能模型。
- uvm_agent
- 是从uvm可重用角度出发,构建的uvm_agent。
- uvm_agent,包括driver和monitor。
- 个人理解,agent的作用,是封装signal level端口级别的driver和monitor;与sequence对应。
- 继承自uvm_component,但是基本上没有任何扩展。只增加了一个成员变量
is_active
。这个is_active
主要作用是让agent判断是否包含driver。因为in_agent
需要driver和monitor;而out_agent
不需要driver,只需要monitor。
- uvm_env
- 继承自
uvm_component
,但是基本上没有任何扩展。 - 封装固定不变的component。
- 继承自
- uvm_test
- 不同测试case之间的差异很大;
uvm_test
里,都要实例化uvm_env
;- 继承自
uvm_component
,但是基本上没有任何扩展。
uvm_object相关宏
'uvm_object_utils
把一个直接或间接继承自uvm_object
的类,注册到factory里。'uvm_object_param_utils
把一个直接或间接继承自uvm_object
的带参数的类,注册到factory里。
书中建议多使用带参数的类,移植性更高。'uvm_object_utils_begin
…..'uvm_object_utils_end
'uvm_object_param_utils_begin
…..'uvm_object_param_utils_end
这个和上面一个宏,主要是配合field_automation
机制。
uvm_component相关宏
完全类似于uvm_object
相关宏。
new构造函数的几种写法
区别只是parent参数不一样。
参数name是uvm树形结构的实例名称。
- new(“name”,this)
推荐写法。 - new(“name”,null)
上一层是最顶层,uvm_root
类实例化的uvm_top
。 - new(“name”)
类似new(“name”,this),但不推荐这么写。
最后,uvm是不推荐使用new构造函数的。
uvm推荐type_name::type_id::create();
.
uvm树形结构
为什么最顶层不是uvm_test_top
,而是uvm_top
?
uvm_test
类实例化名称叫做uvm_top
,uvm_test
类的定义,包含case相关的参数。
一般由'uvm_component_utils_begin
…..'uvm_component_utils_end
定义。
而uvm_root
类,作用是设置top顶层,以及phase的运行。
个人理解,uvm_test
和uvm_root
可以设置成一个类;因为他们都可以作为最顶层,只能实例化一次。但是uvm的概念,包含可重用性的特点;case不同,uvm_test
会有变化;而uvm_root
是可重用的。
综上理解,顶层设置为uvm_test
,更方便测试环境的可重用。
- uvm_top
是一个全局变量,可以在任一层次,使用下述代码段获取uvm_top
的指针。
uvm_root top;
top=uvm_root::get();
uvm树形结构的相关function
- get_parent();
- get_child(string name);
get_children(ref uvm_component children[$]);
get_first_child
get_next_child
get_num_children
- 全局函数
get_full_name();
field_automation
- 针对uvm_sequence_item的注册;
- 使用uvm_field宏注册所有字段;最终目的,是为了简化driver和monitor的代码量。
- 相关函数
- copy、compare
pack_bytes、unpack_bytes
pack、unpack
pack_ints、unpack_ints
- print、clone
phase的概念
- phase的自动运行
- phase是uvm的factory机制,俗话讲,就是把一些繁琐过程加工成一种方便可重用的宏命令。
- 原书有详细介绍,但当前理解,只需要关注phase执行顺序和几个大的phase定义就可以了。
run_test()
命令,执行的先后顺序依次是:new()-->build_phase-->main_phase
- build_phase的内容,一般有:
- 利用config_db set/get传递参数;
- 实例化成员变量
build_phase
是一个function,不消耗仿真时间;main_phase
是一个task,消耗仿真时间。
更多推荐
《UVM实战》阅读笔记[前3章]
发布评论