0
点赞
收藏
分享

微信扫一扫

UVM——TLM通信

东言肆语 2022-03-14 阅读 36

TLM通信

TLM(Transaction-Level Modeling)是一种基于事务的通信方式,通常作为模块之间的通讯使用。TLM通信需要两个通信对象:initiator,target。initiator发起通信请求,target作为发起通信的响应方。而按照transaction的流向,可以将对象分为producer和consumer。producer是数据产生的地方,consumer是数据流向的地方。需要注意的是initiator不一定是producer,target不一定是consumer。
在这里插入图片描述
有了两个参与通信的对象后,用户需要将TLM通信方法在target一端中实现,以便于initiator将来作为发起方可以调用target的通信方法,实现数据传输。在发起端(initiator)的生产者(producer)可以将数据put()给目标端(target)的消费者(consumer),而目标端的生产者也可以将数据get()给发起端的消费者。

分类

TLM通信步骤分为:
- 分辨initiator和target,producer和consumer
- 在target中实现TLM通信方法
- 在两个对象中创建TLM端口
- 在更高层次中将两个对象的端口进行连接

从数据流向来看,传输方向可以分为单向(unidirection)和双向(bidirection):
- 单向传输:由initiator发起request transaction
- 双向传输:由initiator发起request transaction,传递至target;
以前面的组件为例,monitor和scoreboard,monitor是发起端,scoreboard是目标端(单向)。driver和generator,driver是发起端,从gen里get得到transaction,再put回去(双向)。

端口按照类型可以划分为三类:
- port:经常作为initiator的发起端,initiator凭借port才可以访问target的TLM通信方式
- export:作为initiator和target中间层次的端口
- imp:只能作为target接受request的末端,无法作为中间层次的端口,imp的连接无法再次延伸。

如果将传输方向和端口类型加以组合,可形成TLM端口的继承树,分为六类:
- uvm_UNDIR_port #(trans_t)
- uvm_UNDIR_export #(trans_t)
- uvm_UNDIR_imp #(trans_t, imp_parent_t)
- 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)

端口的使用

端口不是组件类型,因此不能用type_id::create创建。
就单向端口而言,声明port和export作为request发起方,需要指定transaction类型参数,而声明imp作为request接收方,需要指定transaction类型,也要指定它所在的component类型
就双向端口而言,指定参数需要考虑双向传输的因素,将传输类型transaction拆分为request transaction和response transaction类型。
从对应连接关系得出TLM端口连接的一般做法:
- 在initiator端例化port,在中间层次例化export,在target端例化imp
- 多个port可以连接到同一个export或者imp;但是单个port或export无法连接到多个imp。这可以抽象为多个initiator可以对同一个target发起request,但是同一个initiator无法连接多个target
- port应为request起点,imp应为request终点,而中间可以穿越多个层次
- port可以连接port、export、imp;export可以连接export、imp;imp只能作为数据传输的终点,无法拓展连接
在这里插入图片描述

//实例
class request extends uvm_transaction;
	byte cmd;
	int  addr;
	int  req;
endclass

class response extends uvm_transaction;
	byte cmd;
	int  addr;
	int  rsp;
	int  status;
endclass

class comp1 extends uvm_agent;
	uvm_blocking_get_port #(request) bg_port;
	`uvm_component_utils(comp1)
	...
endclass

class comp2 extends uvm_agent;
	uvm_blocking_get_port #(request) bg_port;
	uvm_nonblockign_put_imp #(request, comp2) nbq_imp;
	`uvm_component_utils(comp2)
	...
	function bit try_put(request req);
	functuin bit can_put();
class

class comp3 extends uvm_agent;
	uvm_blocking_transport_port #(request, response) bt_port;
	`uvm_component_utils(comp3);
	...
endclass

class comp4 extends uvm_agent;
	uvm_blocking_get_imp #(request, comp4) bg_imp;
	uvm_nonblocking_put_port #(request) nbp_port;
	`uvm_component_utils(comp4);
	...
	task get(output request req);
endclass

class comp5 extends uvm_agent;
	uvm_blocking_transport_imp #(request, response, comp5) bt_imp;
	`uvm_component_utils(comp5);
	...
	task transport(request req, output response rsp);
endclass

class agent1 extends uvm_agent;
	uvm_blocking_get_port #(request) bg_port;
	uvm_nonblocking_put_export #(request) nbp_exp;
	uvm_blocking_transport_port #(request, response) bt_port;
	comp1 c1;
	comp2 c2;
	comp3 c3;
	`uvm_component_utils(agent1)
	...
	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);
		c3 = comp3::type_id::create("c3", this);
	endfunction
	
	function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);
		c1.bg_port.connect(this.bg_port);		//connect左侧可以使initiator、export,右侧是target
		c2.bg_port.connect(this.bg_port);
		this.nbp_exp.connect(c2.nbp_imp);		//连接方向从agent的export到c2的import
		c3.bg_port.connect(this.bg_port);
	endfunction
endclass

class env1 extends uvm_env;
	agent a1;		//a1内包含c1,c2,c3
	comp4 c4;
	comp5 c5;
	`uvm_component_utils(env1)
	...
	function void build_phase(uvm_phase phase);
		super.build_phase(phase);
		a1 = agent::type_id::create("a1", this);
		c4 = comp4::type_id:;create("c4", this);
		c5 = comp5::type_id:;create("c5", this);
	endfunction

	function void connect_phase(uvm_phase phase);
		super.connect_phase(phase);
		a1.bg_port.connect(c4.bg_imp);		//a1的port接口与c4的imp接口连接(这里a1的port接口又连接了a1里面的c1,c2的port)
		c4.nbp_port.connect(a1.nbp_exp);	//c4的port接口与a1的export接口连接
		a1.bt_port.connect(c5.bt_imp);		//a1的port接口与c5的imp接口连接
	endfunction	
endclass

从上例中可以得到建立TLM通信的常规步骤:
- 定义TLM传输中的数据类型,上面分别定义了request类和response类
- 分别在各个层次的component中声明和创建TLM端口对象
- 通过connect()函数完成端口之间的连接
- 在imp端口类中要实现需要提供给initiator的可调用方法。例如,在comp2中由于有一个uvm_noblocking_put_imp#(request, comp2) nbp_imp,因此需要实现两个方法try_put()和can_out();而comp4中有一个uvm_blocking_get_imp#(request, comp4) bg_imp,则需要实现对应的方法get()
- 需要注意,必须在imp端口类中实现对应方法,否则端口即使连接也无法实现数据传输

举报

相关推荐

0 条评论