第五章仿真验证与Testbench编写7/8/20201MicroelectronicsSchoolXidianUniversity5.1VerilogHDL电路仿真和验证概述仿真,也叫模拟,是通过使用EDA仿真工具,通过输入测试信号,比对输出信号(波形、文本或者VCD文件)和期望值,来确认是否得到与期望所一致的正确的设计结果,验证设计的正确性。验证是一个证明设计思路如何实现,保证设计在功能上正确的一个过程。验证在VerilogHDL设计的整个流程中分为4个阶段:阶段1:功能验证;阶段2:综合后验证;阶段3:时序验证;阶段4:板级验证。7/8/20202MicroelectronicsSchoolXidianUniversity5.2VerilogHDL测试程序设计基础•5.2.1Testbench及其结构在仿真的时候Testbench用来产生测试激励给待验证设计(DesignUnderVerification,DUV),或者称为待测设计(DesignUnderTest,DUT)。被验证设计(DUV)测试平台(Testbench)控制反馈激励输入响应输出Testbench平台结构测试程序的一般结构各种输入、输出变量定义数据类型说明//其中激励信号定义为reg型//显示信号定义为wire型integerparameter待测试模块调用激励向量定义(always、initial过程块;function,tast结构等;If-else,for,case,while,repeat,disable等控制语句)显示格式定义($monitor,$time,$display等)module仿真模块名://无端口列表endmodule由于Testbench是一个测试平台,信号集成在模块内部,没有输入输出。在Testbench模块内,例化待测设计的顶层模块,并把测试行为的代码封装在内,直接对待测系统提供测试激励。例5.2-1T触发器测试程序示例moduleTflipflop_tb;//数据类型声明regclk,rst_n,T;wiredata_out;TFFU1(.data_out(data_out),.T(T),.clk(clk),.rst_n(rst_n));//对被测模块实例化always//产生测试激励#5clk=~clk;Initialbeginclk=0;#3rst_n=0;#5rst_n=1;T=1;#30T=0;#20T=1;endInitial//对输出响应进行收集begin$monitor($time,T=%b,clk=%b,rst_n=%b,data_out=%b,T,clk,rst_n,data_out);endendmoduleT触发器的仿真波形和部分文本输出结果:部分文本输出结果:0T=x,clk=0,rst_n=x,data_out=x3T=x,clk=0,rst_n=0,data_out=05T=x,clk=1,rst_n=0,data_out=08T=1,clk=1,rst_n=1,data_out=110T=1,clk=0,rst_n=1,data_out=1激励(Stimulus)实例化DUT(DesignUnderTest)使用仿真工具比较仿真结果在终端上显示仿真的值,或者存成文件自动比较测试结果的正确性从图中可以清晰地看出Testbench的主要功能:(1)为DUT提供激励信号。(2)正确实例化DUT。(3)将仿真数据显示在终端或者存为文件,也可以显示在波形窗口中以供分析检查。(4)复杂设计可以使用EDA工具,或者通过用户接口自动比较仿真结果与理想值,实现结果的自动检查。在编写Testbench时需要注意的问题:(1)testbench代码不需要可综合Testbench代码只是硬件行为描述不是硬件设计。(2)行为级描述效率高VerilogHDL语言具备5个描述层次,分别为开关级、门级、RTL级、算法级和系统级。(3)掌握结构化、程式化的描述方式结构化的描述有利于设计维护,可通过initial、always以及assign语句将不同的测试激励划分开来。一般不要将所有的测试都放在一个语句块中。•5.2.2测试平台举例测试模块待测试模块激励向量输出显示输入激励信号reg类型输出显示信号wire类型DUT的仿真平台测试平台需要产生时钟信号、复位信号和一系列的仿真向量,观察DUT的响应,确认仿真结果。(1)组合逻辑电路仿真环境的搭建moduleadder1(a,b,ci,so,co);inputa,b,ci;outputso,co;assign{co,so}=a+b+ci;endmodule根据全加器的真值表(表5.2-1)编写的全加器测试程序如下:moduleadder1_tb;wireso,co;rega,b,ci;adder1U1(a,b,ci,so,co);//模块例化initial//测试信号产生begina=0;b=0;ci=0;#20a=0;b=0;ci=1;#20a=0;b=1;ci=0;#20a=0;b=1;ci=1;#20a=1;b=0;ci=0;#20a=1;b=0;ci=1;#20a=1;b=1;ci=0;#20a=1;b=1;ci=1;#200$finish;endendmodule全加器的输入a、b和ci定义为reg型变量;把输出so和co定义为wire型变量用模块例化语句“adder1U1(a,b,ci,so,co);”把全加器设计电路例化到测试仿真环境中;用initial块语句改变输入的变化并生成测试条件,输入的变化语句完全根据全加器的真值表编写仿真结果:(2)时序逻辑电路仿真环境的搭建在于时序逻辑电路仿真环境中,需要考虑时序、定时信息和全局复位、置位等信号要求,并定义这些信号。用VerilogHDL编写的十进制加法计数器源程序代码是:modulecnt10(clk,rst,ena,q,cout);inputclk,rst,ena;output[3:0]q;outputcout;reg[3:0]q;always@(posedgeclkorposedgerst)beginif(rst)q=4'b0000;elseif(ena)beginif(q9)q=q+1;elseq=0;endendassigncout=q[3]&q[0];endmoduleVerilogHDL测试程序代码是:modulecnt10_tb;regclk,rst,ena;wire[3:0]q;wirecout;cnt10U1(clk,rst,ena,q,cout);//模块实例化always#50clk=~clk;//时钟信号产生initialbeginclk=0;rst=0;ena=1;//控制信号产生#1200rst=1;#120rst=0;#2000ena=0;#200ena=1;#20000$finish;endendmodule实例化语句“cnt10U1(clk,rst,ena,q,cout);”把十进制计数模块例化到仿真环境中;在always中用语句“#50clk=~clk;”产生周期为100(标准时间单位)的时钟方波;用initial块生成复位信号rst和使能控制信号ena的测试条件。测试结果如图:5.2.3VerilogHDL仿真结果确认(1)直接观察波形通过直接观察各信号波形的输出,比较测试值和期望值的大小,来确定仿真结果的正确性。(2)打印文本输出法moduleadder1_tb;wireso,co;rega,b,ci;adder1U1(a,b,ci,so,co);//模块例化initial//测试信号产生begina=0;b=0;ci=0;#20a=0;b=0;ci=1;#20a=0;b=1;ci=0;#20a=0;b=1;ci=1;#20a=1;b=0;ci=0;#20a=1;b=0;ci=1;#20a=1;b=1;ci=0;#20a=1;b=1;ci=1;#200$finish;end$monitor($time,%b%b%b-%b%b,a,b,ci,so,co);endmodule其输出的结果是:0000-0020001-1040010-1060011-0180100-10系统任务打印任务:$display,直接输出到标准输出设备;$monitor,监控参数的变化;$fdisplay,输出到文件等(3)自动检查仿真结果自动检查仿真结果是通过在设计代码中的关键节点添加断言监控器,形成对电路逻辑综合的注释或是对设计特点的说明,以提高设计模块的观察性。(4)使用VCD文件VerilogHDL提供一系列系统任务用于记录信号值变化保存到标准的VCD(ValueChangeDump)格式数据库中。VCD文件是一种标准格式的波形记录文件,只记录发生变化的波形。VCD文件将在第5.3.7小节中详细讲述。5.2.4VerilogHDL仿真效率因为要通过串行软件代码完成并行语义的转化,VerilogHDL行为级仿真代码的执行时间比较长。提高VerilogHDL代码的仿真代码执行时间:(1)减小层次结构仿真代码的层次越少,执行时间就越短。(2)减少门级代码的使用由于门级建模属于结构级建模,建议仿真代码尽量使用行为级语句,建模层次越抽象,执行时间就越短。(3)仿真精度越高,效率越低计时单位值与计时精度值的差距越大,则模拟时间越长。`timescale仿真时间标度将在第5.9.3小节中详细讲述。(4)进程越少,效率越高代码中的语句块越少仿真越快,这是因为仿真器在不同进程之间进行切换也需要时间。(5)减少仿真器的输出显示VerilogHDL语言包含一些系统任务,可以在仿真器的控制台显示窗口输出一些提示信息,但会降低仿真器的执行效率。5.3与仿真相关的系统任务•5.3.1$display和$write语法格式如下:$display(“format_specifiers”,signal1,signal2,...,signaln);$write(“format_specifiers”,signal1,signal2,...,signaln);“format_specifiers”通常称为“格式控制”“signal1,signal2,……,signaln”则为“信号输出列表”$display自动地在输出后进行换行$write输出特定信息时不自动换行输出格式说明,由“%”和格式字符组成,其作用是将输出的数据转换成指定的格式输出。常用的几种输出格式如右表。输出格式说明%h或%H以十六进制数的形式输出%d或%D以十进制数的形式输出%o或%O以八进制数的形式输出%b或%B以二进制数的形式输出%c或%C以ASCII码字符的形式输出%v或%V输出网络型数据信号强度%m或%M输出等级层次的名字%s或%S以字符串的形式输出%t或%T以当前的时间格式输出%e或%E以指数的形式输出实型数%f或%F以十进制数的形式输出实型数%g或%G以指数或十进制数的形式输出实型数一些特殊的字符可以通过表中的转换序列来输出。换码序列功能\n换行\t横向跳格(即跳到下一个输出区)\\反斜杠字符\\双引号字符\o1到3位八进制数代表的字符%%百分符号%例5.3-1:$display和$write语句moduledisp_tb;reg[31:0]rval;pulldown(pd);initialbeginrval=101;$display(\\\t%%\n\\123);$display(rval=%hhex%ddecimal,rval,rval);$display(rval=%ootal%bbinary,rval,rval);$display(rvalhas%casciicharactervalue,rval);$display(pdstrengthvalueis%v,pd);$display(currentscopeis%m);$display(%sisasciivaluefor101,101);$wr