UVM验证方法学 您所在的位置:网站首页 大学分为几个层次 UVM验证方法学

UVM验证方法学

#UVM验证方法学| 来源: 网络整理| 查看: 265

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机制的引入在很大程度上解决了因代码顺序杂乱可能会引发的问题,也在很大程度上减少了验证平台开发者的工作量。



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有