FPGA|Verilog基础知识(二) Testbench编写

编写Testbench的目的是把RTL代码在Modsim中进行仿真验证,通过查看仿真波形和打印信息验证代码逻辑是否正确。下面以3-8译码器说明Testbench代码结构。
FPGA|Verilog基础知识(二) Testbench编写
文章图片

Testbench代码的本质是通过模拟输入信号的变化来观察输出信号是否符合设计要求!因此,Testbench的核心在于如何模拟输入信号,并把模拟的输入信号输入到功能模块中产生输出信号,如上图所示。解决方案为:

  • 通过随机数产生输入信号
  • 通过实例化模块把模拟输入信号传入功能模块中
1 3-8译码器Testbench代码 1.1现有的功能模块为3-8译码器,其功能模块的RTL代码为:
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

1.2 对应Testbench代码为:
`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.3 代码说明 (1) 时间单位:时间尺度预编译指令 时间单位 / 时间精度
  • 定义时间单位: `timescale 1ns/1ns表示时间单位为1ns,时间精度为1ns
  • 时间单位和时间精度由值 1、10、和 100 以及单位 s、ms、us、ns、ps 和 fs 组成
  • 时间单位不能比时间精度小
  • 仿真过程所有与时间相关量的单位(即1单位的时间)
  • 时间精度:决定时间相关量的精度及仿真显示的最小刻度1ns/1ps精度为.0.01ns
(2) 延时:#数字
  • #10表示延时10个单位的时间,时间单位为1ns时,该语句表示延时10ns
(3) 测试模块的命名:tb_<功能模块名>
  • 功能模块名为:decoder3_8, 则对应测试模块名为:tb_decoder3_8
(4) 需要定义模拟的输入/输出信号:
  • 输入/输出信号与功能模块中定义的输入/输出信号保持一致
  • 输入信号一般定义为 reg 型信号,因为后面需要在always/initial语句块中被赋值
  • 输出信号一般为 wire型即可
(5) 输入信号初始化
  • 用initial 语句进行初始化,该语句中的代码块只执行一次
  • 根据需要初始化为0/1都可
(6) 用always 语句实现信号在仿真过程中的电平变化
  • always在仿真过程中将被多次执行
  • always #10 in <= {$random} % 8; 表示每隔10个时间单位in的电平变化一次:
    {$random}%8表示随机选取[0,7]之间的数
  • in <= {$random} % 8; 在赋值时会自动进行数据类型转换
  • always后面最好只有一条语句
(7) 通过实例化模块把模拟输入信号传入功能模块中
  • 即把模拟的输入信号传入到功能模块中即可
(8) 通过 $monitor实现变量实时监测
  • 实时打印输入输出信号的数值,以便于监测
  • $monitor等系统函数要在initial语句块中

2常用系统函数 testbench文件中编写的系统函数要在initial语句块中!
2.1$timeformat 设置显示时间的格式 使用格式:
$timeformat(time_unit, decimal_number, suffix_string, minimum_field_wdith);

  • time_unit:时间单位,为一个数字。0(s)、-3(ms)、-6(us)、-9(ns)、-12(ps)、
    -15(ps),也可使用中间值:-10表示100ps为单位
  • decimal_number:打印时间值的小数位
  • suffix_string:跟在时间值后的字符串(后缀字符串),一般写对应的时间单位ns、ps等
  • minimum_field_wdith:是时间值字符串与后缀字符串合起来的这部分字符串的最小长度
  • 主要用途:更改$write、$display、$strobe、$monitor、$fwrite、$fdisplay、$fstrobe、$fmonitor等任务在%t格式下显示时间的方式
2.2 其他常用系统函数
$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格式化输出

2.2.1 以 $display 用于输出、打印信息为例
【FPGA|Verilog基础知识(二) Testbench编写】用法:
$display("Add:%b+%b=%d",a, b, c); //格式“%b+%b=%d” 格式控制,未指定时默认十进制

  • %b:表示对应位置显示二进制数
  • %d:表示对应位置显示十进制数
  • a, b, c 为与格式控制语句中格式控制符顺序对应的需要打印的变量

    推荐阅读