之前在使用Verilog做FPGA项目中、以及其他一些不同的场合下,零散的写过一些练手性质的testbench文件,开始几次写的时候,每次都会因为一些基本的东西没记住、写的很不熟练,后面写的时候稍微熟练了一点、但是整体编写下来比较零碎不成体系,所以在这里简要记录一下一般情况下、针对小型的verilog模块进行测试时所需要使用到的testbench文件的编写要点。

本文主要参考了在网上找到的Lattice公司的“A Verilog HDL Test Bench Primer”手册中的有关内容。谢谢!

模块实例化、reg&wire声明、initial和always块的使用

需要测试的模块(Verilog-module)被称为DUT(Design Under Test),在testbench中需要对一个或者多个DUT进行实例化。

Testbench中的顶层module不需要定义输入和输出。

Testbench中连接到DUT instance的输入的为reg类型、连接到DUT instance的输出的为wire类型。

对于DUT的inout类型变量,在testbench中需要分别使用reg、wire类型的变量进行调用。

例如,对于下面这样一个待测试module:

module bidir_infer (DATA, READ_WRITE);
input READ_WRITE ;
inout [:] DATA ;
reg [:] LATCH_OUT ; always @ (READ_WRITE or DATA) begin
if (READ_WRITE == )
LATCH_OUT <= DATA;
end assign DATA = (READ_WRITE == ) ? 'bZ : LATCH_OUT; endmodule

为其设计的testbench文件可以是:

module test_bidir_ver;
reg read_writet;
reg [:] data_in;
wire [:] datat, data_out;
bidir_infer uut (datat, read_writet); assign datat = (read_writet == ) ? data_in : 'bZ;
assign data_out = (read_writet == ) ? datat : 'bZ; initial begin
read_writet = ;
data_in = ;
# read_writet = ;
end endmodule

和普通的Verilog模块中一样、使用assign对wire类型的变量进行赋值。

需要留意的一点是:对于没有在代码中赋初始值的变量,wire类型变量被初始化为Z、reg类型变量被初始化为X。

always和initial是两种对reg变量进行操作的串行控制块。每个initial和always块都会在仿真开始时同时开始运行。

常见的,可以利用它们生成模块所需的时钟和复位信号,如下:

‘timescale  ns /  ps

reg clk_50, rst_l;

initial
begin
$display($time, " << Starting the Simulation >>");
clk_50 = ’b0; // at time 0
rst_l = ; // reset is active
# rst_l = ’b1; // at time 20 release reset
end always
# clk_50 = ~clk_50; // every ten nanoseconds invert

首行定义了时间单位/时间精度。时间单位为1ns,这样生成的clk_50时钟周期就是20ns、也就是频率为50MHz。

复位信号rst_l在初始为0复位态、在20ns之后为1解除复位。

仿真中的停止、变量监视和输出

有两种仿真控制函数:$finish和$stop。其中,$finish任务用于终止仿真并跳出仿真器;$stop任务则用于中止仿真。在Modelsim中,$stop任务则是返回到交互模式。

如果需要监视仿真中某个变量的变化情况,可以使用$monitor函数:

$monitor($time, " clk_50=%b, rst_l=%b, enable_l=%b, load_l=%b, count_in=%h, cnt_out=%h, oe_l=%b, count_tri=%h", clk_50, rst_l, enable_l, load_l, count_in, cnt_out, oe_l, count_tri);

每当变量列表中的任一变量发生变化,就会产生输出。

如果需要在仿真控制台屏幕打印输出,可以使用$display函数:

$display($time, "<< count = %d - Turning OFF count enable >>",cnt_out);

任务Task的用法

可以将一组重复性的或者相关的命令组合到一起构成一个任务。

任务通常可以在initial或者always块中被调用。

一个任务可以拥有输入、输出、以及inouts,也可以包含计时或延时元素。

以一个在FPGA上实现的简单SPI接口为例。外部设备为主、FPGA为从,命令一共32bit,构成为“1位读写命令字(1读0写)+14位地址+1位NO CARE+16位数据”,片选信号拉低之后通信开始,时序如下图:

数据流由外设到FPGA时(FPGA为接收),外设在SCLK的下降沿更新MOSI;FPGA在SCLK的上升沿将MOSI上的值抓取到移位寄存器。

当FPGA为发送方时,FPGA在SCLK的下降沿更新MISO线上的输出,外设在SCLK的上升沿将MISO上的值抓取过来。

外设可以通过该SPI接口访问FPGA内部生成的寄存器。

当对FPGA上的spi模块进行读测试时,外设发给FPGA的读指令为:

{1'b1,address,1'b0,data(读取到的16bit数据)}

为此编写的任务spi_read可以是:

task spi_read;
input[:] address;
output[:] data;
reg [:] output_register;
reg [:]input_register;
integer i;
begin
$display("time:%t----------------task spi_read",$time );
#;
spi_clk = 'b0;
spi_csn = 'b1;
spi_mosi ='b0;
output_register = {'b1,address,1'b0,'d0}; $display("time:%t,testbench read output_register: %h,",$time,output_register );
$display("time:%t,testbench read address: %h",$time,address ); spi_csn = 'b1;
for(i = ; i < ; i=i+)
begin
spi_csn = 'b0;
spi_clk = 'b0;
spi_mosi = output_register[-i];
#;
spi_clk = 'b1;
#;
end for(i = ; i < ; i=i+)
begin
spi_csn = 'b0;
spi_clk = 'b0;
#;
spi_clk = 'b1;
input_register[-i] = spi_miso;
#;
end
spi_csn = 'b1; data = input_register;
$display("time:%t,testbench spi_read read data: %h,",$time,input_register ); $display("time:%t----------------",$time );
#;
end endtask

(其中仿真的时间单位为1ns,spi时钟频率为10MHz)

示例及汇总

根据前述内容,自我总结一般简单的testbench文件的结构形式可以是如下:

`timescale  ns /  ns

module testbench_module_top;
reg
reg
……
wire
wire
…… //reset and clock definition
initial begin …end
initial begin …end //actual testing flows
initial
begin
//variables initialization
a =
b =
… task_1(var_1… var_N)

task_N(var_1… var_N)
$stop;
…end //dut module instance
module_top U1
(
.var1(),
.var2(),

.varN()
) //necessary control logic for testbench module test flow
always@(...) //tasks definition
task task_1;
input …;
output …;
……
//action flow
……
endtask …… task task_N;
……
endtask endmodule

Testbench文件编写纪要(Verilog)的更多相关文章

  1. 转:SYNOPSYS VCS Makefile文件编写与研究

    SYNOPSYS VCS Makefile文件编写与研究 这个Makefile是synopsys提供的模板,看上去非常好用,你只要按部就班提供实际项目的参数就可以了.我们来看这个文件的头部说明:mak ...

  2. Testbench的编写

    Testbench的作用,在于给我们编写的可综合代码的模块送入激励.即在我们波形仿真中用编写testbench来代替拖拽波形.其中还包括了我们硬件仿真与matlab仿真的联调建立(将matlab产生的 ...

  3. 网站 robots.txt 文件编写

    网站 robots.txt 文件编写 Intro robots.txt 是网站根目录下的一个纯文本文件,在这个文件中网站管理者可以声明该网站中不想被robots访问的部分,或者指定搜索引擎只收录指定的 ...

  4. 【OpenWRT】【RT5350】【三】MakeFile文件编写规则和OpenWRT驱动开发步骤

    一.Makefile文件编写 http://www.cnblogs.com/majiangjiang/articles/3218002.html 可以看下上面的博客,总结的比较全了,在此不再复述 二. ...

  5. linux库文件编写入门(笔记)

    linux库文件的编写 作者: laomai地址: http://blog.csdn.net/laomai 本文主要参考了如下资料⑴hcj写的"Linux静态/动态链接库的创建和使用&quo ...

  6. Linux Makefile文件编写详细步骤与实践

    Linux Makefile文件编写详细步骤与实践 1.makefile概述 Windows环境下IDE会帮你完成makefile文件的编写,但在UNIX环境下你就必须自己写makefile了,会不会 ...

  7. Pdf File Writer 中文应用(PDF文件编写器C#类库)

    该文由小居工作室(QQ:2482052910)    翻译并提供解答支持,原文地址:Pdf File Writer 中文应用(PDF文件编写器C#类库):http://www.cnblogs.com/ ...

  8. 一个简单的makefile文件编写

    下午闲来无聊,就打开很久没动过的linux系统想熟悉熟悉在linux上面编译代码,结果一个makefile文件搞到晚上才搞定,哈哈! 先把代码简单贴上来,就写了一个冒泡排序: sort.h: #ifn ...

  9. C++ Makefile文件编写

    对现有的一个C++动态库文件和调用程序,分别编写Makefile文件,从零开始,这里把自己弄明白的一些东西分享给大家. 1.必须明确Linux下,C++的编译器是g++,C语言的是gcc.网上大多数又 ...

随机推荐

  1. [luogu1156]垃圾陷阱_动态规划_背包dp

    垃圾陷阱 luogu-1156 题目大意:Holsteins在距离地面D英尺的地方,FJ间隔时间ti会往下扔第i个垃圾.Holsteins对待每一个垃圾都会选择吃掉或者垫高.Holsteins有10个 ...

  2. js递归解决汉诺塔问题

    汉诺塔是一个印度的古老传说.有三个圆柱,其中一个圆柱上放着若干圆盘,这些圆盘从上到下,直径递增,利用一个辅助圆柱,将原来柱子上的圆盘放到另一个柱子上,依旧是从上到下直径递增. 汉诺塔是一个经典的递归案 ...

  3. mapreduce v1.0学习笔记

    它是什么? 一个用于处理大数据开源的分布式计算框架,它由java实现,原生提供java编程交互接口,其它语言通过hadoop streaming方式和mapreduce框架交互. 可以做什么? 利用框 ...

  4. [转]数据库查询 sysobjects

    sysobjects sysobjects是系统自建的表,里面存储了在数据库内创建的每个对象(约束.默认值.日志.规则.存储过程等),各在表中占一行.只有在 tempdb 内,每个临时对象才在该表中占 ...

  5. [MongoDB]mongo命令行工具

    1.use dbname 自动创建 2.db.user.find() 空 show collections 空 show dbs 3.db.user.save({name:'',age:20}) db ...

  6. java如何实现替换指定位置的指定字符串的功能

    /**  * @创建日期 2013-07-15  * @创建时间 14:25:59  * @版本号 V 1.0  */ public class CosTest {     public static ...

  7. Wikioi 1081 线段树成段更新单点查询

    线段树练习飘逸的写法,自从自己改成这样的写法之后,线段树就没再练过,如今最终练得上了. 由于这里查询仅仅是查询了叶子结点,所以pushUp函数就用不上了,只是我没去掉之前是3ms.去掉之后反而变成4m ...

  8. SVM最通俗的解读

    摘自:https://www.zhihu.com/question/21094489/answer/86273196 什么是SVM? 当然首先看一下wiki. Support Vector Machi ...

  9. B2460 [BeiJing2011]元素 线性基

    这个题是对刚才线性基的一个补充,就是中间有一些小贪心,贪心就很有意思,先按权值排序,然后就瞎搞就行了. 题干: Description 相传,在远古时期,位于西方大陆的 Magic Land 上,人们 ...

  10. img标签间距问题

    关于img标签间距问题:多个img之间有间距,包含img标签的div之间有间距. <!doctype html> 2 <html lang="en"> 3 ...