TestBench编写技巧
1. 参考链接
FPGA仿真:testbench(激励)文件的编写(以及Robei中一些需要注意的点)_fpga激励文件怎么写-CSDN博客
编写TestBench文件的主要目的是为我们建立的硬件电路进行仿真验证,查看各个模块的功能是否达到预期的目标,否则仅仅一次综合+生成比特流进行上板验证一次就消耗小则十几二十分钟,大则花费掉半个甚至一个多小时的时间,而且如果出现一个小问题,还不容易察觉到那个模块出现了错误。
所以在我们编写好硬件电路后,进行仿真来查看生成的波形数据是相对来说非常方便的选择。
2. 如何写好仿真测试文件
1. 基本结构
`timescale 仿真单位/仿真精度
module test_bench();
//通常 testbench没有输入与输出端口
信号或变量定义声明
使用initial或always语句产生激励波形
例化设计模块
endmodule
2. 详细内容
a. 关于仿真时间单位和精度
首先声明我们的仿真时间单位和精度,注意结尾不需要添加“;”
需要注意的是,`timescale 声明仿真单位和精度,比如我们想要延时10ns,在代码里面只需要如下编写:
`timescale 1ns/1ns
module test_beach();
wire rst_n;
rst_n = 1'b1; //上电信号拉低
#10 rst_n = 1'b0;//经过10ns后,rst_n信号拉低
#20 rst_n = 1'b1;//在10ns后,也就是总共20ns的时候,rst_n信号拉高
endmodule
b. 变量的定义赋值及信号类型的定义
· 信号类型
wire
:用于表示模块之间的连接线,由其他的信号或者模块输出驱动或者使用assign
进行赋值reg
:用于存储值,可以在always
块或initial
块中被赋值。
在我们编写测试模块的时候,通常需要模拟外部信号来驱动功能模块的输入,这些信号通常都要被定义为reg
类型
但是对于功能模块的输出,在测试模块中需要定义为wire
类型
总的来说,reg
是寄存器类型,用于信号连续或者时序赋值,wire
是网线类型,用来各个模块之间的连线。
· 在信号的赋值
在initial
或者always
块中,使用<=操作符进行对reg
类型信号赋值
· 定义参数形式
在代码中,可以将一些频繁需要修改或者在多处使用同一个参数值的地方定义成参数的形式,例如在声明一个计数器的时候
parameter CNT_MAX = 999_999;
always (posedge clk)
if(!rst_n)
cnt <= 20'd0;
else if(cnt == CNT_MAX)
cnt <= 20'd0;
else
cnt <= cnt + 1'd1;
3. 简单的测试模块示例
module test_module;
reg clk;
reg reset_n;
reg enable;
wire output;
// 功能模块实例化
my_functional_module uut (
.clk(clk),
.reset_n(reset_n),
.enable(enable),
.output(output)
);
// 初始化信号
initial begin
clk = 0;
reset_n = 0;
enable = 0;
// 等待一些时钟周期来稳定
#100;
// 复位模块
reset_n = 1;
// 使能模块并观察输出
#10 enable = 1;
#100 enable = 0;
// 检查输出是否符合预期
if (output === expected_value) begin
$display("Test passed.");
end else begin
$display("Test failed.");
end
// 结束仿真
#100 $finish;
end
// 时钟信号生成
always #10 clk = ~clk;
endmodule
例1:模拟摄像头输入
`timescale 1ns / 1ps
module test_camera_input;
// 假设的RGB565数据输出
wire [15:0] rgb565_data;
// 摄像头模块的输入引脚
reg [7:0] data_in; // 8个数据引脚
reg en; // 数据使能引脚
reg clk; // 时钟引脚
// 实例化摄像头模块
camera_module uut (
.data_in(data_in),
.en(en),
.clk(clk),
.rgb565_data(rgb565_data)
);
// 摄像头数据模拟
always #10 clk = ~clk; // 产生50Mhz时钟信号
initial begin
// 初始化信号
data_in = 8'b0;
en = 0;
clk = 0;
// 等待一些时钟周期来稳定
#100;
// 开始模拟数据输入
en = 1; // 使能数据输入
data_in = 8'b10001; // 模拟一些数据
#20; // 保持一段时间
// 改变数据
data_in = 8'b11010; // 模拟新数据
#20; // 保持一段时间
// 禁用数据输入
en = 0;
end
endmodule