UVM(七)之phase及objection

2018-02-26 14:52:24 浏览数 (1)

UVM(七)之phase及objection

这两个概念与UVM验证平台息息相关,phase就好比铁轨,让UVM这趟列车在铁轨上向前运行,不会脱轨,不会跳过某一段而直接到达后一段,objection则更像是能量,给列车提供能量,控制着这趟列车何时终止。

phase

1.为什么要分成phase

verilog中有非阻塞赋值和阻塞复制,相应的,在仿真器中要实现NBA区域和Active区域,这样在不同的区域做不同的事情,可以避免竞争关系的存在导致的变量值不确定的情况。同样的,一个验证平台是很复杂的,要搭建一个验证平台是一件相当复杂的事情,要正确的掌握这些步骤并理顺他们是相当难得一个过程。

举一个简单的例子,一个env下面会实例化agent,scoreboard,reference model等,agent下面又会有sequencer,driver,monitor。而且这些组件之间还有连接关系,如agent中monitor的输出要送给scoreboard或reference model,这种通信的前提要先把两者连接起来,reference model要和scoreboard连接在一起,可以如下写:

代码语言:js复制
scoreboard = new;
reference_model = new;
reference_model.connect(scoreboard);
agent = new;
agent.driver = new;
agent.monitor = new;
agent.monitor.connect(scoreboard);

这里反应出来的问题就是最后一句话一定要放在最后写,因为连接的前提是所有的组件已经实例化了。但是相应的, reference_model.connect(scoreboard)要求就没有那么高,只需要在上面代码中reference_model = new之后的任何一个地方写就可以了。

UVM采用的方式:例化放在build_phase来做,而连接关系放在了connection_phase来做,不同时间做不同的事情,这就是UVM中phase的设计哲学,UVM中常用的phase如下:

2.UVM中同一phase的执行顺序

上面说明了不同的phase之间的执行顺序,由于phase是和uvm_component相伴相生的一个概念,对于每一个uvm_component来说,都有上面说得phase。而验证平台中的component又是分层次的。如agent下面有driver和monitor,那么同样是build_phase,先执行agent的build_phase还是先执行driver的build_phase或者是monitor的build_phase?

对于这个问题,如果撇开UVM,那么有多种答案,如遵循自上而下的顺序,先执行agent的,再执行driver和monitor的,也可以遵循自下向上的顺序,先执行driver和monitor的,再执行agent的或者完全采用一种乱序的方式,按照随意的顺序执行。最后一种方式是不受人控制的,在编程的过程中,这种不受控制的代码越少越好,因此可以选择的无非就是自上向下或者自下向上。UVM采用了自上向下的执行顺序,这种钻则其实是唯一的。

假设UVM不使用自上而下的方式执行build_phase,那么会是怎么个情况呢?UVM的设计哲学就是在build_phase中实例化的工作,drive和monitor都是agent的成员变量,所以他们的实例化都要在agent的build_phase中执行。如果在agent的build_phase之前执行driver的build_phase,此时driver还根本没有实例化,所以调用driver.build_phase只会引发错误。

到了这里,有必要澄清一个概念,那就是UVM是在build_phase做实例化工作。这里的实例化指的是uvm_component及其派生类变量的实例化,加入在其他phase实例化一个uvm_component的话,那么系统就会报错的。如果是uvm_object的实例化,那么可以在任何phase完成,当然包括build_phase了。

除了自上而下的执行方式外,UVM的phase还有一种执行方式是自下而上。事实上,除了build_phase之外,所有的不消耗仿真时间的phase(即function phase)都是自下而上执行的。如对于connect_phase,限制性driver和monitor的connect_phase,再执行agent的connect_phase。

本节说得都是不消耗仿真时间的phase,即function phase的执行情况,那么对于run_phase等的执行,他们是如何执行的呢?事实上,他们也是按照自下而上的顺序执行,与前面的function phase自下而上执行不同的是,这种task phase由于是耗费时间的,所以它并不是等到下面的phase执行完了才执行上面的phase的,而是把这些run_phase通过fork.......join_none的形式全部启动起来。所以,自下而上的执行,其更准确的说法是自下而上的启动,同时在运行。

3.UVM中动态运行(run_time)phase

UVM把run_phase又分割成了12个phase,这12个小的phase各自在执行顺序方面与run_phase完全相同,即自下而上的启动,同时运行。这里有两个问题,第一个问题就是为什么要分成小的phase?第二个问题就是这12个小的phase与run_phase之间关系如何?

分成小的phase是为了精细化控制。如这12个小phase的名字所示,reset,configure,main,shutdown四个phase是核心,这四个phase通常也是模拟了DUT的正常工作方式,在reset_phase对DUT进行复位,初始化等操作,在configure_phase则进行DUT配置,DUT的运行主要在main_phase完成,shutdown_phase则是做一些与DUT断电相关的操作。通过细分,对DUT实现更加精确的控制。如,假设要对DUT在运行过程中要进行一次reset操作,在没有细分phase之前,这种才做要在scoreboard,reference model等加入一些额外的代码来保证验证平台不会出错。但是有了这些小的phase之后,分别在scoreboard和reference model及其它部分(如driver,monitor等)的reset_phase写好相关代码,之后想做一次复位操作,那么只要通过phase的jump,就会自动的条状回reset_phase。

第二个问题的:这12个动态运行的phase与run_phase之间是并列的关系,其运行结构大概如下所示:

这段代码只是形象的说明这12个小的phase与run_phase之间的关系,但是有一点要指出的是,这12个小的phase之间并不是这样顺序执行,而是每当一个小的phase执行完后,才会进入下一个小的phase,也就是说有一个同步过程。这段代码中并没有体现出这种同步过程。

objection

1.UVM中的objection

在没有uvm的时候,我们写testbench时,要自己决定什么时候把testbench关掉,通常会调用$finish函数。在UVM中,通过objection机制来控制验证平台的关闭。

4.1obejection控制验证平台的关闭

objection子main的意思就是反对,异议。在验证平台中,可以通过放弃异议(drop_obejection)来通知系统可以关闭验证平台。当然了,在放弃之前,首先要提起异议raise_objection:

在进入到某一phase的时候,UVM会手机此phase提出的所有的objection,并且实时监测所有的objection是否已经drop了,当发现所有的都已经drop后,那么就会关闭此phase,开始进入下一个phase。当所有的phase都执行完毕后,就会调用$finish来把整个验证平台关掉。

4.2参数phase的含义

在UVM中所有的phase的自动执行函数(任务)的参数中,都有一个phase:

task main_phase(uvm_phase phase);

这个输入参数中的phase是为了便于任何component的main_phase中都能raise_objection,而要raise_objection则必须通过phase.raise_objection来完成,所以必须把phase作为参数传递到main_phase等任务中。可以想象,如果没有这个phase参数,那么需要raise一个objection就会比较麻烦。

4.3一般在什么地方raise_objection

在driver中raise_objection的时刻并不多,这是因为driver中通常都是一个无限循环的代码,如下所示:

如果是在while(1)的前面raise_objection,在while循环的end后面drop_objection,那么由于无限循环的特性,phase.raise_objection永远不会被执行到。

一种常见的思维是把raise_objection放在get_next_item之后,这样的话,就可以避免无限循环的问题,确实如此。但是关键问题是如果其他地方没有raise_objection的话,那么如前面所言,UVM不等get_next_item执行完成就已经跳转到了post_main_phase。

在monitor中,scoreboard中,reference model中都有类似的情况,他们都是无限循环的。要解决这个问题,一种方法就是不要让driver无限循环,这个就需要知道在每次运行中需要发多少个item:

另一种方法就是在sequence中把sequencer的objection给raise起来,当sequence完成后,再drop此objection。这种方法相对上一中方法的好处就是不必设置要发送的包的数量。不过,这种方法的限制是,此sequence必须要作为sequencer的某个phase(比如main_phase)的default_sequence,这个通常是比较容易的,一般都使用这种方法。

0 人点赞