【0基础学会Verilog】003. 为Verilog模块编写测试模块testbench

这篇具有很好参考价值的文章主要介绍了【0基础学会Verilog】003. 为Verilog模块编写测试模块testbench。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

完成了C语言函数(function)或Verilog功能模块(module)的编写,接下来我们需要对其进行测试、仿真等手段来验证函数或模块的正确性。本篇博文介绍为一个给定的Verilog模块编写仿真模块,也就是所谓testbench的方法。

我们为上一篇博文【0基础学会Verilog】002. Verilog时序逻辑实现C语言函数所述的calc_wire()以及calc_reg()两种类型的Verilog模块编写相关testbench

1. 为C语言的calc()编写测试模块

还是先以C语言函数的测试为例,为了测试calc_v2()函数模块,我们需要编写一个完整的可执行程序,程序内部调用我们准备测试的calc_v2()函数。

为方便比对,这里我们将待测函数calc_v2()代码列在此处。

//使用指针的C语言函数,计算表达式((a+b) - c * 8)的值
void calc_v2 (
    int a, 
    int b, 
    int c, 
    int* sum)
{
    int tmp = 0;
    tmp = (a+b) - c * 8;
    *sum = tmp;
}

下面代码我们编写一个console程序,为简单起见只有main()函数。从代码分析可以看出一个测试模块的编写主要分为三个部分:

  • 给出待测函数要求的输入参数;
  • 调用待测函数并提取运算结果;
  • 显示函数计算的结果用于比对和验证。
//C语言函数calc_v2()的测试程序
void main(void){
    //1. 给出待测函数要求的输入参数
    int aa = 3;
    int bb = 4;
    int cc = 7;

    //2. 调用待测试函数,并将结果保存到整数dd中
    int dd = calc(aa,bb,cc);

    //3. 显示函数计算的结果用于比对和验证
    printf("(%d +%d)-%d*8 = %d",aa,bb,cc,dd);
}

2. 为calc_wire()模块编写Testbench

Verilog编写的硬件模块设计代码最终是作为FPGA整体设计的一部分,类似于搭积木块的形式完成整体功能。涉及硬件的调试往往代价比较高,无论是时间成本和经济成本都较高。

因此,独立功能的硬件模块代码需要预先充分验证、测试,以保证其功能和性能满足要求,才能集成到系统内部。这也是学习Verilog硬件设计时我们一定要先学会为指定模块编写testbench的原因。

下面的代码完成类似上面C语言main()函数的功能,给定相关的输入数据,调用待测模块,得到模块(/函数)的输出加以验证。

验证可以是自动的,即用所谓Golden Data与模块的输出进行自动比对,直接给出结论。简单的情况下也可以只输出模块的结果,由设计者或测试者自己判断。特别是在调试阶段,对于简单的模块一般采取后者即可。至于自动验证方法,功能强大,但一般比较繁琐,本专栏的主要目标是带领大家学习Verilog的语法,就暂时不涉及完善的测试模块实现,以后另开篇幅介绍验证语言SystemVerilog

为了方便比对学习,同样,我们也把待测的Verilog模块源码列于此处。

//用组合逻辑实现与calc_v2()函数相同的功能
module calc_wire(
    input wire [31:0] a,
    input wire [31:0] b,
    input wire [31:0] c,
    output wire [31:0] sum
);
    wire [31:0] tmp;
    assign tmp = (a+b) - c * 8;
    assign sum = tmp;
endmodule

下面我们开始为calc_wire()编写仿真模块(testbench)

`timescale 1ns/1ps  
//timescale代表时间尺度
//时间单位:1ns, 时间精度:1ps
//下面代码中``#``号后面的数字就是时间,单位是ns
//例如,``#200``表示等待200ns才继续下一个操作

//模块名的声明
//注意:仿真的顶层模块是没有输入和输出参数
//比如下面一行的();表示参数为空
module calc_wire_testbench();
    
    //1. 为待测模块要求的每个输入信号(input)
    //   声明一个对应的reg型变量
    reg [31:0] aa;
    reg [31:0] bb;
    reg [31:0] cc;

    //2. 为待测模块要求的每个输出信号(output)
    //   声明一个对应的wire型变量
    wire [31:0] sum;

    //3. 使用initial块为输入信号变量赋值
    initial begin
        aa = 3;
        bb = 4;
        cc = 7;
    end

    //4. 调用待测试模块(DUT:Design Under Test),
    //   将信号aa,bb,cc的值分别传递给模块的输入参数a,b,c
    //   并将模块运算结果通过sum提取出来
    calc_wire dut(
        .a(aa),
        .b(bb),
        .c(cc),

        .sum(sum)
    );

    //5. 使用initial块显示模块运算的结果,
    //  并在等待一段时间后结束仿真
    initial begin
        #300; //等待 300ns
        $display("result of ((%d +%d) - %d * 8) is %d",
                  aa,bb,cc,sum);
        $finish; //结束仿真
    end
endmodule

3. 为calc_reg()模块编写Testbench

//时间单位:1ns, 时间精度:1ps
`timescale 1ns/1ps     

module calc_reg_testbench();
    
    //1. 时序逻辑需要至少一个时钟信号
    //   因此,testbench必须生成一个虚拟的时钟信号
    reg clk;
    initial begin
        clk = 0;

        forever begin   //死循环
        #5;             //wait 5ns
        clk = ~clk;     //invert the clk
        end
    end

    //2. 给出待测模块需要的输入参数
    reg [31:0] aa;
    reg [31:0] bb;
    reg [31:0] cc;

    initial begin
        aa = 3;
        bb = 4;
        cc = 7;
    end

    //3. 调用待测试函数,并将结果保存到整数dd中
    wire [31:0] sum;
    calc_wire dut(
        .clk(clk),    //时序逻辑必须输入时钟信号

        .a(aa),
        .b(bb),
        .c(cc),

        .sum(sum)
    );

    //4. 显示函数计算的结果用于比对和验证
    initial begin
        #300;
        $display("(%d +%d) - %d * 8 =  %d",aa,bb,cc,sum);
        $finish;
    end

endmodule

4. 用Vivado自带仿真器进行验证

5. 扩展练习

下面的C语言函数calc_v3()基于指针实现多输入和多输出的功能,完成以下作业:文章来源地址https://www.toymoban.com/news/detail-854032.html

  • 组合逻辑将下面的C语言函数转换为Verilog语言的wire版硬件模块calc_v3_wire()
  • 时序逻辑将下面的C语言函数转换为Verilog语言的reg版硬件模块calc_v3_reg()
  • 编写用于测试C语言函数calc_v3()C语言程序主函数main()
  • 为wire版Verilog模块calc_v3_wire()编写Testbench;
  • 为reg版Verilog模块calc_v3_reg()编写Testbench;
//实现多输入和多输出的功能模块
void calc_v3(
    //输入参数
    int a, int b, int c, 
    //输出参数
    int* d, int* e)
{
    //计算d的值并输出
    int dd = 0;
    dd = (a+b) - c * 8;
    *d = dd;

    //计算e的值并输出
    int ee = 0;
    ee = (a+c) - (b << 2);
    *e = ee;

    return;
}

到了这里,关于【0基础学会Verilog】003. 为Verilog模块编写测试模块testbench的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • ASIC-WORLD Verilog(10)编写测试脚本Testbench的艺术

            在自己准备写一些简单的verilog教程之前,参考了许多资料----Asic-World网站的这套verilog教程即是其一。这套教程写得极好,奈何没有中文,在下只好斗胆翻译过来(加了自己的理解)分享给大家。         这是网站原文:Verilog Tutorial         这是系列导航:

    2024年02月07日
    浏览(38)
  • verilog基础-模块例化

    verilog语法中的模块例化 FPGA的设计通常都是由很多个模块组成,有顶层模块、高层模块和子模块之分,模块例化的功能即为 连接这些模块 。 以数码管显示代码为例,根据要实现的功能,需在顶层模块中对计时模块和数码管静态显示模块分别例化。 计时模块代码如下: 数码

    2024年02月11日
    浏览(38)
  • Huff实战:编写测试极致效率数学模块

    读者可前往 我的博客 获得更好的阅读体验。 Huff 是 EVM 专用语言,与 Solidity 不同,Huff 是面向底层的语言,可以类比与汇编语言。这意味着开发者可以直接操作栈、内存和存储等内容,但另一方面,这些底层操作往往没有安全保证,这需要开发者更加仔细的审计和测试代码。

    2024年02月10日
    浏览(38)
  • 【Verilog】期末复习——设计带进位输入和输出的8位全加器,包括测试模块

    数值(整数,实数,字符串)与数据类型(wire、reg、mem、parameter) 运算符 数据流建模 行为级建模 结构化建模 组合电路的设计和时序电路的设计 有限状态机的定义和分类 期末复习——数字逻辑电路分为哪两类?它们各自的特点是什么? 期末复习——VerilogHDL描述数字逻辑电

    2024年01月23日
    浏览(61)
  • Verilog基础语法(4)之模块和端口及其例化和处理

    Verilog进行FPGA/IC设计值,通常划分为各个子模块,木模块之间可能相互例化,并在顶层统一例化,并连接成一个顶层模块文件。 基本的模块模板: 如果模块内的变量位宽参数化,则模块模板为: 例化带参数的模块: 端口类型/端口描述 input 设计模块只能使用其input端口从外部

    2024年02月13日
    浏览(37)
  • FPGA学习笔记:verilog基础代码与modelsim仿真(六)——vga显示模块

    VGA显示 目标:实现屏幕红、橙、黄、绿、青、蓝、紫、黑、白、灰条形显示 1. 模块框图与波形图 vga_colorbar是实现目标功能的总体模块框图,为了实现对应的输出,我们使用三个具体功能模块实现功能。 (1) clk_gen——使用pll锁相环实现时钟分频 (2)vga_ctrl——图像控制与输出模

    2024年02月04日
    浏览(42)
  • 【FPGA】verilog基础语法与应用:位操作 / 模块调用——流水灯(跑马灯)

    今天的实验是计数器实验的升级,设计让8个LED灯以每个0.5s的速率循环闪烁 1 移位法实现 1.1 移位方法1 每个LED灯代表一位,共8位,亮为1,灭为0 如何实现这样的逻辑呢? 移位操作即可! 怎么样才能移位呢? 第一个状态需满足最低位为1,然后每次左移1个 源代码 仿真代码 功

    2024年01月16日
    浏览(50)
  • 【NodeJS】003- NodeJS的path模块与Http模块

    path 模块提供了 操作路径 的功能,较为常用的几个 API: API 说明 path.resolve 拼接规范的绝对路径   常用 path.sep 获取操作系统的路径分隔符 path.parse 解析路径并返回对象 path.basename 获取路径的基础名称 path.dirname 获取路径的目录名 path.extname 获得路径的扩展名  代码演示 2.1、概

    2024年02月21日
    浏览(45)
  • springboot基础学习 之编写单元测试和集成测试。

    编写单元测试和集成测试是保障应用程序质量的关键步骤。单元测试主要用于测试单个组件或模块的功能,而集成测试则关注不同组件之间的协作。下面分别介绍如何编写单元测试和集成测试。 单元测试(Unit Testing): 1. 选择测试框架: 选择适合你项目的测试框架,例如

    2024年02月02日
    浏览(45)
  • 手把手教你如何0基础编写基于AI机器视觉的--王者荣耀百里守约的自瞄程序,我家村头的傻X都能学会的教程!

    不介绍上面的框架了,直入主题: 先安装Anaconda,这是python环境的切换神器! 此处借用Anaconda安装教程 好 现在你安好了。打开cmd,直接输入conda看下是否有命令输出。如果没有,那就是path系统变量你没添加Anaconda。或者你在开始菜单,找到并打开anaconda Prompt (Anaconda3),可以看

    2024年02月14日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包