(4)UVM TLM2.0
作者:互联网
UVM TLM2.0
概述
TLM是一种为了构建更高级抽象模型的传输方式。虽然SV语言本身没有原生的TLM传输方式,但是TLM在UVM很好地集成进来,并且在组件传输中得到了充分运用。
之前的UVM各个组件之间的通信是通过TLM1.0方式实现的,而伴随着SystemC模型的广泛引用,SystemC通信机制TLM2.0也引起了UVM标准委员会的兴趣。
TLM协议本身并不依赖于某一种语言,而是可以跨语言来实现其传输标准。
TLM2.0是SystemC模型之间的核心传输方式,它于2009年发布并随后成为IEEE标准IEEE1666-2011。
与TLM1.0相比,TLM2.0提供了更丰富更强大的传输特性,它们主要包括:
1、双向的阻塞或者非阻塞接口
2、时间标记
3、统一的数据包
通过这些特性,TLM2.0使得接口之间的通信更趋于标准化,更容易为系统构建抽象模型。
虽然TLM2.0一开始作为SystemC标准库的一部分(由C++实现),但是由于RTL与SystemC模型的混合仿真趋势,要求SV也能够有与之匹配的接口便于日后的互相嵌套。
TLM2.0的输是双向的,意味着在一次完整传输中有request和response类型。
这与TLM1.0transport端口传输方式是类似的。
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 uvm_tlm_time delay);
function uvm_tlm_sync_e nb_transport_fw(T t,ref P p,input uvm_tlm_time delay);
这里T代表着统一的传输数据类uvm_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和nonblocking的传输方式,组合initiator或者target的发起端区别,可以分为下面这些端口类型:
uvm_tlm_initiator_socket
uvm_tlm_b_target_socket
uvm_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_tim_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]:如果一些数据域不在上面的部分,那么可以在这个数据延伸域中添加。
从各个数据域的介绍来看,对于一般总线传输而言,这里包含的数据信息已经足够,那么如果该传输还包括其它数据内容,该怎么办呢?
1、一种办法是,将其合并作为数据成员data数组中的一部分。
2、另外一种办法是创建新的uvm_tlm_extension类,将额外的数据成员装入到该数据延伸对象中,通过
uvm_tlm_generic_payload:set_extension(uvm_tlm_extension_base ext)来添加这一部分的数据。
3、对于一个数据类而言,拷贝、比较和打印等功能是必不可少的,而uvm_tlm_extension类也提供了do_copy()、do_compare()和do_print()等回调函数来满足这一要求。
时间标记
不同的时间标记间隔是SystemC可以构建不同时间精确度模型的重要手段。
尽管SystemC原则上也可以通过自建时钟源利用时钟事件来驱动内部逻辑,但为了提高模型的运行效率,将数据传输和处理的时间通过标记时间来反映,可以很大程度上避免时钟依赖。
在TLM2传输中,由于可以标定延迟时间,这使得target端可以模拟延迟,并在准确的延迟刻做出响应。
为了便于标记延迟时间,例如实数范围的延1.1ns(SystemVerilog继承与Verilog的时间精度方式,只能使用整数的延迟方式),UVM新建了一个时间类uvm_tlm_time。
这个时间类的便捷之处在于用户可以随时设置它的时间单位(默认为1ps),并且进行时间的增减操作。
同时这个类的存在,也是为了解决在不同模块或数据包之间出现的不同时间单位和精度单位的问题。
有了这么灵活的时间类,target-侧要进行时间等待这些操作就容易得多了,也不会出现时间单位或精度单位错误的问题。
示例
class comp1 extends uvm_component;
uvm_tlm_b_initiator_socket b_ini_skt;
uvm_component_uti1s(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);
p1.set_data(data);
pl.set_byte_enable_length(8);
pl.set_write();
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
endclass
class 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));
p1.set_response_status(UVM_TLM_OK RESPONSE);
uvm_info("TGTTRSP",$sformatf("completed a trans at %0d ps",$realtime()), UVM_LOW)
pl.print();
endtask
endclass
这篇笔记参考《UVM实战》、《芯片验证漫游指南》和某验证视频整理而成,仅作学习心得交流,如果涉及侵权烦请请告知,我将第一时间处理。
标签:socket,transport,TLM2.0,传输,uvm,tlm,UVM 来源: https://blog.csdn.net/qq_40051553/article/details/121388265