verilog,testbench
编写高效率的testbench
编写高效率的testbench简介:由于设计的规模越来越大也越来越复杂,数字设计的验证已经成为一个日益困难和繁琐的任务。
验证工程师们依靠一些验证工具和方法来应付这个挑战。
对于几百万门的大型设计,工程师们一般使用一套形式验证(formal verification)工具。
然而对于一些小型的设计,设计工程师常常发现用带有testbench的HDL仿真器就可以很好地进行验证。
Testbench已经成为一个验证高级语言(HLL --High-Level Language) 设计的标准方法。
通常testbench完成如下的任务:1.实例化需要测试的设计(DUT);2.通过对DUT模型加载测试向量来仿真设计;3.将输出结果到终端或波形窗口中加以视觉检视;4.另外,将实际结果和预期结果进行比较。
通常testbench用工业标准的VHDL或Verilog硬件描述语言来编写。
Testbench调用功能设计,然后进行仿真。
复杂的testbench完成一些附加的功能—例如它们包含一些逻辑来选择产生合适的设计激励或比较实际结果和预期结果。
后续的章节描述了一个仔细构建的testbench的结构,并且提供了一个自动比较实际结果与预期结果的进行自我检查的testbench例子。
图1给出了一个如上所描述步骤的标准HDL验证流程。
由于testbench使用VHDL或Verilog来描述,testbench的验证过程可以根据不同的平台或不同的软件工具实现。
由于VHDL或Verilog是公开的通用标准,使用VHDL或Verilog编写的testbench以后也可以毫无困难地重用(reuse)。
图1使用Testbench的HDL验证流程构建TestbenchTestbench用VHDL或Verilog来编写。
由于testbench只用来进行仿真,它们没有那些适用于综合的RTL语言子集的语法约束限制,而是所有的行为结构都可以使用。
因而testbench可以编写的更为通用,使得它们可以更容易维护。
verilogtestbench写法
Verilog测试平台(testbench)技术(一) 收藏对设计进行功能仿真和时序仿真时,需要给待测模块提供激励输入。
对于由V erilog语言描述的设计模块,最好的方法自然同样是用Verilog语言对待测模块施加激励和检测模块的输出响应。
实际应用中,Verilog测试平台(testbench)就是用来提供上述功能的。
Verilog测试平台是一个例化的待测(MUT)Verilog模块,给它施加激励并观测其输出。
由于测试平台是用Verilog语言描述的,因此可以应用到不同的仿真环境中。
待测模块和与之对应的测试平台组成一个仿真模型,应用这个模型可以在不同的测试环境中用相同的激励对待测模块进行调试。
下面就对不同电路类型分别介绍verilog测试平台的语言结构。
一、测试平台1.组合电路测试设计组合电路的测试平台时,待测模块及其功能决定了激烈的选择与测试次数。
对于一个已有的待测模块,测试平台中需要声明与待测模块输入输出端口对应的变量。
与输入端口相连接的变量定义为reg,与输出端口相连接的变量定义为wire,例化时将测试平台中声明的变量与待测模块的输入输出端口相关联。
使用initial语句控制程序运行,initial语句是一种过程结构,在initial块中可使用延迟控制语句来控制initial块中的程序流动。
这里对一个简单的算术逻辑单元(ALU)为例进行测试,下面是该单元Verilog 描述。
/***************************************************************** ********///多动能ALU的Verilog代码'timescale 1ns/100psmodule alu_4bit(a,b,f,oe,y,p,ov,a_gt_b,a_eg_b,a_lt_b);input [3:0] a,b;input [1:0] f;input oe;input [3:0] y;output p,ov,a_gt_b,a_eg_b,a_lt_b; reg [4:0] im_y;always @(a or b or f)beginov=1'b0;im_y=0;case(f)2'b00:beginim_y=a+b;if(im_y>5'b01111)ov=1'b1;end2'b01:beginim_y=a-b;if(im_y>5'b01111)ov=1'b1;end2'b10:im_y[3:0]=a&b;2'b11:im_y[3:0]=a^b;default:im_y[3:0]=4'b0000;endcaseendalways @(a or b)beginif(a>b){a_gt_b,a_ge_b,a_lt_b}=3'b100;else if(a<b){a_gt_b,a_ge_b,a_lt_b}=3'b001;else{a_gt_b,a_ge_b,a_lt_b}=3'b010;endassign p=^im_y[3:0];assign y=oe?im_y[3:0]:4'bz;endmodule/***************************************************************** ********/模块alu_4bit是四功能的算术逻辑单元,输入包括数据信号a、b和功能信号f,输出包括数据信号y和ALU生成的奇偶校验信号p、溢出信号ov及比较信号。
systemverilogfortestbench
SystemVerilog for Testbench1、并发性和控制(Concurrency and Control)并发(Concurrency)可以允许你从一个父进程中同时运行多个并行的进程。
它给你的需要执行并行的验证环境带来更多的主动性和灵活性。
一个典型的例子是,给设计加激励,之后检查并行的结果。
这使你的tb能及时果断地作出反应,以便修改激励(甚至在模拟完也可)。
用fork-join结构来实现并发(Concurrency)。
父进程的join-back依赖于并行进程是否完成。
Mailbox:对于进程内部的通信,一种叫做mailbox的结构允许任何进程将消息发送到其他的任何进程。
接受的进程也能够使用wait命令和发送的进程来同步。
Semaphores:信号量(semaphores)是为了防止一个资源被许多个并行的进程争抢的情况。
比如在一个信号在任何时刻只能有一个进程执行它。
Events:进程中的事件(events)用 -> 操作符来触发。
这些被触发的事件被其他的进程用事件控制结构来接受,为的是使得触发进程同步。
2、带约束的随机激励(Random Stimulus Generation with Constraints)验证的过程是要证明你的设计是全面测试过的。
随机激励确保测试角落情形的到达和测试。
这是一个重要的组成部分,以确保验证的时间和精力是最有效的方式进行的。
SystemVerilog提供一个非常强有力的机制来产生随机刺激。
它是基于类的对象(class-object)随机化,这意味着一个类的对象随机变量自动通过调用预定义的随机方法与对象相关联。
约束(Constraints)进一步增强随机化的功能。
他们有两个主要优点:(1)您可以添加任意权重的刺激,使某些激励信号比其他的信号更频繁地产生,也就是你可以设置一个激励产生的分布函数,(2)您可以使用现有的设计来改变这种状态权重,从而为下一个状态做限制。
verilog testbench语法
verilog testbench语法Verilog testbench 是用来对 Verilog 设计进行仿真验证的代码。
它提供了一系列的输入信号和时钟,以及对输出结果的预期值进行比较,以验证设计的正确性。
以下是 Verilog testbench 的基本语法:1. 模块定义:```module testbench_name;// 输入输出信号声明// 实例化需要测试的模块// 给输入信号赋值// 检查输出信号和预期结果是否相符endmodule```2. 时钟定义:```reg clk; // 定义时钟信号always #5 clk = ~clk; // 定义时钟周期```3. 输入信号声明和赋值:```reg input1;wire expected_output;reg [3:0] array_input [7:0];// 给输入信号赋值initial begininput1 = 1'b0;#10;input1 = 1'b1;#10;//...end```4. 实例化需要测试的模块:```// 通过实例化需要测试的模块// 给模块的输入端口连接输入信号// 给模块的输出端口连接输出信号// 在 testbench 中实例化被测试的模块//...```5. 检查输出信号和预期结果:```// 在仿真过程中,通过比较输出信号和预期结果来验证设计的正确性// 根据需要使用相应的比较语句,如 `==`, `!=`, `===`, `!==`, `>`, `<` 等// 在每个时钟周期末检查预期输出结果//...```这些是 Verilog testbench 的基本语法。
在具体的测试中,需要根据设计的功能和需求来给输入信号赋值,并检查输出信号和预期结果是否一致。
(总)基于Verilog的4位计数器源程序与testbench测试程序
1、简单4位计数器程序:module count4(clk,cnt);input clk;output reg[3:0]cnt=4'b0;always @(posedge clk)begincnt<=cnt+1;endendmodule测试程序:`timescale 1 ns/10 psmodule test_count4();reg clk=0;wire [3:0]cnt;count4 i1(.clk(clk),.cnt(cnt));always #10 clk=~clk;initialbegin$monitor($time,,,"clk=%d cnt=%d",clk,cnt); #400 $stop;endendmodule仿真波形:2、异步清零4位计数器源程序module count4_reset(clk,rst,cnt);input clk,rst;output reg[3:0]cnt=4'b0;always @(posedge clk or negedge rst)beginif(!rst) cnt<=4'b0;else cnt<=cnt+1;endendmodule测试程序`timescale 1 ns/10 psmodule test_count4_reset();reg clk=0;reg rst;wire [3:0]cnt;count4_reset i1(.clk(clk),.rst(rst),.cnt(cnt));always #10 clk=~clk;initialbeginrst=0;#20 rst=1;#45 rst=0;#10 rst=1;endinitialbegin$monitor($time,,,"clk=%d rst=%d cnt=%d",clk,rst,cnt);#800 $stop;endendmodule仿真波形3、异步清零、计数使能控制的4位计数器module count4_rst_en(clk,rst,en,cnt);input clk,rst,en;output [3:0]cnt;reg [3:0]cnt;always @(posedge clk or negedge rst)beginif(!rst) cnt<=0;else if(en==1) cnt<=cnt+1;endendmodule测试程序`timescale 1 ns/10 psmodule test_count4_rst_en();reg clk=0;reg rst,en;wire [3:0]cnt;count4_rst_en i1(.clk(clk),.rst(rst),.en(en),.cnt(cnt));always #10 clk=~clk;initialbeginrst=0;en=0;#15 en=1;#20 rst=1;#20 en=0;#20 en=1;rst=0;#20 rst=1;endinitialbegin$monitor($time,,,"clk=%d rst=%d en=%d cnt=%d",clk,rst,en,cnt);#800 $stop;endendmodule仿真波形:4、异步清零、计数使能、数据加载控制功能的4位计数器:module count4_rst_en_load(clk,rst,en,load,data,cnt);input clk,rst,en,load;input [3:0]data;output reg[3:0]cnt;always @(posedge clk or negedge rst)beginif(!rst) cnt<=0;else if(en==1)beginif(load) cnt<=data;else cnt<=cnt+1;endendendmodule测试程序:`timescale 1 ns/10 psmodule test_count4_rst_en_load();reg clk=0;reg rst,en,load;reg [3:0]data;wire [3:0]cnt;count4_rst_en_load i1(.clk(clk),.rst(rst),.en(en),.load(load),.data(data),.cnt(cnt));always #10 clk=~clk;initialbeginrst=0;en=0;load=0;data=4'd6;#20 en=1;#20 rst=1;#20 load=1;#20 rst=0;#20 rst=1;#20 load=0;endinitialbegin$monitor($time,,,"clk=%d rst=%d en=%d load=%d cnt=%d",clk,rst,en,load,data,cnt);#800 $stop;endendmodule仿真波形:。
如何编写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;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 定义存储器meminitial $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 scropeS -- Ports of the specified scope and below, excluding library cellsC -- Ports of the specified scope and below, including library cellsAS -- Signals of the specified scope and below, excluding library cellsAC -- 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_PLIPtrfsdb数据库⽂件的记录⽅法,是使⽤$fsdbDumpfile和$fsdbDumpvars系统函数,使⽤⽅法参见VCD注意: 在⽤ncverilog的时候,为了正确地记录波形,要使⽤参数: "+access+rw", 否则没有读写权限在记录信号或者波形时需要指出被记录信号的路径,如:tb.module.u1.clk.………………………………………………………………………………………………………关于信号记录的系统任务的说明:在testbench中使⽤信号记录的系统任务,就可以将⾃⼰需要的部分的结果以及波形⽂件记录下来(可采⽤sigalscan⼯具查看),适⽤于对较⼤的系统进⾏仿真,速度快,优于全局仿真。
Verilog仿真文件testbench编写样例
Verilog 仿真文件testbench编写样例`timescale 1ns/100psmodule testbench;localparam DATA_WIDTH = 32;localparam CLK_100_PERIOD = 5;localparam CLK_200_PERIOD = 2.5;localparam SIM_TIME = 150000;localparam ;localparam ;reg clk_100, clk_200;wire clk;assign clk = clk_100;alwaysbeginclk_100 = 0;forever #CLK_100_PERIOD clk_100 = ~clk_100;endalwaysbeginclk_200 = 0;forever #CLK_200_PERIOD clk_200 = ~clk_200;endreg rstn;integer fp_testin;integer fp_matlab_out;integer fp_sim_out;integer fp_outdiff;reg signed [DATA_WIDTH/2-1:0] matlab_in_re, matlab_in_im;reg signed [DATA_WIDTH/2-1:0] matlab_out_re, matlab_out_im;reg signed [DATA_WIDTH/2-1:0] matlab_diff_re, matlab_diff_im;reg signed [DATA_WIDTH/2-1:0] matlab_diff_re2, matlab_diff_im2;reg signed [DATA_WIDTH/2-1:0] max_diff_re, max_diff_im;initial beginmax_diff_re = 0;max_diff_im = 0;rstn = 0;#500rstn = 1;#SIM_TIMEsim_finish();$stop();endtask sim_finish;beginif(fp_testin!=0)$fclose(fp_testin);if(fp_matlab_out!=0)$fclose(fp_matlab_out);if(fp_sim_out)$fclose(fp_sim_out);if(fp_outdiff!=0)$fclose(fp_outdiff);endendtaskinitialbeginfp_testin = 0;fp_testin=$fopen("txt_file/input_data.txt"," r");if(fp_testin==0)begin$display("input_data.txt open failed!"); sim_finish();$stop();endelse begin$fscanf(fp_testin,"%d, %d\n",matlab_in_re,matlab_in_im); endfp_matlab_out = 0;fp_matlab_out =$fopen("txt_file/matlab_out.txt"," r");if(fp_matlab_out==0)begin$display("fp_matlab_out.txt openfailed!");sim_finish();$stop();endelse begin$fscanf(fp_matlab_out,"%d, %d\n",matlab _out_re,matlab_out_im);endfp_sim_out = 0;fp_sim_out =$fopen("txt_file/modelsim_out.txt",&quo t;w");if(fp_sim_out == 0)begin$display("modelsim_out_re.txt openfailed!");sim_finish();$stop();endfp_outdiff = 0;fp_outdiff =$fopen("text_file/outdiff.txt","w& quot;);if(fp_outdiff==0)begin$display("outdiff.txt open failed!"); sim_finish();$stop();endendalways @(posedge clk)beginif(stest_wvalid && stest_wready) //ready to changebeginif(~$feof(fp_testin))$fscanf(fp_testin,"%d, %d\n",matlab_in_re,matlab_in_im); endelsebeginmatlab_in_re <= matlab_in_re;matlab_in_im <= matlab_in_im;endendalways @(posedge clk_100)beginif(mfc_wready && mfc_wvalid)beginmatlab_diff_re <= mfc_wdata_re - matlab_out_re; matlab_diff_im <= mfc_wdata_im - matlab_out_im; matlab_diff_re2 <= matlab_out_re - mfc_wdata_re ; matlab_diff_im2 <= matlab_out_im - mfc_wdata_im ; if(max_diff_re < matlab_diff_re)beginmax_diff_re <= matlab_diff_re;$display("max_diff_re:%dmax_diff_im:%d\n",max_diff_re,max_diff_im); endelse if(max_diff_re < matlab_diff_re2)beginmax_diff_re <= matlab_diff_re2;$display("max_diff_re:%dmax_diff_im:%d\n",max_diff_re,max_diff_im); endif(max_diff_im < matlab_diff_im)beginmax_diff_im <= matlab_diff_im;$display("max_diff_re:%dmax_diff_im:%d\n",max_diff_re,max_diff_im); endelse if(max_diff_im < matlab_diff_im2)beginmax_diff_im <= matlab_diff_im2;$display("max_diff_re:%dmax_diff_im:%d\n",max_diff_re,max_diff_im); end$fscanf(fp_matlab_out,"%d, %d\n",matlab _out_re,matlab_out_im);$fwrite(fp_sim_out, "%d, %d\n",mfc_wdata_re,mfc_wdata_im);$fwrite(fp_outdiff,"%d, %d\n",matlab_diff_re,matlab_diff_i m);endendendmodule。
Verilog中inout类型的数据的使用和testbench仿真写法
Verilog inout 双向口使用和仿真芯片外部引脚很多都使用inout类型的,为的是节省管腿。
一般信号线用做总线等双向数据传输的时候就要用到INOUT类型了。
就是一个端口同时做输入和输出。
inout在具体实现上一般用三态门来实现。
三态门的第三个状态就是高阻' Z'。
当inout端口不输出时,将三态门置高阻。
这样信号就不会因为两端同时输出而出错了,更详细的内容可以搜索一下三态门tri-state的资料.1 使用inout类型数据,可以用如下写法:inout data_inout;input data_in;reg data_reg;//data_inout的映象寄存器reg link_data;assign data_inout=link_data?data_reg:1’bz;//link_data控制三态门//对于data_reg,可以通过组合逻辑或者时序逻辑根据data_in对其赋值.通过控制link_data的高低电平,从而设置data_inout是输出数据还是处于高阻态,如果处于高阻态,则此时当作输入端口使用.link_data可以通过相关电路来控制.2 编写测试模块时,对于inout类型的端口,需要定义成wire类型变量,而其它输入端口都定义成reg类型,这两者是有区别的.当上面例子中的data_inout用作输入时,需要赋值给data_inout,其余情况可以断开.此时可以用assign语句实现:assign data_inout=link?data_in_t:1’bz;其中的link ,data_in_t是reg类型变量,在测试模块中赋值.另外,可以设置一个输出端口观察data_inout用作输出的情况:Wire data_out;Assign data_out_t=(!link)?data_inout:1’bz;else,in RTLinout use in top module(PAD)dont use inout(tri) in sub module也就是说,在内部模块最好不要出现inout,如果确实需要,那么用两个port实现,到顶层的时候再用三态实现。
verilog testbench数学函数
深度评估和探讨Verilog Testbench中的数学函数在Verilog中,Testbench是用于验证电路设计的一种非常重要的方法。
它可以用于评估电路的功能,并进行仿真和验证。
在Testbench 中,数学函数的使用非常普遍,这些函数可以帮助我们模拟各种电路功能和行为。
在本篇文章中,我将深度评估和探讨在Verilog Testbench中数学函数的使用,以帮助你更深入地理解这一主题。
1. 介绍在Verilog Testbench中,数学函数的使用非常广泛。
这些函数包括但不限于求幂、求余、开方、三角函数等等。
它们可以帮助我们进行各种复杂电路的仿真和验证。
2. 求幂函数在Verilog Testbench中,使用求幂函数可以帮助我们模拟电路中的幂运算。
这个函数的使用非常简单,例如:```verilogoutput = $pow(a, b);```这行代码表示将a的b次幂赋值给output。
利用这个功能,我们可以轻松地验证电路中的幂运算功能。
3. 求余函数另一个常见的数学函数是求余函数。
在电路设计中,模运算是非常普遍的,使用求余函数可以帮助我们验证这部分功能。
例如:```verilogoutput = $mod(a, b);```这行代码表示将a除以b的余数赋值给output。
通过这种方式,我们可以验证电路中模运算的准确性。
4. 开方函数Verilog Testbench还提供了开方函数,通过这个函数我们可以验证电路中的开方运算功能。
例如:```verilogoutput = $sqrt(a);```这行代码表示将a的开方值赋值给output。
这个函数可以帮助我们验证电路中的开方运算是否准确。
5. 三角函数除了上述的基本数学函数外,Verilog Testbench还提供了各种三角函数,包括正弦、余弦、正切等。
通过这些函数,我们可以验证电路中的三角函数运算。
例如:```verilogoutput = $sin(a);```这行代码表示将a的正弦值赋值给output。
vivadotestbench写法
主题:vivadotestbench编写方法内容:1. 什么是vivadotestbench?vivadotestbench是一个用于编写Verilog的测试台,用于对Verilog 模块进行仿真和验证。
它可以帮助工程师们在Verilog设计的早期阶段进行功能验证和性能评估,以确保设计的稳定性和正确性。
2. vivadotestbench的基本结构vivadotestbench通常包含以下基本结构:模块实例化、时钟和复位初始化、输入数据生成、仿真控制和输出检测。
这些基本结构构成了一个完整的测试台,可以用于对Verilog模块进行全面的验证和测试。
3. vivadotestbench的编写步骤编写vivadotestbench的步骤可以分为以下几个部分:3.1 模块实例化:首先需要实例化待测模块,并且连接时钟、复位信号和输入输出端口。
3.2 时钟和复位初始化:在测试台中需要为待测模块提供时钟信号,并对复位信号进行初始化。
3.3 输入数据生成:根据待测模块的输入端口,生成相应的测试数据,并将其输入到待测模块中。
3.4 仿真控制:控制仿真的开始、暂停和结束,以及执行仿真的时长和步长等。
3.5 输出检测:对待测模块的输出进行检测和比对,以验证其正确性和稳定性。
4. vivadotestbench的常见问题及解决方法在编写vivadotestbench的过程中,可能会遇到一些常见的问题,例如时序约束不准确、测试数据生成不完整、输出检测逻辑错误等。
针对这些问题,可以采取一些解决方法,如优化时序约束、增加测试数据生成的覆盖率、修正输出检测逻辑等。
5. vivadotestbench的优点和应用场景vivadotestbench具有易用性好、灵活性强、功能全面等优点,适用于对Verilog模块进行全面的仿真和验证。
它可以帮助工程师们提高设计的稳定性和正确性,加快设计的上线速度,降低设计的风险和成本。
结论:vivadotestbench是一个强大的Verilog测试台,可以帮助工程师们在Verilog设计的早期阶段进行全面的功能验证和性能评估。
(verilog和vhdl)Testbench编程指南
(verilog和vhdl)Testbench编程指南TestBench编程指南如今数字设计的规模变得越来越庞大,设计的复杂程度也越来越高,这就使得设计的验证变得越来越困难,而且费时费力。
为了应对这种挑战,验证工程师依靠各种验证工具和方法。
对于大型设计,如几百万门的设计,通常采用一整套正式的验证工具。
然而,对于小一些的设计,设计工程师发现往往采用带TestBench的HDL仿真工具是最好的途径。
TestBench已经变成验证高级语言设计的一种标准的方法。
通常,TestBench执行以下任务:z例化设计,使其可测试(DUT-design under test);z通过将测试向量应用到模型来仿真例化后的可测试的设计;z将结果输出到终端,或者输出波形窗口;z将真实的结果和期望的结果进行比较;一般,TestBench采用工业标准的VHDL或者Verilog硬件描述语言来编写。
TestBench调用功能设计,然后仿真。
复杂的测试文件执行附加功能――例如,他们包含逻辑以决定合适的设计激励或者比较真实的结果和期望的结果。
以下章节将讨论一个组织良好的测试文件的组成,以及例举了一个带有自检的测试文件(自动将真实的结果和预期的结果进行比较)。
下图是一个标准的HDL验证的流程。
自从测试文件可以用VHDL或者Verilog编写以来,测试验证流程就可以在平台和供应商的工具交叉进行。
同时,由于VHDL和Verilog都是标准的公用的语言,所以用VHDL或者是Verilog描述的验证可以很简单的被再使用。
图1. HDL验证流程测试文件构成:测试文件可以采用VHDL或者Verilog语言编写。
由于测试文件只是用来仿真的,他们就不被用于综合的RTL语言子集的语法所约束。
相反,所有行为结构都可以被使用。
这样,测试文件可以被写的更通用,更易于维护。
所有的测试文件都包含以下基本内容,如表1。
如上所属,测试文件经常同时包含附加功能,如结果的可视化显示和内建错误检测。
Testbench文件编写纪要(Verilog)
Testbench⽂件编写纪要(Verilog)之前在使⽤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 [1:0] DATA ;reg [1:0] LATCH_OUT ;always @ (READ_WRITE or DATA) beginif (READ_WRITE == 1)LATCH_OUT <= DATA;endassign DATA = (READ_WRITE == 1) ? 2'bZ : LATCH_OUT;endmodule为其设计的testbench⽂件可以是:module test_bidir_ver;reg read_writet;reg [1:0] data_in;wire [1:0] datat, data_out;bidir_infer uut (datat, read_writet);assign datat = (read_writet == 1) ? data_in : 2'bZ;assign data_out = (read_writet == 0) ? datat : 2'bZ;initial beginread_writet = 1;data_in = 11;#50 read_writet = 0;endendmodule和普通的Verilog模块中⼀样、使⽤assign对wire类型的变量进⾏赋值。
verilog testbench语法
Verilog Testbench语法深度解析1. 什么是Verilog Testbench?Verilog Testbench是一种用于验证Verilog硬件描述语言(HDL)设计的测试环境。
它可以模拟设计的功能,并验证其正确性。
Testbench通常包括测试向量生成、时序控制、错误检测和报告等功能,用于对设计的每个功能进行全面的测试。
2. Verilog Testbench的基本结构Verilog Testbench通常包括模块实例化、时钟生成、信号驱动、仿真结束条件等基本结构。
下面我们分别来详细解析一下这些基本结构:2.1 模块实例化模块实例化是将被测试的Verilog设计模块实例化到Testbench中进行仿真。
在Testbench中,需要为被测设计的每个模块实例化一个对应的实例,并连接所需的输入和输出信号。
如果我们要测试一个简单的加法器模块,那么Testbench中就需要实例化这个加法器,并为其提供输入信号。
2.2 时钟生成时钟是数字电路中非常重要的一部分,它的稳定性和频率对设计的正确性有很大影响。
因此在Testbench中,通常需要生成一个时钟信号,并为被测设计提供时钟。
时钟的生成需要考虑到时钟周期、占空比、起始相位等因素。
2.3 信号驱动在Verilog Testbench中,需要为被测设计提供输入信号,并对其进行驱动。
这些输入信号可以是测试用的模拟信号,也可以是从文件读取的数据。
对于复杂的设计,输入信号的生成可能需要一定的算法和规则。
2.4 仿真结束条件仿真结束条件是指在Testbench中指定了仿真运行的结束条件。
通常情况下,仿真会在满足了所有测试用例,并且通过了所有检查点之后结束。
在Testbench中需要注意设置好仿真的结束条件,以避免不必要的浪费。
3. Verilog Testbench的个人观点对于Verilog Testbench,我个人认为它是Verilog设计中不可或缺的一部分。
verilog testbench例子
Verilog Testbench例子Verilog是一种硬件描述语言,用于描述数字系统。
在Verilog中,testbench是用于验证设计的一部分。
它是一个独立的模块,用于提供输入信号并验证设计的输出信号。
在本文中,我们将介绍一个Verilog testbench的例子,以帮助读者更好地理解Verilog设计和验证的流程。
1. 确定测试目标在编写Verilog testbench之前,首先需要确定测试的目标。
这包括对设计的功能和性能的需求,并确定测试中需要关注的重点。
测试目标的确定将有助于后续测试用例的编写和验证结果的分析。
2. 编写testbench框架testbench通常包括以下几个部分:- 时钟信号生成器:用于生成时钟信号,驱动设计的时序逻辑。
- 信号生成器:用于生成各种输入信号,模拟实际工作状态下的输入情况。
- 仿真模型:绑定被测设计的接口,将输入信号传递给设计,并验证设计的输出信号是否符合预期。
下面是一个简单的testbench框架的例子:```verilog`timescale 1ns / 1nsmodule tb_example;// Define signalsreg clk;reg rst;reg [7:0] data_in;wire [7:0] data_out;// Instantiate design under test (DUT) example_dut dut(.clk(clk),.rst(rst),.data_in(data_in),.data_out(data_out));// Clock generatoralways#5 clk = ~clk;// Stimulus generatorinitial beginrst = 1;#10 rst = 0;#20 data_in = 8'hFF;#20 data_in = 8'h00;// Add more stimulus hereend// Check outputsalways (posedge clk) begin// Add output check hereendendmodule```3. 编写测试用例编写测试用例是testbench编写的关键步骤之一。
verilog testbench语法
verilog testbench语法【最新版】目录1.Verilog Testbench 简介2.Verilog Testbench 的基本语法3.Verilog Testbench 的应用实例正文1.Verilog Testbench 简介Verilog Testbench 是一种用于验证 Verilog 模型的工具,它可以帮助设计人员对硬件电路进行功能验证和性能分析。
Testbench 是一个独立的 Verilog 模块,可以驱动和监控被测模块,通过生成各种测试向量来验证被测模块的正确性。
2.Verilog Testbench 的基本语法Verilog Testbench 的基本语法包括以下几个方面:(1)`module`声明:定义一个 Testbench 模块,与被测模块类似,也需要声明输入输出端口。
(2)`initial`语句:在 Testbench 模块的初始化阶段执行的操作,通常用于初始化测试向量、设置初始状态等。
(3)`always`语句:在 Testbench 模块的时钟上升沿执行的操作,用于驱动被测模块,并监控被测模块的输出。
(4)`wire`声明:定义一个 Testbench 模块内部的信号线,用于连接被测模块的输入输出端口。
(5)`reg`声明:定义一个 Testbench 模块内部的寄存器,用于存储测试向量或中间结果。
(6)`if`和`case`语句:用于生成测试向量,根据不同的条件驱动被测模块。
(7)`assert`和`asserter`语句:用于验证被测模块的输出是否符合预期,如果符合则通过,否则产生错误信息。
3.Verilog Testbench 的应用实例下面是一个简单的 Verilog Testbench 应用实例,用于验证一个 4 位加法器的正确性:```verilogmodule tb_adder_4bit;reg [3:0] a, b;wire [3:0] sum;wire cin;initial begincin = 1;for (a = 0; a < 16; a = a + 1) beginfor (b = 0; b < 16; b = b + 1) begin#10;a = a + 1;b = b + 1;sum = a + b;if (sum === (a + b)) begin$display("Test passed for a = %0d and b = %0d", a, b);end else begin$display("Test failed for a = %0d and b = %0d", a, b);endendendendendmodule```这个 Testbench 实例中,我们定义了一个 4 位加法器模型,并通过循环遍历所有可能的输入组合,验证加法器的输出是否正确。
组合-时序逻辑电路Verilog-Testbench代码_带仿真代码和波形_
组合-时序逻辑电路Verilog-Testbench代码_带仿真代码和波形_1组合逻辑电路--基本门电路1.1基本门电路1.1.1结构化描述⽅式代码如下View Code1 module logics2 (3 input iA,4 input iB,5 output oAnd,6 output oOr,7 output oNot8 );910 and and_inst(oAnd,iA,iB);11 or or_inst(oOr,iA,iB);12 not not_inst(oNot,iA);1314 endmodule最底层的是门级原语and or not RTL级视图testbench如下View Code1 `timescale 1 ns/ 1 ns2 module logics_tb();34 reg ia;5 reg ib;67 wire oAnd;8 wire oOr;9 wire oNot;1011 initial12 begin13 ia=0;14 #40 ia=1;15 #40 ia=0;16 #40 ia=1;17 #40 ia=0;18 end1920 initial21 begin22 ib=0;23 #40 ib=0;24 #40 ib=1;25 #40 ib=1;26 #40 ib=0;27 end2829 logics logics_inst30 (31 .iA(ia),32 .iB(ib),33 .oAnd(oAnd),34 .oOr(oOr),35 .oNot(oNot)36 );37RTL级仿真图形如下GATE级仿真图如下可见RTL级仿真是理想的,GATE级仿真考虑了延迟和信号开始的不确定。
1.1.2采⽤流描述⽅法代码如下View Code1 module logics2 (3 input iA,4 input iB,5 output oAnd,6 output oOr,7 output oNot8 );910 assign oAnd=iA&iB11 assign oOr=iA|iB;12 assign oNot=~iA;1314 endmoduleRTL级视图,仿真图形同上。
verilog testbench语法
verilog testbench语法摘要:一、Verilog 简介二、Verilog Testbench 的作用三、Verilog Testbench 语法1.模块声明2.信号声明3.初始化语句4.循环语句5.断言和读取语句6.函数和任务声明7.子模块和测试序列四、Verilog Testbench 实例1.简单实例2.复杂实例五、Verilog Testbench 应用场景六、总结正文:一、Verilog 简介Verilog 是一种硬件描述语言,用于描述数字电路和模拟混合信号电路。
它被广泛应用于电子设计自动化(EDA)领域,可以用来设计、验证和仿真数字电路。
二、Verilog Testbench 的作用Verilog Testbench 是一个用于验证Verilog 代码的工具,它可以模拟真实环境中的测试信号,并检查电路的行为是否符合预期。
Testbench 可以帮助我们发现代码中的错误,提高设计质量。
三、Verilog Testbench 语法1.模块声明一个Testbench 模块使用`module`关键字声明,例如:```module tb_example();```2.信号声明在Testbench 中,需要声明待测试模块的输入输出信号。
例如:```reg [7:0] A, B;wire C;```3.初始化语句初始化语句用于设置信号的初始值。
例如:```initial beginA = 8"h00;B = 8"h01;end```4.循环语句Testbench 中可以使用`for`、`forever`和`while`等循环语句。
例如:```initial beginfor (A = 8"h00; A < 8"hFF; A = A + 8"h01) begin// 测试代码endend```5.断言和读取语句断言语句用于检查信号之间的关系是否满足预期。
verilog testbench语法
verilog testbench语法摘要:1.Verilog Testbench 简介2.Testbench 结构3.编写Testbench 的注意事项4.Testbench 常用技巧与策略5.UVM 与Verilog Testbench 的区别正文:Verilog Testbench 是一种用于验证数字电路设计的测试工具,通过模拟和仿真来检查电路功能是否符合预期。
Testbench 主要由三个部分组成:驱动模块、监控模块和测试模块。
在本文中,我们将详细讨论Testbench 的语法、结构以及编写Testbench 时需要注意的要点。
1.Verilog Testbench 简介Verilog Testbench 是基于文本的测试工具,它使用Verilog 编程语言编写。
通过描述性文本和激励信号,Testbench 可以模拟数字电路的行为,并在仿真过程中检查电路的响应是否正确。
Testbench 主要用于验证电路设计的功能、时序和性能。
2.Testbench 结构一个典型的Testbench 结构包括以下几个部分:- 驱动模块:负责产生输入信号,用于刺激被测电路。
- 监控模块:用于捕获被测电路的输出信号,并与预期值进行比较。
- 测试模块:根据输入信号和输出信号的比较结果,判断电路设计的正确性。
3.编写Testbench 的注意事项- 确保Testbench 与被测模块的接口匹配,包括输入信号、输出信号和参数。
- 使用适当的时钟信号和复位信号,确保仿真过程中电路状态的正确切换。
- 编写清晰的注释,便于理解和维护。
- 合理使用宏定义和参数化,提高Testbench 的可复用性。
- 验证电路的边界条件,确保测试的全面性。
4.Testbench 常用技巧与策略- 使用事件驱动的仿真算法,提高仿真速度。
- 采用分阶段测试策略,逐步验证电路的各个功能模块。
- 使用随机化测试,提高测试覆盖率。
- 结合断言和检查点,确保电路的正确性。
Verilog-HDL-如何编写TESTBENCH
08:292主要内容Verilog 对验证的支持系统函数和系统任务如何编写模块的TESTBENCH08:293系统任务和系统函数是Verilog中预先定义好的,用于调试和编译预处理的任务或函数。
以$开头,用于控制和检测仿真模拟过程主要有:(1)用于获取仿真时间的系统函数(2)支持文本输出(检测信号、显示信号)的系统任务(3)用于文件输入、输出操作的系统任务(4)用于暂停和退出仿真的系统任务(5)用于产生随机数的系统任务08:294获取当前仿真时间的系统函数$time,$realtime,$stime:返回当前仿真时间。
$time返回一个64位的整数时间值,$realtime返回的结果是实数时间值,是更为精确的仿真时间 $stime返回一个32位整数时间值。
(对大于232的时间,返回模232的值。
使用它可以节省显示及打印空间。
)这些函数的返回值使用调用模块中`timescale 定义的模块仿真时间尺度为单位08:295例..\..\verilog_example\Dec2x4.v..\..\verilog_example\Dec_Test.v # At time 0, input is 0,0,0, output is,xxxx # At time 4, input is 0,0,0, output is,1111# At time 10, input is 0,0,1, output is,1111# At time 13, input is 0,0,1, output is,0111# At time 20, input is 1,0,1, output is,0111# At time 23, input is 1,0,1, output is,0101# At time 26, input is 1,0,1, output is,1101# At time 30, input is 1,1,1, output is,1101# At time 33, input is 1,1,1, output is,1100# At time 36, input is 1,1,1, output is,1110# At time 40, input is 0,1,1, output is,1110# At time 44, input is 0,1,1, output is,1011# At time 50, input is 0,0,1, output is,1011# At time 54, input is 0,0,1, output is,011108:296Verilog 支持的文本输出的系统任务显示任务:用于仿真模拟期间显示信息。
Verilog-testbench的写法
数字集成电路设计入门--从HDL到版图于敦山北大微电子学系第十五章Verilog Test Bench使用简介学习内容:•用一个复杂的test bench复习设计的组织与仿真•建立test bench通常使用的编码风格及方法设计组织虚线表示编译时检测输入文件是否存在及可读并允许生成输出文件。
test bench 组织stimulus要验证的设计简单的test bench•简单的test bench 向要验证的设计提供向量,人工验证输出。
•复杂的test bench 是自检测的,其结果自动验证。
复杂的test bench激励验证结果要验证的设计并行块•fork…join块在测试文件中很常用。
他们的并行特性使用户可以说明绝对时间,并且可以并行的执行复杂的过程结构,如循环或任务。
module inline_ tb;reg [7: 0] data_ bus;// instance of DUTinitial forkdata_bus = 8'b00;Time | data_ bus0 | 8’b0000_0000 10 | 8’b0100_0101 30 | 8’b0100_0110 40 | 8’b0100_0111 45 | 8’b1000_1110#10 data_bus = 8'h45;#20 repeat (10) #10 data_bus = data_bus + 1;#25 repeat (5) #20 data_bus = data_bus<< 1;#140 data_bus = 8'h0f;joinendmodule上面的两个repeat循环从不同时间开始,并行执行。
象这样的特殊的激励集在单个的begin…end块中将很难实现。
50 | 8’b1000_1111 60 | 8’b1001_0000 65 | 8’b0010_0000 70 | 8’b0010_0001 80 | 8’b0010_0010 85 | 8’b0100_0100 90 | 8’b0100_0101 100 | 8’b0100_0110 105 | 8’b1000_1100 110 | 8’b1000_1101 120 | 8’b1000_1110 125 | 8’b0001_1100 140 | 8’b0000_1111包含文件•包含文件用于读入代码的重复部分或公共数据。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
Testbench专题所谓testbench,即测试平台,详细的说就是给待验证的设计添加激励,同时观察输出响应是否符合设计要求。
也许我们会把把程序开发出来算作一个工程项目的重大的比例,这在今天的FPGA设计中,并不是如此,往往在仿真验证上的工作量占到一半以上。
试想这么一个测试,一个16位的输入总线,它可以有多少种组合?如果每次随机产生一种输入,用波形的去画一画,眼花!波形是最直观的测试手段,但不是唯一手段。
一个完整的测试平台如下图所示,它是分结构组成的,其中对设计测试结果的判断不仅可以通过观察对比波形得到,而且可以灵活使用脚本命令将有用的输出信息打印到终端或者产生文本进行观察,也可以写一段代码让它们自动比较输出结果。
TB的设计是多种多样,可以使用灵活的VERILOG的验证脚本,但是它也是基于硬件语言但是又服务于软件测试的语言,有时并行有时顺序,只有掌握这些关键点,才能很好服务测试。
技巧1Tb中的例化应该把INPUT转换成REG,因为待测设计的输入值是由TB 决定的。
相应的OUTPUT 就应该转换成WIRE,因为待测设计的输出值不是由tb决定的。
这里需要注意Inout端口,在例化中也是一个wire型。
技巧2时钟产生第一种:parameter PERIOD=XX; Initial beginClk=0;Forever#( PERIOD /2) clk =~clk; End第二种parameter PERIOD=XX;always begin#( PERIOD /2) clk=0;# (PERIOD /2) clk=1;End技巧3复位信号Initial beginReset_task(XX);//注意时间尺度…….EndTask reset_task;Input [15:0]reset_time;BeginReset=0;# reset_time;Reset =1;End技巧4变量的定义在编写testbench时,关于变量的定义常犯的错误就是将一个定义的全局变量应用到了两个不同的always块中(如例1所示),那么由于这两个always块独立并行的工作机制,很可能会导致意想不到的后果。
例1:integer i;always beginfor (i = 0; i < 32; i = i + 1) begin ………endendalways beginfor (i = 0; i < 32; i = i + 1) begin ……endend实际上,在verilog中(编写testbench 时),如果在begin end之间定义了always的块名,那么你可以如例2一样申明变量。
这样两个always块里的变量i就互不相关,也就不会产生不可预料的结果了。
例2:alwaysbegin: block_linteger i;for (i = 0; i < 32; i = i + 1) begin……endendalwaysbegin: block_2integer i;for (i = 15; i >= 0; i = i - 1) begin……endend除此以外,在verilog中的function 和task也支持类似上面的局部变量定义。
技巧5封装有用的子程序 moduel display_report();//封装一些做测试时有用的报告显示//包括任务error,warning,fatal,terminate//显示warning报告,同时包含显示当前时间和警告内容(由用户输入)task warning;input [80*8:1] msg;begin$write("WARNING at %t: %s", $time, msg);endendtask//显示error报告,同时包含显示当前时间和错误内容(由用户输入)task error;input [80*8:1] msg;begin$write("-ERROR- at %t: %s", $time, msg);endendtask//显示fatal报告,同时包含显示当前时间和致命内容(由用户输入)task fatal;input [80*8:1] msg;begin$write("*FATAL* at %t: %s", $time, msg);terminate;endendtask//显示warning报告,同时包含显示当前时间和结束信息(该任务自动生成)task terminate;begin$write("Simulation completed\n");$finish;endendtaskendmodule//使用上面封装好的taskmodule testcase();//包含已经编写好的display_report.v ,后面就可以调用其封装好的task了`include " display_report.v"……initial beginif (...) error("Unexpected response\n"); //调用error任务……terminate; //调用terminate任务end……endmodulemodule testcase;initialbeginif (...) syslog.error("Unexpected response");syslog.terminate;endendmodule这里提出的子程序封装的概念还是很受益的,这样封装好的task对于以后的testbench随时都可以拿来用,免去繁杂的重复劳动。
技巧6防止同时调用task Testben使用的是硬件语言,而其所依赖的环境却是基于PC的软件平台。
这也就决定了其独特的代码风格。
有时的的确确是以一个软件式的顺序方式在给待测试硬件代码做测试,但是写出来的testbench 代码中却时常布满了并行执行的陷阱。
这给硬件测试者带来了不少麻烦,既然我们选择了verilog,那么就得好好领会它在硬件测试环境下的特殊性。
或者说,我们应该掌握一些常用的技巧来避免这些问题,让我们的testbench更高效的执行。
下面就是一个task使用的常见冲突以及解决办法。
task write;input [7:0] wadd;input [7:0] wdat;beginad_dt <= wadd;ale <= 1’bl;rw <= 1’bl;@ (posedge rdy) ;ad_dt <= wdat;ale <= 1’b0;@ (negedge rdy);endendtaskinitial write(8’h5A, 8’h00);initial write(8’hAD, 8’h34);上面的task实现了往存储器的指定地址写入指定数据的功能。
由于verilog中的always和initial在实际执行中都是并行工作的,也就很有可能出现上面两个initial同时进行task调用,同时需要写存储器的情况。
那样会出现什么后果呢?可想而知,这是我们不希望看到的。
那么如何解决这样的问题呢?看下面改进后的代码。
task write;input [7:0] wadd;input [7:0] wdat;reg in_use;beginif (in_use === 1’b1) $stop;in_use = 1’b1;ad_dt <= wadd;ale <= 1’b1;rw <= 1’b1;@ (posedge rdy);ad_dt <= wdat;ale <= 1’b0;@ (negedge rdy);in_use = 1’b0;endendtask粗体部分就是加入了检错机制,用in_use作为task已被调用的标志信号,从而避免其它的调用。
技巧7结构化Testbench这是假设的待验证模块的顶层:moduleprj_top(clk,rst_n,dsp_addr,dsp_data,dsp_r w……);input clk;input rst_n;input[23:0] dsp_addr;input dsp_rw;inout[15:0] dsp_data;………………endmodule这是testbench的顶层:module tf_prj_top;/*这个例化适用于被例化文件(这里是print_task.v)不对待验证模块接口进行控制*///print_task.v里包含常用信息打印任务封装print_task print();/*这个例化适用于被例化文件需要对待验证模块接口进行控制,和通常RTL设计中例化方法时一样的*///sys_ctrl_task.v里包含系统时钟产生单元和系统复位任务sys_ctrl_task sys_ctrl(.clk(clk),.rst_n(rst_n));//dsp_ctrl_task.v包含DSP读写控制模拟dsp_ctrl_task dsp_ctrl(.dsp_rw(DSP_RW),.dsp_addr(dsp_addr),.dsp_data(dsp_data),……);/*这里的端口例化需要注意的时,原来被测试模块的output为reg,如果被底层的例化模块所控制,那么这个reg要改为wire类型进行定义,而底层模块要将其定义为reg*/wire clk;wire rst_n;wire[23:0] dsp_addr;wire dsp_rw;wire[15:0] dsp_data;……//例化待验证工程顶层prj_top uut(.clk(clk),.rst_n(rst_n),.dsp_addr(dsp_addr),.dsp_data(dsp_data),.dsp_rw(dsp_rw),……);/*注意下面调用底层模块的任务的方式,例如sys_ctrl表示上面例化的sys_ctrl_task.v,sys_reset是例化文件中的一个任务,用”.”做分割*/Initial beginsys_ctrl.sys_reset(32’d1000); //系统复位1000ns#1000;dsp_ctrl.task_dsp_write(SELECT_STR B0,24'h000001,16’h00ff); //DSP写任务调用#1000;dsp_ctrl.task_dsp_read(SELECT_STRB 0,24'h000008,dsp_rd_data); //DSP读任务调用……print.terminate;endendmodule//调用层1module print_task;//----------------------------------------------------------------------////常用信息打印任务封装//----------------------------------------------------------------------////警告信息打印任务task warning;input[80*8:1] msg;begin$write("WARNING at %t : %s",$time,msg);endendtask//错误信息打印任务task error;input[80*8:1] msg;begin$write("ERROR at %t : %s",$time,msg);endendtask//致命错误打印并停止仿真任务task fatal;input[80*8:1] msg;begin$write("FATAL at %t : %s",$time,msg);$write("Simulation false\n");$stop;endendtask//完成仿真任务task terminate;begin$write("Simulation Successful\n");$stop;endendtaskendmodule//调用层2module sys_ctrl_task(clk,rst_n);output reg clk; //时钟信号output reg rst_n; //复位信号parameter PERIOD = 20; //时钟周期,单位nsparameter RST_ING = 1'b0; //有效复位值,默认低电平复位//----------------------------------------------------------------------////系统时钟信号产生//----------------------------------------------------------------------//initial beginclk = 0;forever#(PERIOD/2) clk = ~clk;end//----------------------------------------------------------------------////系统复位任务封装//----------------------------------------------------------------------//task sys_reset;input[31:0] reset_time; //复位时间输入,单位nsbeginrst_n = RST_ING; //复位中#reset_time; //复位时间rst_n = ~RST_ING; //撤销复位endendtaskendmodule//调用层3module dsp_ctrl_task(dsp_rw,dsp_strb0,dsp_strb1,dsp_iostrb, dsp_addr,dsp_data);output reg dsp_rw; //DSP读写信号,低--写,高--读output reg dsp_strb0; //DSP存储空间STRB0选通信号output reg dsp_strb1; //DSP存储空间STRB1选通信号output reg dsp_iostrb; //DSP存储空间IOSTRB选通信号output reg [23:0] dsp_addr; //DSP地址总线inout wire [15:0] dsp_data; //DSP数据总线//print_task.v里包含常用信息打印任务封装print_task print();//----------------------------------------------------------------------////模拟DSP读写任务封装//----------------------------------------------------------------------////DSP地址空间选择//parameter SELECT_STRB0 = 2'd1,SELECT_STRB1 = 2'd2,SELECT_IOSTRB = 2'd3;reg[15:0] dsp_data_reg; //DSP数据总线寄存器assign dsp_data = dsp_rw ? 16'hzz : dsp_data_reg;reg rd_flag; //任务忙标志位,用于防止同时调用该任务reg wr_flag; //任务忙标志位,用于防止同时调用该任务initial beginrd_flag = 0; //DSP读任务不忙wr_flag = 0; //DSP写任务不忙//DSP信号接口初始化dsp_rw = 1;dsp_data_reg = 16'hzzzz;dsp_addr = 24'hzzzzzz;dsp_strb0 = 1;dsp_strb1 = 1;dsp_iostrb = 1;endreg h1; //DSP时钟模拟,h1为DSP指令周期initial beginh1 = 1'b0;forever#20 h1 = ~h1;end//模拟 DSP读FPGA任务task task_dsp_read;input[1:0] tcs; //片选输入 input[23:0] taddr; //地址输入 output[15:0] tdata; //数据读出 begin……endendtask//模拟DSP写FPGA任务task task_dsp_write;input[1:0] tcs; //片选输入 input[23:0] taddr; //地址输入 input[15:0] tdata; //数据写入 begin……endendtaskendmodule一些函数的说明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=%do1=%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);任务:一熟悉刚才所学!!!!!!从简单的函数运用入手练习特别是列出的常用的函数对RAMIP核进行仿真将初始化的RAM的数据读出写入一个文件DAT的文件中。