UVM使用经验
0. 介绍
这篇积累一下UVM使用过程中遇到的一些问题、bug和经验。
1. 经验
1.1 phase相关
======================================================================================
1.每个phase函数或者任务都要加上super. * _phase(phase)*
之前再看《UVM实战》的时候以为只有build_phase需要使用super,但是今天在使用callback机制的时候,connect_phase中没有用super.,出现了一些怪异的错误。
好吧,我刚才把connect_phase注释了,跑一下发现也没错,醉了,以后留意一下吧。
======================================================================================
2. 如果两个component有端口连接,需要注意connect_phase,是否要seper.connect_phase(phase)
今天遇到一个问题,我们知道uvm_driver中有个seq_item_port,在uvm_sequencer中有一个seq_item_export,今天我在写的时候,出现了一个错误:
1 |
|
查了一下,好像是跟connect_phase有关,也不太清楚,我就看代码,发现我的sequencer、driver、agent,他们的connect_phase中都没有用super.connect_phase。因为看张强的那本书说,用不用都一样,今天我就省略了。然后我就把他们的super.connect_phase都加上了,结果正确了。
然后我又逐个注释掉,看到底是哪一个在起作用,结果发现只有在我重载了sequencer的connect_phase,但是在其中没有写super.connect_phase,才会出错,其他任何情况都不会出现这个错误。最简单的避免错误的方法就是如果用不到这个phase,就不要写出来,不写就没错,如果写了那么还是把super给加上吧。
然后我又用自定义port、export、imp来测试了一下,我不用seq_item_port和seq_item_export,发现怎么写都没有错,怪哉啊。
所以一个不严谨的结论就是,sequencer的connect_phase要写super.connect_phase(phase),否则就别写connect_phase函数。
======================================================================================
2019–08-29
可配置的验证平台中,会通过uvm_config_db#(..)::set来设置一些控制参数,来看重验证平台组件的生成,比如uvm_agent中的is_active。
比如现在是在给agent设置is_active,那么我们希望agent能知道我们重新设置了这个变量,为了实现这个在UG中强烈建议加上super.build_phase(uvm UG 1.1 P44),而且出现了好多次。当然用这个也是有前提的,这个算是config_db自动获取,我们需要:
1. 将agent用factory宏注册。
2. 将agent中需要 自动获取的变量用filed automation。
3. config_db中set函数的第三个参数和agent中的变量名是一样的。
======================================================================================
2019–08-29
我们创建component要在build_phase中,比如我们在base_test中例化了env,并在base_test::build_phase中创建了它,那么在特定的case(继承自base_test)中,我们不必再例化env和创建它,只需要调用super.build_phase就可以了。
======================================================================================
2019–08-29
如果想要再case中向sequence中传递sequencer指针,那么uvm_config_db::set要写在build_phase之后的connect_phase中。
详细见这篇博客UVM——Fun with UVM Sequences - Coding and Debugging中的有用-CONTROLLING OTHER SEQUENCES一节
======================================================================================
1.2 callback
======================================================================================
1.在使用回调的时候,自己定义的回调对象不能跟sequence在同一个phase。可以是sequence在build phase上启动,而callback object在connect phase中创建。
======================================================================================
1.3 运行仿真环境
======================================================================================
我们知道,UVM中的factory机制可以实现通过字符串创建对象,从书上知道,在VCS仿真的时候我们可以通过用+UVM_TESTNAME选项来指定不同的case。
如果我们的sequence都编译好了,也就是说已经执行了vcs -sverilog ….这条脚本,那么我们可以通过
1 |
|
来执行不同的case。
但是如果我们的sequence被修改了,那么我们需要用vcs脚本重新编译一下,再用simv仿真,这样改变之后的效果才能呈现出来。
======================================================================================
1.4 config_db使用
======================================================================================
在top module中,要通过config_db来设置虚接口,然后运行run_test()例化test case,在这里有个顺序问题,需要先config_db,再run_test()
1 |
|
要不然报错:driver得不到接口
1 |
|
可以猜测,uvm_config_db机制可能只是向一个表中记录设置参数的路径信息,当你创建对象的时候,你先要访问这个表,看有没有给对象设置了信息,如果先创建了对象,在对象的build_phase中get参数,就会发生get不到的情况,所以需要先set,然后再创建对象。
但是如果是在组件中使用的话,先创建对象还是先config_db都可以,比如:
在environment中创建i_agt,需要设置is_active变量。下面这两种方法都能run。
1 |
|
1 |
|
======================================================================================
config_db如果配置的对象是个参数类,那么可以将类的参数写出来,也可以不写出来,都能配置对,只要你set和get同步就行,别一个写了参数,一个没写,比如我要传递 sequencer#(transaction)到virtual sequence中。
1 |
|
get的时候也一样,要加参数
1 |
|
======================================================================================
上面介绍的传递sequencer,有一点要注意,比如我实在test case中set,那么set函数一定不要写在build_phase中,可以写在connect_phase,否则传递失败,但编译器却不会报错,不过但你要用sequencer来启动sequence的时候,又会告诉你说sequencer没有实例化。
1 |
|
======================================================================================
在路径索引中使用的路径,比如一个i_agt,这个其实是i_agt对象在创建时候的名字,比如
1 |
|
名字是new中引号内的字符串,而不是开头的i_agt,当然,这里他们是相同的。
我们可以写成:
1 |
|
1.5 任务和函数
======================================================================================
任务中的变量一定要先定义,然后才能进行接下来的操作。
在phase方法中调用super之前一定要先把变量都声明好了。
1 |
|
上面那种写法会说 transaction tr;语句出错,应该把变量的定义写在开头。
1 |
|
======================================================================================
1.6 程序块
======================================================================================
在写if else语句的时候,如果写成下面这样会报错,
1 |
|
if也要加上 begin end
1 |
|
但是如果单独写if没有else,那么不需要加begin end(if后只有一条语句的时候)
======================================================================================
1.7 端口 port export imp analysis fifo
======================================================================================
看UVM UG里面,端口的new写在build phase 里。
======================================================================================
1.8 tb上的组件
======================================================================================
UG中建议不要再new中创建组件(UG1.1 P62),它说在面向对象的编程中new函数在重载的时候有一些限制,所以,应该用build_phase来代替,在其中创建验证平台组件。
比如说,我们在base_test中例化了env,并在base_test::build_phase中创建了它,那么在特定的case(继承自base_test)中,我们不必再例化env和创建它,只需要调用super.build_phase就可以了。****
======================================================================================
1.9 接口
虚接口将硬件接口和SV仿真环境链接在一起,在顶层通过uvm_config_db机制传递。
之前都是用通配符*来传递,但是如果要传递多个接口那么可能会出现比必要的问题,在UG上看到一个写法:将虚接口传递给agent,然后在agent中通过uvm_config_db 得到虚接口,如果driver或者monitor中需要这个虚接口,可以通过如下方式:
1 |
|
1.10 一些函数
$root,在SV1800中的介绍:
1 |
|
$root是在top module上面的实例,算是实例树种的根,类似于UVM中的uvm_top这个实例。
我们可以这样访问:$root.top.inst_A。这样就可以访问到top中的实例inst_A。
2. 问题
2.1 仿真时候卡主了
======================================================================================
运行 ./simv +UVM_TESTNAME=case0 -l sim.log 卡在下面的界面
1 |
|
应该是忘了在top module中运行run_test
1 |
|
======================================================================================
2.2 模块定义
======================================================================================
uvm_driver uvm_sequence uvm_sequencer是参数化的类,可以加上要传递什么类型的transaction,但是uvm_monitor不可以。
======================================================================================
有的时候说找不到class定义,
这说明`include的顺序不对,先用到的要先include,但也可以通过typedef来解决,在那些报错的类所在的文件夹中:
1 |
|
表明这个类在下文是有定义的。
2.3 驱动接口编写
======================================================================================
driver中在何时驱动接口,接口信号才能在时钟被采样到
这个好像是跟SV的仿真原理和EDA仿真工具都有关系。
我今天的错误情况:
TB驱动接口信号在时钟沿改变,DUT采样不到;
改变后的正确情况:
TB驱动接口信号提前半个周期,在下降沿改变,DUT采样到。
所以应该在时钟下降沿使数据有效,等待DUT执行结束后,在上升沿使数据无效。
======================================================================================
2.4 `ifdef `endif
Error-[IWNMEE] ifdef or
ifndef with no matching
pkg.sv, 3
ifdef or
ifndef has no matching else or
elsif or `endif.
Check that the directives are balanced.
本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!