【验证技能树】UVM 源码解读06 -- Objection 的完整源码解剖

Objection 看起来像计数器,
但本质上是一个:
有层级传播、有语义约束、有调度钩子的
分布式同步协议。

本文将从源码开始系统地拆解:
源码 → 设计动机 → 为什么它不是一个简单计数器


一、先把"错误直觉"打掉

很多人第一反应是:

"Objection 不就是:

raise +1,drop -1,

等到 0 就结束 run_phase 吗?"

这个理解是危险的。

如果 Objection 真是这样设计的,UVM 在以下场景会直接崩:

  • 多层 component hierarchy
  • 并行 run_phase
  • 动态 raise / drop
  • 中途插入的 sequence / monitor
  • Phase 之间的依赖关系

所以:Objection 必须比计数器复杂。


二、Objection 要解决的"真实工程问题"

在源码之前,先明确它解决什么问题。

核心问题只有一个:

在一个分布式、并行的验证系统中,
谁来决定"什么时候可以结束一个 phase"?

现实情况是:

  • driver 还在发 transaction
  • monitor 还在收最后一个 response
  • scoreboard 还没比完
  • coverage 还没 flush

👉 没有"中心节点"知道全局状态。

这就是 Objection 的存在理由。


三、Objection 的源码入口

📁 核心文件

复制代码
src/base/uvm_objection.svh

类定义(语义级)

systemverilog 复制代码
class uvm_objection extends uvm_object;

注意第一点:

Objection 本身是一个 object,而不是 component。

这意味着:

  • 它是"机制",不是"参与者"
  • 它不跑 phase,只服务 phase

四、Objection 的三层计数结构

源码里,Objection 维护的不是一个计数器,而是三层状态

1️⃣ 本地计数(per component)

systemverilog 复制代码
int m_source_count[uvm_component];

含义:

"某个 component 自己 raise 了多少 objection"

这是最直观的一层。


2️⃣ 层级传播计数(hierarchical)

systemverilog 复制代码
int m_total_count[uvm_component];

含义:

"这个 component + 所有子孙
一共还有多少 objection"

这是第一个"不是计数器"的地方。


3️⃣ 全局计数(phase-level)

systemverilog 复制代码
int m_total_objection_count;

含义:

"整个 phase 是否还能结束"

Phase 调度器只看这一层。


五、为什么需要"层级传播"?(核心设计点)

看一个非常现实的例子:

复制代码
env
 ├── agent
 │    ├── driver
 │    └── monitor

如果:

  • driver raise objection
  • monitor 没 raise
  • agent/env 没 raise

问题来了:

👉 env 要不要等 driver?

答案必须是:要。

所以 Objection 的规则是:

raise / drop 会沿 component hierarchy 向上传播。

源码中你会看到类似逻辑:

systemverilog 复制代码
parent.raise_propagated_objection();

这一步,直接否定了"简单计数器"的可能性。


六、为什么不能用"全局计数器"?

看起来可以这样写:

systemverilog 复制代码
global_cnt++;
...
global_cnt--;

但这样会直接带来三个致命问题:


❌ 1. 无法定位"是谁没结束"

UVM 在 objection 未清零时,可以打印:

  • 哪个 component
  • raise 了多少
  • 还没 drop

这在 debug 时是救命的。


❌ 2. 无法支持层级隔离

agent 内部 raise,不应该影响隔离的 env?

UVM 允许你:

  • 在某一层"截断" objection
  • 或只关心某个子树

全局计数器做不到。


❌ 3. 无法支持 phase 钩子语义

Objection 和 Phase 强绑定:

  • phase_ready_to_end
  • phase_ended

这些都需要 结构化信息,而不是一个数。


七、raise / drop 的真实语义(源码级)

raise_objection() 做的事 ≠ +1

源码语义是:

  1. 记录 source component
  2. 更新 source_count
  3. 更新 total_count
  4. 向 parent 传播
  5. 通知 phase:状态可能改变

同理,drop 也不是简单 -1,而是:

  • 检查合法性(不能 drop 超过 raise)
  • 检查是否触发"all dropped"
  • 通知 phase 调度器

八、all_dropped():不是"计数归零"那么简单

你会在源码里看到:

systemverilog 复制代码
if (m_total_objection_count == 0)
  all_dropped();

all_dropped() 不是 return true,而是:

  • 触发 phase_ready_to_end
  • 给 component 最后一次发言机会
  • 允许有人 重新 raise objection

这是一个非常关键的设计点

Phase 结束不是"瞬间事件",
而是一个"协商过程"。


九、为什么允许"快结束时再 raise objection"?

因为真实系统里经常发生:

  • monitor 收到最后一个 response
  • 突然发现还有 pending check
  • 需要多跑几个 delta cycle

如果 Objection 只是计数器,这种场景会直接失败。


十、用一句工程级总结

Objection 不是计数器,
而是一个:
以 component hierarchy 为传播路径、
以 phase 生命周期为边界、
以"协商结束"为目标的
分布式同步协议。


十一、为什么这是"架构级设计"?

因为 Objection:

  • 解耦了"谁在跑" vs "什么时候结束"
  • 支持并行、不要求中心协调
  • 支持扩展、不破坏既有代码

这已经是操作系统 / 分布式系统级别的设计思想


如果你已经能顺着源码理解到这里

你已经不再是"学 UVM",

而是在读一个复杂系统的内核设计


相关推荐
愤怒学习的白菜2 天前
0 trivial:UVM的空壳平台
学习·uvm·ic验证
啄缘之间9 天前
11. UVM Test [uvm_test]
经验分享·笔记·学习·uvm·总结
CHY_12811 天前
Synopsys JESD204B VIP(3)测试序列和SYSREF请求
uvm·vip·jesd204
CHY_12811 天前
Synopsys JESD204B VIP(2)传输示例和事项
uvm·vip·jesd204
CHY_12821 天前
Synopsys JESD204 VIP(1)环境介绍、传输配置类和接口
uvm·vip·jesd204
CHY_1282 个月前
UVM环境自动生成工具(2)uvmdvgen
uvm
openHiTLS密码开源社区4 个月前
【密码学基础】加密消息语法 CMS:给数字信息装个 “安全保险箱”
cms·加密·签名·验证·加密消息语法
白又白、5 个月前
uvm-tlm-sockets
uvm
百锦再5 个月前
WPF依赖属性深度解析:从原理到高级应用
wpf·依赖·绑定·验证·net·强制