图2说明格式显示结果
图2仿真结果返回结果
简单的测试设计
简单的测试设计实例化用户设计,然后提供相应的激励。测试输出被图形化显示在仿真器的波形窗口里或者作为文本发送到用户的终端或者是管道输出文本。
以下是一个简单的用Verilog实现的设计,它实现了一个移位寄存器的功能。
module shift_reg (clock, reset, load, sel, data, shiftreg);
input clock;
input reset;
input load;
input [1:0] sel;
input [4:0] data;
output [4:0] shiftreg;
reg [4:0] shiftreg;
always @ (posedge clock)
begin
if (reset)
shiftreg = 0;
else if (load)
shiftreg = data;
else
case (sel)
2’b00 : shiftreg = shiftreg;
2’b01 : shiftreg = shiftreg << 1;
2’b10 : shiftreg = shiftreg >> 1;
default : shiftreg = shiftreg;
endcase
end
endmodule
以下是简单的测试设计示例移位寄存器设计的例子,verilog描述。
module testbench; // declare testbench name
reg clock;
reg load;
reg reset; // declaration of signals
wire [4:0] shiftreg;
reg [4:0] data;
reg [1:0] sel;
// instantiation of the shift_reg design below
shift_reg dut(.clock (clock),
.load (load),
.reset (reset),
.shiftreg (shiftreg),
.data (data),
.sel (sel));
//this process block sets up the free running clock
initial begin
clock = 0;
forever #50 clock = ~clock;
end
initial begin// this process block specifies the stimulus.
reset = 1;
data = 5’b00000;
load = 0;
sel = 2’b00;
#200
reset = 0;
load = 1;
#200
data = 5’b00001;
#100
sel = 2’b01;
load = 0;
#200
sel = 2’b10;
#1000 $stop;
end
initial begin// this process block pipes the ASCII results to the
//terminal or text editor
$timeformat(-9,1,"ns",12);
$display(" Time Clk Rst Ld SftRg Data Sel");
$monitor("%t %b %b %b %b %b %b", $realtime,
clock, reset, load, shiftreg, data, sel);
end
endmodule
以上的测试设计实例化设计,设置时钟,提供激励信号。所有的进程块在仿真时间零点开始。英镑标记(#)说明下一个激励作用前的延迟。$stop命令使仿真器停止测试仿真(所有测试设计中都应该包含一个停止命令)。最后,$monitor语句返回ascII格式的结果到屏幕或者管道输出到一个文本编辑器。接后的是一个vhdl描述的的测试设计,它实例化设计并提供激励到上述用verilog描述的移位寄存器.
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, tbtenthsout);
if ( tbtenthsout !== Data_in_t )
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结构。
如果仿真成功,下图的信息就会在显示终端上显示:
图3 verilog
VHDL 示例:
在VHDL中,向量文件包含预期的结果。VHDL 的textio程序包用于从向量文件中读取数据,和显示错误信息。这个测试用VHDL示例秒表设计.
LIBRARY IEEE;
USE IEEE.std_logic_1164.all;
LIBRARY ieee;
USE IEEE.STD_LOGIC_TEXTIO.ALL;
USE STD.TEXTIO.ALL;
ENTITY testbench IS
END testbench;
ARCHITECTURE testbench_arch OF testbench IS
COMPONENT stopwatch
PORT (
CLK : in STD_LOGIC;
RESET : in STD_LOGIC;
STRTSTOP : in STD_LOGIC;
TENTHSOUT : out STD_LOGIC_VECTOR (9 DOWNTO 0);
ONESOUT : out STD_LOGIC_VECTOR (6 DOWNTO 0);
TENSOUT : out STD_LOGIC_VECTOR (6 DOWNTO 0)
);
END COMPONENT;
SIGNAL CLK : STD_LOGIC;
SIGNAL RESET : STD_LOGIC;
SIGNAL STRTSTOP : STD_LOGIC;
SIGNAL TENTHSOUT : STD_LOGIC_VECTOR (9 DOWNTO 0);
SIGNAL ONESOUT : STD_LOGIC_VECTOR (6 DOWNTO 0);
SIGNAL TENSOUT : STD_LOGIC_VECTOR (6 DOWNTO 0);
constant ClockPeriod : Time := 60 ns;
FILE RESULTS: TEXT IS OUT "results.txt";
signal i: std_logic;
BEGIN
UUT : stopwatch
PORT MAP (
CLK => CLK,
RESET => RESET,
STRTSTOP => STRTSTOP,
TENTHSOUT => TENTHSOUT,
ONESOUT => ONESOUT,
TENSOUT => TENSOUT
);
stimulus: PROCESS
begin
reset <= ’1’;
strtstop <= ’1’;
wait for 240 ns;
reset <= ’0’;
strtstop <= ’0’;
wait for 5000 ns;
strtstop <= ’1’;
wait for 8125 ns;
strtstop <= ’0’;
wait for 500 ns;
strtstop <= ’1’;
wait for 875 ns;
reset <= ’1’;
wait for 375 ns;
reset <= ’0’;
wait for 700 ns;
strtstop <= ’0’;
wait for 550 ns;
strtstop <= ’1’;
end process stimulus;
clock: process
begin
clk <= ’1’;
wait for 100 ns;
loop
wait for (ClockPeriod / 2);
CLK <= not CLK;
end loop;
end process clock;
check_results : process
variable tmptenthsout: std_logic_vector(9 downto 0);
variable l: line;
variable good_val, good_number, errordet: boolean;
variable r : real;
variable vector_time: time;
variable space: character;
file vector_file: text is in "values.txt";
begin
while not endfile(vector_file) loop
readline(vector_file, l);
read(l, r, good => good_number);
next when not good_number;
vector_time := r * 1 ns;
if (now < vector_time) then
wait for vector_time - now;
end if;
read(l, space);
read(l, tmptenthsout, good_val);
assert good_val REPORT "bad tenthsoutvalue";
wait for 10 ns;
if (tmptenthsout /= tenthsout) then
assert errordet REPORT "vector mismatch";
end if;
end loop;
wait;
end process check_results;
end testbench_arch;
library XilinxCoreLib;
CONFIGURATION stopwatch_cfg OF testbench IS
FOR testbench_arch
FOR ALL : stopwatch use configuration work.cfg_tenths;
END FOR;
END FOR;
END stopwatch_cfg;
以下向量文件用于上述的测试。它包含了预期的仿真值。
-- Vector file containing expected results
0 1111111110
340 1111111110
400 1111111101
460 1111111011
520 1111110111
580 1111101111
640 1111011111
700 1110111111
760 1101111111
820 1011111111
880 0111111111
940 1111111110
1000 1111111110
1060 1111111101
1120 1111111011
1180 1111110111
1240 1111101111
1300 1111011111
1360 1110111111
1420 1101111111
1480 1011111111
1540 0111111111
1600 1111111110
1660 1111111110
1720 1111111101
1780 1111111011
如果错误被检测到,它会显示在一个仿真提示器中显示。图4展示在MTI脚本窗口的错误显示
|