LTM通信有三种常用的操作:put操作、get操作和transport操作。其中发起者具有的端口是PORT,接收者具有的端口是EXPORT。这三种操作都有阻塞与非阻塞之分。
常用的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);
常用的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#(T,IMP);
uvm_get_peek_imp#(T,IMP);
uvm_blocking_transport_imp#(REQ,RSP,IMP);
uvm_nonblocking_transport_imp#(REQ,RSP,IMP);
uvm_transport_imp#(REQ,RSP,IMP);
PORT具有高优先级,EXPORT具有中优先级,IMP具有最低优先级,只有高优先级的端口才能向低优先级的端口发起上述三种操作。
UVM中使用connect函数建立连接关系,如A要与B通信,这么写:A.port.connect(B.export),写成B.export.connect(A.port)是错误的,因为A是发起者,B是被动承担者,主次顺序一定要对。例子如下:
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);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
A_port.put(tr);//发送tr数据包
endtask
B的代码:
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::build_phase(uvm_phase phase);
super.build_phase(phase);
B_export = new("B_export",this);
B_imp = new("B_imp",this);
endfunction
function void B::connect_phase(uvm_phase phase);
super.build_phase(phase);
B_export.connect(B_imp) ;
endfunction
function void B::put(my_transaction tr);
tr.print();
endfunction
在env中建立起两者的连接:
class my_env extends uvm_env;
A A_inst;
B B_inst;
endclass
function void my_env::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
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(B_inst.B_export);
endfunction
在上述连接关系中,IMP是连接的终点,也只有IMP才能作为连接的终点,PORT或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);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
A_port.put(tr);//发送tr数据包
endtask
B的代码:
class B extends uvm_component;
`uvm_component_utils(B);
uvm_blocking_put_imp#(my_transaction,B) B_imp;//定义端口类型
endclass
function void B::build_phase(uvm_phase phase);
super.build_phase(phase);
B_imp = new("B_imp",this);
endfunction
function void B::put(my_transaction tr);
tr.print();
endfunction
在env中建立起两者的连接:
```typescript
class my_env extends uvm_env;
A A_inst;
B B_inst;
endclass
function void my_env::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
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(B_inst.B_imp);
endfunction
A的代码:
class A extends uvm_component;
`uvm_component_utils(A);
uvm_blocking_put_export#(my_transaction) A_export;//定义端口类型
endclass
function void A::build_phase(uvm_phase phase);
super.build_phase(phase);
A_export = new("A_export",this);//例化端口
endfunction
task A::main_phase(uvm_phase phase);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
A_export.put(tr);//发送tr数据包
endtask
B的代码:
class B extends uvm_component;
`uvm_component_utils(B);
uvm_blocking_put_imp#(my_transaction,B) B_imp;//定义端口类型
endclass
function void B::build_phase(uvm_phase phase);
super.build_phase(phase);
B_imp = new("B_imp",this);
endfunction
function void B::put(my_transaction tr);
tr.print();
endfunction
在env中建立起两者的连接:
class my_env extends uvm_env;
A A_inst;
B B_inst;
endclass
function void my_env::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
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_export.connect(B_inst.B_imp);
endfunction
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);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
A_port.put(tr);//发送tr数据包
endtask
B的代码:
class B extends uvm_component;
`uvm_component_utils(B);
A A_inst;
uvm_blocking_put_port#(my_transaction) B_port;//定义端口类型
endclass
function void B::build_phase(uvm_phase phase);
super.build_phase(phase);
A_inst = A::type_id::create("A_inst",this);
B_port = new("B_port",this);
endfunction
function void B::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(this.B_port);
endfunction
task B::main_phase(uvm_phase phase);
endtask
C的代码:
class C extends uvm_component;
`uvm_component_utils(C);
uvm_blocking_put_imp#(my_transaction,C) C_imp;//定义端口类型
endclass
function void C::build_phase(uvm_phase phase);
super.build_phase(phase);
C_imp = new("C_imp",this);
endfunction
function void C::put(my_transaction tr);
tr.print();
endfunction
在env中建立起两者的连接:
class my_env extends uvm_env;
B B_inst;
C C_inst;
endclass
function void my_env::build_phase(uvm_phase phase);
super.build_phase(phase);
B_inst = B::type_id::create("B_inst",this);
C_inst = C::type_id::create("C_inst",this);
endfunction
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
B_inst.B_port.connect(C_inst.C_imp);
endfunction
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);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
A_port.put(tr);//发送tr数据包
endtask
B的代码:
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::build_phase(uvm_phase phase);
super.build_phase(phase);
B_export = new("B_export",this);
B_imp = new("B_imp",this);
endfunction
function void B::connect_phase(uvm_phase phase);
super.build_phase(phase);
B_imp = new("B_export",this);
B_imp = new("B_imp",this);
this.B_export.connect(this.B_imp);
endfunction
function void B::put(my_transaction tr);
tr.print();
endfunction
C的代码:
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 B::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
在env中建立起两者的连接:
class my_env extends uvm_env;
A A_inst;
C C_inst;
endclass
function void my_env::build_phase(uvm_phase phase);
super.build_phase(phase);
A_inst = A::type_id::create("A_inst",this);
C_inst = C::type_id::create("C_inst",this);
endfunction
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(C_inst.C_export);
endfunction
get系列端口与put系列端口在某些方面完全相反,如数据流方向与put端口正好相反,例子如下:
A的代码:
class A extends uvm_component;
`uvm_component_utils(A);
uvm_blocking_get_export#(my_transaction) A_export;//定义端口类型
uvm_blocking_get_imp#(my_transaction,A) A_imp;//定义端口类型
endclass
function void A::build_phase(uvm_phase phase);
super.build_phase(phase);
A_export = new("A_export",this);//例化端口
A_imp = new("A_imp",this);//例化端口
endfunction
function void A::connect_phase(uvm_phase phase);
super.build_phase(phase);
A_export.connect(A_imp);
endfunction
task A::get(output my_transaction tr);
while(tr_q.size() == 0);
tr = tr_q.pop_front();
endtask
task A::main_phase(uvm_phase phase);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
tr_q.push_back(tr);//tr数据包存入队列中
endtask
B的代码:
class B extends uvm_component;
`uvm_component_utils(B);
uvm_blocking_put_port#(my_transaction) B_port;//定义端口类型
endclass
function void B::build_phase(uvm_phase phase);
super.build_phase(phase);
B_port = new("B_port",this);
endfunction
task B::main_phase(uvm_phase phase);
my_transaction tr;
while(1)begin
B_port.get(tr);
tr.print();
end
endtask
在env中建立起两者的连接:
class my_env extends uvm_env;
A A_inst;
B B_inst;
endclass
function void my_env::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
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
B_inst.B_port.connect(A_inst.A_export);
endfunction
与put和get系列端口的单向通信不同,transport系列端口通信是双向的,例子如下:
A的代码:
class A extends uvm_component;
`uvm_component_utils(A);
uvm_blocking_transport_port#(my_transaction,my_transaction) A_transport;//定义端口类型
endclass
function void A::build_phase(uvm_phase phase);
super.build_phase(phase);
A_transport = new("A_transport",this);//例化端口
endfunction
task A::main_phase(uvm_phase phase);
my_transaction tr;
my_transaction rsp;
tr = new("tr");
assert(tr.randomize());
A_transport.transport(tr,rsp);
rsp.print();
endtask
B的代码:
class B extends uvm_component;
`uvm_component_utils(B);
uvm_blocking_transport_imp#(my_transaction,my_transaction,B) B_imp;//定义端口类型
endclass
function void B::build_phase(uvm_phase phase);
super.build_phase(phase);
B_imp = new("B_imp",this);
endfunction
task B::transport(my_transaction req,my_transaction rsp);
req.print();
rsp = new("rsp");
endtask
在env中建立起两者的连接:
class my_env extends uvm_env;
A A_inst;
B B_inst;
endclass
function void my_env::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
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_transport.connect(B_inst.B_imp);
endfunction
nonblocking系列端口的所有操作都是非阻塞的,例子如下:
A的代码:
class A extends uvm_component;
`uvm_component_utils(A);
uvm_nonblocking_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);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
while(!A_port.can_put()) ;//等待并判断是否可以执行put操作
A_port.try_put(tr);
endtask
B的代码:
class B extends uvm_component;
`uvm_component_utils(B);
uvm_nonblocking_put_imp#(my_transaction,B) B_imp;//定义端口类型
my_transaction tr_q[$];
endclass
function void B::build_phase(uvm_phase phase);
super.build_phase(phase);
B_imp = new("B_imp",this);
endfunction
function bit B::can_put();
if(tr_q.size() > 0)
return 0;
else
return 1;
endfunction
function bit B::try_put(my_transaction tr);
if(tr_q.size() > 0)
return 0;
else
tr_q.push_back(tr);
return 1;
endfunction
task B::main_phase(uvm_phase phase);
my_transaction tr;
while(1)begin
if(tr_q.size() > 0)
tr = tr_q.pop_front();
end
tr.print();
endtask
在env中建立起两者的连接:
class my_env extends uvm_env;
A A_inst;
B B_inst;
endclass
function void my_env::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
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
A_inst.A_port.connect(B_inst.B_imp);
endfunction