UVM验证方法学_phase机制

phase机制是uvm最重要的几个机制之一,它使得uvm的运行仿真层次化,使得各种例化先后次序正确,保证了验证环境与DUT的正确交互。


一、phase机制概述

uvm中的phase按照是否消耗仿真时间分为function phase和task phase两类,不消耗仿真时间的为function phase,而消耗仿真时间的为task phase。

uvm中的phase:

phase机制的意义是使得UVM的运行层次化,使得各种例化先后次序正确。UVM的phase主要有9个,外加12个小phase,这12个小的phase称为run-time phase。其中除了run phase和12个小的phase是task之外,其余的都是function。比较常用的phase有build_phase、connect_phase、reset_phase、main_phase、run_phase、report_phase、final_phase等。

为什么要引入这12个小的phase?分成小的phase是为了实现更加精细化的控制。reset、configure、main、shutdown四个phase是核心,这四个phase通常模拟DUT的正常工作方式:

(1)在reset_phase对DUT进行复位、初始化等操作。

(2)在configure_phase则进行DUT的配置。

(3)在main_phase主要是DUT的运行。

(4)在shutdown_phase主要是一些与DUT断电相关的操作。

通过这种细分实现对DUT更加精确的控制,同时也可以让我们实现在phase间的跳转,更便于去构建一些场景。

二、phase执行顺序

phase的执行顺序可以分为时间和空间。

(1)时间顺序

先说时间,在时间层面所有的phase会按照顺序自上向下依次执行。其中12个小的phase与run_phase是并行的关系。

run_phase和main_phase之间的关系:
objection机制是UVM中唯一可以控制仿真开始和结束的方式。在task phase中,至少有一个task phase要在消耗第一条消耗仿真时间的语句执行之前挂起objection。
(1)如果12个分支中有一个phase(比如main_phase)挂起了objection ,那么run_phase 中则不需要挂起objection 就可以执行其中的代码;但是这时,run_phase的运行时间被动地受这个挂起objection的分支phase的控制。
(2)而如果在run_phase中挂起了objection,没有在main_phase中挂起,main_phase中的操作则不会执行,此时的运行时间完全由run_phase控制。

请注意不要混淆,这里的时间顺序并不是指消耗仿真时间,只有task phase才会消耗仿真时间!所有的function phase都会在0时刻完成。

对于task phase,uvm内置了phase的同步。只有同一个phase全部执行完毕,才会执行下一个phase。但是从整个环境的角度来看,各个task phase之间是没有空白的。

(2)空间顺序

再说空间,uvm中规定层次越高,优先级越高,层次即为在uvm树中的位置,uvm_top是树根,越靠近树根,则层次越高。

我们可以再思考一下,层次越高,就会越接近用户。我们会在uvm_test_top(也就是testcase)中启动不同的sequence,来实现不同的测试场景,而env则是在uvm_test_top中才会完成例化,向下依此类推。

值得注意的是,uvm的设计哲学就是在build_phase中完成例化,在connect_phase中完成连接,这种分块式设计。所以build_phase比较特殊,由于树形结构实例化必须从树根开始,也就是自顶向下运行。但是例如connect_phase则是自底向上运行,因为组件的连接必须从最基础的部件开始。所以对于空间来说:

只有build phase和final phase是自顶向下运行,其余phase都是自底向上运行。

可以使用print_topology来打印树形结构,可以清晰看到各个组件之间的关联。例如:

UVM_INFO @ 33626.00ns: reporter [UVMTOP] UVM testbench topology:
------------------------------------------------------------------
Name                       Type                        Size  Value
------------------------------------------------------------------
uvm_test_top               tc_sanity                   -     @471 
  fifo_env                 env                         -     @479 
    rd_agt                 rd_agent                    -     @495 
      drv                  rd_driver                   -     @621 
        rsp_port           uvm_analysis_port           -     @638 
        seq_item_port      uvm_seq_item_pull_port      -     @629 
      mon                  rd_monitor                  -     @770 
        ap                 uvm_analysis_port           -     @780 
      sqr                  rd_sequencer                -     @647 
        rsp_export         uvm_analysis_export         -     @655 
        seq_item_export    uvm_seq_item_pull_imp       -     @761 
        arbitration_queue  array                       0     -    
        lock_queue         array                       0     -    
        num_last_reqs      integral                    32    'd1  
        num_last_rsps      integral                    32    'd1  
    rdmon_scb_fifo         uvm_tlm_analysis_fifo #(T)  -     @564 
      analysis_export      uvm_analysis_imp            -     @608 
      get_ap               uvm_analysis_port           -     @599 
      get_peek_export      uvm_get_peek_imp            -     @581 
      put_ap               uvm_analysis_port           -     @590 
      put_export           uvm_put_imp                 -     @572 
    scb                    scoreboard                  -     @503 
      rd_port              uvm_blocking_get_port       -     @803 
      wr_port              uvm_blocking_get_port       -     @794 
    wr_agt                 wr_agent                    -     @487 
      drv                  wr_driver                   -     @939 
        rsp_port           uvm_analysis_port           -     @956 
        seq_item_port      uvm_seq_item_pull_port      -     @947 
      mon                  wr_monitor                  -     @965 
        ap                 uvm_analysis_port           -     @975 
      sqr                  wr_sequencer                -     @816 
        rsp_export         uvm_analysis_export         -     @824 
        seq_item_export    uvm_seq_item_pull_imp       -     @930 
        arbitration_queue  array                       0     -    
        lock_queue         array                       0     -    
        num_last_reqs      integral                    32    'd1  
        num_last_rsps      integral                    32    'd1  
    wrmon_scb_fifo         uvm_tlm_analysis_fifo #(T)  -     @511 
      analysis_export      uvm_analysis_imp            -     @555 
      get_ap               uvm_analysis_port           -     @546 
      get_peek_export      uvm_get_peek_imp            -     @528 
      put_ap               uvm_analysis_port           -     @537 
      put_export           uvm_put_imp                 -     @519 
------------------------------------------------------------------

我们可以用build_phase和connect_phase来举例,比如:

UVM_INFO @ 0: reporter [RNTST] Running test tc_sanity...
UVM_INFO ../tc/tc_sanity.sv(30) @ 0.00ns: uvm_test_top [uvm_test_top] build_phase active.
UVM_INFO ../ver/env.sv(33) @ 0.00ns: uvm_test_top.fifo_env [fifo_env] build_phase active.
UVM_INFO ../ver/scoreboard.sv(36) @ 0.00ns: uvm_test_top.fifo_env.scb [scb] build_phase active.
UVM_INFO ../ver/wr_agent/wr_agent.sv(32) @ 0.00ns: uvm_test_top.fifo_env.wr_agt [wr_agt] build_phase active.
UVM_INFO ../ver/wr_agent/wr_driver.sv(31) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [drv] build_phase active.
UVM_INFO ../ver/wr_agent/wr_monitor.sv(29) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.mon [mon] build_phase active.
UVM_INFO ../ver/wr_agent/wr_sequencer.sv(28) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr [sqr] build_phase active.

UVM_INFO ../ver/scoreboard.sv(43) @ 0.00ns: uvm_test_top.fifo_env.scb [scb] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_driver.sv(39) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.drv [drv] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_monitor.sv(38) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.mon [mon] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_sequencer.sv(33) @ 0.00ns: uvm_test_top.fifo_env.wr_agt.sqr [sqr] connect_phase active.
UVM_INFO ../ver/wr_agent/wr_agent.sv(42) @ 0.00ns: uvm_test_top.fifo_env.wr_agt [wr_agt] connect_phase active.
UVM_INFO ../ver/env.sv(46) @ 0.00ns: uvm_test_top.fifo_env [fifo_env] connect_phase active.
UVM_INFO ../tc/tc_sanity.sv(36) @ 0.00ns: uvm_test_top [uvm_test_top] connect_phase active.

可以清晰的看到build_phase的运行是自顶向下,而connect_phase的运行是自底向上。
 

三、phase机制中uvm树的遍历

其实在上面的代码中能够看到,build_phase中scoreboard执行是要先于wr_agent的,这是因为uvm中字典序所导致的。scoreboard的s在字典序中要先于w,如果将scoreboard的例化名称改为z_scoreboard,则会晚于wr_agent执行。实际使用中这种顺序理论上不应该产生影响,但是假如要求一定是某种固定的执行顺序,那么这种代码存在很高风险,应立即进行修改。

从树形结构上来说,scoreboard级别是高于agent中的组件的,但是他们build_phase的执行顺序其实并不确定。UVM中采用的是深度优先的原则,即会先执行完某一条树枝,才会去执行下一条树枝。例如agent和scoreboard,他们的层次相同,在执行时会先将agent中包含的组件全部执行完成,才去执行scoreboard,这就是深度优先原则。我们可以总结为:

横向按照字典序,纵向按照深度原则。

四、phase的super

通过super对父类的内容进行继承,其中build_phase的super语句最重要且必须存在,其他phase的super则可以省略。查看uvm源码,可以看到除了build_phase之外其他的phase几乎没有做任何相关的事情:

// phase methods
//--------------
// these are prototypes for the methods to be implemented in user components
// build_phase() has a default implementation, the others have an empty default

function void uvm_component::build_phase(uvm_phase phase);
  m_build_done = 1;
  build();
endfunction

// Backward compatibility build function

function void uvm_component::build();
  m_build_done = 1;
  apply_config_settings(print_config_matches);
  if(m_phasing_active == 0) begin
    uvm_report_warning("UVM_DEPRECATED", "build()/build_phase() has been called explicitly, outside of the phasing system. This usage of build is deprecated and may lead to unexpected behavior.");
  end
endfunction

// these phase methods are common to all components in UVM. For backward
// compatibility, they call the old style name (without the _phse)

function void uvm_component::connect_phase(uvm_phase phase);
  connect();
  return; 
endfunction
function void uvm_component::start_of_simulation_phase(uvm_phase phase);
  start_of_simulation();
  return; 
endfunction
function void uvm_component::end_of_elaboration_phase(uvm_phase phase);
  end_of_elaboration();
  return; 
endfunction
task          uvm_component::run_phase(uvm_phase phase);
  run();
  return; 
endtask
function void uvm_component::extract_phase(uvm_phase phase);
  extract();
  return; 
endfunction
function void uvm_component::check_phase(uvm_phase phase);
  check();
  return; 
endfunction
function void uvm_component::report_phase(uvm_phase phase);
  report();
  return; 
endfunction


// These are the old style phase names. In order for runtime phase names
// to not conflict with user names, the _phase postfix was added.

function void uvm_component::connect();             return; endfunction
function void uvm_component::start_of_simulation(); return; endfunction
function void uvm_component::end_of_elaboration();  return; endfunction
task          uvm_component::run();                 return; endtask
function void uvm_component::extract();             return; endfunction
function void uvm_component::check();               return; endfunction
function void uvm_component::report();              return; endfunction
function void uvm_component::final_phase(uvm_phase phase);         return; endfunction

// these runtime phase methods are only called if a set_domain() is done

task uvm_component::pre_reset_phase(uvm_phase phase);      return; endtask
task uvm_component::reset_phase(uvm_phase phase);          return; endtask
task uvm_component::post_reset_phase(uvm_phase phase);     return; endtask
task uvm_component::pre_configure_phase(uvm_phase phase);  return; endtask
task uvm_component::configure_phase(uvm_phase phase);      return; endtask
task uvm_component::post_configure_phase(uvm_phase phase); return; endtask
task uvm_component::pre_main_phase(uvm_phase phase);       return; endtask
task uvm_component::main_phase(uvm_phase phase);           return; endtask
task uvm_component::post_main_phase(uvm_phase phase);      return; endtask
task uvm_component::pre_shutdown_phase(uvm_phase phase);   return; endtask
task uvm_component::shutdown_phase(uvm_phase phase);       return; endtask
task uvm_component::post_shutdown_phase(uvm_phase phase);  return; endtask

不过为了代码风格的统一,我还是会给每个phase都加上。

五、phase的跳转

这里先说一下跳转,后面在专门讨论复位的时候会再次用到它,因为跳转对于复位实现来说是必要的。跳转中最难的地方在于清理和准备工作,组件之间的fifo需要全部清空,组件内部的队列也需要全部清空,如果清空做不好可能会引发很多未知问题。

跳转使用jump函数,比如:

            begin
                @(negedge this.wr_drv_if.wrst_n);
                phase.jump(uvm_reset_phase::get());
                `uvm_info(this.name,"2nd reset activated.",UVM_LOW)
            end

这里就是复位信号到来跳转至reset_phase。

当然能够做跳转的phase也有限制,在uvm_pre_reset_phase::get() 后的所有phase都可以:

uvm_build_phase::get();
uvm_connect_phase::get();
uvm_end_of_elaboration_phase::get();
uvm_start_of_simulation_phase::get();
uvm_run_phase::get();
uvm_pre_reset_phase::get();

// ----------------------------------------------------------
uvm_reset_phase::get();
uvm_post_reset_phase::get();
uvm_pre_configure_phase::get();
uvm_configure_phase::get();
uvm_post_configure_phase::get();
uvm_pre_main_phase::get();
uvm_main_phase::get();
uvm_post_main_phase::get();
uvm_pre_shutdown_phase::get();
uvm_shutdown_phase::get();
uvm_post_shutdown_phase::get();
uvm_extract_phase::get();
uvm_check_phase::get();
uvm_report_phase::get();
uvm_final_phase::get();

六、phase的调试和超时退出

除了使用uvm_info打印信息来帮助检查问题之外,uvm还提供命令行参数UVM_PHASE_TRACE来对phase机制进行调试。需要在仿真的命令后面加入:+UVM_PHASE_TRACE,或者加在makefile当中。

UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1381) @ 33626.00ns: reporter [PH/TRC/DONE] Phase 'common.report' (id=271) Completed phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1403) @ 33626.00ns: reporter [PH/TRC/SCHEDULED] Phase 'common.final' (id=283) Scheduled from phase common.report
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1124) @ 33626.00ns: reporter [PH/TRC/STRT] Phase 'common.final' (id=283) Starting phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1381) @ 33626.00ns: reporter [PH/TRC/DONE] Phase 'common.final' (id=283) Completed phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1403) @ 33626.00ns: reporter [PH/TRC/SCHEDULED] Phase 'common.common_end' (id=180) Scheduled from phase common.final
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1124) @ 33626.00ns: reporter [PH/TRC/STRT] Phase 'common.common_end' (id=180) Starting phase
UVM_INFO /opt/Synopsys/VCS2014/etc/uvm-1.1/base/uvm_phase.svh(1381) @ 33626.00ns: reporter [PH/TRC/DONE] Phase 'common.common_end' (id=180) Completed phase

挂死是有时候会遇到的问题,一般是陷入了死循环无法终止。出现挂死的时候设置的drain_time就不会起作用,导致仿真无法结束。在uvm中通过uvm_root的set_timeout函数可以设置超时时间来强制结束(在top中使用$finish或者$stop是同样的效果)。

function void base_test::build_phase(uvm_phase phase);
    super.build_phase(phase);
    env = my_env::type_id::create("env", this);
    uvm_top.set_timeout(500ns, 0);
endfunction

set_timeout函数有两个参数,第一个参数是要设置的时间,第二个参数表示此设置是否可以被其后的其他set_timeout语句覆盖。如果达到规定时间后测试用例还没有运行完毕,则会给出一条uvm_fatal的提示信息,并退出仿真。


总结

phase机制是uvm最重要的几个机制之一,它使得uvm的运行仿真层次化,使得各种例化先后次序正确,保证了验证环境与DUT的正确交互。

验证平台是很复杂的,要搭建出一个验证平台是一件相当繁杂的事情,要正确地掌握并理顺这些步骤是一个相当艰难的过程。在不同时间做不同的事情,这就是uvm中phase的设计哲学。但是仅仅划分成phase是不够的,phase的自动执行功能极大地方便了用户。同时,phase机制的引入在很大程度上解决了因代码顺序杂乱可能会引发的问题,也在很大程度上减少了验证平台开发者的工作量。

UVM(Universal Verification Methodology)是一种基于SystemVerilog的验证方法学,它提供了一种灵活的机制开发可重用的验证环境。UVM中定义了一系列的phase,用于控制验证环境中的各个组件的执行顺序和时序。 UVM中的phase机制主要由以下几个部分组成: 1. UVM Manager:负责管理phase的全局状态和控制phase的执行顺序。 2. UVM Phasing Mechanism:包括各个组件的phase方法和phase queue,用于在不同的phase中执行相应的任务。 3. UVM Phasing Callbacks:用于在phase开始和结束时执行相应的回调方法。 4. UVM Factory:用于创建和配置UVM组件。它提供了一种机制来动态创建和配置组件,使得验证环境更加灵活和可重用。 在UVM中,整个验证环境被分为多个阶段,每个阶段执行不同的任务。这些阶段包括: 1. Build Phase:在这个阶段中,各个组件被创建和配置。 2. Connect Phase:在这个阶段中,各个组件被连接起来,形成完整的验证环境。 3. Run Phase:在这个阶段中,进行实际的测试,包括生成测试向量、模拟等。 4. Shutdown Phase:在这个阶段中,关闭测试环境,释放资源。 在每个阶段中,UVM Manager都会调用相应的phase方法来执行各个组件的任务。各个组件可以通过实现相应的任务方法来完成各自的任务。同时,UVM还提供了一些回调方法,用于在phase开始和结束时执行一些额外的操作,例如打印日志、统计分析等。 通过使用UVMphase机制,可以使验证环境更加灵活、可重用和可维护。同时,由于UVM是基于SystemVerilog的,所以也可以很好地与设计进行集成,提高验证的效率和准确性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Clock_926

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值