- 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函数源码进行说明。
- function new(string name, uvm_component parent, int min_size=1, int 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 |