UVM序列篇之四:sequencer和driver

本文转自:http://www.eetop.cn/blog/html/28/1561828-5940197.html

我们之前在《新手上路》中谈过,driver同sequencer之间的TLM通信采取了get模式,即由driver发起请求,从sequencer一端获得item,再由sequencer将其传递至driver。按照TLM通信模式的描述, TLM通信可以绘制为下图:

UVM序列篇之四:sequencer和driver_第1张图片

作为driver,它往往是一个“永动机”,胃口很大的家伙,永远停不下来,只要它可以从sequencer获取item,它就能一直跳下去,根本停不下来。这同我们之前《sequence和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

 

通常情况下,用户可以通过匹配的第一对TLM接口完成item的完整传送,即driver::seq_item_port和sequencer::seq_item_export。这一段端口在连接时的同其它端口连接一样,即通过driver::seq_item_port.connect(sequencer::seq_item_export)完成。而这一种类型的TLM接口主要支持如下的方法:

  • task get_next_item(output REQ req_arg):采取blocking的方式等待从sequence获取下一个item。

  • task try_next_item(output REQ req_arg):采取nonblocking的方式从sequencer获取item,如果立即返回的结果req_arg为null,则表示sequence还没有准备好。

  • function void item_done(input RSP rsp_arg=null):用来通知sequence当前的sequence item已经消化完毕,可以有选择性地传递RSP参数,返回状态值。

  • task wait_for_sequences():等待当前的sequence直到产生下一个有效的item。

  • function bit has_do_available():如果当前的sequence准备好而且可以获取下一个有效的item,则返回1,否则返回0。

  • function void put_response(input RSP rsp_arg):采取nonblocking方式发送response,如果成功返回1,否则返回0。

  • task get(output REQ req_arg):采用get方式获取item。

  • task peek(output REQ req_arg):采用peek方式获取item。

  • task put(input RSP rsp_arg):采取blocking方式将response发送回sequence。

 

上面的这一类接口功能是主要用来做request获取和response返回的。读者们在这里需要了解的是,关于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的时候,它们可以使用缺省类型type REQ=uvm_sequence_item,以及RSP与REQ类型一致。同时这会带来一个潜在的类型转换要求,即driver得到REQ对象(uvm_sequence_item)在进行下一步处理时,需要进行动态的类型转换,将REQ转换为uvm_sequence_item的子类型才可以从中获取有效的成员数据;而另外一种可行的方式是在自定义sequencer和driver时就标明了其传递的具体item类型,这样也就不用再进行二次的类型转换了。通常情况下,RSP类型与REQ类型保持一致,这么做的好处是为了便于统一处理,方便item对象的拷贝、修改等操作。

 

在driver消化完当前的request,即可以通过item_done(input RSP rsp_arg=null)方法来告知sequence此次传输已经结束,参数中的RSP可以选择填入,返回正确的状态值。driver也可以单独通过put_response()或者put()方法来单独发送response。此外,发送response还可以通过成对的uvm_driver::rsp_port和uvm_driver::rsp_export端口来完成,方法为uvm_driver::rsp_port::write(RSP)来完成。

 

接下来,我们就sequencer和driver的这一典型的item传输给出一段例码,帮助读者理解整个传输过程的起点、各个重要节点以及最后的终点。读者一旦理解了这其中的朴素原理,那么这两个组件之间的握手也就不再那么神秘了。

UVM序列篇之四:sequencer和driver_第2张图片

 

UVM序列篇之四:sequencer和driver_第3张图片

UVM序列篇之四:sequencer和driver_第4张图片

输出结果:

UVM序列篇之四:sequencer和driver_第5张图片

 

上面这段例码给出了从item定义,到sequence定义,最后到sequencer与driver的连接。这段精简的代码对于读者理解driver从sequencer获取item,经过时序处理,再返回给sequence很有帮助。为此,我们做出详细的分析,帮助读者理清例码中的关键处理:

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

  • 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获取有效的request item。

    • 从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端口连接,比如在例码中drv.seq_item_port.connect(sqr.seq_item_export)。

  • 在完成了flat_seq、sequencer、driver和env的定义之后,到了test1层,除了需要考虑挂起objection防止退出,便可以利用uvm_sequence类的方法uvm_sequence::start(SEQUENCER)来实现sequence到sequencer的挂载。

 

上面是对于例码重点的详细解释,在介绍flat_seq::body()时,例码实际上是将以往的`uvm_do等常用的宏进行了拆解,这些常用的sequence/item的宏和主要方法我们也将在下一节《sequencer和sequence》中为大家介绍。

 

无论是sequence还是driver,它们与之通话的对象都是sequencer。多个sequence都试图要挂载到同一个sequencer上时,涉及sequencer的仲裁功能,这也会在下一节谈到。我们本节重点分析sequencer作为sequence与driver之间握手的桥梁,是如何扮演好这一角色的。在下面的图中,我们将抽取去这三个类的主要方法,利用时间箭头演示出完整的TLM通信过程。

UVM序列篇之四:sequencer和driver_第6张图片

 

在这张图中,读者们可以结合上面的例码,找到各个关键节点的处理方式。

  • 对于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在获取该消息后,就表示正式完成了这一次item的握手传输。在这次传递中,driver可以选择将RSP作为状态返回值传递给sequence,而sequence也可以选择调用get_response(RSP)等待从driver一侧获取返回的数据。

 

最后,在结束本节之前,是我们关于sequencer与driver之间握手的代码建议。

  • 在多个sequence同时向sequencer发送item时,就需要有ID信息表明该item从哪个sequence来,这个ID信息在sequence创建item时就赋值了,而在到达driver以后,这个ID也能用来跟踪它的sequence信息,这就跟食品加工从源头就标记二维码一样,使得运输和使用更加安全。这个ID信息在稍后driver假如要返回response item时,需要给定正确的信息,如上面例码中通过函数set_sequence_id()来标记,这也就使得sequencer可以根据ID信息来分发这些response item返回至正确的sequence源头。

  • 我们建议用户在driver中,通过clone()的方式单独创建response item,保证request item和response item两个对象的独立性。也许有的用户为了“简便”,而在使用了request item之后,就直接修改了它的数据作为要返回给sequence的response item。这么做看来,似乎节能环保,但实际上殊不知可能埋下隐患,一方面它延长了本来应该丢进垃圾桶的request item寿命,同时也无法再对request item原始生成数据做出有效记录。所以,谈到这里,请读者们记住一点,clone()和copy()是个好习惯,虽然多了那么几行代码,但你的代码稳健性无形中却提高了,这种代码方式可以帮助减少一些可能的隐患。

  • 为了统一起见,用户可以不在定义sequence或者driver时指定sequence item类型,使用默认类型REQ = uvm_sequence_item,但是用户需要注意在driver一侧的类型转换,例如get_next_item(REQ)的输出REQ句柄应当做出二次转换,得到正确类型之后再进行接下来的操作。

  • 有的时候,如果要复用一些验证IP,用户需要修改原有的底层sequence item。这个时候,处于验证复用的角度,我们建议通过继承于原有sequence item的方式定义子类,同时在顶层通过factory override的方式用新的sequence item替换原有的sequence item类型。

你可能感兴趣的:(IC_UVM)