验证一个设计需要经过几个步骤:生成输入激励,捕获输出相应,决定对错和衡量进度。要完成这个设计,首先第一步就是如何将DUT(Design Under Test)连接到测试平台。这一章的内容就来解决一下这个问题。
4.1 将测试平台和设计分开
测试平台的代码独立于设计的代码,设计者需要编写满足规范的代码,而验证工程师需要创建使得设计不满足设计规范的场景。使用模块来保存测试平台经常会引起驱动和采样时的时序问题,在SystemVerilog引入程序块(program block),从逻辑和时间上来分开测试平台。
4.1.1 测试平台和DUT之间的通信
随着设计复杂度的增加,模块之间的连接也变得复杂。在本章中,为了让大家更好地了解测试平台与DUT之间的连接关系,我们以搭建仲裁器的测试平台为例进行分析。
通常在我们Verilog的端口描述中是比较繁琐的,现在就这个例子,我们来看一下复杂的端口描述。
例4.1 使用verilog端口的仲裁器模型
module arb_port (output logic[1:0] grant,
input logic[1:0] request,
input logic rst,
input logic clk );
always@(posedge clk or posedge rst)
begin
if(rst)
grant<=2'b00;
else
......
end
endmodule
测试平台定义在另一个模块中,与设计所在的模块相互独立。一般来说,测试平台通过端口与设计连接。
例4.2 使用端口的测试平台
module test (input logic[1:0],
input logic clk,
output logic[1:0] request,
output logic rst);
initial begin
@(posedge clk) request<=2'b01;
$ display("@%0t:Drove req=01",$ time);
repeat(2) @(posedge clk);
if(grant!=2'b01)
$ diaplay("@%0t:a1:grant!=2'b01",$time);
......
$finish;
end
endmodule
顶层网单连接了测试平台和DUT,并且包含有一个简单地时钟发生器(clock generator)。
例4.3 没有接口的顶层网单
module top;
logic[1:0] grant, request;
bit clk,rst;
always #5 clk=~clk; //时钟发生器
arb_port a1 (grant,request,rst,clk); //例4.1 使用端口的仲裁器模型
test t1 (grant,request,rst,clk); //例4.2 使用端口的测试平台
endmodule
虽然通过端口连接,上面的例子看上去并不是太复杂,但是在实际的真实设计中往往含有数百个端口信号,需要数页代码来声明信号和端口。所有的这些连接都是极易出错的。如果你想添加一个新的信号,它必须在多个文件中定义和连接。针对以上问题,SystemVerilog都有相应的解决方案。
4.2 接口 interface
SystemVerilog使用接口为块之间的通信建模,接口看成一捆智能的连线。接口包含了连接、同步、甚至两个或者更多块之间的通信,它们连接了设计块和测试平台。
4.2.1 使用接口来简化连接
我们将端口捆绑成一个接口。接口扩展到测试平台和DUT的驱动和接收功能模块。时钟可以是接口的一部分或者是一个独立的端口。
最简单的接口仅仅是一组双向信号的组合。这些信号使用logic数据类型,可以使用过程语句驱动。
例4.4 仲裁器的简单接口
interface arb_if (input bit clk);
logic[1:0] grant,request;
logic rst;
endinterface
例4.5 使用了简单接口的仲裁器模型
module arb (arb_if arbif); //DUT使用接口,接口实例名arbif
......
always@(posedge arbif.clk or posedge arbif.rst)
begin
if(arb.rst)
arb.grant<=2'b00;
else
......
end
endmodule
可以通过使用实例名arbif.request来引用接口的信号。接口信号必须使用非阻塞