phase.raise.objection (phase); seq=new(); seq.start(e.sgr);
phase.drop_objection(phase) ;其中raise和drop是什么作用?是否重要?
在 UVM 的run_phase(或其它消耗时间的 task phase)中,raise_objection和drop_objection是极其重要、不可或缺的机制。它们直接决定了仿真会不会“提前结束”,以及各个组件之间的运行时间能否对齐。
一、它们的作用是什么?
UVM 的 phase 机制(尤其是run_phase及其子 phase)靠objection(反对/异议)机制来判断“这个 phase 该不该结束”。
raise_objection(提起异议):告诉 UVM 调度器:“我现在正在干活(比如启动 sequence、驱动激励),这个 phase 还不能结束,请等我。”drop_objection(撤销异议):告诉 UVM 调度器:“我干完活了,这个 phase 可以结束了(如果别人也没有异议的话)。”
UVM 只有在所有组件都 drop 了 objection(即没有任何 objection 被 raise)之后,才会结束当前 phase,进入下一个 phase。
二、结合你的代码逐行解析
phase.raise_objection(phase); seq = new(); seq.start(e.sgr); phase.drop_objection(phase);1.phase.raise_objection(phase);
phase是当前运行的 phase 对象(比如run_phase)。raise_objection是uvm_phase类的方法。- 传入的参数
phase(注意:标准写法通常是this,即当前组件)表示是谁提出了这个 objection。- 标准写法是
phase.raise_objection(this);。 - 这里传了
phase本身,语法上不报错,但追踪 objection 来源时会有些奇怪。建议改成this。
- 标准写法是
- 执行这行后,UVM 的 objection 计数器加 1,当前 phase 不会结束。
2.seq = new();
- 创建一个 sequence 对象。
- 注意:这里用了
new()而不是type_id::create(),意味着这个 sequence 不走 factory,不会被 override。如果想让 sequence 支持工厂覆盖,应该用seq = my_seq::type_id::create("seq");。 - 这一步本身不消耗仿真时间,只是分配内存。
3.seq.start(e.sgr);
start是uvm_sequence的方法。e.sgr是 sequencer 的句柄(假设e是某个环境组件,sgr是它里面的 sequencer)。seq.start(e.sgr)会把 sequence 挂到 sequencer 上,然后开始执行 sequence 的body()任务。- 这是一个消耗仿真时间的操作:sequence 会通过
start_item/finish_item把 item 发给 driver,driver 驱动 DUT,可能需要等几十、几百甚至几千个时钟周期。 - 所以必须在它前面
raise_objection,否则仿真会在时间 0 就结束,sequence 根本跑不完。
4.phase.drop_objection(phase);
- sequence 跑完后,撤销之前的 objection。
- 此时 objection 计数器减 1。
- 如果这是最后一个 objection,UVM 就会结束当前 phase,进入下一个 phase。
- 同样,标准写法是
phase.drop_objection(this);。
三、为什么说它们“极其重要”?
1. 没有 raise/drop,仿真会瞬间结束
UVM 的run_phase默认行为是:
如果没有任何 objection 被 raise,
run_phase会在时间 0 立即结束。
也就是说,如果你写:
task run_phase(uvm_phase phase); seq = new(); seq.start(e.sgr); endtask仿真会在时间 0 直接跳过run_phase,你的 sequence 根本来不及跑,DUT 也收不到任何激励。你会看到仿真“什么都没干就结束了”。
2. 它们控制 phase 的结束时机
UVM 的 phase 执行流程:
进入 run_phase ↓ 所有组件并行执行 run_phase 任务 ↓ 等待所有 objection 被 drop ↓ run_phase 结束,进入下一个 phaseraise_objection相当于“拉住刹车”;drop_objection相当于“松开刹车”;- 只有所有“刹车”都松开,phase 才会结束。
3. 多组件并行时的同步作用
一个测试平台里可能有多个组件同时 raise objection:
test里启动 sequence;scoreboard里等待比对完成;monitor里等待采集完最后一笔数据。
只要任何一个组件还持有 objection,run_phase就不会结束。这保证了所有组件都能把自己该干的事干完。
四、标准写法示例
class my_test extends uvm_test; `uvm_component_utils(my_test) my_sequence seq; my_env e; function new(string name, uvm_component parent); super.new(name, parent); endfunction function void build_phase(uvm_phase phase); super.build_phase(phase); e = my_env::type_id::create("e", this); endfunction task run_phase(uvm_phase phase); // 1. 提起 objection,阻止 phase 结束 phase.raise_objection(this); // 2. 创建并启动 sequence seq = my_sequence::type_id::create("seq"); seq.start(e.sgr); // 3. 撤销 objection,允许 phase 结束 phase.drop_objection(this); endtask endclass注意顺序:
raise_objection必须在消耗时间的操作(如seq.start)之前;drop_objection必须在消耗时间的操作之后;- 如果中间有
fork...join或异常,要确保drop_objection一定被执行(可以用try...finally或仔细控制流程)。
五、常见误区与注意事项
| 误区 | 说明 |
|---|---|
在build_phase里用 objection | build_phase是 function phase,不消耗时间,objection 无效,也不该用 |
raise了忘记drop | 仿真会一直卡住,直到超时(phase_done超时) |
drop了没raise | UVM 会报 warning/error,objection 计数器不能为负 |
用new()创建 sequence | 不推荐,应该用type_id::create(),否则无法被 factory override |
传参传phase而不是this | 语法允许,但标准写法是传this,便于调试和追踪 objection 来源 |
六、一句话总结
raise_objection是“等等我还没干完”,drop_objection是“我干完了,可以走了”。
它们决定了run_phase什么时候结束,是 UVM 仿真时间推进的核心控制机制。没有它们,run_phase会在时间 0 直接结束,sequence 根本跑不起来。所以它们非常重要,而且是每个 UVM 验证工程师必须掌握的基础。