当前位置:   article > 正文

FPGA入门基础之Testbench仿真文件编写示例_testbench编写与仿真

testbench编写与仿真

引言:在编写完HDL代码后,往往需要通过仿真软件Modelsim或者Vivadao自带的仿真功能对HDL代码功能进行验证,此时我们需要编写Testbench文件对HDL功能进行测试验证。本文我们介绍写Testbench编写的一些要点。

1.Testbench文件结构模板

编写Testbench的目的是为了测试设计电路的功能、性能与设计的预期是否相符。验证软件功能通过包括以下步骤:
      • 产生合适的模拟激励(波形):该激励通常要覆盖被测HDL模块(黑盒或者称作DUT模块)所有可能得输入状态;
      • 将产生的激励加入到被测试模块中并观察其响应:即将DUT模块例化到Testbench文件中,运行仿真软测测试;
      • 将输出响应与期望值相比较:该步骤是验证DUT功能较耗时的部分,需要仔细分析代码功能是否达到预期设计,所有代码段功能是否正常。

Testbench结构一般模板如下:

  1. module Test_bench_name();//通常无输入无输出
  2. //01:信号或变量声明定义
  3. //--逻辑设计中输入对应 reg 型
  4. //--逻辑设计中输出对应 wire 型
  5. //02:使用 initial 或 always 语句产生激励
  6. //03:例化待测试DUT模块
  7. //04:监控和比较输出响应
  8. endmodule

2.时钟激励输入示例

常见的时钟有:50%占空比连续时钟、固定周期数时钟、非50%占空比时钟,示例如下。

  1. /*----------------------------------------------------------------
  2. 时钟激励产生方法一:50%占空比时钟
  3. ----------------------------------------------------------------*/
  4. parameter ClockPeriod=10; //参数化时钟周期
  5. initial
  6. begin
  7. clk_i=0;
  8. forever#(ClockPeriod/2) clk_i = ~clk_i;
  9. end
  10. /*----------------------------------------------------------------
  11. 时钟激励产生方法二:50%占空比时钟
  12. ----------------------------------------------------------------*/
  13. initial
  14. begin
  15. clk_i=0;
  16. end
  17. always #(ClockPeriod/2) clk_i=~clk_i;
  18. /*----------------------------------------------------------------
  19. 时钟激励产生方法三:产生固定数量的时钟脉冲
  20. ----------------------------------------------------------------*/
  21. parameter ClockPeriod=10; //参数化时钟周期
  22. initial
  23. begin
  24. clk_i=0;
  25. repeat(6)
  26. #(ClockPeriod/2) clk_i=~clk_i;
  27. end
  28. /*----------------------------------------------------------------
  29. 时钟激励产生方法四:产生非占空比为 70%的时钟
  30. ----------------------------------------------------------------*/
  31. parameter ClockPeriod=10; //参数化时钟周期
  32. initial
  33. begin
  34. clk_i=0;
  35. forever
  36. begin
  37. #((ClockPeriod/2)-2) clk_i=0;
  38. #((ClockPeriod/2)+2) clk_i=1;
  39. end
  40. end

3.复位激励输入示例

复位输入主要包括异步复位、同步复位,代码示例如下。

  1. /*----------------------------------------------------------------
  2. 复位信号产生方法一:异步复位
  3. ----------------------------------------------------------------*/
  4. initial
  5. begin
  6. rst_n_i=1;
  7. #100; rst_n_i=0;
  8. #100; rst_n_i=1;
  9. end
  10. /*----------------------------------------------------------------
  11. 复位信号产生方法二:同步复位
  12. ----------------------------------------------------------------*/
  13. initial
  14. begin
  15. rst_n_i=1; clk_i = 0;
  16. @(negedge clk_i)
  17. rst_n_i=0;
  18. #100; //固定时间复位
  19. repeat(10) @(negedge clk_i); //固定周期数复位
  20. @(negedge clk_i)
  21. rst_n_i=1;
  22. end
  23. always #5 clk_i=~clk_i;
  24. /*----------------------------------------------------------------
  25. 复位信号产生方法三:复位任务封装
  26. ----------------------------------------------------------------*/
  27. task reset;
  28. input [31:0] reset_time; //复位时间可调,输入复位时间
  29. RST_ING=0; //复位方式可调,低电平或高电平
  30. begin
  31. rst_n_i=RST_ING; //复位中
  32. #reset_time; //复位时间
  33. rst_n_i=~RST_ING; //撤销复位,复位结束
  34. end
  35. endtask

4.双向口inout示例

  1. /*----------------------------------------------------------------
  2. 双向信号inout 在 testbench 中定义为 wire 型变量
  3. ----------------------------------------------------------------*/
  4. reg sck;
  5. wire sda; //inout信号sda定义为wire型
  6. wire sda_r; //
  7. reg sda_en;
  8. assign sda_r = (sda_en) ? mosi : 1'bz;
  9. assign sda =sda_r;

5.特殊信号设计

  1. /*----------------------------------------------------------------
  2. 特殊激励信号产生描述一:输入信号任务封装
  3. ----------------------------------------------------------------*/
  4. task i_data;
  5. input [7:0] dut_data;
  6. begin@(posedge data_en); send_data=0;
  7. @(posedge data_en); send_data=dut_data[0];
  8. @(posedge data_en); send_data=dut_data[1];
  9. @(posedge data_en); send_data=dut_data[2];
  10. @(posedge data_en); send_data=dut_data[3];
  11. @(posedge data_en); send_data=dut_data[4];
  12. @(posedge data_en); send_data=dut_data[5];
  13. @(posedge data_en); send_data=dut_data[6];
  14. @(posedge data_en); send_data=dut_data[7];
  15. @(posedge data_en); send_data=1;
  16. #100;
  17. end
  18. endtask
  19. //调用方法:i_data(8'hXX);
  20. /*----------------------------------------------------------------
  21. 特殊激励信号产生描述二:多输入信号任务封装
  22. ----------------------------------------------------------------*/
  23. task more_input;
  24. input [7:0] a;
  25. input [7:0] b;
  26. input [31:0] times;
  27. output [8:0] c;
  28. begin
  29. repeat(times) //等待 times 个时钟上升沿
  30. @(posedge clk_i) c=a+b; //时钟上升沿 a,b 相加
  31. end
  32. endtask
  33. //调用方法:more_input(x,y,t,z); //按声明顺序
  34. /*----------------------------------------------------------------
  35. 特殊激励信号产生描述三:输入信号产生,一次 SRAM 写信号产生
  36. ----------------------------------------------------------------*/
  37. initial
  38. begin
  39. cs_n=1; //片选无效
  40. wr_n=1; //写使能无效
  41. rd_n=1; //读使能无效
  42. addr=8'hxx; //地址无效
  43. data=8'hzz; //数据无效
  44. #100; cs_n=0; //片选有效
  45. wr_n=0; //写使能有效
  46. addr=8'hF1; //写入地址
  47. data=8'h2C; //写入数据
  48. #100; cs_n=1; wr_n=1;
  49. #10; addr=8'hxx;
  50. data=8'hzz;
  51. end
  52. /*----------------------------------------------------------------
  53. 特殊激励信号产生描述四:@与 wait
  54. ----------------------------------------------------------------*/
  55. //@使用沿触发
  56. //wait 语句都是使用电平触发
  57. initial
  58. begin
  59. start=1'b1;
  60. wait(en=1'b1);
  61. #10; start=1'b0;
  62. end

6.仿真控制语句及系统任务描述

  1. /*----------------------------------------------------------------
  2. 仿真控制语句及系统任务描述
  3. ----------------------------------------------------------------*/
  4. $stop // 停止运行仿真,modelsim 中可继续仿真
  5. $stop(n) //带参数系统任务,根据参数 0,12不同,输出仿真信息
  6. $finish //结束运行仿真,不可继续仿真
  7. $finish(n) //带参数系统任务,根据参数 0,12不同,输出仿真信息
  8. //0:不输出任何信息
  9. //1:输出当前仿真时刻和位置
  10. //2:输出当前仿真时刻、位置和仿真过程中用到的 memory 以及 CPU 时间的统计
  11. $random //产生随机数
  12. $random % n //产生范围-n 到 n 之间的随机数
  13. {$random} % n //产生范围 0 到 n 之间的随机数
  14. /*----------------------------------------------------------------

7. 仿真终端显示描述

  1. /*----------------------------------------------------------------
  2. 仿真终端显示描述
  3. ----------------------------------------------------------------*/
  4. $monitor //仿真打印输出, 打印出仿真过程中的变量,使其终端显示
  5. /*$monitor($time,,,"clk=%d reset=%d out=%d",clk,reset,out);*/
  6. $display //终端打印字符串,显示仿真结果等
  7. /*
  8. $display(” Simulation start ! ");
  9. $display(” At time %t,input is %b%b%b,output is %b",$time,a,b,en,z); */
  10. $time //返回 64 位整型时间
  11. $stime //返回 32 位整型时间
  12. $realtime //实行实型模拟时间

8. 文本输入方式
 

  1. /*----------------------------------------------------------------
  2. 文本输入方式:$readmemb/$readmemh
  3. ----------------------------------------------------------------*/
  4. //verilog 提供了读入文本的系统函数
  5. $readmemb/$readmemh("<数据文件名>",<存储器名>);
  6. $readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>);
  7. $readmemb/$readmemh("<数据文件名>",<存储器名>,<起始地址>,<结束地址>);
  8. $readmemb:/*读取二进制数据,读取文件内容只能包含:空白位置,注释行,二进制数
  9. 数据中不能包含位宽说明和格式说明,每个数字必须是二进制数字。*/
  10. $readmemh:/*读取十六进制数据,读取文件内容只能包含:空白位置,注释行,十六进制数
  11. 数据中不能包含位宽说明和格式说明,每个数字必须是十六进制数字。*/

图片

欢迎关注FPGA技术实战公众号,喜欢就多多转发吧!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/805138
推荐阅读
相关标签
  

闽ICP备14008679号