UVM TLM通信之端口的互联
PORT与EXPORT的连接
如图所示,ABCD四个端口, 要在A和B之间、C和D之间通信。为了实现这个目标,必须要在A和B之间、C和D之间建立一种连接关系,否则的话,A如何知道是和B通信而不是和C或者D通信呢?所以一定要在通信前建立连接关系。
如A要和B通信(A是发起者),那么可以这么写:A.port.connect(B.export),但是不能写成B.export.connect(A.port)。因为在通信的过程中,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
其中A_port在实例化的时候第一个参数是名字,而第二个参数则是一个uvm_component类型的父结点变量
。
B的代码类同A,在env中建立两者之间关系的连接如下:
class my_env extends uvm_env;
A A_inst;
B B_inst;
...
virtual function void build_phase(uvm_phase phase);
super.build_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
注:PORT和EXPORT恰如一道门,它们只是一个通行的作用,它不可能把一笔transaction存储下来,没有存储作用,除了转发操作之外不作其他操作。因此,这笔transaction一定要由B_export后续的某个组件进行处理。在UVM中,完成这种后续处理的也是一种端口:IMP。
PORT和IMPORT的连接
有了IMP之后,之前的PORT与EXPORT之间的连接就可以实现了。下图为component在连接中的作用
A和B的代码为:
class A extends uvm_component;
`uvm_component_utils(A)
uvm_blocking_put_port#(my_transaction) A_port;
...
endclass
...
task A::main_phase(uvm_phase phase);
my_transaction tr;
repeat(10) begin
#10;
tr = new("tr");
assert(tr.randomize());
A_port.put(tr);
end
endtask
//------------------------------------------------------------------------------------------
class B extends uvm_component;
`uvm_component_utils(B)
uvm_blocking_put_export#(my_transaction) B_export;
uvm_blocking_put_imp#(my_transaction, B) B_imp;
...
endclass
function void B::connect_phase(uvm_phase phase);
super.connect_phase(phase);
B_export.connect(B_imp);
endfunction
function void B::put(my_transaction tr);
`uvm_info("B", "receive a transaction", UVM_LOW)
tr.print();
endfunction
在B的代码中,关键是要实现一个put函数/任务。如果不实现,将会给出错误提示
在UVM中,只有IMP才能作为连接关系的终点。如果是PORT或者EXPORT作为终点,则会报错。
A_port的put操作最终要落到B的put上。所以在B中要定义一个名字为put的任务/函数。
当B中完成B_imp和put的定义后,在env的connect_phase就需要把Aport和B_imp连接在一起了:
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(B_inst.B_imp);
endfunction
EXPORT和IMP的连接
PORT可以与IMP相连接,同样的EXPORT也可以与IMP相连接,其连接方法与PORT和IMP的连接完全一样。之前完成了EXPORT与IMP的连接,不过在那个连接中EXPORT只是作为中间环节,这里把EXPORT作为连接的起点。
除了A_port变成B_export之外,其他没有任何改变。在B中也必须定义一个名字为put的任务。
PORT和PORT的连接
在之前的连接中,都是不同类型的端口之间连接(PORT与IMP、PORT与EXPORT、EXPORT与IMP),且不存在层次的关系。在UVM中,支持带层次的连接关系,
在上图中,A与C中是PORT,B中是IMP。UVM支持C的PORT连接到A的PORT,并最终连接到B的IMP。
C和A的代码如下:
class C extends uvm_component;
`uvm_component_utils(C)
uvm_blocking_put_port#(my_transaction) C_port;
...
endclass
task C::main_phase(uvm_phase phase);
my_transaction tr;
repeat(10) begin
#10;
tr = new("tr");
assert(tr.randomize());
C_port.put(tr);
end
endtask
//-------------------------------------------------------------------------------------------
class A extends uvm_component;
`uvm_component_utils(A)
C C_inst;
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);
C_inst = C::type_id::create("C_inst", this);
endfunction
function void A::connect_phase(uvm_phase phase);
super.connect_phase(phase);
C_inst.C_port.connect(this.A_port);
endfunction
task A::main_phase(uvm_phase phase);
endtask
其他代码仅需修改端口类型,其他均相同;
PORT与PORT之间的连接不只局限于两层,可以有无限多层。
EXPORT和EXPORT的连接
在下图中,A中是PORT,B与C中是EXPORT,B中还有一个IMP。UVM支持C的EXPORT连接到B的EXPORT,并最终连接到B的IMP。
A、B代码同前,C的代码和env代码如下:
class C extends uvm_component;
`uvm_component_utils(C)
B B_inst;
uvm_blocking_put_export#(my_transaction) C_export;
...
endclass
function void C::build_phase(uvm_phase phase);
super.build_phase(phase);
C_export = new("C_export", this);
B_inst = B::type_id::create("B_inst", this);
endfunction
function void C::connect_phase(uvm_phase phase);
super.connect_phase(phase);
this.C_export.connect(B_inst.B_export);
endfunction
task C::main_phase(uvm_phase phase);
endtask
//-------------------------------------------------------------------------------------------
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(C_inst.C_export);
endfunction
同样的,EXPORT与EXPORT之间的连接也不只局限于两层,也可以有无限多层。
这篇笔记参考《UVM实战》、《芯片验证漫游指南》和某验证视频整理而成,仅作学习心得交流,如果涉及侵权烦请请告知,我将第一时间处理。