目录

sequence和sequencer

将sequence挂载到sequencer

将item挂载到sequencer

宏定义使用实例

sequencer仲裁特性

实例

sequencer的锁定机制

virtual sequence

layering sequence


在上篇博客中,讲了sequencer和driver之间传递sequence item的握手过程,也讲了sequence和item之间的关系,下面我们来讲讲sequence和sequencer之间的关系,以及当多个sequence挂载到sequencer时冲裁这么处理。

sequence和sequencer


class bus_trans extends uvm_sequence_item;rand int data;`uvm_object_utils_begin(bus_trans)`uvm_field_int(data, UVM_ALL_ON)`uvm_object_utils_end...
endclassclass child_seq extends uvm_sequence;`uvm_object_utils(child_seq)...task body();uvm_sequence_item tmp;bus_trans req;tmp = create_item(bus_trans::get_type(), m_sequencer,"req");void'($cast(req, tmp));start_item(req);req.randomize with {data == 10;};finish_item(req);endtask
endclassclass top_seq extends uvm_sequence;`uvm_object_utils(top_seq)...task body();uvm_sequence_item tmp;child_seq cseq;bus_trans req;// create child sequence and itemscseq = child_seq::type_id::create("cseq");tmp = create_item(bus_trans::get_type(), m_sequencer,"req");// send child sequence via start()cseq.start(m_sequencer, this); // 挂载到sequencer// send sequence itemvoid'($cast(req, tmp));start_item(req);req.randomize with {data == 20;};finish_item(req);endtask
endclassclass sequencer extends uvm_sequencer;`uvm_component_utils(sequencer)...
endclassclass driver extends uvm_driver;`uvm_component_utils(driver)...task run_phase(uvm_phase phase);REQ tmp;bus_trans req;forever beginseq_item_port.get_next_item(tmp);void'($cast(req, tmp));`uvm_info("DRV", $sformatf("gor a item \n %s", req.sprint()), UVM_LOW)seq_item_port.item_done();endendtask
endclassclass env extends uvm_env;sequencer sqr;driver drv;`uvm_component_utils(env)...function void build_phase(uvm_phase phase);sqr = sequencer::type_id::create("sqr", this);drv = driver::type_id::create("drv", this);endfunctionfunction void connect_phase(uvm_phase phase);drv.seq_item_port.connect(sqr.seq_item_export);endfunction
endclass

将sequence挂载到sequencer

将sequence挂载到sequencer上:

uvm_sequence::start(uvm_sequencer_base sequencer,   uvm_sequence_base parent_sequence = null, int this_priority = -1, bit call_pre_post = 1)

第一个变量,是指明sequence要挂载到哪个sequencer上面;第二个sequence是默认当前的sequence是没有parent sequence的;第三个参数默认值是-1,会使得该sequence如果有parent_sequence会继承其优先级值,如果它是顶层sequence,则其优先级会被自动设置为100,用户也可以自己指定优先级数值;第四个参数建议使用默认值,这样body() 函数预定义的回调函数,uvm_sequence::pre_body()和uvm_sequence::post_body()两个方法会在uvm_sequence::body()的前后执行。

在上面的代码中,child_seq被嵌套在top_seq中,所以在挂载的时候,需要指明它的parent_sequence;而在test一层调用top_seq时,由于它是root sequence,所以不需要再指定parent sequence;另外,在调用挂载sequence时,需要对这些sequence进行例化。

将item挂载到sequencer

发送方法是将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&finish item方法时,需要使用create_item来对item进行创建,以及对其进行随机化处理。

对比start()方法和start_item()/finish_item()方法,要注意,它们面向的挂载对象是不同的。在执行start()的过程中,默认情况下会执行sequence的pre_body()和post_body(),但是如果start()的参数call_pre_post = 0,那么就不会执行。

        item之所以必须要依赖于sequence,是因为在执行finish_item的时候,用到了sequencer的方法,只有item通过sequence,拿到sequence挂载的sequencer的句柄,才能调用它的方法send_request(item)和wait_for_item_done() 。

发送item和sequence相关的宏:

上面为UVM宏定义,每个宏所对应要做的事情,打x的为要做。uvm_create(item) + uvm_send(item)的功能可以等效为uvm_do(item) 。

用户可以通过`uvm_do/`uvm_do_with来发送无论是sequence还是item。这种不区分对象sequence还是item的方式,带来了不少便捷,但容易让新手不知道这些宏定义背后做了那些工作,因此,需要先了解它们背后的sequence和item各自发送的方法。

不同的宏,可能会包含创建对象的过程,也可能不会创建对象。比如`uvm_do/`uvm_do_with会创建对象,而`uvm_send则不会创建对象,也不会将对象做随机处理,因此需要了解它们各自包含的执行内容和顺序。

    `uvm_do宏使用的场景只有在sequence中才可以使用,因为其中涉及了一些调用sequence中定义的方法,因此不能在其他例如uvm_test、uvm_env中调用sequence相关的宏定义。

宏定义使用实例

class child_seq extends uvm_sequence;...task body();bus_trans req;`uvm_create(req)`uvm_rand_send_with(req, {data == 10};)//上面两行宏定义也可以合并成一条:uvm_do_with(req, {data == 10};)endtask
endclassclass top_seq extends uvm_sequence;...task body();child_seq cseq;   //sequencebus_trans req;    //item// send child sequence via start()`uvm_do(cseq)// send sequence item`uvm_do_with(req, {data == 20;}) //使用宏定义后,发送sequence和item和之前相比,减少了很多代码endtask
endclass

尽量要避免使用fork-join_any和for-join_none来控制sequence的发送顺序,因为退出fork-join块之后,在执行后续的操作时,可能有sequence还没发送完毕,那么在用户想终止后台运行的sequence线程而使用disable时,可能会在不合适的时间点锁住sequencer。

如果一定要使用fork-join_any和for-join_none来控制sequence的发送顺序,应当在使用disable之前,对各个sequence线程的后台状况保持关注,尽量在发完item完成握手之后再终止sequence;如果要使用fork-join,那么应当确保有方法可以让sequence线程在满足一些条件后停止发送item。否则只要有一个sequence线程无法停止,则整个fork-join无法退出。

sequencer仲裁特性

在多个sequence挂载到一个seuqencer的情况下,uvm_sequencer类自建了仲裁机制来保证多个sequence在同时挂载到sequencer时,可以按照仲裁规则允许特定sequence中的item优先通过。

在实际使用中,我们可以通过uvm_sequencer::set_arbitration(UVM_SEQ_ARB_TYPE val)函数来设置仲裁模式,这里的仲裁模式UVM_SEQ_ARB_TYPE有如下几种值可以选择:

※ UVM_SEQ_ARB_FIFO:默认模式,来自sequences的发送请求,按照FIFO先进先出的方式被依次授权,和优先级没有关系,谁先申请,谁就获得。

※ UVM_SEQ_ARB_STRICT_FIFO:先看优先级,再看顺序,优先级高的先发送,优先级一致的,优先授权先申请的sequence。

※ UVM_SEQ_ARB_WEIGHTED:不同sequence的发送请求,按照它们的优先级权重随机授权。

※ UVM_SEQ_ARB_RANDOM:不同的请求会被随机授权,而无视它们的抵达顺序和优先级。

※ UVM_SEQ_ARB_STRICT_RANDOM:不同的请求,会按照它们的最高优先级随机授权,与抵达时间无关。

※ UVM_SEQ_ARB_USER:用户可以自定义仲裁方法user_priority_arbitration()来裁定哪个sequence的请求被优先授权。

实例

class bus_trans extends uvm_sequence_item;rand int data;...
endclassclass child_seq extends uvm_sequence;rand int base;...task body();bus_trans req;repeat(2) `uvm_do_with(req, {data inside {[base: base+9]};})endtask
endclassclass top_seq extends uvm_sequence;...task body();child_seq seq1,seq2,seq3;m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);fork`uvm_do_pri_with(seq1, 500, {base == 10;})`uvm_do_pri_with(seq2, 500, {base == 20;})`uvm_do_pri_with(seq3, 300, {base == 30;})joinendtask
endclassclass sequencer extends uvm_sequencer;...
endclassclass driver extends uvm_driver;...task run_phase(uvm_phase phase);REQ tmp;bus_trans req;forever beginseq_item_port.get_next_item(tmp);void'($cast(req, tmp));`uvm_info("DRV", $sformatf("got a item %0d from parent sequence %s", req.data, req.get_parent_sequence().get_name()), UVM_LOW)seq_item_port.item_done();endendtask
endclassclass env extends uvm_env;sequencer sqr;driver drv;...function void build_phase(uvm_phase phase);sqr = sequencer::type_id::create("sqr", this);drv = driver::type_id::create("drv",this);endfunctionfunction void connect_phase(uvm_phase phase);drv.seq_item_port.connect(sqr.seq_item_eport);endfunction
endclassclass test1 extends uvm_test;env e;...task run_phase(uvm_phase phase);top_seq seq;phase.raise_objection(phase);seq = new();seq.start(e.sqr);phase.drop_objection(phase);endtask
endclass

输出结果:

由于将seq1和seq2设置为同样的高优先级(500),而seq3设置为较低的优先级(300),这样在随后的UVM_SEQ_ARB_STRIC_FIFO仲裁模式下,可以从输出结果看到,按照优先级高低和传送请求时间顺序,先将seq1和seq2中的item发送完毕,随后再将seq3发送完。

sequencer的锁定机制

uvm_sequencer提供了两种锁定机制,分别通过lock()和grab()方法实现,这两种方法的区别在于:

lock()和unlock()这一对方法可以为sequence提供排外的访问权限,但前提条件是,该sequence首先需要按照sequencer的仲裁机制获得授权。而一旦sequence获得授权,则无需担心权限被收回,只有该sequence主动解锁(unlock)它的sequencer,才可以释放这一锁定的权限。lock()是一种阻塞任务,只有获得了权限,它才会返回。

grab()和ungrab()也可以为sequence提供排外的访问权限,而且它只需要在sequencer下一次授权周期时就可以无条件地获得授权。与lock方法相比grab方法无视同一时刻内发起传送请求的其他sequence,而唯一可以组织它的只有已经预先获得授权的其他lock或者grab的sequence。

如果sequence使用了lock()或者grab()方法,必须在sequence结束前调用unlock()或者ungrab()方法来释放权限,否则sequencer会进入死锁状态而无法继续为其余sequence授权

实例

class bus_trans extends uvm_sequence_item;...
endclassclass child_seq extends uvm_sequence;rand int base;...task body();bus_trans req;repeat(2) #10ns `uvm_do_with(req, {data inside {[base: base+9]};})endtask
endclassclass lock_seq extends uvm_sequence;...task body();bus_trans req;#10ns;m_sequencer.lock(this);`uvm_info("LOCK", "get exclusive access by lock()", UVM_LOW)repeat(3) #10ns `uvm_do_with(req, {data inside {[100:110]};})m_sequencer.unlock(this);endtask
endclassclass grab_seq extends uvm_sequence;...task body();bus_trans req;#20ns;m_sequencer.grab(this);`uvm_info("GRAB", "get exclusive access by grab()", UVM_LOW)repeat(3) #10ns `uvm_do_with(req, {data inside {[200:210]};})m_sequencer.ungrab(this);endtask
endclassclass top_seq extends uvm_sequence;...task body();child_seq seq1, seq2, seq3;lock_seq locks;grab_seq grabs;m_sequencer.set_arbitration(UVM_SEQ_ARB_STRICT_FIFO);fork`uvm_do_pri_with(seq1, 500, {base == 10;})`uvm_do_pri_with(seq2, 500, {base == 20;})`uvm_do_pri_with(seq3, 300, {base == 30;})`uvm_do_pri(locks, 300)`uvm_do(grabs)joinendtask
endclass

输出结果:

之所以seq1和seq2都在10ns的时候发送一次,而不是发送两次,是因为在发送item时,延迟了10ns再发送。然后lock_sequence锁住sequencer,发送三次item。

class grab_seq extends uvm_sequence;...task body();bus_trans req;#20ns;m_sequencer.grab(this);`uvm_info("GRAB", "get exclusive access by grab()", UVM_LOW)repeat(3) #10ns `uvm_do_with(req, {data inside {[200:210]};})m_sequencer.ungrab(this);endtask
endclass

从这段代码中,我们知道,grab_sequence在20ns的时候,就已经开始申请sequencer了(实际上seq1、seq2、seq3也同时发起了请求),但是在40ns才获得sequencer,这是因为sequencer被lock_sequence锁住了。等到40ns,unlock之后才被grab。被grab后,发送三次item,到70ns,ungrab。seq1、seq2、seq3再根据优先级依次发送item。

virtual sequence

virtual sequence可以承载不同目标sequencer的sequence群落,组织协调这些sequence的方式类似于高层次的hierarchical sequence。virtual sequencer和普通的sequencer有很大的不同,它起到了桥接其他sequencer的作用,即virtual sequencer是一个链接所有底层sequencer句柄的地方,是一个中心化的路由器。

virtual sequencer本身不会传送item数据对象,因此virtual sequencer不需要与任何driver进行TLM链接。所以用户需要在顶层connect阶段,做好virtual sequencer中各个sequencer句柄与底层sequencer实体对象的一一对接,避免句柄悬空。

在virtual sequence中使用uvm_do_on把不同sequence挂载到不同的sequencer上面,而不是想hierarchical sequence那样直接用uvm_do默认把sequence挂载到顶层。

对于virtual sequence而言,它可以承载各个子模块环境的element sequence,而最后通过virtual sequencer中的各个底层sequencer句柄,各个element sequence可以分别挂载到对应的底层sequencer上。

使用`uvm_declare_p_sequencer,可以在后台新建一个p_sequencer变量,而将m_sequencer的默认变量(uvm_sequencer_base类型)通过动态转换($cast),变为类型virtual_sequencer的p_sequencer。

        这种中心化的协调方式,使得顶层环境在场景创建和激励控制方面更加得心应手,而且在代码后期维护中,测试场景的可读性也得到了提高。

使用virtual sequence时容易遇到的错误:

※ 需要区分virtual sequence 同其它普通sequennce(element sequence、hierarchical sequence)

※ 需要区分virtual sequencer同其它底层负责传送数据对象的sequencer

※ 在virtual sequence中记得使用宏`uvm_declare_p_sequencer来创建正确类型的p_sequencer变量,方便接下来各个目标的sequencer索引。

※ 在顶层环境中记得创建virtual sequencer,并且完成virtual sequencer中各个sequencer句柄与底层sequencer的跨层次链接,避免句柄悬空。

layering sequence

在构建更加复杂的协议总线传输,例如PCIe,USB3.0等,那么通过一个单一的传输层级会对以后的激励复用、上层控制不那么友好。对于这种更深层次化的数据传输,在实际中无论是VIP还是自开发的环境,都倾向于通过若干抽象层次的sequence群落来模拟协议层次。

通过层次化的sequence可以分别构建transaction layer、transport layer和physical layer等从高抽象级到低抽象级的transaction转化。这种层次化的sequence构建方式,我们称之为layering sequence。例如在进行寄存器级别的访问操作,其需要通过transport layer转化,最终映射为具体的总线传输。

layering sequence会包含三部分,高抽象层次的item、低抽象层次的item、中间作转化的sequence。

在各个抽象级的sequencer中,需要有相应的转换方法,将从高层次的transaction从高层次的sequencer获取,继而转换为低层次的transaction,最终通过低层次的sequencer发送出去。例如adapter_seq负责从layer_sequencer获取layer_trans,再将其转换为phy_master_sequencer一侧对应的sequence或者transaction,最后将其从phy_master_sequencer发送出去。

UVM基础-Sequence、Sequencer(二)相关推荐

  1. UVM基础-Sequence、Sequencer(一)

    目录 Sequence.Sequencer.Driver大局观 Sequence和item item与sequence的关系 flat sequence hierarchical sequence s ...

  2. 【UVM基础】虚序列器与虚序列(virtual sequencer与virtual sequence)快速上手指南

    文章目录 一.virtual sequence与virtual sequencer 二.virtual sequence and sequencer的产生 2.1.嵌入序列器 2.2.嵌入序列,控制序 ...

  3. uvm中sequence和virtual sequence中objection的控制

    sequence中的objection的控制策略 在整颗UVM树中,树的结点很多,理论来说在任何组件中都可以控制objection.一般在sequence和virtual sequence中,也有在s ...

  4. Python基础学习(二)-条件,循环语句

    Python基础学习(二)-条件,循环语句     一,条件语句    1,if  else           if  判断条件:               执行语句...           e ...

  5. python 基础系列(二) — Python基本语法

    python 基础系列(二) - Python基本语法 python基础系列索引 python 基础系列(一) - Python介绍 python 基础系列(二) - Python基本语法 pytho ...

  6. Oracle数据库基础入门《二》Oracle内存结构

    Oracle数据库基础入门<二>Oracle内存结构 Oracle 的内存由系统全局区(System Global Area,简称 SGA)和程序全局区(Program Global Ar ...

  7. Tensorflow深度学习之十二:基础图像处理之二

    Tensorflow深度学习之十二:基础图像处理之二 from:https://blog.csdn.net/davincil/article/details/76598474   首先放出原始图像: ...

  8. SQL基础使用入门(二): DML语句和DCL语句

    SQL语句第二个类别--DML 语句 DML是数据操作语言的缩写,主要用来对数据表中数据记录实例对象进行操作,包括插入.删除.查找以及修改四大操作,这也是开发人员使用中最为频繁的操作. 1.插入记录 ...

  9. Linux中的基础IO(二)

    Linux中的基础IO(二) 文章目录 Linux中的基础IO(二) 一.基本接口 二.文件描述符 三.文件描述符的分配规则 四.重定向 五.dup2系统调用 六.minishell 一.基本接口 i ...

最新文章

  1. Access和Access VBA学习总结
  2. ioc spring 上机案例_通过实例解析Spring Ioc项目实现过程
  3. Java限流之 —— Nginx限流
  4. 文博项目-终端网口测试-软件
  5. “618”台前幕后的那些事
  6. ORACLE1.8-序列
  7. python之模块导入和包
  8. 基于Python的开源人脸识别库:离线识别率高达99.38%(转)
  9. 登陆注册页面html代码(仿知乎)
  10. Vue.filter过滤器存储单位换算按KB 、M、 G显示字节大小
  11. 三维全景融合拼接技术
  12. burst什么意思_burst是什么意思
  13. Joyoshare Media Cutter for Mac(智能媒体剪辑软件)激活版
  14. 面向初学者的 Python IDE:Thonny,你值得一试
  15. erlang使用httpc:request报错nxdomain
  16. 加入购物车里面的商品被商家调整价格以后如何处理金额问题
  17. 机器学习——线性回归(拟合一条直线)
  18. SonarQube代码质量管理
  19. 我的第一个JDBC小项目
  20. Hibernate2:构建单例模式的SessionFactory

热门文章

  1. js 比较啷个日期的大小
  2. 无法打开计算机开始菜单,开始菜单,教您开始菜单无法打开
  3. C#命名空间 System.IO思维导图
  4. 关于微软虚拟机更新后密码问题
  5. 去日本东京旅行(2)-- 国内机场停车篇
  6. 软件测试工作学习必备指南——硬实力
  7. cada0图纸框_CAD的图框应该怎么画-百度经验
  8. 基于TCP的网络实时聊天室(socket通信案例)
  9. 和数传媒:人工智能和区块链可能是典型应用
  10. -XX:SoftRefLRUPolicyMSPerMB从名字看不出什么意思?【官文解读】