目录
一、概述(目前工作中大多数应用场景都是单向通信)
单向通信指的是从initiator到target之间的数据流向是单一方向的,或者说initiator和target只能扮演producer和consumer中的一个角色。
在UVM中,单一数据流向的TLM端口有很多类型:
uvm_blocking_put_PORT
uvm_nonblocking_put_PORT
uvm_put_PORT
uvm_blocking_get_PORT
uvm_nonblocking_get_PORT
uvm_get_PORT
uvm_blocking_peek_PORT
uvm_nonblocking_peek_PORT
uvm_peek_PORT
uvm_blocking_get_peek_PORT
uvm_nonblocking_get_peek_PORT
uvm_get_peek_PORT
其中PORT代表了三种端口名:port、export、imp。
按照UVM端口名的命名规则,它们指出了通信的两个要素:
- 是否是阻塞的方式(即可以等待延时)
- 是哪一种通信方法 (initiator要调用target端声明的方法)
下面是put 和 get的具体区别:
peek和get流向一样,只不过没把数据从buff中拿过来,并没有把数据从buff中移除掉。
二、方法
阻塞传输方式将blocking前缀作为函数名的一部分,而非阻塞方式则名为nonblocking。阻塞端口的方法类型为task,这保证了可以实现事件等待和延时,非阻塞端口的方式类型为function,保证了方法调用可以立即返回。
blocking阻塞传输的方法:
- put():initiator先生成数据T t,同时将该数据传送至target。
- get():initiator从target获取数据T t,而target中的该数据T t则应消耗。
- peek():initiator从target获取数据T t,而target中的该数据T t还应保留。
nonblocking非阻塞传输方法:
- try_put()
- can_put()
- try_get()
- can_get()
- try_peek()
- can_peek()
三、示例
class itrans extends uvm_transaction;
int id;
int data;
...
endclass
class otrans extends uvm_transaction;
int id;
int data;
...
endclass
class comp1 extends uvm_component;
uvm_blocking_put_port #(itrans) bp_port; // #(itrans)是声明的参数类型
uvm_nonblocking_get_port #(otrans) nbg_port;
`uvm_component_utils(comp1)
...
task run_phase(uvm_phase phase);
itrans itr;
otrans otr;
int trans_num = 2;
fork
//************* fork 中用了两个线程***************
begin
for(int i = 0; i < trans_num; i++) begin
itr = new("itr", this);
itr.data = 'h10 + i;
this.bp_port.put(itr);
//目前只知道发送transaction,但不知道往哪个组件发送
//也看不出是调用组件2中的put方法
`uvm_info("PUT", $sformatf("put itrans id: 'h%0x, data: 'h%0x", itr.id, itr.data), UVM_LOW)
end
end
begin
for(int j = 0; j < trans_num; j++) begin
forever begin
if(this.nbg_port.try_get(otr) == 1) break;
else #1ns;
end
`uvm_info("TRYGET", $sformatf("get otrans id: 'h%0x, data: 'h%0x", otr.id, otr.data), UVM_LOW)
end
end
join
endtask
endclass
class comp2 extends uvm_component;
uvm_blocking_put_imp #(itrans, comp2) bp_imp;
uvm_nonblocking_get_imp #(otrans, comp2) nbg_imp;
itrans itr_q[$];
`uvm_component_utils(comp2)
...
task put(itrans t);
itr_q.push_back(t);
endtask
function bit try_get(output otrans t);
itrans i;
if(itr_q.size() != 0) begin
i = itr_q.pop_front();
t = new("t", this);
t.id = i.id;
t.data = i.data << 8;
return 1;
end
else return 0;
endfunction
function bit can_get();
if(itr_q.size() != 0) return 1;
else return 0;
endfunction
endclass
class env1 extends uvm_env;
comp1 c1;
comp2 c2;
`uvm_component_utils(env1)
...
function void build_phase(uvm_phase phase);
super.build_phase(phase);
c1 = comp1::type_id::create("c1", this);
c2 = comp2::type_id::create("c2", this);
endfunction
function void connect_phase(uvm_phase phase);
super.connect_phase(phase);
c1.bp_port.connect(c2.bp_imp);
c1.nbg_port.connect(c2.nbg_imp);
endfunction
endclass
四、总结(重要)
- 要知道接下来的传输类型是什么
- 在接两个组件声明的接口要对应,即组件1和组件2的接口都是blocking_put_port 或者都是 nonblocking_get_port 。。传输的数据类型也要一致。
- 在target一侧实现put 、try_get 、can_get
- 在顶层环境将对应的port和imprt连接起来,注意连接的政策是initiator , 右侧是target。