Testbench介绍及其重作用

编写Testbench的主要目的是为了对使用硬件描述语言(HDL)设计的电路进行仿真验证,测试设计电路的功能、部分性能是否与预期的目标相符。
  博主在刚开始入门FPGA时把写RTL代码当成重点,不愿写Testbench,仅仅使用Quartus II自带的仿真产生几个激励,然后观察一下最后输出的波形就完事了。有段时间甚至直接忽视仿真,拿单片机在线调试那一套来对付FPGA,直接把代码下载到板子里看效果,若与预期不符,再修改代码,再次下载到板子,如此反复,效率、效果都很低。
  后来随着深入地了解,发现FPGA水很深,而且和单片机等有很大的不同。因此劝各位要管住自己、不去使用Quartus II自带的仿真。如果你立志从事FPGA行业,那么会写Testbench才你的敲门砖,才是去大厂的门票,别想着去公司写RTL代码了,公司一定是让你来写Testbench测试文件的。
  Testbench作为Modelsim的激励文件,也是自成体系的,同样具有规范化的设计,需要完美的风格及苛刻的结构
  本篇只讲Testbench测试代码的推荐编写规范,Modelsim仿真步骤请移步另一篇博客https://blog.csdn.net/zhaogoudan/article/details/111663758。

一个最基本的Testbench包含三个部分,信号定义、模块接口和功能代码。借用一下特权同学总结的编写Testbench的三个基本步骤:

  1. 对被测试设计的顶层接口进行例化;

  2. 给被测试设计的输入接口添加激励;

  3. 判断被测试设计的输出相应是否满足设计要求

    逐步解决编写Testbench的这三点:

对被测试设计的顶层接口进行例化

首先“对被测试设计的顶层接口进行例化”,这一步相对比较简单,就是简单的例化,但端口多时,也比较困难,而且要分wire、reg,有时会弄错。这里我推荐大家可以偷个懒,通过Quartus II自动生成一个Testbench的模板,里面会自动例化好顶层的接口。
  步骤:选择Processing -> Start -> Start Test Bench Template Writer,等待完成后打开刚才生成的Testbench,默认是保存在simulation\Modelsim文件夹下的.vt格式文件。这一步就不多讲了,偷懒就挺好。

给被测试设计的输入接口添加激励

其次“给被测试设计的输入接口添加激励”,一般时序设计必然涉及到最基本的两个信号——clk、rst_n(时钟、复位)。肯定有朋友会讲可以没有rst_n,是可以没有,但让代码更丰富、更严谨没有错。下面来看看激励clk、rst_n的写法:
首先先讲一下timescale,因为想要进行仿真首先要规定时间单位,而且最好在Testbench里面统一规定时间单位,而不要在工程代码里定义,因为不同的模块如果时间单位不同可能会为仿真带来一些问题,而timescale本身对综合也就是实际电路没有影响。 `timescale 1ns/ 1ps表示仿真的单位时间为1ns,精度为1ps。

系统时钟的三种写法 :

`timescale 1ns/1ps
initialclk = 0;
always#10 clk <= ~clk;
`timescale 1ns/1ps
initial beginclk = 0;forever#10 clk = ~clk;
end
`timescale 1ns/1ps
always begin#10 clk <= 0;#10 clk <= 1;
end

上述三种代码的目的就是产生系统时钟,给clk一个初值后,不断重复执行:每10ns翻转一次clk,从而生成一个周期为20ns,频率50MHz的方波信号。第一、二种基本类似,第三种比较简单,少了一个initial,放在了always里初始化。

三种方法都无一例外地给clk赋了初值,因为信号的缺省值为Z,如果不赋初值,则反相后还是Z,时钟就一直处于高阻Z状态。

复位信号rst_n的两种写法

根据复位方式的不同,rst_n一般有两种写法:

`timescale 1ns/1ps
initial beginrst_n = 1;#100 rst_n = 0;#500 rst_n = 1;
end
//同步复位
`timescale 1ns/1ps
initial beginrst_n = 1;@(negedge clk) //等待时钟下降沿repeat(3) @(negedge clk);rst_n = 1;
end

上述两种代码的目的基本都是延时复位,但一个异步复位,一个同步复位,用途不同。

一种推荐的时钟发生器编写规范

推荐!

//clock generate moudle
initial
begin                                                  clk = 0;forever #(PERIOD/2)clk = ~clk;
end                                                    //将复位信号封装在Task(任务)当中
task task_reset;
beginrst_n = 0;repeat(2) @(negedge clk); //等待clk出现两个下降沿之后,才继续执行后续语句rst_n = 1;
end
endtask

判断被测试设计的输出相应是否满足设计要求

最后“判断被测试设计的输出相应是否满足设计要求”。首先介绍最常用的两个系统任务函数 $ stop和$ finish。$ stop代表暂停仿真后返回软件操作主窗口,将控制权交给user;$ finish代表终止仿真后关闭软件操作主窗口。其他任务函数如$ monitor、$ display 、$ time、$ fwrite等也比较重要,用到的时候再一一介绍。
RTL代码:

  * All rights Reserved, Designed By https://blog.csdn.net/zhaogoudan* @projectName     :led* @title            :    * @description     :LED自加  * @author           :zhaodongliang* @date               :21/01/07  * @version       :V1.0.0* @copyright ${YEAR} https://blog.csdn.net/zhaogoudan*/
module led(input                clk,input               rst_n,output reg [3:0]  led_data
);//---------------------------
//Delay for 0.3s
localparam DELAY_TOP = 24'd15_000_000;
//localparam DELAY_TOP = 24'd4;           //just for testreg  [23:0]  delay_cnt;
always @(posedge clk or negedge rst_n) beginif(!rst_n)delay_cnt <= 24'd0;else if(delay_cnt < DELAY_TOP) delay_cnt <= delay_cnt + 1'b1;elsedelay_cnt <= 24'd0;
endwire delay_done = (delay_cnt == DELAY_TOP) ? 1'b1 : 1'b0;//----------------------------
always @(posedge clk or negedge rst_n) beginif(!rst_n)led_data <= 4'd0;else if(delay_done) beginif(led_data < 4'd15)led_data <= led_data + 1'b1;elseled_data <= 4'd0;end
end
endmodule

testbench代码

`timescale 1 ns/ 1 ns
module led_vlg_tst();localparam PERIOD = 20;reg clk;
reg rst_n;
// wires
wire [3:0]  led_data;// assign statements (if any)
led i1 (
// port map - connection between master ports and signals/registers   .clk(clk),.led_data(led_data),.rst_n(rst_n)
);initial
begin                                                  clk = 0;forever #(PERIOD/2)clk = ~clk;
end                                                    task task_reset;
beginrst_n = 1'b0;repeat(2) @(negedge clk)rst_n = 1'b1;
end
endtask//-------------------
//systerm initialization
task task_sysinit;
begin
end
endtask//--------------------
//testbench of the RTL
initial
begintask_sysinit;      //必须先进行系统初始化task_reset;         //再进行复位//然后才能进行其他的激励
endendmodule

Testbench可以通过设计Task功能来实现任务的模块化编写及调用,而这些部分的目的就是为了在最后生成待测试的测试激励。
在测试激励生成的代码编写规范中,要遵守以下几点:

  1. 采用initial设计,生成现成的激励
  2. 为了可移植性,激励都通过Task编写调用
  3. 必须先进行系统初始化,接着进行复位,然后才能进行其他的激励
    如下所示:
//testbench of the RTLinitial
begintask_sysinit;      //必须先进行系统初始化task_reset;         //再进行复位//然后才能进行其他的激励
end

输入
必须为reg,因为对于testbench来说输入其实是要输出给测试模块的,也就是相当于需要一个东西来存储,所以是register类型

输出
必须为wire,因为对于testbench来说输出其实是测试模块的输入,也就是需要通过wire来进行连接

—————————————————————————————————

【FPGA自学总结】Testbench测试代码推荐编写规范相关推荐

  1. junit编写测试代码_编写数据访问代码测试-不测试框架

    junit编写测试代码 当我们向数据访问代码编写测试时,是否应该测试其公共API的每种方法? 一开始听起来很自然. 毕竟,如果我们不测试所有内容,那么如何知道我们的代码可以按预期工作? 这个问题为我们 ...

  2. junit编写测试代码_编写数据访问代码测试–绿色建筑不够好

    junit编写测试代码 开始为数据访问代码编写集成测试之前,我们要做的第一件事是决定如何配置测试用例. 我们有两种选择:正确的一种和错误的一种. 不幸的是,许多开发人员选择错误. 我们如何避免犯同样的 ...

  3. 03_MyBatis基本查询,mapper文件的定义,测试代码的编写,resultMap配置返回值,sql片段配置,select标签标签中的内容介绍,配置使用二级缓存,使用别名的数据类型,条件查询ma

     1 PersonTestMapper.xml中的内容如下: <?xmlversion="1.0"encoding="UTF-8"?> < ...

  4. Emmet:HTML/CSS代码快速编写规范(转发)

    Emmet的前身是大名鼎鼎的Zen coding,如果你从事Web前端开发的话,对该插件一定不会陌生.它使用仿CSS选择器的语法来生成代码,大大提高了HTML/CSS代码编写的速度,比如下面的演示: ...

  5. VS2010 测试功能之旅:编码的UI测试(4)-通过编写测试代码的方式“.NET研究”建立UI测试(下)...

    回顾 最近比较忙,距离上次更新的时间较久,见谅. 在本章上部分,介绍了"添加用户"窗口的测试代码编写.想必大家也看到了,在UIMap.cs文件中实现自定义编码是一件很轻松的事情,接 ...

  6. Modelsim联合Matlab进行FPGA图像处理仿真与测试的学习总结(以RGB转Ycbcr转Gray为例)

    文章目录 一.Modelsim联合Matlab进行FPGA图像仿真的步骤 二.具体实现方法 2.1 新建一个Modelsim项目并编写测试代码 2.2 新建v文件来编写待测试代码 2.3 建成项目后, ...

  7. 领导让我重写测试代码,我该怎么办?

    我有一个朋友,有一天问我这样的一个问题:"说现在他们公司有五个 python 测试工程师.但是有一天领导要求他把所有的自动化测试代码,全部都转化成 Java 语言." 虽然说他们在 ...

  8. S3C6410开发板adc驱动代码分析及测试代码分析

    在本文中,我们对S3C6410开发板adc驱动代码的实现过程进行分析,然后通过一个实例对adc功能进行测试.在本文的资源中包含了设备驱动的源码和测试的源码. 一.设备驱动源码分析 adc的设备驱动主要 ...

  9. S3C6410开发板LED驱动代码分析及测试代码分析

    在本文中,我们对S3C6410开发板LED驱动代码的实现过程进行分析,然后通过一个实例对LED进行控制.在本文的资源中包含了设备驱动的源码和测试的源码. 一.设备驱动源码分析 设备驱动主要实现了模块的 ...

  10. S3C6410开发板按键驱动代码分析及测试代码分析

    在本文中,我们对S3C6410开发板按键驱动代码的实现过程进行分析,然后通过一个实例对按键功能进行测试.在本文的资源中包含了设备驱动的源码和测试的源码. 一.设备驱动源码分析 按键的设备驱动主要实现了 ...

最新文章

  1. 【杂谈】为什么邀请大家加入硬核知识星球有三AI
  2. 1020 月饼 (25 分)(c语言)
  3. 王彪20162321 2016-2017-2 《程序设计与数据结构》第5周学习总结
  4. camvid数据集使用方法_使用PyTorch处理CIFAR10数据集并显示
  5. 在 Gitee 上使用 GPG公钥(Beta版)
  6. rabbitmq rpc
  7. ArcGIS Desktop10.2与CityEngine2012兼容问题
  8. 【图像处理算法】直方图均衡化
  9. Pandas实战-Series的方法
  10. 2019年终总结2020个人规划和目标
  11. licecap免费+轻量+使用简单的录屏制作gif工具
  12. 计算机网络基础——网络的性能
  13. 角度转度分秒lisp函数_自改小程序,提示错误,运行另一个lisp后就不会出错,求帮忙!...
  14. 图像对齐讲座—旷世成都研究院 数据策略产品经理——阿里讲座
  15. 开启Fluter基础之旅三-------Material Design风格组件、Cupertino风格组件、Flutter页面布局篇...
  16. office提示为什么要冒险的解决办法
  17. kettle使用过程记录(详细)
  18. Linux下挂载移动硬盘和USB的方法
  19. Concepts:Stateful Stream Processing
  20. 反射内存卡读写测试(RFM2gRead和RFM2gWrite)-- C++

热门文章

  1. Java小游戏程序打包成exe文件
  2. asp.net中使用FreeTextBox控件
  3. PMP 考试一定要报培训班吗?(PMP备考资料分享)
  4. Java用POI导出Excel表格中的数据
  5. 时钟芯片ds1302的使用
  6. R 语言的安装(详细教程)
  7. Android App 启动时立即崩溃无法debug的解决方法
  8. ASP.NET MVC- UrlHelper的用法
  9. Python学习手册(第4版).pdf
  10. 什么是软件著作权,怎么申请软件著作权