VHDL 测试设计示例:
library IEEE;
use IEEE.std_logic_1164.all;
entity testbench is
end entity testbench;
architecture test_reg of testbench is
component shift_reg is
port (clock : in std_logic;
reset : in std_logic;
load : in std_logic;
sel : in std_logic_vector(1 downto 0);
data : in std_logic_vector(4 downto 0);
shiftreg : out std_logic_vector(4 downto 0));
end component;
signal clock, reset, load: std_logic;
signal shiftreg, data: std_logic_vector(4 downto 0);
signal sel: std_logic_vector(1 downto 0);
constant ClockPeriod : TIME := 50 ns;
begin
UUT : shift_reg port map (clock => clock, reset => reset,
load => load, data => data,
shiftreg => shiftreg);
process begin
clock <= not clock after (ClockPeriod / 2);
end process;
process begin
reset <= ’1’;
data <= "00000";
load <= ’0’;
set <= "00";
wait for 200 ns;
reset <= ’0’;
load <= ’1’;
wait for 200 ns;
data <= "00001";
wait for 100 ns;
sel <= "01";
load <= ’0’;
wait for 200 ns;
sel <= "10";
wait for 1000 ns;
end process;
end architecture test_reg;
上述vhdl测试设计与之前提到的verilog测试设计的功能是相似的,如希望用一个命令来返回输出到终端。在vhdl中,std_textio程序包被用于在终端上显示信息,它将被搁到下一节说明。自动验证
推荐自动实现测试结果的验证,尤其是对于较大的设计来说。自动化减少了检查设计是否正确所要求的时间,也使人可能的犯错最少。
一般有以下几种常用的自动测试验证的方法:
1、数据库比较。首先,要创建一个包含预期输出(一个黄金向量文件)的数据库文件。然后,仿真输出被捕获并与黄金向量文件中参考的向量比较(在unix中的diff 工具可以用来比较ascii数据文件)。然而,因为从输出到输入文件指针没有提供,是这种方法的一个缺点,使得跟踪一个导致错误输出的原因比较困难。
2、波形比较。波形比较可以自动或是手动的运行。自动的方法使用一个测试比较器来比较黄金波形与测试输出波形。xilinx的hdl bencher工具可以用于执行一个自动波形比较(关于hdl bencher的相关信息,请参看
http://www.xilinx.com/products/software/statecad/index.htm)
3、自较验测试。一个自较验测试检查预期的结果与运行时间的实际结果,并不是在仿真结束以后。因为有用的错误跟踪信息可以内建在一个测试设计中,用来说明哪些地方设计有误,调试时间可以非常明显地缩短。更多的关于自较验测试的信息在下一节说明。自较验测试
自较验测试通过在一个测试文档中放置一系列的预期向量表来实现。运行时间时间间隔将这些向量与定义好的实际仿真结果进行比较。如果实际结果与预期结果匹配,仿真成功。如果结果不匹配,测试报告两者的差异。
为同步设计实现自较验测试更简单一些,因为与实现的结果相比较可以在一个时钟沿或任何一个整数倍的时钟周期后。比较的方法基于设计本身的特性。比如一个用于内存I/O的测试应该检查每一次更新数据时的结果或者从一个内存位置读取。类似的,如果一个设计用了一个显而易见的组合块的数字,在预期结果描述时,组合时延就必须要考虑。
在自较验测试中,预期输出与实际输出在一个特定的运行时间间隔比较以便提供自动的错误检查。这个技术在小到中型的设计中非常好。但是,因为当设计复杂后,可能的输出组合成指数倍的增长,为一个大型设计编写一个自较验测试设计是非常困难和非常费时的。
以下是一个用verilog和vhdl描述的自较验测试的简单的例子:
Verilog例子
下述的设计实例中,预期的结果被详细说明。后面的代码,两种结果被比较,比较的结果被返回终端。如果没有错误,一个“end of good simulation”消息会显示。如果失配发生,根据期望与实际值的失配情况,错误会被相应报告。
‘timescale 1 ns / 1 ps
module test_sc;
reg tbreset, tbstrtstop;
reg tbclk;
wire [6:0] onesout, tensout;
wire [9:0] tbtenthsout;
parameter cycles = 25;
reg [9:0] Data_in_t [0:cycles];
// /////////////////////////////
// Instantiation of the Design
// /////////////////////////////
stopwatch UUT (.CLK (tbclk), .RESET (tbreset), .STRTSTOP (tbstrtstop),
.ONESOUT (onesout), .TENSOUT (tensout), .TENTHSOUT (tbtenthsout));
wire [4:0] tbonesout, tbtensout;
assign tbtensout = led2hex(tensout);
assign tbonesout = led2hex(onesout);
///////////////////////////////////////////////////////////////
//EXPECTED RESULTS
///////////////////////////////////////////////////////////////
initial begin
Data_in_t[1] =10’b1111111110;
Data_in_t[2] =10’b1111111101;
Data_in_t[3] =10’b1111111011;
Data_in_t[4] =10’b1111110111;
Data_in_t[5] =10’b1111101111;
Data_in_t[6] =10’b1111011111;
Data_in_t[7] =10’b1110111111;
Data_in_t[8] =10’b1101111111;
Data_in_t[9] =10’b1011111111;
Data_in_t[10]=10’b0111111111;
Data_in_t[11]=10’b1111111110;
Data_in_t[12]=10’b1111111110;
Data_in_t[13]=10’b1111111101;
Data_in_t[14]=10’b1111111011;
Data_in_t[15]=10’b1111110111;
Data_in_t[16]=10’b1111101111;
Data_in_t[17]=10’b1111011111;
Data_in_t[18]=10’b1110111111;
Data_in_t[19]=10’b1101111111;
Data_in_t[20]=10’b1011111111;
Data_in_t[21]=10’b0111111111;
Data_in_t[22]=10’b1111111110;
Data_in_t[23]=10’b1111111110;
Data_in_t[24]=10’b1111111101;
Data_in_t[25]=10’b1111111011;
end
reg GSR;
assign glbl.GSR = GSR;
initial begin
GSR = 1;
// ///////////////////////////////
// Wait till Global Reset Finished
// ///////////////////////////////
#100 GSR = 0;
end
// ////////////////
// Create the clock
// ////////////////
initial begin
tbclk = 0;
// Wait till Global Reset Finished, then cycle clock
#100 forever #60 tbclk = ~tbclk;
end
initial begin
// //////////////////////////
// Initialize All Input Ports
// //////////////////////////
tbreset = 1;
tbstrtstop = 1;
// /////////////////////
// Apply Design Stimulus
// /////////////////////
#240 tbreset = 0;
tbstrtstop = 0;
#5000 tbstrtstop = 1;
#8125 tbstrtstop = 0;
#500 tbstrtstop = 1;
#875 tbreset = 1;
#375 tbreset = 0;
#700 tbstrtstop = 0;
#550 tbstrtstop = 1;
// /////////////////////////////////////////////////////
// simulation must be halted inside an initial statement
// /////////////////////////////////////////////////////
// #100000 $stop;
end
integer i,errors;
///////////////////////////////////////////////////////////////////
///////////////
// Block below compares the expected vs. actual results
// at every negative clock edge.
///////////////////////////////////////////////////////////////////
///////////////
always @ (posedge tbclk)
begin
if (tbstrtstop)
begin
i = 0;
errors = 0;
end
else
begin
for (i = 1; i <= cycles; i = i + 1)
begin
@(negedge tbclk)
// check result at negedge
$display("Time%d ns; TBSTRTSTOP=%b; Reset=%h; Expected
TenthsOut=%b; Actual TenthsOut=%b", $stime, tbstrtstop, tbreset,
Data_in_t[i], tbtenthsout);
if ( tbtenthsout !== Data_in_t[i] )
begin
$display(" ------ERROR. A mismatch has occurred-----");
errors = errors + 1;
end
end
if (errors == 0)
$display("Simulation finished Successfully.");
else if (errors > 1)
$display("%0d ERROR! See log above for details.",errors);
else
$display("ERROR! See log above for details.");
#100 $stop;
end
end
endmodule
这种简单的自较验测试设计可以转换到任何测试场合----当然,预期的输出值和信号的名字在重用时是需要更改的。如果不需要每个时钟沿检查,需要的话可以修改for-loop结构。
如果仿真成功,下图的信息就会在显示终端上显示: