3. TLM FIFO:uvm_tlm_fifo 的作用、深度配置、阻塞与非阻塞操作及组件间通信应用

在 UVM 验证环境中,组件之间的数据传输是验证平台的核心功能。TLM FIFO(First-In-First-Out)作为 UVM TLM 标准库中最基础、最常用的传输通道,承担着连接 producer 与 consumer、解耦组件执行时序、缓存数据的关键角色。本章将深入剖析 uvm_tlm_fifo 的作用机制、深度配置方法、阻塞与非阻塞操作的区别,以及它在实际组件间通信中的典型应用模式。

3.1 uvm_tlm_fifo 的作用与定位

uvm_tlm_fifo 是 UVM 提供的一个参数化、基于 TLM 接口的 FIFO 实现。它本质上是一个带有存储能力的 TLM 传输通道,既可以作为 put/get 操作的端点,也可以作为 export 端口对外提供服务。其核心作用包括:

  • 数据缓存与缓冲:当 producer 产生数据的速度与 consumer 消费数据的速度不匹配时,FIFO 可以暂存数据,避免数据丢失或阻塞。
  • 时序解耦:producer 和 consumer 可以在不同的仿真时间点执行 put 和 get 操作,FIFO 作为中间存储层,使双方无需同步等待。
  • 接口适配:FIFO 可以连接不同类型的 TLM 端口(如 put_port 与 get_export),实现接口协议的转换与匹配。
  • 事务级建模:在事务级模型中,FIFO 作为通信通道,支持事务的排队、优先级处理以及延迟模拟。
关键概念:uvm_tlm_fifo 是一个参数化类,其声明为 class uvm_tlm_fifo #(type T=int) extends uvm_component。类型参数 T 决定了 FIFO 中存储的事务数据类型,默认值为 int。

3.2 FIFO 的深度配置

FIFO 的深度决定了其最多可以缓存多少个事务。深度配置直接影响验证平台的资源消耗、数据吞吐量以及死锁风险。UVM 提供了两种配置方式:

配置方式 语法/方法 说明
构造函数参数 new(name, parent, depth) 在创建 FIFO 实例时直接指定深度,最常用。
运行时配置 set_depth(int depth) 通过 FIFO 对象的方法动态修改深度,需谨慎使用。
默认深度 不指定时默认深度为 1 仅能缓存一个事务,适用于同步传输场景。
// 创建深度为 10 的 FIFO,用于传输 my_transaction 类型
uvm_tlm_fifo #(my_transaction) fifo_h;
fifo_h = new("fifo_h", this, 10);

// 运行时修改深度(不推荐在仿真过程中频繁使用)
fifo_h.set_depth(20);
深度配置注意事项:深度过小可能导致 producer 阻塞(当 FIFO 满时 put 操作被阻塞);深度过大则浪费内存资源。建议根据 producer 与 consumer 的速率比、事务大小以及仿真时间窗口来估算合理深度。对于无界 FIFO,可以使用 uvm_tlm_fifo #(T)::new("name", this, 0),此时深度为 0 表示无限制。

3.3 阻塞与非阻塞操作

uvm_tlm_fifo 支持两种类型的 put/get 操作:阻塞操作和非阻塞操作。这两种操作模式决定了当 FIFO 满(put 时)或空(get 时)时,调用方的行为。

3.3.1 阻塞操作

阻塞操作会在条件不满足时挂起当前进程,直到操作可以成功执行。这是最常用的操作模式,适用于 producer 和 consumer 可以等待的场景。

方法 功能 阻塞条件
put(T t) 将事务 t 放入 FIFO FIFO 满时阻塞,直到有空位
get(output T t) 从 FIFO 取出事务到 t FIFO 空时阻塞,直到有数据
peek(output T t) 查看 FIFO 头部事务但不移除 FIFO 空时阻塞
// 阻塞 put 示例
task run_phase(uvm_phase phase);
  my_transaction tr;
  forever begin
    // 产生事务
    tr = my_transaction::type_id::create("tr");
    // 阻塞放入 FIFO,若 FIFO 满则等待
    fifo_h.put(tr);
  end
endtask

// 阻塞 get 示例
task run_phase(uvm_phase phase);
  my_transaction tr;
  forever begin
    // 阻塞从 FIFO 取出事务,若 FIFO 空则等待
    fifo_h.get(tr);
    // 处理事务
    process_transaction(tr);
  end
endtask

3.3.2 非阻塞操作

非阻塞操作会立即返回,无论操作是否成功。调用方需要检查返回值来判断操作是否完成。这种模式适用于需要轮询或超时控制的场景。

方法 功能 返回值
try_put(T t) 尝试放入事务 t 成功返回 1,失败返回 0
try_get(output T t) 尝试取出事务到 t 成功返回 1,失败返回 0
can_put() 查询是否可以放入 有空位返回 1,否则 0
can_get() 查询是否可以取出 有数据返回 1,否则 0
// 非阻塞 try_put 示例
task run_phase(uvm_phase phase);
  my_transaction tr;
  forever begin
    tr = generate_transaction();
    // 尝试非阻塞放入,若失败则丢弃或重试
    if (fifo_h.try_put(tr)) begin
      `uvm_info("PRODUCER", "Transaction put successfully", UVM_MEDIUM)
    end else begin
      `uvm_warning("PRODUCER", "FIFO full, transaction dropped")
    end
  end
endtask

// 非阻塞 try_get 示例
task run_phase(uvm_phase phase);
  my_transaction tr;
  forever begin
    // 尝试非阻塞取出
    if (fifo_h.try_get(tr)) begin
      process_transaction(tr);
    end else begin
      // FIFO 空,执行其他任务或等待
      #10;
    end
  end
endtask
阻塞 vs 非阻塞选择指南:
  • 阻塞操作:适用于 producer 和 consumer 速率匹配、可以相互等待的场景。代码简洁,逻辑清晰。
  • 非阻塞操作:适用于需要超时控制、多路复用、或者 producer/consumer 不能长时间阻塞的场景。需要额外处理失败情况。
  • 混合使用:可以在同一个 FIFO 上混合使用阻塞和非阻塞操作,但需注意避免死锁。

3.4 FIFO 在组件间通信中的应用

在 UVM 验证平台中,uvm_tlm_fifo 最常见的应用场景是连接 driver 与 monitor、sequencer 与 driver,以及 scoreboard 与 coverage collector 之间的数据传输。下面通过一个典型的验证平台架构图来展示 FIFO 的通信位置。

UVM 验证平台中 TLM FIFO 通信架构 UVM 验证平台 TLM FIFO 通信架构 Sequencer (事务生成器) Driver (接口驱动) Monitor (信号采样) Scoreboard (数据比对) Coverage Collector (覆盖率收集) FIFO #1 seq_item_port FIFO #2 mon_ap FIFO #3 cov_ap 图例说明 • FIFO #1 (seq_item_port):Sequencer 将事务序列发送给 Driver,Driver 阻塞 get 等待事务。 • FIFO #2 (mon_ap):Monitor 将采样到的事务通过 analysis port 发送给 Scoreboard 进行比对。 • FIFO #3 (cov_ap):Monitor 同时将事务发送给 Coverage Collector 进行覆盖率采样。

3.4.1 典型应用模式:Sequencer 与 Driver 之间的 FIFO

在 UVM 中,Sequencer 和 Driver 之间通过 seq_item_port 和 seq_item_export 连接,底层实际上使用了一个 uvm_tlm_fifo 作为传输通道。这个 FIFO 的深度通常为 1,但可以通过配置修改。

// 在 agent 中连接 sequencer 和 driver
class my_agent extends uvm_agent;
  my_sequencer sqr;
  my_driver    drv;
  
  function void build_phase(uvm_phase phase);
    sqr = my_sequencer::type_id::create("sqr", this);
    drv = my_driver::type_id::create("drv", this);
  endfunction
  
  function void connect_phase(uvm_phase phase);
    // 通过 TLM FIFO 连接 sequencer 和 driver
    drv.seq_item_port.connect(sqr.seq_item_export);
  endfunction
endclass

3.4.2 典型应用模式:Monitor 与 Scoreboard 之间的 FIFO

Monitor 通过 analysis port 将采集到的事务广播给多个 subscriber(如 Scoreboard、Coverage Collector)。每个 subscriber 内部都有一个 uvm_tlm_fifo 来缓存接收的事务。

// Monitor 端:通过 analysis port 发送事务
class my_monitor extends uvm_monitor;
  uvm_analysis_port #(my_transaction) mon_ap;
  
  function void build_phase(uvm_phase phase);
    mon_ap = new("mon_ap", this);
  endfunction
  
  task run_phase(uvm_phase phase);
    my_transaction tr;
    forever begin
      // 从 DUT 接口采样事务
      tr = sample_transaction();
      // 通过 analysis port 广播
      mon_ap.write(tr);
    end
  endtask
endclass

// Scoreboard 端:通过 analysis export 接收事务
class my_scoreboard extends uvm_scoreboard;
  uvm_tlm_fifo #(my_transaction) fifo_h;
  
  function void build_phase(uvm_phase phase);
    // 创建深度为 100 的 FIFO,用于缓存 monitor 发送的事务
    fifo_h = new("fifo_h", this, 100);
  endfunction
  
  task run_phase(uvm_phase phase);
    my_transaction tr;
    forever begin
      // 阻塞从 FIFO 取出事务进行处理
      fifo_h.get(tr);
      compare_transaction(tr);
    end
  endtask
endclass

3.5 FIFO 状态查询与调试

uvm_tlm_fifo 提供了一系列状态查询方法,方便在仿真过程中监控 FIFO 的使用情况,对于覆盖率分析和调试非常有用。

方法 返回值 说明
used() int 当前 FIFO 中缓存的事务数量
is_empty() bit FIFO 是否为空
is_full() bit FIFO 是否已满
size() int FIFO 的最大深度
flush() void 清空 FIFO 中的所有事务
// 在覆盖率分析中使用 FIFO 状态
function void check_fifo_coverage();
  if (fifo_h.is_full()) begin
    `uvm_info("FIFO_COV", $sformatf("FIFO full at time %0t, used=%0d", $time, fifo_h.used()), UVM_LOW)
    // 记录 FIFO 满的覆盖率事件
    cov_group.sample();
  end
  
  if (fifo_h.used() > fifo_h.size() * 0.8) begin
    `uvm_warning("FIFO_COV", $sformatf("FIFO usage exceeds 80%%: %0d/%0d", fifo_h.used(), fifo_h.size()))
  end
endfunction
覆盖率分析要点:在验证平台中,FIFO 的深度使用情况、满/空状态切换频率、阻塞等待时间等指标都可以作为覆盖率分析的输入。通过监控 FIFO 的状态,可以评估验证平台的通信效率、发现潜在的死锁风险,并优化 FIFO 深度配置。

3.6 本章小结

uvm_tlm_fifo 是 UVM 验证平台中组件间通信的核心通道。通过合理配置 FIFO 深度、选择合适的阻塞/非阻塞操作模式,可以构建高效、稳定的数据传输链路。在实际应用中,FIFO 不仅承担数据缓存的功能,更是实现组件解耦、时序隔离和覆盖率分析的关键基础设施。掌握 FIFO 的配置与使用,是构建高质量 UVM 验证平台的基础。