SV interface
Interface
概述
interface 可以用做设计,也可以用作验证;
在验证环境中,接口可以使得连接变得简洁而不易出错;
在interface 中可以定义端口,也可以定义双向信号;可以使用initial 和 always,也可以定义function 和 task;但是不可以定义class;
interface可以在软件环境和硬件环境中传递,interface类似一个插排,DUT和TB之间的数据驱动关系都可以使用interface这个插排来完成;
特性
ineterface定义与module类似, 例化方式也类似;
在interface的端口列表中只需要定义时钟、复位等公共信号,也可以不定义任何端口信号,而在变量列表中定义各个需要跟DUT和TB连接的变量;推荐使用logic 定义变量;
interface 也可以依靠参数化方式提高复用性;
对于有对应interface的DUT和TB 组件,在其例化时,只需要传递匹配的interface变量名即可完成interface的传递;
interface 里面可以例化interface,但是不可以例化module;
TB和DUT连接
verilog方式
连接实例
例化
module top; wire [1:0] grant,request; wire clk, rest; arb a1(.grant(grant), .request(request), .reset(reset), .clk(clk)); test t1(.grant(grant), .request(request), .reset(reset), .clk(clk)); endmodule
systemverilog方式
方式1: .* ,匹配连接模块的同名,同size,类型兼容的port;
方式2: .name,默认连接的模块存在同名,同size的port;
方式3: interface
// 方式1: module top; logic [1:0] grant,request; logic clk, rest; arb a1(.*); test t1(.*); endmodule // 方式2 module top; logic [1:0] grant,request; logic clk, rest; arb a1(.grant, .request, .reset, .clk); test t1(.grant, .request, .reset, .clk); endmodule
TB和DUT连接:interface
连接
实例
interface.sv
interface arb_intf(input bit clk); logic [1:0] grant, request; logic reset; endinterface
test.sv
module test(arb_if arbif); initial begin @(posedge arbif.clk); arbif.request<=2'b01; $display("@%0t:Drove req=01", $time); repeat(2) @(posedge arbif.clk); if(arbif.grant!=2'b01) $display("@%0d:a1:grant != 2'b01", $time); $finish; end endmodule
top.sV
module top; bit clk; always #5 clk=~clk; arb_if arbif(clk); // 方式1 arb a1 (arbif); test t1 (arbif); // 方式2 arb a1(.grant(arbif.grant), .request(arbif.request), .reset(arbif.reset), .clk(arbif.clk)); test t1(.grant(arbif.grant), .request(arbif.request), .reset(arbif.reset), .clk(arbif.clk)); endmodule
modport
定义不同方向的信号
interface arb_intf(input bit clk); logic [1:0] grant, request; logic reset; modport TEST(outport request, reset, input grant, clk ); modport DUT(input request, reset,clk, output grant); endinterface module arb(arb_intf.DUT arbif); ... endmodule module test(arb_intf.TEST arbif); ... endmodule
竞争问题
引入竞争
为了避免在RTL仿真行为中发生的信号竞争问题,建议通过非阻塞赋值或者特定的信号延迟来解决同步的问题;
在仿真行为中,为了尽量避免时序电路中的时钟和驱动信号的时序竞争,需要给出尽量明确的驱动时序和采样时序;
默认情况下,时钟对于组合电路的驱动会添加一个无限最小时间(delta-cycle)的延迟,该延迟无法用绝对的时间单位衡量,它要比最小时间单位精度还小;
避免采样竞争
在驱动时,添加响应的人为延迟;模拟真实的延迟行为,同时加大clk与变量之间的延迟,以提高DUT使用信号时的准确度和TB采样信号时的可靠性;
对于一些采样时依然存在delta-cycle延迟的信号,可以依靠在采样事件前的某段时刻中进行采样,来模拟建立时间的采样要求,确保采样的可靠性;
为了避免可能的竞争,验证工程师应该在验证环境的驱动环节就添加固定的延迟,使得在仿真波形中更容易体现出时钟与被驱动信号之间的时序前后关系,同样也便于DUT的准确处理和TB的的准确采样;
clocking blocks
在interface中声明 clocking 和采样的时钟信号,用来做信号的同步和采样;
clocking 块基于时钟周期对信号进行驱动或者采样方式,使得TB 不在苦恼如何准确及时地对信号驱动或者采样,消除信号竞争问题;
clocking块不仅可以定义在interface中,也可以定义在module或者program中;
clocking中列举的信号不是自己定义的,而是有interface或其他声明clocking的模块定义的
clocking在声明完名字后,应该伴随着定义默认的采样事件: default input #10ns output #2ns;
如果没有默认事件定义,则会默认地在clocking采样事件前1step对输入进行采样,在采样事件后的#0对输出进行驱动
除了定义默认的采样和驱动事件,也可意在定义信号方向时,用新的采样时间对默认事件进行覆盖
采样与驱动
testbench在时钟沿之前采样
testbench在时钟沿之后驱动
clocking bus @(posedge clock1); // 定义时钟上升沿驱动和采样 default input #10ns output #2ns; // 上升沿的前10ns对其进行输入采样,事件后的2ns对其进行输出驱动 input data, ready, enable; // 声明要采样的三个输入信号,采样事件使用默认输入事件,上升沿的前10ns output negedge ack; // 声明要驱动的ack信号,驱动事件为下降沿,覆盖了原来的默认输出事件,上升沿后的2ns input #1step addr; // 自定义的采样事件,上升沿前的1step,这个1step使采样发生在上升沿的上一个时间片采样区域,即可采样到的数据是上一个时钟周期的数据 endcloking