学习到一篇有趣的接口interface介绍 验证IP(VIP)编写-interface_验证 vip-CSDN博客
《UVM白皮书》关于接口的介绍
interface是用来连接DUT和验证环境的端口。
一、定义一组接口
interface avsbus_interface(input clk, input rst_n)
logic avsbus_md;
…
endinterface
二、在top_tb和driver里声明这个接口
1. 定义了interface之后,在top_tb中(是个module)就可以连接dut使用:
module harness();
…
avsbus_interface u_avsbus_if(clk_avs,rst_n);
…
dut my_dut(.clk(clk),
.rst_n(rst_n),
.AVSMADATA(u_avsbus_if.avsbus_md));
OR
initial begin
force U_DUT.AVS_MDATA = u_avsbus_if.avsbus_md;
end
…
endmodule
2. 但是在driver中声明interface用上述方式的话,是会报错的,只有在module块里才可以。
在driver这种class类里使用的是virtual interface
class avsbus_driver extends uvm_driver#(avsbus_xaction);
…
virtual avsbus_interface vif;
…
function new(string name="avsbus_driver",uvm_component parent = null);
super.new(name,parent);
endfunction
…
endclass
在声明了vif之后,就可以在main_phase等中驱动其中的信号了。
task avsbus_driver::run_phase(uvm_phase phase);
super.run_phase(phase);
…
vif.avsbus_md <= 1'b1 ;
…
endtask
这样做可以消除代码中的绝对路径,大大提高了代码的可移植性。
三、连接top_tb 和 driver 中的接口
但是怎么把top_tb中的u_avs_bus_if与driver中的vif连接起来呢?
这就要用到config_db机制了。
在config_db机制中,分为set“寄信”和get“收信”两步操作。
示例:
1. 在top_tb中进行set操作:
module harness();
…
avsbus_interface u_avsbus_if(clk_avs,rst_n);
…
initial begin
force U_DUT.AVS_MDATA = u_avsbus_if.avsbus_md;
end
…
*******************************************************************************************
initial begin
uvm_config_db#(virtual avsbus_interface)::set(null,"*","vif",u_avsbus_if);
end
*******************************************************************************************
endmodule
2. 在my_driver中进行get操作:
class avsbus_driver extends uvm_driver#(avsbus_xaction);
…
virtual avsbus_interface vif;
…
function new(string name="avsbus_driver",uvm_component parent = null);
super.new(name,parent);
endfunction
*******************************************************************************************
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(virtual avsbus_interface)::get(this," ","vif",vif))
`uvm_fatal(get_type_name(),"VIRTUAL INTERFACE MUST BE SET FOR VIF!!!")
endfunction
*******************************************************************************************
...
endclass
这里引入了build_phase,它是UVM_phase机制中的一个,在new函数之后main_phase之前执行。
- build_phase 主要用来通过config_db机制的set,get来传递一些数据,以及实例化成员变量等。
- 它是一个function phase函数phase,是不消耗仿真时间的,总是在仿真时间0执行;而其他main/ run_phase是task phase,是任务phase,需要消耗时间。
- 在build_phase出现了uvm_fatal宏,倘若被打印,完成打印后会直接调用Verilog的finish函数结束仿真。
-
condig_db机制介绍:
uvm_config_db#(virtual avsbus_interface)::set(null,"*","vif",u_avsbus_if);
*******************************************************************************************
uvm_config_db#(virtual avsbus_interface)::get(this," ","vif",vif)
- config_db的set和get函数都有4个参数。它们的第3个参数必须完全一致,第4个参数,set的表示要传递给driver的interface是哪个,get的表示把接收到的interface传递给自己的哪个变量。set的第2个参数表示路径索引,也即uvm_test_top(top_tb中UVM-run_test创建的固定名实例)
- set和get函数都是静态函数,所以使用双冒号::。
- uvm_condig_db#(virtual avsbus_interface)是一个参数化的类,其参数(括号里的)就是要寄信的类型。
应用举例
向my_driver的var变量传递一个int类型的数据
top_tb.v:
initial begin
uvm_config_db#(int)::set(null,"*","var",100);
end
*******************************************************
my_driver.sv:
virtual function void build_phase(uvm_phase phase);
super.build_phase(phase);
if(!uvm_config_db#(int)::get(this," ","var",var))begin
`uvm_fatal(get_type_name(),"VAR MUST BE SET!!!");
end
endfunction
END.
`ifndef A_INTERFACE_SV
`define A_INTERFACE_SV
interface a_interface(input clk, input rst_n);
logic a_ck;
logic a_md;
logic a_sd;
logic [15:0] vout_avs_raila;
logic [15:0] vout_avs_railb;
logic [15:0] trans_rate_wh_raila;
logic [15:0] trans_rate_wh_railb;
logic bus_idle;
logic cnt_resync;
logic cmd_reset_vol_raila;
logic cmd_reset_vol_railb;
logic vdone_ra; logic vdone_rb;
logic ocw_ra; logic ocw_rb;
logic uvw_ra; logic uvw_rb;
logic otw_ra; logic otw_rb;
logic opw_ra; logic opw_rb;
bit check;
clocking m_drv_cb @(posedge clk);
default input #1 output #1;
input a_md;
output a_sd;
endclocking
clocking m_mon_cb @(posedge clk);
default input #1 output #1;
input a_sd;
endclocking
mmodport M_DRV(clocking m_drv_cb);
mmodport M_MON(clocking m_mon_cb);
endinterfce
`endif