棋子 · 1月21日

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

问题引入

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

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

image.png

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 平台了,其他的方法后续再更新。

END

文章来源:处芯积律

推荐阅读

更多 IC 设计干货请关注IC设计专栏。欢迎添加极术小姐姐微信(id:aijishu20)加入技术交流群,请备注研究方向。


推荐阅读
关注数
20704
内容数
1316
主要交流IC以及SoC设计流程相关的技术和知识
目录
极术微信服务号
关注极术微信号
实时接收点赞提醒和评论通知
安谋科技学堂公众号
关注安谋科技学堂
实时获取安谋科技及 Arm 教学资源
安谋科技招聘公众号
关注安谋科技招聘
实时获取安谋科技中国职位信息