自定义phase实现方法之: UVM经典推荐

文摘   2025-01-20 22:15   北京  

问题引入

UVM中,phase机制是一个基本而又非常核心的特性之一,uvm phase将验证环境的运行划分为不同的阶段,如build, configue, reset, main等。每个phase阶段可对应着环境或者DUT的初始化或者处理过程。

phase的执行机制遵循UVM的"树"结构,从top-down角度看,有自上而下和自下而上的phase区别。也有function phase 和 task phase之分,区别在于是否消耗仿真时间。uvm中定义的phase如下所示:

UVM已有的phase机制已经可以解决大家绝大部分的场景需求。

近期项目验证架构调整,遇到这样的需求。简化来说,SoC验证环境中会集成数十个子系统的验证UVC(有uvm_test, uvm_env,agent), 其中env A 和env B的初始化build有约束,需要保证env B的build phase内容在env A之前完成。

解决方案:

根据这个需求,其实有这样几个解决办法。

  1. 将env A和env B build_phase中有约束的部分上移,将需要协调同步的内容放到uvm_test中的build_phase中实现。这样就需要Block level和SoC level在集成时进行区别处理。

  2. 将uvm_env的实例名按字典排序。在uvm_phase或者树的遍历中,按照字典序进行,因此可以将env B和env A的实例名按字典序命名。

  3. 如果是类似随机的过程的代码,可以尝试将env B的该部分代码放到new函数中。new函数会在build_phase前执行。

  4. 给env B建立一个自定义phase, 该phase在build_phase之前执行,完成同步。

因此就对自定义phase的实现进行了小小的尝试和solution的package设计,有几种方路线可选:

  1. UVM推荐的经典实现
  2. 基于UVM预先埋入的回调函数实现
  3. 基于interface class的插件式方法
  4. 基于AOP(Aspect Oriented Programming)实现

先介绍第一种的经典做法。

自定义phase实现之: UVM经典推荐

自定义phase的实现,也能找到一些开源的代码,主要步骤:

  1. 根据所需,选择function phase还是task phase。并实现对应的exec_function或者exec_task。

  2. 获取uvm_domain句柄。function phase对应uvm_domain::get_common_domain()。task phase使用uvm_domain::get_uvm_domain()。

  3. 获取domain中需要插入phase的位置

  4. 调用uvm_domain的add函数,将自定义的phase插入到指定位置。

  5. 扩展包含新的phase的uvm组件

下面以建立一个pre_build_phase为例,相关代码如下。

user_pre_build_test

先新建一个包含pre_build_phase的base component, 根据需求继承uvm_test或者uvm_env。然后用户的component均此component扩展。

class user_pre_build_test extends uvm_test;
    `uvm_component_utils(pre_build_test)
    
    functionnew (string name="pre_build_test",uvm_component parent=null);
        super.new(name,parent);
    endfunction

    virtualfunctionvoid pre_build_phase(uvm_phase phase);
    endfunction

endclass

class user_test extends user_pre_build_test;
    `uvm_component_utils(user_test)

    functionnew (string name="pre_build_test",uvm_component parent=null);
        super.new(name,parent);
    endfunction

    virtualfunctionvoid build_phase(uvm_phase phase);
        super.build_phase(phase);
        `uvm_info(get_type_name, "Here is build_phase", UVM_NONE)
    endfunction

    virtualfunctionvoid pre_build_phase(uvm_phase phase);
        `uvm_info(get_type_name, "Here is pre_build_phase", UVM_NONE)
    endfunction
endclass

user_pre_build_phase

实现pre_build_phase的class, 可以参考uvm_build_phase的实现。如果是task类选的phase,需要继承uvm_task_phase, 实现exec_task, 可以参考uvm_main_phase的实现。

class user_pre_build_phase extends uvm_topdown_phase;
    localstatic user_pre_build_phase m_inst;

    staticconststring type_name = "user_pre_build_phase";

    protectedfunctionnew(string name="user_pre_build_phase");
    endfunction

    staticfunction user_pre_build_phase get();
        if(m_inst == null) m_inst = new();
        return m_inst;
    endfunction

    virtualfunctionstring get_type_name();
        return type_name;
    endfunction

    virtualfunctionvoid exec_func(uvm_component comp, uvm_phase phase);
        user_pre_build_test t;
        if($cast(t,comp) ) begin
            t.pre_build_phase(phase);
        end
    endfunction
endclass

uvm_domain.add(...)

最后在TB的initial里将user_pre_build_phase插入到build_phase之前即可。

module tb;
    import uvm_pkg::*;
    initialbegin
        uvm_domain sim_common_domain;
        uvm_phase  target_phase;
        sim_common_domain = uvm_domain::get_common_domain();
        target_phase = sim_common_domain.find(uvm_build_phase::get() );
        sim_common_domain.add(
            .phase(user_pre_build_phase::get() ),
            .with_phase(null ),
            .after_phase(null ),
            .before_phase(target_phase )
        );
    end

    initialbegin
        run_test();
    end
endmodule

根据上面的代码可以逐步实现所需要的phase实现,可以看到期望的输出,也是比较基础和经典的代码。后几种方法可以进一步提升自定义phase的易用性和集成性。因为最近找不到可用的VCS平台了,其他的方法后续再更新。




处芯积律
处芯积律,而后知所至。一个芯片人的技术和行业研究分享。
 最新文章