如何编写testbench的总结

作者&投稿:廖甘 (若有异议请与网页底部的电邮联系)
如何编写testbench的总结~

  如何编写 testbench 的总结(非常实用的总结) 1.激励的设置 相应于被测试模块的输入激励设置为 reg 型,输出相应设置为 wire 类型,双向端口 inout 在 测试中需要进行处理。 方法 1:为双向端口设置中间变量 inout_reg 作为该 inout 的输出寄存,inout 口在 testbench 中要定义为 wire 型变量,然后用输出使能控制传输方向。 eg: inout[0:0]bi_dir_port; wire[0:0]bi_dir_port; reg[0:0]bi_dir_port_reg; regbi_dir_port_oe; assignbi_dir_port=bi_dir_port_oe?bi_dir_port_reg:1'bz; 用 bi_dir_port_oe 控制端口数据方向,并利用中间变量寄存器改变其值。等于两个模块之间 用 inout 双向口互连。往端口写(就是往模块里面输入) 方法 2:使用 force 和 release 语句,这种方法不能准确反映双向端口的信号变化,但这种方 法可以反映块内信号的变化。具体如示: moduletest(); wiredata_inout; regdata_reg; reglink; #xx;//延时 forcedata_inout=1'bx;//强制作为输入端口 ............... #xx; releasedata_inout;//释放输入端口 endmodule 从文本文件中读取和写入向量 1)读取文本文件:用$readmemb 系统任务从文本文件中读取二进制向量(可以包含输入激 励和输出期望值) 。$readmemh 用于读取十六进制文件。例如: reg[7:0]mem[1:256]//a8-bit,256-word 定义存储器 mem initial$readmemh("mem.data",mem)// 将.dat 文件读入寄存器 mem 中 initial$readmemh("mem.data",mem,128,1)// 参数为寄存器加载数据的地址始终 2)输出文本文件:打开输出文件用?$fopen 例如: integerout_file;//out_file 是一个文件描述,需要定义为 integer 类型 out_file=$fopen("cpu.data");//cpu.data 是需要打开的文件,也就是最终的输出文本 设计中的信号值可以通过$fmonitor,$fdisplay, 2.Verilog 和 Ncverilog 命令使用库文件或库目录 ex).ncverilog-frun.f-vlib/lib.v-ylib2+libext+.v//一般编译文件在 run.f 中, 库文件在 lib.v 中,lib2 目录中的.v 文件系统自动搜索 使用库文件或库目录,只编译需要的模块而不必全部编译 3.VerilogTestbench 信号记录的系统任务: 1).SHM 数据库可以记录在设计仿真过程中信号的变化. 它只在 probes 有效的时间内记录你 setprobeon 的信号的变化. ex).$shm_open("waves.shm");//打开波形数据库 \f$shm_probe(top,"AS");//setprobeon"top", 第二个参数:A--signalsofthespecificscrope S--Portsofthespecifiedscopeandbelow,excludinglibrarycells C--Portsofthespecifiedscopeandbelow,includinglibrarycells AS--Signalsofthespecifiedscopeandbelow,excludinglibrarycells AC--Signalsofthespecifiedscopeandbelow,includinglibrarycells 还有一个 M,表示当前 scope 的 memories,可以跟上面的结合使用,"AM""AMS""AMC" 什么都不加表示当前 scope 的 ports; $shm_close//关闭数据库 2).VCD 数据库也可以记录在设计仿真过程中信号的变化. 它只记录你选择的信号的变化. ex).$dumpfile("filename");//打开数据库 $dumpvars(1,top.u1);//scope=top.u1,depth=1 第一个参数表示深度, 为 0 时记录所有深度; 第二个参数表示 scope,省略时表当前的 scope. $dumpvars;//depth=allscope=all $dumpvars(0);//depth=allscope=current $dumpvars(1,top.u1);//depth=1scope=top.u1 $dumpoff//暂停记录数据改变,信号变化不写入库文件中 $dumpon//重新恢复记录 3).Debussyfsdb 数据库也可以记录信号的变化,它的优势是可以跟 debussy 结合,方便调试. 如果要在 ncverilog 仿真时,记录信号, 首先要设置 debussy: a.setenvLD_LIBRARY_PATHLD_LIBRARY_PATH (pathfordebpli.sofile(/share/PLI/nc_xl//nc_loadpli1)) b.whileinvokingncverilogusethe+ncloadpli1option. ncverilog-frun.f+debug+ncloadpli1=debpli:deb_PLIPtr fsdb 数据库文件的记录方法,是使用$fsdbDumpfile 和$fsdbDumpvars 系统函数,使用方法参见 VCD 注意: 在用 ncverilog 的时候,为了正确地记录波形,要使用参数:"+access+rw", 否则没有读写 权限 在记录信号或者波形时需要指出被记录信号的路径,如:tb.module.u1.clk. ??????????????????????????????????????? 关于信号记录的系统任务的说明: 在 testbench 中使用信号记录的系统任务,就可以将自己需要的部分的结果以及波形文件记 录下来(可采用 sigalscan 工具查看) ,适用于对较大的系统进行仿真,速度快,优于全局仿 真。使用简单,在 testbench 中添加: initialbegin $shm_open("waves.shm"); $shm_probe("要记录信号的路径“, ”AS“) ; #10000 $shm_close;即可。 4.ncverilog 编译的顺序:ncverilogfile1file2.... 有时候这些文件存在依存关系,如在 file2 中要用到在 file1 中定义的变量,这时候就要注意其 编译的顺序是 从后到前,就先编译 file2 然后才是 file2. 5.信号的强制赋值 force \f首先, force 语句只能在过程语句中出现,即要在 initial 或者 always 中间. 去除 force 用 release 语句. initialbeginforcesig1=1'b1;...;releasesig1;end force 可以对 wire 赋值,这时整个 net 都被赋值; 也可以对 reg 赋值. 6.加载测试向量时,避免在时钟的上下沿变化 为了模拟真实器件的行为,加载测试向量时,避免在时钟的上下沿变化,而是在时钟的上升 沿延时一个时间单位后,加载的测试向量发生变化。如: assign#5c=a^b ?? @(posedgeclk)#(0.1*`cycle)A=1; ****************************************************************************** //testbench 的波形输出 moduletop; ... initial begin $dumpfile("./top.vcd");//存储波形的文件名和路径,一般是.vcd 格式. $dumpvars(1,top);//存储 top 这一层的所有信号数据 $dumpvars(2,top.u1);//存储 top.u1 之下两层的所有数据信号(包含 top.u1 这一层) $dumpvars(3,top.u2);//存储 top.u2 之下三层的所有数据信号(包含 top.u2 这一层) $dumpvars(0,top.u3);//存储 top.u3 之下所有层的所有数据信号 end endmodule //产生随机数,seed 是种子 $random(seed); ex:dinY)=0.2; (B*->Y)=0.3; (C*->Y)=0.1; endspecify endmodule //时间刻度 `timescale 单位时间/时间精确度 //文件 I/O 1.打开文件 integerfile_id; file_id=fopen("file_path/file_name"); 2.写入文件 //$fmonitor 只要有变化就一直记录 $fmonitor(file_id,"%format_char",parameter); egfmonitor(file_id,"%m:%tin1=%do1=%h",$time,in1,o1); //$fwrite 需要触发条件才记录 $fwrite(file_id,"%format_char",parameter); //$fdisplay 需要触发条件才记录 $fdisplay(file_id,"%format_char",parameter); $fstrobe(); 3.读取文件 integerfile_id; file_id=$fread("file_path/file_name","r"); 4.关闭文件 $fclose(fjile_id); 5.由文件设定存储器初值 $readmemh("file_name",memory_name");//初始化数据为十六进制 $readmemb("file_name",memory_name");//初始化数据为二进制 //仿真控制 $finish(parameter);//parameter=0,1,2 $stop(parameter); //读入 SDF 文件 \f$sdf_annotate("sdf_file_name",module_instance,"scale_factors"); //module_instance:sdf 文件所对应的 instance 名. //scale_factors:针对 timmingdelay 中的最小延时 min,典型延迟 typ,最大延时 max 调整延迟参 数 //generate 语句,在 Verilog-2001 中定义.用于表达重复性动作 //必须事先声明 genvar 类型变量作为 generate 循环的指标 eg: genvari; generatefor(i=0;i<4;i=i+1) begin assign=din=i%2; end endgenerate //资源共享 always@(AorBorCorD) sum=sel?(A+B) C+D); //上面例子使用两个加法器和一个 MUX,面积大 //下面例子使用一个加法器和两个 MUX,面积小 always@(AorBorCorD) begin tmp1=sel?A:C; tmp2=sel?B ; end always@(tmp1ortmp2) sum=tmp1+tmp2; ****************************************************************************** 模板: moduletestbench;//定义一个没有输入输出的 module reg??//将 DUT 的输入定义为 reg 类型 ?? wire??//将 DUT 的输出定义为 wire 类型 ?? //在这里例化 DUT initial begin ??//在这里添加激励(可以有多个这样的结构) end always??//通常在这里定义时钟信号 initial //在这里添加比较语句(可选) end initial //在这里添加输出语句(在屏幕上显示仿真结果) end \fendmodule 一下介绍一些书写 Testbench 的技巧: 1.如果激励中有一些重复的项目,可以考虑将这些语句编写成一个 task,这样会给书写和仿 真带来很大方便。例如,一个存储器的 testbench 的激励可以包含 write,read 等 task。 2.如果 DUT 中包含双向信号(inout),在编写 testbench 时要注意。需要一个 reg 变量来表示 其 输入,还需要一个 wire 变量表示其输出。 3.如果 initial 块语句过于复杂,可以考虑将其分为互补相干的几个部分,用数个 initial 块来 描述。在仿真时,这些 initial 块会并发运行。这样方便阅读和修改。 4.每个 testbench 都最好包含$stop 语句,用以指明仿真何时结束。

一、 基本概念和基础知识
Testbench 不仅要产生激励也就是输入,还要验证响应也就是输出。当然也可以只产生
激励,然后通过波形窗口通过人工的方法去验证波形,这种方法只能适用于小规模的设计。
在ISE 环境中,当前资源操作窗显示了资源管理窗口中选中的资源文件能进行的相关操
作。在资源管理窗口选中了testbench 文件后,在当前资源操作窗显示的ModelSim
Simulator 中显示了4 种能进行的模拟操作,分别是:Simulator Behavioral Model(功能
仿真)、Simulator Post-translate VHDL Model(翻译后仿真)、Simulator Post-Map VHDL
Model(映射后仿真)、Simulator Post-Place & Route VHDL Model(布局布线后仿真)。如
图1 所示:
图1
l Simulator Behavioral Model 也就是所说的功能仿真、行为仿真、前仿真。验证
功能是否正确,这是设计的第一步。功能仿真正确的程序不一定能被正确综合,也
就是硬件实现。有的在综合时报错误,有的虽然能综合但结果并不正确。当然,功
能仿真如果都不能通过,以后的步骤也就无法进行。这是必做的仿真。
l Simulator Post-translate VHDL Model 也就是翻译后仿真。对源程序进行编译后
首先排除了语法错误,对一些像类属命令(Generic)、生成语句(Generate)等进
行了展开。不是必做的仿真。
l Simulator Post-Map VHDL Model也就是映射后仿真。不同的器件内部结构也不尽
相同,映射的作用就是将综合后产生的网表文件对应到实际的器件上去。由于映射
不包含布线,也就是要用什么类型的逻辑单元虽然已经确定但要用哪个位置的还没
有确定,因此,映射后仿真不包含布线延时。不是必做的仿真。
l Simulator Post-Place & Route VHDL Model 也就是所说的布局布线后仿真、时序
仿真、后仿真。这是最完整的仿真,既包含逻辑延时又包含布线延时。在做布局布
线后仿真时要用到一个叫SDF的文件。SDF文件包含设计中每个单元(Cell)的延
时和时序约束数据。通过加载这个文件就能得到完整的时序情况。它是必做的仿真。
一般必须进行功能仿真和布局布线后仿真。
常见问题:
为什么有的testbench在进行功能仿真时能正确进行,而在进行布局布线后仿真时就不
能运行。有两点要注意的地方:(1)、在做映射后仿真或布局布线后仿真时,都已经经过了
综合工具的综合,源程序中的类属命令(Generic)、生成语句(Generate)等都已经进行展
开。例如,如果用Generic 定义了一个参数width,综合工具进行综合时已经按照一个确定
的width 值进行了综合。它生成的电路已经具有一个确定的结构,不能再随意调整。所以在
映射后仿真和布局布线后仿真的testbench中,往往不能出现Generic 语句。(2)映射后仿
真和布局布线后仿真都要用到SDF 文件,并且要将SDF文件关联到设计中的实例。所以在映
射后仿真和布局布线后仿真的testbench中,第一,要将你的设计声明成一个元件。第二,
实例化你设计的元件并且实例名要取为UUT(默认的,当然也可以改)。
关于断言语句
在仿真中为了能得到更多信息,经常要用到断言语句(assert)。其语法如下:
Assert
Report
Severity;
出错级别共有5 种:
l Note
l Warning
l Error
l Failure
l Fatal
在VHDL 模型的模拟过程中,一旦断言语句的条件为假,则发送消息并将出错级别发送
给模拟器。通常可以设置一个中止模拟器运行的出错级别,一般默认的中止运行的出错级别
为Failure。
我们来看一个例子:
assert false
report "********* " & IMAGE(DWIDTH) & "BIT DIVIDER SEQUENCE FINISHED
AT " & IMAGE(now) & " !" & " *********"
severity note;
断言的条件不是一个条件表达式,而直接是false。这说明只要程序执行到这里断言就
一定会成立,送出消息。出错级别为note,在模拟器的输出窗口将会显示:
图2
再看一个例子:
assert (s_cyi((DWIDTH-1)/4) = '0')
and (s_ovi = '0')
and (s_qutnt = conv_std_logic_vector(v_quot,DWIDTH))
and (s_rmndr = conv_std_logic_vector(v_remd,DWIDTH))
report "ERROR in division!"
severity failure;
断言的条件有4 个并且是与的关系,只要其中一个条件不成立则整个表达式为假,断言
成立。如果断言成立将输出“ERROR in division!“这个消息。并且通知模拟器出错级别为
failure,这一般会停止模拟。这个断言实际是在对结果进行验证。
二、实际testbench分析
下面将详细分析一个实际的testbench,它是用来测试8051 的ALU单元的除法功能的。
8 位的除法器,被除数和除数的组合共有256×256=65536 种。我们采用的方法是穷举所有
的输入组合,这样的代码覆盖率可以达到100%。它的验证必须通过程序自动完成,否则通
过人工方法工作量太大。
把要测试的程序当作一个元件,例如想象成一个74 系列数字电路。Testbench 的作用
是在被测试电路的输入端加上激励,然后比较被测试电路的输出和计算出来的期望值是否一
致。对我们这个例子来说,在要仿真的ALU 输入端产生65536 种输入组合,然后将ALU产生
的对应输出值和testbench 算出的期望值相比较,如果有错误产生则停止模拟并输出信息。
ALU 的除法单元的输入有4 个,分别是被除数、除数、进位、溢出位;输出也有4 个,分别
是商、余数、新的进位、新的溢出位。
1、 testbench 的输出s_dvdnd(被除数)、s_dvsor(除数)、s_cyo(进位)、s_ovo(溢
出位)连接到ALU 的输入acc_i(被除数)、ram_data_i(除数)、cy_i(进位)、ov_i
(溢出位);
2、 testbench 的输入s_qutnt(商)、s_rmndr(余数)、s_cyi(进位)、s_ovi(溢出位)
连接到ALU的输出result_a_o(商)、 result_b_o(余数)、new_cy_o(进位)、new_ov_o
(溢出位)。
3、 总之,testbench 驱动被测试单元,同时对被测试单元的输出进行验证。
4、assert (s_cyi((DWIDTH-1)/4) = '0')
and (s_ovi = '0')
and (s_qutnt = conv_std_logic_vector(v_quot,DWIDTH))
and (s_rmndr = conv_std_logic_vector(v_remd,DWIDTH))
report "ERROR in division!"
severity failure;
根据51 指令系统规定,除法运算的cy 位固定为0,如果除数为0则ov 置1,否则置0。
程序中
s_qutnt = conv_std_logic_vector(v_quot,DWIDTH)
s_rmndr = conv_std_logic_vector(v_remd,DWIDTH)
用来对运算结果进行比较。conv_std_logic_vector()是类型转换函数。
――首先是对库的引用
library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.std_logic_arith.all;
library work;
use work.mc8051_p.all;
library STD;
use STD.textio.all;
――定义结构体,testbench程序的结构体是空的。因为testbench是用来仿真的,不存在
--对外的接口,所以entity是空的。但是必须要有,这是语法的要求。
entity TBX_mc8051_alu is
end TBX_mc8051_alu;
-------------------------------------------------------------------------------
architecture TBX_ARCH_DIV of TBX_mc8051_alu is
――定义元件,映射后仿真和布局布线后仿真要使用SDF 文件,必须指定实例名。要实例
--化元件首先必须定义元件。
component mc8051_alu
port (
new_ov_o : out STD_LOGIC; ――新的ov位,输出
ov_i : in STD_LOGIC := 'X'; ――ov位,输入
new_cy_o : out STD_LOGIC_VECTOR ( 1 downto 0 ); ――新的cy位,输出
acc_i : in STD_LOGIC_VECTOR ( 7 downto 0 ); ――acc,输入
rom_data_i : in STD_LOGIC_VECTOR ( 7 downto 0 ); ――rom_data,输入
cmd_i : in STD_LOGIC_VECTOR ( 5 downto 0 ); ――命令,输入
ram_data_i : in STD_LOGIC_VECTOR ( 7 downto 0 ); ――ram_data,输入
cy_i : in STD_LOGIC_VECTOR ( 1 downto 0 ); ――cy,输入
result_b_o : out STD_LOGIC_VECTOR ( 7 downto 0 ); ――结果b,输出
result_a_o : out STD_LOGIC_VECTOR ( 7 downto 0 ) -―结果a,输出
);

1.激励的设置

相应于被测试模块的输入激励设置为reg型,输出相应设置为wire类型,双向端口inout在测试中需要进行处理。

方法1:为双向端口设置中间变量inout_reg作为该inout的输出寄存,inout口在testbench中要定义为wire型变量,然后用输出使能控制传输方向。

eg:

inout [0:0] bi_dir_port;

wire [0:0] bi_dir_port;

reg [0:0] bi_dir_port_reg;

reg bi_dir_port_oe;

assign bi_dir_port=bi_dir_port_oe?bi_dir_port_reg:1'bz;

用bi_dir_port_oe控制端口数据方向,并利用中间变量寄存器改变其值。等于两个模块之间用inout双向口互连。往端口写(就是往模块里面输入)

方法2:使用force和release语句,这种方法不能准确反映双向端口的信号变化,但这种方法可以反映块内信号的变化。具体如示:

module test();

wire data_inout;

reg data_reg;

reg link;

#xx; //延时

force data_inout=1'bx; //强制作为输入端口

...............

#xx;

release data_inout; //释放输入端口

endmodule

从文本文件中读取和写入向量

1)读取文本文件:用 $readmemb系统任务从文本文件中读取二进制向量(可以包含输入激励和输出期望值)。$readmemh
用于读取十六进制文件。例如:

reg [7:0] mem[1:256] // a 8-bit, 256-word
定义存储器mem

initial $readmemh ( "mem.data", mem ) // 将.dat文件读入寄存器mem中

initial $readmemh ( "mem.data", mem, 128, 1 ) // 参数为寄存器加载数据的地址始终

2)输出文本文件:打开输出文件用?$fopen 例如:

integer out_file; // out_file 是一个文件描述,需要定义为 integer类型

out_file = $fopen ( " cpu.data " ); // cpu.data 是需要打开的文件,也就是最终的输出文本

设计中的信号值可以通过$fmonitor, $fdisplay,

2. Verilog和Ncverilog命令使用库文件或库目录
ex). ncverilog -f run.f -v
lib/lib.v -y lib2 +libext+.v //一般编译文件在run.f中,
库文件在lib.v中,lib2目录中的.v文件系统自动搜索
使用库文件或库目录,只编译需要的模块而不必全部编译

3.Verilog Testbench信号记录的系统任务:

1). SHM数据库可以记录在设计仿真过程中信号的变化. 它只在probes有效的时间内记录你set probe
on的信号的变化.
ex). $shm_open("waves.shm");
//打开波形数据库
$shm_probe(top,
"AS"); // set probe on
"top",
第二个参数:
A -- signals of the specific scrope

S
-- Ports of the specified scope and below, excluding library
cells
C
-- Ports of the specified scope and below, including library
cells
AS
-- Signals of the specified scope and below, excluding library
cells
AC
-- Signals of the specified scope and below, including library
cells
还有一个
M ,表示当前scope的memories, 可以跟上面的结合使用, "AM" "AMS"
"AMC"
什么都不加表示当前scope的ports;
$shm_close
//关闭数据库
2). VCD数据库也可以记录在设计仿真过程中信号的变化.
它只记录你选择的信号的变化.
ex). $dumpfile("filename");
//打开数据库
$dumpvars(1,
top.u1); //scope = top.u1, depth =
1
第一个参数表示深度,
为0时记录所有深度;
第二个参数表示scope,省略时表当前的scope.
$dumpvars;
//depth = all scope =
all
$dumpvars(0);
//depth = all scope =
current
$dumpvars(1,
top.u1); //depth = 1 scope =
top.u1
$dumpoff
//暂停记录数据改变,信号变化不写入库文件中
$dumpon
//重新恢复记录
3). Debussy
fsdb数据库也可以记录信号的变化,它的优势是可以跟debussy结合,方便调试.
如果要在ncverilog仿真时,记录信号,
首先要设置debussy:
a. setenv LD_LIBRARY_PATH
:$LD_LIBRARY_PATH
(path for
debpli.so file
(/share/PLI/nc_xl//nc_loadpli1))
b. while
invoking ncverilog use the +ncloadpli1
option.
ncverilog -f
run.f +debug
+ncloadpli1=debpli:deb_PLIPtr
fsdb数据库文件的记录方法,是使用$fsdbDumpfile和$fsdbDumpvars系统函数,使用方法参见VCD
注意:
在用ncverilog的时候,为了正确地记录波形,要使用参数: "+access+rw", 否则没有读写权限

在记录信号或者波形时需要指出被记录信号的路径,如:tb.module.u1.clk.

………………………………………………………………………………………………………

关于信号记录的系统任务的说明:

在testbench中使用信号记录的系统任务,就可以将自己需要的部分的结果以及波形文件记录下来(可采用sigalscan工具查看),适用于对较大的系统进行仿真,速度快,优于全局仿真。使用简单,在testbench中添加:initial
begin

$shm_open("waves.shm");

$shm_probe("要记录信号的路径“,”AS“);

#10000

$shm_close; 即可。

4. ncverilog编译的顺序: ncverilog file1 file2
....
有时候这些文件存在依存关系,如在file2中要用到在file1中定义的变量,这时候就要注意其编译的顺序是
从后到前,就先编译file2然后才是file2.

5.
信号的强制赋值force
首先, force语句只能在过程语句中出现,即要在initial 或者 always 中间. 去除force
用 release 语句.
initial begin
force sig1 = 1'b1; ... ; release sig1;
end
force可以对wire赋值,这时整个net都被赋值; 也可以对reg赋值.

6.加载测试向量时,避免在时钟的上下沿变化

为了模拟真实器件的行为,加载测试向量时,避免在时钟的上下沿变化,而是在时钟的上升沿延时一个时间单位后,加载的测试向量发生变化。如:

assign #5 c=a^b

……

@(posedge clk) #(0.1*`cycle) A=1;

******************************************************************************

//testbench的波形输出

module top;

...

initial

begin

$dumpfile("./top.vcd");
//存储波形的文件名和路径,一般是.vcd格式.

$dumpvars(1,top);
//存储top这一层的所有信号数据

$dumpvars(2,top.u1);
//存储top.u1之下两层的所有数据信号(包含top.u1这一层)

$dumpvars(3,top.u2);
//存储top.u2之下三层的所有数据信号(包含top.u2这一层)

$dumpvars(0,top.u3);
//存储top.u3之下所有层的所有数据信号

end

endmodule

//产生随机数,seed是种子

$random(seed);

ex: din <= $random(20);

//仿真时间,为unsigned型的64位数据

$time

ex:

...

time condition_happen_time;

...

condition_happen_time = $time;

...

$monitor($time,"data utput = %d", dout);

...

//参数

parameter para1 = 10,

para2 = 20,

para3 = 30;

//显示任务

$display();

//监视任务

$monitor();

//延迟模型

specify

...

//describ pin-to-pin delay

endspecify

ex:

module nand_or(Y,A,B,C);

input A,B,C;

output Y;

AND2 #0.2 (N,A,B);

OR2 #0.1 (Y,C,N);

specify

(A*->Y) = 0.2;

(B*->Y) = 0.3;

(C*->Y) = 0.1;

endspecify

endmodule

//时间刻度

`timescale 单位时间/时间精确度

//文件I/O

1.打开文件

integer file_id;

file_id = fopen("file_path/file_name");

2.写入文件

//$fmonitor只要有变化就一直记录

$fmonitor(file_id, "%format_char", parameter);

eg:$fmonitor(file_id, "%m: %t in1=%d o1=%h", $time, in1, o1);

//$fwrite需要触发条件才记录

$fwrite(file_id, "%format_char", parameter);

//$fdisplay需要触发条件才记录

$fdisplay(file_id, "%format_char", parameter);

$fstrobe();

3.读取文件

integer file_id;

file_id = $fread("file_path/file_name", "r");

4.关闭文件

$fclose(fjile_id);

5.由文件设定存储器初值

$readmemh("file_name", memory_name"); //初始化数据为十六进制

$readmemb("file_name", memory_name"); //初始化数据为二进制

//仿真控制

$finish(parameter); //parameter = 0,1,2

$stop(parameter);

//读入SDF文件

$sdf_annotate("sdf_file_name", module_instance, "scale_factors");

//module_instance: sdf文件所对应的instance名.

//scale_factors:针对timming delay中的最小延时min,典型延迟typ,最大延时max调整延迟参数

//generate语句,在Verilog-2001中定义.用于表达重复性动作

//必须事先声明genvar类型变量作为generate循环的指标

eg:

genvar i;

generate for(i = 0; i < 4; i = i + 1)

begin

assign = din[i] = i % 2;

end

endgenerate

//资源共享

always @(A or B or C or D)

sum = sel ? (A+B):(C+D);

//上面例子使用两个加法器和一个MUX,面积大

//下面例子使用一个加法器和两个MUX,面积小

always @(A or B or C or D)

begin

tmp1 = sel ? A:C;

tmp2 = sel ? B:D;

end

always @(tmp1 or tmp2)

sum = tmp1 + tmp2;

******************************************************************************

模板:

module testbench; //定义一个没有输入输出的module

reg ……
//将DUT的输入定义为reg类型

……

wire……
//将DUT的输出定义为wire类型

……

//在这里例化DUT

initial

begin

……
//在这里添加激励(可以有多个这样的结构)

end

always……
//通常在这里定义时钟信号

initial

//在这里添加比较语句(可选)

end

initial

//在这里添加输出语句(在屏幕上显示仿真结果)

end

endmodule

一下介绍一些书写Testbench的技巧:

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

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

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

4.每个testbench都最好包含$stop语句,用以指明仿真何时结束。

最后提供一个简单的示例(转自Xilinx文档):

DUT:

module shift_reg (clock, reset, load, sel, data, shiftreg);

input clock;

input reset;

input load;

input [1:0] sel;

input [4:0] data;

output [4:0] shiftreg;

reg [4:0] shiftreg;

always @ (posedge clock)

begin

if (reset)

shiftreg = 0;

else if (load)

shiftreg = data;

else

case (sel)

2’b00 : shiftreg = shiftreg;

2’b01 : shiftreg = shiftreg << 1;

2’b10 : shiftreg = shiftreg >> 1;

default : shiftreg = shiftreg;

endcase

end

endmodule

Testbench:

module testbench; // declare testbench name

reg clock;

reg load;

reg reset; // declaration of signals

wire [4:0] shiftreg;

reg [4:0] data;

reg [1:0] sel;

// instantiation of the shift_reg design below

shift_reg dut(.clock (clock),

.load
(load),

.reset
(reset),

.shiftreg
(shiftreg),

.data
(data),

.sel
(sel));

//this process block sets up the free running clock

initial begin

clock = 0;

forever #50 clock = ~clock;

end

initial begin// this process block specifies the stimulus.

reset = 1;

data = 5’b00000;

load = 0;

sel = 2’b00;

#200

reset = 0;

load = 1;

#200

data = 5’b00001;

#100

sel = 2’b01;

load = 0;

#200

sel = 2’b10;

#1000 $stop;

end

initial begin// this process block pipes the ASCII results to the

//terminal or text editor

$timeformat(-9,1,"ns",12);

$display(" Time Clk Rst Ld SftRg Data Sel");

$monitor("%t %b %b %b %b %b %b", $realtime,

clock,
reset, load, shiftreg, data, sel);

end

endmodule


如何编写testbench的总结
方法1:为双向端口设置中间变量inout_reg作为该inout的输出寄存,inout口在testbench中要定义为wire型变量,然后用输出使能控制传输方向。eg:inout [0:0] bi_dir_port;wire [0:0] bi_dir_port;reg [0:0] bi_dir_port_reg;reg bi_dir_port_oe;assign bi_dir_port=bi_dir_port_oe?bi_...

如何编写testbench的总结
Testbench 不仅要产生激励也就是输入,还要验证响应也就是输出。当然也可以只产生 激励,然后通过波形窗口通过人工的方法去验证波形,这种方法只能适用于小规模的设计。在ISE 环境中,当前资源操作窗显示了资源管理窗口中选中的资源文件能进行的相关操 作。在资源管理窗口选中了testbench 文件后,在当前资源...

如何编写testbench的总结
\/\/通常在这里定义时钟信号 initial \/\/在这里添加比较语句(可选) end initial \/\/在这里添加输出语句(在屏幕上显示仿真结果) end endmodule 一下介绍一些书写 Testbench 的技巧: 1.如果激励中有一些重复的项目,可以考虑将这些语句编写成一个 task,这样会给书写和仿 真带来很大方便。例如,一个存储器的 testbench ...

如何编写 test bench来仿真VHDL程序
通常testbench完成如下的任务:1. 实例化需要测试的设计(DUT);2. 通过对DUT模型加载测试向量来仿真设计;3. 将输出结果到终端或波形窗口中加以视觉检视;4. 另外,将实际结果和预期结果进行比较。 一、构建Testbench 本文用VHDL来写,由于testbench只用来进行仿真,它们没有那些适用于综合的RTL语言...

怎样编写一简单的批处理文件test.bat并执行
这个确实是简单的批处理 命令都提供给你了 你新建一个记事本 输入:cd\\ dir date \/t time \/t 然后另存为text.bat保存类型选择所有文件即可。ps:你如果想看见结果最好在后面加上 pause

使用quartus时,仿真时编写的testbench文件要在哪里新建?
写在同一个project的文件夹里,如果是VHDL,那就写一个.VHD文件就行,然后再加入你的project里。编译时直接编译,不用把testbench置顶,如果置顶,会编译出错。

FPGA中能用Verilog编写个testbench去测试一个原理图文件吗?
当然可以 你的这个大模块 也只是一个模块而已 在tesetbench 中调用就可以

使用mysql编写一个名为test的数据库
create database test;drop table if exists users;create table users(name varchar(20),email varchar(20),telephone varchar(20));insert into users(name,email,telephone) valuse('tom','tom@sina.com','123456789');

2.编写一个 Java 应用程序 Test 类,实现成员方法max(a,b)的重载。具体...
以下是一个 Java 应用程序 Test 类,实现了 max 方法的重载:public class Test { \/\/ 重载方法 max,用于比较两个整数并返回较大值 public int max(int a, int b) { return (a > b) ? a : b;} \/\/ 重载方法 max,用于比较两个双精度浮点数并返回较大值 public double max(double a,...

一段用verilog编写的testbench程序,不知道有什么错误。
删除initial块内部以下内容:100;forever 50 clk=~clk;在initial块外部(注意是外部,不是内部)添加以下内容:always #50 clk= ~clk;另外,initial内部的“rst_n = 1; ”也要改成以下形式:rst_n=1'b0;3 rst_n=1'b1;以便对电路进行复位。

江油市19352346689: 如何编写testbench的总结 -
岛邦佐米: 然后用输出使能控制传输方向,这种方法不能准确反映双向端口的信号变化;延时 force data_inout=1',但这种方法可以反映块内信号的变化:使用force和relea**语句;/.等于两个模块之间用inout双向口互连;bz:0] bi_dir_port.eg,并利用中...

江油市19352346689: 如何编写 test bench来仿真VHDL程序 -
岛邦佐米: 本文介绍如何写testbench来仿真VHDL程序. 通常testbench完成如下的任务:1. 实例化需要测试的设计(DUT);2. 通过对DUT模型加载测试向量来仿真设计;3. 将输出结果到终端或波形窗口中加以视觉检视;4. 另外,将实际结果和...

江油市19352346689: 怎样编写verilog 测试语句 -
岛邦佐米: Test bench大致能分成三个部分.第一部分是时钟控制,用alway 语句实现.第二部分就是实例化要测试的module第三部分就是对实例的输入赋值资料可以看看 A Verilog HDL Test Bench Primer ,网上可以找到.

江油市19352346689: 怎样写testbench -
岛邦佐米: module counter_tb; reg [7:0] data; reg load; reg clk; reg reset; wire [7:0] out; counter U_counter( .out(out), .data(data), .load(load), .reset(reset), .clk(clk) ); initial begin data =7'b0; load =1'b0; clk = 1'b0; reset = 1'b1; #1 reset=1'b0; #1 reset=1'b1; #...

江油市19352346689: 基于verilog的QPSK调制解调系统,书上代码有了 就是不知道如何进行编写testbench 还请大虾劳驾了 -
岛邦佐米: QPSK调制程序的testbench程序如下:******************************************************************************** `timescale 1ns/1ns //单位时间,时间精度 module qpsk_tb; //qpsk调制的testbench reg clk; reg rst; reg x; wire y; qpsk qpsk(.clk(clk),.rst(rst),....

江油市19352346689: 编写test bench,怎么样设计测试向量 -
岛邦佐米: 给出时间基准,然后建立或者实例化一个实例,针对输入输出端口给予激励信号和敏感单元,查看中间变量和输出.或者直接将实例写进主程序module中,然后再描述敏感单元和触发信号的变化.注意一切以并行理念和时间顺序为准.

江油市19352346689: testbench 需要编译吗 -
岛邦佐米: Testbench学习笔记(一) 书写testbench是数字电路设计中不可或缺的一项设计方法,主要是提供的是激励.尽管现在各种开发工具都通过绘制波形图的方法生成测试激励,测试书写的代码,但是其不可移植性,不可通用性,还有有些功能无法...

江油市19352346689: verilog inout信号testbench写法 -
岛邦佐米: 当oe=0时,inout类型的data在这个模块是作为输入的啊,本来就不能赋值,也不需要赋值(使用的输入值).作为输入时,应该是和这个模块连接的另一个模块中进行赋值,那个模块中的输出是这个模块的输入(那个模块的输出还是reg的).

江油市19352346689: ds1302的testbench怎么写 -
岛邦佐米: 标志位可以在testbench中写,你自己添加的reg flag,在初始化中要赋值,否则就是x或者z; 例如: initial begin flag = 1'b0; end

江油市19352346689: 我在使用Verilog - a仿真,现在已经写好一个模块的Verilog - a,该如何写一个testbench -
岛邦佐米: 模块,其实就是个延长网线,方便操作的作用,如果模块是A接法,交换机也用A接法, 其实通用的是B接法, 实际当中,所以的网线接口,包括模块里的线序和水晶头的都一样就可以了,要么全A,要么全B.

本站内容来自于网友发表,不代表本站立场,仅表示其个人看法,不对其真实性、正确性、有效性作任何的担保
相关事宜请发邮件给我们
© 星空见康网