目录

TLM 2.0 通信

端口定义

传送数据

时间标记

同步通信元件

uvm_event

uvm_event

总结

uvm_barrier

uvm_callback


TLM 2.0 通信

TLM 2.0是System C模型之间的核心传输方式,通常情况下我们都用TLM 1通信,但当遇到模型是使用System C编写的时,UVM要将System C模型继承到验证环境里做reference model的时候会用到TLM 2.0通信

端口定义

与TLM 1.0相比,TLM 2.0提供更加强大的传输特性,主要包括:① 双向的阻塞或者非阻塞接口;(TLM 1.0也有) ② 时间标记; (从一个组件到另一个组件到底花了多长数据传输)③ 统一的数据包。通过这些特性,TLM 2.0使得接口之间的通信趋于标准化,更容易为系统构建抽象模型。

在定义TLM 2.0的过程中,仍然有initiator和target的概念,也有port、export以及imp端口类型。对于port类型,它是用来发起请求并调用target一端的传输方法;export用来传导这一需求;最后由imp端口所在组件来实现数据传输方法。

为了区别于TLM 1.0对于端口类型的称谓,UVM将TLM 2.0端口类型称之为socket。它们是由port、export和imp组合而成的。一个socket是双向传输的。socket则按照blocking 和 unblocking的传输方式,组合initiator或者target的发起端区别,可以分为:

uvm_tlm_b_initiator_socket                 //blocking
uvm_tlm_b_target_socket
uvm_tlm_nb_initiator_socket                //unblocking
uvm_tlm_nb_target_socket
uvm_tlm_b_passthrough_initiator_socket
uvm_tlm_b_passthrough_target_socket
uvm_tlm_nb_passthrough_initiator_socket
uvm_tlm_nb_passthrough_target_socket

socket类型都继承与uvm_port_base,具有同TLM 1.0端口一样的基础函数,而在这些socket内部,它们是通过例化port、export以及imp最终实现数据双向传输的。匹配的方法不再是put()、get()、peek()而是变成了b_transport()、nb_transport_fw()和nb_transport_bw()。

socket通过内置这些端口,就可以实现了数据的双向传输。

传送数据

TLM 1.0中传输的数据类型是用户自定义的,这就会产生一些限制,如果端口传输数据类型不同,则端口无法连接,针对传输不同数据类型的TLM端口,相应的传送方法也要做出调整。

TLM 2.0对传送数据的类型提出了一致性的要求,统一的数据类型由uvm_tlm_generic_payload 表示,即传输方法中使用的数据类型都应该为 uvm_tlm_generic_payload。

TLM 2.0标准制定的背景就是为了解决总线级别的抽象问题,所以它的统一数据格式也是按照总线数据的内容来定义的。

        bit [63:0] m_address:数据的读写地址。14.28

        uvm_tlm_command_e m_command:数据的读写命令。

  byte unsigned data[]:写入的数据或者读出的数据,由byte unsigned类型构成动态数组。

    int unsigned length:data数组的长度。

uvm_tlm_response_status_e m_response_status:由target返回的状态值,表示数据传输是否完成和有效。

  byte unsigned m_byte_enable[]:用来标记写入数据的有效性,标记哪个byte应该写入。

  int unsigned m_byte_enable_length:该数值应该等于m_byte_enable数组的容量值。

    m_stream_width:用来表示连续传输时的数据传输长度。

uvm_tlm_extension_base m_extensions[uvm_tlm_extension_base]:如果一些数据不在上面的部分,那么可以在这个数据延伸域中添加。

时间标记

不同的时间标记间隔是System C可以构建不同时间精度模型的重要手段。

在TLM 2.0传输中,由于可以标定延时时间,使得target端可以模拟延迟,并且在准确的延迟时刻做出响应。为了便于标记延迟时间,譬如1.1ns(SV和Verilog一样,只能使用整数的延迟方式),UVM新建了一个时间类uvm_tlm_time。这个时间类使得用户可以随时设置它的时间单位,也解决了不同模块或数据包之间出现的不同时间单位和精度单位的问题。

class comp1 extends uvm_component'uvm_tlm_b_initiator_socket b_ini_skt;`uvm_component_utils(comp1)...task run_phase(uvm_phase phase);byte unsigned data[] = {1, 2, 3, 4, 5, 6, 7, 8};uvm_tlm_generic_payload pl = new("pl");uvm_tlm_time delay = new("delay");pl.set_address('h0000F000);pl.set_data_length(8);pl.set_data(data);pl.set_byte_enable_length(8);delay.incr(0.3ns, 1ps);`uvm_info("INITRSP", $sformatf("initiated a trans at %0d ps", $realtime()), UVM_LOW)b_ini_skt.b_transport(pl, delay);endtask
endclassclass comp2 extends uvm_component;uvm_tlm_b_target_socket #(comp2) b_tgt_skt;`uvm_component_utils(comp2)...task b_transport(uvm_tlm_generic_payload pl, uvm_tlm_time delay);`uvm_info("TGTTRSP", $sformatf("received a trans at %0d ps", $realtime()), UVM_LOW)pl.print();#(delay.get_realtime(1ps));pl.set_response_status(UVM_TLM_OK_RESPONSE);`uvm_info("TGTTRSP", $sformatf("completed a trans at %0d ps", $realtime()), UVM_LOW)pl.print();endtask
endclassclass env1 extends uvm_env;comp1 c1;comp2 c2;`uvm_component_utils(env1)...function void build_phase(uvm_phase phase);super.build_phase(phase);c1 = comp1::type_id::create("c1", this);c2 = comp2::type_id::create("c2", this);endfunction: build_phasefunction void connect_phase(uvm_phase phase);super.connect_phase(phase);c1.b_ini_skt.connect(c2.b_tgt_skt);endfunction: connect_phase
endclass

上面的代码定义了两个component类型,一个从从comp1一个comp2,以及调用它们的顶层env1。可以看到,我们通过“uvm_tlm_b_initiator_socket”在comp1中定义了一个initiator,自然的我们就需要在comp2中定义一个target类型的端口和它对应“uvm_tlm_b_target_socket”,TLM端口用的都是socket类型。

同步通信元件

SV中用来做线程同步的几种元件为:event、semaphore和mailbox。在UVM中,需要同步线程不仅仅在同一个对象中,还需要解决不同组件之间的线程同步问题。

UVM为了解决封闭性的问题,定义了如下的类来满足组件之间的同步要求:

※ uvm_event, uvm_event_pool和uvm_event_callback

※ uvm_barrier, uvm_barrier_pool

上面的两组类分别用于两个组件之间的同步多个组件之间的同步

uvm_event

uvm_event

不同组件可以共享同一个uvm_event,这不需要通过跨层次传递uvm_event对象句柄来实现共享,该共享方式是通过uvm_event_pool这一全局资源池来实现的。uvm_event_pool是uvm_object_string_pool #(T) 的子类,它可以生成和获取通过字符串索引的uvm_event对象。

通过全局资源池uvm_event_pool(唯一的),环境中的任何组件都可以从资源池获取共享的对象句柄,这就避免了组件之间的互相依赖(跨层次通信)。

下面来看一个结合了uvm_event、uvm_event_pool和回调函数的代码:

class edata extends uvm_object;int data;`uvm_object_utils(edata)...
endclassclass ecb extends uvm_event_callback;`uvm_object_utils(ecb)...//在uvm_event 被trigger之前,希望做什么事情,可以传入参数,可以通过pre_trigger中的data传入,trigger一些datafunction bit pre_trigger(uvm_event e, uvm_object data = null);`uvm_info("EPRETRIG", $sformatf("before trigger event %s", e.get_name()), UVM_LOW)return 0;endfunction//在uvm_event 被trigger之后,希望做什么事情,可以传入参数,可以通过post_trigger中的data传入,trigger一些datafunction void post_trigger(uvm_event e, uvm_object data = null);`uvm_info("EPOSTRIG", $sformatf("after trigger event %s", e.get_name()), UVM_LOW)endfunction
endclassclass comp1 extends uvm_component;uvm_event e1;`uvm_component_utils(comp1)...function void build_phase(uvm_phase phase)super.build_phase(phase);//通过全局的event_pool中搜索是否有名为e1的uvm_event,如果event_pool中有e1,则拿到e1,否则会自动创建一个名为e1的uvm_evente1 = uvm_event_pool::get_global("e1");  endfunctiontask run_phase(uvm_phase phase);edata d = new();ecb cb = new();d.data = 100;#10ns;e1.add_callback(cb); //创建了一个callback对象,要和event link在一起,通过add_callback函数。e1.trigger(d);       //event关联了callback函数之后,只要event被trigger了,就会自动调用回调函数。`uvm_info("ETRIG", $sformatf("trigger sync event at %t ps", $time), UVM_LOW)endtask
endclassclass comp2 extends uvm_component;uvm_event e1;`uvm_component_utils(comp2)...function void build_phase(uvm_phase phase);super.build_phase(phase);e1 = uvm_event_pool::get_global("e1");endfunctiontask run_phase(uvm_phase phase);uvm_object tmp;edata d;`uvm_info("ESYNC", $sformatf("wait sync event at %t ps", $time), UVM_LOW)e1.wait_trigger_data(tmp);  //等待trigger的到来,同时还要等待trigger送data进来。void'($cast(d,tmp));        //tmp数据是uvm_object类型,edata是继承于uvm_object的类型,父类和子类之间的转化使用cast函数。`uvm_info("ESYNC", $sformatf("get data %0d after sync at %t ps", d.data, $time), UVM_LOW)endtask
endclass
class env1 extends uvm_env;comp1 c1;             //先实例化c1,也即先调用c1的build_phase,在uvm_event_pool中创建了一个名为e1的eventcomp2 c2;             //c2在执行build_phase的过程中,是拿到了一个e1的句柄,c1和c2自始至终都是对同一个event(e1)做处理`uvm_component_utils(env1)...
endclass

代码输出结果:

该段代码中,组件c1和c2之间完成了从c1到c2的同步,而且在同步过程中通过uvm_event e1传递了数据edata,并且调用了回调函数类ecb的pre_trigger()和post_trigger()方法。pre_trigger()和post_trigger()是uvm_event_callback自带的回调函数。event在将要被trigger时,被trigger之前会执行pre_trigger(),在被trigger之后会执行post_trigger。

pre_trigger有返回值,如果返回值为1,则表示uvm_event不会被trigger,也就不会再执行post_trigger,如果返回值为0,则会继续triiger该事件对象。


总结

uvm_event类与event相比,有一定的区别:

① event被->触发之后,会触发使用@等待该事件的对象;uvm_event通过trigger()来触发,会触发使用wait_trigger()等待该事件的对象。

② 如果要再次等待事件触发,event只需要再次用->来触发,而uvm_event需要先通过reset()方法重置初始状态,再使用trigger()来触发

③ event无法携带更多的信息,而uvm_event可以通过trigger(T data = null)的可选参数,将伴随触发的数据对象都写入到该触发事件中,而等待该事件的对象可以通过方法wait_trigger_data(output T data)来获取事件触发时写入的数据对象。

④ event触发时无法直接触发回调函数,而uvm_event可以通过add_callback(uvm_event_callback cb,  bit append = 1)函数来添加回调函数。

⑤ event无法直接获取等待它的进程数目,而uvm_event可以通过get_num_waiters()来获取等待它的进程数目

uvm_event解决了一个重要问题,那就是在一些uvm_objectuvm_component对象之间如果要发生同步,但是无法通过TLM完成数据传输,因为TLM传输必须是在组件和组件之间进行的。如果要在sequence与sequence之间进行同步,或者sequence与driver之间进行同步,就可以借助uvm_event来实现。


uvm_barrier

UVM提供了一个新的类uvm_barrier来对多个组件进行同步协调, 同时为了解决组件独立运作的封闭性需要,也定义了新的类uvm_barrier_pool来全局管理这些uvm_barrier对象。uvm_barrier_pool同之前的uvm_event_pool一样,也是基于通用参数类uvm_object_string_pool来定义的。

uvm_barrier可以设置一定的等待阈值(threshold),当有不少于该阈值的进程在等待对象时,才会触发该事件,同时激活所有正在等待的进程,使其可以继续进行。

class comp1 extends uvm_component;uvm_barrier b1;`uvm_component_utils(comp1)...function void build_phase(uvm_phase phase);super.build_phase(phase);b1 = uvm_barrier_pool::get_global("b1");endfunctiontask run_phase(uvm_phase phase);#10 ns;`uvm_info("BSYNC", $sformatf("c1 wait for b1 at %0t ps", $time), UVM_LOW)b1.wait_for();`uvm_info("BSYNC", $sformatf("c1 is activated at %0t ps", $time), UVM_LOW)endtask
endclass
class comp2 extends uvm_component;uvm_barrier b1;`uvm_component_utils(comp2)...function void build_phase(uvm_phase phase);super.build_phase(phase);b1 = uvm_barrer_pool::get_global("b1");endfunctiontask run_phase(uvm_phase phase);#20 ns;  //比comp1慢进行wait_for()`uvm_info("BSYNC", $sformatf("c2 wait for b1 at %0t ps", $time), UVM_LOW)b1.wait_for();`uvm_info("BSYNC", $sformatf("c2 is activated at %0t ps", $time), UVM_LOW)endtask
endclassclass env1 extends uvm_env;comp1 c1;comp2 c2;uvm_barrier b1;`uvm_component_utils(env1)...function void build_phase(uvm_phase phase);super.build_phase(pase);c1 = comp1::type_id::create("c1", this);c2 = comp2::type_id::create("c2", this);b1 = uvm_barrier_pool::get_global("b1");endfunction:build_phasetask run_phase(uvm_phase phase);b1.set_threshold(3);`uvm_info("BSYNC", $sformatf("env set b1 threshold %d at %0t ps", b1.get_threshold(), $time), UVM_LOW)#50 ns;b1.set_threshold(2);`uvm_info("BSYNC", $sformatf("env set b1 threshold %d at %0t ps", b1.get_threshold(), $time), UVM_LOW)endtask
endclass

代码输出结果:

从这段代码中可以看到,c1和c2的run_phase任务之间需要同步,而同步它们的元件则是来自于顶层的一个uvm_barrier b1。

c1、c2和env1都共享该对象,这使得c1和c2可以通过wait_for()来等待激活,而env1可以设置阈值来调控什么时间来“开阀”。

在一开始的时候,阈值设置为3,但由于等待该barrier的进程只有2个,无法达到阈值条件,使得两个进程都无法激活。在env1将b1的阈值设置为2时,等待该barrier的两个进程都被激活。通过uvm_barrier::set_threshold()和uvm_barrier::wait_for()这样的方式,可以实现多个组件之间的同步,同时可以保持各个组件之间的独立性。


uvm_callback

通常情况下得到了一个封闭的包(pkg),其中的类如果有些成员方法需要修改,或者需要扩展新的方法时,应该怎么做呢?如果这个包是外来的,那么维护方法不建议去修改这个类本身。callback方法可以为用户提供自定义的处理方法。

uvm_object本身提供了一些callback方法供用户定义:

copy()  <=  do_copy()

print()   <=  do_print()

compare() <= do_compare()

pack() <= do_pack()

默认情况下,这些回调函数do_xxx是定义为空的。如果用户执行了uvm_object::copy()函数,那么在该函数执行末尾会自动执行uvm_object::do_copy()。UVM是通过两个相关类uvm_callback_iteruvm_callbacks #(T,CB)来实现函数回调的顺序和继承性的。

class edata extends uvm_object;int data;`uvm_object_utils(edata)...
endclass
class cb1 extends uvm_callback;`uvm_object_utils(cb1)...virtual function void do_trans(edata d);d.data = 200;`uvm_info("CB", $sformatf("cb1 executed with data %0d", d.data), UVM_LOW)endfunction
endclassclass cb2 extends cb1;`uvm_object_utils(cb2)...function void do_trans(edata d);d.data = 300;`uvm_info("CB", $sformatf("cb2 executed with data %0d", d.data), UVM_LOW)endfunction
endclass
class comp1 extends uvm_component;`uvm_component_utils(comp1)`uvm_register_cb(comp1, cb1)    //如果要将component同callback作关联,需要对其进行注册,使用uvm_register_cb...task run_phase(uvm_phase phase);edata d = new();d.data = 100;`uvm_info("RUN", $sformatf("proceeding data %0d", d.data), UVM_LOW)`uvm_do_callbacks(comp1, cb1, do_trans(d)); //在comp1中调用cb1类的do_trans函数endtask
endclassclass env1 extends uvm_env;comp1 c1;cb1 m_cb1;cb2 m_cb2;`uvm_component_utils(env1)function new(string name, uvm_component parent);super.new(name, parent);m_cb1 = new("m_cb1");m_cb2 = new("m_cb2");endfunctionfunction void build_phase(uvm_phase phase);super.build_phase(phase);c1 = comp1::type_id::create("c1", this);uvm_callbacks #(comp1)::add(c1, m_cb1);  //添加callbackuvm_callbacks #(comp1)::add(c1, m_cb2);endfunction: build_phase
endclass

 输出结果:

为了保证调用uvm_callback的组件类型T与uvm_callback类型CB保持匹配,建议使用宏`uvm_register_cb(T, CB)来进行绑定。

如果要将component同callback作关联,需要对其进行注册,使用uvm_register_cbcallback类和component作绑定,绑定后可以通过在build_phase中使用uvm_callbacks #(comp1)::add(c1, m_cb1) 添加callback。使用uvm_register_cb之后,如果调用的T与CB不匹配,那么在检查完匹配注册表之后系统会打印warning信息,提示用户使用回调函数的潜在问题。

此外,宏`uvm_do_callbacks_exit_on(T, CB, METHOD, VAL)可以进一步控制执行回调函数的层次,简单来讲,回调函数会保持执行直到返回值与给如的VAL值相同才会返回,譬如说我们给一个component绑定了三个回调函数,顺序执行,假设执行到第二个回调函数的时候返回值和VAL值相同,那么就直接返回而不会执行第三个回调函数。这点使得回调函数方法在执行顺序上面有了更多的可控性。

callback函数使用总结:

首先定义一个回调函数继承于uvm_callback,并在其中定义function;然后使用`uvm_register_cb(T, CB)和`uvm_do_callbacks(comp1, cb1, do_trans())绑定及插入callback函数;在顶层把组件和callback都作例化,然后将 uvm_callbacks #(comp1)::add(c1, m_cb2); 把回调函数添加到组件中,形成一个组件-callback对子。

UVM基础-TLM通信机制(二)相关推荐

  1. UVM基础-TLM通信机制(一)

    目录 基本概念 TLM通信分类 单向通信 单向通信举例 单向通信代码 双向通信 多向通信 多向通信总结 通信管道 TLM FIFO Analysis Port Analysis TLM FIFO 芯片 ...

  2. 【UVM基础】CallBack机制快速上手指南

    文章目录 一.Callback机制的作用 二.回调函数callback的使用步骤: 三.代码code应用实例 3.1.声明一个UVM callback空壳类 3.2.在组件中的主操作函数或任务之前或者 ...

  3. ROS通信机制(二) —— 服务(service)与srv文件

    文章目录 简述 特点 相关常用命令 通信模型 核心元素 通信过程 代码示例(服务端和客户端) 服务端(server.cpp) 客户端(client.cpp) 配置 CMakeLists.txt 编译和 ...

  4. UVM基础-Seq-Sqr-Driver交互详解

    一.Sequence机制的使用方法 1.1 seq.sqr与driver 熟悉UVM的朋友都知道,在一个基于UVM搭建的验证环境中,Sequence负责产生环境所需的数据包:Transaction,而 ...

  5. UVM-TLM通信机制(四)

    UVM-TLM通信机制 一.两对象与三端口 1.1.两个通信对象:initiator.target 1.2.三个通信端口:port.export.imp 二.一对一传输 2.1.单向传输--put( ...

  6. 理解同步和异步通信:以ROS的3中典型通信机制为例

    文章目录 一.ROS中的几种通信机制 二.不同通信机制的特点 2.1 话题消息通信 2.2 服务消息通信 2.3 动作消息通信 3. 同步和异步 一.ROS中的几种通信机制 在ROS中,不同的进程可以 ...

  7. uvm基础(2)TLM通信,看这一篇就够了

    tlm通信概述 tlm通信的步骤:1.分辨出initiator和target,producer和consumer. 2.在target中实现tlm通信方法. 3.在俩个对象中创建tlm端口. 4.在更 ...

  8. UVM重点归纳(二)之TLM通信

    1 概念 initiator:发起通信请求的对象: target:接收通信请求的对象: producer:数据开始产生的对象: consumer:数据最终流向的对象: initiator和target ...

  9. Chapter2 ROS通信机制----基础篇(Ⅰ)vs配置及通信基础

    目录 一.复习及launch 1.1 深入理解配置信息(非常重要) 1.2 launch文件演示 二.ROS通信机制-----基础 2.1 本节导论 2.2 话题通信 2.2.1 话题通信概述 2.2 ...

最新文章

  1. 关于回答「对极几何与基本矩阵」的几点感悟
  2. iPhone开发环境搭建For PC
  3. 一名不加班的运维,怎能不会善待混合云容器
  4. python的dataframe的groupby_python pandas.DataFrame.groupby()方法详解
  5. 大三下,第一次前端面试经历
  6. 用pandas对分类变量作统计
  7. vivo oppo 相机权限处理
  8. win10无线断开无法连接服务器,win10wifi自动断开什么原因_win10wifi自动断开且无法连接如何解决...
  9. python数据挖掘项目——航空公司客户价值分析(详解)
  10. 使用OpenOffic在线转换文档错误
  11. lighttpd支持AJAX吗,lighttpd配置https
  12. 广州润衡网吧装饰,很牛的网吧装饰
  13. 国货崛起,科技潮流——雷神星驰轮胎
  14. 2020-09-27程序设计基础知识
  15. Windows下机器视觉YOLOv5+arduino单片机玩转创客小物件
  16. jQuery+html5音乐网站mp3播放器代码
  17. Pinia全新一代状态管理工具Pinia-Vue3全家桶
  18. Spark 安装配置及下载地址
  19. 查找素材终极神器,视频片段查找神器!
  20. (3.6)Case用法

热门文章

  1. 4.2 基础数据模型
  2. 40本编程开发电子书免费送
  3. vue config.js详解——vue config.js到底是什么,有什么作用?
  4. ruyistdio IDE caffemodel 转.wk
  5. CT图像密度分辨力和空间分辨力的区别和联系
  6. 爬取知乎神回复 | 上次笑死人,这次继续笑~
  7. 初识go-micro
  8. 35岁以后不建议裸辞
  9. 6.22 Java练习(根据输入的值计算BMI的值,根据标准判断BMI的值并给出相应健康提示。)
  10. 【Spring入门】