一、testbench基本结构
通常,testbench没有输入与输出端口,应包括信号或变量定义、产生激励波形语句、例化设计模块以及监控和比较响应输出语句。
module test_bench;
//信号或变量定义声明
//使用initial或always语句来产生激励波形
//例化设计模块
//监控和比较输出响应
endmodule
二、常用产生激励描述方式
(1)产生时钟的几种方式
- initial,产生占空比为50%的时钟
initial begin clk = 0; #delay; forever #(period/2) clk = ~ clk; end
- always,产生占空比为50%的时钟
initial clk = 0; always #(period/2) clk = ~ clk;
- repeat,产生确定数目的时钟脉冲
initial begin clk = 0; repeat(6) #(period/2) clk = ~ clk; end
- 产生占空比非50%的时钟
initial clk = 0; always begin #3 clk = ~ clk; #2 clk = ~ clk; end
(2)产生复位信号的几种方式
- 异步复位
initial begin rst = 1; #100; rst = 0; #500; rst = 1; end
- 同步复位①
initial begin rst = 1; @(negedge clk); //等待时钟下降沿 rst = 0; #30; @(negedge clk); //等待时钟下降沿 rst = 1; end
- 同步复位②
initial begin rst = 1; @(negedge clk); //等待时钟下降沿 repeat(3) @(negedge clk); //经过3个时钟下降沿 rst = 1; end
三、常用的Verilog调试语句
(1)两种调试信息打印语句——$display与$monitor
/*在终端上打印信号的ASCII值*/
initial
begin
$timeformat (-9,1, “ns”,12); //设置输出时钟格式
$display(“stime clk rst pause ms_h ms_l s_h s_l m_h m_l”); //显示输入的字符串
$monitor(“%t %b %b %b %b %b %b %b %b”, //设置输出信号格式
$realtime,clock,reset,pause,ms_h,ms_l,s_h,s_l,m_h,m_l); //指定输出的信号
end
- $display:将函数内部双引号中的字符串输出在终端上,而$monitor则不同,它的输出是事件驱动的。
上例代码中,$monitor信号列表中$realtime信号的变化会触发终端显示事件的发生,每次$monitor的触发将会把信号列表中的信号值显示在终端中。
- $monitor:语句中的“%”用于定义信号列表中信号的输出格式。
例如,%t将信号按照时间格式输出,%b将信号按照二进制格式输出。另外Verilog HDL语言还提供了其它的输出格式,比如%h:十六进制、%d:十进制、%o:八进制等。
add wave -hex /pulse_out_top_inst/Act_x //Act_x的波形数据将会以十六进制的方式显示
add wave -decimal /pulse_out_top_inst/Act_y //Act_y的波形数据将会以十进制的方式显示
(2)timescales
'timescale 1ns/1ps //度量参考为1ns,精度为1ps
module testbench;
…
initial
begin
#10 rst = 1; //10个仿真时间延时,相当于10x1ns=10ns的仿真时间
…
end
initial
begin
//display语句将在每一个仿真推进布进中执行,也就是1ps执行一次
$display (''%d, rst = %b"m $time, rst);
end
endmodule
'timescale reference_time / precision
其中,reference_time是单位时间的度量,precision决定了仿真的推进延迟精度,同时也要设置仿真的推进步进单位。
# 是延迟的意思,而#号后面的数字是延迟的数量,延迟的单位由`timescale控制
比如有:当代码指定`timescale 1ns/1ps,那么,#10就是延迟10ns的意思
PS:在同步时序数字逻辑电路的verilog代码中,是不能加入“#”进行延迟,这不是代码编写阶段能决定的。
(3)force与release
module testbench;
initial
begin
rst = 1; //在仿真时间零点将rst赋值1
force data = 101; //在仿真时间零点强制使data为101,并保持
#30 rst = 0; //在仿真绝对时间30将rst赋值0
#50 release data; //在仿真绝对时间80释放
//data值将保持直到下一个对它的赋值语句
end
endmodule
force与release语句可以用来强制对执行过程中的reg或wire型信号量赋值。
这两条语句共同完成一个强制赋值的过程。当一个被force的信号被release以后,这个信号将会保持当时的状态直到下一个赋值语句产生为止。
(4)assign/deassign
module testbench;
...
initial
begin
rst = 1; //在仿真时间零点将rst赋值1
force data = 101;
#30 rst = 0; //在仿真绝对时间30将rst赋值0
#30 release data;
...
end
initial
begin
#20 assign rst = 1; //此条语句覆盖之前的赋值语句(即绝对时间零点的赋值)
#30 rst = 0; //绝对时间50对rst赋值0
#50 release rst; //绝对时间100释放rst信号
endmodule
PS:assign/deassign语句与force/release语句相类似,不过assign/deassign语句只能对设计中的reg型信号赋值。它们常常用来设置输入值。