【Verilog TestBench教程】
Verilog TestBench教程
- 1. Verilog Testbench 的结构
- 2. 实例化待测模块(DUT)
- 3. 时间建模
- 4. Verilog 初始化模块/永久循环
- 5. Verilog 系统任务
- 6.实例分析
- 附录
- a.modelsim-objects窗口为空的解决办法
- b.modelsim仿真报错“error loading design”
- 参考文献
1. Verilog Testbench 的结构
TestBench文件中,包括了很多不可综合的Verilog代码,这些代码可以用于生成测试激励,并且用于检查待测模块是否满足了设计的要求。
激励模块用于生成测试信号,输出检测模块用于检测输出结构是否与设计预期结构相同。对于复杂的TestBench,激励模块和输出检查模块可以放在其他的文件中,对于结构简单的TestBench可以将全部内容放到一个文件里。
为了能够直观观察仿真波形,我们可以利用Vivado等IDE提供的仿真工具,也可以利用开源工具icarus verilog
和GTKwave
进行仿真。此外还有在线工具EDA Playground
可裨用户进行仿真工作。
2. 实例化待测模块(DUT)
写作Verilog Testbench文件的第一步是创建一个用于仿真的顶层模块。我们希望我们的Testbench的可以完完全全自动完成整个测试过程,所以我们的顶层模块是一个没有信号输入与信号输出的模块。
module example_tb();
//信号定义
endmodule
第二步需要实例化一个待测模块
<module_name> # (// If the module uses parameters they are connected here.<parameter_name> (<parameter_value>)
)
<instance_name> (// Connection to the module ports.<port_name> (<signal_name>),.<port_name> (<signal_name>)
);
//实例化主要分为两个部分一个是参数设置,一个是端口映射。
//第一个首先写出设计模块名字,之后一个括号,内部是参数名和参数值格式位.<parameter_name> (<parameter_value>)参数的括号后没有分号
//再次是dut实例名字
//其次是端口的映射,格式为.<port_name> (<signal_name>),port 之间用`,`隔开,最后括号后面有一个括号,一个完整的模块实例化只有一个分号做结尾。
3. 时间建模
因为我们的TestBench 文件是不去进行综合的,这需要我们去指定仿真过程中的时间消耗的约束。为了在Verilog语言中去建模时间延时的过程,我们要使用#
这个符号去完成。下面这一行代码是一个例子
#10
这段代码意味着延时是个时间单元,另外需要强调的是延时语句结束后没有分号;
。另外延时语句经常和后面的语句写在一行中,如下面这一句代码:
#10 a = 1'b1;
前面我们提到了“时间单元”这个概念。因为TestBench代码不会去进行综合,所以需要我们进行指定后才有意义。下面是两个例子:
·timescale <timeunit>/ <resolution>
`timescale 1ns / 1ps
4. Verilog 初始化模块/永久循环
用initial修饰的初始化模块只在模块开始运行的时候运行一次。结构如下面这一段代码所示:
initial beginclk = 1'b0;forever begin#1 clk = ~clk;endend
forever
语句的功能是持续执行forever
块语句中的代码,其的语法结构如下所示,即forever
语句下跟随一个块语句:
forever begin
//our code goes here
end
5. Verilog 系统任务
Verilog相同任务可以帮助用户以文本形式读取仿真的结果和信号状态。最为重要的两个函数为$display
、$monitor
。$dispaly
函数的用法和作用类似于C语言中的printf
函数。$monitor
的用法与$display
相同,两个函数最大的区别是$display
在某个特定位置打印某些变量和信号值;$monitor
函数是用于检测信号的变化,调用后会持续运行,进行对信号的监控。这个函数是单线程的,一个函数运行时,会关闭之前的监控函数。
下面是两个函数的用法实例:
// General syntax
$display(<string_to_display>, <variables_to_display);
// Example - display value of x as a binary, hex and decimal number
$display("x (bin) = %b, x (hex) = %h, x (decimal) = %d", x, x, x);
// General syntax
$monitor(<message_to_display>, <variables_to_display>);
// Example - monitor the values of the in_a and in_b signals
$monitor("in_a=%b, in_b=%b\n", in_a, in_b);
两个函数的格式代码表格如下图所示:
6.实例分析
本文用一个半加器的项目例子来介绍如何设计组合逻辑电路的Testbench。
// half_adder.v
//这是一个半加器的设计代码
module half_adder
(input wire a, b,output wire sum, carry
);//模块定义
assign sum = a ^ b;
assign carry = a & b;
endmodule
这是对应的Testbench代码
// half_adder_tb.v`timescale 1 ns/10 ps //时间单元位1ns,时间精度位10ps
module half_adder_tb;reg a, b;wire sum, carry;//将每一位的周期设置为20个时间单位,即20ns。localparam period = 20; half_adder UUT (.a(a), .b(b), .sum(sum), .carry(carry));initial // initial block executes only oncebegin// 产生用于测试的a、b信号值a = 0;b = 0;#period; // 等待一个信号周期a = 0;b = 1;#period;a = 1;b = 0;#period;a = 1;b = 1;#period;end
endmodule
上面这一段Testbench 主要分成这样几个部分第一个timescale
语句设置了时间单元和时间精度。之后设置了一个参数用于确定信号持续时间。之后定定义了测试模块。这个模块没有输入和输出端口。之后是模块内部信号定义,测试模块实例化。之后是用initial
语句生成了四组测试信号。测试模块中的信号定义,对应模块输入的两个信号a
和b
两个信号定义为reg
类型,应当是为了方便在块语句中进行赋值。和输出端口对应的信号没有这个问题,定义为了wire
类型信号。
附录
a.modelsim-objects窗口为空的解决办法
使用Modelsim进行仿真时,点击start simulateion后,出现Objects空白的问题,导致add wave -hex 后出现“No objects found matching '’”;尽管输入run后,可以运行仿真,但却无法察看wave窗口的波形。[2]
解决方案:
- 点击工具栏中的“simulate”按钮,调出start smulation窗口,把窗口中最下边optimization栏中的Enable optimization项目前的钩钩去掉,然后选择仿真的文件,点击OK,就一切正常了,能看到objects了。
- 找到modelsim安装目录下的modelsim.ini文件,将VoptFlow = 1注释掉,或者把1改为0,这样默认的状态就是不优化。
解决这一问题的核心在于取消优化。
b.modelsim仿真报错“error loading design”
模块描述和Testbench文件编译都通过了,但是无法进入仿真器,仿真器报错“Error loading design”。出现这个问题可以主要从下面四个角度进行排查[3]:
1.检查文件是否未被包含且未加入工程。
2.检查设计文件的端口声明与实例化时的端口是否一致。
3.检查设计文件的模块名是否与实例化时的模块名一致。
4.检查未在顶层文件中修改的端口是否为
wire
。
参考文献
- [1] How to Write a Basic Verilog Testbench
- [2] modelsim-objects窗口为空的解决办法
- [3] modelsim 居然 error loading design?
【Verilog TestBench教程】相关推荐
- Verilog初级教程(20)Verilog中的`ifdef 条件编译语句
文章目录 前言 正文 语法 示例 Testbench文件 往期回顾 参考资料及推荐关注 前言 `ifdef条件编译语句在逻辑设计中还是很常见的,但也常见一些滥用的情况,这应该避免. 应该在什么情况下使 ...
- Verilog初级教程(12)Verilog中的generate块
文章目录 前言 正文 generate for generate if generate case 参考资料 本系列博文 前言 verilog中的generate块可以称为生成块,所谓生成,可以理解为 ...
- Verilog初级教程(23)Verilog仿真中的显示任务
文章目录 前言 正文 Display/Write Tasks Verilog Strobes Verilog Continuous Monitors Verilog Format Specifiers ...
- Verilog初级教程(21)Verilog中的延迟控制语句
文章目录 前言 正文 延迟控制语句 事件控制语句 Named Events Event or operator 往期回顾 参考资料及推荐关注 前言 Verilog中的延迟控制有两种类型–延迟和事件表达 ...
- Verilog初级教程(15)Verilog中的阻塞与非阻塞语句
文章目录 前言 正文 阻塞赋值 非阻塞赋值 往期回顾 参考资料以及推荐关注 前言 本文通过仿真的方式,形象的说明阻塞赋值以及非阻塞赋值的区别,希望和其他教程相辅相成,共同辅助理解. 正文 阻塞赋值 阻 ...
- Verilog初级教程(14)Verilog中的赋值语句
文章目录 前言 正文 合理的左值 过程性赋值(Procedural assignment) 连续赋值 过程连续性赋值 往期回顾 前言 何为赋值语句?即将值放到线网或者变量上,这种操作称为赋值,英文:a ...
- Verilog初级教程(11)Verilog中的initial块
文章目录 前言 正文 语法格式 initial块是用来干什么的? initial块何时开始又何时结束? 一个模块中允许有多少个initial块? 参考资料 写在最后 前言 仿真中通常会依次执行一组Ve ...
- Verilog初级教程(9)Verilog的运算符
博文目录 写在前面 正文 Verilog算术运算符 Verilog关系运算符 Verilog等价运算符 Verilog逻辑运算符 Verilog位元运算符 Verilog移位运算符 参考资料 交个朋友 ...
- Verilog初级教程(7)Verilog模块例化以及悬空端口的处理
博文目录 写在前面 正文 按顺序排列的端口连接 按名称排列的端口连接 未连接/悬空端口处理 关于模块端口的说明 参考资料 交个朋友 写在前面 此系列相关博文: Verilog初级教程(6)Verilo ...
- Verilog testbench总结(二)
1.激励的设置 相应于被测试模块的输入激励设置为reg型,输出相应设置为wire类型,双向端口inout在测试中需要进行处理. 方法1:为双向端口设置中间变量inout_reg作为该inout的输出寄 ...
最新文章
- php base64解码,PHP Base64 中英文编码 JavaScript 解码
- 2020年github文件高速下载方法
- 为什么叫python编程-中小学生为什么要学Python编程
- 解决方法WindowsError: [Error 193] %1 is not a valid Win32 application
- bzoj2653: middle
- 推荐系统炼丹笔记:推荐算法特征交叉新方式CAN
- 君君喂大象C语言答案,2017年北师大版二年级语文上册句子专项复习题及答案
- Cisco2960交换机密码忘记恢复教程
- 读源码搞懂为什么Redis用单线程还这么快
- 数百万的 Android 手机预装了危险的恶意软件!
- 【2021】15天通过阿里云云计算架构师认证考试(ACE)- 经验分享
- 利用antd进行轻量级表单开发,获取验证码
- Python的数据类型
- 用python画奥特曼_你都用 Python 来做什么?
- Golang zip流式解析器
- centos 6.2 安装intel 显卡驱动
- HDU-1111解题报告
- mysql 给表添加唯一约束、联合唯一约束,指定唯一约束的名字
- C# GZip 压缩 / 解压
- 车牌识别(一)BMP文件读写