UVM uvm_root 详解
一、什么是 uvm_root
uvm_root 是 UVM (Universal Verification Methodology) 中的顶级类 ,它是所有 UVM 组件的隐式父类。在整个 UVM 验证环境中,有且仅有一个 uvm_root 实例。
关键要点
uvm_root继承自uvm_component,因此它本身就是一个 UVM 组件- 它是 UVM 树形结构(component hierarchy)的根节点
- 它由 UVM 内部自动创建,无需用户手动实例化
- 通过
uvm_root::get()全局静态方法获取其单例引用
二、如何获取 uvm_root 实例
获取方式非常简单:
systemverilog
uvm_root root;
root = uvm_root::get();
get() 是一个静态方法(singleton 模式),无论在代码的哪个位置调用,返回的都是同一个 uvm_root 实例。
在环境中的典型用法
systemverilog
class test_base extends uvm_test;
function void build_phase(uvm_phase phase);
super.build_phase(phase);
// 获取 top-level 的根
uvm_root root = uvm_root::get();
// 通过根节点可以遍历或查找整个组件树
endfunction
endclass
三、uvm_root 扮演的核心角色
| 角色 | 说明 |
|---|---|
| 组件树的根 | 所有通过 create() 或 type_id::create() 创建的组件,其父链最终都指向 uvm_root |
| 全局拓扑管理器 | 维护完整的组件层次结构,提供全局查找、遍历功能 |
| Phase 控制器 | 负责 UVM Phase 的执行调度,控制 run_phase 等所有 phase 的启动与结束 |
| 报告服务器 | 提供全局的报告处理机制,控制日志的严重级别、action 等 |
| 全局资源入口 | 通过 uvm_root 可以访问 UVM 的全局资源配置(resource database) |
隐式 top 组件 |
未指定父组件时,父组件默认为 uvm_root |
四、UVM 树形结构是如何建立的
创建阶段的层级
当用户创建组件实例时:
systemverilog
// parent 为 uvm_root 或者某个已经挂载到 uvm_root 下的组件
my_driver drv = my_driver::type_id::create("drv", this);
- 每个
uvm_component都有一个m_parent指针 uvm_root的m_parent为null- 每个组件通过
m_children(关联数组) 维护其子组件列表 - 从
uvm_root向下遍历,就得到了完整的组件树
树形结构示意图
uvm_root (隐式创建,不可见)
├── uvm_test_top (用户定义的 test,顶层的可见组件)
│ ├── env
│ │ ├── agent
│ │ │ ├── driver
│ │ │ ├── monitor
│ │ │ └── sequencer
│ │ └── scoreboard
│ └── ...
└── (其他所有未指定 parent 的组件)
自动命名为 uvm_test_top
用户 test 类在 run_test() 中被实例化时,UVM 会自动将其命名为 uvm_test_top,作为 uvm_root 的直接子节点。
五、与结构相关的关键函数
以下函数均定义在 uvm_component 中(uvm_root 继承自它),用于操作和查询组件树的层次结构:
5.1 获取当前组件信息
| 函数 | 返回值 | 说明 |
|---|---|---|
get_name() |
string |
返回当前组件的名称 |
get_full_name() |
string |
返回从 uvm_root 开始的完整路径名称,如 uvm_test_top.env.agent.driver |
get_parent() |
uvm_component |
返回当前组件的父组件(uvm_root 返回 null) |
get_depth() |
int |
返回当前组件在树中的深度(uvm_root 深度为 0) |
5.2 遍历子组件
| 函数 | 返回值 | 说明 |
|---|---|---|
get_num_children() |
int |
返回直接子组件的数量 |
get_child(string name) |
uvm_component |
通过名称获取一个直接子组件 |
get_children(ref uvm_component children[$]) |
void |
将所有直接子组件放入队列 |
get_first_child() |
string |
返回第一个子组件的名称(用于迭代) |
get_next_child(ref string name) |
int |
返回下一个子组件(与上面配合实现迭代遍历) |
has_child(string name) |
bit |
检查是否存在名为 name 的直接子组件 |
5.3 全局查找组件
| 函数 | 返回值 | 说明 |
|---|---|---|
find(string name) |
uvm_component |
在全局范围内搜索任意组件 |
find_all(string name, ref uvm_component comps[$]) |
int |
查找全局范围内所有匹配的组件(支持通配符 *) |
这些函数通常在 uvm_root 句柄上调用,实现从根开始的全局搜索:
systemverilog
uvm_root root = uvm_root::get();
uvm_component comp;
// 通过完整路径查找
comp = root.find("uvm_test_top.env.agent.driver");
// 使用通配符查找所有 monitor
uvm_component monitors[$];
root.find_all("*monitor*", monitors);
5.4 类型化查找
| 函数 | 说明 |
|---|---|
find_all(uvm_component comps[$], T obj) |
SystemVerilog 参数化版本,查找所有指定类型的组件 |
get_objectors() |
返回所有注册此类型的组件队列 |
5.5 创建与销毁
| 函数 | 说明 |
|---|---|
create(string name, uvm_component parent, ...) |
创建一个子组件并自动挂载到组件树中 |
type_id::create(string name, uvm_component parent) |
推荐的 factory 创建方式,自动挂载 |
build_phase(uvm_phase phase) |
UVM phase 回调,在 build_phase 中创建子组件 |
5.6 树形结构的核心机制:build_phase 递归
uvm_root 在 build_phase 中会递归调用 所有子组件的 build_phase:
uvm_root.build_phase()
└─ uvm_test_top.build_phase()
└─ env.build_phase()
├─ agent.build_phase()
│ ├─ driver.build_phase()
│ ├─ monitor.build_phase()
│ └─ sequencer.build_phase()
└─ scoreboard.build_phase()
这就是为什么用户只需要在 env 的 build_phase 中创建组件,它们就会被自动整合到树中。
六、uvm_root 的 Phase 控制
uvm_root 负责整个仿真的 phase 调度,关键函数:
| 函数 | 说明 |
|---|---|
run_test() |
全局入口,创建 test、启动 phase 调度 |
stop_phase(string phase_name) |
停止指定的 phase |
phase_done() |
组件通知 phase 结束(用于 objection 机制) |
phase_ready_to_end() |
Phase 结束前的回调,由 objection 机制使用 |
run_test() 的执行流程
1. run_test("my_test")
2. └─ 创建 uvm_root 实例(如果不存在)
3. └─ 设置报告服务器
4. └─ 创建 my_test 实例,命名为 uvm_test_top
5. └─ 依次执行所有 phase:
build_phase → connect_phase → end_of_elaboration_phase
→ start_of_simulation_phase → run_phase (及12个run-time sub-phases)
→ extract_phase → check_phase → report_phase → final_phase
七、常见使用场景与示例
场景 1:在任意位置获取组件树根
systemverilog
uvm_root root = uvm_root::get();
`uvm_info("ROOT", $sformatf("Top level test: %s", root.get_full_name()), UVM_LOW)
场景 2:遍历整个组件树(调试用)
systemverilog
function void print_hierarchy(uvm_component comp = null, int depth = 0);
uvm_root root = uvm_root::get();
if (comp == null) comp = root;
for (int i = 0; i < depth; i++) $write(" ");
$display("- %s", comp.get_name());
uvm_component children[$];
comp.get_children(children);
foreach(children[i])
print_hierarchy(children[i], depth + 1);
endfunction
场景 3:全局查找特定组件
systemverilog
uvm_root root = uvm_root::get();
uvm_component comps[$];
root.find_all("*scoreboard*", comps);
场景 4:通过 uvm_top 句柄(已被标注为 deprecated)
早期 UVM 版本使用全局变量 uvm_top 作为 uvm_root 的句柄,当前推荐使用 uvm_root::get():
systemverilog
// 旧方式 (deprecated)
// uvm_component comp = uvm_top.find("...");
// 推荐方式
uvm_component comp = uvm_root::get().find("...");
八、总结
| 概念 | 要点 |
|---|---|
| 单例模式 | 整个 UVM 环境有且仅有一个 uvm_root 实例 |
| 自动创建 | 在第一次调用 run_test() 或 uvm_root::get() 时由 UVM 内核自动创建 |
| 树根 | 所有 UVM 组件的最终父级 |
| 全局访问 | 通过 uvm_root::get() 在任何位置获取 |
| Phase 调度 | 负责启动、控制、停止所有 UVM Phase |
| 全局查找 | find() / find_all() 提供基于名称的组件搜索 |
uvm_test_top |
用户 test 的默认顶层实例名称 |
理解 uvm_root 是掌握 UVM 组件层级管理和仿真控制流程的第一步,几乎所有 UVM 环境的建立和运行机制都与它直接相关。