UVM——sequence机制(六)
标签: UVM
sequence机制(下)
sequence机制(五)已经了解到sequencer与driver之间的传递sequence item的握手过程,同时也掌握了sequence与item之间的关系。接下来,我们需要就sequence挂载到sequencer上的常用方法做出总结,我们可以通过对这些常用方法和宏的介绍,了解到它们的不同的使用场景。另外,面对多个sequence如果需要同时挂载到sequencer时,那么就面临着仲裁的需要,uvm_sequencer自带有仲裁特性,结合着sequence的优先级设定,最终可以实现想要的效果。
一、sequence的启动方式细节
UVM中sequence的启动分为显示启动和隐式启动两种方式。
- 显式启动(直接启动)——调用start()方法启动。
- 隐式启动 ——使用uvm_config_db机制配置default_sequence启动。
//sequence的显式启动
//该方法提起和落下objection,通过phase.raise_objection(this)/phase.drop_objection(this)
my_sequence seq = my_sequence::type_id::create("seq");
phase.raise_objection(this);
seq.start(sequencer);
phase.drop_objection(this)
//sequence的隐式启动
//使用uvm_config_db#(uvm_object_wrapper)配置default_sequence,事实上default_sequence会调用start任务
uvm_config_db#(uvm_object_wrapper)::set(this,"env.i_agt.sqr.main_phase",
"default_sequence",
case0_sequence::get_type());
//sequence的隐式启动二种先实例化要启动的sequence,之后再通过default_sequence启动:该示例在uvm1.1可以正常运行,uvm1.2中有问题。
function void my_case0::build_phase(uvm_phase phase);
case0_sequence cseq;
super.build_phase(phase);
cseq = new("cseq");
uvm_config_db#(uvm_sequence_base)::set(this, "env.i_agt.sqr.main_phase","default_sequence",cseq); endfunction
sequence启动后,会根据参数设置情况,自动执行*pre_start(), pre_body(), parent_seq.pre_do(),parent_seq.mid_do(), body(), parent_seq.post_do(), post_body, post_start()*等函数/任务。
seq.start (m_sequencer, null, , 1);
// The following methods will be called in start()
seq.pre_start(); (task)
seq.pre_body(); (task) if call_pre_post == 1
parent_seq.pre_do() (task) if parent_seq != null
parent_seq.mid_do(this) (func) if parent_seq != null
seq.body() (task) your code
parent_seq.post_do(this) (func) if parent_seq != null
seq.post_body() (task) if call_pre_post == 1
sub_seq.post_start() (task)
二、常见sequence/item发送的方法和宏
针对将sequence挂载到sequencer上的应用
uvm_sequence::start(uvm_sequencer_base sequencer,
uvm_sequence_base parent_sequence = null,
int this_priority = -1,
bit call_pre_post = 1)
在使用该方法的过程中,用户首先应该指明sequencer的句柄。如果该sequence是顶部的sequence,即没有更上层的sequence嵌套它,则它可以省略对第二个参数parent_sequence的指定。第三个参数的默认值-1会使得该sequence如果有parent_sequence,即继承下来,如果是root sequence,则将其优先级设定为100。 第四个参数建议使用默认值,这样的话,uvm_sequence::pre_doby()和uvm_sequence::post_body()两个方法会在uvm_sequence::body()的前后执行。
将item挂载到sequencer上的应用
uvm_sequence::start_item (uvm_sequence_item item,
int set_priority = -1,
uvm_sequencer_base sequencer=null);
uvm_sequence::finish_item (uvm_sequence_item item, int set_priority = -1);
于start_item()的使用,第三个参数用户需要注意是否要将item挂载到非当前parent sequence挂载到的sequencer上面,有点绕口是吗?简单来说,如果你想将item和parent sequence挂载到不同的sequencer上面,你就需要指定这个参数。默认情况下,“父”与“子”都是走的一条道路(virtual sequence除外,我们会在后面讨论)。在使用这一对方法时,用户除了需要记得创建item,例如通过uvm_object::create()或者uvm_sequence::create_item(),还需要在它们之间完成item的随机化处理。从这一点建议来看,也需要读者了解到,对于一个item的完整传送,sequence要才sequencer一侧获得什么权限,也可以顺利将其发送至driver。我们可以通过拆解这三个步骤得到更多的细节:
- 创建item
- 通过start_item(),等待获得sequence的授权许可,其后执行parent sequence的方法pre_do()。
- 对item进行随机化处理
- 通过finish_item(),在对item进行了随机化处理之后,执行parent sequence的mid_do(),以及调用uvm_sequencer::send_request()和uvm_sequencer::wait_for_item_done()来将item发送至sequencer再完成与driver之间的握手。最后,执行了parent_sequence的post_do()。

如果对比start()方法和start_item()/finish_item(),读者首先要分清它们面向的挂载对象是不同的。此外,还需要清楚,在执行start()过程中,默认情况下,会执行sequence的pre_body()和post_body(),但是如果start()的参数call_pre_post = 0,那么就不会这样执行,所以在一些场景中的,UVM用户会奇怪为什pre_body()和post_body()没有被执行。在这里,用户需要注意,pre_body()和post_body()并不是一定会被执行的,这一点同UVM的phase顺序执行时有区别的。它们执行的顺序关系和条件在第一部分sequence的启动方式细节得知。
而对于pre_do()、mid_do()、post_do()而言,这是子一级的item/sequence在调用过程中,会间接调用parent sequence的pre_do()等方法。只要在参数传递过程中,确保child item/sequence与parent sequence的联系,那么这些执行过程是会按照上面的描述依次执行的。下面的也给出一段自然代码描述,来表示执行item时的相关方法执行顺序:
create_item(item) \
sequencer.wait_for_grant(prior) (task) \ start_item \
parent_seq.pre_do(1) (task) / \
`uvm_do* macros
parent_seq.mid_do(item) (func) \ /
sequencer.send_request(item) (func) \finish_item /
sequencer.wait_for_item_done() (task) /
parent_seq.post_do(item) (func) /
在熟悉了sequence/item的传送方法之后,我们就可以进一步来看看常见的宏有哪些,它们的主要作用是什么。下面给出了一张列表对这些宏做出总结:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-75JzXPYv-1608018323890)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\image-20201215115818179.png)]
正是通过几个sequence/item宏打天下的方式,用户们可以通过uvm_do和uvm_do_with来发送无论是sequence还是item。这种不区分对象是sequence还是item的方式,带来了不少便捷,但也容易引起verifier们的惰性。所以在使用它们之前,需要先了解它们背后的sequence和item各自发送的方法。
uvm_do系列宏主要有以下8个:
`uvm_do(SEQ_OR_ITEM) //1. 根据sequence_item实例,随机化产生数据
`uvm_do_with(SEQ_OR_ITEM, CONSTRAINTS) //2. 在随机化数据的基础上,添加约束
`uvm_do_pri(SEQ_OR_ITEM, PRIORITY)
`uvm_do_pri_with(SEQ_OR_ITEM, PRIORITY, CONSTRAINTS)
`uvm_do_on(SEQ_OR_ITEM, SEQR) //3. 随机化同时,显式的指定使用哪个sequencer来发送此transaction
`uvm_do_on_pri(SEQ_OR_ITEM, SEQR, PRIORITY)
`uvm_do_on_with(SEQ_OR_ITEM, SEQR, CONSTRAINTS)
`uvm_do_on_pri_with(SEQ_OR_ITEM, SEQR, PRIORITY, CONSTRAINTS)
- `uvm_do系列宏其实是将下述动作封装在了一个宏中(start_item与finish_item运用)。在实际的代码编写中,工程师可以不使用宏uvm_do()处理数据,而是根据实际情况手动执行这些内嵌程序。
req = my_sequence::type_id::create("req"); \ 1. 创建item对象实例;
start_item(req); \ 2.获取sequencer的授权许可;
assert(req.randomzie() with {req.data == 100;}); //assert(req.ranomzie()); 3.**对item进行随机化处理**;
finish_item(req); \ 4.将item发送至sequencer,进而完成与driver之间的交互
- 宏`uvm_do_with (item, { constraint })与 宏 ‘uvm_do( )无本质区别,只是多了约束条件;需要说明的是宏‘uvm_do( )不支持randc类型的随机变量。
三、sequence的仲裁机制
- UVM要求item的创建和随机化都应该发生在sequence的body()任务中,而不是在sequencer或者driver中;
- 按照item对象的生命周期来区分,它的生命应该开始于sequence中的创建,而后经历了随机化和穿越sequencer最终到达driver,直到被driver消化之后,它的生命周期一般来讲才算寿终正寝。
- 在driver的run_phase阶段,利用TLM端口
seq_item_port的get_next_item()和item_done()方法控制数据包的传输;
class tr_sequence extends uvm_sequence#(transaction);
...
virtual task body();
if(starting_phase != null)
starting_phase.raise_objection(this,"starting"); //1.启动仿真,生产数据
`uvm_do(req); //2.通过宏`uvm_do自动随机化产生数据
if(starting_phase != null)
starting_phase.drop_objection(this,"done"); //3.结束仿真
endtask
endclass
class driver extends uvm_driver#(transaction);
...
virtual task run_phase(uvm_phase phase);
forever begin
seq_item_port.get_next_item(req); //4.driver申请数据
send(req); //5.按照物理时序处理接收到的数据
seq_item_port.item_done(); //6.数据传输完毕
end
endtask
endclass
当一个sequence启动后,会自动执行sequence中的body任务,在body任务中可以调用`uvm_do系列宏来生产数据。
- 当同一个sequencer上启动多个sequence时,由于sequencer会依据何种选择启用哪一个sequence的transaction存疑,故引入仲裁机制。使用仲裁机制的相关系列宏如下所指示:(默认仲裁算法是SEQ_ARB_FIFO,遵循先入先出,不考虑优先级)
SEQ_ARB_FIFO, //默认仲裁算法是SEQ_ARB_FIFO,遵循先入先出,不考虑优先级
SEQ_ARB_WEIGHTED, //加权的仲裁
SEQ_ARB_RANDOM, //是完全随机选择
SEQ_ARB_STRICT_FIFO, //是严格按照优先级的按照先入先出的顺序选择
SEQ_ARB_STRICT_RANDOM, //是严格按照优先级的按最高里面随机
SEQ_ARB_USER//用户可以自定义
四、sequence对sequencer的占用或失效
1. 用lock()和grab()排他性占用sequencer
在sequence的body()中使用lock()…unlock()或grab()…ungrab(), 可以让在其中间发送(假设中间的sequence具有最高级)的所有transaction连续的获取sequencer的仲裁,从而连续的发送到driver而不被别是sequence打断。
二者的区别仅在仲裁机制不一样:
lock会放在仲裁队列的末尾,sequencer将原来就在仲裁队列里的transaction发送完后才执行lock的transaction,一旦lock占用sequencer后,只有unlock后才释放。
grab会放在仲裁队列的最前面,grab操作比lock操作优先级更高,sequencer会立即执行grab的transaction,同样一旦grab占用sequencer后,只有ungrab后才释放。
grab实时性强,是插队操作。unlock则不是。
2. sequence的is_revelant函数和wait_for_relevant任务。
- sequencer在仲裁时, 会查看sequence的is_relevant函数的返回结果, 为1说明此sequence有效并参加仲裁, 否则无效。
- 可以通过重载is_relevant函数来使sequence失效。
- 当sequencer将所有有效transaction发送完毕后,它会调用处于无效状态的sequence的**wait_for_relevant任务。**当wait_for_relevant返回后,sequencer还会继续调用is_relevant函数。
- 在wait_for_relevant任务中,user一定要清除sequence的无效状态。否则系统会进入死循环。
六、Sequence的层次化
hierarhical sequence主要面对的对象是同一个sequencer,即hierarchical sequence本身也会挂载到sequencer上面,而对于virtual sequence而言,它内部的sequence可以允许面向不同的sequencer种类,这一点我们也将在接下来详细讨论。
对于顶层的测试环境, 测试序列所要协调的不再只是面向一个sequencer的sequence群,而是要面向多个sequencer的sequence群, 面向不同sequencer的sequence群如何挂载到不同的sequencer上呢? 这就需要用到virtual sequence和virtual sequencer来解决。对于单一的sequencer下的sequence群,其挂接较为简单,即通过uvm_sequence::start()来挂载root sequence,而在内部的child sequence可以通过宏`uvm_do()来实现。
- virtual sequence:承载不同目标sequencer的sequence群落,
实现sequence同步;virtual sequence一般只会挂载到virtual sequencer上,且没有自己的sequence_item,只用于控制其他的sequence执行顺序,起统一调度作用。 - virtual sequencer:桥接其它sequencer,即
连接所有底层sequencer的句柄(指针),是一个中心化的路由器。virtual sequencer本身并不传送item数据对象,因此不需要与driver进行TLM连接。所以用户需在顶层的connect阶段做好virtual sequencer中各个sequencer句柄与sequencer实体对象的一一连接,避免句柄悬空。
在验证环境中或测试案例中,使用virtual sequence可以来同步不同接口之间的数据和时序。
virtual_sequence
在virtual sequence中定义sequence句柄,在body( )任务中控制这些序列;- 通过宏`uvm_declare_p_sequencer( )来绑定virtual sequencer同时声明p_sequencer,并操作virtual sequencer中的内容;
- 通过宏`uvm_do_on( )将虚序列器句柄与虚序列句柄相连接;
- 注意区别:virtual_sequence中嵌套的sequence和普通sequence中嵌套sequence。普通sequence中嵌套的sequence都在同一个sequencer上启动(通过sequencer仲裁决定);而在virtual sequence中嵌套的sequence可以在不同sequencer实体上同时启动。

class virtual_sequence extends uvm_sequence;
`uvm_object_utils(virtual_sequence)
`uvm_declare_p_sequencer(virtual_sequencer) //1.声明p_sequencer,操作virtual sequencer中的内容
bfm_sequence bfm0_seq; //2.插入序列句柄
bfm_sequence bfm1_seq; //序列seq可由不同的seqr启动
virtual task body();
`uvm_do_on(bfm0_seq,p_sequencer.bfm0_sqr); //3. 将虚序列器句柄与虚序列句柄相连接
`uvm_do_on(bfm1_seq,p_sequencer.bfm1_sqr);
endfunction
endclass
在使用uvm_do_on宏的情况下,虽然bfm_seq是在virtual_sequence上启动,但他们最终会被交给p_sequencer.bfm_sqr,也即env.bfm_agt.bfn_sqr。这也就是virtual sequence和virtual sequencer中virtual的来源。他们各自不产生transaction,只是控制其他sequence为相应的sequencer产生transaction。
- 关于p_sequencer的说明:
sequence类里有一个uvm_sequencer_base类型m_sequencer指针,当sequence和sequencer关联后,m_sequencer会自动指向该sequencer,但通过m_sequencer不能直接使用seqr里的变量,因为m_sequencer是父类句柄,是不能向子类访问的。否则会出现编译错误。只能使用cast强制向子类转换后,才能通过m_sequencer.xxx来访问该seqr内的xxx变量。
UVM引入p_sequencer,可以自动的实现上面所述的cast动作,从而可以在sequence中自由使用关联sequencer内的变量。
p_sequencer并不是UVM自动地在sequence的创建的,需要用户使用uvm_declare_p_sequencer宏声明,之后UVM会自动实现指向seqr及cast的动作。
virtual sequencer
在virtual sequencer中定义指向其他真实sequencer句柄指针;

class virtual_sequencer extends uvm_sequencer;
bfm_sequencer bfm0_sqr; //1.插入虚序列器句柄,指向真实sequencer
bfm_sequencer bfm1_sqr;
function new(string name, uvm_component parent);
super.new(name,parent);
endfunction
endclass
连接sequencer到virtual sequencer
- 在build_phase阶段创建virtual sequencer;将default sequence设置为null,关闭相应的sequence;配置virtual sequencer,在需要的phase阶段执行virtual sequence;
在connect_phase阶段,将被控制的sequencers与virtual sequencer关联一起;

class top_env extends uvm_env;
virtual_sequencer v_sqr; //and subenvs
...
virtual funvtion void build_phase(uvm_phase phase);
super.build_phase(phase);
...
v_sqr = virtual_sequencer::type_id::create("v_sqr",this);
uvm_config_db#(uvm_object_wrapper)::set(this,"subenv0.bfm0_agt.sqr.main_phase","default_sequence",null);
uvm_config_db#(uvm_object_wrapper)::set(this,"subenv0.bfm1_agt.sqr.main_phase","default_sequence",null);
uvm_config_db#(uvm_object_wrapper)::set(this,"v_sqr.main_phase","default_sequence",virtual_sequence::get_type());
endfunction
virtual function void connect_phase(uvm_phase phase);
v.sqr.bfm0_sqr = bfm_agt0.bfm0_sqr; //将被控制的真实sequencers赋给virtual sequencer的指针,建立连接
v.sqr.bfm1_sqr = bfm_agt1.bfm1_sqr;
endfunction
endclass
参考:
http://www.eetop.cn/blog/html/28/1561828-5940198.html
http://blog.eetop.cn/blog-1561828-5940199.html
https://blog.csdn.net/weixin_46022434/article/details/105869127
智能推荐
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按键键 踢你自己),它会应用默认的内置代码样式,并对此进行修复。 不,不是,因为我相信你仍然不喜欢它的格式。 没有两个开发人员能够就...
Vue+Springboot解决数据传输时参数格式不匹配问题
前端:使用的是ant design vue ,端口号为8000 后端:使用的是springboot框架开发,端口号为8080 需求:已经解决跨域问题,前端发送登录的信息给后台,后台接收不到 样例: 前端: 后台: 请求的数据格式为json格式,后台参数类型不匹配 解决方案 第一种: 修改后端,参数类型: 第二种方式: 在前端vue框架中加入qs插件,qs 是一个增加了一些安全性的查询字符串解析和序...
Flex布局做出自适应页面--语法和案例
本文发布在: github项目地址:https://github.com/tenadolanter/flex-layout-demo SegmentFault地址:https://segmentfault.com/a/1190000012916949/ CSDN地址:http://blog.csdn.net/qq_34648000/article/details/79115294 博客园地址:ht...
Java - 基于 Apache POI 创建 Excel 文件
基于 Apache POI 创建 Excel 文件 准备 新建 Maven Project,引入依赖: 创建行和列 设置列宽 设置列宽(第 19 行): 注意:其他行的首列的宽度是受第一行、第一列的影响而变宽,并非我们设置的。 设置字体颜色 设置字体颜色(第 25 ~ 31 行): 设置网页超链接 设置网页超链接(第 18、27 ~ 29 行): 参考 java操作excel常用的两种方式...
