[UVM]TLM (2)

TLM FIFO

 

1. 把uvm_tlm_fifo/uvm_tlm_analysis_fifo中常用的task/function list 在下面,如果fifo例化在接收端的component中,那接收端就可以直接调用get,而不用再例化port/export.

2. 使用FIFO时,一端用put 类型的port,另一端用get 类型的port。

3. put_ap和get_ap的作用可以参考后面code。

peek与get的区别:

调用get任务时,FIFO内部缓存中会少一个transaction,而peek被调用时,FIFO会把transaction复制一份发出去,其内部缓存中的transaction数量并不会减少。

只有uvm_tlm_analysis_fifo才有analysis_export.

nametype

put_export
uvm_put_imp
blocking_put_exportuvm_put_imp

noblocking_put_export
uvm_put_imp     
analysis_exportuvm_analysis_imp
get_peek_exportuvm_get_peek_imp
get_exportuvm_get_peek_imp
blocking_get_exportuvm_get_peek_imp
noblocking_get_exportuvm_get_peek_imp
peek_exportuvm_get_peek_imp
blocking_peek_exportuvm_get_peek_imp
noblocking_peek_exportuvm_get_peek_imp
blocking_get_peek_exportuvm_get_peek_imp
nonblocking_get_peek_exportuvm_get_peek_imp

put_ap

get_ap

uvm_analysis_port

 

给出针对第一点的例子

class scb extends uvm_scoreboard;

  uvm_tlm_analysis_fifo#(txn) recv_fifo[16];
  
  function void build_phase(uvm_phase phase);
    string inst_name;
    foreach(recv_fifo[ii])begin
      $sformat(inst_name,"tx_trans_fifo[%0d]",ii);
      recv_fifo[ii] = new(inst_name,this);
    end
  endfunction


  task run_phase(uvm_phase phase);
    forever begin

      recv_fifo[0].get(tx_trans);
      ...
    end

  endtask


endclass

 

 

class uvm_tlm_fifo #(type T=int) extends uvm_tlm_fifo_base #(T);

     const static string type_name = "uvm_tlm_fifo #(T)";

      local mailbox #( T ) m;  //用mailbox实现FIFO内部的缓存
      local int m_size;
      protected int m_pending_blocked_gets;
  // Function: new
  //
  // The ~name~ and ~parent~ are the normal uvm_component constructor arguments. 
  // The ~parent~ should be null if the <uvm_tlm_fifo> is going to be used in a
  // statically elaborated construct (e.g., a module). The ~size~ indicates the
  // maximum size of the FIFO; a value of zero indicates no upper bound.
function new (string name, uvm_component parent = null, int size = 1);   
super.new(name, parent);
    m = new( size );
    m_size = size;
endfunction
 

  virtual function string get_type_name();
      return type_name;
  endfunction

  // Function: size
  //
  // Returns the capacity of the FIFO-- that is, the number of entries
  // the FIFO is capable of holding. A return value of 0 indicates the
  // FIFO capacity has no limit.
  virtual function int size();
    return m_size;
  endfunction
 

  // Function: used
  //
  // Returns the number of entries put into the FIFO.

  virtual function int used();
    return m.num();
  endfunction
  // Function: is_empty
  //
  // Returns 1 when there are no entries in the FIFO, 0 otherwise.

  virtual function bit is_empty();
    return (m.num() == 0);
  endfunction
 

  // Function: is_full
  //
  // Returns 1 when the number of entries in the FIFO is equal to its <size>,
  // 0 otherwise.

  virtual function bit is_full();
     return (m_size != 0) && (m.num() == m_size);
  endfunction
 

  virtual task put( input T t );
     m.put( t );
     put_ap.write( t );
  endtask

  virtual task get( output T t );
     m_pending_blocked_gets++;
     m.get( t );
     m_pending_blocked_gets--;
     get_ap.write( t );
  endtask
  
  virtual task peek( output T t );
     m.peek( t );
  endtask
   
  virtual function bit try_get( output T t );
    if( !m.try_get( t ) ) begin
       return 0;
    end

    get_ap.write( t );
    return 1;
  endfunction 
  
  virtual function bit try_peek( output T t );
     if( !m.try_peek( t ) ) begin
       return 0;
     end
     return 1;
  endfunction

  virtual function bit try_put( input T t );
     if( !m.try_put( t ) ) begin
        return 0;
     end
  
    put_ap.write( t );
    return 1;
  endfunction  

  virtual function bit can_put();
     return m_size == 0 || m.num() < m_size;
  endfunction  

  virtual function bit can_get();
     return m.num() > 0 && m_pending_blocked_gets == 0;
  endfunction
  
  virtual function bit can_peek();
     return m.num() > 0;
  endfunction



  // Function: flush
  //
  // Removes all entries from the FIFO, after which <used> returns 0
  // and <is_empty> returns 1.

 
virtual function void flush();
T t;

    bit r;

    r = 1; 

    while( r ) r = try_get( t ) ;  
    if( m.num() > 0 && m_pending_blocked_gets != 0 ) begin
      uvm_report_error("flush failed" ,
      "there are blocked gets preventing the flush", UVM_NONE);
    end
endfunction

 

endclass 


//------------------------------------------------------------------------------
//
// Class: uvm_tlm_analysis_fifo
//
// An analysis_fifo is a <uvm_tlm_fifo> with an unbounded size and a write interface.
// It can be used any place a <uvm_analysis_imp> is used. Typical usage is
// as a buffer between an <uvm_analysis_port> in an initiator component
// and TLM1 target component.
//
//------------------------------------------------------------------------------


class uvm_tlm_analysis_fifo #(type T = int) extends uvm_tlm_fifo #(T);

  // Port: analysis_export #(T)
  //
  // The analysis_export provides the write method to all connected analysis
  // ports and parent exports:
  //
  //|  function void write (T t)
  //
  // Access via ports bound to this export is the normal mechanism for writing
  // to an analysis FIFO. 
  // See write method of <uvm_tlm_if_base #(T1,T2)> for more information.

  uvm_analysis_imp #(T, uvm_tlm_analysis_fifo #(T)) analysis_export;



  // Function: new
  //
  // This is the standard uvm_component constructor. ~name~ is the local name
  // of this component. The ~parent~ should be left unspecified when this
  // component is instantiated in statically elaborated constructs and must be
  // specified when this component is a child of another UVM component.

  function new(string name ,  uvm_component parent = null);
      super.new(name, parent, 0); // analysis fifo must be unbounded
      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);
      void'(this.try_put(t));
  endfunction

endclass

 

<think>首先,用户的问题是关于UVM TLM验证方法和最佳实践的。我需要基于提供的引用内容来构建回答。引用内容涉及UVM TLM的核心概念、端口类型、以及一些UVM的基础知识。 关键引用: - 引用[2]:详细描述了UVM TLM的核心作用、端口类型和应用。 - 引用[3]:讨论了UVM的标准化、灵活性和可重用性,提到UVM支持TLM。 - 引用[4]:提到了run_test()方法,虽然不直接相关,但可能涉及测试环境设置。 - 引用[1]:是关于UVM实战的书籍推荐,可以作为学习资源。 用户的问题焦点是“UVM TLM验证方法和最佳实践”,所以我需要围绕这个主题组织回答。 回答结构: 1. **理解UVM TLM**:简要介绍UVM TLM是什么,基于引用[2]。 2. **验证方法**:解释如何验证TLM通信,包括测试点的定义、事务生成、检查机制等。 3. **最佳实践**:基于引用内容,提供实际建议,如模块化设计、重用性、错误处理等。 4. **相关工具和资源**:提到引用[1]中的书籍作为学习资源。 5. **生成相关问题**:在末尾添加相关问题,以引导进一步讨论。 6. **引用标识**:在回答中自然地添加引用标识,例如[^2]。 确保使用中文回答,因为用户指定了中文。 LaTeX格式: - 行内数学表达式用$...$,例如变量。 - 独立公式用$$...$$,但在这个主题中可能不需要数学公式,除非涉及算法或性能指标。如有必要,添加简单公式。 回答内容大纲: - **引言**:重述用户问题,确认焦点。 - **UVM TLM概述**:基于引用[2],解释TLM的核心作用。 - **验证方法**: - 如何设置TLM通信测试。 - 使用UVM组件如uvm_tlm_analysis_port等。 - 事务级测试用例设计。 - **最佳实践**: - 模块化和重用性(引用[3])。 - 错误注入和覆盖率分析。 - 性能优化(如仿真效率)。 - **实战案例**:基于引用[1],建议参考书籍。 - **常见问题解决**:基于引用[4],如测试类找不到的问题。 - **总结**:强调关键点。 - **相关问题**:生成3-5个相关问题。 生成相关问题: 1. 如何调试UVM TLM通信失败? 2. UVM TLM中有哪些常见的端口类型及其区别? 3. 如何实现TLM事务的随机化测试? 4. UVM TLM验证中的覆盖率驱动方法? 5. 对比UVM TLM与其他验证方法如OVM。 确保回答真实可靠:基于提供的引用内容,避免编造信息。</think>### UVM TLM验证方法和最佳实践 UVM TLM(事务级建模)是UVM验证平台的核心机制,它通过抽象事务(Transaction)实现组件间的高效通信,提升验证的可重用性和仿真效率。以下是基于UVM TLM的验证方法和最佳实践的详细解析,结合了UVM的核心概念和实际应用经验。 #### 1. **UVM TLM概述** - **核心作用**:UVM TLM将数据传输抽象为事务(如寄存器读写或数据包),隐藏底层信号时序细节,显著提升仿真效率和平台可维护性[^2]。例如,事务传输比信号级仿真快$10\times$以上,尤其适合复杂协议验证。 - **端口类型**: - `uvm_tlm_analysis_port`:用于单向广播事务(如监控器到记分板)。 - `uvm_tlm_put_port` 和 `uvm_tlm_get_port`:用于双向事务(如驱动器和代理)。 - `uvm_tlm_fifo`:作为事务缓冲区,解决组件间速度不匹配问题[^2]。 - 这种抽象机制使验证平台更易解耦,支持模块化设计,便于重用[^3]。 #### 2. **UVM TLM验证方法** 验证UVM TLM通信的核心是确保事务正确生成、传输和处理。以下是标准方法: - **测试点定义**:基于设计规范,识别关键事务路径。例如: - 事务完整性:检查事务数据是否在传输中损坏。 - 时序约束:验证事务延迟是否符合协议要求(如$t_{\text{latency}} \leq 10\text{ns}$)。 - 错误场景:注入错误事务(如无效地址),测试错误处理机制。 - **事务生成与检查**: - 使用`uvm_sequence`生成随机事务,覆盖边界条件(如最小/最大数据包大小)。 - 在接收端(如记分板)实现`uvm_subscriber`,比较输入/输出事务的一致性。 - 示例代码片段: ```systemverilog class my_scoreboard extends uvm_scoreboard; uvm_tlm_analysis_fifo #(my_transaction) fifo; function void compare(my_transaction tx_sent, tx_rcvd); if (tx_sent.data !== tx_rcvd.data) begin `uvm_error("TLM_ERR", "事务数据不匹配") // 错误检查 end endfunction endclass ``` - **覆盖率驱动验证**: - 定义功能覆盖率模型(如`uvm_covergroup`),覆盖事务类型、数据范围和错误码。 - 目标:达到$>95\%$的代码覆盖率和功能覆盖率,确保TLM路径全覆盖[^2]。 - **调试工具**:使用UVM内置报告机制(如`uvm_info`/`uvm_error`)和仿真器日志,快速定位事务丢失或错误。 #### 3. **最佳实践** 基于UVM标准,以下实践可提升TLM验证的效率和可靠性: - **模块化设计**:将TLM组件(如生产者、消费者)封装为独立模块,通过接口连接。这减少耦合,便于平台重用(例如,同一TLM代理可用于多个DUT)[^3]。 - **重用性与扩展性**: - 使用UVM工厂模式(`uvm_factory`)动态创建事务类型,支持测试扩展。 - 避免硬编码端口类型,改用参数化接口(如`uvm_tlm_generic_payload`)。 - **错误注入与恢复**:在序列中随机插入错误事务(如CRC错误),验证DUT的鲁棒性。结合断言(SVA)实时监控事务状态。 - **性能优化**: - 限制事务数量:使用`uvm_tlm_fifo`设置深度阈值,防止仿真过载。 - 异步通信:对高吞吐场景,优先选择`uvm_tlm_nonblocking_port`,减少仿真等待。 - **资源推荐**:参考《UVM实战》书籍,它提供了TLM验证的实战案例,包括事务建模和调试技巧,帮助从入门到精通[^1]。 #### 4. **常见问题与解决方案** - **问题:事务丢失或不匹配** 解决方案:检查端口连接(如`connect_phase`),确保发送/接收组件正确绑定;使用记分板比较事务源和目的数据[^2]。 - **问题:测试类找不到(如引用[4]中的错误)** 解决方案:确认`run_test()`中测试类名拼写正确,并在工厂注册(`uvm_component_utils`)。 - **问题:仿真效率低** 解决方案:优化事务生成算法(如避免全随机),使用TLM的non-blocking模式减少事件调度[^3]。 #### 总结 UVM TLM验证的核心在于事务抽象和模块化设计,通过覆盖率驱动和错误注入确保通信可靠性。遵循最佳实践(如重用组件和性能优化)能显著提升验证效率。推荐结合《UVM实战》中的案例进行实践,以深化理解[^1]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值