电子说
TLM是transaction Level Modeling(事务级建模)的缩写。简单来说,一个transaction就是把具有某一特定功能的一组信息封装在一起而成为的一个类。
如何要在两个uvm_component之间通信,例如实现monitor和scoreboard通信,最简单的方法就是使用全局变量,在monitor里对此全局变量进行赋值,在scoreboard里监测此全局变量值的改变。
这种方法简单、直接,不过要避免使用全局变量,滥用全局变量只会造成灾难性的后果。
由config机制的特性可以想出另一种方法来,即从uvm_object派生出一个参数类config_object,在此类中有monitor要传给scoreboard的变量。在base_test中,实例化这个config_object,并将其指针通过config_db#(config_object)::set传递给scoreboard和monitor。
当monitor要和scoreboard通信时,只要把此config_object中相应变量的值改变即可。scoreboard中则监测变量值的改变,监测到之后做相应动作。但是一是要引入一个专门的config_object类,二是一定要有base_test这个第三方的参与。永远不能保证某一个从base_test派生而来的类会不会改变这个config_object类中某些变量的值。
TLM通信中有如下几个常用的术语:
1)put操作,通信的发起者A把一个transaction发送给B。。A具有的端口(用方框表示)称为PORT,而B的端口(用圆圈表示)称为EXPORT。这个过程中,数据流是从A流向B的。
2)get操作,A向B索取一个transaction。A上的端口依然是PORT,而B上的端口依然是EXPORT。这个过程中,数据流是从B流向A的。到这里,读者应该意识到,PORT和EXPORT体现的是控制流而不是数据流。
3)transport操作,A上的端口依然是PORT,而B上的端口依然是EXPORT。A依然是“发起者”,B依然是“目标”。在这个过程中,数据流先从A流向B,再从B流向A。在现实世界中,相当于是A向B提交了一个请求(request),而B返回给A一个应答(response)。所以这种transport操作也常常被称做request-response操作。
put、get和transport操作都有阻塞和非阻塞之分。
PORT与EXPORT
PORT具有高优先级,而EXPORT具有低优先级。只有高优先级的端口才能向低优先级的端口发起三种操作
UVM提供对TLM操作的支持,在其中实现了PORT与EXPORT。对应于不同的操作,有不同的PORT,UVM中常用的PORT有
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);//peek系列端口,它们与get系列端口类似,用于主动获取数据
uvm_blocking_get_peek_port#(T);
uvm_nonblocking_get_peek_port#(T);
uvm_get_peek_port#(T);//集合了get操作和peek操作两者的功能
uvm_blocking_transport_port#(REQ, RSP);
uvm_nonblocking_transport_port#(REQ, RSP);
uvm_transport_port#(REQ, RSP);
这15个端口中前12个定义中的参数就是这个PORT中的数据流类型,而最后3个定义中的参数则表示transport操作中发起请求时传输的数据类型和返回的数据类型
TLM中的操作,同时以blocking和nonblocking关键字区分。对于名称中不含这两者的,则表示这个端口既可以用作是阻塞的,也可以用作是非阻塞的,否则只能用于阻塞的或者只能用于非阻塞的。
下面的15种EXPORT定义与前面的15种PORT一一对应
来源:UVM源代码
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 是发起者),那么可以这么写:A.port.connect(B.export),但是不能写成B.export.connect(A.port),只有发起者才能调用connect 函数。
举例,A的代码为
文件:src/ch4/section4.2/4.2.1/A.sv3
class A extends uvm_component;
`uvm_component_utils(A)
uvm_blocking_put_port#(my_transaction) A_port;
endclass14
function void
A::build_phase(uvm_phase phase);
super.build_phase(phase);
A_port = new("A_port", this);
endfunction19
task A::main_phase(uvm_phase phase);
endtask
接一个EXPORT。B的代码为
文件:src/ch4/section4.2/4.2.1/B.sv3
class B extends uvm_component;
`uvm_component_utils(B)
uvm_blocking_put_export#(my_transaction) B_export;
…endclass
function void B::build_phase(uvm_phase phase);
super.build_phase(phase);
B_export = new("B_export", this);
endfunction19
task B::main_phase(uvm_phase phase);
endtask
在env中建立两者之间的连接:
文件:src/ch4/section4.2/4.2.1/my_env.sv4
class my_env extends uvm_env;
A A_inst;
B B_inst;
…
virtual function void build_phase(uvm_phase phase);
…
A_inst = A::type_id::create("A_inst", this);
B_inst = B::type_id::create("B_inst", this);
endfunction
…
endclass
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(B_inst.B_export);
endfunction
全部0条评论
快来发表一下你的评论吧 !