1、UVM中的analysis 端口
包含有analysis_port和analysis_export两种端口,它们与port、export和imp的主要区别在于:
第一,默认情况下,analysis_port(analysis_export)可以连接多个IMP,而put和get系列端口连接一个IMP(除非在例化时修改连接数量)。
第二,analysis_port和analysis_export没有阻塞与非阻塞之分,而put和get系列端口有阻塞与非阻塞之分。
第三,put系列端口有put、try_put和can_put等操作;get系列端口有get、try_get和can_get等操作;analysis_port和analysis_export端口只有一种操作:write。在analysis_imp所在的component,必须定义一个名字为write的函数。
2、analysis 端口连接关系
A的代码:
class A extends uvm_component;
`uvm_component_utils(A);
uvm_analysis_port#(my_transaction) A_ap;//定义端口类型
endclass
function void A::build_phase(uvm_phase phase);
super.build_phase(phase);
A_ap = new("A_port",this);//例化端口
endfunction
task A::main_phase(uvm_phase phase);
my_transaction tr;
tr = new("tr");
assert(tr.randomize());
A_ap.write(tr);//发送tr数据包
endtask
B的代码:
class B extends uvm_component;
`uvm_component_utils(B);
uvm_analysis_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::write(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_ap.connect(B_inst.B_imp);
endfunction
3、特别说明
与put系列端口的PORT和EXPORT直接相连出错一样,analysis_port与analysis_export直接相连也会出错,只有在analysis_export后面连接一级analysis_imp才不会出错。
4、uvm_analysis_imp_decl宏的使用
当出现analysis_imp所在的component需要接收多路数据的情况时,但write只有一个,那么该如何定义write函数呢?这时就用到了宏uvm_analysis_imp_decl。例子如下:
`uvm_analysis_imp_decl(_monitor)
`uvm_analysis_imp_decl(_model)
class my_scoreboard extends uvm_scoreboard;
my_transaction tr;
uvm_analysis_imp_monitor#(my_transaction ,my_scoreboard) monitor_imp;
uvm_analysis_imp_model#(my_transaction ,my_scoreboard) model_imp;
extern function void write_monitor(my_transaction tr);
extern function void write_model(my_transaction tr);
endclass
function void my_scoreboard::write_monitor(my_transaction tr);
endfunction
function void my_scoreboard::write_model(my_transaction tr);
endfunction
只要完成后缀的声明,并在write后面加上相应的后缀即可正常工作。
5、使用fifo通信
fifo的本质是一个缓存加两个IMP,例子如下:
class my_scoreboard extends uvm_scoreboard;
my_transaction tr;
my_transaction get_exp;
my_transaction get_act;
uvm_blocking_get_port#(my_transaction) exp_port;
uvm_blocking_get_port#(my_transaction) act_port;
endclass
task my_scoreboard::main_phase(phase);
fork
while(1)begin
exp_port.get(get_exp);//获取数据包
end
while(1)begin
act_port.get(get_act);//获取数据包
end
join
endtask
在env中建立起连接:
```typescript
class my_env extends uvm_env;
my_agent i_agt;
my_agent o_agt;
my_scoreboard scb;
my_model mdl;
uvm_tlm_analysis_fifo#(my_transaction ) agt_scb_fifo;
uvm_tlm_analysis_fifo#(my_transaction ) agt_mdl_fifo;
uvm_tlm_analysis_fifo#(my_transaction ) mdl_scb_fifo;
endclass
function void my_env::connect_phase(uvm_phase phase);
super.connect_phase(phase);
i_agt.A_ap.connect(agt_mdl_fifo.analysis_export);//input monitor->fifo
mdl.port.connect(agt_mdl_fifo.blocking_get_export);//fifo->model
mdl.ap.connect(mdl_scb_fifo.analysis_export);//model->fifo
scb.exp_port.connect(mdl_scb_fifo.blocking_get_export);//fifo->scoreboard
o_agt.A_ap.connect(agt_scb_fifo.analysis_export);//output monitor -> fifo
scb.act_port.connect(agt_scb_fifo.blocking_get_export);//fifo->scoreboard
endfunction
使用fifo连接之后,scoreboard可以按照自己的节奏工作,而不用去适应monitor的节奏。同时也不用建立两个write函数,省去了好多麻烦。