编写Testbench的目的是把RTL代码在Modsim中进行仿真验证,通过查看仿真波形和打印信息验证代码逻辑是否正确。下面以3-8译码器说明Testbench代码结构。
Testbench代码的本质是通过模拟输入信号的变化来观察输出信号是否符合设计要求!因此,Testbench的核心在于如何模拟输入信号,并把模拟的输入信号输入到功能模块中产生输出信号,如上图所示。解决方案为:
module decoder3_8(
input wire [2:0] in,
output reg [7:0] out
);
// always/initial 模块中只能用 reg型变量
always @(*) begin
case(in)
3'h0: out = 8'h01;
3'h1: out = 8'h02;
3'h2: out = 8'h04;
3'h3: out = 8'h08;
3'h4: out = 8'h10;
3'h5: out = 8'h20;
3'h6: out = 8'h40;
3'h7: out = 8'h80;
// 避免lanth
default: out = 8'h00;
endcase
end
endmodule
`timescale 1ns/1ns // 时间单位及=精度设置
module tb_decoder3_8();
reg [2:0] in;
wire [7:0] out;
// 初始化
initial begin
in <= 3'h0;
end
// 实现输入信号电平自动变化
always #10 in <= {$random} % 8;
initial begin
$timeformat(-9, 0, "ns", 6);
$monitor("time:%t in:%b out:%b",$time,in,out);
end
// 通过实例化模块把模拟输入信号传入功能模块中
decoder3_8 decoder3_8_inist(
.in(in),
.out(out)
);
endmodule
(1) 时间单位:时间尺度预编译指令 时间单位 / 时间精度
(2) 延时:#数字
(3) 测试模块的命名:tb_<功能模块名>
(4) 需要定义模拟的输入/输出信号:
(5) 输入信号初始化
(6) 用always 语句实现信号在仿真过程中的电平变化
(7) 通过实例化模块把模拟输入信号传入功能模块中
(8) 通过 $monitor实现变量实时监测
testbench文件中编写的系统函数要在initial语句块中!
使用格式:
$timeformat(time_unit, decimal_number, suffix_string, minimum_field_wdith);
$display //打印信息,自动换行
$write //打印信息
$strobe //打印信息,自动换行,最后执行
$monitor //监测变量
$stop //暂停仿真
$finish //结束仿真
$time //时间函数
$random //随机函数
$readmemb //读文件函数
用法:
$<系统函数名>("格式控制语句", 变量1, 变量2, 变量3....);
相应的格式控制符有:
(1) 常用转义字符
转义字符 | 含义 |
\n | 换行符 |
\t | 横向制表符 |
\v | 纵向制表符 |
\\ | 反斜杠 / |
\'' | 引号 '' |
\a | 响铃 |
%% | 百分号 % |
(2) 常用数据格式
格式 | 说明 |
%b / %B | 二进制 |
%d / %D | 十进制 |
%o / %O | 八进制 |
%h / %H | 十六进制 |
%e / %E | 科学计数法显示十进制数 |
%c / %C | ASCII码 |
%t / %T | 时间 |
%s / %S | 字符串 |
%v / %V | 线网型信号强度 |
%m / %M | 层次名 |
更多打印格式参考:
System_Verilog打印格式_我不是悍跳狼丶的博客-CSDN博客_verilog格式化输出
用法:
$display("Add:%b+%b=%d",a, b, c); //格式“%b+%b=%d” 格式控制,未指定时默认十进制