UVM基础-TLM机制之端口通信

  • TLM各组件端口之间的互联

1 端口连接规则

上文有提到,组件之间端口的连接,只能由优先级高的端口连接到优先级低的端口上,因此对于不同种类型的连接关系,port连接到export,export连接到imp,或者是port直接连接到imp,不可以反向连接。而且,同种类的port端口要和同类型的export端口连接,也就是说:uvm_blocking_put_port只能连接到uvm_blocking_put_export上或者uvm_blocking_put_imp上,不可以连接到uvm_nonblocking_put_export,或者uvm_blocking_get_export上,实际使用时要尽量避免出现这种操作类型不同的端口之间的连接。

端口的连接实现实在uvm验证环境中更上层的节点中,通过调用优先级较高的端口类型的connect函数,将优先级低的端口类型,作为参数传递给connent函数实现。这个结论听着有些抽象,可以举例说明:当在一个env中,rm的高优先级端口想要连接scoreboard上的低优先级端口,那么要在rm中申明port,在scoreboard中申明export和imp,port和export的连接在env中完成,因为在rm中,并看不到scoreboard的端口,rm和scoreboard是同层级的节点,export和imp的连接在scoreboard中就可以完成,通过高优先级端口的connect函数实现。如图3.1.1所示:

 

图3.1.1 组件端口之间的连接关系

       从图3.1.1中可以看出来,低优先级的端口组件的句柄作为高优先级组件connect函数的参数,实现连接,因此,在高优先级端口组件中,是可以调用低优先级组件的函数或者任务的,这也是为什么一次通信操作下,put过程(或者是其他过程)是通过调用被动接受者内部的函数或任务实现。实际写段代码感受下:

RM的代码:

1.	class reference_model extend uvm_component;
2.	      `uvm_component_utils(reference_model)
3.	      uvm_nonblock_put_port#( my_transaction ) rm_port;
4.	 ......
5.	      extern function void build_phase(uvm_phase phase);
6.	......
7.	endclass
8.	
9.	function void reference_model::build_phase(uvm_phase phase);
10.	      super.build_phase(phase);
11.	      rm_port = new("rm_port", this, min_size=1, max_size=1);
12.	......
13.	endfunction:build_phase

在RM的build phase中将port实例化;

Scoreboard代码:

1.	class scoreboard extend uvm_scoreboard;
2.	      `uvm_component_utils(scoreboard)
3.	      uvm_nonblocking_put_export# (my_transaction) scb_export;
4.	      uvm_nonblocking_put_imp# (my_transaction, scoreboard) scb_imp;
5.	      my_transaction tr_q[$];
6.	 ......
7.	      extern function void build_phase(uvm_phase phase);
8.	      extern funciton void connect_phase(uvm_phase phase);
9.	......
10.	      extern function bit can_put();
11.	      extern function bit try_put(my_transaction tr);
12.	endclass
13.	
14.	function void scoreboard::build_phase(uvm_phase phase);
15.	      super.build_phase(phase);
16.	      scb_export = new("scb_export", this, min_size=1, max_size=1);
17.	      scb_img     = new("scb_imp", this, mix_size=1, max_size=1);
18.	......
19.	endfunction:build_phase
20.	
21.	function void scoreboard::connect_phase(uvm_phase phase);
22.	      super.connect_phase(phase);
23.	      scb_export.connect(scb_imp);
24.	......
25.	endfunction:connect_phase
26.	
27.	function bit scoreboard::can_put();
28.	      if (tr_q.size() > 0) begin
29.	              return 0;
30.	      end
31.	      else begin
32.	              return 1;
33.	      end
34.	endfunction:can_put
35.	
36.	function bit scoreboard::try_put(my_transaction tr);
37.	      if(tr_q.size() == 0) begin
38.	               tr_q.push_back(tr);
39.	               return 1;
40.	      end
41.	      else begin
42.	               return 0;
43.	      end
44.	endfunction:try_put

在scoreboard中的分别例化了export和imp,并且在connect_phase中进行了连接。此外,正如2.3节所介绍的结论,在被动接受这scoreboard中,还应该申明nonblocking的关键函数can_put和try_put,以便在动作发起者中进行调用。为什么要这样做,在本章节的后面部分小结会详细展开描述。

ENV代码:

1.	class env extend uvm_env;
2.	      `uvm_component_utils(env)
3.	      reference_model my_mdl;
4.	      scoreboard          my_scb;
5.	......
6.	      extern function void build_phase(uvm_phase phase);
7.	      extern function void connect_phase(uvm_phase phase);
8.	......
9.	endclass
10.	
11.	function void env::build_phase(uvm_phase phase);
12.	      super.build_phase(phase);
13.	      my_mdl = reference_model::type_id::create("my_mdl", this);
14.	      my_scb = scoreboard::type_id::create("my_scb", this);
15.	 ......
16.	endfunction:build_phase
17.	
18.	function void env::connect_phase(uvm_phase phase);
19.	      super.connect_phase(phase);
20.	      this.my_mdl.rm_port.connect(this.my_scb.scb_export);
21.	......
22.	endfunction:connect_phase

在ENV的connect phase中实现了rm的port与scoreboard的export连接。

       另外,在默认情况下,一个port只能连接一个export或者imp,但TLM提供了更灵活的连接方式,也就是可以通过参数的控制,让一个port可以连接多各export。使用者在实例化的时候可以通过端口的new函数将个数进行传递。此处通过UVM Port new函数源码进行说明。

  1. function new(string name, uvm_component parent, int min_size=1int max_size=1);

可以看到,在端口的new函数中,除了需要传递的端口名称字符串和申明端口位于那个节点上,以形成UVM树形结构的parent之外,还多了两个参数,min_size和max_size,上例代码中也用到了。这两个参数含义是指端口在实现连接的时候,connect函数被调用的最小次数和最大次数。

2 通信过程的底层逻辑

       前文中其实也或多或少的提到了,在一次通信过程中,动作发起者发起的操作,最终其实会调用到被动接受者组件内部的函数上,这是为什么呢?其实在uvm底层源码逻辑中可以发现,在连接的过程中,高优先级的端口的connect函数,参数是低优先级端口的句柄,而作为与组件通信窗口的imp而言,会将实例化imp的组件的句柄,作为申明imp的参数进行传递,以blocking put类型的port为例,在传输数据包transaction时,在动作发起者组件中调用port.put函数,实际上是调用的被动接受者组件内部的put函数,那么这是为什么呢?动作发起者组件内部压根就看不到被动接受者的函数(因为同级组件一般不会相互例化)。

其实这个问题的答案是,通过port->export->imp->被动接受者组件,这一个管道实现的,调用过程为:port.put函数内部会调用与其相连的export的put函数,因为在connect过程中,将export的句柄传递给了port的connect,因此在port内可以获取到export的函数;而export的put函数会调用imp的put函数,原因和port调用put类似,而imp的put函数,最终会调用实例化他的被动接受者内部的put,因此整个过程中,在动作发起者组件内部调用的put,最终会落到被动接受者的put函数上,而这个函数本身并不会在动作发起者组件内,port,export以及imp中声明。如图3.2.1所示:

图3.2.1 各端口之间操作的调用关系

       如图3.2.1所示,Aport在调用put(tr)时,函数体内部会调用与之相连的export的put,而export的put函数体内部,又会调用与之相连的imp的put函数,而imp内部的put函数,会调用component的put函数,因此整个过程中,put操作最终会落到被动接受者组件的put函数上。

       这个过程也可以看出imp的重要性,因为通信操作最终会通过imp,落在被动接受者组件的具体操作函数上,因此一个imp就要与一个component所对应。

       理解了这个底层的逻辑,3.1节RM的代码可以再丰富下,考虑tr的调用和传输:

1.	class reference_model extend uvm_component;
2.	      `uvm_component_utils(reference_model)
3.	      uvm_nonblock_put_port#(my_transaction) rm_port;
4.	      my_transaction tr;
5.	......
6.	      extern function void build_phase(uvm_phase phase);
7.	      extern task main_phase(uvm_phase phase);
8.	......
9.	endclass
10.	
11.	function void reference_model::build_phase(uvm_phase phase);
12.	      super.build_phase(phase);
13.	      rm_port = new("rm_port", this, min_size=1, max_size=1);
14.	......
15.	endfunction:build_phase
16.	
17.	task reference_model::main_phase(uvm_phase phase);
18.	......
19.	      phase.raise_objection(this);
20.	      if (rm_port.can_put()) begin
21.	              put_success_flg = rm_port.try_put(tr);
22.	              if (put_success_flg) begin
23.	                        `uvm_info(get_type_name(), "tr put success", UVM_HIGH);
24.	              end
25.	      end
26.	      phase.drop_objection(this);
27.	endtask:main_phase

 这段代码引入了main phase来处理数据包,再main phase中,加入举手机制,判断当前scoreboard是否可以传输TR,如果可以传输,则调用try_put,当try_put返回1,说明当前tr传输成功,打印“tr put success”。

3 各种类型端口之间的连接

本节具体介绍TLM中port,export,imp三者之间的连接关系,以及各种类型操作和特点的端口之间应具备的方法。

3.1 port与export的连接

       这种连接关系是比较典型的连接,上文介绍的较多,本节不做过多介绍,需要注意的是在连接过程中,申明export的端口的句柄应作为参数传递给port的connect函数,实现连接。

       事实上,一个验证环境中,仅仅由port和export是无法完成数据包在两个组件之间的传输的,因为没有imp作为通信管道发送tr的纽带和动力源,因此仅通过port和export实现组件通信的过程中,UVM会报UVM_FATAL错误。

3.2 export与imp的连接

       在引入imp端口组件的过程中,其实很容易就能想到的一个问题,就是既然说必须要由imp作为纽带,连接两个组件,那么是不是可以不需要port口,或者不需要export口,通过port或者是export直接与imp连接,这样管道窗口有了(imp本身也可以作为组件通信的“大门”),动力源有了,是否可以直接连接?答案是肯定的,确实可以通过省略一个port或者export,实现两个组件的通信。但UVM设计TLM过程中,引入imp的剧情其实并不想让用户感知到imp的存在,其意义在TLM基于FIFO的通信中可以体现的更加明确。此处先介绍export与imp之间的互联。如图3.3.2.1所示:

图3.3.2.1 export与imp的连接

       正如前文提及的,export与imp连接过程中,一次通讯操作,最终会落到被动接受者的具体的操作函数上,而不同种类型的端口,操作函数的实现也不同,具体见下表3.3.2.1:

表3.3.2.1 操作函数实现说明

按操作特点分

按照操作类型分

在被动接受者中应实现的函数(任务)

备注说明

blocking

put_export

put(my_transaction tr)

函数体内部应体现“阻塞功能”,且实现可以是task,也可以是function,因为task可以带时间参数

get_export

get(output my_transaction tr)

peek_export

peek

get_peek_export

get和peek

transport_export

transport(my_transaction req, output my_transaction rsp)

nonblocking

put_export

try_put,can_put

函数体内部应体现“非阻塞功能”,实现只能是function

get_export

try_get,can_get

peek_export

try_peek,can_peek

get_peek_export

try_get,can_get,

try_peek,can_peek

transport_export

nb_transport

二者兼具

put_export

put,try_put,can_put

get_export

get,try_get,can_get

peek_export

peek, try_peek, can_peek

get_peek_export

get, try_get, can_get,

peek, try_peek, can_peek

transport_export

transport, nb_transport

3.3 port与imp的连接

       与export和imp连接类似,port与imp之间的互联。如图3.3.3.1所示:

图3.3.3.1 port与imp的连接

       同理,port与imp连接过程中,一次通讯操作,最终会落到被动接受者的具体的操作函数上,而不同种类型的端口,操作函数的实现也不同,具体见下表3.3.3.1:

表3.3.3.1 操作函数实现说明

按操作特点分

按照操作类型分

在被动接受者中应实现的函数(任务)

备注说明

blocking

put_port

put(my_transaction tr)

函数体内部应体现“阻塞功能”,且实现可以是task,也可以是function,因为task可以带时间参数

get_port

get(output my_transaction tr)

peek_port

peek

get_peek_port

get和peek

transport_port

transport(my_transaction req, output my_transaction rsp)

nonblocking

put_port

try_put,can_put

函数体内部应体现“非阻塞功能”,实现只能是function

get_port

try_get,can_get

peek_port

try_peek,can_peek

get_peek_port

try_get,can_get,

try_peek,can_peek

transport_port

nb_transport

二者兼具

put_port

put,try_put,can_put

get_port

get,try_get,can_get

peek_port

peek, try_peek, can_peek

get_peek_port

get, try_get, can_get,

peek, try_peek, can_peek

transport_port

transport, nb_transport

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值