Verilog如何编写一个基础的Testbench
本文将讲述如何使用Verilog 编写一个基础的测试脚本(testbench)。
在考虑一些关键概念之前,先来看看testbench的架构是什么样的。架构包括建模时间、initial块(initial block)和任务(task)。此文最后将以一个完整的testbench编写作为示例。
在使用verilog设计数字电路时,设计人员通常还会创建一个testbench来仿真代码以确保其按预期设计运行。设计人员可以使用多种语言构建testbench,其中最流行的是VHDL、Verilog和System verilog。
System Verilog 在行业中被广泛应用,可能是用于测试的最常用语言,但本文仅介绍 verilog 中testbench设计的基本原则。
1、Testbench的架构
testbench由不可综合的verilog 代码组成,这些代码生成被测设计的输入并验证被测设计的输出是否正确(输出是否符合预期)。
下图展示了一个基本testbench的典型架构。
激励(stimulus block)是为 FPGA 设计生成的输入
输出校验(output checker)检查被测模块的输出是否符合预期
被测模块(design under test,DUT)即是编写的verilog模块,testbench的主要设计目的就是对其进行验证,以确保在特定输入下,其输出均与预期一致
对于较大规模的设计,激励和输出校验可以位于单独的文件中,也可以将所有这些不同的模块都包含在同一个文件中。
2、例化被测模块
编写testbench的第一步是创建一个 verilog 模块作为测试的顶层。
与讨论过的verilog module不同,在这种情况下,设计人员要创建的是一个没有输入和输出的模块。这是因为设计人员希望testbench模块是完全独立的(self contained)。
下面的代码片段展示了一个空模块的语法,这可以被用作testbench。
module <module_name> ();//在这里写testbench
endmodule : <module_name>
创建了一个testbench之后,必须例化被测设计,这可以将信号连接到被测设计以激励代码运行。
下面的代码片段展示了如何例化一个被测模块。
<module_name> # (//例化参数.<parameter_name> (<parameter_value>)
)
<instance_name> (//连接端口信号.<port_name> (<signal_name>),.<port_name> (signal_name>)
);
完成此操作后,就可以开始将激励写入testbench。激励包括时钟信号和复位信号,以及创建发送到testbench的测试数据。
为此,需要使用一些尚未学过的 verilog 结构----initial块(initial block)、foever循环(foever loop)和时间控制(time consuming)语句。
3、Verilog 中的建模时间(Modelling Time)
testbench代码和设计代码之间的主要区别是testbench并不需要被综合成实际电路,为此可以使用时间控制语句这种特殊结构。事实上,这对于创建测试激励至关重要。
在 Verilog 中有一个可用的结构----它能够对仿真进行延时。在 verilog 中使用 # 字符后跟多个时间单位来模拟延时。
例如,下面的 verilog 代码展示使用延时运算符等待 10 个时间单位。
#10
这里要注意的是代码末尾并没有分号。
将延时语句写在与赋值相同的代码行中也很常见,这可以有效地行使调度功能,将信号的变化安排在延迟时间之后。下面的代码片段是此种情况的一个示例。
#10 a = 1'b1; // 在10个时间单位后,a将被赋值为1
3.1、时间单位(Timescale )编译指令
在上一节已经讨论了十个时间单位的延时用法,但在设计人员真正定义所使用的时间单位之前,这样的讨论是毫无意义的。
为了指定在仿真期间所使用的时间单位,需要使用指定时间单位和时间精度(分辨率)的 verilog 编译器指令。这只需要在testbench中运行该指令一次,而且应在模块外完成。
下面的代码片段展示用来在 verilog 中指定时间单位和精度的编译指令。
`timescale <unit_time> / <resolution>
<unit_time> 指定时间的单位,<resolution>则指定时间精度。
<resolution> 很重要,因为设计人员可以使用小数来指定 verilog 代码中的延时。例如,如果设计人员想要 10.5ns 的延迟,就可以简单地写为 #10.5。因此,编译指令中的 <resolution> 决定了可以实现最小时间的步长(即精度)。
此编译指令中的两个参数都采用时间类型,例如 1ps 或 1ns。
4、Verilog initial block(初始块)
在initial 块中编写的任何代码都会在仿真开始时执行一次且仅执行一次。
下面的 verilog 代码展示了initial 块的一般语法。
initial begin//这里写代码
end
与 always 块不同,在 initial 块中编写的 verilog 代码几乎是不可综合的,因此其几乎只被用于仿真。但是,在verilog RTL 中也可以使用initial块来初始化信号(几乎很少用)。
为了更好地理解如何使用initial块在 verilog 中编写激励,请来看一个基本示例----假设现在想要测试一个基本的两输入与门,为此需要编写代码来生成所有可能的四种输入。此外还需要使用延时运算符以在生成不同的输入之间延迟一段时间。这很重要,因为这可以允许信号有时间来传播。
下面的 verilog 代码展示了在initial块中编写此测试的方法。
initial begin// 每隔10个时间单位就生成一个输入and_in = 2b'00;#10 and_in = 2b'01;#10 and_in = 2b'10;#10 and_in = 2b'11;
end
5、Verilog Foever 循环(Loop)
在 verilog testbench中可以使用一种重要的循环类型——foever循环。
使用这个构造时,实际上是创建了一个无限的循环----这意味着创建了一段在仿真过程中将永远运行的代码。
下面的 verilog 代码展示了用来编写foever循环的一般语法。
forever begin// our code goes here
end
当用其他编程语言编写代码时,无限循环一般被视为应极力避免的严重错误。但是,verilog 与其他编程语言不同,编写 verilog 代码是在描述硬件而不是在编写软件。
因此,至少有一种情况是可以使用无限循环的----时钟信号。为此需要一种定期连续反转信号的方法,foever循环与此相当契合。
下面的 verilog 代码展示了如何使用foever循环在testbench中生成一个时钟。需要注意的是,所编写的任何循环都必须包含在过程块(procedural block)中或生成块(generate块)中。
initial beginclk = 1'b0;forever begin#1 clk = ~clk;end
end
6、Verilog 系统任务(System Tasks)
在 verilog 中编写testbench时,有一些内置的任务和函数可以提供帮助。这些被统称为系统任务或系统函数,它们很容易被识别----总是以美元符号($)开头。
虽然有很多这样的系统任务可用,但是这三个是最常用的 :$display、$monitor 和 $time。
6.1、$display
$display 是 verilog 中最常用的系统任务之一。设计人员可以使用它来输出一条消息,该消息在仿真时将会显示在控制台上。
$display的使用方式与C语言中的printf函数非常类似,这意味着设计人员可以轻松地在testbench中创建文本语句,并使用它们来显示有关仿真状态的信息。
设计人员还可以在字符串中使用特殊字符 (%) 来显示设计中的信号。这样做时,还必须使用一个格式字母来决定以何种格式显示变量。最常用的格式是 b(二进制)、d(十进制)和 h(十六进制)。设计人员还可以在这个格式代码前面加上一个数字来确定要显示的位数。
下面的 verilog 代码展示了 $display 系统任务的一般语法。此代码片段还包括一个示例用例。
//一般语法
$display(<string_to_display>, <variables_to_display);//例子:分别用2进制、16进制和10进制来打印x的值
$display("x (bin) = %b, x (hex) = %h, x (decimal) = %d", x, x, x);
设计人员可以在 $display 系统任务中使用的不同格式的完整列表如下所示。
格式代码 | 描述 |
%b 或 %B | 显示为二进制 |
%d 或 %D | 显示为十进制 |
%h 或 %H | 显示为十六进制 |
%o 或 %O | 显示为八进制格式 |
%c 或 %C | 显示为 ASCII 字符 |
%m 或 %M | 显示模块的层级名称 |
%s 或 %S | 显示为字符串 |
%t 或 %T | 显示为时间 |
6.2、$monitor
$monitor 函数与 $display 函数非常相似,但它一般被用来监视testbench的信号值,这些信号中的任何一个改变状态,都会在终端打印一条消息。
所有的系统任务在使用时都会被综合工具忽略,因此甚至可以在verilog RTL 代码中使用 $monitor 语句,尽管这并不常见。
此系统任务的一般语法显示在下面的代码片段中。此代码片段还包括一个示例用例。
//一般语法
$monitor(<message_to_display>, <variables_to_display>);//例子:监控信号in_a和in_b的值。其中任何一个发生变化都会立即在终端打印出两个信号的值
$monitor("in_a=%b, in_b=%b\n", in_a, in_b);
6.3、$time
在testbench中常用的最后一个系统任务是 $time 。这个系统任务可以用来获取当前的仿真时间。
在testbench中通常将 $time 与 $display 或 $monitor 一起使用,以便在打印的消息中显示具体仿真时间。
下面的 verilog 代码展示了如何一起使用 $time 和 $display 来打印信息。
$display("Current simulation time = %t", $time); //打印当前仿真时间
7、Verilog testbench示例
接下来将为一个非常简单的电路构建一个testbench以检查其功能的正确性。
下面显示的电路是将用于此示例的电路,由一个简单的两输入与门以及一个寄存器组成。
7.1、创建一个testbench模块
在testbench中做的第一件事就是声明一个空模块来写入代码。
下面的代码片段展示了此testbench的模块声明。请注意,最好让被测试设计的名称与testbench的名称保持相似。一般可以简单地将 _tb 或 _test 附加到被测设计名称的末尾。
module example_tb ();//在这里写测试代码
endmodule : example_tb
7.2、例化被测模块
现在只有一个空白的testbench模块,接下来需要例化要测试的设计模块。
下面的代码片段展示了如何例化被测模块,假设信号 clk、in_1、in_b 和 out_q 之前就已声明。
example_design dut (.clock (clk),.reset (reset),.a (in_a),.b (in_b),.q (out_q)
);
7.3、生成时钟和复位信号
接下来要做的是在testbench中生成一个时钟和复位信号。可以在initial块中为时钟和复位信号编写代码,然后使用延时运算符来实现信号状态的变化。
对于时钟信号,可以使用 forever 关键字在仿真期间持续运行时钟信号。使用此语法将每 1 ns 进行一次反转,从而实现500MHz 的时钟频率----选择此频率纯粹是为了实现快速仿真,实际上FPGA 中的 500MHz 时钟速率很难实现,所以testbench的时钟频率应尽量与硬件时钟频率匹配。
下面的 verilog 代码展示了如何在testbench中生成时钟和复位信号。
//生成时钟信号
initial beginclk = 1'b0;forever #1 clk = ~clk;
end//生成复位信号
initial beginreset = 1'b1;#10reset = 1'b0;
end
7.4、编写测试激励信号
最后一部分是编写测试激励。为了测试被测电路,需要依次生成四种可能输入中的每一种,然后需要等待一小段时间,让信号通过代码块传播。
为此,将为输入赋值,然后使用延时语句来通过 FPGA 进行传播。如果还想监控输入和输出的值,可以使用 $monitor这个系统任务来完成。
下面的代码片段展示了相关代码。
initial begin$monitor("time=%3d, in_a=%b, in_b=%b, q=%2b \n",$time, in_a, in_b, q);in_a = 1'b0;in_b = 1'b0;#20 in_a = 1'b1;#20 in_a = 1'b0;in_b = 1'b1;#20 in_a = 1'b1;
end
7.5、完整示例代码
下面的 verilog 代码展示了完整的testbench示例。
`timescale 1ns / 1ps //时间单位1ns,精度1psmodule example_tb ();//声明时钟和复位信号
reg clk;
reg reset;//输入和输出信号
reg in_a;
reg in_b;
wire out_q;//例化被测模块
example_design dut (.clock (clk),.reset (reset),.a (in_a),.b (in_b),.q (out_q)
);//生成时钟信号
initial beginclk = 1'b0;forever #1 clk = ~clk;
end//生成复位信号
initial beginreset = 1'b1;#10 reset = 1'b0;
end//生成测试激励信号initial begin$monitor("time=%3d, in_a=%b, in_b=%b, q=%2b \n",$time, in_a, in_b, q);in_a = 1'b0;in_b = 1'b0;#20in_a = 1'b1;#20in_a = 1'b0;in_b = 1'b1;#20in_a = 1'b1;endendmodule
📣您有任何问题,都可以在评论区和我交流📃!
📣本文由 孤独的单刀 原创,首发于CSDN平台🐵,博客主页:wuzhikai.blog.csdn.net
📣您的支持是我持续创作的最大动力!如果本文对您有帮助,还请多多点赞👍、评论💬和收藏⭐!
相关文章:
Verilog如何编写一个基础的Testbench
本文将讲述如何使用Verilog 编写一个基础的测试脚本(testbench)。在考虑一些关键概念之前,先来看看testbench的架构是什么样的。架构包括建模时间、initial块(initial block)和任务(task)。此文…...
基于JavaEE社区物业管理系统开发与实现(附源码资料)
文章目录1. 适用人群2. 你将收获3.项目简介4.技术栈5.测试账号6.部分功能模块展示6.1.管理员6.2.业主1. 适用人群 本课程主要是针对计算机专业相关正在做毕业设计或者是需要实战项目的Java开发学习者。 2. 你将收获 提供:项目源码、项目文档、数据库脚本、软件工…...
问一下ChatGPT:DIKW金字塔模型
经常看到这张DIKW金字塔模型图,还看到感觉有点过份解读的图,后面又加上了insight,impact等内容。 Data:是数据,零散的、无规则的呈现到人们眼前,如果你只看到这些数字,如果没有强大的知识背景&a…...
javaScript基础面试题 ---闭包
闭包1、闭包是什么?2、闭包可以解决什么问题?3、闭包的缺点1、闭包是什么? 闭包是一个函数加上到创建这个函数的作用域的链接,就是一个作用域可以访问到另一个作用域的变量,闭包‘关闭’了函数的自由变量 function f…...
如何自定义您的网站实时聊天图标
实时聊天图标是您网站上的一个按钮,可在访问者单击时打开实时聊天。它代表了您的企业与客户沟通的门户。这是您的网站访问者与您联系、提出问题和接收个性化推荐的一种方式,聊天图标的设计最好是简单且引人入胜,个性化的图标往往更能提现企业…...
Vue侦听器Watch
31. Vue侦听器Watch 1. 定义 Watch是Vue.js提供的一个观察者模式,用于监听数据的变化并执行相应的回调函数。虽然计算属性Computed在大多数情况下更合适,但有时也需要一个自定义的侦听器Watch。因为在有些情况下,我们需要在状态变化时执行一…...
云快充研发中心平台架构师谈云原生稳定性建设之路
作者:吕周洋 大家好,我是来自云快充研发中心的平台架构师吕周洋,今天我给大家分享云快充云原生稳定性之路。 点击查看:云快充研发中心平台架构师 吕周洋:云快充云原生稳定性治理之路 云快充成立于2016年,…...
ENVI IDL学习笔记之基本操作
前言ENVI IDL(交互式数据语言)是一个通用的科学计算包,它提供了一套数学函数、数据分析工具,以及一些科学可视化和动画工具。IDL 是 ENVI 图像处理和分析软件的基础,可用于编写脚本并自动执行许多使用 ENVI 图形用户界…...
多线程面试题
1. Sychronized的锁升级过程是怎样的? 2. Tomcat 中为什么要使用自定义类加载器? 3. 说说对线程安全的理解 4. 对守护线程的理解 5. 并发、并行、串行之间的区别 6. Java死锁如何避免? 7. 谈谈你对AQS的理解,AQS如何实现可重入锁&…...
YARN运行流程
YARN是Hadoop资源管理器,他是一个通用资源管理平台和调度平台,可为上层应用提供统一的资源管理和调度,MapReduce等运算程序则相当于运行于操作系统上的应用程序,YARN为这些程序提供运算所需的资源内存、cpu。 YARN并不清楚用户提…...
java八股系列——SpringMVC从接受请求到完成响应的过程
Spring的MVC框架是围绕一个DispatcherServlet来设计的,这个Servlet会把请求分发给各个处理器,并支持可配置的处理器映射、视图渲染、本地化、时区与主题渲染等,甚至还能支持文件上传。 流程大致如下: 用户发起请求:用…...
Elasticsearch索引全生命周期
索引(Index)是Elasticsearch中最重要的概念之一,也是整个Elasticsearch操作的基础,它是相互关联的文档的一个集合。在Elasticsearch种,数据存储为 JSON 文档,每个文档将一组键(字段或属性的名称)与其对应的…...
汇编指令学习(LOOP)
一、xor异或操作,相同为0,不同为1xor eax,eaxeax异或eax,相同为0,并把结果存放到eax,简单说该语句就是想eax寄存器清零。二、ECX,计数器mov ecx,0x3将ecx寄存器设置为3三、DEC减一操作dec ecxecx寄存器的值…...
Linux 配置本地yum源
挂载光盘 进入包 配置路径,查看在线yum源 移动在线yum源到/home/目录下 进入vi,任意取名以.repo结尾即可 按住i进行编辑,输入以下内容 注意gpgcheck1是检验,配置本地yum源不需要检验 写入上图内容按住:输入wq,点击回车…...
【PyTorch】教程:torch.nn.LeakyReLU
torch.nn.LeakyReLU 原型 CLASS torch.nn.LeakyReLU(negative_slope0.01, inplaceFalse) 参数 negative_slope (float) – 控制负值斜率,默认为 1e-2inplace (bool) – in-place 操作,默认为 False 定义 LeakyReLU(x)max(0,x)negative_slope∗min…...
【刷题】-- 基础 -- 二分查找
精于结构、敏于心智、熟于代码 方式:对于会的代码:学会以最快的速度构建,并以最快的速度书写;对于不会的代码:学会(以最短的路径下)看懂别人的代码。学会使用参考文档、熟悉每一个容器。 刷题位…...
Spark MLlib 特征工程
Spark MLlib 特征工程预处理特征选择归一化离散化Embedding向量计算特征工程制约了模型效果 : 决定了模型效果的上限 , 而模型调优只是在不停地逼近上限好的特征工程才能有好的模型 特征处理函数分类 : 预处理 : 将模型无法直接消费的数据,转为可消费的数据形式特…...
CentOS7 完全卸载 php
在 CentOS 7 使用 yum install 简单安装 php 后,发现 php 版本 5.4 ,太低了! 然后,使用 yum remove 简单卸载后,发现 php 还在,不干净! 只好 rpm 慢慢卸载 rpm -qa |grep php php-gd-5.4.16-4…...
关于OCS认证里必须知晓的内容
【关于OCS认证里必须知晓的内容】美国非营利组织Textile Exchange推出的有机认证标准——有机含量标准(The Organic Content Standard),简称OCS。该标准通过跟踪有机原材料的种植从而监管整个有机产业链。OCS将应用于各种有机种植原料的验证,而不只限于有…...
创业做电商难不难?新人做电商怎么才能挣钱?
这几年经济不景气,创业做电商的人越来越多,但是,对于多数人来说,一开始做电商,都是试错成本,没有系统学习或者是跟着半吊子二把刀学的,结果赔钱就算了,新人创业做电商到底难不难&…...
【项目设计】高并发内存池(七)[性能测试和提升]
🎇C学习历程:入门 博客主页:一起去看日落吗持续分享博主的C学习历程博主的能力有限,出现错误希望大家不吝赐教分享给大家一句我很喜欢的话: 也许你现在做的事情,暂时看不到成果,但不要忘记&…...
PHP:Laravel cast array json数据存数据库时unicode 编码问题和update更新不触发数据转换
目录问题描述问题解决方式一:自定义属性方式二:继承覆写方式三:trait复用方式四:定义Cast子类update不生效参考文章问题描述 Model示例 class UserModel extends Model {protected $table tb_user;protected $casts [alias …...
自动化测试总结--断言
采购对账测试业务流程中,其中一个测试步骤总是失败,原因是用例中参数写错及断言不明确 一、问题现象: 采购对账主流程中,其中一个步骤失败了,会导致这个套件一直失败 图(1)测试报告视图中&…...
传输线的物理基础(三):传输线的瞬时阻抗
每个信号都有一个上升时间 RT,通常是从 10% 到 90% 的电压电平测量的。当信号沿传输线向下移动时,前沿在传输线上展开并具有空间范围。如果我们可以冻结时间并观察电压分布向外移动时的大小,我们会发现类似下图的东西。传输线上上升时间的长度…...
第六章:多线程
第六章:多线程 6.1:程序、进程、线程基本概念 程序 程序program是为了完成特定任务、用某种语言编写的一组指令的集合。即指一段静态的代码,静态对象。 进程 进程process是程序的一次执行过程,或是正在运行的一个程序。是一个…...
铁路与公路
蓝桥杯集训每日一题acwing4074 某国家有 n 个城市(编号 1∼n)和 m 条双向铁路。 每条铁路连接两个不同的城市,没有两条铁路连接同一对城市。 除了铁路以外,该国家还有公路。 对于每对不同的城市 x,y,当且仅当它们之…...
GitHub Copilot 全新升级,工作效率提升 55%
2021年 6 月,GitHub 和 OpenAI 推出了 GitHub Copilot 预览版,可根据命名或者正在编辑的代码上下文为开发者提供代码建议,被称为“你的 AI 结对程序员”。 近日,GitHub 宣布,经过去年 12 月以来的短暂测试后ÿ…...
【IoT】《天道》中音响案例的SWOT分析
在20世纪80年代初,SWOT最初是由美国知名管理学教授海因茨韦里克提出的。 之后这个工具就经常被用于企业的战略分析、竞争对手分析等场景。 在每年例行的公司产品规划过程中,我个人也经常使用这个工具。 由于涉及一些公司商业上的信息,下面会用…...
如何实现接口幂等性
1 什么是幂等 幂等操作的特点是一次或者任意多次执行所产生的影响均与一次执行的影响相同,不会因为多次的请求而产生不一样的结果。换句话说,就是我使用相同的请求参数,去请求同一个接口,不管请求多少次获取到的响应数据应该是一…...
相恨见晚的office办公神器(不坑盒子/打工人Excel插件2023年最新版)
不坑盒子 这是一个非常好用的插件工具,专门应用在Word文档和wps,支持Office 2010以上的版本,操作也简单且实用。 不坑盒子下载及使用说明 一键排版功能 像是下面的自动排版功能,可以在配置里面先设定好需要的格式,…...
上海网站建设怎么弄/临沂seo代理商
8种机械键盘轴体对比本人程序员,要买一个写代码的键盘,请问红轴和茶轴怎么选?一、HMR介绍在我们开发react应用的时候,在配置了webpack-dev-server的前提下每一次的组件内容修改都需要手动的刷新浏览器,为了解决这个问题…...
ppt做多个网站/深圳做推广哪家比较好
这问题一般是在manifest.xml中没有配置相应的activity,或者配置的android:name 的路径不对,没写全。 可是今天我在manifest中已经配置正确了activity还有这错误。 原因在activity的构造方法 我的activity中的构造方法中写多了参数,导致跳转时…...
临汾网站建设 吕梁网站建设/开鲁网站seo免费版
默认情况下,Java类的反射对象并未包含方法入参的名称,如果编译时打开debug开关(javac-debugno),则方法入参名也会记录到类的反射对象中,所有如果PathVariable注解后面不指定参数的时候,要使方法…...
模板做网站多少钱/巨量算数数据分析
十年之前的1月20日,Michel Schinz宣布了Scala编程语言的第一个实现。在宣布之时,Scala被描述为“一种平滑地集成了面向对象编程和函数式编程的语言”,而且“是为以简洁、优雅且类型安全的方式表达常见编程模式而设计的”。\u0026#xD;当时是这…...
wordpress seo by yoast中文/seo技术分享
OLED显示电容式土壤湿度传感器数据 本文将演示如何在OLED中显示土壤湿度传感器数据以及不同的数据值范围,使用不同的表情图片显示。 本次实例主要通过如下步骤来完成: 土壤湿度传感器数据采集OLEDc驱动采集数据处理及OLED显示在前面的文章中,对OLED及其驱动做了详细的介绍,…...
wordpress 同步phpcms/广告软文营销平台
文章目录一 HBase优化1 预分区(1)手动设定预分区(2)生成16进制序列预分区(3) 按照文件中设置的规定预分区(4)使用JavaAPI创建预分区2 RowKey设计3 内存优化4 基础优化二 整合Phoenix…...