• 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的更多相关文章

  1. (转帖) 有限狀態機FSM coding style整理 (SOC) (Verilog)

    来源:http://www.codesoso.net/Record/101092_95120_21.html 来源:http://www.cnblogs.com/oomusou/archive/201 ...

  2. 有限狀態機FSM coding style整理 (SOC) (Verilog)

    AbstractFSM在數位電路中非常重要,藉由FSM,可以讓數位電路也能循序地執行起演算法.本文將詳細討論各種FSM coding style的優缺點,並歸納出推薦的coding style. In ...

  3. 编程风格(Coding Style)要求

    编程风格(Coding Style)要求2.1.1 文件(1) 每个模块(module)一般应存在于单独的源文件中,通常源文件名与所包含模块名相同.(2) 每个设计文件开头应包含如下注释内容:? 年份 ...

  4. Linux 内核Coding Style整理

    转载:http://www.cnblogs.com/wang_yb/p/3532349.html 总结linux内核开发的coding style, 便于以后写代码时参考. 下面只是罗列一些规则, 具 ...

  5. linux c coding style

    Linux kernel coding style This is a short document describing the preferred coding style for the lin ...

  6. c coding style之学习篇

    1. 使用do-while结构去避免潜在的内存泄漏问题. do {     p1 = malloc(10);     if (null == p1)     {         break;     ...

  7. [中英对照]Linux kernel coding style | Linux内核编码风格

    Linux kernel coding style | Linux内核编码风格 This is a short document describing the preferred coding sty ...

  8. 谈谈Linux内核驱动的coding style【转】

    转自:http://www.cnblogs.com/wwang/archive/2011/02/24/1960283.html 最近在向Linux内核提交一些驱动程序,在提交的过程中,发现自己的代码离 ...

  9. Google's C++ coding style

    v0.2 - Last updated November 8, 2013 源自 Google's C++ coding style rev. 3.274 目录 由 DocToc生成     头文件   ...

随机推荐

  1. POJ 2337 Catenyms(有向欧拉图:输出欧拉路径)

    题目链接>>>>>> 题目大意: 给出一些字符串,问能否将这些字符串  按照 词语接龙,首尾相接  的规则 使得每个字符串出现一次 如果可以 按字典序输出这个字符串 ...

  2. Flutter常用组件(Widget)解析-Image

    显示图片的组件 以下是几种加载图片路径方式: Image.asset 加载asset项目资源中的文件 Image.network 加载网络资源图片,通过url加载 Image.file 加载本地文件中 ...

  3. ApplicationListener<ContextRefreshedEvent>接口,Spring启动后获取所有拥有特定注解的Bean

    最近项目中遇到一个业务场景,就是在Spring容器启动后获取所有的Bean中实现了一个特定接口的对象,第一个想到的是ApplicationContextAware,在setApplicationCon ...

  4. Python中按值来获取指定的键

    转自: https://blog.csdn.net/Jerry_1126/article/details/87907162 Python字典中的键是唯一的,但不同的键可以对应同样的值,比如说uid,可 ...

  5. 洛谷.1251.餐巾计划问题(费用流SPFA)

    题目链接 /* 每一天的餐巾需求相当于必须遍历某些点若干次 设q[i]为Dayi需求量 (x,y)表示边x容y费 将每个点i拆成i,i',由i'->T连(q[i],0)的边,表示求最大流的话一定 ...

  6. 潭州课堂25班:Ph201805201 爬虫基础 第十二课 点触验证码二 (课堂笔记)

    为上次代码添加 模拟人操作 的鼠标的移动轨迹 # -*- coding:utf-8 -*- # 斌彬电脑 # @Time : 2018/9/14 0014 上午 8:08 from selenium ...

  7. rabbitmq使用(三)

    Publish/Subscribe In the previous tutorial we created a work queue. The assumption behind a work que ...

  8. JSON Web Token(JWT)机制

    JSON Web Token(JWT)机制  JWT是一种紧凑且自包含的,用于在多方传递JSON对象的技术.传递的数据可以使用数字签名增加其安全行.可以使用HMAC加密算法或RSA公钥/私钥加密方式. ...

  9. 几种php加速器比较

    一.PHP加速器介绍 PHP加速器是一个为了提高PHP执行效率,从而缓存起PHP的操作码,这样PHP后面执行就不用解析转换了,可以直接调用PHP操作码,这样速度上就提高了不少. Apache中使用mo ...

  10. 《Attention is All You Need》

    https://www.jianshu.com/p/25fc600de9fb 谷歌最近的一篇BERT取得了卓越的效果,为了研究BERT的论文,我先找出了<Attention is All You ...