uvm_tlm_fifo内部代码的相关方法和功能

我们现在就UVM TLM FIFO 类来拆解uvm_tlm_fifo 的相关方法和功能,代码中包含了uvm_tlm_fifo 和 uvm_tlm_analysis_fifo。它们用于在 UVM 验证环境中不同组件之间传输事务。让我们分别分析其功能:

  1. uvm_tlm_fifo 类:

功能: 这是一个通用的 TLM FIFO,用于在两个进程之间缓存事务。它具有有限的容量(可以通过 size 参数指定,默认为 1),并按照先进先出 (FIFO) 的原则处理事务。

关键方法:

new(): 构造函数,初始化 FIFO 的大小。如果 size 为 0,则 FIFO 容量无限大。

put(): 将事务放入 FIFO。如果 FIFO 已满,则阻塞直到有空间。

get(): 从 FIFO 获取事务。如果 FIFO 为空,则阻塞直到有事务可用。

peek(): 查看 FIFO 中下一个事务,但不将其移除。

try_put(), try_get(), try_peek(): 非阻塞版本的 put, get, peek 方法。如果操作成功则返回 1,否则返回 0.

size(): 返回 FIFO 的容量。

used(): 返回 FIFO 中已使用空间的大小。

is_empty(): 检查 FIFO 是否为空。

is_full(): 检查 FIFO 是否已满。

can_put(): 检查是否可以放入事务。

can_get(): 检查是否可以获取事务。

can_peek(): 检查是否可以查看事务。

flush(): 清空 FIFO。

内部机制: 使用 mailbox #(T) 作为底层存储机制。mailbox 是 UVM 提供的用于进程间通信的组件,它提供了线程安全的读写操作。

  1. uvm_tlm_analysis_fifo 类:

功能: 这是一个基于分析接口的 FIFO,其容量无限大。它主要用于连接分析端口 (uvm_analysis_port) 和 TLM 目标组件。这种 FIFO 能够在不阻塞的情况下写入事务,因为它的容量是无限的。

关键方法:

new(): 构造函数,初始化一个无限容量的 FIFO,并创建一个 analysis_export 接口。

write(): 将事务写入 FIFO。由于容量无限大,此操作总是成功的。

与 uvm_tlm_fifo 的区别:

容量:uvm_tlm_analysis_fifo 容量无限大,而 uvm_tlm_fifo 容量有限。

接口:uvm_tlm_analysis_fifo 提供了 analysis_export 接口,用于连接分析端口。

阻塞:uvm_tlm_analysis_fifo 的 write 操作是非阻塞的,而 uvm_tlm_fifo 的 put 操作可能是阻塞的。

typedef class uvm_tlm_event; // 定义一个 uvm_tlm_event 类类型的别名

//------------------------------------------------------------------------------
// 标题:TLM FIFO 类
//
// 本节定义基于 TLM 的 FIFO 类。
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
// 类:uvm_tlm_fifo
//
// 此类在两个独立运行的进程之间提供事务的存储。事务通过 ~put_export~ 放入 FIFO。
// 事务按到达的顺序从 FIFO 中获取,通过 ~get_peek_export~ 获取。~put_export~ 和
// ~get_peek_export~ 继承自 <uvm_tlm_fifo_base #(T)> 超类,这些导出提供的接口方法由
// <uvm_tlm_if_base #(T1,T2)> 类定义。
//------------------------------------------------------------------------------

class uvm_tlm_fifo #(type T=int) extends uvm_tlm_fifo_base #(T); // 定义一个名为 uvm_tlm_fifo 的类,参数化类型为 T (默认是 int),继承自 uvm_tlm_fifo_base #(T)

  const static string type_name = "uvm_tlm_fifo #(T)"; // 定义类的类型名称

  local mailbox #( T ) m; // 定义一个局部邮箱,用于存储事务,类型为 T
  local int m_size; // 定义FIFO的大小
  protected int m_pending_blocked_gets; // 保护型变量,跟踪阻塞的get操作数量


  // 函数:new
  //
  // ~name~ 和 ~parent~ 是标准的 uvm_component 构造函数参数。如果 <uvm_tlm_fifo> 将
  // 用于静态详细阐述的结构(例如,模块),则 ~parent~ 应为 null。~size~ 指示 FIFO 的
  // 最大大小;值为零表示没有上限。

  function new(string name, uvm_component parent = null, int size = 1); // 构造函数
    super.new(name, parent); // 调用父类的构造函数
    m = new( size ); // 创建一个大小为 size 的邮箱
    m_size = size; // 设置 FIFO 大小
  endfunction

  virtual function string get_type_name(); // 获取类名
    return type_name;
  endfunction


  // 函数:size
  //
  // 返回 FIFO 的容量,即 FIFO 能够容纳的条目数。返回值 0 表示 FIFO 容量没有限制。

  virtual function int size();
    return m_size;
  endfunction


  // 函数:used
  //
  // 返回放入 FIFO 的条目数。

  virtual function int used();
    return m.num(); // 返回邮箱中事务的数量
  endfunction


  // 函数:is_empty
  //
  // 当 FIFO 中没有条目时返回 1,否则返回 0。

  virtual function bit is_empty();
    return (m.num() == 0); // 判断邮箱是否为空
  endfunction


  // 函数:is_full
  //
  // 当 FIFO 中的条目数等于其 <size> 时返回 1,否则返回 0。

  virtual function bit is_full();
    return (m_size != 0) && (m.num() == m_size); // 判断邮箱是否已满
  endfunction



  virtual task put( input T t ); // 将事务 t 放入 FIFO
    m.put( t ); // 将事务放入邮箱
    put_ap.write( t ); // 将事务写入put接口
  endtask

  virtual task get( output T t ); // 从 FIFO 获取事务
    m_pending_blocked_gets++; // 阻塞的get操作计数加1
    m.get( t ); // 从邮箱获取事务
    m_pending_blocked_gets--; // 阻塞的get操作计数减1
    get_ap.write( t ); // 将事务写入get接口
  endtask

  virtual task peek( output T t ); // 查看FIFO中的事务,但不移除
    m.peek( t ); // 查看邮箱中的事务
  endtask

  virtual function bit try_get( output T t ); // 尝试从FIFO获取事务,失败返回0
    if( !m.try_get( t ) ) begin // 尝试从邮箱获取事务
      return 0; // 获取失败
    end

    get_ap.write( t ); // 将事务写入get接口
    return 1; // 获取成功
  endfunction

  virtual function bit try_peek( output T t ); // 尝试查看FIFO中的事务,失败返回0
    if( !m.try_peek( t ) ) begin // 尝试查看邮箱中的事务
      return 0; // 查看失败
    end
    return 1; // 查看成功
  endfunction

  virtual function bit try_put( input T t ); // 尝试将事务放入FIFO,失败返回0
    if( !m.try_put( t ) ) begin // 尝试将事务放入邮箱
      return 0; // 放入失败
    end

    put_ap.write( t ); // 将事务写入put接口
    return 1; // 放入成功
  endfunction

  virtual function bit can_put(); // 判断是否可以放入事务
    return m_size == 0 || m.num() < m_size; // 如果大小为0或未满则可以放入
  endfunction

  virtual function bit can_get(); // 判断是否可以获取事务
    return m.num() > 0 && m_pending_blocked_gets == 0; // 如果邮箱不为空且没有阻塞的get操作,则可以获取
  endfunction

  virtual function bit can_peek(); // 判断是否可以查看事务
    return m.num() > 0; // 如果邮箱不为空,则可以查看
  endfunction


  // 函数:flush
  //
  // 删除 FIFO 中的所有条目,之后 <used> 返回 0,<is_empty> 返回 1。

  virtual function void flush(); // 清空FIFO
    T t;
    bit r;

    r = 1;
    while( r ) r = try_get( t ) ; // 循环尝试获取事务直到FIFO为空

    if( m.num() > 0 && m_pending_blocked_gets != 0 ) begin // 判断是否有阻塞的get操作
      uvm_report_error("flush failed" , // 报告错误
               "there are blocked gets preventing the flush", UVM_NONE); // 错误信息
    end

  endfunction

endclass


//------------------------------------------------------------------------------
// 类:uvm_tlm_analysis_fifo
//
// analysis_fifo 是一个大小无界且具有写入接口的 <uvm_tlm_fifo>。它可以在任何使用
// <uvm_analysis_imp> 的地方使用。典型的用法是作为启动器组件中的 <uvm_analysis_port>
// 和 TLM1 目标组件之间的缓冲区。
//------------------------------------------------------------------------------

class uvm_tlm_analysis_fifo #(type T = int) extends uvm_tlm_fifo #(T); // 定义一个名为 uvm_tlm_analysis_fifo 的类,继承自 uvm_tlm_fifo

  // 端口:analysis_export #(T)
  //
  // analysis_export 向所有连接的分析端口和父导出提供 write 方法:
  //
  //|  function void write (T t)
  //
  // 通过绑定到此导出的端口进行访问是写入分析 FIFO 的正常机制。
  // 有关更多信息,请参见 <uvm_tlm_if_base #(T1,T2)> 的 write 方法。

  uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export; // 定义一个分析接口


  // 函数:new
  //
  // 这是标准的 uvm_component 构造函数。~name~ 是此组件的本地名称。当此组件在
  // 静态详细阐述的结构中实例化时,应不指定 ~parent~,而当此组件是另一个 UVM
  // 组件的子组件时,必须指定 ~parent~。

  function new(string name ,  uvm_component parent = null); // 构造函数
    super.new(name, parent, 0); // analysis fifo must be unbounded  // 调用父类的构造函数,大小设置为0,表示无界
    analysis_export = new("analysis_export", this); // 创建分析接口
  endfunction

  const static string type_name = "uvm_tlm_analysis_fifo #(T)"; // 定义类的类型名称

  virtual function string get_type_name(); // 获取类名
    return type_name;
  endfunction

  function void write(input T t); // 写入事务到FIFO
    void'(this.try_put(t)); // unbounded => must succeed // 因为是无界FIFO,所以写入一定成功
  endfunction

endclass

总结:

这两个类为 UVM 验证环境提供了灵活的 TLM 事务缓存机制。uvm_tlm_fifo 提供了有限容量的 FIFO,适合需要控制缓冲区大小的场景;uvm_tlm_analysis_fifo 提供了无限容量的 FIFO,并通过分析接口与其他组件通信,适合用于连接分析端口和目标组件,减少阻塞,提高效率。 它们都使用了 mailbox 来保证线程安全。 m_pending_blocked_gets 变量用于跟踪阻塞的 get 操作,这对于 flush 函数的正确性至关重要,以避免在存在阻塞的 get 的情况下,错误地清空 FIFO。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值