UVM基础-TLM机制之analysis端口与FIFO

  • TLM的analysis端口与FIFO

1 analysis端口

       除了port,export,imp之外,TLM还提出了另一种端口,analysis类型的端口,analysis类型的端口也会区分port,export,imp。Analysis端口与所描述的端口的差异,主要体现在两个方面:

  1. 一个analysis_port/analysis_export可以连接多个analysis_imp,实现一对多的连接,并且动作发起者通过广播的方式,将数据写到与之相连的全部imp上。
  2. analysis端口的操作不区分阻塞和非阻塞,因为是广播操作,因此只存在非阻塞的场景。
  3. analysis端口的广播操作通过write函数实现,且没有其他多余的操作函数(put,try_put,can_put等),因此,需要在被动接受者的主体内部实现write函数。

analysis端口的互联如图4.1.1所示。

 

图4.1.1 analysis端口之间的连接关系

其他特性,与常规的port,export,imp类似,一个uvm_analysis_port与uvm_analysis_export连接会报错,终点必须是uvm_analysis_imp,uvm_analysis_port,uvm_analysis_export,uvm_analysis_imp都是参数化类,且参数与常规的port,export,imp一致。

写段代码感受下:

组件A:

1.	class a extend uvm_component;
2.	      `uvm_component_utils(a)
3.	      uvm_analysis_port# (my_tr) a_ap;
4.	......
5.	       extern function void build_phase(uvm_phase phase);
6.	......
7.	endclass
8.	
9.	function void a::build_phase(uvm_phase phase);
10.	      super.build_phase(phase);
11.	      a_ap = new("a_ap", this);
12.	......
13.	endfunction:build_phase

 组件B:

1.	class b extend uvm_component;
2.	      `uvm_component_utils(b)
3.	      uvm_analysis_export# (my_tr) b_aep;
4.	      uvm_analysis_imp#(my_tr, b) b_aimp;
5.	......
6.	       extern function void build_phase(uvm_phase phase);
7.	       extern function void connect_phase(uvm_phase phase);
8.	       extern function void write(my_tr tr);
9.	......
10.	endclass
11.	
12.	function void b::build_phase(uvm_phase phase);
13.	      super.build_phase(phase);
14.	      b_aep   = new("b_aep", this);
15.	      b_aimp = new("b_aimp", this);
16.	......
17.	endfunction:build_phase
18.	
19.	function void b::connect_phase(uvm_phase phase);
20.	      super.connect_phase(uvm_phase phase);
21.	      this.b_aep.connect(this.b_aimp);
22.	......
23.	endfunction:connect_phase
24.	
25.	function void b::write(my_tr tr);
26.	      //do something on tr
27.	endfunction:write

组件B因为是动作的被动接受者,因此其中有write函数,组件C与组件B类似,不在赘述。

TOP代码,体现连接关系:

1.	class TOP extend uvm_component;
2.	      `uvm_component_utils(TOP)
3.	      a my_a;
4.	      b my_b;
5.	      c my_c;
6.	......
7.	       extern function void build_phase(uvm_phase phase);
8.	       extern function void connect_phase(uvm_phase phase);
9.	......
10.	endclass
11.	
12.	function void TOP::build_phase(uvm_phase phase);
13.	      super.build_phase(phase);
14.	      my_a = a::type_id::create("my_a", this);
15.	      my_b = b::type_id::create("my_b", this);
16.	      my_c = c::type_id::create("my_c", this);
17.	......
18.	endfunction:build_phase
19.	
20.	function void b::connect_phase(uvm_phase phase);
21.	      super.connect_phase(uvm_phase phase);
22.	      this.my_a.a_ap.connect(this.my_b.b_aep);
23.	      this.my_a.a_ap.connect(this.my_c.c_aep);
24.	......
25.	endfunction:connect_phase

与常规的port,export类似,analysis类型的端口同样会遇到需要跨层次连接的情况,此类场景与常规port,export的连接关系相同,以agent组件为例,此处给出总结:

  1. 可以通过在agent组件中声明且实例化analysis port,在connect phase中由内向外连接到agent的analysis port(analysis export是由外向内连接)
  2. 可以通过在agent组件中声明analysis port或者export,不进行实例化,在connect phase中将内层次的port或者export的直接赋值给agent组件的analysis port或者export。
  3. 在agent中不声明也不例化,在TOP层的connect phase中,通过跨层次连接,直接将动作发起者的analysis port连接至被动接受者的analysis export或者analysis imp

 

2 基于FIFO的通信

       整个TLM机制下,底层逻辑离不开动作发起者和被动接受者这个底层的模型基础,但实际上,在验证环境中,任何一个组件,都有可能成为动作的发起者,都有可能主动发起命令,且只有掌握主动权,才能更灵活的控制数据的流通,因此TLM机制下,实际用的最多的组件,也就是基于FIFO的数据通信。

2.1 FIFO上的端口类型

       想象一下,如果两个通信的组件都是动作发起者,也就是说在发送组件需要发送数据的时候发送数据,在接受组件想要接受数据的时候接受,且还可以提供数据的暂存服务,此时FIFO可以很好的实现这个功能,FIFO可以作为整个通信过程的被动接受者而存在,如图4.2.1所示。

 

图4.2.1 基于FIFO的通信

       FIFO上存在的端口如表4.2.1所示:

表4.2.1 FIFO上的端口

端口名

说明

属性

blocking_put_export

阻塞put操作

IMP

nonblocking_put_export

非阻塞put操作

IMP

put_export

阻塞/非阻塞put操作

IMP

blocking_get_export

阻塞get操作

IMP

nonblocking_get_export

非阻塞get操作

IMP

get_export

阻塞/非阻塞get操作

IMP

blocking_peek_export

阻塞peek操作

IMP

nonblocking_peek_export

非阻塞peek操作

IMP

peek_export

阻塞/非阻塞peek操作

IMP

blocking_get_peek_export

阻塞get/peek操作

IMP

nonblocking_get_peek _export

非阻塞get/peek操作

IMP

get_peek_export

阻塞/非阻塞get/peek操作

IMP

analysis_export

analysis

analysis imp

put_ap

analysis型

analysis port

get_ap

analysis

analysis port

       在UVM TLM通信中,FIFO一共由两种类型,一是uvm_tlm_analysis_fifo #(my_transaction);另一个是uvm_tlm_fifo#(my_transaction)。两者的区别是,带analysis的fifo比不带analysis的fifo多了一个analysis_export。

       看了表4.2.1,会产生一个问题,就是FIFO作为被动接受者,其上面的端口类型应该是imp才对,其实,TLM机制为了掩饰掉imp类型的端口,让用户对其不可见,在FIFO的端口声明中增加了export字样,实际上FIFO上的这些export的类型其实是IMP类型,正如表4.2.1属性列所示,读者也可以查阅FIFO的UVM源码可以获得答案。

       此处说明peek操作和get操作的差异,peek操作,FIFO在完成一次数据的发送时,会在本地保留一份,而get操作则不会保留。

如图4.2.2所示FIFO上的端口:

 

图4.2.2 FIFO上的端口

2.2 FIFO上的操作及FIFO自身函数、FIFO深度

FIFO作为动作的被动接受者,其上面理应会存在相应类型的操作函数,实际上,当一个port或者export与FIFO相连时,会调用FIFO上的操作函数,以put操作为例,当一个uvm_blocking_put_port/export与FIFO上的blocking_put_export相连时,put操作会调用FIFO上的put函数;当一个uvm_blocking_get_port/export与FIFO上的blocking_get_export相连时,get操作会调用FIFO上的get函数。put操作会将发来的数据包存在FIFO缓存中,FIFO的缓存是通过system verilog 的mailbox实现的。get操作会将FIFO的缓存包发走。此外,FIFO上还具备try_put,can_put,try_get,can_get等等一系列操作,此处不再赘述。

       UVM TLM FIFO对操作做了很好的封装,因此用户不需要再纠结是否需要在组件中自己写操作函数,因此极大程度上提高了代码开发效率。

       FIFO的内置函数:

  • used函数返回FIFO中存在的数据包个数
  • is_empty函数用于判断FIFO是否为空
  • is_full函数用于判断FIFO是否为满
  • flush函数用于清空FIFO

FIFO的大小,对于uvm_tlm_fifo来讲,存在大小限制,在FIFO的new函数中可以体现:

  1. function new(string name, uvm_component parent=null, int size=1);

可以看到,FIFO new函数的第三个参数,实际上是FIFO的大小,默认大小为1,当size值设为0时,FIFO深度定义为无限大。而对于uvm_tlm_analysis_fifo而言,其大小默认只能是无限大,也就不存在new函数中的第三个参数。

 

2.3 基于FIFO的实训

       在实际项目中,组件间的通讯用的最多的还是FIFO,使用FIFO可以让用户不再纠结操作函数的开发,以及组件是动作发起者还是被动接受者等角色而引入开发的难度,甚至可以忽略IMP类型的端口,直接在组件上开发port或者export,在env或者高层组件中实例化FIFO,并连接FIFO上的对应端口,即可完成组件之间的通信。且FIFO还支持循环多例化和多连接,减少了一个组件包含多个imp,还要使用`uvm_analysis_imp_decl(_xxx)来指明到底是哪个组件对应的imp,极大化简了代码,增强了可读性。

       以一个具体的通讯实例为主,开发代码,环境框图如图4.2.3.1所示:

 

图4.2.3.1 代码实训框图

RM代码:

1.	class my_mdl extend uvm_component;
2.	.......
3.	       uvm_blocking_put_port #(my_tr) mdl_port;
4.	       `uvm_component_utils(my_mdl)
5.	
6.	       extend function new(string name = "my_mdl", uvm_component parent);
7.	       extend virtual function void build_phase(uvm_phase phase);
8.	       extend virtual function void connect_phase(uvm_phase phase);
9.	......
10.	       extend virtual task main_phase(uvm_phase phase);
11.	......
12.	endclass
13.	
14.	function my_mdl::new(string name="my_mdl", uvm_component parent);
15.	      super.new(name);
16.	endfunction:new
17.	
18.	function void my_mdl::build_phase(uvm_phase phase);
19.	      super.build_phase(phase);
20.	......
21.	      mdl_port  = new("mdl_port", this);
22.	endfunction:build_phase
23.	
24.	......

 

RM中例化port。

Scoreboard代码:

1.	class my_scb extend uvm_scoreboard;
2.	.......
3.	       uvm_blocking_get_port #(my_tr) scb_port;
4.	       `uvm_component_utils(my_scb)
5.	
6.	       extend function new(string name = "my_scb", uvm_component parent);
7.	       extend virtual function void build_phase(uvm_phase phase);
8.	       extend virtual function void connect_phase(uvm_phase phase);
9.	......
10.	       extend virtual task main_phase(uvm_phase phase);
11.	......
12.	endclass
13.	
14.	function my_scb::new(string name="my_scb", uvm_component parent);
15.	      super.new(name);
16.	endfunction:new
17.	
18.	function void my_scb::build_phase(uvm_phase phase);
19.	      super.build_phase(phase);
20.	......
21.	      scb_port  = new("scb_port", this);
22.	endfunction:build_phase
23.	
24.	...... 

env代码:

1.	class my_env extend uvm_env;
2.	      my_mdl   mdl;
3.	      my_scb   scb;
4.	      uvm_tlm_analysis_fifo #(my_tr)   rm2scb_fifo;
5.	
6.	      `uvm_component_utils(my_env)
7.	      
8.	      extern function new(string name="my_env", uvm_component parent);
9.	      extern virtual function void build_phase(uvm_phase phase);
10.	      extern virtual function void connect_phase(uvm_phase phase);
11.	......
12.	      extern virtual task main_phase(uvm_phase phase);
13.	......
14.	endclass
15.	
16.	function my_env::new(string name="my_env", uvm_component parent);
17.	      super.new(name);
18.	endfunction:new
19.	
20.	function void my_env::build_phase(uvm_phase phase);
21.	      super.build_phase(phase);
22.	      mdl = my_mdl::type_id::create("mdl", this);
23.	      scb  = my_scb::type_id::create("scb", this);
24.	      rm2scb_fifo = new("rm2scb_fifo", this);
25.	endfunction:build_phase
26.	
27.	function void my_env::connect_phase(uvm_phase phase);
28.	      super.connect_phase(phase);
29.	      this.mdl.mdl_port.connect(rm2scb_fifo.blocking_put_export);
30.	      this.scb.scb_port.connect(rm2scb_fifo.blocking_get_export);
31.	......
32.	endfunction:connect_phase
33.	......

        这里的代码实例化FIFO以及连接的时候,没有使用for循环去例化,有点偷懒,读者可以自行补充这种情况的代码。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值