uvm启动过程及phase机制实现原理介绍

我们通常会在top写下类似下面的代码

module top();
    import uvm_pkg::*;
 
    ......
    initial begin
         run_test();
    end
    ......
endmoudle

我们写的这个run_test()就是整个UVM验证平台最顶层的入口。这里的run_test()不是任何一个类的成员,而是一个global task,位于uvm_globals.svh中。如下:

Caption

在这个global的run_test task中,通过cs.get_root创建了uvm_root单例,然后调用了uvm_root的的run_test task。在uvm_root的run_test task中,根据plus args UVM_TESTNAME创建了uvm_test_top对象,如下:

Caption

然后,还是在uvm_root的run_test task中,调用了uvm_phase的一个static task m_run_phases, 开始了uvm phases的启动,如下:

Caption

uvm_phase的静态成员m_run_phases的实现如下:

Caption

上面的m_phase_hopper是一个uvm_phase类型的mailbox,在m_run_phases中,先是将common domain的第一个phase(即build_phase) put进mailbox中,然后进入forever,在forever中不断地去get phase,get成功就去执行phase的execute_phase task。

在uvm_phase的execute_phase中,会遍历uvm components tree上的所有component. 这里是通过调用uvm_phase的traverse()函数实现的。如下,在execute_phase中调用traverse:

Caption

遍历完成之后,当然要进入下一个phase,于是在退出execute_phase之前,将下一个phase给put进mailbox中。如下:

Caption

这里还涉及到一些phase跳转的处理,暂时不作具体的研究讨论。

uvm_phase分为function phase和task phase, 而function phase又可以分为uvm_topdown_phase和uvm_bottomup_phase。uvm_bottomup_phase和uvm_task_phase都是从下往上遍历,而uvm_topdown_phase是从上往下遍历。function phase中只有build_phase和final_phase是topdown phase,其它的都是bottomup_phase。uvm_task_phase,uvm_bottomup_phase和uvm_topdown_phase都是继承于uvm_phase的子类,而traverse又是uvm_phase的虚函数,所以这3个子类理所当然地实现了自己的traverse()。

这里我们就挑uvm_topdown_phase的traverse实现出来看看吧,如下:

Caption
Caption

这里通过函数迭代的方式实现了遍历,不断地去get_child并用child去迭代。这个地方调用了execute函数,execute函数的实现如下:

Caption

这里的execute函数又调用了exec_func(),exec_func也是虚函数,各个子类有不同的实现,比如uvm_build_phase的实现:

Caption

终于,uvm_build_phase实现的地方调用了component的build_phase函数。

总结一下整个过程的调用栈:run_test -> uvm_root::run_test -> uvm_phase::m_run_phases -> uvm_phase::execute_phase -> uvm_topdown_phase::traverse -> uvm_topdown_phase::execute -> uvm_build_phase::exec_func -> uvm_component::build_phase

 

### UVM 中序列(Sequence)的启动方式 在 UVM 框架中,序列(`uvm_sequence`)是一种用于驱动事务项(transaction items)进入代理(agent)的核心组件。以下是关于如何在 UVM启动序列的具体方法及其工作原理: #### 1. 使用 `start()` 方法手动启动 Sequence 这是最常见的启动方式之一。通过显式调用 `seq.start(sequencer)` 来启动一个序列实例。这种方式允许用户完全控制何时以及在哪种条件下运行序列。 以下是一个典型的例子: ```verilog task my_env::main_phase(uvm_phase phase); my_sequence seq; // 定义自定义序列对象 phase.raise_objection(this); // 提升异议以保持当前相位活跃状态 seq = my_sequence::type_id::create("seq"); // 工厂创建序列实例 seq.start(env.i_agt.sqr); // 启动序列并与指定的 sequencer 关联 phase.drop_objection(this); // 移除异议以便继续后续流程 endtask : main_phase ``` 这种方法提供了极大的灵活性,因为开发者可以直接干预序列的行为参数设置、随机约束加载等过程[^2]。 #### 2. 利用 Default Sequence 自动启动 另一种更简洁的方式是利用默认序列功能 (`default_sequence`) 。当设置了 default sequence 后,在相应的测试平台生命周期阶段(通常是 main_phase),框架会自动尝试找到并激活这个预设好的序列而无需额外编码去单独触发它。 ##### 设置 Default Sequence 的两种途径: - **Type-Level Configuration** 这是最推荐的做法,因为它依赖于类型ID而不是具体实例化出来的object本身。 ```verilog function void my_test::build_phase(uvm_phase phase); super.build_phase(phase); uvm_config_db#(uvm_object_wrapper)::set( this, "env.i_agt.sqr.main_phase", "default_sequence", my_default_sequence::type_id::get() ); endfunction : build_phase ``` - **Instance-Based Assignment** 虽然也能达到目的,但由于硬编码了一个实际的对象指针进去所以不够通用灵活。 ```verilog function void my_test::build_phase(uvm_phase phase); my_default_sequence dflt_seq; super.build_phase(phase); dflt_seq = my_default_sequence::type_id::create("dflt_seq"); uvm_config_db#(uvm_sequence_base)::set( this, "env.i_agt.sqr.main_phase", "default_sequence", dflt_seq ); endfunction : build_phase ``` 无论哪种形式,默认序列最终都会由环境内部的标准逻辑负责执行其`.start()`命令[^1]. #### 3. 借助宏指令简化常用模式 为了进一步降低复杂度,UVM还提供了一些方便快捷的宏定义来帮助快速编写标准场景下的sequence启动代码[UVM_DO].例如下面这段简单的do_transaction语句实际上就相当于完整地实现了前面提到的手动启动sequence的过程. ```verilog // Equivalent to creating and starting a single transaction item as part of an implicit inline sequence uvm_do(req, .parent_sequence(null), .priority(PRIORITY_NONE)); ``` 这里需要注意的是虽然看起来简单明了但实际上背后隐藏了很多细节处理比如objections管理等等因此建议初学者还是应该理解清楚基本概念后再考虑使用此类高级特性[^3]. --- ### 总结 综上所述,UVM支持多种不同的sequence启动机制分别适用于不同场合需求:从最基础也是最为直观可控的手工调用start()接口直至高度抽象封装后的macro表达形式不一而足.开发人员可以根据项目实际情况权衡选用最适合自己的方案. ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值