You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

UVM中如何在一个组件结束时终止另一个组件的forever循环?

UVM组件同步终止问题

问题背景

在UVM环境中存在两个组件:

  • component_a 通过 uvm_analysis_port 向 uvm_tlm_analysis_fifo 发送事务
  • component_b 用forever循环轮询FIFO接收事务

需求是component_a完成事务发送后,component_b随之停止运行。但当前存在两个核心问题:

  1. component_b的forever循环无法终止
  2. 循环无时间消耗,抢占所有仿真时间片,导致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监听事件并在处理完剩余事务后退出循环。

  1. 在环境/测试中定义事件:
uvm_event tx_done_event;
  1. 修改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
  1. 修改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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 23:45:39