Testbench基本组成与示例

testbench编写指南(1)基本组成与示例
生成时钟信号
生成测试激励
显示结果
简单示例
设计规则
对于小型设计来说,最好的测试方式便是使用testbench和hdl仿真器来验证其正确性。一般testbench需要包含这些部分:实例化待测试设计、使用测试向量激励设计、将结果输出到终端或波形窗口便于可视化观察、比较实际结果和预期结果。下面是一个标准的hdl验证流程:
testbench可以用vhdl或verilog、systemverilog编写,本文以verilog hdl为例。fpga设计必须采用verilog中可综合的部分子集,但testbench没有限制,任何行为级语法都可以使用。本文将先介绍testbench中基本的组成部分。
生成时钟信号
使用系统时钟的设计在testbench中必须要生成时钟信号,该功能实现起来也非常简单,示例代码如下:
parameter clockperiod = 10;
//方法1 initial begin forever clock = #(clockperiod/2) ~ clock; end //方法2 initial begin always #(clockperiod/2) clock = ~clock; end
生成测试激励
只有给设计激励数据,才能得到验证结果。提供激励的方法有两种,绝对时间激励以仿真时刻0为基准,给信号赋值,示例如下:
initial begin reset = 1; load = 0; count = 0; #100 reset = 0; #20 load = 1; #20 count = 1; end ‘#’用于指定等待的延迟时间,之后才会执行下一个激励。相对时间激励给信号一个初始值,直到某一事件发生后才触发激励赋值,示例如下: always @ (posedge clk) tb_cnt <= tb_cnt + 1; initial begin if (tb_cnt <= 5) begin reset = 1; load = 0; count = 0; end else begin reset = 0; load = 1; count = 1; end end
根据需要,可以同时使用两种方法。每一个initial块、always块之间都是并行工作的关系,但在initial块内部是顺序地处理事件。因此复杂的激励序列应该分散到多个initial或always块中,以提高代码可读性和可维护性。
显示结果
verilog中可以使用display和display和display和monitor系统任务来显示仿真结果,示例代码如下:
initial begin $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
$display会将双引号之间的文本输出到终端窗口。$monitor的输出为事件驱动型,如上例中$realtime变量用于触发信号列表的显示,%t表示$realtime以时间格式输出,%b表示其余值以二进制格式输出。其余还有%d、%h、%o等与惯例相同。
简单示例
下面是一个简单的移位寄存器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; default : shiftreg = shiftreg; endcase end endmodule
下面给出上述设计的testbench示例:
module testbench; // 申明testbench名称 reg clock; reg load; reg reset; // 申明信号 wire [4:0] shiftreg; reg [4:0] data; reg [1:0] sel; // 申明移位寄存器设计单元 shift_reg dut(.clock (clock), .load (load), .reset (reset), .shiftreg (shiftreg), .data (data), .sel (sel)); initial begin // 建立时钟 clock = 0; forever #50 clock = ~clock; end initial begin // 提供激励 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 // 打印结果到终端 $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
testbench中包括实例化设计、建立时钟、提供激励、终端显示几个部分。每个initial块之间都从0时刻开始并行执行。$stop用来指示仿真器停止testbench仿真(建议每个testbench中都有至少一个$stop)。$monitor会在终端以ascii格式打印监测结果。
设计规则
下面给出一些编写testbench的基本设计规则:
了解仿真器特性:不同的仿真器由不同的特性、能力和性能差异,可能会产生不同的仿真结果。仿真器可分为两类:(1).基于事件,当输入、信号或门的值改变时调度仿真器事件,有最佳的时序仿真表现;(2).基于周期,在每个时钟周期优化组合逻辑和分析结果,比前者更快且内存利用效率高,但时序仿真结果不准确。即使是基于事件的仿真器,在调度事件时采用不同的算法也会影响到仿真性能(比如同一仿真时刻发生了多个事件,仿真器需要按一定的序列依次调度每个事件)。了解仿真器特性有一定必要,但目前最常用的modelsim、vivado simulator等仿真器也已经非常强大。
避免使用无限循环:仿真器调度事件时,会增加cpu和内存的使用率,仿真进程也会变慢。因此除非迫不得已(比如利用forever生成时钟信号),尽量不要使用无限循环。
将激励分散到多个逻辑块中:verilog中的每个initial块都是并行的,相对于仿真时刻0开始运行。将不相关的激励分散到独立的块中,在编写、维护和更新testbench代码时会更有效率。
避免显示不重要的数据:对于大型设计来说,会有超过10万个事件和大量的信号,显示大量数据会极度拖慢仿真速度。因此最好的做法是每隔n个时钟周期显示重要信号的数据,以保证足够的仿真速度。


无缝高清矩阵切换器的常见故障及解决方案有哪些?
连续激光器中激光二极管的挑战
华为诺亚提出VanillaNet:一种新视觉Backbone,极简且强大!
红外热释电传感器与红外传感器差异对比
英飞特公布2019年度报告 新兴应用领域为公司带来新的利润增长点
Testbench基本组成与示例
关于过氧化氢对铜抛光的影响研究报告
苹果发邀请函确认发布会时间 iPhone7都有哪些靠谱曝光?
新交通电气化计划为城市百万电动汽车发展铺路
什么是65W(1A2C)PD快充方案?
爱驰U5上市迎合消费升级 直面新能源汽车领域的挑战
贴片电解电容的外形规格代号
10W高精度离线式开关电源芯片CY2525D
关于高压真空断路器操纵大功率电器的原理
华为P10闪存门最新消息:普通群众怎么看华为P10闪存门事件,用数据说话
LED热量产生的基本原理解析
三星电子与LG电子2018年四季度业绩大幅下滑导致Earning Shock
邬贺铨:5G最大意义在于生产场景,将深刻影响衣食住行
有线或无线回波损耗的测量方法介绍
自动重合闸断路器的组成结构是怎样的