news 2026/8/26 15:17:39

UVM 句柄与对象:为什么 reg_model 在 env 但 vsequencer 有句柄?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
UVM 句柄与对象:为什么 reg_model 在 env 但 vsequencer 有句柄?

对象在哪里创建,句柄在哪里可见?

在 UVM 验证环境中,我们经常看到这样的现象:reg_model对象在envbuild_phase中创建,但在test层可以直接通过env.reg_model访问它;而vsequencer中也持有各个 real sequencer 的句柄,但它自身并没有创建那些 sequencer。这一切都源于 SystemVerilog 的句柄(handle)与对象(object)分离机制

很多初学者会混淆:为什么在 env 里 new 出来的东西,test 里也能用?为什么 vsequencer 可以调度别的 sequencer?答案很简单:组件变量是引用(句柄),不是值本身。理解了这一点,UVM 中 99% 的“神秘现象”都会豁然开朗。

句柄是指向对象的引用

句柄与对象:一对多的关系

在 SystemVerilog 中,类类型变量存储的是对象的内存地址,而不是对象本身。这个变量就是“句柄”。对象的实际内存是在new()create()时分配的。一个对象可以有多个句柄指向它,也可以没有句柄(此时对象被垃圾回收)。

重点:create()实际上执行了两步:分配内存并调用构造函数(new),然后返回该对象的句柄。我们把这个句柄赋值给某个变量(如m_reg_model),这只是让该变量指向对象,并不复制对象。

例如:

reg_model rm = reg_model::type_id::create("rm", this);

这里rm是一个句柄,指向工厂新创建的那个reg_model对象。我们可以把这个句柄复制给其他变量,它们都指向同一个对象。

父子组件间的句柄传递

在 UVM 组件树中,父组件在build_phase中创建子组件,并通常将子组件的句柄保存在自己的成员变量中。例如env创建了agent,并保存了agent的句柄。其他组件如果需要访问该agent,可以通过父组件的层次路径找到它,或者通过config_db传递句柄。

重点:父组件保留子组件句柄,是为了方便管理和访问。test 层能够通过env.agent访问,正是因为 env 的成员变量中保存了 agent 的句柄,而 test 持有 env 的句柄。

config_db注入等价于句柄传递

uvm_config_db::set()get()实际上存储和获取的是句柄值,而不是对象拷贝。当你set一个对象句柄后,其他组件get到的是同一个对象的句柄,因此它们共享同一个对象。这就是为什么 reg_model 在 env 中创建,test 中还能通过config_db拿到同一个 reg_model。

重点:config_db传递的是句柄(引用),不是深拷贝。所有通过get获取该对象的组件,操作的都是同一个对象。

对象创建与句柄共享

以下代码展示了在 env 中创建 reg_model 和 vsequencer,并通过 config_db 将 reg_model 句柄传递给 test 或其他组件。

class my_env extends uvm_env; reg_model m_reg_model; my_vseqr m_vseqr; `uvm_component_utils(my_env) function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); // 创建 reg_model 对象,并将句柄存到 m_reg_model m_reg_model = reg_model::type_id::create("m_reg_model", this); m_reg_model.build(); // 构建寄存器模型 // 创建 vsequencer 对象,并将句柄存到 m_vseqr m_vseqr = my_vseqr::type_id::create("m_vseqr", this); // 通过 config_db 将 reg_model 句柄共享给 test 层或其他组件 uvm_config_db #(reg_model)::set(this, "*", "reg_model", m_reg_model); endfunction endclass

在 test 中获取 reg_model:

class my_test extends uvm_test; `uvm_component_utils(my_test) function void build_phase(uvm_phase phase); super.build_phase(phase); my_env env; // 假设 env 已经作为 test 的子组件创建 env = my_env::type_id::create("env", this); // 通过 config_db 获取同一个 reg_model 对象 reg_model rm; if (!uvm_config_db #(reg_model)::get(this, "", "reg_model", rm)) begin `uvm_fatal("NOREG", "reg_model not found") end // 现在 rm 和 env.m_reg_model 指向同一个对象 endfunction endclass

解析:

  • m_reg_model = reg_model::type_id::create(...)中,create()返回一个句柄,该句柄指向新创建的对象,同时赋值给m_reg_model
  • uvm_config_db::set(this, "*", "reg_model", m_reg_model)将这个句柄放入配置数据库。注意,这里m_reg_model是句柄,存储的是对象的地址,不是对象本身。
  • 在 test 中get时,获得的是同一个句柄,因此rmenv.m_reg_model指向同一个对象,对rm的任何修改都会影响env.m_reg_model

跨组件共享同一对象

跨 env 共享 reg_model

在大型 SoC 验证中,可能有多个 env 或子 env 需要访问同一个寄存器模型。例如 CPU env 和 DMA env 都需要读写系统寄存器。此时只需在顶层 env 或 test 中创建一次 reg_model,然后通过 config_db 将句柄传递给所有需要的组件。这样既避免了重复创建,也保证了数据一致性。

virtual sequencer 挂载 real sequencer 句柄

在 SOC 验证中,virtual sequencer需要调度多个real sequencer。这些 real sequencer 实际上是由各自的 agent 创建的,vsequencer 并不创建它们,而是通过句柄引用它们。通常在 env 的connect_phase中,将 real sequencer 的句柄赋值给 vsequencer 的成员:

function void connect_phase(uvm_phase phase); vseqr.m_cpu_sqr = cpu_agt.sqr; // 只是句柄赋值,没有新对象 vseqr.m_dma_sqr = dma_agt.sqr; endfunction

这样 vsequencer 就拥有了这些 sequencer 的“通讯录”,可以指挥它们,但并没有拥有这些 sequencer 的所有权(对象仍然由各自的 agent 管理)。

共享配置对象

很多时候我们需要在多个组件间共享一个配置对象(例如接口配置、测试参数)。利用句柄传递,我们只需创建一个配置对象,通过 config_db 或直接赋值传递句柄,所有组件看到的是同一份配置,修改时也能实时同步。

句柄使用中的常见错误

  1. 句柄未初始化(null)就使用
    如果在new()create()之前就使用句柄,或者create()失败(例如工厂未注册),句柄为 null,调用其成员会引发运行时错误。务必在对象创建后检查句柄是否非空,或用$isunknown等确认。

  2. 句柄拷贝 ≠ 对象拷贝
    很多人误以为a = b会复制对象。实际上,a = b只是让两个句柄指向同一对象。如果希望复制对象,需要使用copy()方法或new后手动复制字段。理解引用语义是避免逻辑错误的关键。

  3. 父子句柄关系混淆
    子组件句柄由父组件保存,但子组件内部也可以通过get_parent()获取父组件句柄。如果错误地释放或覆盖父组件句柄,可能导致无法访问子组件。保持组件树清晰,避免手动销毁由 UVM 管理的组件。

  4. 句柄 null 调用 fatal
    在 UVM 中,访问 null 句柄会导致仿真中止(fatal error)。通常表现为Null pointer dereference在使用前必须检查,尤其是从config_db获取的对象,必须判断返回值是否为 1(成功)。

  5. build_phase 后才 set 句柄失败
    如果通过config_db传递句柄,set必须在目标组件的get之前完成。由于组件build_phase顺序自上而下,通常应在父组件或 test 的build_phase中尽早set。如果在connect_phase或之后才set,子组件已经get失败,导致句柄为 null。务必在正确 phase 完成配置传递。

6句柄理解透,UVM 99% 错误都能自解

在 UVM 学习和使用中,句柄与对象的关系是最基础也最重要的概念。很多看似玄乎的问题(为什么这个变量改了那个也变?为什么这里报 null?)根源都在于对句柄的误解。

记住以下要点:

  • 类类型变量是句柄,存储地址,不是数据本身。
  • new()/create()分配对象内存,返回句柄。
  • 多个句柄可以指向同一对象;一个对象可以被多个组件共享。
  • config_db传递的是句柄,不是对象拷贝,所以是高效的共享方式。
  • 使用前检查句柄是否非空,是避免 90% 运行时错误的好习惯。

当你彻底理解“句柄是指向对象的引用”后,UVM 环境中的对象创建、组件连接、配置共享都会变得清晰透明。这也是区分新手和老手的一道分水岭。掌握它,你在调试 UVM 平台时就能快速定位问题,不再被“奇怪”的现象迷惑。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/26 15:15:43

基于springboot房屋租赁系统的设计与实现源码+文档

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

作者头像 李华
网站建设 2026/8/26 15:13:17

基于springboot小说在线阅读平台源码+文档

温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:本人主页置顶文章(点我)开头有 CSDN 平台…

作者头像 李华
网站建设 2026/8/26 15:12:05

ModelManager + Bmc:rust-web-app数据访问层的设计哲学与实战

ModelManager Bmc:rust-web-app数据访问层的设计哲学与实战 【免费下载链接】rust-web-app Code template for a production Web Application using Axum: The AwesomeApp Blueprint for Professional Web Development. 项目地址: https://gitcode.com/gh_mirror…

作者头像 李华
网站建设 2026/8/26 15:12:03

CSP-J 初赛(以满分为目标):第八课《数组、字符串与常见数据结构——程序里的“储物柜”:一格一格存数据》

第八课 数组、字符串与常见数据结构——程序里的“储物柜”:一格一格存数据这一课是从“单个变量”走向“一组数据”的关键一步。本课要解决一个新问题:如果我要同时保存100个、1000个数据怎么办?这就进入了数组、字符串以及线性数据结构。一…

作者头像 李华