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

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

1.Testbench文件结构模板

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

Testbench结构一般模板如下:

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

2.时钟激励输入示例

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

/*----------------------------------------------------------------
时钟激励产生方法一:50%占空比时钟
----------------------------------------------------------------*/
parameter ClockPeriod=10; //参数化时钟周期
initial
  begin
    clk_i=0;
    forever#(ClockPeriod/2) clk_i = ~clk_i; 
end

/*---------------------------------------------------------------- 
时钟激励产生方法二:50%占空比时钟
----------------------------------------------------------------*/
initial
begin
  clk_i=0; 
end
always #(ClockPeriod/2) clk_i=~clk_i;

/*---------------------------------------------------------------- 
时钟激励产生方法三:产生固定数量的时钟脉冲
----------------------------------------------------------------*/
parameter ClockPeriod=10; //参数化时钟周期
initial
begin
  clk_i=0; 
  repeat(6)
  #(ClockPeriod/2) clk_i=~clk_i; 
end

/*---------------------------------------------------------------- 
时钟激励产生方法四:产生非占空比为 70%的时钟
----------------------------------------------------------------*/
parameter ClockPeriod=10; //参数化时钟周期
initial
begin
clk_i=0;
forever
  begin
    #((ClockPeriod/2)-2) clk_i=0;
    #((ClockPeriod/2)+2) clk_i=1; 
    end
end

3.复位激励输入示例

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

/*---------------------------------------------------------------- 
复位信号产生方法一:异步复位
----------------------------------------------------------------*/
initial
begin
  rst_n_i=1;
  #100; rst_n_i=0;
  #100; rst_n_i=1; 
end
/*---------------------------------------------------------------- 
复位信号产生方法二:同步复位
----------------------------------------------------------------*/
initial
begin
  rst_n_i=1; clk_i = 0;
  @(negedge clk_i)
  rst_n_i=0;
  #100; //固定时间复位
  repeat(10) @(negedge clk_i); //固定周期数复位
  @(negedge clk_i)
  rst_n_i=1; 
end
always #5 clk_i=~clk_i;


/*---------------------------------------------------------------- 
复位信号产生方法三:复位任务封装
----------------------------------------------------------------*/
task reset;
input [31:0] reset_time; //复位时间可调,输入复位时间
  RST_ING=0; //复位方式可调,低电平或高电平
  begin
    rst_n_i=RST_ING; //复位中
    #reset_time; //复位时间
    rst_n_i=~RST_ING; //撤销复位,复位结束
  end
endtask

4.双向口inout示例

/*---------------------------------------------------------------- 
双向信号inout 在 testbench 中定义为 wire 型变量
----------------------------------------------------------------*/
reg  sck;
wire sda;   //inout信号sda定义为wire型
wire  sda_r; // 
reg  sda_en;
assign sda_r = (sda_en) ? mosi : 1'bz;
assign sda =sda_r;

5.特殊信号设计

/*---------------------------------------------------------------- 
特殊激励信号产生描述一:输入信号任务封装
----------------------------------------------------------------*/
task i_data;
  input [7:0] dut_data;
  begin@(posedge data_en); send_data=0;
    @(posedge data_en); send_data=dut_data[0];
    @(posedge data_en); send_data=dut_data[1];
    @(posedge data_en); send_data=dut_data[2];
    @(posedge data_en); send_data=dut_data[3];
    @(posedge data_en); send_data=dut_data[4];
    @(posedge data_en); send_data=dut_data[5];
    @(posedge data_en); send_data=dut_data[6];
    @(posedge data_en); send_data=dut_data[7];
    @(posedge data_en); send_data=1;
    #100; 
  end
endtask
//调用方法:i_data(8'hXX);

/*---------------------------------------------------------------- 
特殊激励信号产生描述二:多输入信号任务封装
----------------------------------------------------------------*/
task more_input;
  input [7:0] a;
  input [7:0] b;
  input [31:0] times; 
  output [8:0] c;
  begin
    repeat(times) //等待 times 个时钟上升沿
    @(posedge clk_i) c=a+b; //时钟上升沿 a,b 相加
  end
endtask
//调用方法:more_input(x,y,t,z); //按声明顺序

/*---------------------------------------------------------------- 
特殊激励信号产生描述三:输入信号产生,一次 SRAM 写信号产生
----------------------------------------------------------------*/
initial
begin
  cs_n=1; //片选无效
  wr_n=1; //写使能无效
  rd_n=1; //读使能无效
  addr=8'hxx; //地址无效
  data=8'hzz; //数据无效
  #100; cs_n=0; //片选有效
  wr_n=0; //写使能有效
  addr=8'hF1; //写入地址
  data=8'h2C; //写入数据
  #100; cs_n=1; wr_n=1;
  #10; addr=8'hxx;
  data=8'hzz; 
end

/*----------------------------------------------------------------
特殊激励信号产生描述四:@与 wait
----------------------------------------------------------------*/
//@使用沿触发
//wait 语句都是使用电平触发
initial
begin
  start=1'b1; 
  wait(en=1'b1);
  #10; start=1'b0; 
end

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

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

7. 仿真终端显示描述

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

8. 文本输入方式
 

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

图片

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

  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
testbench(测试台框架)是用于验证设计功能的一种方式,在FPGA或ASIC设计中非常常见。testbench文件编写方法如下: 1. 定义module:首先,在testbench文件中定义一个module,该module将作为顶层实例来实例化要测试的设计模块。 2. 为输入信号添加时钟:为设计模块的输入信号添加时钟信号。这个时钟信号可以是固定的时钟频率,也可以是根据需要来控制的时钟。 3. 为输入信号添加数据:为设计模块的输入信号添加数据,以便测试设计的各种情况。通常需要为输入信号定义一组数据,以覆盖不同的测试用例。 4. 实例化设计模块:在module定义中实例化设计模块,并将输入信号连接到testbench模块的输出信号。 5. 配置仿真环境:设置仿真环境的一些参数,如仿真时间,仿真精度等。 6. 模拟输入:使用initial块或always块在仿真过程中为输入信号提供数据。可以使用任务或函数来生成数据。 7. 模拟输出:使用initial块或always块来检查设计模块的输出信号。可以使用assert语句来验证输出是否符合预期。 8. 运行仿真:在仿真环境中运行仿真,检查设计模块的输出是否与预期一致。 9. 分析仿真结果:根据仿真结果来评估设计的功能和性能。 10. 优化设计:根据仿真结果,进行必要的调整和改进,以优化设计的性能和功能。 以上是testbench仿真文件编写的一般方法。根据具体的设计需求和测试要求,可以进行相应的调整和改进。编写良好的testbench可以确保设计的正确性和可靠性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FPGA技术实战

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值