UVM中如何在一个组件结束时终止另一个组件的forever循环?
UVM组件同步终止问题
问题背景
在UVM环境中存在两个组件:
component_a通过uvm_analysis_port向uvm_tlm_analysis_fifo发送事务component_b用forever循环轮询FIFO接收事务
需求是component_a完成事务发送后,component_b随之停止运行。但当前存在两个核心问题:
component_b的forever循环无法终止- 循环无时间消耗,抢占所有仿真时间片,导致
component_a及测试的run_phase完全无法执行,仅能看到component_b反复打印FIFO为空的信息
原代码
class basic_test extends uvm_test; .. task run_phase(uvm_phase phase); phase.raise_objection(this); // raise an objection #500; phase.drop_objection(this); // drop an objection endtask: run_phase endclass class component_a extends uvm_component; transaction trans; ... uvm_analysis_port#(transaction) analysis_port; ... virtual task run_phase(uvm_phase phase); for(int a=0; a<10; a++) begin trans = transaction::type_id::create("trans"); if (!trans.randomize()) `uvm_fatal("RNDERR", "Randomization of trans failed"); analysis_port.write(trans); `uvm_info(get_type_name(), "Trans Sending....",UVM_LOW) end endtask endclass class component_b extends uvm_component; ... virtual task run_phase(uvm_phase phase); ... forever begin `uvm_info(get_type_name(), $sformatf(" FIFO used: %0d", analy_fifo.used()), UVM_LOW) if(analy_fifo.is_empty()) begin `uvm_info(get_type_name(), "FIFO is Empty!!!!!!",UVM_LOW) end else begin analy_fifo.get(trans); `uvm_info(get_type_name(),$sformatf(" Printing receive trans, \n ",trans.sprint()),UVM_LOW) end end endtask endclass
当前仿真输出
UVM_INFO component_b.sv(55) @ 0: uvm_test_top.env.comp_b [component_b] FIFO is Empty!!!!!! UVM_INFO component_b.sv(52) @ 0: uvm_test_top.env.comp_b [component_b] FIFO used: 0 UVM_INFO component_b.sv(55) @ 0: uvm_test_top.env.comp_b [component_b] FIFO is Empty!!!!!! UVM_INFO component_b.sv(52) @ 0: uvm_test_top.env.comp_b [component_b] FIFO used: 0 ...
解决方案
方法1:利用UVM阶段终止信号(推荐)
通过UVM phase的is_done()方法监听阶段结束状态,同时添加小延时避免抢占时间片,确保其他组件能正常执行。
修改component_b的run_phase:
virtual task run_phase(uvm_phase phase); transaction trans; forever begin // 检查阶段是否准备结束,是则退出循环 if (phase.is_done()) break; `uvm_info(get_type_name(), $sformatf(" FIFO used: %0d", analy_fifo.used()), UVM_LOW) if(analy_fifo.is_empty()) begin `uvm_info(get_type_name(), "FIFO is Empty!!!!!!",UVM_LOW) // 添加小延时,释放仿真时间片 #1; end else begin analy_fifo.get(trans); `uvm_info(get_type_name(),$sformatf(" Printing receive trans, \n %s",trans.sprint()),UVM_LOW) end end endtask
同时优化component_a的objection管理,确保事务处理完成后再结束阶段:
virtual task run_phase(uvm_phase phase); phase.raise_objection(this); for(int a=0; a<10; a++) begin trans = transaction::type_id::create("trans"); if (!trans.randomize()) `uvm_fatal("RNDERR", "Randomization of trans failed"); analysis_port.write(trans); `uvm_info(get_type_name(), "Trans Sending....",UVM_LOW) // 给component_b留处理时间 #1; end // 等待FIFO清空后再结束阶段 while(!analy_fifo.is_empty()) #1; phase.drop_objection(this); endtask
方法2:显式同步事件通知
通过uvm_event实现组件间的同步,component_a发完事务后触发事件,component_b监听事件并在处理完剩余事务后退出循环。
- 在环境/测试中定义事件:
uvm_event tx_done_event;
- 修改
component_a触发事件:
virtual task run_phase(uvm_phase phase); for(int a=0; a<10; a++) begin // 原有事务发送逻辑 trans = transaction::type_id::create("trans"); if (!trans.randomize()) `uvm_fatal("RNDERR", "Randomization of trans failed"); analysis_port.write(trans); `uvm_info(get_type_name(), "Trans Sending....",UVM_LOW) #1; end // 触发事务发送完成事件 tx_done_event.trigger(); `uvm_info(get_type_name(), "All transactions sent", UVM_LOW) endtask
- 修改
component_b监听事件:
virtual task run_phase(uvm_phase phase); transaction trans; fork // 等待结束事件,之后处理剩余事务 begin tx_done_event.wait_trigger(); while(!analy_fifo.is_empty()) #1; end // 事务接收逻辑 begin forever begin // 事件触发且FIFO为空时退出 if(tx_done_event.is_triggered() && analy_fifo.is_empty()) break; `uvm_info(get_type_name(), $sformatf(" FIFO used: %0d", analy_fifo.used()), UVM_LOW) if(analy_fifo.is_empty()) begin `uvm_info(get_type_name(), "FIFO is Empty!!!!!!",UVM_LOW) #1; end else begin analy_fifo.get(trans); `uvm_info(get_type_name(),$sformatf(" Printing receive trans, \n %s",trans.sprint()),UVM_LOW) end end end join_any endtask
方法3:阻塞式接收(已知事务数量场景)
如果明确知道接收事务的数量,可以将轮询改为阻塞式get,避免空转循环:
virtual task run_phase(uvm_phase phase); transaction trans; int num_rx = 0; // 接收10个事务(与component_a发送数量一致) while(num_rx < 10) begin // 阻塞等待FIFO数据 analy_fifo.get(trans); num_rx++; `uvm_info(get_type_name(),$sformatf(" Printing receive trans, \n %s",trans.sprint()),UVM_LOW) `uvm_info(get_type_name(), $sformatf(" FIFO used: %0d", analy_fifo.used()), UVM_LOW) end `uvm_info(get_type_name(), "All transactions received", UVM_LOW) endtask
关键注意点
- 必须在
component_b的循环中添加延时(如#1),否则会无限抢占仿真时间片,导致其他组件无法执行,这是当前问题的核心原因。 - 严格管理objection,确保所有事务发送、接收完成后再drop objection,避免仿真提前结束。
内容的提问来源于stack exchange,提问作者bu-ral
相关产品推荐
相关产品推荐

