uvm_root详解

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_rootm_parentnull
  • 每个组件通过 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_rootbuild_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()

这就是为什么用户只需要在 envbuild_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 环境的建立和运行机制都与它直接相关。

相关推荐
fei_sun3 天前
UVM中的sequence
uvm
Salt & Light4 天前
UVM 字段自动化 Field Automation:让打印、复制、比较自动化
学习·systemverilog·uvm
fei_sun11 天前
UVM中的TLM1.0通信
运维·服务器·uvm
liuluyang53017 天前
UVM学习-2
uvm
liuluyang53019 天前
UVM入门和进阶实验2
uvm
啄缘之间19 天前
5.1 uvm‑component 的层级结构管理? new (name,parent) 参数
开发语言·笔记·学习·ic·uvm·sv
北方孤寂的灵魂1 个月前
关于AXI协议详解
verilog·systemverilog·sv·数字验证
happyDogg_1 个月前
UVM 中 virtual 关键字的使用详解
virtual·uvm·interface·数字验证
啄缘之间3 个月前
8.【学习】工业级详细接口约束&覆盖率
开发语言·笔记·学习·uvm·sv