UVM入门与进阶学习笔记12——TLM2通信(1)


  • TLM是为了构建更高级抽象模型的传输方式。虽然SV本身没有原生的TLM传输方式,但是TLM在UVM很好地集成进来,并且在组件传输中得到了充分运用。
  • 伴随着SystemC模型的广泛引用,SystemC通信机制TLM2.0业发展起来,成为SystemC模型之间的核心传输方式。
  • TLM协议本身并不依赖于某一种语言,而是可以跨语言来实现其传输标准;TLM2.0是SystemC模型之间的核心传输方式
  • 与TLM1.0相比,TLM2.0提供了更丰富更强大的传输特性,主要包括:双向的阻塞或非阻塞接口时间标记统一的数据包。通过这些特性,TLM2.0使得接口之间的通信更趋于标准化,更容易为系统构建抽象模型
  • 虽然TLM2.0一开始作为SystemC标准库的一部分(由C++实现),但是由于RTL与SystemC模型的混合仿真趋势,要求SV也能够有与之匹配的接口便于日后的互相嵌套。

接口实现

  • 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 uvm_tlm_time delay);
function uvm_tlm_sync_e nb_transport_bw(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_b_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_tlm_b_transport_portuvm_tlm_b_transport_exportuvm_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

  • 为了保持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应该写入。
    • byte 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)添加这一部分的数据。
    • 对于一个数据类而言,拷贝、比较、和打印等功能是必不可少的,而uvm_tlm_extension类也提供do_copy()、do_compare()、do_print()等回调函数来满足这一要求。

时间标记

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

示例:利用TLM2的socket建立一个轻量级的例子,从这个例子体会一下与TLM1.0相比,TLM2.0传输的特点:

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 p1 = new("p1");
		uvm_tlm_time delay = new("delay");
		p1.set_address('h0000F000);
		p1.set_data_length(8);
		p1.set_data(data);
		p1.set_byte_enable_length(8);
		p1.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(p1, 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 p1, uvm_tlm_time delay);
		`uvm_info("TGTTRSP", $sformatf("received a trans at %0d ps", $realtime()), UVM_LOW)
		p1.print();
		#(delay.get_realtime(1ps));
		p1.set_response_status(UVM_TLM_OK_RESPONSE); //切换为OK的response,默认为不OK
		`uvm_info("TGTTRSP", $sformatf("complete a trans at %0d ps", $realtime()), UVM_LOW)
		p1.print();
	endtask
endclass
class 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
	function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);
		c1.b_ini_skt.connect(c2.b_tgt_skt);
	endfunction
endclass

总结:

  • 从示例可以看出,有了标准的传输数据包和准确的延迟时间,方便了模块之间的复用和建立更高层次的模型。
  • 从实用角度来看,TLM2.0在UVM的实现是为了可以同SystemC的TLM2.0接口无缝衔接
  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值