学习目标
UVM入门和进阶部分5
学习内容
1.TLM是一种基于事务的通信方式,将模块内的计算和模块之间的通信从时间跨度方面剥离开了
2.提高系统模型的仿真性能,两方面:建模自身的运算优化、模型之间的通信优化
3.TLM通信的两个通信对象:
initiator/target:通信请求方、通信响应方
producer/consumer:数据产生、数据流向
4.TLM通信步骤:
分辨出initiator/target和producer/consumer
在target中实现TLM通信方法
在两个对象中创建TLM端口
在更高层次中将两个对象的端口进行连接
5.从数据流向来看,传输方向可以分为单向和双向
6.端口类型划分为三种:
port----经常作为initiator的发起端,initiator凭借port才可以访问target的TLM通信方法
export—作为initiator/target中间层次的端口
imp—只能作为target接收request的末端
7.port/export作为request发起方,需要指定transaction类型参数,而声明imp作为request接收方,不但需要指定transaction类型,也需要指定它所在的component类型
8.建立TLM通信的详细步骤:
定义TLM传输中的数据类型
分别在各个层次的component中声明和创建TLM端口对象
通过connect()函数完成端口之间的连接
在imp端口类中实现需要提供给initiator的可调方法
9.阻塞端口的方法类型为task,这保证了可以实现事件等待和延时
非阻塞端口的方式类型为function,这确保了方法调用可以立即返回
10.blocking阻塞传输的方法包含:
put():initiator先生成数据T t,同时将该数据传送至target
get():initiator从target获取数据,而target中的该数据则应消耗
peek():initiator从target获取数据,而target中的该数据则应保留
try_put()、can_put()、try_get()、can_get()、try_peek()、can_peek()
try_xxx函数可以发送或者获取数据,执行成功返回1,失败返回0
can_xxx函数,先试探target是否可以接收数据,如果可以,再通过try_xxx发送,提高数据发送的成功率
11.单向通信示例:(不懂看视频)
class itrans extends uvm_transaction;
int id;
int data;
...
endclass
class otans extends uvm_transaction;
int id;
int data;
...
endclass
class comp1 extends uvm_component;
uvm_blocking_put_port #(itrans) bp_port;
uvm_nonblocking_get_port #(otrans) nbg_port;
'uvm_component_utils(comp1)
...
task run_phase(uvm_phase phase)
itrans itr;
otraans otr;
int trans_num=2;
fork
begin
for(int i=0;i<trans_num;i++) begin
itr=new("itr",this);
itr.id=i;
itr.data='h10+i;
this.bp_port.put(itr);
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
end
join
class comp2 extends uvm_component;
uvm_blocking_put_imp #(itrans,comp2) bp_port;
uvm_nonblocking_get_imp #(otrans,comp2) nbg_port;
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;
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);
c2.nbg_port.connect(c2.nbg_imp);
endfunction:connect_phase
endclass
12.双向端口按照通信握手方式可以分为:
transport双向通信方式
master和slave双向通信方式
13.transport端口通过transport()方法,可以在同一方法调用过程中完成REQ和RSP的发出和返回
14.master和slave的通信方式必须分别通过put、get和peek的调用,使用两个方法才可以完成一次握手通信
15.双向通信transport
class itrans extends uvm_transaction;
int id;
int data;
...
endclass
class otans extends uvm_transaction;
int id;
int data;
...
endclass
class comp1 extends uvm_component;
uvm_blocking_transport_port #(itrans,otrans) bt_port;
'uvm_component_utils(comp1)
...
task run_phase(uvm_phase phase)
itrans itr;
otraans otr;
int trans_num=2;
for(int i=0;i<trans_num;i++) begin
itr=new("itr",this);
itr.id=i;
itr.data='h10+i;
this.bp_port.put(itr);
end
endtask
class comp2 extends uvm_component;
uvm_blocking_transport_imp #(itrans,otrans,comp2) bt_imp;
'uvm_component_utils(comp2)
...
task transport(itrans req,output otrans rsp);
rsp=new("rsp",this);
rsp.id=req.id;
rsp.data=req.data<<8;
endtask
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.bt_port.connect(c2.bp_imp);
endfunction:connect_phase
endclass
16.多向通信仍然是两个组件之间的通信
如果initiator和target之间的相同TLM端口数目超过一个时的处理解决方法
17.多向通信
'uvm_blocking_put_imp_decl(_p1)
'uvm_blocking_put_imp_decl(_p2)
class comp1 extends uvm_component;
uvm_blocking_put_port #(itrans) bp_port1;
uvm_blocking_put_port #(itrans) bp_port2;
'uvm_component_utils(comp1)
...
task run_phase(uvm_phase phase)
itrans itr1,itr2;
otraans otr;
int trans_num=2;
fork
for(int i=0;i<trans_num;i++) begin
itr1=new("itr1",this);
itr1.id=i;
itr1.data='h10+i;
this.bp_port1.put(itr1); //这里调用的是put,非put_p1
end
for(int i=0;i<trans_num;i++) begin
itr2=new("itr2",this);
itr2.id=i;
itr2.data='h10+i;
this.bp_port2.put(itr2);
end
join
endtask
enclass
class comp2 extends uvm_component;
uvm_blocking_put_imp_p1 #(itrans,comp2) bt_imp_p1;
uvm_blocking_put_imp_p2 #(itrans,comp2) bt_imp_p2;
itrans itr_q[$];
semaphore key;
'uvm_component_utils(comp2)
...
task put_p1(itrans t); //方法为put_p1
key.get();
itr_q.push_back(t);
key.put();
endtask
task put_p2(itrans t);
key.get();
itr_q.push_back(t);
key.put();
endtask
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.bt_port1.connect(c2.bp_imp_p1);
c2.bt_port2.connect(c2.bp_imp_p2);
endfunction:connect_phase
endclass
用户只需要在例化多个imp端口的组件中实现不同名称的方法,使其与对应imp类型名保持一致
而对于port端口,不需要关心调用的方法的名称
18.TLM_fifo
uvm_tlm_fifo类是一个新组件,它继承于uvm_component类,而且已经预先内置了多个端口以及实现了多个对应方法供用户使用