【验证技能树】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",

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


相关推荐
liuluyang5304 天前
UVM 工厂机制 完整可编译运行 Demo
uvm·uvm工厂机制
liuluyang5304 天前
UVM工厂机制
uvm·工厂机制
liuluyang5304 天前
UVM工厂机制(二)
uvm·工厂机制
liuluyang53010 天前
SystemVerilog常用关键词与函数
uvm·systermverilog
liuluyang53010 天前
SV主要关键词详解
fpga开发·uvm·sv
liuluyang53025 天前
clk_mux_seq sv改进
fpga开发·uvm
谷公子的藏经阁1 个月前
DVCon 2025 论文精华导读及下载链接
ai·论文·systemverilog·uvm·dvcon
蓝天下的守望者3 个月前
SystemVerilog中 `timescale的使用问题
systemverilog·uvm·vcs
蓝天下的守望者4 个月前
uvm_field_automation机制学习
uvm
Irene19914 个月前
Vue3 TypeScript 项目中,Emits 验证的使用场景
typescript·vue3·验证