一、接口interface介绍
1.1.interface产生背景
传统的Verilog连接验证平台Testbench与DUT的方式:名字映射、位置映射
下面给出实例:
SystemVerilog则对Verilog的连接方式进行了改进补充,引入了接口interface。
1.2.接口的使用方式
- 可以直接通过接口的例化名字来实现连接;
- 可以通过接口中定义的信号来实现连接;
SV中接口为块之间的通信建模,接口可以看成是一捆智能的连线。接口包含了连接,同步,甚至是两个块或者更多块之间的通信功能。它们连接了设计和测试平台。具有以下特点:
- interface中包含了 一组信号;
- interface可以是 一个独立的文件,将多个模块通用的信号集中放在一个文件中;
- interface中集合了多个Verilog类型信号,是一个独立的端口类型;
- interface中可以包含多个modport, 定义interface的不同视图view(DUT、Test program)
- interface中可以使用clocking模块 显式指明同步时钟域;
- interface中的clocking只用于验证平台,其中可包含多个clocking模块,clocking中的信号方向与Testbench相关;
二、示例代码
以下为一个简易的仲裁器RTL(DUT)代码arb.v:
module arb( //简单的仲裁器
input reset_n,
input clk,
input request,
output reg grant);
always @(posedge clk or negedge reset_n) begin
if(reset_n == 1'b0)begin
grant <= 1'b0;
end
else if(request == 1'b1)begin
grant <= 1'b1;
end
else if(request == 1'b0)begin
grant <= 1'b0;
end
end
endmodule
接口interface文件arb_if.sv:
interface arb_if(input bit clk); //通常在接口的端口列表中声明时钟信号
logic grant;
logic request;
logic reset_n;
clocking cb@(posedge clk); //用于同步时钟域,相当于寄存器,将信号寄存一拍
input grant; //clocking模块主要服务于TB
output request;
endclocking
modport TB( //定义TB视图view
clocking cb,
output reset_n);
modport dut( //定义dut视图view
input request,
input reset_n,
output grant);
endinterface
激励文件test.sv: 通常使用program块编写,可以隐式执行$finish;系统函数结束代码块。
program test(arb_if.TB arbif); //例化接口中的TB视图
initial begin
//Asynch drive reset_n
arbif.cb.request <= 1'b0; //通过时钟clk上沿将request发出给DUT
arbif.reset_n <= 1'b1; //TB中的reset_n与request是异步关系,不需要cb
#15 arbif.reset_n <= 1'b0; //复位,稳定电路
#35 arbif.reset_n <= 1'b1; //撤离复位
#5;
//Synch drive request
//repeat(5)begin
arbif.cb.request <= 1'b1; //TB通过clk上沿将cb.request发送至DUT,DUT会输出一个dut.grant,并传递回给TB(cb.grant)
wait(arbif.cb.grant == 1'b1;); //TB对接收自DUT(dut.grant)的cb.grant进行判断,完成一次信息交互
arbif.cb.request <= 1'b0;
@arbif.cb; //@(posedge clk);
@arbif.cb;
@arbif.cb;
//end
end
endprogram //program模块不需要$finish函数来结束激励
顶层文件arb_tb.sv:包裹接口文件、激励文件和DUT文件
module ARB_TB();
bit clk;
arb_if arbif(.*); //隐式例化接口(clk信号名一样),等价arb_if arbif(.clk(clk));
test u_test(.*); //隐私例化激励文件
arb u_arb( //通过接口连接TB与DUT
.reset_n(arbif.reset_n),
.clk (clk),
.request(arbif.request),
.grant (arbif.grant)
);
initial begin
clk = 0;
forever #10 clk = ~clk;
end
endmodule
对于波形图, 要注意时钟沿数数据变化边沿出现重合的情况,此时,由于数据延迟,时钟沿通常采集的是数据变化边沿之前的状态数据。如下图DUT中所示:
同时要注意clocking对于信号的同步时钟域作用
。