1.虚接口(virtual interface)
1.1为什么引入虚接口?
我们知道,通过引入interface可以简化模块儿之间的连接,即interface是连接硬件的,其是硬件语言;但对于验证来说,其描述语言往往是软件语言,interface无法在基于OOP的测试平台中实例化,因此我们无法通过interface把激励传送到DUT中;为了解决这个问题,引入了virtual interface,使得基于OOP的验证环境可以通过虚接口把激励传送给DUT。
1.2虚接口如何实现测试平台与DUT的连接?
virtual interface的本质是指向interface的指针,因此其并不是一个真实存在的实体,而interface是一个真实存在的实体;基于OOP的测试平台会通过调用virtual interface来间接操作实际的信号。
1.3示例
现有如下RTL代码,要求搭建一个简单的测试平台:
module counter(input clk,resetn,
input [3:0] load_value,
input load_valid,
output reg [3:0] q);
always@(posedge clk or negedge resetn)begin
if(!resetn)
q<=4d0;
else if(load_valid)
q<=load_value;
else
q<=q+4'd1;
end
endmodule
首先创建一个interface简化与DUT的连接:
interface counter_if(input logic clk);
logic load_valid;
logic [3:0] load_value;
endinterface
其次创建一个transaction用来生成随机激励:
class transaction;//用rand来生成随机化激励
rand logic load_valid;
rand logic [3:0] load_value;
endclass
然后创建一个driver来驱动激励到DUT上:
class driver;
virtual counter_if vif;//生成一个virtual interface句柄
function new(input virtual counter_if vif);//该new函数用来使虚接口句柄指向interface
this.vif=vif
endfunction
transaction tr;
task run(int n);//产生n次激励
for(int i=0;i<n;i++)begin
tr=new;
assert(tr.randomize());//
$display("tr.load_valid=%0d,tr.load_value=%0d",tr.load_valid,tr.load_value);
@(posedge vif.clk)begin//在clk上升沿,通过虚接口将transaction中的随机激励传送到interface上
vif.load_valid<=tr.load_valid;
vif.load_value<=tr.load_value;
end
end
endtask
endclass
最后创建top文件,用来将以上文件整合:
module tb_top;
logic clk,rstn;
logic[3:0]q;
counter_if dutif(clk);//实例化interface
driver my_driver;//声明句柄
counter u_counter(.resetn(rstn),
.clk(clk),
.load_valid(dutif.load_valid),
.load_value(dutif.load_value),
.q(out));//实例化DUT
initial begin
my_driver=new(dutif)//实例化驱动,使虚接口句柄指向interface
repeat(2) @(posedge clk);
@(posedge rstn);
repeat(5) @(posedge clk);
my_driver.run(20);//产生20次随机激励
end
initial beign//生成T=10的时钟
clk=1'b0;
forever #5 clk=~clk;
end
initial begin//复位信号的生成
rstn=1;repeat(2) @(posedge clk);
rstn=0;repeat(5) @(posedge clk);
rstn=1;repeat(50) @(posedge clk);
$finish;
end
endmodule
仿真结果: