拓冰建站拓冰建站
首页 / 资讯中心 / 正文

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

对象在哪里创建句柄在哪里可见在 UVM 验证环境中我们经常看到这样的现象reg_model对象在env的build_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_modelclass 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时获得的是同一个句柄因此rm和env.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 或直接赋值传递句柄所有组件看到的是同一份配置修改时也能实时同步。句柄使用中的常见错误句柄未初始化null就使用如果在new()或create()之前就使用句柄或者create()失败例如工厂未注册句柄为 null调用其成员会引发运行时错误。务必在对象创建后检查句柄是否非空或用$isunknown等确认。句柄拷贝 ≠ 对象拷贝很多人误以为a b会复制对象。实际上a b只是让两个句柄指向同一对象。如果希望复制对象需要使用copy()方法或new后手动复制字段。理解引用语义是避免逻辑错误的关键。父子句柄关系混淆子组件句柄由父组件保存但子组件内部也可以通过get_parent()获取父组件句柄。如果错误地释放或覆盖父组件句柄可能导致无法访问子组件。保持组件树清晰避免手动销毁由 UVM 管理的组件。句柄 null 调用 fatal在 UVM 中访问 null 句柄会导致仿真中止fatal error。通常表现为Null pointer dereference。在使用前必须检查尤其是从config_db获取的对象必须判断返回值是否为 1成功。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 平台时就能快速定位问题不再被“奇怪”的现象迷惑。
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门