UVM之TLM port基础

TLM port分类

  • port
  • export
  • imp

UVM TLM ports and exports are also used to send transaction objects cross different levels of testbench hierarchy.

Ports shall be used to initiate and forward packets to the top layer of the hierarchy. Exports shall be used to accept and forward packets from the top layer to destination. Implementation ports shall be used to define the put method at the target. Shown below are a few examples that use ports, exports and implementation for components at different hierarchy levels.

在这里插入图片描述

PORT互连规则

参考<uvm_port_base.svh>中的uvm_port_base中的connect函数,三种port的互联规则如下:

port连接到port

规则:只能是子port连接到父port。

Connecting port-to-port: CHILD.port.connect(PARENT.port)

port连接到export/imp

规则:port与export/imp有共同的祖父,即sibling可以是亲兄妹或者堂兄妹或者表兄妹

Connecting port-to-export: SIBLING.port.connect(SIBLING.export)
Connecting port-to-imp: SIBLING.port.connect(SIBLING.imp)

export连接到export/imp

规则:只能是父连子

Connecting export-to-export: PARENT.export.connect(CHILD.export)
Connecting export-to-imp: PARENT.export.connect(CHILD.imp)

连接方向

如上面所示,只能单向连接,不能反过来连接。

port类型

//-----------------
// Group: Port Type
//-----------------

// Enum: uvm_port_type_e
//
// Specifies the type of port
//
// UVM_PORT           - The port requires the interface that is its type
//                      parameter.
// UVM_EXPORT         - The port provides the interface that is its type
//                      parameter via a connection to some other export or
//                      implementation.
// UVM_IMPLEMENTATION - The port provides the interface that is its type
//                      parameter, and it is bound to the component that
//                      implements the interface.

typedef enum
{
  UVM_PORT ,
  UVM_EXPORT ,
  UVM_IMPLEMENTATION
} uvm_port_type_e;

常见的TLM port

uvm_analysis_port

该端口扩展子uvm_port_base,其中write函数的实现如下:

class uvm_analysis_port # (type T = int)
  extends uvm_port_base # (uvm_tlm_if_base #(T,T));

  function new (string name, uvm_component parent);
    super.new (name, parent, UVM_PORT, 0, UVM_UNBOUNDED_CONNECTIONS);
    m_if_mask = `UVM_TLM_ANALYSIS_MASK;  
  endfunction

  virtual function string get_type_name();
    return "uvm_analysis_port";
  endfunction

  // Method: write
  // Send specified value to all connected interface
  // Modified by Verdi
  function void write (input T t);
    uvm_tlm_if_base # (T, T) tif;
`ifndef UVM_VERDI_NO_PORT_RECORDING
    `UVM_IF_METHOD_BEGIN(t,"write");
`endif
    for (int i = 0; i < this.size(); i++) begin
      tif = this.get_if (i);
      if ( tif == null )
        uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE);
      tif.write (t);
    end
`ifndef UVM_VERDI_NO_PORT_RECORDING
    `UVM_IF_METHOD_END(t,"write");
`endif
  endfunction
  // End
endclass

这里的write()函数会通过遍历(this.get_if())查找出与该analysis port互联的所有的实现口。注意analysis port连接时可以是一对多的关系。比如连接关系可能包括:

  • port->port->export->export->imp
  • port->export->imp
  • port->imp

this.get_if()通过递归查找的方式找到所有imp,然后调用该实现口的write函数。我们再去看imp的write函数。

uvm_analysis_imp

// Modified by Verdi
class uvm_analysis_imp #(type T=int, type IMP=int)
  extends uvm_port_base #(uvm_tlm_if_base #(T,T));
  `UVM_IMP_COMMON(`UVM_TLM_ANALYSIS_MASK,"uvm_analysis_imp",IMP)
  function void write (input T t);
`ifndef UVM_VERDI_NO_PORT_RECORDING
    `UVM_IF_METHOD_BEGIN(t,"write");
`endif
    m_imp.write (t);
`ifndef UVM_VERDI_NO_PORT_RECORDING
    `UVM_IF_METHOD_END(t,"write");
`endif
  endfunction
endclass
// End

该参数化类的第二个参数是该imp例化时所在的uvm_componentcomponent type。比如该实现口例化在类aes_rm中,那么IMP=aes_rm。注意该write()函数的实现在IMP中,即示例aes_rm中。

uvm_analysis_export

//------------------------------------------------------------------------------
// Class: uvm_analysis_export
//
// Exports a lower-level <uvm_analysis_imp> to its parent.
//------------------------------------------------------------------------------

class uvm_analysis_export #(type T=int)
  extends uvm_port_base #(uvm_tlm_if_base #(T,T));

  // Function: new
  // Instantiate the export.
  function new (string name, uvm_component parent = null);
    super.new (name, parent, UVM_EXPORT, 1, UVM_UNBOUNDED_CONNECTIONS);
    m_if_mask = `UVM_TLM_ANALYSIS_MASK;
  endfunction

  virtual function string get_type_name();
    return "uvm_analysis_export";
  endfunction
  
  // analysis port differs from other ports in that it broadcasts
  // to all connected interfaces. Ports only send to the interface
  // at the index specified in a call to set_if (0 by default).
  // Modified by Verdi
  function void write (input T t);
    uvm_tlm_if_base #(T, T) tif;
`ifndef UVM_VERDI_NO_PORT_RECORDING
    `UVM_IF_METHOD_BEGIN(t,"write");
`endif
    for (int i = 0; i < this.size(); i++) begin
      tif = this.get_if (i);
      if (tif == null)
         uvm_report_fatal ("NTCONN", {"No uvm_tlm interface is connected to ", get_full_name(), " for executing write()"}, UVM_NONE);
      tif.write (t);
    end
`ifndef UVM_VERDI_NO_PORT_RECORDING
    `UVM_IF_METHOD_END(t,"write");
`endif
  endfunction
  // End
endclass

write()函数很类似uvm_analysis_portwrite()函数,不同之处:

  • port type不一样,一个是UVM_PORT,一个是UVM_EXPORT

二者的m_if_mask都是UVM_TLM_ANALYSIS_MASK,连接的port数量均不受限制(UVM_UNBOUNDED_CONNECTIONS

uvm_tlm_fifo_base

该类为TLM FIFO类的基类,扩展自uvm_component,定义了两个端口put_export和get_peek_export用于存取transaction。

  // Port: put_export
  //
  // The ~put_export~ provides both the blocking and non-blocking put interface
  // methods to any attached port:
  //
  //|  task put (input T t)
  //|  function bit can_put ()
  //|  function bit try_put (input T t)
  //
  // Any ~put~ port variant can connect and send transactions to the FIFO via this
  // export, provided the transaction types match. See <uvm_tlm_if_base #(T1,T2)>
  // for more information on each of the above interface methods.

  uvm_put_imp #(T, this_type) put_export;
  

  // Port: get_peek_export
  //
  // The ~get_peek_export~ provides all the blocking and non-blocking get and peek
  // interface methods:
  //
  //|  task get (output T t)
  //|  function bit can_get ()
  //|  function bit try_get (output T t)
  //|  task peek (output T t)
  //|  function bit can_peek ()
  //|  function bit try_peek (output T t)
  //
  // Any ~get~ or ~peek~ port variant can connect to and retrieve transactions from
  // the FIFO via this export, provided the transaction types match. See
  // <uvm_tlm_if_base #(T1,T2)> for more information on each of the above interface
  // methods.

  uvm_get_peek_imp #(T, this_type) get_peek_export;  

该类的new()函数实例化了所有的端口:

  // 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);
    super.new(name, parent);

    put_export = new("put_export", this);
    blocking_put_export     = put_export;
    nonblocking_put_export  = put_export;

    get_peek_export = new("get_peek_export", this);
    blocking_get_peek_export    = get_peek_export;
    nonblocking_get_peek_export = get_peek_export;
    blocking_get_export         = get_peek_export;
    nonblocking_get_export      = get_peek_export;
    get_export                  = get_peek_export;
    blocking_peek_export        = get_peek_export;
    nonblocking_peek_export     = get_peek_export;
    peek_export                 = get_peek_export;

    put_ap = new("put_ap", this);
    get_ap = new("get_ap", this);
    
  endfunction

uvm_tlm_fifo

该类扩展自uvm_tlm_fifo_base,其详细功能描述如下:

//------------------------------------------------------------------------------
//
// Class: uvm_tlm_fifo#(T)
//
// This class provides storage of transactions between two independently running
// processes. Transactions are put into the FIFO via the ~put_export~. 
// transactions are fetched from the FIFO in the order they arrived via the
// ~get_peek_export~. The ~put_export~ and ~get_peek_export~ are inherited from
// the <uvm_tlm_fifo_base #(T)> super class, and the interface methods provided by
// these exports are defined by the <uvm_tlm_if_base #(T1,T2)> class.
//
//------------------------------------------------------------------------------

以上描述中规定了该FIFO的输入输出端口的连接,即:

  • 通过put_export压入transaction
  • 通过get_peek_export获取transaction

该类中定义了一个mailbox,用于存储transaction。

local mailbox #( T ) m;

邮箱中存取transaction的实现如下:

  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

调用的port是put_apget_ap

uvm_tlm_analysis_fifo

该类扩展自uvm_tlm_fifo,内部定义了一个新的export,如下:

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)); // unbounded => must succeed
  endfunction

endclass

其中write()函数中的try_put()来自其父类uvm_tlm_fifo,其实现如下:

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

try_put()除了将t压入邮箱m外,还将其推入put_ap(uvm_analysis_port类型),其作用是如果有外部其他的port和put_ap互联,则t同时传递到外部互联的端口去。try_get()函数也是类似的实现:

  virtual function bit try_get( output T t );
    if( !m.try_get( t ) ) begin
      return 0;
    end

    get_ap.write( t );
    return 1;
  endfunction 

其中get_ap的定义在uvm_tlm_fifo_base中:

  uvm_analysis_port #(T) get_ap;

应用实例

sequencer和driver的互联

driver中通过port seq_item_port获取sequencer发出的transaction,其定义如下:

  // Port: seq_item_port
  //
  // Derived driver classes should use this port to request items from the
  // sequencer. They may also use it to send responses back.

  uvm_seq_item_pull_port #(REQ, RSP) seq_item_port;

与其互联的sequencer中的port为seq_item_export,其定义如下:

  // Variable: seq_item_export
  //
  // This export provides access to this sequencer's implementation of the
  // sequencer interface.
  //

  uvm_seq_item_pull_imp #(REQ, RSP, this_type) seq_item_export;

在顶层agent中的互联如下:

drv.seq_item_port.connect(sqr.seq_item_export);

monior中的port

定义:

uvm_analysis_port #(my_transaction) analysis_port;  //TLM analysis port

使用:

analysis_port.write(tr);

rm中的port

port定义:

uvm_blocking_get_peek_port#(my_in_transaction) in_port;
uvm_blocking_put_port#(my_out_transaction) out_port;

port使用:

in_port.get(in_tr);
out_port.put(exp_tr);

env中的port

env中例化了三组FIFO(也可以不例化):

uvm_tlm_analysis_fifo#(my_in_transaction)    	mon2rm_fifo;
uvm_tlm_analysis_fifo#(my_out_transaction) 	rm2chk_fifo;
uvm_tlm_analysis_fifo#(my_out_transaction)	 	mon2chk_fifo;

互联关系如下:

iagt.mon.mon_analysis_port.connect(mon2rm_fifo.analysis_export);
rm.in_port.connect(mon2rm_fifo.blocking_get_peek_export);

rm.out_port.connect(rm2chk_fifo.blocking_put_export);
chk.rm_in_port.connect(rm2chk_fifo.blocking_get_export);

chk.mon_in_port.connect(mon2chk_fifo.blocking_get_export);
oagt.mon.mon_analysis_port.connect(mon2chk_fifo.analysis_export);

Note:根据uvm_tlm_fifo_base章节中new()函数的定义:

  • blocking_get_peek_export = get_peek_export
  • blocking_get_export = get_peek_export
  • blocking_put_export = analysis_export

checker中的port

port定义:

uvm_blocking_get_port#(my_out_transaction) rm_in_port;
uvm_blocking_get_port#(my_out_transaction) mon_in_port;

port使用:

rm_in_port.get(tr);
mon_in_port.get(tr);

使用_decl宏

引用一段uvm class reference中原话:

The TLM implemenation declaration macros provide a way for components to provide multiple implemenation ports of the same implementation interface. When an implementation port is defined using the built-in set of imps, there must be exactly one implementation of the interface.

The important thing to note is that each `uvm_imp_decl creates a new class of type uvm_imp, where suffix is the input argument to the macro. For this reason, you will typically want to put these macros in a seperate package to avoid collisions and to allow sharing of the definitions.

Summary

TLM Implementation Port Declaration Macros
The TLM implemenation declaration macros provide a way for components to provide multiple implemenation ports of the same implementation interface.
Macros	
`uvm_blocking_put_imp_decl	
`uvm_nonblocking_put_imp_decl	
`uvm_put_imp_decl	
`uvm_blocking_get_imp_decl	
`uvm_nonblocking_get_imp_decl	
`uvm_get_imp_decl	
`uvm_blocking_peek_imp_decl	
`uvm_nonblocking_peek_imp_decl	
`uvm_peek_imp_decl	
`uvm_blocking_get_peek_imp_decl	
`uvm_nonblocking_get_peek_imp_decl	
`uvm_get_peek_imp_decl	
`uvm_blocking_master_imp_decl	
`uvm_nonblocking_master_imp_decl	
`uvm_master_imp_decl	
`uvm_blocking_slave_imp_decl	
`uvm_nonblocking_slave_imp_decl	
`uvm_slave_imp_decl	
`uvm_blocking_transport_imp_decl	
`uvm_nonblocking_transport_imp_decl	
`uvm_transport_imp_decl	
`uvm_analysis_imp_decl

uvm_analysis_imp_decl为例,示例代码如下:

`uvm_analysis_imp_decl(_ingress)
`uvm_analysis_imp_decl(_egress)

class myscoreboard extends uvm_component;
  uvm_analysis_imp_ingress#(mydata, myscoreboard) ingress;
  uvm_analysis_imp_egress#(mydata, myscoreboard) egress;
  mydata ingress_list[$];
  ...

  function new(string name, uvm_component parent);
    super.new(name,parent);
    ingress = new("ingress", this);
    egress = new("egress", this);
  endfunction

  function void write_ingress(mydata t);
    ingress_list.push_back(t);
  endfunction

  function void write_egress(mydata t);
    find_match_in_ingress_list(t);
  endfunction

  function void find_match_in_ingress_list(mydata t);
    //implement scoreboarding for this particular dut
    ...
  endfunction
endclass

参考资料1: https://www.chipverify.com/uvm/tlm-preface
参考资料2:https://www.accellera.org/downloads/standards/uvm

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sunvally

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值