DFT学习笔记-Verilog testbench语法扫盲

目录

什么是testbench及其作用:

Testbench测试机制:

完整的testbench结构:

1、创建verilog模块:

2、声明变量并例化被测设计:

 3、使用initial或always语句产生激励

4、任务函数task,function

5、verilog系统任务


做仿真时需要编写testbench,作为完全没学过verilog的小白,第一次碰到需要手写的verilog是testbench文件。那就正好从testbench入手,逐句学习verilog和testbench的语法。

什么是testbench及其作用:

Verilog 代码设计完成后,还需要进行重要的步骤,即逻辑功能仿真。仿真激励文件称之为 testbench,放在各设计模块的顶层,以便对模块进行系统性的例化调用进行仿真。

毫不夸张的说,对于稍微复杂的 Verilog 设计,如果不进行仿真,即便是经验丰富的老手,99.9999% 以上的设计都不会正常的工作。不能说仿真比设计更加的重要,但是一般来说,仿真花费的时间会比设计花费的时间要多。有时候,考虑到各种应用场景,testbench 的编写也会比 Verilog 设计更加的复杂。

Testbench测试机制:

任何一个设计好的模块,都有输入和输出,此模块是否满足要求就是看给定满足要求的输入,是否能够得到满足要求的输出。所以testbench的测试机制就是:用各种verilog或者VHDL语法,产生满足条件的激励信号(也就是对被模块的输入),同时对模块的输出进行捕捉,测试输出是否满足要求。如下图,产生激励输出验证模块两个模块都属于testbench,最好的输出验证模块最终只需要给一个pass和fail的答案出来就可以了。不管是用一个信号表示pass和fail还是用$display()函数打印,最终简单明了的给出过或者不过的信息就好了。请大家写仿真文件的时候尽量做到这点。

完整的testbench结构:

module Test_bench();//创建verilog模块
  信号或变量声明定义
  逻辑设计中输入信号在这里对应reg型变量
  逻辑设计中的输出信号在这里对应wire型
  例化测试模块DUT
  使用initial或always语句块产生激励
  监控和比较输出响应
endmodule

1、创建verilog模块:

编写testbench的第一步是创建一个 verilog 模块作为测试的顶层。

与verilog module不同,在这种情况下,要创建的是一个没有输入和输出的模块。因为设计人员希望testbench模块是完全独立的(self contained)。

下面的代码片段展示了一个空模块的语法,这可以被用作testbench。

module ();
//在这里写testbench
endmodule :

2、声明变量并例化被测设计:

创建了一个testbench之后,必须例化被测设计,这可以将信号连接到被测设计以激励代码运行。下面的代码片段展示了如何例化一个被测模块。

<模块本身的名字> <例化的模块名字>  (
  //例化参数
  .<parameter_name1> (<parameter_value1>);
  .<parameter_name2> (<parameter_value2>)
)

下面举一个简单的例子:

wire in_a = 1'b0; //声明连线in_a
wire in_b = 1'b1; //声明连线in_b
wire out_q; //声明连线out_q
//例化设计
example_design dut (
    .a     (in_a),
    .b     (in_b),
    .q     (out_q)
);

在这里首先声明了三条连线,并将原模块example_design中的端口(.<name>表示端口)与连线(括号里的,也是前面声明好的)连接起来。

数据类型种类:

除了上面用到的wire型外,还有其他数据类型。其中,wire与reg是最常用的两种数据类型,其他数据类型可以认为是这两种的扩展或辅助。

wire:wire 类型表示硬件单元之间的物理连线,由其连接的器件输出端连续驱动。如果没有驱动元件连接到 wire 型变量,缺省值一般为 "Z"。

wire   interrupt ;
wire   flag1, flag2 ;
wire   gnd = 1'b0 ;

reg:寄存器(reg)用来表示存储单元,它会保持数据原有的值,直到被改写。

reg    clk_temp;
reg    flag1, flag2 ;

在仿真时,寄存器的值可在任意时刻通过赋值操作进行改写。例如:

reg rstn ;
initial begin
    rstn = 1'b0 ;
    #100 ;
    rstn = 1'b1 ;
end

向量:当位宽大于 1 时,wire 或 reg 即可声明为向量的形式。例如:整数,实数,时间寄存器变量

reg [3:0]      counter ;    //声明4bit位宽的寄存器counter
wire [32-1:0]  gpio_data;   //声明32bit位宽的线型变量gpio_data
wire [8:2]     addr ;       //声明7bit位宽的线型变量addr,位宽范围为8:2
reg [0:31]     data ;       //声明32bit位宽的寄存器变量data, 最高有效位为0

整数,实数,时间寄存器变量:

integer j ;  //整型变量
real    temp ;  //实数型变量
time    current_time ;  //时间型变量

 3、使用initial或always语句产生激励

 和功能文件的书写上有些区别,测试模块则一般习惯性用initial模块去产生一个信号的输入激励或对一个变量进行初始化赋值操作。在initial 块中编写的任何代码都会在仿真开始时执行一次且仅执行一次。与 always 块不同,在 initial 块中编写的 verilog 代码几乎是不可综合的,因此其几乎只被用于仿真。但是,在verilog RTL 中也可以使用initial块来初始化信号(几乎很少用)。

语法格式:

initial begin
    语句1;
    ...
    语句n;
end

为了更好地理解如何使用initial块在 verilog 中编写激励,请来看一个基本示例----假设现在想要测试一个基本的两输入与门,为此需要编写代码来生成所有可能的四种输入。此外还需要使用延时运算符以在生成不同的输入之间延迟一段时间。这很重要,因为这可以允许信号有时间来传播。

initial begin
  // 每隔10个时间单位就生成一个输入
  and_in = 2b'00;
  #10 and_in = 2b'01;
  #10 and_in = 2b'10;
  #10 and_in = 2b'11;
end

#+数字:表示verilog中的建模时间(类似于delay(num))。

testbench代码和设计代码之间的主要区别是testbench并不需要被综合成实际电路,为此可以使用时间控制语句这种特殊结构。事实上,这对于创建测试激励至关重要。

在 Verilog 中有一个可用的结构----它能够对仿真进行延时。在 verilog 中使用 # 字符后跟多个时间单位来模拟延时。

例如,下面的 verilog 代码展示使用延时运算符等待 10 个时间单位。

#10

将延时语句写在与赋值相同的代码行中也很常见,这可以有效地行使调度功能,将信号的变化安排在延迟时间之后。下面的代码片段是此种情况的一个示例。

#10 a = 1'b1;    // 在10个时间单位后,a将被赋值为1

注意,除非#10作为单独一行,否则其后没有分号。

————————————————
版权声明:本文为CSDN博主「孤独的单刀」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wuzhikaidetb/article/details/129396009

4、任务函数task,function

task和function说明语句分别用来定义测试模块当中的任务和函数,利用任务和函数可以把一个很大规模的程序分解成很多较小的任务和函数,非常便于Testbench的编写、理解以及调试,类似于C语言中的函数接口,输入、输出、总线信号的值可以传入、传出任务和函数,所以说学会灵活使用task和function可以极大程度上简练Testbench的程序结构,使得程序整体上通俗易懂,直观明了。

任务格式:task <任务名>

              <端口和数据类型声明语句>

语句1;

                  ……

语句n;

              endtask

如上图所示,是按键消抖测试模块的task任务,这里我们模拟按键闭合和按下可能存在的机械抖动情况,并将其做成了task任务,方便在Testbench的编写时候去调用它,从而更加简化测试模块的程序结构。

函数格式:function <返回值的类型或范围>(函数名)

              <端口说明语句>

<变量类型说明语句>

              begin

语句1;

                  ……

语句n;

end

              endfunction

如下图所示,我们用阶乘函数的定义和调用来举例说明function的具体用法,在这个例子当中也用嵌套使用了for循环语句和$display,代码层面整体上并不难理解,所以就不再赘述了。

task和function说明语句也存在一些不同点,请大家在编程时需要去注意:1.函数只能和本模块共用同一个仿真时间单位,而任务则可以定义自己的仿真时间单位;2.函数不能启动任务,而任务里能启动其他任务或函数;3.函数至少要有一个输入变量,而任务可以没有或者有多个任意类型的变量;4.函数返回一个值,而任务则不返回值。

因为task的书写格式总得来说要比function更加宽泛和灵活,所以在实际应用操作中,大家一般都习惯性定义task来分割任务,这其实类似于上面的while、repeat和for语句都可以表示循环,但是repeat和for语句因为其书写上的灵活性更容易被人们所接受。
————————————————
版权声明:本文为CSDN博主「青青豌豆」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wandou0511/article/details/122953707

可以看到在任务/函数中间,用begin...end语句做了任务块的分割,这是常用的方法。除此之外,还有一种fork...join的任务块分割语法:

fork...join与begin...end的区别就是,前者中的语句是并行执行的,后者中的语句是顺序执行的。一个小例子:

第一个代码中顺序块的执行时间是d+d+d+d,这里d=50,那么这个块完成的时间就是250;第二个代码中每条语句都是同时执行的,这个块完成的时间是最慢的那条语句完成的时间,这里是250。

parameter  d=50;

reg   [7:0] r;

begin

    #d   r='h35;

    #d   r='hE2;

    #d   r='h00;

    #d   r='hF7;

    #d   ->end_wave;                   //->表示触发事件end_wave使其翻转

end
fork

    #250  ->end_wave; 

    #200   r='hF7;

    #150   r='h00;

    #100   r='hE2;

    #50     r='h35;

join

5、verilog系统任务

在 verilog 中编写testbench时,有一些内置的任务和函数可以提供帮助。这些被统称为系统任务或系统函数,它们很容易被识别----总是以美元符号($)开头。

虽然有很多这样的系统任务可用,但是这三个是最常用的 :$display、$monitor 和 $time。
————————————————
版权声明:本文为CSDN博主「孤独的单刀」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/wuzhikaidetb/article/details/129396009

这个写的挺好,收藏一下:

Verilog HDL菜鸟学习笔记———三、Verilog常用语法之一 - 知乎

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
FPGAtestbench是用于对使用硬件描述语言(HDL)设计的电路进行仿真验证的。它的主要目的是测试设计电路的功能和性能是否与预期的目标相符。编写testbench可以帮助开发者更好地理解和验证设计电路的行为。而且在FPGA行业中,具备编写testbench的能力是非常重要的,因为大部分公司都会让你来编写testbench测试文件。 一个基本的testbench通常包含三个部分:信号定义、模块接口和功能代码。信号定义部分用于定义输入输出信号的类型和大小,这些信号需要使用register类型来存储输入的数据。模块接口部分定义了需要测试的模块的输入输出接口。功能代码部分则包含了对测试模块进行功能验证的代码。 编写testbench时,需要遵循规范化的设计和苛刻的结构。testbench的编写规范可以参考Modelsim仿真步骤的相关文档。 总结起来,FPGAtestbench是对设计电路进行仿真验证的重要工具,它需要包含信号定义、模块接口和功能代码三个部分,并且需要遵循规范化的设计和苛刻的结构。掌握编写testbench的能力对于在FPGA行业中的发展非常重要。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【FPGA自学总结】Testbench测试代码推荐编写规范](https://blog.csdn.net/zhaogoudan/article/details/111933722)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值