作者:桂。

时间:2017-08-15  07:11:50

链接:http://www.cnblogs.com/xingshansi/p/7363048.html


前言

  Testbench主要用于module的测试,这里仅记录一般的操作流程。

〇、verilog与C的区别

  本段文字出处

  RTL级的verilog其实就是常说的verilog语言中可综合的那部分,它是verilog语言的一个子集。所谓的RTL级建模,其实也就是用verilog语言去描述实际电路的行为,比如用verilog语言去描述一个ram或者是一个移位寄存器。 
  对于这个层次上的建模,最重要的思想就是“硬件意识”,也就是说,我们在写代码的时候,大脑里要先知道我们设计的是什么样的电路,然后再用verilog语言将它描述出来。其实,在出现硬件描述语言之前,电路设计都是用原理图去搭的,这种设计过程也是我们心中先有了电路,然后用一种计算机能够识别的方式进行描述,现在的verilog HDL只是相当于我们有了更先进的描述方法,但是在RTL级的设计过程还是不变----心中先有电路,再将它翻译成verilog代码。 
刚才我们说了,RTL的设计其实就是用verilog去描述电路的行为,那么,我们要怎么去理解这个“电路的行为”呢? 
第一,电路在物理上是并行工作的。 
  我们知道,在写C程序的时候,由于CPU在任一时刻最多只能执行一条指令,程序都是顺序执行的,即使是我们平时说的多任务操作系统,所谓的并行任务也只是从宏观上来说的(人感觉不到而已),但从微观上来说它仍然是顺序执行的。所以我们设计C程序时思维是串行或者说是并行的。所以看语言不能从上往下看调用逻辑,而是要抓住数据的流向,各个In/out的调用顺序。
  但是数字电路设计则不然,数字电路芯片无非是由一些门电路和触发器组成,从物理上看,在任何时刻,芯片内部各部分电路都是同时工作的。所以在设计的时候,我们需要以一种并发的思维去思考。以下面例子为例: 
例3:

always @(posedge clk or negedge rst_n)
begin
if ( rst_n == 1'b0 )
begin
wren <= 1’b0;
rden <= 1’b0;
end
else
begin
wren <= a&b;
rden <= c&d;
end
end

  在综合成实际电路之后,wren和rden的赋值是同时进行的,并不会因为wren在rden前面就先对wren赋值(其实将赋值理解高低电平的传递会更好一些)。事实上,当综合成网表文件后,这种赋值的先后顺序也就不存在了。

第二,电路行为的先后顺序是通过时钟节拍去完成的。 
  在一些时候,我们需要完成这样的功能:在STATE0状态下,当事件A来了后,去触发状态STATE1;在状态STATE1下,外部总线上读取数据;在处理完后,又进入到状态STATE2,将数据突发传送到背板总线上,并回到STATE0。 
  这就有了一种逻辑上的先后关系,但是由于我们的电路都是并行工作的,我们不能像C语言的方式将代码在一个进程中按先后顺序排放后就可以完成功能。那我们要怎么去实现呢?我们知道,我们人类去判别先后顺序是按通过时间完成的,也就是说,如果我们是基于时钟节拍去设计的话----即在节拍n事件A到来,在节拍B进入状态STATE0,在n+1到n+k节拍中每x个节拍从外部总线上取一个数,在n+k节拍后,每一个节拍将缓存在FIFO的数据放到背板总线上,就可以实现这种逻辑的先后顺序。总结起来,就是电路行为的逻辑先后顺序是通过时钟节拍去体现的,设计时可以通过将事件安排在不同的时钟节拍去完成。

  二、Testbench的基本操作

  A-基本操作

  对于testbench而言,端口与被测module一一对应,input声明为reg,output声明为wire,如果是systemveriog,则可以统一定义为logic。

1-直接赋值

initial操作:

module exam();
reg rst_n;
reg clk;
reg data; initial
begin
clk=1'b0;
rst=1'b1;
#10
rst=1'b0;
#500
rst=1'b1;
end always
begin
#10
clk=~clk;
end

  注意到有个#符号,该符号的意思是指延迟相应的时间单位。该时间单位由timscale决定.一般在testbench的开头定义时间单位和仿真 精度,比如`timescale 1ns/1ps,前面一个是代表时间单位,后面一个代表仿真时间精度。以上面的例子而言,一个时钟周期是20个单位,也就是20ns。而仿真时间精度的概 念就是,你能看到1.001ns时对应的信号值,而假如timescale 1ns/1ns,1.001ns时候的值就无法看到。对于一个设计而言,时间刻度应该统一,如果设计文件和testbench里面的时间刻度不一致,仿真 器默认以testbench为准。一个较好的办法是写一个global.v文件,然后用include的办法,可以防止这个问题。

2-重复操作

例如写某一个字符串,需要重复操作且字符串内容有变更,这个时候可以借助task来完成。

task load_count;
input [3:0] load_value;
begin
@(negedge clk_50);
$display($time, " << Loading the counter with %h >>", load_value);
load_l = 1’b0;
count_in = load_value;
@(negedge clk_50);
load_l = 1’b1;
end
endtask //of load_count initial
begin
load_count(4’hA); // 调用task
end

  其他像forever,for,function等等语句用法类似,虽然不一定都能综合,但是用在testbench里面即使是偏高级的语言也不要紧,写testbench与写普通的module思路略有差异。

3-文件输入

有时候,需要大量的数据输入,直接赋值的话比较繁琐,可以先生成数据,再将数据读入到寄存器中,需要时取出即可。用 $readmemb系统任务从文本文件中读取二进制向量(可以包含输入激励和输出期望值)。$readmemh 用于读取十六进制文件。例如:

reg [7:0]   mem[1:256]   //   a 8-bit, 256-word 定义存储器mem
initial $readmemh ( "E:/readhex/mem.dat", mem ) // 将.dat文件读入寄存器mem中
initial $readmemh ( "E:/readhex/mem.dat", mem, 128, 1 ) // 参数为寄存器加载数据的地址始终

  B-查看仿真结果

  对于简单的module来说,要在modelsim的仿真窗口里面看波形,就用add wave ..命令,比如,testbench的顶层module名叫tb,要看时钟信号,就用add wave tb.clk。要查看所有信号的时候,就用 add wave /*。当然,也可以在workspace下的sim窗口里面右键单击instance来添加波形。
  对于复杂的仿真,免不了要记录波形和数据到文件里面去。 这一块的资料可搜索关键词:$dumpvar

  C-testbench编写技巧

1).如果激励中有一些重复的项目,可以考虑将这些语句编写成一个task,这样会给书写和仿真带来很大方便。例如,一个存储器的testbench的激励可以包含write,read等task。

2).如果DUT中包含双向信号(inout),在编写testbench时要注意。需要一个reg变量来表示其输入,还需要一个wire变量表示其输出。

3).如果initial块语句过于复杂,可以考虑将其分为互补相干的几个部分,用数个initial块来描述。在仿真时,这些initial块会并发运行。这样方便阅读和修改。

4).每个testbench都最好包含$stop语句,用以指明仿真何时结束。
5).加载测试向量时,避免在时钟的上下沿变化,比如数据最好在时钟上升沿之前变化,这也符合建立时间的要求。

  三、常用的时钟/复位

时钟clk以及复位rst是除了测试模块外,必须要考虑的信息。

  A-产生时钟的几种方式
(a)使用initial方式产生占空比50%的时钟
initial
begin
Clk = 0 ;
# delay ;
forever
# (period/2) Clk = ~ Clk ;
end

  注意一定要给时钟赋初始值,因为信号的缺省值为z,如果不赋初值,则反相后还是z,时钟就一直处于高阻z状态。产生的时钟信号如下

(b)使用always方式
initial
Clk= 0 ;
always
# (period/2) Clk = ~ Clk ;
(c)使用repeat产生确定数目的时钟脉冲
initial
begin
Clk = 0 ;
repeat ( 6 )
# (period/2) Clk = ~ Clk ;
end

  该例使用repeat产生 3个时钟脉冲,产生的波形如下:


(d)产生占空比非50%的时钟
initial
Clk = 0 ;
always
begin
# 3 Clk=~Clk;
#2 Clk=~Clk;
end

  B-产生复位信号的几种形式

(a)异步复位
initial
begin
Rst = 1 ;
# 100 ;
Rst = 0 ;
# 500 ;
Rst = 1 ;
end
(b)同步复位信号
initial
begin
Rst = 1 ;
@( negedge Clk) ; //等待时钟下降沿
Rst = 0 ;
# 30 ;
repeat(3)@( negedge Clk) ; //等待3个时钟下降沿
Rst = 1 ;
end
 
参考
  • http://blog.csdn.net/wordwarwordwar/article/details/53885209

Testbench的更多相关文章

  1. UVM Top Testbench

    top testbench在top_tb中包含进所有的文件,将DUT放在top_tb中(例化DUT),连接好各个端口,提供clk时钟和rst_n复位信号.最主要的是要给组件中的虚接口设置接口,一般是给 ...

  2. VHDL TestBench基础(转)

    TestBench的主要目标是: 实例化DUT-Design Under Test 为DUT产生激励波形 产生参考输出,并将DUT的输出与参考输出进行比较 提供测试通过或失败的指示 TestBench ...

  3. VHDL的testbench的编写(转)

    大多数硬件设计人员对verilog的testbench比较熟悉,那是因为verilog被设计出来的目的就是为了用于测试使用,也正是因为这样verilog的语法规则才被设计得更像C语言,而verilog ...

  4. quartus II 自动生成testbench

    如果自己不想写这些testbench的这些固定格式,可以在quartus里自动生成testbench文件的模板,然后往里面写信号就行了 步骤:processing->start->star ...

  5. testbench中将外部数据引入输出的方法(转载)

    在进行HDL的仿真测试时,除了用较为直观的波形仿真图像以外,通过编写测试文件testbench进行仿真并将仿真结果保存在对应的文件,显得尤为重要.文件的操作主要用到读和写两种操作. 1. 读操作 读操 ...

  6. 关于使用ModelSim中编写testbench模板问题

    对于初学者来说写Testbench测试文件还是比较困难的,但Modelsim和quartus ii都提供了模板,下面就如何使用Modelsim提供的模板进行操作. Modelsim提供了很多Testb ...

  7. IIC模块TestBench的书写方法

    今天在看黑金AX309FPGA开发板自带教程中的EEPROM那一章,考虑如何写其中iic_com模块的TestBench,难点在于1. 该模块存在一个inout型的端口信号:2. 时序较为复杂,不可能 ...

  8. Testbench(转)

    本来还打算自己写下对Testbench的理解,后来发现百度百科名片解释得很好,所以就直接转了. 原文百度百科链接:http://baike.baidu.com/link?url=dxzsOAs32IE ...

  9. vcs+Makefile实现简单的testbench

    网络上找的文章,实现了一遍. 步骤如下: 1. 创建verilog代码, 包括8位加法器代码和testbench代码. adder8.v module adder8 ( input clk, inpu ...

  10. Verilog TestBench Coding Style

    Abtract 关于编写testbench的一些经验总结心得. Introduction 1.基本的Testbench结构 1)常用的编码结构 `timescale 1 ns / 1 ps       ...

随机推荐

  1. C++中用完需要释放掉内存的几个类

      BSTR BSTR bstrXML = NULL; //用完以后,或者 catch段中 if(bstrXML) ::SysFreeString(result); VARIANT VARIANT v ...

  2. 正则 js分转元带千分符号

    可以通过缩放来进行分到元的转换,同时使用正则对处理后的数字进行千分位格式化 方法1:(不丢失精度) function Fen2Yuan( num ) { if ( typeof num !== &qu ...

  3. uva 11181 - Probability|Given(概率)

    题目链接:uva 11181 - Probability|Given 题目大意:有n个人去超市买东西,给出r,每个人买东西的概率是p[i],当有r个人买东西的时候,第i个人恰好买东西的概率. 解题思路 ...

  4. java创建线程的三种方式及其对比

    第一种方法:继承Thread类,重写run()方法,run()方法代表线程要执行的任务.第二种方法:实现Runnable接口,重写run()方法,run()方法代表线程要执行的任务.第三种方法:实现c ...

  5. 【C++系列小结】面向过程的编程风格

    前言 编程语言有面向过程和面向对象之分,因此编程风格也有所谓的面向过程的编程和面向对象的编程,并且语言的性质不会限制编程的风格. 这里主要说一以下向过程的编程. "面向过程"(Pr ...

  6. SoapUI 测试接口演示

      SoapUI 测试接口演示 CreateTime--2018年4月2日15:54:05 Author:Marydon 以webservice为例 1.安装:  SoapUI-x64-5.4.0-E ...

  7. 〖Eclipse〗Eclipse实现类似于YouCompleteMe补全插件的tab选择,shift+tab反向选择,空格、回车、点号等结束选择。

    1.增加Eclipse的提示功能 在Eclipse中,从Window -> preferences -> Java -> Editor -> Content assist -& ...

  8. Asp.net Mvc (Filter及其执行顺序)

    应用于Action的Filter 在Asp.netMvc中当你有以下及类似以下需求时你可以使用Filter功能判断登录与否或用户权限,决策输出缓存,防盗链,防蜘蛛,本地化设置,实现动态Actionfi ...

  9. 使用quartz进行容器启动时登陆接口服务器和接口服务器进行心跳连接

    1.下载quartz的相应jar包 2.增加spring配置文件(applicationContext-quartz.xml) 内容如下: <?xml version="1.0&quo ...

  10. java 如何取前32位全是1的int型数据的后八位

    直接&255 因为Integer.toBinaryString(255) 是 8个1. 如果一个负数byte转成int则前面全部会补1,就是24个1和它自己的八位,,于是和八个1相&就 ...