uvm 通信
tlm通信
通信继承于uvm_void,不是object或者component,不能type_id::create
端口分类:
port:经常作为initiator的发起端,initiator凭借port才可以访问target的TLM通信方法。
export:作为initiator和target中间层次的端口。
imp:只能作为target接收request的末端,它无法作为中间层次的端口,所以imp的连接无法再次延伸。
根据传输方向跟端口类型排列组合,共有6类。
- uvm_UNDIR_port #(trans_t)
- uvm_UNDIR_export #(trans_t)
- uvm_UNDIR_imp#(trans_t,imp_parent_t)
- uvm_BIDIR_port#(req_trans_t,rsp_trans_t)
- uvm_BIDIR_export #(req_trans_t,rsp_trans_t)
- uvm_BIDIR_imp #(req_trans_t,rsp_trans_t,imp_parent_t)
单项通信
分类命名uvm(_blocking or _nonblocking)_(put get peek get_peek)_(imp port export)
- 第一项决定是阻塞还是非阻塞,省略的话两者都支持。
- 第二项决定数据传输方式。
- 第三项决定端口类型。
两者共同决定需要实现的函数 - 以blocking,put为例,在target中需要实现函数为task put(Tr t);
- 以nonblocking,put为例,在target中需要实现函数为function bit try_put(Tr t); function bit can_put();
双向通信
分类命名uvm(_blocking or _nonblocking)_(transport master slave)_(imp port export)
- 第一项决定是阻塞还是非阻塞,省略的话两者都支持。
- 第二项决定数据传输方式。
transport的话需要实现task transport(REQ req,output RSP rsp)或者task nb_transport(REQ req,output RSP rsp),发req并用rsp收。
master(以blocking为例)需要实现task put(REQ t),task get(output RSP t),task peek(output RSP t)
slave(以blocking为例)则相反,task put(RSP t),task get(output REQ t),task peek(output REQ t) - 第三项决定端口类型。
多个单项端口
一个组件中有多个端口时,函数名相同,会互相冲突。
在组件之前`组件名_decl(_uvc),定义使用该端口对应的方法也要加上后缀。
单对多通信
uvm_analysis_port ap; uvm_analysis_imp aimp;
需要在uvm_analysis_imp中需要自己实现write函数。
在port中write时,会遍历所有连接到的imp,执行其中的write函数。
fifo
单项通信
uvm_tlm_fifo,里面包含了多种配置端口。
双向通信
uvm_tlm_req_rsp_fifo
uvm_tlm_transport_fifo
单对多通信
针对这种端口,fifo使用uvm_tlm_analysis_fifo
使用示例如下:
//发送端
uvm_analysis_port #(uvc_transaction) trans_ap;
trans_ap.write();
//接收端
uvm_blocking_get_port #(uvc_transaction) trans_ap;
trans_ap.get();
//连接端
uvm_tlm_analysis_fifo #(uvc_transaction) uvc_fifo;
tx.trans_ap.connect(uvc_fifo.analysis_export);
rx.trans_ap.connect(uvc_fifo.blocking_get_export);
uvm_event
uvm_event不需要通过跨层次传递对象句柄,通过uvm_event_pool全局资源池来实现。
class ecb extends uvm_event_callback;
`uvm_object_utils(ecb)
function bit pre_trigger(uvm_event e,uvm_object data = null);
endfunction
function bit post_trigger(uvm_event e,uvm_object data = null);
endfunction
endclass
class comp1 extends uvm_component;
uvm_event e1;
edata d;
e1 = uvm_event_pool::get_global("e1");//有就直接拿到,没有就自动创建
e1.add_callback(cb);//添加回调函数
e1.trigger(d);//可以传递任何一个继承自uvm_object的类型,也可以不传递
endclass
class comp2 extends uvm_component;
uvm_event e1;
uvm_object tmp;
edata d;
e1 = uvm_event_pool::get_global("e1");
e1.wait_trigger_data(tmp);//边沿触发
//没传数据的话e1.wait_trigger();就可以
void'($cast(d,tmp));
endclass
uvm_event可以通过get_num_waiters()来获取等待的进程数。
wait_ptrigger_data(tmp)与wait_ptrigger()可以等待电平触发。
uvm_barrier
class comp1 extends uvm_component;
uvm_barrier b1;
b1 = uvm_event_pool::get_global("b1");//有就直接拿到,没有就自动创建
b1.wait_for();//可以传递任何一个继承自uvm_object的类型,也可以不传递
endclass
class comp2 extends uvm_component;
uvm_barrier b1;
b1 = uvm_event_pool::get_global("b1");
b1.wait_for();//可以传递任何一个继承自uvm_object的类型,也可以不传递
endclass
在外界,b1.set_threshold(n),等到调用wait_for的数量达到n以后,同时释放所有进程。
uvm_callback
class cb1 extends uvm_callback;
`uvm_object_utils(cb1)
function void func_name();
endfunction
endclass
class comp1 extends uvm_component;
`uvm_register_cb(comp1,cb1)
task run_phase(uvm_phase phase);
...
`uvm_do_callbacks(comp1,cb1,func_name)//也可以在func_name里面传参
...
endtask
endclass
class env1 extends uvm_env;
cb1 m_cb1;
comp1 c1;
function void build_phase
uvm_callbacks #(comp1)::add(c1,m_cb1);
endfunction
endclass
如果有cb2继承于cb1,就不需要uvm_register_cb(comp1,cb2),也不需要uvm_do_callbacks,
只需要uvm_callbacks #(comp1)::add(c1,m_cb2);

浙公网安备 33010602011771号