一、接口
1.概念
- 将interface看作一个“插排”,DUT与TB之间的数据驱动关系都可以使用interface这个插排来完成。
- interface和module的使用性质很像。它可以定义端口,也可以定义双向信号。他可以使用initial和always,也可以定义function和task。
- interface可以用做设计也可以用作验证。
2.优势
- 将有关信号封装在同一个接口中,对于设计和验证环境都有利于维护和使用。如果需要新添加信号,只需在接口中声明一次。
- 由于可以例化的特性,使得对于多组相同的总线,在使用和例化时变得更加灵活。
- 作为SV中唯一的硬件与软件环境的媒介交互,既可以在硬件世界(module)中使用,也可以在软件世界(class)中使用。
3.定义与使用
定义:
- 定义与module类似,例化方式同module一样。
- 在interface的端口列表中只需要定义时钟、复位等公共信号,或者不定义任何端口信号,转而在变量列表中定义各个需要跟DUT和TB连接的logic变量。
- interface可以依靠参数化方式提高复用性。
使用:
- 接口信号必须使用非阻塞赋值来驱动。
- 使用接口时确保在模块和程序块之外声明接口变量。
- 在接口中使用modport将信号分组并指定方向。
//带有modport的接口
interface arb_if(input bit clk);
logic[1:0]grant, request;
logic rst;
modport TEST(output request, rst,
input grant, clk);
modport DUT(input request, rst, clk,
output grant);
modport MONITOR(input request, grant, rst, clk);
endinterface
//接口中使用modport的仲裁器模型
module arb(arb_if.DUT arbif);
...
endmodule
//接口中使用modport的测试平台
module TEST(arb_if.TEST arbif);
...
endmodule
二、采样与驱动
1.竞争问题
- 在仿真行为中,为了尽量避免时序电路中时钟和驱动信号的时序竞争问题,应给出尽量明确的驱动时序和采样时序。
- 默认情况下,时钟对于组合电路的驱动会添加一个无限最小时间(delta-cycle)的延迟,该延迟无法用绝对时间单位衡量,比最小的时间单位精度还小。
- 在一个时间片(time-slot)中可以发生很多事情,例如在仿真器中敲入“run 0”,即是让仿真器运行一个delta-cycle的时间。
如何避免采样的竞争问题?
- 在驱动时,添加相应的人为延迟,模拟真实的延迟行为,同时加大clk与变量之间的延迟,以此提高DUT使用信号时的准确度和TB采样信号时的可靠性。
- 对于一些采样时依然存在delta-cycle延迟的信号,还可以依靠在采样事件前的某段时刻中进行采样,来模拟建立时间的采样要求,确保采样的可靠性。
2.clocking时钟块
- 可以在interface中声明clocking和采样的时钟信号用来做信号的同步和采样。
- clocking块基于时钟周期对信号进行驱动或者采样的方式,使得testbench不再苦恼于如何准确及时地对信号驱动或者采样,消除了信号竞争问题。
//在clock1的上升沿来驱动和采样
clocking bus@(posedge clock1);
//在clock1上升沿前10ns对其进行输入采样,
//在后2ns对其进行输出驱动。
default input #10ns output #2ns
input ready, margin;
output data, valid;
endclocking
clocking的使用
- clocking块不但可以定义在interface中,也可以定义在module和program中。
- clocking中列举的信号不是自己定义的,而是应该由interface或者其他声明clocking的模块定义的。
- clocking在声明完名字之后,应该伴随着定义默认的采样事件,即"default input/output event"。如果没有定义,则会默认地在clocking采样事件前的1step对输入进行采样,在采样事件后的#0对输出进行驱动。
- 除了定义默认的采样和驱动事件,也可以在定义信号方向时,用新的采样事件对默认事件做覆盖。