Verilog TestBench Coding Style
Abtract
关于编写testbench的一些经验总结心得。
Introduction
1.基本的Testbench结构
1)常用的编码结构
`timescale 1 ns / 1 ps // 时间精度和刻度
module 模块名称;
DUT输入信号定义; // DUT输入信号一般定义为reg类型
DUT输出信号定义; // DUT输出信号一般定义为wire类型
...
DUT // 待测module
...
initial begin
// 定义相关信号初始值或者定义时钟复位等控制信号
// 监测、添加约束等
end
...
always // 处理相关需要变化的值
...
endmodule
2)常用结构图示
下节针对Testbench的基本结构的细节进行解析说明。
2.DUT输入输出端口
1)输入端口
DUT的输入端口(input)一般定义为reg类型。
2)输出端口
DUT的输出端口(output)一般定义为wire类型。
3)双向端口
DUT的端口中如果存在双向端口(inout),则一般定义为wire类型。
注意:面对inout类型的处理,通常可以采用以下方法:
a.通过中间变量作为inout类型端口的输出寄存;
e.g. inout bi_port;
wire bi_port;
reg bi_port_reg; // inout类型的中间变量为reg
reg bi_port_en;
assign bi_port = bi_port_en ? bi_port_reg : 1'bz;
b.使用force和release语句
e.g. force bi_port = 1'b1; // 强制作为输入端口
release bi_port; // 释放端口
4)模块之间连接
如果Testbench中存在多个模块,且多个模块之间存在互连,则相互之间的连线定义为wire类型。
关于Testbench中各种类型的定义如下如所示:
3.initial定义使用方法
1)在initial语句中定义时钟
initial begin
...
clk = 1'b0;
forever #(clk_halfp) clk = ~clk; // 其中clk_halfp为半周期
end
2)在initial语句中定义复位
initial begin
...
reset = 1'b0; // 如果是低电平复位
#(reset_time); // 复位时间
reset = 1'b1; // 复位撤销
...
end
3)在initial语句中定义相关数据信号
initial begin
...
dat = 2'b00; // 数据值1
#(gap_time); // 数据间隔
dat = 2'b01; // 数据值2
#(gap_time); // 数据间隔
dat = 2'b11; // 数据值3
...
#(gap_time); // 数据间隔
dat = 2'b10; // 数据值4
...
end
4)在initial语句中加入关键字
initial begin
...
$sdf_annotat("abc.sdf",top); // 指定sdf文档路径和反标层次
...
$finish; // 程序结束
...
// 其他系统函数
...
$fsdbDumpfile("top.fsdb"); // 生成Novas调用的波形文档
$fsdbDumpvars(0, tb);
...
end
5)在initial语句中定义#0延时信号
6)initial语句的几个特性
u initial语句在0时刻启动
u initial语句只能执行一次
u 当Testbench中有多个initial语句,则所有的initial语句同时并行执行
7)initial语句中被赋值的变量通常为reg类型
8)常用系统函数可作为监控等,详见下文第7节。
4.always定义使用方法
1)产生时钟
always
begin
...
# (clk_halfp) clk = ~clk // clk_halfp为系统半时钟
...
end
2)产生数据
always @(敏感信号列表或者时钟)
begin
...
dat <= temp; // 其中temp可以为DUT的反馈信号,用以产生dat作为DUT输
// 入信号
...
end
5.DUT监测方法
1)调用系统函数对DUT运行状况进行实时监测($dispaly()、$strobe()、$monitor() 、$fwrite()等)
...
initial begin
fp = $fopen("log.txt","w"); // 打开存储数据的文件
...
$monitor("%0dns :\$monitor: a=%b b=%b" , $stime, a, b); // 实时监控a,b
$display("%0dns :\$display: a=%b b=%b" , $stime, a, b); // 显示a,b
$strobe ("%0dns :\$strobe : a=%b b=%b\n" , $stime, a, b); // 下时阶显示当前a,b
$fwrite(fp, "%0dns :\$fwrite : a=%b b=%b\n", $stime, a, b); // 按引号中格式输出a,
// b的变化
...
$fclose(fp); // 关闭存储数据的文件
end
...
关于系统函数的详细使用方法可以参阅相关Verilog书籍。
2)通过功能相似的IP核进行验证
通过SOURCE输入的激励信号同时发送给IP核(该IP功能与DUT功能相同),经过相应处理之后,将DUT与IP核的输出数据进行比较(CHECK),同时在CHECK中可以对相关的比较进行记录(可以调用系统函数,将结果输出到指定文档等)
6.编写Testbench常用技巧
1)CGU:时钟产生电路
将时钟电路作为专门的电路单元或者task进行编写,同时参数化其中的周期参数等,在Testbench中进行例化与DUT进行连接,减少Testbench中的代码量,同时使Testbench中的代码更加简洁、模块化、参数化。
2)RGU:复位产生电路
RGU模块的作用类似于CGU。
3)CHECK:结果比较电路
基于Testbench简洁清晰化、模块化、参数化,可以讲CHECK专门作为一个模块,对测试验证的结果进行相应的处理加工。
4)PARAMETER:参数化设计
在对模块调用时,只需要在Testbench中例化模块式,填写相应的参数即可对模块进行中的相应参数进行修改,修改方便简洁。
e.g. ...
parameter clk_halfp = 50; // 定义时钟半周期
...
CGU u_cgu #(.clk_halfp(clk_halfp)) // 配置CGU中参数clk_halfp,生成时钟
(
...
.clk(clk_sys) // 输出时钟信号
...
)
可见,通过参数化处理,不仅可以配置时钟周期,还可以确定数据位宽等,当然在设计中同样可以使用include "abc_cfg.v"文件,对整个系统设计中的所有参数进行统一管理和定义。
5)IP REUSE:IP复用
随着IP设计的愈加成熟,复用已经成熟的IP进行设计和验证可以大大缩短设计和验证的周期,加快产品的开发,因此,建议在Testbench中可以复用已经成熟的IP进行设计和验证。
6)在initial语句中最好,定义$stop,用以指明仿真何时结束。
7.常用系统函数使用举例
1)添加SDF文件
添加SDF文件不仅可以通过一些仿真工具进行增加,同时还可以使用$sdf_annotate函数进行指定。
e.g. $sdf_annotate("sdf_file_name",module_instance,"scale_factors");
其中module_instance:使用sdf文件所对应的instance name;
scale_factors:针对timming delay中的最小延迟(min)、典型延迟(typ)、最大延时(max)
2)生成VCD文件,VCD文件可以记录仿真过程中信号的变化,只记录在函数中指定的层次中相关的信号。
e.g. $dumpfile("filename"); // open database
$dumpvars(1,TB.u1); // 只记录u1中的数据,记录深度仅为1层
注意:其中第一个参数表示深度,为0表示记录所有层次深度中的信号的变化;第二个参数表示scope,即表示要观测的模块的例化名,当省略时表示当前scope。
e.g. $dumpvars; // depth = all;scope = all
$dumpvars(0); // depth = all;scopt = current
$dumpoff // 暂停记录数据的变化,此刻之后dumpop之前的
// 所有信号的变化将不计入database。
$dumpon // 回复记录数据
3)文本文件的梳理
a.读取文本文件
用$readmemb系统任务从文本文件中读取二进制向量(可以包含输入输出),$readmemh用于读取十六进制文件。
e.g. reg [7:0] mem [0:255] // the data is 8-0bit & the addr is 0~256
initial begin
$readmemh("mem.dat",mem); // read the data from mem.dat to mem
$readmemh("mem.dat",mem,128,1); // read the data addr is 1 to 128
end
b.输出文本文件
这里需要注意在对文件进行写操作之前需要打开建立文件,使用$fopen(),在写完文件之后要关闭文件$fclose()。
e.g. integer out_file; // 类似C语言中指定文件指针
out_file = $fopen("abc.dat"); // abc.dat为要输出的文档名
可以通过$fmonitor,$fdisplay把需要观测的数据按照相应的格式输出到abc.dat中
e.g. $fdisplay(out_file,data); // output the data to the file abc.dat
转载:http://www.cnblogs.com/nanoty/archive/2012/11/02/2751873.html
Verilog TestBench Coding Style的更多相关文章
- (转帖) 有限狀態機FSM coding style整理 (SOC) (Verilog)
来源:http://www.codesoso.net/Record/101092_95120_21.html 来源:http://www.cnblogs.com/oomusou/archive/201 ...
- 有限狀態機FSM coding style整理 (SOC) (Verilog)
AbstractFSM在數位電路中非常重要,藉由FSM,可以讓數位電路也能循序地執行起演算法.本文將詳細討論各種FSM coding style的優缺點,並歸納出推薦的coding style. In ...
- 编程风格(Coding Style)要求
编程风格(Coding Style)要求2.1.1 文件(1) 每个模块(module)一般应存在于单独的源文件中,通常源文件名与所包含模块名相同.(2) 每个设计文件开头应包含如下注释内容:? 年份 ...
- Linux 内核Coding Style整理
转载:http://www.cnblogs.com/wang_yb/p/3532349.html 总结linux内核开发的coding style, 便于以后写代码时参考. 下面只是罗列一些规则, 具 ...
- linux c coding style
Linux kernel coding style This is a short document describing the preferred coding style for the lin ...
- c coding style之学习篇
1. 使用do-while结构去避免潜在的内存泄漏问题. do { p1 = malloc(10); if (null == p1) { break; ...
- [中英对照]Linux kernel coding style | Linux内核编码风格
Linux kernel coding style | Linux内核编码风格 This is a short document describing the preferred coding sty ...
- 谈谈Linux内核驱动的coding style【转】
转自:http://www.cnblogs.com/wwang/archive/2011/02/24/1960283.html 最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离 ...
- Google's C++ coding style
v0.2 - Last updated November 8, 2013 源自 Google's C++ coding style rev. 3.274 目录 由 DocToc生成 头文件 ...
随机推荐
- 【LeetCode】159. Longest Substring with At Most Two Distinct Characters
Difficulty: Hard More:[目录]LeetCode Java实现 Description Given a string S, find the length of the long ...
- Mq的介绍
1.使用场景 异步处理 日志收集 流量削峰 应用解耦 2.通信协议 高级消息队列协议(AMQP). 参考文档:http://www.huangxiaobai.com/archives/1267
- Ucinet6 + Netdraw 根据excel文件绘制网络拓扑图
条件: 具备Ucinet6 和 Netdraw 两款软件的Windows excel文件格式(.xlsx .xls .csv):必须是数字,如果现有的文件不是数字,可以采用某种编码的方式将其映射成 ...
- 洛谷 P1359 租用游艇【dp】(经典)
题目链接:https://www.luogu.org/problemnew/show/P1359 题目描述 长江游艇俱乐部在长江上设置了n 个游艇出租站1,2,…,n.游客可在这些游艇出租站租用游艇, ...
- P1356 数列的整数性
P1356 数列的整数性打的骗分,在多组数据的情况下还能骗到分,可以了.又TMD是dp.f[i][j]表示+-第i个数能否达到%p后的余数j,如果f[n][0]==true就可以. #include& ...
- 001.Docker简介概述
一 简介 Docker最初是dotCloud公司的一个内部项目,诞生于 2013 年初,由google公司开源的Go语言开发. Docker是一个开源的引擎,可以轻松的为任何应用创建一个轻量级的.可移 ...
- python魔法方法-属性访问控制
属性访问控制 所谓的属性访问控制就是控制点号访问属性的行为,而且不仅是类的外部,连类的内部也受控制,代码见真章,边看代码边解释: __getattr__(self, item) 定义当访问不存在的属性 ...
- Chrome for Mac键盘快捷键!来自Google Chrome官网!
⌘-N 打开新窗口. ⌘-T 打开新标签页. ⌘-Shift-N 在隐身模式下打开新窗口. 按 ⌘-O,然后选择文件. 在 Google Chrome 浏览器中打开计算机中的文件. 按住 ⌘ 键,然后 ...
- 如何将Object类型转换成String类型
1. Object.toString() obj.toString() 注意:必须保证Object不是null值,否则将抛出NullPointerException异常. 2. (String)Obj ...
- tcp连接状态查看
linux常用查看tcp状态工具netstat和ss,这两个工具查看时都有1个Recv-Q和Send-Q 解释如下: 对应处于Listen状态的套接字: Recv-Q表示已建立连接队列中连接个数(等待 ...