TLM端口

TLM1.0的定义

TLM(Transaction Level Modeling):起源于SystemC的一种通信标准。所谓transaction level是相对DUT中各个模块之间信号线级别的通信来说的。一个transaction就是把具有某一特定功能的一组信息封装在一起而成为的一个类。

常用操作

  • put操作:
    在这里插入图片描述
    通信的initiator A把一个transaction发送给target B。A具有的端口称为PORT,而B的端口称为EXPORT。这个过程中,数据流是从A流向B的。
  • get操作:
    在这里插入图片描述
    A向B索取一个transaction。在这个过程中,A依然是initiator,B依然是target,A上的端口依然是PORT,而B上的端口依然是EXPORT。这个过程中,数据流是从B流向A的。
    PORT和EXPORT体现的是控制流而不是数据流。initiator拥有的都是PORT端口,而不是EXPORT。作为一个EXPORT来说,只能被动地接收PORT的命令。
  • transport操作:
    在这里插入图片描述
    transport操作相当于一次put操作加一次get操作,这两次操作的initiator都是A,target都是
    B。A上的端口依然是PORT,而B上的端口依然是EXPORT。在这个过程中,数据流先从A流向B,再从B流向A。在现实世界中,相当于是A向B提交了一个请求(request),而B返回给A一个应答(response)。

put、get和transport操作都有阻塞和非阻塞之分。

PORT与EXPORT

UVM中的port根据操作可以分为get、put、transport、peek、get_peek这几种,每种都有blocking和nonblocking之分。

uvm_blocking_put_port#(T);
uvm_nonblocking_put_port#(T);
uvm_put_port#(T);
uvm_blocking_get_port#(T);
uvm_nonblocking_get_port#(T);
uvm_get_port#(T);
uvm_blocking_peek_port#(T);
uvm_nonblocking_peek_port#(T);
uvm_peek_port#(T);
uvm_blocking_get_peek_port#(T);
uvm_nonblocking_get_peek_port#(T);
uvm_get_peek_port#(T);
uvm_blocking_transport_port#(REQ, RSP);
uvm_nonblocking_transport_port#(REQ, RSP);
uvm_transport_port#(REQ, RSP);

export也类似。

uvm_blocking_put_export#(T);
uvm_nonblocking_put_export#(T);
uvm_put_export#(T);
uvm_blocking_get_export#(T);
uvm_nonblocking_get_export#(T);
uvm_get_export#(T);
uvm_blocking_peek_export#(T);
uvm_nonblocking_peek_export#(T);
uvm_peek_export#(T);
uvm_blocking_get_peek_export#(T);
uvm_nonblocking_get_peek_export#(T);
uvm_get_peek_export#(T);
uvm_blocking_transport_export#(REQ, RSP);
uvm_nonblocking_transport_export#(REQ, RSP);
uvm_transport_export#(REQ, RSP);

各种端口的互连

PORT与EXPORT的连接

UVM中使用connect函数来建立连接关系。如A要和B通信(A是initiator),那么可以这么写:A.port.connect(B.export),但是不能写成B.export.connect(A.port)。只有initiator才能调用connect函数。
EXPORT无法把transaction存储下来除了转发操作之外不作其他操作。因此,这笔transaction一定要由B_export后续的某个组件进行处理。在UVM中,完成这种后续处理的也是一种端口:IMP。

UVM中的IMP

  • 按照控制流的优先级排序,UVM中三种端口顺序为:PORT、EXPORT、IMP。IMP的优先级最低,一个PORT可以连接到一个IMP,并发起三种操作,反之则不行。
  • 在UVM中,只有IMP才能作为连接关系的终点。如果是PORT或者EXPORT作为终点,则会报错。
    在这里插入图片描述
    如图中的这种连接,要在B中实现具体的任务,例如,如果A发起put操作,则需要在B中定义put任务/函数。

PORT与IMP的连接

由于具体的操作需在imp中实现,实现时有如下的规律:

  • 对于所有blocking系列的端口来说,可以定义相应的task或function,如对于blocking_put端口来说,可以定义名字为put的task,也可以定义名字为put的function。这是因为A会调用B中名字为put的接口,而不管这个接口的类型。由于A中的put是个task,所以B中的put可以是task,也可以是function。
  • 但是对于nonblocking系列端口来说,只能定义function。

EXPORT与IMP的连接

PORT可以与IMP相连接,同样的EXPORT也可以与IMP相连接,其连接方法与PORT和IMP的连接完全一样。区别在于这里把EXPORT作为连接的起点。

PORT与PORT的连接

在前面的连接中,都是不同类型的端口之间连接(PORT与IMP、PORT与EXPORT、EXPORT与IMP),且不存在层次的关系。在UVM中,支持带层次的连接关系,如下图所示:
在这里插入图片描述
A与C中是PORT,B中是IMP。UVM支持C的PORT连接到A的PORT,并最终连接到B的IMP。,具体代码如下:

class C extends uvm_component;
	`uvm_component_utils(C)

	uvm_blocking_put_port#(my_transaction) C_port;
…
endclass
…
task C::main_phase(uvm_phase phase);
	my_transaction tr;
	repeat(10) begin
		#10;
		tr = new("tr");
		assert(tr.randomize());
		C_port.put(tr);
	end
endtask


class A extends uvm_component;
	`uvm_component_utils(A)

	C C_inst;
	uvm_blocking_put_port#(my_transaction) A_port;
…
endclass

function void A::build_phase(uvm_phase phase);
	super.build_phase(phase);
	A_port = new("A_port", this);
	C_inst = C::type_id::create("C_inst", this);
endfunction

function void A::connect_phase(uvm_phase phase);
	super.connect_phase(phase);
	C_inst.C_port.connect(this.A_port);
endfunction

PORT与PORT之间的连接不只局限于两层,可以有无限多层。

EXPORT与EXPORT的连接

同样的,,UVM也支持EXPORT与EXPORT之间的连接。
在这里插入图片描述

class C extends uvm_component;
	`uvm_component_utils(C)

	B B_inst;

	uvm_blocking_put_export#(my_transaction) C_export;
…
endclass

function void C::build_phase(uvm_phase phase);
	super.build_phase(phase);
	C_export = new("C_export", this);
	B_inst = B::type_id::create("B_inst", this);
endfunction

function void C::connect_phase(uvm_phase phase);
	super.connect_phase(phase);
	this.C_export.connect(B_inst.B_export);
endfunction


function void my_env::connect_phase(uvm_phase phase);
	super.connect_phase(phase);
	A_inst.A_port.connect(C_inst.C_export);
endfunction

同样的,EXPORT与EXPORT之间的连接也不只局限于两层,也可以有无限多层。

通信方式

UVM中的analysis端口

UVM中有两种特殊的端口:analysis_port和analysis_export。这两者与put和get系列端口类似,都用于传递transaction。区别在于:

  1. 默认情况下,一个analysis_port(analysis_export)可以连接多个IMP,是一对多的通信,而put和get系列端口与相应IMP的通信是一对一的通信。
  2. 对于analysis_port和analysis_export来说,没有阻塞和非阻塞的概念。因为它本身就是广播,不必等待与其相连的其他端口的响应,所以不存在阻塞和非阻塞。
  3. 一个analysis_port可以和多个IMP相连接进行通信,但是IMP的类型必须是uvm_analysis_imp,否则会报错。对于analysis_port和analysis_export来说,只有一种操作:write。在analysis_imp所在的component,必须定义一个名字为write的函数。
    在这里插入图片描述
    如上图中即实现了一个port与两个imp的连接,代码如下:
class A extends uvm_component;
	`uvm_component_utils(A)
	uvm_analysis_port#(my_transaction) A_ap;
…
endclass
…
task A::main_phase(uvm_phase phase);
	my_transaction tr;
	repeat(10) begin
		#10;
		tr = new("tr");
		assert(tr.randomize());
		A_ap.write(tr);
	end
endtask

class B extends uvm_component;
	`uvm_component_utils(B)
	uvm_analysis_imp#(my_transaction, B) B_imp;
…
endclass
function void B::write(my_transaction tr);
	`uvm_info("B", "receive a transaction", UVM_LOW)
	tr.print();
endfunction
//C的代码与B完全相同,所以在这里不列出


function void my_env::connect_phase(uvm_phase phase);
	super.connect_phase(phase);
	A_inst.A_ap.connect(B_inst.B_imp);
	A_inst.A_ap.connect(C_inst.C_imp);
endfunction
  • analysis_export和IMP也可以如上图一样相连接,只需将上面例子中的uvm_analysis_port改为uvm_analysis_export就可以。
  • 要注意的是,与put系列端口的PORT和EXPORT直接相连会出错的情况一样,analysis_port如果和一个analysis_export直接相连也会出错。只有在analysis_export后面再连接一级uvm_analysis_imp,才不会出错。

一对多的通信

UVM定义了一个宏uvm_analysis_imp_decl来解决有多个IMP时定义函数的问题:

`uvm_analysis_imp_decl(_monitor)
`uvm_analysis_imp_decl(_model)
class my_scoreboard extends uvm_scoreboard;
	my_transaction expect_queue[$];
	uvm_analysis_imp_monitor#(my_transaction, my_scoreboard) monitor_imp;
	uvm_analysis_imp_model#(my_transaction, my_scoreboard) model_imp;extern function void write_monitor(my_transaction tr);
	extern function void write_model(my_transaction);
	extern virtual task main_phase(uvm_phase phase);
endclass

上述代码通过宏uvm_analysis_imp_decl声明了两个后缀_monitor和_model。UVM会根据这两个后缀定义两个新的IMP类:uvm_analysis_imp_monitor和uvm_analysis_imp_model,并在my_scoreboard中分别实例化这两个类:monitor_imp和model_imp。当与monitor_imp相连接的analysis_port执行write函数时,会自动调用write_monitor函数,而与model_imp相连接的analysis_port执行write函数时,会自动调用write_model函数。
后续还要在具体定义write时添加上相应的后缀:

function void my_scoreboard::write_model(my_transaction tr);
	expect_queue.push_back(tr);
endfunction

function void my_scoreboard::write_monitor(my_transaction tr);
	my_transaction tmp_tran;
	bit result;
	if(expect_queue.size() > 0) begin
…
	end
endfunction

使用FIFO通信

为了使两边的组件都可以充当initiator,可以使用FIFO来通信:
在这里插入图片描述

如上图b)所示,在agent和scoreboard之间添加一个uvm_analysis_fifo。FIFO的本质是一块缓存加两个IMP。

  • 在monitor与FIFO的连接关系中,monitor中依然是analysis_port,FIFO中是uvm_analysis_imp,数据流和控制流的方向相同。
  • 在scoreboard与FIFO的连接关系中,scoreboard中使用blocking_get_port端
    在这里插入图片描述
  • 上图为FIFO中的端口,值得注意的是,虽然名字中有关键字export,但是其类型却是IMP。UVM为了掩饰IMP的存在,在它们的命名中加入了export关键字
  • FIFO中还有两个analysis_port:put_ap和get_ap。当FIFO上的blocking_put_export或者put_export被连接到一个blocking_put_port或者put_port上时,FIFO内部被定义的put任务被调用,这个put任务把传递过来的transaction放在FIFO内部的缓存里,同时,把这个transaction通过put_ap使用write函数发送出去。与put_ap相似,当FIFO的get任务被调用时,同样会有一个transaction从get_ap上发出。内部的缓存用SV中的mailbox来实现。

FIFO的类型有两种,一种uvm_tlm_analysis_fifo,另外一种是uvm_tlm_fifo。这两者的唯一差别在于前者有一个analysis_export端口,并且有一个write函数,而后者没有。

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值