数字IC验证23908--sequence

Sequence ltem介绍

  • item是基于uvm_object类,这表明了它具备UVM核心基类所必要的数据操作方法,例如copy()、clone()、compare()、
    record()等。
  • item通常应该具备有什么类型的数据成员呢?我们将它们划分为如下几类:
    ·控制类。譬如总线协议上的读写类型、数据长度、传送模式等。
    ·负载类。一般指数据总线上的数据包。
    ·配置类。用来控制driver的驱动行为,例如命令driver的发送间隔或者有无错误插入。
    ·调试类。用来标记一些额外信息方便调试,例如该对象的实例序号、创建时间、被driver解析的时间始末等。

item使用时的特点:

  • 如果数据域属于需要用来做驱动,那么用户应考虑定义为rand类型,同时按照驱动协议给出合适的constraint。
  • 由于item本身的数据属性,为了充分利用UVM域声明的特性,我们建议将必要的数据成员都通过`uvm_field_xxx宏来声明,以便日后uvm_object的基本数据方法自动实现,例如上面的print()函数。
  • t1没有被随机化而t2被随机化了,这种差别在item通往sequencer之前是很明显的。UVM要求item的创建和随机化都应该发生在sequence的body()任务中,而不是在sequencer或者driver中。
  • 按照item对象的生命周期来区分,它的生命应该开始于sequence的body()方法,而后经历了随机化并穿越sequencer最终driver,直到被driver消化之后,它的生命一般来讲才会结束。之所以要突出这一点,是因为一些用户在使用中会不恰当地直接操作item对象,直接修改其中的数据,或者将它的句柄发送给其它组件使用,这会无形中修改item的数据基因,或者延长一个item对象的寿命。这种不合适的对象操作方式是需要注意的,可以取代的方式则是合理利用copy()和clone()等数据方法。

ltem与Sequence的关系

  • 一个sequence可以包含一些有序组织起来的item实例,考虑到item在创建后需要被随机化,sequence在声明时也需要预留一些可供外部随机化的变量,这些随机变量一部分是用来通过层级传递约束来最终控制item对象的随机变量,一部分是用来对item对象之间加以组织和时序控制的。
  • 为了区分几种常见的sequence定义方式,我们在介绍sequence之前首先将其分类为:
    扁平类(flat sequence)。这一类往往只用来组织更细小的粒度,即item实例构成的组织。
    层次类(hierarchical sequence)。这一类是由更高层的sequence用来组织底层的sequence,进而让这些sequence或者按照顺序方式,或者按照并行方式,挂载到同一个sequencer上。
    虚拟类(virtual sequence)。这一类则是最终控制整个测试场景的方式,鉴于整个环境中往往存在不同种类的sequencer和其对应的sequence,我们需要一个虚拟的sequence来协调顶层的测试场景。之所以称这个方式为virtual sequence,是因为该序列本身并不会固定挂载于某一种sequencer类型上,而是将其内部不同类型sequence最终挂载到不同的目标sequencer上面。这也是virtual sequence不同于hierarchical sequence的最大一点.

Flat Sequence介绍

  • 一个flat sequence往往由细小的sequence item群落构成,在此之上sequence还有更多的信息来完备它需要实现的激励场景。
  • —般对于flat sequence而言,它包含的信息有:
    ·sequence_tem以及相关的constraint用来关联生成的item之间的关系,从而完善出一个flat_sequence的时序形态。
    ·除了限制sequence item的内容,各个item之间的时序信息也需要由flat_sequence给定,例如何时生成下一个item并且发送至driver。
    ·对于需要与driver握手的情况例如读探TP数据响应操作),都需要做出反应(例如slave的memory response数据响应操作),都需要sequence在收到另外一侧组件的状态后,再决定下一步操作,即响应具体事件从而创建对应的item并且发送出去。

Hierarchical Sequence介绍

  • Hierarchical sequence区别于flat sequence的地方在于,它可以使用其他sequence,当然还有item,这么做是为了创建更丰富的激励场景。
  • 通过层次嵌套关系,可以让hierarchical sequence使用其它hierarchical sequence、flat sequence和sequence item,这也就意味着,如果底层的sequence item和flat sequence的粒度得当,那么用户就可以充分复用这些sequence/item来构成形式更加多样的hierarchical sequence。
  • 接下来就之前定义的bus trans和flat_seq给出一个简单的hier_seq类,帮助理解这些sequence/item类之间的联系。
class hier_seq extends uvm _sequence;
	'uvm_object_utils(hier_seq)
	function new(string name = "hier_seq" ) ;
		super.new(name) ;
	endfunction
	task body ( ) ;
		bus_trans t1, t2 ;
		flat_seq s1, s2;
		'uvm_do_with(t1, { length == 2;})
		fork
			`uvm_do_with (s1, { length == 5; })
			'uvm_do_with(s2,{ length == 8; })
		join
		uvm_do_with(t2,{ length == 3; })endtask
endclass

uvm_do_with 做了三件事:1、创建item或者sequence。 2、设置约束。 3、发送出去

sequence和driver

在这里插入图片描述

  • driver同sequencer之间的TLM通信采取了get模式,即由driver发起请求,从sequencer一端获得item,再由sequencer将其传递至driver。
  • 作为driver,它往往是一个“永动机”,胃口很大的家伙,永远停不下来,只要它可以从sequencer获取item。
  • sequencer和item只应该在合适的时间点产生需要的数据,而至于怎么处理数据,则会由driver来实现。

端口和方法

为了便于item传输,UVM专门定义了匹配的TLM端口供sequencer和driver使用:

  • uvm_seq_item_pull_port #(type REQ=int, type RSP=REQ).
  • uvm_seq_item_pull_export #(type REQ=int, type RSP=REQ)
  • uvm_seq_item_pull_imp #(type REQ=int, type RSP=REQ, type imp=int)·
    由于driver是请求发起端,所以在driver一侧例化了下面两种端口:
  • uvm_seq_item_pull_port #(REP, RSP) seq_item_port.
  • uvm_analysis_port #(RSP) rsp_port //广播模式端口
    而sequencer一侧则为请求的响应端,在sequencer—侧例化了对应的两种端口︰
  • uvm_seq_item_pull_imp #(REQ, RSP, this_type)
  • seq_item_export.
  • uvm_analysis_export #(RSP) rsp_export
    在driver一侧端口可以使用以下方法
    在这里插入图片描述
  • get_next_item和item_done会经常出现。
    读者在这里需要了解关于REQ和RSP类型的一致性,由于uvm_sequencer与uvm_driver实际上都是参数化的类
  • uvm_sequencer #(type REQ=uvm_sequence_item,RSP=REQ)
  • uvm_driver #(type REQ=uvm_sequence_item,RSP=REQ)
  • 用户在自定义sequencer或者driver的时候,它们可以使用缺省类型typeREQ=uvm_sequence_item,以及RSP与REQ类型保持一致。
  • 这有一个潜在的类型转换要求,即driver得到REQ对象在进行下一步处理时,需要进行动态的类型转换,将REQ转换为
    uvm_sequence_item的子类型才可以从中获取有效的成员数据。
  • 另外一种可行的方式是在自定义sequencer和driver时就标明了其传递的具体item类型,这样就不用再进行额外的类型转换了。
  • driver消化完当前的request后,可以通过item_done(input RSP rsp_arg=null)方法来告知sequence此次传输已经结束,参数中的RSP可以选择填入,返回相应的状态值。
  • driver也可以通过put_response()或者put()方法来单独发送response。此外发送response还可以通过成对的
    uvm_driverrsp_port和uvm_driver::rsp_export端口来完成,方法为uvm_driver::rsp_port::write(RSP)。

事务传输过程分析

在定义sequencer时,默认REQ类型为uvm_sequence_item类型,这与稍后定义driver时采取默认REO类型保持一致。

  • flat_seq作为动态创建的数据生成载体,它的主任务flat_seq::body()做了如下的几件事情:
    ·通过方法create_item()创建request item对象。
    ·调用start_item()准备发送item。
    ·在完成发送item之前对item进行随机处理。
    ·调用finish_item()完成item发送。
    ·有必要的情况下可以从driver那里获取response item。

  • 在定义driver时,它的主任务driver:run_phase()也应通常做出如下处理:
    ·通过seq_item_port.get_next_item(REQ)从sequencer获取有效的requestitem。
    ·从request item中获取数据,进而产生数据激励。
    ·对request item进行克隆生成新的对象response item。
    ·修改response item中的数据成员,最终通过seq_item_port.item_done(RSP)将response item对象返回给sequence。

  • 对于uvm_sequence::get_response(RSP)和uvm_driver:item_done(RSP)这种成对的操作,是可选的而不是必须的,即用户可以选择uvm_driver不返回response item,同时sequence也无需获取response item。

    • 在高层环境中,应该在connect phase中完成driver到sequencer的TLM端口连接,比如例码在env::connect_phase()中通过drv.seq_item_port.connect(sqr.seq_item_export)完成了driver与sequencer之间的连接。
  • 在完成了flat_seq、sequencer、driver和env的定义之后,到了test1层,除了需要考虑挂起objection防止提前退出,便可以利用uvm_sequence类的方法uvm_sequence::start(SEQUENCER)来实现sequence到sequencer的挂载。

通信时序

  • 无论是sequence还是driver,它们通话的对象都是sequencer。当多个sequence试图要挂载到同一个sequencer上时,涉及sequencer的仲裁功能。
  • 重点分析sequencer作为sequence与driver之间握手的桥梁,是如何扮演好这一角色的。
  • 我们将抽取去这三个类的主要方法,利用时间箭头演示出完整的TLM通信过程。
    在这里插入图片描述
  • 对于sequence而言,无论是flat sequence还是hierarchical sequence,进—步切分的话,流向sequencer的都是sequence item,所以就每个item的“成长周期”来看,它起始于create_item(),继而通过start_item()尝试从sequencer获取可以通过的权限。
  • 对于sequencer的仲裁机制和使用方法我们暂且略过,而driver—侧将一直处于“吃不饱”的状态,如果它没有了item可以使用,将调用get_next_item()来尝试从sequencer—侧获取item。
  • 在sequencer将通过权限交给某一个底层的sequence前,目标sequence中的item应该完成随机化,继而在获取sequencer的通过权限后,执行finish_item()。
  • 接下来sequence中的item将穿过sequencer到达driver—侧,这个重要节点标志着sequencer第一次充当通信桥梁的角色已经完成。
  • driver在得到新的item之后,会提取有效的数据信息,将其驱动到与DUT连接的接口上面。
  • 在完成驱动后,driver应当通过item_done()来告知sequence已经完成数据传送,而sequence在获取该消息后,则表示driver与sequence双方完成了这一次item的握手传输。
  • 在这次传递中,driver可以选择将RSP作为状态返回值传递给sequence,而sequence也可以选择调用get_response(RSP)等待从driver—侧获取返回的数据对象。
  • 在多个sequence同时向sequencer发送item时,就需要信信后在明该item从哪个sequence来,ID信息在sequence创建Item时就赋值了。
  • 在到达driver以后,这个ID也可以用来跟踪它的sequence信息,使得运输和使用更加安全,sequencer可以根据ID信息来分发这些response item返回至正确的sequence源头。
  • 建议用户在driver中,通过clone()方式单独创建response item,保证request item和response item两个对象的独立性。
  • 也许有的用户为了“简便”,在使用了request item之后,就直接修改它的数据并作为要返回给sequence的response item。这么做看来似乎节能环保,但实际上殊不知可能埋下隐患,一方面它延长了本来应该丢进垃圾桶的request item寿命,同时也无 法再对request item原始生成数据做出有效记录。
  • 为了统一起见,用户可以不在定义sequence或者driver时指定sequence item类型,使用默认类型REQ = uvm_sequence_it
    em,但是用户需要注意在driver—侧的类型转换,例如对get_next_item(REQ)的返回值REQ句柄做出动态类型转换,待得到正确类型之后再进行接下来的操作。
  • 有的时候如果要复用一些验证IP,用户需要修改原有的底层sequenceitem。从处于验证复用的角度,我们建议通过继承于原有sequenceitem的方式定义新的item子类,同时在顶层通过factory override的方式用新的item类型替换原有的item类型。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值