1、数字集成电路设计入门-从HDL到版图于敦山北大微电子学系第十五章 Verilog Test Bench使用简介学习内容: 用一个复杂的testbench复习设计的组织与仿真 建立testbench通常使用的编码风格及方法设计组织虚线表示编译时检测输入文件是否存在及可读并允许生成输出文件。test bench组织stimulus 要验证的设计 简单的test bench 简单的testbench向要验证的设计提供向量,人工验证输出。 复杂的testbench是自检测的,其结果自动验证。复杂的test bench激励验证结果要验证的设计并行块 forkjoin块在测试文件中很常用。他们的并行特性使
2、用户可以说明绝对时间,并且可以并行的执行复杂的过程结构,如循环或任务。module inline_ tb;reg 7: 0 data_ bus;/ instance of DUTinitial forkdata_bus = 8b00;#10 data_bus = 8h45;Time | data_ bus0 | 8b0000_000010 | 8b0100_010130 | 8b0100_011040 | 8b0100_011145 | 8b1000_111050 | 8b1000_1111#20 repeat (10) #10 data_bus = data_bus + 1;#25 repe
3、at (5) #20 data_bus = data_bus 1; i = i -1) / 循环#50 stimulus = stim_arrayi ;#30 $finish;endendmodule矢量采样 在仿真过程中可以对激励和响应矢量进行采样,作为其它仿真的激励和期望结果。module capture_tb;parameter period = 20reg 7:0 in_vec, out_vec;integer RESULTS, STIMULUS;DUT u1 (out_ vec, in_ vec);initialbeginSTIMULUS = $fopen(“stimulus. tx
4、t“) ;RESULTS = $fopen(“results. txt“) ;forkif (STIMULUS != 0 ) forever #( period/2)$fstrobeb (STIMULUS, “%b“, in_vec);if (RESULTS != 0 ) #( period/2) forever #( period/2)$fstrobeb (RESULTS, “%b“, out_vec);joinendendmodule矢量回放 保存在文件中的矢量反过来可以作为激励module read_file_tb;parameter num_vecs = 256;reg 7:0 dat
5、a_bus;reg 7:0 stim num_vecs-1:0;integer i;DUT u1 (results, data_bus)initial/ 激励文件vec.txt001110000011100100111010001111000011000000101000begin / Vectors are loaded$readmemb (“vec. txt“, stim);for (i =0; i num_vecs ; i = i + 1)#50 data_bus = stimi;endendmodule000110000111100010111000. 使用矢量文件输入/输出的优点:
6、激励修改简单 设计反复验证时直接使用工具比较矢量文件。错误及警告报告 使用文本或文件输出类的系统任务报告错误及警告always ( posedge par_err)$display (“ error-bus parity errors detected“);always ( posedge cor_err)$display(“warning-correctable error detected“); 一个更为复杂的testbench可以: 不但能报告错误,而能进行一些动作,如取消一个激励块并跳转到下一个激励。 在内部保持错误跟踪,并在每次测试结束时产生一个错误报告。强制激励 在过程块中,可以用
7、两种持续赋值语句驱动一个值或表达式到一个信号。 过程持续赋值通常不可综合,所以它们通常用于测试基准描述。 对每一种持续赋值,都有对应的命令停止信号赋值。 不允许在赋值语句内部出现时序控制。 对一个寄存器使用assign和deassign,将覆盖所有其他在该信号上的赋值。这个寄存器可以是RTL设计中的一个节点或测试基准中在多个地方赋值的信号等。initial begin#10assigntop.dut.fsm1.state_reg=init_state;#20deassigntop.dut.fsm1.state_reg;end 在register和net上(例如一个门级扫描寄存器的输出)使用fo
8、rce和release,将覆盖该信号上的所有其他驱动。initialbegin#10forcetop.dut.counter.scan_reg.q=0;#20releasetop.dut.counter.scan_reg.q;end强制激励 可以强制(force)并释放一个信号的指定位、部分位或连接,但位的指定不能是一个变量(例如out_veci) 不能对register的一位或部分位使用assign和deassign在上面两个例子中,在net或register上所赋的常数值,覆盖所有在时刻10和时刻20之间可能发生在该信号上的其他任何赋值或驱动。如果所赋值是一个表达式,则该表达式将被持续计算
9、。 对同一个信号,force覆盖assign。 后面的assign或force语句覆盖以前相同类型的语句。 如果对一个信号先assign然后force,它将保持force值。在对其进行release后,信号为assign值。 如果在一个信号上force多个值,然后release该信号,则不出现任何force值。建立时钟例1:虽然有时候在设计中给出时钟,但通常时钟是测试基准中建立。下面介绍如何产生不同的时钟波形。同时给出用门级和行为级描述方法下面是一个简单对称时钟的例子:reg ck;always beginreg go; wire ck;nand #( period/2) u1 (ck, ck
10、, go);initial begin#( period/2) ck = 0;#( period/2) ck = 1;endgo = 0;#( period/2) go = 1;end注意:在一些仿真器中,时钟与设计使用相同的抽象级描述时,仿真性能会好一些。产生的波形(假定period为20)建立时钟例2:有启动延时的对称时钟的例子:reg ck;initial beginck = 0;#( period)reg go; wire ck;nand #( period/2) u1 (ck, ck, go);initialbeginforever#( period/2) ck = !ck;endg
11、o = 0;#(period) go = 1;end注意:在行为描述中,在时间0将CK初始化为0;而在结构描述中,直到period/2才影响CK值。当go信号在时间0初始化时,CK值到period/2才变化。可以使用特殊命令force和release立即影响CK值。产生的波形(假定period为20)建立时钟例3:有不规则启动延时的不对称时钟的例子:reg ck;initial begin#(period + 1) ck = 1;#(period/2 1)forever beginreg go; wire ck;nand #(3*period/4, period/4)u1(ck, ck, go
12、);initial begin#(period/4 + 1) go = 0;注意:在行为描述中,CK值立刻被影响;而在结构描述中,在传播延时后才输出正确波形。产生的波形(假定period为20)#(period/4) ck = 0;#(3*period/4) ck = 1;endend#(5*period/4 1) go = 1;end使用task在test bench中使用task可以压缩重复操作,提高代码效率。module bus_ctrl_tb;reg 7: 0 data;reg data_valid, data_rd;cpu u1 (data_valid, data,data_rd);
13、initial begintask cpu_driver;input 7:0 data_in;begin#30 data_valid = 1;wait (data_rd = 1);cpu_driver (8b0000_0000);cpu_driver (8b1010_1010);cpu_driver (8b0101_0101);end#20 data = data_ in;wait (data_rd = 0);#20 data = 8hzz;#30 data_valid = 0;endendtaskendmodule使用task产生的波形复习问题: 什么操作可以容易的在forkjoin块做到,而不容易在beginend块做到? 通常怎样产生规则激励和不规则激励? 从一个文件中读取激励时使用什么数据类型? 在行为级时钟模型中能做哪些在门级时钟模型中很难或不能作到的事?解答: forkjoin块中不但能够赋值,还可以并行执行循环、条件语句、任务或函数调用。 循环或always块能有效地产生规则激励,不规则激励适合用在initial块产生。 用寄存器组(存储器)并用$readmem系统任务从一个文件以读取向量。 行为级代码可以很容易地产生一个启动时间不规则的时钟波形,并且可以在时刻零初始化时钟。