UVM--TLM2.0通信

TLM2.0通信

TLM2.0是SystemC模型之间的核心传输方式,它于2009年发布并随后成为IEEE标准IEEE1666-2011。

与 TLM1.0 相比, TLM2.0 提供了更丰宫、 更强大的传输特性, 主要包括:

•    双向的阻塞或非阻塞接口;
•    时间标记;
•    统一的数据包。

通过这些特性, TLM2.0使得接口之间的通信更趋于标准化, 更容易为系统构建抽象模型。虽然 TLM2.0 开始作为 SystemC 标准库的一部分(由 C++实现), 但是由于 RTL 与SystemC 模型的混合仿真趋势, 要求 SV 也能够有与之匹配的接口便于日后的互相嵌套。 本节将重点介绍 TLM2.0 的特性、 它在 UVM 中的实现方式以及其使用方式。

接口实现

TLM2.0 的传输是双向的, 意味着在一次完整传输中有 request 和 response 类型。这听起来和我们在 TLM1.0 中学习的 transport 端口传输方式类似, 先别急着下结论, 我们继续往下看。TLM2.0 支持 blocking 和 nonblocking 两种 transport 方式。

•    blocking 的传输方式要求在一次传输过程中, 完成 request 和 response 的传输。
•    nonblocking 的传输方式则将 request 和 response 的传输分为了两个独立的单向传输,而两次传输整体视为完成一次握手传输。

上面两种传输方式对应的UVM方法如下:

task b_transport(T t, uvm_tlm_time delay); 
function uvm_tlm_sync_e nb_transport_fw (T t, ref P p, input uvrn_tlm_time delay);                  function uvrn_tlm_sync_e nb_transport_bw (T t, ref P p, input uvrn_tlm_time delay);

这里 T 代表统一的传输数据类 uvrn_tlm_generic_payload, 而 P 代表在 nonblocking 传输方式中用来做状态同步的类型。在定义 TLM2.0 的过程中,仍然有 initiator 和 target 的概念,也有 port、export 以及 imp 端口类型。port 类型是用来发起请求并调用target 一端的传输方法, export 用来传导这一要求, 最后由 imp 端口所在组件来实现数据传输方法。

为了区别于 TLM1.0 对端口类型的称谓, UVM将TLM2.0 端口类型称为 socket, 它们是由 port export 和 imp 组合而成的。 一个 socket 首先是双向传输, 例如 TLM1.0的双向传输端口 transport 可以用来做单次完成的双向传输, master 和 slave 端口用来完成多次的单向传输。 而 socket 则按照 blocking 和 n成的双向传输, master 和 slave 端口用来完成多次的单向传输。 而 socket 则按照 blocking 和 nonblocking 的传输方式, 并且组合 initiator 或 target, 可以分为下面这些端口类型:

uvm_tlm_b_initiator_socket 
uvrn_tlm_b_target_socket 
uvrn_tlm_nb_initiator_socket 
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, 具有同 TLM1.0端口一样的基础函数, 而在这些 socket 内部, 它们是通过例化 port、export 以及 imp 最终实现数据双向传输的。 

TLM2.0 的 port、export 和 imp 类型不同于 TLM1.0。首先, 这些相关的端口类型是新引入的
类, 例如 uvm_tlm_b_transport_port、uvm_tlm_b_transport_export 和 uvm_tlm_b_transport_ imp。这里没有改变的概念是不同端口类型之间的连接关系 改变的只是新的端口类型名所匹配的方法不再是 put(), get(), peek(), 而是变为 b_transport(), nb_transport_ fw()和 nb_ transport _bw().socket 通过内置这些端口, 可以实现数据的双向传输。 

传送数据

TLM1.0 传送的数据类型由用户自定义, 这对组件之间的数据传输做出了更多限制。 例如, 端口传输数据类型不同, 则端口无法连接, 同时针对传输不同数据类型的 TLM 端口, 相应的传送方法也要做出调整,因此这种方式不利于组件之间的快速连接和整个平台的搭建。TLM2.0 对传送数据类型提出了一致化要求,这里统一的数据类型由 uvm_tlm_generic_payload 表示, 即传输方法中使用的数据类型都应该为 uvm_ tlm _generic _payload。为了保持 TLM2.0端口的良好连接性, 并不建议在 uvm_tlm_generic_payload 类的基础上做出更多扩展, 因为该类本身可以容纳更多的扩展数据部分。 

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

•     bit [63:0] m_address: 数据的读写地址。
•     uvm _ tlm_command_ e m _command: 数据的读写命令。
•     byte unsigned data[ ]: 写入的数据或读出的数据, 由 byte unsigned 的类型构成动态数组。 这是按照总线传输的最小粒度进行划分, 便于 target一侧进行数据整合。                                          •     int unsigned length: data 数组的长度, 该数值应该与 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]: 如果一些数据域不在上面的部分, 那么可以在这个数据延伸域中添加。

从各个数据域的介绍来看, 对于一般总线传输而言, 这里包含的数据信息已经足够, 那么如果该传输还包括其他数据内容, 该怎么办呢? 一种办法是, 将其合并作为数据成员data 数组中的一部分,另一种办法是创建新的 uvm_tlm_extension 类,将额外的数据成员装入到该数据延伸对中,通过 uvm_tlm_generic_payload: :set_ extension(uvm_ tlm_ extension_ base ext) 来添加这一部分的数据。 对于一个数据类而言, 复制、 比较和打印等功能是必不可少的, 该类提供了do_copy( ) 、 do_compare()和 do_print()等回调函数来满足这一要求。

时间标记

不同的时间标记间隔是 SystemC 构建不同时间精确度模型的重要手段。 尽管原则上SystemC 也可以通过自建时钟源利用时钟事件来驱动内部逻辑,但为了提高模型的运行效率, 将数据传输和处理的时间通过标记时间来反映, 可以很大程度上避免时钟依赖。 在 TLM2.0 传输中, 由于可以标定延迟时间, 使得 target 端可以模拟延迟, 并且在准确的延迟时刻做出响应。 为了便于标记延迟时间, 例如实数范围的延迟 1.1ns (SV 继承与 Verilog 的时间精度方式, 只能使用整数的延迟方式), UVM新建了一个时间类 uvm_tlm_time。这个时间类的便捷之处在于用户可以随时设置它的时间单位(默认为 lps), 还可以进行时间的增减操作。 这个类的存在, 也是为了解决在不同模块或数据包之间出现的不同时间单位和精度单位的问题。 有了这么灵活的时间类, target 一侧要进行时间等待这些操作就容易得多了, 也不会出现时间单位或精度单位错误的问题。

参考实例

class compl extends uvm_component;
uvm_tlm_b_initiator_socket b_ini_skt;//定义了TLM2.0的通信端口,并不需要指定数据的传输类型
`uvm_component_utils(compl)
...
task run_phase(uvm_phase phase);
byte unsigned data[] = {l, 2, 3, 4, 5, 6, 7, 8}; 
uvm_tlm_generic_payload pl = new("pl"); 
uvm_tlm_time delay = new("delay"); 
pl.set_address ('hOOOOFOOO); 
pl.set_data_length(8); 
pl.set_data(data); 
pl.set byte enable length(8);
pl.set_ write() ; //pl通过调用函数赋值
delay.incr(0.3ns, lps); 
`uvm info("INITRSP", $sformatf("initiated a trans at %0d ps",$realtime()), UVM_LOW) 
b_ini_skt.b_transport(pl, delay); //comp1中调用
endtask 
endclass 
class comp2 extends uvm_component;
uvm_tlm_b_target_socket #(comp2) b_tgt_skt; //定义了通信端口,并不需要指定数据的传输类型,但在target中仍旧需要指定参数的组件类型
`uvm_component_utils(comp2)
...
task b_transport(uvm_tlm_generic_payload pl, uvm_tlm_time delay);//uvm_tlm_generic_payload为TLM2.0的标准数据类型
`uvm info("TGTTRSP", $sformatf("received a trans at %0d ps",$realtime()), UVM_LOW) 
pl. print () ; 
#(delay.get_realtime(lps));//对于delay的应用,等待调用自身的函数get_realtime最小精度1ps,计算出的时间
pl.set_response_status(UVM_TLM_OK_RESPONSE);//调用函数将response状态切换为ok。
`uvm info("TGTTRSP", $sformatf("completed a trans at %0d ps",$realtime()), UVM_LOW) 
pl. print () ;
endtask 
endclass 
class envl extends uvm_env; 
compl cl;
comp2 c2;
'uvm_component_utils(envl)
...
function void build_phase(uvm_phase phase);
super.build_phase(phase); 
cl = compl::type_id::create("cl", this); 
c2 = comp2::type_id::create("c2", this);
endfunction: build_phase 
function void connect_phase(uvm_phase phase);
super.connect_phase(phase); 
cl.b_ini_skt.connect(c2.b_tgt_skt); //c1的skt连接到c2上
endfunction: connect_phase
endclass 


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

创芯人

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

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

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

打赏作者

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

抵扣说明:

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

余额充值