编写高效率的testbench_第1页
编写高效率的testbench_第2页
编写高效率的testbench_第3页
编写高效率的testbench_第4页
编写高效率的testbench_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、Writing Efficient Testbenches编写高效的测试设计(testbenches)原文作者:Mujtaba Hamid注:一个设计的测试验证是非常重要的。有效的测试可以助我们快速的完成或改善设计。Testbenches建议编写有效的测试代码来通过软件实现可靠的验证。无意中发现,顺手译为中文,以备将来方便。也贴给没有找到更好中文版本的同道人。Testbenches本意应该是测试平台更合理,但是在中文中阅读起来很不舒服。所以本文中有时译为“测试设计”,“测试代码”,有时干脆是“测试”。摘要:应用笔记为HDL验证设计的新手,或者是没有丰富的测试设计经验的逻辑设计者而编写。测试设计

2、是验证HDL设计的主要手段。本应用笔记为创建或准备和构建有效的测试设计提供准则。它也提供一个为任何设计开发自较验测的测试设计的一个代数方法。涉及的所有设计文件可以从以下的站点获得:PC: 简介:由于设计的规模越来越大也越来越复杂,数字设计的验证已经成为一个日益困难和繁琐的任务。验证工程师们依靠一些验证工具和方法来应付这个挑战。对于几百万门的大型设计,工程师们一般使用一套形式验证(formal verification)工具。然而对于一些小型的设计,设计工程师常常发现用带有testbench的HDL仿真器就可以很好地进行验证。Testbench已经成为一个验证高级语言(HLL -High-Lev

3、el Language) 设计的标准方法。通常testbench完成如下的任务:1. 实例化需要测试的设计(DUT);2. 通过对DUT模型加载测试向量来仿真设计;3. 将输出结果到终端或波形窗口中加以视觉检视;4. 另外,将实际结果和预期结果进行比较。通常testbench用工业标准的VHDL或Verilog硬件描述语言来编写。Testbench调用功能设计,然后进行仿真。复杂的testbench完成一些附加的功能例如它们包含一些逻辑来选择产生合适的设计激励或比较实际结果和预期结果。后续的章节描述了一个仔细构建的testbench的结构,并且提供了一个自动比较实际结果与预期结果的进行自我检查

4、的testbench例子。图1给出了一个如上所描述步骤的标准HDL验证流程。由于testbench使用VHDL或Verilog来描述,testbench的验证过程可以根据不同的平台或不同的软件工具实现。由于VHDL或Verilog是公开的通用标准,使用VHDL或Verilog编写的testbench以后也可以毫无困难地重用(reuse)。图1使用Testbench的HDL验证流程构建TestbenchTestbench用VHDL或Verilog来编写。由于testbench只用来进行仿真,它们没有那些适用于综合的RTL语言子集的语法约束限制,而是所有的行为结构都可以使用。因而testbench

5、可以编写的更为通用,使得它们可以更容易维护。所有testbench包含了如表1的基本程序段。正如上面所提到的,testbench通常包含附加功能,如在终端上可视的结果和内建的错误检测。表1 testbench的基本程序段下面的例子介绍testbench中经常使用的结构。产生时钟信号使用系统时钟的时序逻辑设计必须产生时钟。时钟信号在VHDL或Verilog中可以很容易地实现。以下是VHDL和Verilog的时钟发生示例。VHDL:- Declare a clock period constant.Constant ClockPeriod : TIME := 10 ns;- Clock Gener

6、ation method 1:Clock = not Clock after ClockPeriod / 2;- Clock Generation method 2:GENERATE CLOCK: processbeginwait for (ClockPeriod / 2)Clock = 1;wait for (ClockPeriod / 2)Clock = 0;end process;Verilog:/ Declare a clock period constant.Parameter ClockPeriod = 10;/ Clock Generation method 1:initial

7、beginClock = 0;forever Clock = #(ClockPeriod / 2) Clock;end/ Clock Generation method 2:always #(ClockPeriod / 2) Clock = Clock;提供激励信号为了获得testbench的验证结果,激励必须作用于DUT。在testbench中使用的并行激励块提供必要的激励。激励的产生可以采用两个方法:绝对时间激励和相对时间激励。在第一个方法里,仿真变量相对于仿真时间零点进行详细描述。相对而言,相对时间激励提供初始值,然后等待一个事件来重新触发激励。根据设计者的需要,两种方法可以在testb

8、ench中同时使用。下面的程序段是绝对时间激励的例子。initial beginreset = 1;load = 0;cout_updn = 0;#100 reset = 0;#20 load = 1;#20 count_updn = 1;end下面的程序段是相对时间激励的例子。always (posedge clock)tb_count = tb_count + 1;initial beginif(tb_count = 5)beginreset = 1;load = 0;count_updn = 0;endelsebegin reset = 0;load = 1;count_updn = 1

9、;endendinitial begin if(count = 1100) begincount_updn = 0;$display(“Terminal count Reached,now counting down”); endendVerilog的initial块与文件中的其他initial块是同时执行。然而,在每一个initial块中,事件是按照书写的顺序执行的。这说明在每一个并行块中的激励序列从序仿真时间零点开始。为了代码有更好的可读性和更方便的可维护性,应采用多个块来分割复杂的测试激励。显示结果在Verilog中可以非常方便地使用系统函数$display()和$monitor()显示

10、结果。VHDL没有等效的显示指令,它提供了std_textio标准文本输入输出程序包。它允许文件的i/o重定向到显示终端窗口(作为这个技术的示例,参看下面的自较验查验证设计)下面是verilog示例,它将在终端屏幕上显示一些值。/ pipes the ASCII results to the terminal or text editorinitial begin$timeformat(-9,1,ns,12);$display( Time Clk Rst Ld SftRg Data Sel);$monitor(%t %b %b %b %b %b %b, $realtime,clock, res

11、et, load, shiftreg, data, sel);end系统函数$display在终端屏幕上输出引用的附加说明文字(“。”)。系统函数$monitor操作不同。因为它的输出是事件驱动的。例中的变量$realtime(由用户赋值到当前的仿真时间)用于触发信号列表中值的显示。信号表由变量$realtime开始,跟随其他将要显示的信号名(clock, reset, load等)。以%开始的关键字包含一个格式描述的表,用来控制如何格式化显示信号列表中的每个信号的值。格式列表是位置确定的。每个格式说明有序地与信号列表中的信号顺序相关。比如%t说明规定了$realtime的值是时间格式。并且第

12、一个%b说明符格式化clock的值是二进制形式。Verilog提供附加的格式说明,比如%h用于说明十六进制,%d说明十进制,%c说明显示为八进制。图2说明格式显示结果图2仿真结果简单的testbench简单的testbench实例化用户设计,然后提供相应的激励。测试输出被图形化显示在仿真器的波形窗口里或者作为文本发送到用户的终端或者是管道输出文本。以下是一个简单的用Verilog实现的设计,它实现了一个移位寄存器的功能。module shift_reg (clock, reset, load, sel, data, shiftreg);input clock;input reset;input

13、 load;input 1:0 sel;input 4:0 data;output 4:0 shiftreg;reg 4:0 shiftreg;always (posedge clock)beginif (reset)shiftreg = 0;else if (load)shiftreg = data;elsecase (sel)2b00 : shiftreg = shiftreg;2b01 : shiftreg = shiftreg 1;default : shiftreg = shiftreg;endcaseendendmodule以下是简单的testbench,示例移位寄存器设计的例子v

14、erilog描述。module testbench; / declare testbench namereg clock;reg load;reg reset; / declaration of signalswire 4:0 shiftreg;reg 4:0 data;reg 1:0 sel;/ instantiation of the shift_reg design belowshift_reg dut(.clock (clock),.load (load),.reset (reset),.shiftreg (shiftreg),.data (data),.sel (sel);/this

15、 process block sets up the free running clockinitial beginclock = 0;forever #50 clock = clock;endinitial begin/ this process block specifies the stimulus.reset = 1;data = 5b00000;load = 0; sel = 2b00;#200reset = 0;load = 1;#200data = 5b00001;#100sel = 2b01;load = 0;#200sel = 2b10;#1000 $stop;endinit

16、ial 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);endendmodule以上的testbench实例化设计,设置时钟,提供激励信号。所有的进程块在仿真时间零点开始。英镑标记(#)说明下

17、一个激励作用前的延迟。$stop命令使仿真器停止测试仿真(所有测试设计中都应该包含一个停止命令)。最后,$monitor语句返回ascII格式的结果到屏幕或者管道输出到一个文本编辑器。自动验证推荐自动实现测试结果的验证,尤其是对于较大的设计来说。自动化减少了检查设计是否正确所要求的时间,也使人可能的犯错最少。一般有以下几种常用的自动测试验证的方法:1、数据库比较(database comparison)。首先,要创建一个包含预期输出的数据库文件。然后,仿真输出被捕获并与预期输出数据库文件中参考的向量比较。然而,因为从输出到输入文件指针没有提供,是这种方法的一个缺点,使得跟踪一个导致错误输出的原

18、因比较困难。2、波形比较(waveform comparison)。波形比较可以自动或是手动的运行。自动的方法使用一个测试比较器来比较预期输出波形与测试输出波形。3、自我检查测试平台(self-checking testbenches)。一个自我检查testbench检查预期的结果与运行时间的实际结果,并不是在仿真结束以后。因为有用的错误跟踪信息可以内建在一个测试设计中,用来说明哪些地方设计有误,调试时间可以非常明显地缩短。自我检查testbenches自我检查testbench通过在一个测试文档中放置一系列的预期向量表来实现。运行时按定义好的时间间隔将这些向量与实际仿真结果进行比较。如果实际

19、结果与预期结果匹配,仿真成功。如果结果不匹配,则报告两者的差异。对于同步设计,实现自我检查testbench会更简单一些,因为与实现的结果相比较可以在时钟沿或每个几个时钟进行。比较的方法基于设计本身的特性。比如一个存储器读写的testbench在每次数据写入后者读出时进行检查。在自我检查的testbench中,预期输出与实际输出在一定的时间间隔比较以便提供自动的错误检查。这个技术在小到中型的设计中非常好。但是,因为当设计复杂后,可能的输出组合成指数倍的增长,为一个大型设计编写一个自我检查的testbench是非常困难和非常费时的。以下是一个用Verilog描述的简单的自我检查的testbenc

20、h例子:下述的设计实例中,预期的结果被详细说明。后面的代码,两种结果被比较,比较的结果被返回终端。如果没有错误,一个“end of good simulation”消息会显示。如果失配发生,根据期望与实际值的失配情况,错误会被相应报告。timescale 1 ns / 1 psmodule 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;/ / Instantiatio

21、n 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 beginData_in_t1 =10

22、b1111111110;Data_in_t2 =10b1111111101;Data_in_t3 =10b1111111011;Data_in_t4 =10b1111110111;Data_in_t5 =10b1111101111;Data_in_t6 =10b1111011111;Data_in_t7 =10b1110111111;Data_in_t8 =10b1101111111;Data_in_t9 =10b1011111111;Data_in_t10=10b0111111111;Data_in_t11=10b1111111110;Data_in_t12=10b1111111110;Da

23、ta_in_t13=10b1111111101;Data_in_t14=10b1111111011;Data_in_t15=10b1111110111;Data_in_t16=10b1111101111;Data_in_t17=10b1111011111;Data_in_t18=10b1110111111;Data_in_t19=10b1101111111;Data_in_t20=10b1011111111;Data_in_t21=10b0111111111;Data_in_t22=10b1111111110;Data_in_t23=10b1111111110;Data_in_t24=10b1

24、111111101;Data_in_t25=10b1111111011;endreg GSR;initial beginGSR = 1;/ / Wait till Global Reset Finished/ /#100 GSR = 0;end/ / Create the clock/ /initial begintbclk = 0;/ Wait till Global Reset Finished, then cycle clock#100 forever #60 tbclk = tbclk;endinitial begin/ / Initialize All Input Ports/ /t

25、breset = 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

26、integer i,errors;/ Block below compares the expected vs. actual results/ at every negative clock edge./always (posedge tbclk)beginif (tbstrtstop)begini = 0;errors = 0;endelsebeginfor (i = 1; i 1)$display(%0d ERROR! See log above for details.,errors);else$display(ERROR! See log above for details.);#1

27、00 $stop;endendendmodule如果仿真成功,下图的信息就会在显示终端上显示:图3 verilog示例验证编写testbench的准则本节罗列一些编写testbench的准则。正如规划一个电路设计可以帮助得到更好的电路性能,规划好的testbench可以提高仿真验证的效率。在编写testbench前要了解仿真器虽然通用仿真工具兼容HDL工业标准,但标准并没有重点强调跟仿真相关的一些主题。不同的仿真器有不同的特点、功能和执行效率。对我们而言要全面了解Active-HDL这个工具。-基于事件vs基于周期的仿真仿真器使用基于事件或基于周期的仿真方法。基于事件的仿真器,当输入,信号,或

28、是门改变了值,来确定仿真器事件的时间。在一个基于事件的仿真器中,一个延时值可以附加在门电路或是电路网络上来构建最优的时序仿真。基于周期的仿真器面向同步设计。这类工具优化组合逻辑,在时钟沿分析结果。这个功能使得基于周期的仿真器比基于事件的仿真器更快更有效。-确定事件时间基于事件的仿真器提供商使用不同的运算法则来确定仿真事件。所以,根据仿真器用来确定的运算法则不同,同一个仿真时间的事件被确定为不同的次序(根据在每个事件之间插入的delta延时)。为避免对运算法则的依赖和确保正确的结果,一个事件驱动测试应该详细描述明确的激励顺序。-避免使用无限循环当一个事件添加到基于事件的仿真器,cpu和内存的使用

29、就增加了,仿真过程就会变慢。除非是评价testbench,无限循环不应该使用来作为设计的激励。一般地,只有时钟被描述成一个无限循环(如forever循环)。-细分激励到逻辑模块 在测试中,所有initial块(verilog)并行执行。如果无关的激励被分离到独立的块中,测试激励的顺序会变得更容易实现和检查。因为每个并行的块相关于仿真时间的零点开始执行,对于分离的块传递激励更容易。使用分离激励块使得testbench的建立,维护和升级更加容易。-避免显示并不重要的数据大型设计的测试可能包含10万以上的事件或匿名信号。显示大量的仿真数据会相当地降低仿真的速度。高级测试技术根据任务和过程细分激励模块

30、在创建一个大的testbench时,激励将会被分割使得代码清晰而易于修改。Task块可以被用来分割信号。在下面例子中的testbench用于一个SDRAM控制器的测试。设计包括重复的激励模块,testbench通过不同的task来划分测试激励。这些task稍后被调用来进行独立块的功能的测试仿真。task addr_wr; 地址写input 31 : 0 address;begindata_addr_n = 0;we_rn = 1;ad = address;endendtasktask data_wr; 数据写input 31 : 0 data_in;begindata_addr_n = 1;w

31、e_rn = 1;ad = data_in;endendtasktask addr_rd; 地址读input 31 : 0 address;begindata_addr_n = 0;we_rn = 0;ad = address;endendtasktask data_rd; 数据读input 31 : 0 data_in;begindata_addr_n = 1;we_rn = 0;ad = data_in;endendtasktask nop; 空操作begindata_addr_n = 1;we_rn = 0;ad = hi_z;endendtask这些任务描述设计功能的独立单元:地址的读

32、写,数据的读写,或者空操作。当这些task描述完成后,这些task可以在testbench中被调用。如下所示:Initial beginnop ; / Nop#( 86* CYCLE +1); addr_wr (32h20340400); / Precharge, loadController MR#(CYCLE); data_wr (32h0704a076); / value for Controller MR#(CYCLE); nop ; / Nop#(5 * CYCLE); addr_wr (32h38000000); / Auto Refresh#(CYCLE); data_wr (3

33、2h00000000); /#(CYCLE); nop ; / Nopend细分激励到独立的任务使得激励很容易实现,也使得代码的可读性更好。在仿真时控制双向信号多数设计使用双向信号,在testbench中必须区别对待双向信号和单向信号。双向总线由testbench控制,双向总线的值可以通过数据顶层信号来访问。以下是一个双向总线示例。module bidir_infer (DATA, READ_WRITE);input READ_WRITE ;inout 1:0 DATA ;reg 1:0 LATCH_OUT ;always (READ_WRITE or DATA)beginif (READ_W

34、RITE = 1)写LATCH_OUT = DATA;endassign DATA = (READ_WRITE = 1) ? 2bZ : LATCH_OUT;endmoduleVerilog testbench可以如下描述:module test_bidir_ver;reg read_writet;reg 1:0 data_in;wire 1:0 datat, data_out;bidir_infer uut (datat, read_writet);assign datat = (read_writet = 1) ? data_in : 2bZ;assign data_out = (read

35、_writet = 0) ? datat : 2bZ;initial beginread_writet = 1;data_in = 11;#50 read_writet = 0;endendmodule在这些测试设计中,data_in信号提供激励到设计中的双向DATA数据信号,data_out信号读取该DATA数据信号.Verilog中有用的语法结构其他有用的Verilog语法结构,如 $monitor, $display, 及$time,在前面的verilog测试示例中论述过,这一节说明另外的可以在测试设计中使用的verilog语句结构。force/releaseforce/release语

36、句可以用来跨越进程对一个寄存器或一个wire网络的赋值。这个结构一般用于强制特定的设计行为。一旦一个强制值释放,这个信号保持它的状态直到新的值被进程赋值。以下是force/release语句的用法。module testbench;.initial beginreset = 1;force DataOut = 101;#25 reset = 0;#25 release DataOut;.endendmoduleassign/deassignassign/deassign语句与force/release相类似,但是assign/deassign只用于设计中的寄存器。他们一般用于设置输入值。就象一个force语句,assign语句覆盖进程语句的赋值。以下是一个assign/deassign语句的用法。modu

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论