【UVM入门笔记(三)】TLM通信

一、TLM通信概述
  1. 系统原型阶段和芯片验证阶段均使用了TLM通信方式。前者为了更快地实现硬件原型之间的数据通信,后者为了更快地实现验证组件之间的数据通信。
  2. TLM是一种提高数据传输抽象级的标准,可以用来表示宽松时间跨度内的硬件通信数据。通过将低颗粒硬件周期内的数据打包成一个大数据,可以有效地提升整体环境的仿真速度。
  3. 基本概念
    1)两个通信对象:initial(发起通信请求的一方)和target(发起通信的响应方)。
    2)按照transaction的流向区分两个对象:producer(数据产生一方)和consumer(数据流向方)。
    initialtarget的关系同producerconsumer的关系是不固定的。
  4. TLM通信步骤
    1)在两个对象中创建TLM端口
    2)在target中实现TLM通信方法
    3)在更高的层次中将两个对象的端口进行连接
  5. 分类
    ①按照端口类型:
    1)port:作为initiator的发起端
    2)export:作为initialtarget中间层次的端口
    3)imp:只能作为target接收request的末端,无法再次延伸。
    ②按照数据流向
    1)单向传输
    2)双向传输
    👉数据流向和端口类型加以组合,TLM端口共可以分为六类。
uvm_UNDIR_port #(trans_t)
uvm_UNDIR_export #(trans_t)
uvm_UNDIR_imp #(trans_t, imp_parent_t)  // 不仅需指定transaction类型,还需指定所在component类型。
uvm_BIDIR_port #(req_trans_t, rsp_trans_t)
uvm_BIDIR_export #(req_trans_t, rsp_trans_t)
uvm_BIDIR_imp #(req_trans_t, rsp_trans_t, imp_parent_t)
  1. 端口使用注意问题
    1)多个port可以连接到同一个export或者imp,但是单个port或者export无法连接多个imp。
    2)port可以连接port、export或者imp;export可以连接export或者imp;imp只能作为数据传送的终点,无法扩展连接。
二、单向通信

在这里插入图片描述

  • 阻塞传输方式(blocking前缀)对应方法类型为task;非阻塞传输方式(nonblocking前缀)对应方法类型为function。
  • peek同get的区别在于peek只是没把原数据移除。
  • try_xxx()方法和can_xxx()方法的区别在于can_xxx()函数先试探target是否可以接收数据,如果可以,再通过try_xxx()函数发送,提高数据发送的成功率。
//example
class comp1 extends uvm_component;
  uvm_blocking_put_port #(itrans) bp_port;
  uvm_nonblocking_get_port #(otrans) nbg_port;
  ...
  // inside run phase
  this.bp_port.put(xx);
  ...
  if(this.nbg_port.try_get(xx)==1) ...;
  ...
endclass
class comp2 extends uvm_component;
  uvm_blocking_put_imp #(itrans, comp2) bp_imp;
  uvm_nonblocking_get_imp #(otrans, comp2) nbg_imp;
  ...
  task put(itrans t);
  ...
  endtask
  function bit try_get(output otrans t);
  ...
  endfunction
endclass

class env1 extends uvm_env;
  comp1 c1;
  comp2 c2;
  ...
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    c1.bp_port.connect(c2.bp_imp);
    c1.nbg_port.connect(c2.nbg_imp);   //左侧initiator, 右侧target
  endfunction: connect_phase
endclass
三、双向通信
  • 双向通信中的两端同时扮演着producer和consumer的角色,而initiator作为request发起方,在发起request之后,还会等待response返回。
    在这里插入图片描述
四、多向通信
  • 多向通信仍然是两个组件之间的通信,是针对initiator与target之间相同TLM端口数目超过一个时的处理解决办法。
  • 通过端口宏声明方式解决。eg. `uvm_blocking_put_imp_decl(SFX)
`uvm_blocking_put_imp_decl(_p1)
`uvm_blocking_put_imp_dec1(_p2)
class comp1 extends uvm_component;  //组件1不受任何影响,目前并不知道最后连接到哪里
  uvm_blocking_put_port #(itrans) bp_port1;
  uvm_blocking_put_port #(itrans) bp_port2;
  ...
  // inside run_phase
  this.bp_port1.put(xx);
  ...
  this.bp_port2.put(xx);
endclass
class comp2 extends uvm_component;
  uvm_blocking_put_imp_p1 #(itrans, comp2) bt_imp_p1;
  uvm_blocking_put_imp_p1 #(itrans, comp2) bt_imp_p2;
  semaphore key;   //对于共享资源,做互斥访问的保护
  ...
  task put_p1(itrans t);
    key.get();
    ...
  endtask
  task put_p2(itrans t);
    key.get();
    ...
  endtask
endclass
class env1 extends uvm_env;
  comp1 c1;
  comp2 c2;
  ...
  function void connect_phase(uvm_phase phase);
    super.connect_phase(phase);
    c1.bp_port1.connect(c2.bt_imp_p1);
    c1.bp_port2.connect(c2.bt_imp_p2);
  endfunction: connect_phase
endclass
五、管道通信

👉解决问题:1)不自己实现target一端需要实现的传输方法;2)解决一端到多端的传输

  1. TLM_FIFO
    多数情况下,需要实现的传输方法都是相似的,方法的主要内容即是为了实现一个数据缓存功能。TLM FIFO uvm_tlm_fifo类是一个新组件,继承于uvm_component类,而且已经预先内置了多个端口以及实现了多个对应方法供用户使用。
    在这里插入图片描述
  2. Analysis Port
    1)针对一个initiator端到多个target端的方式;需要调用的是write()函数来实现数据传输。
    2)类似于其它TLM端口,按照传输方法和端口方向组合可以将analysis port分为uvm_analysis_portuvm_analysis_export以及uvm_analysis_imp
    3)在initiator端调用write()函数时,实际上通过循环的方式将所有连接的target端内置的write()函数进行了调用。
  3. Analysis TLM FIFO
    uvm_tlm_analysis_fifo类继承于uvm_tlm_fifo,这表明它本身具有面向单一TLM端口的数据缓存特性,而同时该类又有一个uvm_analysis_imp端口analysis_export并实现了write()函数。
    注意,虽然名为export但实际上是imp类型的端口,并且下图中的target端的端口类型变成了port类型,整体的数据流向与原来的是相同的。
    在这里插入图片描述
  4. 双向通信管道
    1)uvm_tlm_req_rsp_channel
    在这里插入图片描述2)uvm_tlm_transport_channel
    uvm_tlm_req_rsp_channel继承于uvm_tlm_req_rsp_channel
    在这里插入图片描述
六、TLM2通信
  • TLM2强大的传输特性包括: 1)双向的阻塞或者非阻塞接口;2)时间标记;3)统一的数据包。
  • 为了区别与TLM1对于端口类型的称谓,UVM将TLM2.0端口类型称为socket。
七、同步通信元件
  1. uvm_event
    1)不同组件可以共享同一个uvm_event,不需要通过跨层次传递uvm_event对象句柄来实现共享(这不符合组件环境封闭的原则),该共享方式是通过uvm_event_pool这一全局资源池来实现。
    2)如果要传递数据,用户可以定义扩展于uvm_object的数据子类,并通过uvm_event::trigger(T data=null)来传递数据对象。在等待uvm_event一侧的组件则需要通过uvm_event::wait_trigger_data(output T data)来获取该对象。
    3)用户可以扩展uvm_event_callback类,定义uvm_event被trigger前后的调用方法pre_trigger()post_trigger()pre_trigger()要有返回值,如果返回值为1,则不会继续向下执行。
    4)如果无法确定在等待事件之前,事件是否已经被trigger,那么还可通过wait_ptrigger()wait_ptrigger_data()来完成等待。
    5)组件之间的常规数据流向是通过TLM通信方法实现的。对于uvm_object和uvm_component之间或者uvm_object之间的同步可以借助uvm_event实现。

  2. uvm_barrier
    👉对多个组件进行同步协调,uvm_barrier可以设置一定的等待阈值xx.set_threshod(2),当有不少于该阈值的进程在等待该对象xx.wait_for()时才会触发该事件,同时激活所有正在等待的进程,使其可以继续进行。

  3. uvm_callback
    类的复用除了通过继承还可以通过回调函数实现。
    1)为了保证调用uvm_callback的组件类型T与uvm_callback类型CB保持匹配,可通过宏声明uvm_register_cb(T, CB)来实现。
    2)uvm_callback建立了回调函数执行的层次性,不再是在T中直接调用某个回调函数,而是通过宏uvm_do_callback(T, CB, METHOD)来声明。
    3)在执行回调方法时,依赖的是已经例化的uvm_callback对象。

class env1 extends uvm_env;
  comp1 c1;
  cb1 m_cb1;
  cb2 m_cb2;
  ...
  function void build_phase(uvm_phase phase);
    super.build_phase(phase);
    c1 = comp1::type_id::create("c1", this);
    uvm_callback #(comp1)::add(c1, m_cb1);
    uvm_callback #(comp2)::add(c1, m_cb2);
  endfunction
endclass
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值