3.UVM中的TLM1.0通信
TLM1.0
1.
如果要在两个uvm_component
之间通信,如一个monitor向一个scoreboard传递一个数据,你可以采用下图中的方法:
当然也可以从uvm_object
派生出一个参数类config_object
,在此类中有monitor要传给scoreboard的变量。在base_test中,实例化这个config_object,并将其指针通过config_db#(config_object)::set
传递scoreboard和monitor。当monitor要和scoreboard通信时,只要把此config_object中相应变量的值改变即可。scoreboar中则监测变量值的改变,监测到之后做相应动作。
但是以上这种方式还是存在风险,即不能保证某一个从base_test派生而来的类会不会改变这个config_object类中某些变量的值,而且还缺少对阻塞和非阻塞情况的考虑。
解决这些问题最好的办法就是在monitor和scoreboard之间专门建立一个通道,让信息只能在这个通道内流动,scoreboard也只能从这个通道中接收信息,这样几乎就可以保证scoreboard中的信息只能从monitor中来,而不能从别的地方来;同时赋予这个通道阻塞或者非阻塞等特性。UVM中的各种端口就可以实现这种功能。
2.
TLM是Transaction Level Modeling(事务级建模)的缩写,一个transaction就是把具有某一特定功能的一组信息封装在一起而成为的一个类。
首先要理解get、put和transport操作,即:
- put:通信的发起者A把一个transaction发送给B;
- get:A向B索取一个transaction;
- transport:一次put操作加一次get操作,即做request - response操作。
3.
UVM通过端口PORT和EXPORT来实现对TLM的支持,常用的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);
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);
UVM中端口互连
1.
UVM中使用connect
函数来建立端口的连接,如A要和B通信(A是发起者),那么可以这么写:
A.port.connect(B.export)
注意顺序,A是发起者,B是被动承担者。只有发起者才能调用connect函数,而被动承担者则作为connect的参数。
使用上述方式建立A.PORT和B.EXPORT之间的连接关系。A的代码为:
class A extends uvm_component;
`uvm_component_utils(A)
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);
endfunction
task A::main_phase(uvm_phase phase);
endtask
B的代码为:
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);
endfunction
task B::main_phase(uvm_phase phase);
endtask
在env中建立两者之间的连接:
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
但是仿真会报错,因为这里只是完成了端口的连接,但是并没有对transaction进行处理,PORT和EXPORT只是个闸口,而在EXPORT端口之后的处理才是重点,而完成这种后续处理的端口叫做IMP。
2.
UVM中的IMP有:
uvm_blocking_put_imp#(T, IMP);
uvm_nonblocking_put_imp#(T, IMP);
uvm_put_imp#(T, IMP);
uvm_blocking_get_imp#(T, IMP);
uvm_nonblocking_get_imp#(T, IMP);
uvm_get_imp#(T, IMP);
uvm_blocking_peek_imp#(T, IMP);
uvm_nonblocking_peek_imp#(T, IMP);
uvm_peek_imp#(T, IMP);
uvm_blocking_get_peek_imp#(T, IMP);
uvm_nonblocking_get_peek_imp#