UVM世界观之八:phase机制(下)
标签: UVM
本文转自:http://www.eetop.cn/blog/html/28/1561828-2331503.html
如何开始UVM仿真
如果只是从UVM的应用角度来看,要在仿真开始时建立验证环境,那么用户可以考虑选择下面几种方式:
- 可以通过全局函数(由uvm_pkg提供)run_test()来选择性地指定要运行哪一个uvm_test。这里的test类均继承于uvm_test。这样的话,指定的test类将被例化并指定为顶层的组件。一般而言,run_test()函数可以在合适的module中initial进程块中调用。
- 如果没有任何参数传递给run_test(),那么用户可以在仿真时通过传递参数+UVM_TESTNAME=<test_name>,来指定仿真时调用的uvm_test。当然,即便run_test()函数在调用时已经有test传递进去,在仿真时的+UVM_TESTNAME=<test_name>也可以从顶层覆盖底层的指定。这种方式使得在仿真开始时,不需要通过再次修改run_test()调用的test名字和重复编译,而可以灵活选定test。
无论上面哪一种方式,都必须有顶层调用全局函数run_test(),用户可以考虑不传递test名字作为参数,而在仿真时通过传递参数+UVM_TESTNAME=<test_name>实现。全局函数run_test()的重要性,正是从uvm_root创建了一个UVM的世界。来看看这一段代码:
task run_test (string test_name="");
uvm_root top;
uvm_coreservice_t cs;
cs = uvm_coreservice_t::get();
top = cs.get_root();
top.run_test(test_name);
endtask
uvm-1.2/base/uvm_globals.svh
这里需要先来了解UVM的顶层类uvm_root。该类也继承与uvm_component,说明它必然是UVM环境结构中的一员,而他可以作为顶层结构类,它提供了一些像run_test这种方法,来充当了UVM世界中的核心角色。在uvm_pkg中,有且只有一个顶层类uvm_root例化的对象,即uvm_top。这就同“道生一,一生二,二生三,三生万物”的古语一般。在UVM的世界中,“道”就是uvm_pkg,“一”就是uvm_top,而后来的“万物”就是uvm_top下例化的uvm_test及其更多的子组件。
uvm_top充当的主要核心任务包括:
- 作为隐形的UVM世界顶层,任何其它的组件都在它之下,通过创建组件时指定parent来构成层次。如果parent设定为null,那么它将作为uvm_top的子组件。
- phase控制。控制所有组件的phase顺序。
- 索引功能。通过层次名称来索引组件实例。
- 报告配置。通过uvm_top来全局配置报告的繁简度(verbosity)。
- 全局报告设备。由于uvm_top全局可以访问,因此UVM的报告配置在组件内部和组件外部(例如module和seequence)都可以访问。
通过uvm_top调用方法run_test(test_name),uvm_top做了如下的初始化:
- 得到正确的test_name。
- 初始化objection机制。
- 创建uvm_test_top实例。
- 调用phase控制方法,安排所有组件的phase方法执行顺序。
- 等待所有phase执行结束,关闭phase控制进程。
- 报告总结和结束仿真。
下面从源代码中精简的例码,对照着上面对uvm_root::run_test()初始化的内容:
task uvm_root::run_test(string test_name="");
uvm_report_server l_rs;
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
bit testname_plusarg;
int test_name_count;
string test_names[$];
string msg;
uvm_component uvm_test_top;
process phase_runner_proc; // 存储forked线程用于最终的进程清理
testname_plusarg = 0;
uvm_objection::m_init_objections();
... // 获得 test_name
// if test now defined, create it using common factory
if (test_name != "") begin
uvm_coreservice_t cs = uvm_coreservice_t::get();
uvm_factory factory=cs.get_factory();
...
// 创建 uvm_test_top
$cast(uvm_test_top, factory.create_component_by_name(test_name,
"", "uvm_test_top", null));
...
end
...
// phase控制方法,按phase顺序执行所有组件的phase
fork begin
// spawn the phase runner task
phase_runner_proc = process::self();
uvm_phase::m_run_phases();
end
join_none
#0; // let the phase runner start
// 等待组件的phase执行完毕
wait (m_phase_all_done == 1);
// 关闭phase控制线程
phase_runner_proc.kill();
// 报告总结
l_rs = uvm_report_server::get_server();
l_rs.report_summarize();
// 结束仿真
if (finish_on_completion)
$finish;
endtask
uvm-1.2/base/uvm_root.svh
如何结束UVM仿真
UVM的仿真开始相对于仿真结束要容易一些,毕竟只需要在仿真时传递test名字,就可以在仿真开始时创建对应的test顶层实例。而对于结束仿真来说,要理解和合理地利用UVM结束机制就显得困难一些了。在之前介绍的所有phase当中,只有run phase(对应12个run-time phase)是task,何时可以结束仿真,实际上同run phase何时结束直接相关。
从UVM-1.1开始已经将仿真结束机制做了大量的简化,为了做出一个仿真结束机制的比对,我们将UVM-1.0和UVM-1.1之后的run phase执行机制分别介绍,以便读者可以了解和比较这两种不同的机制版本。
UVM-1.0版本的结束机制
我们将run phase执行分为两个阶段和三种执行的线程。这两个阶段是活跃期(active stage)和停止中断期(stop-interrupt stage),如下图所示:
从这一版本的结束机制可以看到:
- 默认情况下,如果没有objection反停止标记挂起的,所有的run_phase任务在执行时,会直接放入到fork-join_none进程当中。因此run_phase()中的任务会在后台执行,但不会阻止run_phase()结束,进入下一个phase。因此,objection机制是控制仿真退出run phase的一种办法。
- 另外,如果在任何的组件中,有设置enable_stop_interrupt比特,那么要退出run_phase(),除过需要考虑之前的objection机制,用户还可以在run_phase()中调用global_stop_request()。调用global_stop_request()后,run_phase()会立即结束活跃期,进入停止中断期,继而执行用户自定义的stop_phase()任务。但是,如果在调用global_stop_request()时,已经有组件挂起了objection反停止标记,那么global_stop_request()的停止活跃期的要求会被忽略,结束机制只会遵循objection机制。
UVM-1.1版本之后的结束机制
上面的UVM-1.0主要两种控制run_phase()的结束方式,同OVM的结束机制是一致的。而到了UVM-1.1版本以后,结束机制得到了更多的简化。上面的两种结束方式,global_stop_request()的结束方式已经被废除,也就是说run phase不再拥有停止中断期,只依靠objection机制来结束仿真。
uvm_objection类提供了一种供所有component和sequence共享的计数器。如果有组件来挂起objection,那么它还应该记得落下objection。参与到objection机制中的参与组件,可以独立的各自挂起objection,来防止run phase退出,但是只有这些组件都落下objection后,uvm_objection共享的counter才会变为0,这意味run phase推出的条件满足,因此可以退出run phase。
对于uvm_objection类,用来反停止的控制方法包括:
- raise_objection ( uvm_object bj = null, string description = "" , int count = 1) 挂起objection
- drop_objection ( uvm_object bj = null, string description = "" , int count = 1) 落下objection
- set_drain_time ( uvm_object bj = null, time drain) 设置退出时间
对这几种典型方法,在实际应用中的建议包括:
- 对于component()而言,用户可以在run_phase()中使用phase.raise_objection()/phase.drop_objection()来控制run phase退出。
- 用户最好提供对于description字符串参数用来描述,这有利于后期的调试。
- 应该使用默认count值。
- 对于uvm_top或者uvm_test_top应该尽可能少使用set_drain_time()。
在简化了run phase退出机制之后,用户为了让使得run phase在全部激励完毕、DUT数据全部发送完毕以及所有数据比较结束之后才退出,需要懂得在何时挂起和落下objection。下面是一段典型的objection机制应用代码:
class test1 extends uvm_test;
`uvm_component_utils(test1)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
phase.raise_objection(this);
`uvm_info("run_phase", "entered ..", UVM_LOW)
#1us;
`uvm_info("run_phase", "exited ..", UVM_LOW)
phase.drop_objection(this);
endtask
endclass
initial begin
run_test("test1");
end
endmodule
输出结果:
UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top [run_phase] entered ..
UVM_INFO @ 1000000: uvm_test_top [run_phase] exited ..
UVM_INFO @ 1000000: reporter [TEST_DONE] 'run' phase is ready to proceed to the 'extract' phase
UVM_INFO @ 1000000: reporter [UVM/REPORT/CATCHER]
从输出结果来看,uvm_pkg::uvm_test_done实例会在test1的run_phase()执行完毕之后,才会退出run phase。这得益于test1::run_phase()中在仿真一开始就挂起了objection。在执行完毕之后,才落下了objection。这时,uvm_pkg::uvm_test_done认为run phase已经可以退出,进而转向了下一个extract phase。直到退出所有的phase之后,UVM进入了报告总结阶段。
那么如果没有挂起objection,UVM仿真会怎么样呢?
module objection_application;
import uvm_pkg::*;
`include "uvm_macros.svh"
class test1 extends uvm_test;
`uvm_component_utils(test1)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
`uvm_info("run_phase", "entered ..", UVM_LOW)
#1us;
`uvm_info("run_phase", "exited ..", UVM_LOW)
endtask
endclass
initial begin
run_test("test1");
end
endmodule
输出结果:
UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: uvm_test_top [run_phase] entered ..
UVM_INFO @ 0: reporter [UVM/REPORT/CATCHER]
这个简单的例码说明,如果在整个test及其子组件和sequence中,都没有通过objection()机制来控制run phase退出,那么所有组件的run phase都会通过fork-join_none线程提交之后,立即转入到extract phase。所以objection机制的应用是必不可少的。那么,在什么时间点应该挂起objection呢?再来看下面这段例码:
module objection_application;
import uvm_pkg::*;
`include "uvm_macros.svh"
class test1 extends uvm_test;
`uvm_component_utils(test1)
function new(string name, uvm_component parent);
super.new(name, parent);
endfunction
task run_phase(uvm_phase phase);
#1ps;
phase.raise_objection(this);
`uvm_info("run_phase", "entered ..", UVM_LOW)
#1us;
`uvm_info("run_phase", "exited ..", UVM_LOW)
phase.drop_objection(this);
endtask
endclass
initial begin
run_test("test1");
end
endmodule
输出结果:
UVM_INFO @ 0: reporter [RNTST] Running test test1...
UVM_INFO @ 0: reporter [UVM/REPORT/CATCHER]
这段代码中,看起来挂起objection()已经晚了,因为run phase还是立即退出了。这是因为在挂起objection之前还需要运行1ps,而处于fork-join_none后的run_phase任务在0时刻被调用后,run phase退出机制在0时刻发现没有挂起的objection,因此终止所有的run_phase()任务,继而转入了extract phase。所以,如果要在component中挂起objection,建议在一进入run_phase()后就挂起,保证objection counter及时被增加;另外,需要用户习惯在sequence中挂起objection,由于sequence不是uvm_component类,而是uvm_object类,因此它只有body()方法,而没有run_phase()方法。所以,在sequence中使用objection机制,可以在body()中的首尾部分分别调用uvm_test_done.raise_objection()和uvm_test_done.drop_objection()。有的用户习惯在pre_body()中调用uvm_test_done.raise_objection(),在post_body()中调用uvm_test_done.drop_objection(),这么做在多数情况下可以起到objection的防退出机制,但是一些情况下,sequence的pre_body()和post_body()并不会调用,所以objection机制也没有起到作用。因此,我们建议在sequence body()任务中raise/drop objection。
对于有OVM经验的用户,在使用objection机制时,他们会通过uvm_test_done.objection()/uvm_test_done.drop_objection()来控制run phase退出。这与phase.raise_objection()/phase.drop_objection()的作用是一致的,背后都是通过uvm_pkg的全局变量uvm_test_done(全局唯一的uvm_test_done_objection类的实例)来控制的。关于uvm_objection与uvm_test_done_objection类的关系,可以通过下面UML类图得到:
至此,phase机制和run phase的进入、退出机制已为读者们介绍到这里,希望读者们可以更好地理解phase机制,掌握run phase的进入、退出方法。
下一节课中,我们将为大家介绍UVM的另外一大魅力《config机制》。
智能推荐
我的开源世界观
我是一个Python程序员,在Web开发中我会用到一大堆的开源项目,如Linux、Python、Emacs、Spacemacs、Httpie、Flask、Requests、Sentry、IPython、Pyramid、Mako、Oh My Zsh等等。无法想象没有它们,我该如何工作。 相信你看到上述列表中出现的项目名字,有些也很熟悉,甚至是经常和它们在打交道。 我们先看一个有趣的事情(2016-0...
spring IOC核心类DefaultListableBeanFactory的世界观
IOC作为Spring的核心功能其核心思想: 帮用户管理对象,对象的创建不需要再由应用实现,而是交给了spring来管理。也就是对象的控制交给了第三方,也就是控制反转的由来。 下面是Spring IOC核心工厂类的结构图 从这个类结构图我们可以看出DefaultListableBeanFactory实现了哪些功能 1、 是一个BeanDefinition注册器 2、 最重要的它是一个bean工厂 ...
UVM_sequence机制
Sequence机制 1、什么是UVM的sequence机制 控制和产生一系列的事物,并通过某种方法将事物发送给driver的机制。具有控制何时产生事物,产生事物并将事物发送(通过sequencer)给driver的功能。Sequence是一个产生和发送数据的过程,会消耗仿真时间。只有在task_phase中才会启动。 事物产生和发送流程: (1)当进入某个task_phase之后,sequenc...
linux上安装Qt4.8.6+QtCreator4.0.3
一、Qt简介 Qt是1991年奇趣科技开发的一个跨平台的C++图形用户界面应用程序框架。它提供给应用程序开发者建立艺术级的图形用户界面所需的所有功能。Qt很容易扩展,并且允许真正地组件编程。 准备工作 操作系统:centos6.5 位数:64位 二、安装 1、获取源码Qt4.8.6 2、获取源码QtCreator4.0.3 2、安装QtCreator4.0.3 进入QtCreator安装界面,指定...
react-native metro 分析
文章目录 前言 概念 Resolution Transformation Serialization 打包方式 Moudles Plain bundle Indexed RAM bundle File RAM bundle 流程 前置流程 resolve流程 Transformer流程 序列化流程 缓存 为什么要缓存 缓存的请求与缓存 Metro配置 结构 前言 metro是一种支持ReactNa...
猜你喜欢
嵌入式Linux——应用调试:用户态打印段错误信息
简介: 很多时候我们会遇到段错误:segmentation fault,而段错误有时是由内核引起的,有时是由应用程序引起的。在内核态时,发生段错误时会打印oops信息,但是在用户态时,发生段错误却只会打印segmentation fault而并不会打印其他的信息。所以本文主要介绍在用户态时,通过修改内核设置和添加启动参数来打印引发segmentati...
springboot1.4.1整合logback 遇到的问题
springboot1.4.1整合logback 遇到的问题 项目使用了springboot1.4.1整合logback,然而设置的过期时间15 并没有生效, 2GB达到2G自动删除也没有生效,仅仅实现了按大小分割。 经过查看pom 父工程内的源码发现是默认的logback版本是1.1.7,而过期时间配置是在logback 1.1.8以后才支持的。 不得不说这是springboot1.4.1 的b...
记一次C/S架构的渗透测试
概述 目标站点是http://www.example.com,官网提供了api使用文档,但是对其测试后没有发现漏洞,目录、端口扫描等都未发现可利用的点。后发现官网提供了客户端下载,遂对其进行一番测试。 信息收集 先抓了下客户端的包,使用Fiddler和BurpSuite都抓不到,怀疑走的不是HTTP协议,用WireShark查看其确实用的是HTTP协议,但是数据包不好重放,这里最后使用了WSExp...
Linux:结合Securecrt进行文件上传(lrzsz)P2
1、安装rzsz软件 2、点击Scurecrt的option——X/Y/Z配置上传和下载目录 3、首先在Linux里切换到一个目录,然后用rz命令,文件就会上传到钙Linux的目录下 只要敲rz即可,然后在弹出的对话框里选择需要上传的文件即可 4、下载文件用sz 下载单个文件:在当前目录下有该文件 sz filename 下载...
SQL 提示作为 布局 生存工具指南
下面是一些展示AdventureWorks中表现最好的销售人员并列出他们的经理的结构化查询语言代码。 它产生以下结果。 所以,代码是有效的,但它是丑陋的。 如果我需要理解和改进代码,我首先需要把它变成可读的形式。 我有结构化查询语言提示,所以我可以按下计算机的ctrl按键键 踢你自己),它会应用默认的内置代码样式,并对此进行修复。 不,不是,因为我相信你仍然不喜欢它的格式。 没有两个开发人员能够就...
