verilog testbench 写法.docx
《verilog testbench 写法.docx》由会员分享,可在线阅读,更多相关《verilog testbench 写法.docx(23页珍藏版)》请在冰豆网上搜索。
verilogtestbench写法
Verilog测试平台(testbench)技术
(一)收藏
对设计进行功能仿真和时序仿真时,需要给待测模块提供激励输入。
对于由Verilog语言描述的设计模块,最好的方法自然同样是用Verilog语言对待测模块施加激励和检测模块的输出响应。
实际应用中,Verilog测试平台(testbench)就是用来提供上述功能的。
Verilog测试平台是一个例化的待测(MUT)Verilog模块,给它施加激励并观测其输出。
由于测试平台是用Verilog语言描述的,因此可以应用到不同的仿真环境中。
待测模块和与之对应的测试平台组成一个仿真模型,应用这个模型可以在不同的测试环境中用相同的激励对待测模块进行调试。
下面就对不同电路类型分别介绍verilog测试平台的语言结构。
一、测试平台
1.组合电路测试
设计组合电路的测试平台时,待测模块及其功能决定了激烈的选择与测试次数。
对于一个已有的待测模块,测试平台中需要声明与待测模块输入输出端口对应的变量。
与输入端口相连接的变量定义为reg,与输出端口相连接的变量定义为wire,例化时将测试平台中声明的变量与待测模块的输入输出端口相关联。
使用initial语句控制程序运行,initial语句是一种过程结构,在initial块中可使用延迟控制语句来控制initial块中的程序流动。
这里对一个简单的算术逻辑单元(ALU)为例进行测试,下面是该单元Verilog描述。
/*************************************************************************/
//多动能ALU的Verilog代码
'timescale1ns/100ps
modulealu_4bit(a,b,f,oe,y,p,ov,a_gt_b,a_eg_b,a_lt_b);
input[3:
0]a,b;
input[1:
0]f;
inputoe;
input[3:
0]y;
outputp,ov,a_gt_b,a_eg_b,a_lt_b;
reg[4:
0]im_y;
always@(aorborf)
begin
ov=1'b0;
im_y=0;
case(f)
2'b00:
begin
im_y=a+b;
if(im_y>5'b01111)
ov=1'b1;
end
2'b01:
begin
im_y=a-b;
if(im_y>5'b01111)
ov=1'b1;
end
2'b10:
im_y[3:
0]=a&b;
2'b11:
im_y[3:
0]=a^b;
default:
im_y[3:
0]=4'b0000;
endcase
end
always@(aorb)
begin
if(a>b)
{a_gt_b,a_ge_b,a_lt_b}=3'b100;
elseif(a
{a_gt_b,a_ge_b,a_lt_b}=3'b001;
else
{a_gt_b,a_ge_b,a_lt_b}=3'b010;
end
assignp=^im_y[3:
0];
assigny=oe?
im_y[3:
0]:
4'bz;
endmodule
/*************************************************************************/
模块alu_4bit是四功能的算术逻辑单元,输入包括数据信号a、b和功能信号f,输出包括数据信号y和ALU生成的奇偶校验信号p、溢出信号ov及比较信号。
下面代码描述了alu_4bit模块的测试平台。
/*************************************************************************/
moduletest_alu_4bit;
reg[3:
0]a=4'b1011,b=4'b0110;
reg[1:
0]f=2'b00;
regoe=1;
wire[3:
0]y;
wirep,ov,a_gt_b,a_eg_b,a_lt_b;
alu_4bitcut(a,b,f,oe,y,p,ov,a_gt_b,a_eg_b,a_lt_b);
initial
begin
#20b=4'b1011;
#20b=4'b1110;
#20b=4'b1110;
#80oe=1'b0;
#20$finish;
end
always#23f=f+1;
endmodule
/*************************************************************************/
与alu_4bit模块相连的变量在声明时被赋初值。
用一个initial语句对ALU的输入数据b和输出使能oe赋值,在前60ns,每隔20n给b赋一个新值然后等待80ns,给oe赋0值来禁止ALU的输出,再等待20ns后结束仿真。
最终等待20ns后,显示的仿真结果里包含最后一个输入数据产生的输出。
用always语句对alu_4bit的输入数据f赋值,f的初值为0,以后每隔23ns它的值加1.initial块的$finish语句在160ns时被执行,此时所有正在运行的过程语句都停止,仿真结束。
下图所示是仿真后的波形曲线。
Verilog测试平台(testbench)技术
(二)收藏
2.时序电路测试
时序电路测试包括测试电路时钟与输入数据的同步。
这里以一个名为misr的模块为例说明时序电路的测试方法。
misr模块描述的电路有一个输入时钟、一个复位信号、输入数据与输出数据。
该电路有一个poly参数,用于计算让的输出值和数据压缩。
每个时钟上升沿到来时,通过已有的misr寄存器数据和输入数据计算新的输出值。
其Verilog描述如下。
/*************************************************************************/
`timescale1ns/100ps
modulemisr#(parameter[3:
0]poly=0)(inputclk,rst,input[3:
0]d_in,outputreg[3:
0]d_out);
always@(posedgeclk)
if(rst)
d_out=4'b0000;
else
d_out=d_in^({4{d_out[0]}}&poly)^{1'b0,d_out[3:
1]};
endmodule
/*************************************************************************/
下面是misr模块的测试平台。
/*************************************************************************/
moduletest_misr;
regclk=0,rst=0;
reg[3:
0]d_in;
wire[3:
0]d_out;
misr#(4'b1100)MUT(clk,rst,d_in,d_out);
initial
begin
#13rst=1'b1;
#19d_in=4'b1000;
#31rst=1'b0;
#330$stop;
end
always#37d_in=d_in+3;
always#11clk=~clk;
endmodule
/*************************************************************************/
测试平台中的initial语句产生rst信号的一个上升脉冲,从13ns到63ns。
这样做的目的是让这个脉冲至少覆盖一个时钟上升沿,这样,同步的rst信号可以初始化misr模块的寄存器。
输入数据d_in初始值为不定态,当rst为1时,被赋予初值4'b1000。
除了这个initial语句块之外,test_misr模块还包括两个always语句,用于生成clk和d_in。
时钟是周期信号,每隔11ns翻转一次,另外每隔37ns就给输入d_in一个新值。
为了降低多个输入同时翻转的概率,对时序电路的输入一般采用素数作为时间间隔。
仿真波形如下所示。
Verilog测试平台(testbench)技术(三)收藏
二、测试平台技术
下面讨论许多有关测试激励生成与输出结果观测的代码编写技术。
在这里待测模块我们使用一个如下描述的Moore状态机,它是一个101Moore序列检测器。
当检测到输入序列为101时,当前状态值变为d,输出z的值为1。
这是一个同步复位电路。
/*************************************************************************/
`timescale1ns/100ps
moduleMoore_detector(inputx,rst,clk,outputz);
parameter[1:
0]a=0,b=1,c=2,d=3;
reg[1:
0]current;
always@(posedgeclk)
begin
if(rst)
current=a;
else
case(current)
a:
current=x?
b:
a;
b:
current=x?
b:
c;
c:
current=x?
d:
a;
d:
current=x?
b:
c;
default:
current=a;
endcase
end
assignz=(current==d)?
1'b1:
1'b0;
endmodule
/*************************************************************************/
1.测试数据
如下代码是moore_detector模块的测试平台,与前面类似,测试平台是一个没有输入输出端口的模块。
这个模块有4个过程块用于生成待测状态机的测试数据。
与例化模块MUT的输入端相连的变量在过程块里位于赋值语句的左侧,它们的定义为reg类型。
/*************************************************************************/
moduletest_moore_detector;
regx,reset,clock;
wirez;
Moore_detectorMUT(x,reset,clock,z);
initial
begin
clock=1'b0;
x=1'b0;
reset=1'b1;
end
initial
#24reset=1'b0;
always#5clock=~clock;
always#7x=~x;
endmodule
/*************************************************************************/
通常不是在声明reg类型变量时对其进行初始化,而是采用initial块对其进行初始化。
初始化变量很重要,特别是对clock这种需要利用它前一时刻的值来计算当前时刻的值的变量,若不对其进行初始化,它的初始值为不确定状态,并将一直保持为该状态。
2.对仿真的控制
下面代码描述了moore_detector模块的另一种测试平台。
上一节介绍的测试平台,如果不中断它或停止它,它会一直运行,而下面描述的测试平台解决了这个问题,它加入另一个initial块,使仿真在189ms时停止。
/*************************************************************************/
//有$stop仿真控制任务的测试平台
moduletest_moore_detector;
regx=0,reset=1,clock=0;
wirez;
Moore_detectorMUT(x,reset,clock,z);
initial
#24reset=1'b0;
always#5clock=~clock;
always#7x=~x;
initial
#189$stop;
endmodule
/*************************************************************************/
$stop和$finish是仿真控制任务。
当过程块运行到此类任务时,仿真暂停或结束。
暂停的仿真可以继续运行,而结束的仿真则不能。
仿真波形如下图。
下面是moore_detector模块的第三种测试平台,它把reset信号无效和仿真控制任务放在同一个initial块里,在这种时序下,仿真在189ns时刻停止。
/*************************************************************************/
//有$finish仿真控制任务的测试平台
moduletest_moore_detector;
regx=0,reset=1,clock=0;
wirez;
Moore_detectorMUT(x,reset,clock,z);
initial
begin
#24reset=1'b0;
#165$finish;
end
always#5clock=~clock;
always#7x=~x;
endmodule
/*************************************************************************/
Verilog测试平台(testbench)技术(四)收藏
3.设置数据限制
测试平台也可以不通过设置仿真时间限制来控制仿真时间,而是通过对MUT输入数据的数量进行设置来达到控制仿真时间的目的。
同样,也可以停止仿真,避免其无限制地运行。
下面Verilog代码描述了moore_detector模块的第四中测试平台。
这里采用$random对输入x生成随机数据。
initial块里的repeat语句让时钟共执行13次变化,每5ns变化一次;而x共得到10个新数据,每隔7ns变化一次。
这里采用随机信号代替固定的测试数据。
这种策略生成数据比较简单,但是分析输出时比较困难,因为它的输入是不可预测的。
对于大规模电路来说,随机数据比可控的数据更有用。
/*************************************************************************/
//用repeat语句限制输入数据的测试平台
moduletest_moore_detector;
regx=0,reset=1,clock=0;
wirez;
Moore_detectorMUT(x,reset,clock,z);
initial#24reset=1'b0;
initialrepeat(13)#5clock=~clock;
initialrepeat(10)#7x=$random;
endmodule
/*************************************************************************/
4.采用同步数据
前面介绍的几个测试平台的例子中,时钟和数据均采用独立时序。
当同时施加几组数据时,数据与系统时钟的同步将出现困难。
改变时钟频率会造成待测模块所有输入数据时序的改变。
下面描述的moore_detector模块的测试平台解决了这一问题。
它采用事件控制语句来同步由测试平台生成的x与时钟。
在一个initial语句里用repeate语句生成clock信号。
另一个initial语句用于生成随机的数据x。
其中,用一个forever循环来重复执行这项操作。
这个循环语句等到clock上升沿到来3ns后执行,为x生成新的随机数。
这个时钟上升沿后稳定的数据在下一时钟上升沿时施加到moore_detector模块。
这种激励技术保证数据和时钟不会同时变化。
/*************************************************************************/
//与时钟同步的数据
moduletest_moore_detector;
regx=0,reset=1,clock=0;
wirez;
Moore_detectorMUT(x,reset,clock,z);
initial#24reset=1'b0;
initialrepeat(13)#5clock=~clock;
initialforever@(posedgeclock)#3x=$random;
endmodule
/*************************************************************************/
这里采用3ns的延迟,使该测试平台既可以用于行为仿真,又可以用于综合后仿真。
在综合后仿真时,采用带有真实时延的元件模型,测试平台的延迟使该测试数据比其余测试数据先结束。
5.输出结果的同步显示
在前面所述测试平台的基础上,下面介绍一种可以用于同步观测待测模块的输出或内部信号的方法。
当采用层次化命名时,这种测试平台能够显示待测模块的内部变量和内部信号。
在这里我们用到了任务函数$display和$monitor。
以下面描述的moore_detector模块测试平台为例来介绍这一方法。
该平台用于观测moore_detector状态值current和输出值z,其中用到任务函数$monitor来显示寄存器current的值,另外在一个always块中,用任务函数$diaplay来显示输出结果z。
每当current状态值和输出值z变化时,就会显示变化后的值。
/*************************************************************************/
moduletest_moore_detector;
regx=0,reset=1,clock=0;
wirez;
Moore_detectorMUT(x,reset,clock,z);
initial#24reset=1'b0;
initialrepeat(19)#5clock=~clock;
initialforever@(posedgeclock)#3x=$random;
initial$monitor("Newstateis%dandoccursat%t"