VHDL——如何写简单的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可以编写的更为通用,使得它们可以更容易维护。
AD6 中VHDL设计及创建Testbench参考

VHDL语言设计参考VHDL是一种用于数字系统行为级描述的编程语言。
VHDL具备了许多适合于电子器件行为级描述的特性,无论是简单的逻辑门电路还是复杂的微处理器或用户自定制的器件。
从而,VHDL满足电路行为中电气特征(诸如信号上升/下降时间、门延迟和功能)的精确描述。
并且利用VHDL仿真模型可以搭建更大的可仿真电路。
VHDL还是一种通用的可编程语言,就如同利用高级语言在计算机上编写复杂的设计程序,VHDL允许输入复杂电子电路的行为级设计,并实现自动电路综合或系统仿真。
同时,VHDL也不同于高级语言,采用并发事件设计(即在执行阶段内,每个语句行为是并行执行的);这一特性取决于硬件电路设计上固有的并行执行的特性。
VHDL最重要的应用之一就是设计电路的执行规范,语法规则与Testbench相一致。
Testbench是用于验证电路在时间上行为级描述的。
在任何时候,Testbench都将作为VHDL 设计项目的一个组成部分。
注:符号 <=为付值操作符,表示将符号右边的数值给符号左边的变量;一个完整的VHDL设计项目至少要包含一个实体(entity)和结构体(architecture)定义。
对于一个大型设计,通常需要定义多个实体/结构对并且将他们连接在一起形成一个完整的电路。
实体定义用于描述电路的输入/输出端口;结构体定义是VHDL设计中最小的组成单元。
在仿真或综合执行前,每个实体必须被相对应结构体封装。
在结构体中描述了实际的功能。
实体定义entity comp_name isport(in_port : in bit_vector(7 downto 0); out_port : out bit);end comp_name;结构体定义:architecture comp_name of entity_name isbegin<conditional assignment>;end comp_name;注:关键字process用来封装复杂的顺序逻辑设计;VHDL语言中的数据类型:VHDL设计中实际由5种设计单元类型构成:实体、结构体、程序包、程序包体和配置。
testbench(框架—基础—进阶)

--------------------------------------project-------------------------------------------------------此模块为yuv444转yuv422模块,由输入24bit数转8bit输出,本笔记都以此工程为基础,都仿真测试过module yuv444to422(input ccd_clk,input sys_clk,input resetn,input HD,input VD,input [23:0] yuv,input yuv_trans_done,output clk_out,output reg [7:0] data_out,output HD_out,output VD_out,output reg [11:0] v_cnt);assign clk_out = ~ccd_clk;assign HD_out = HD;// ;hd1[1]assign VD_out = VD;//v_cnt_out;//;vd1[1]///////////////////1280*1024-->1280*720////////////reg [1:0] hs_edge;always@(posedge ccd_clk)beginif(!resetn)hs_edge <= 2'b00;elsehs_edge<= {hs_edge[0],HD};endalways@(posedge ccd_clk)beginif(!resetn)v_cnt <= 12'b0;else if(!VD)v_cnt <=0;else if(hs_edge==2'b01)v_cnt <= v_cnt +1;endreg v_cnt_out;always@(posedge sys_clk)beginif(!resetn)v_cnt_out <= 1'd0;else if ((v_cnt >= 12'd179) && (v_cnt <= 12'd899)) v_cnt_out <= 1'd1;else v_cnt_out <= 1'd0;end*/////////////////////////////reg [1:0]cnt1;always@(posedge ccd_clk)beginif(!resetn)cnt1<=0;else if(yuv_trans_done)cnt1<=cnt1+1;endalways@(posedge ccd_clk)beginif(!resetn)begindata_out <= 8'b0;endelse if (HD)begincase(cnt1)2'b0:data_out <= yuv[23:16];2'b1:data_out <= yuv[15:8]; //8'h80;//2'd2:data_out <= yuv[23:16];2'd3:data_out <= yuv[7:0]; //8'h80;//endcaseendendmodule--------------------------------------------testbench------------------------------------------- `timescale 1 ns/ 1 ps`include "D:/tangate_quartus/yuv444to422/yuv444to422.v"module yuv444to422_vlg_tst();reg HD;reg VD;reg ccd_clk;reg resetn;reg sys_clk;reg [23:0] yuv;reg yuv_trans_done;// wireswire HD_out;wire VD_out;wire clk_out;wire [7:0] data_out;wire [11:0] v_cnt;yuv444to422 i1 (.HD(HD),.HD_out(HD_out),.VD(VD),.VD_out(VD_out),.ccd_clk(ccd_clk),.clk_out(clk_out),.data_out(data_out),.resetn(resetn),.sys_clk(sys_clk),.v_cnt(v_cnt),.yuv(yuv),.yuv_trans_done(yuv_trans_done));//------------------------------------------------------------------------------------- parameter n = 10;//-------------------------------------------------------------------------------------initialbeginHD = 1'b0; // time 0 时刻VD = 1'b0;repeat(n)begin# 200 VD = 1'b1; // time 200repeat(10*n)begin#100 HD = 1'b1; //time 300#100 HD = 1'b0; //time 700end#100 VD = 1'b0;endend//------------------------------------------------initialbeginyuv_trans_done = 1'b0;#30 yuv_trans_done = 1'b1;end//----------------------------------------------/*initialbeginresetn = 1'b0;#30 resetn = 1'b1;end*///---------------------------------------------initialbeginsys_rst (100);//复位100个时间单位endtask sys_rst ;input [10:0] rst_time; //调用task的时候,将参数赋值给rst_time beginresetn = 0;#rst_time;resetn = 1;endendtask//-----------------------------------------------------alwaysbegin#10 ccd_clk = 1'b0;#10 ccd_clk = 1'b1;endinitialbeginyuv = 24'b0;forever @(posedge ccd_clk) #20 yuv = $random;end//-----------------------------------------------------------initialbegin#10000 $stop(2);end//------------------------------ok---------------------------------/*initialbegin#3000begin$display("current scope is %m");$display("the signal is %s",data_out);$display("the time is %t",$time) ;$display("data_out has %c ascii character value",data_out);$display("data_out=%h hex %d decimal", data_out, data_out);$display("data_out=%o otal %b binary", data_out, data_out);endend*///--------------------------------------ok------------------------------------------//always @(data_out) $display("Output changed at %t to %b",$time,data_out); //---------------------------------ok---------------------------------------------------//always @(data_out) $strobe("Output changed at %t to %b",$time,data_out); //-------------------------------ok----------------------------------------------------//initial//$monitor ("at time is %t and the signal is %b\n",$time , VD_out) ;//----------------------------------ok------------------------------------//initial// $monitor ("%d is changed at %t",data_out,$time);//yuv444to422_vlg_tst. //-----------------------------------ok--------------------------------------/* reg [23:0] buffer;initialbuffer = 24'b0000_1110_0001_1011_0101_1100;always @ ( posedge ccd_clk) #10 {yuv,buffer} = {buffer,yuv};*///-------------------------------------ok---------------------------------------------/*always @ (ccd_clk)begin$timeformat(-9,1,"ns",0);$display ("time clk HD VD v_cnt data_out ");$monitor("%t %b %b %b %b %b ", $realtime, clk_out, HD_out, VD_out, v_cnt, data_out);end*///--------------------------------write ok--------------------------------------/*initialbegin : blockinteger file_id;file_id = $fopen("D:/tangate_quartus/yuv444to422/data_out.txt");//1.打开文件//$fmonitor只要有变化就一直记录自动换行无需加\n//格式:$fmonitor(file_id, "%format_char", parameter);$fmonitor(file_id, "%m: %t data_out=%d v_cnt=%h___tangate", $time, data_out, v_cnt);//$fwrite需要触发条件才记录,只记录一行数据,换行需加\n,注意反斜杠的方向$fwrite(file_id, "%m: time is %t**data_out=%d**v_cnt=%h\n", $time, data_out, v_cnt);//2.写入文件//$fdisplay需要触发条件才记录,只记录一行数据,自动换行无需加\n//格式:$fdisplay(file_id, "%format_char", parameter);$fdisplay (file_id, "%m: %t data_out=%d v_cnt=%h___great man", $time, data_out, v_cnt);$fclose("D:/tangate_quartus/yuv444to422/data_out.txt"); //3.关闭文件end*///-----------------------------------read ok----------------------------------------------begin : blockinteger file_id;file_id = $fopen("D:/tangate_quartus/yuv444to422/data_out.txt");//1.打开文件$fread( "D:/tangate_quartus/yuv444to422/data_out.txt", $time, data_out, v_cnt);//2.读取文件$fclose("D:/tangate_quartus/yuv444to422/data_out.txt"); //3.关闭文件endendmoduleTestbench 学习笔记(框架)为什么C不能取代verilog和VHDL作为硬件描述语言?因为C缺少了硬件描述最基本的三个思想:连通性(Connectivity),时间性(Time)和并行性(Concurrency)。
Testbench基本入门

Testbench入门1 编写testbench目的编写testbench的主要目的是为了对使用硬件描述语言(HDL)设计的电路进行仿真验证,测试设计电路的功能、部分性能是否与预期的目标相符。
编写testbench进行测试的过程如下:1)产生模拟激励(波形);2)将产生的激励加入到被测试模块并观察其输出响应;3)将输出响应与期望进行比较,从而判断设计的正确性。
2 基本的testbench结构module test_bench;// 通常testbench没有输入与输出端口信号或变量定义声明使用initial或always语句来产生激励波形例化设计模块监控和比较输出响应endmodule简单的testbench的结构通常需要建立一个顶层文件,顶层文件没有输入和输出端口。
在顶层文件里,把被测模块和激励产生模块实例化进来,并且把被测模块的端口与激励模块的端口进行对应连接,使得激励可以输入到被测模块。
端口连接的方式有名称和位置关联两种方式,我们常常使用“名称关联”方式。
3 产生激励的一些描写方式3.1 产生时钟的几种方式1)使用initial方式产生占空比50﹪的时钟initialbeginCLK = 0;#delay;forever#(period/2) CLK = ~CLK;end注意:一定要给时钟赋初始值,因为信号的缺省值为z,如果不赋初值,则反相后还是z,时钟就一直处于高阻z状态。
产生的时钟信号如下图所示:2)使用always方式initialCLK = 0;always#(period/2) CLK = ~CLK;3)使用repeat产生确定数目的时钟脉冲initialbeginCLK = 0;repeat(6)#(period/2) CLK = ~CLK;end该例使用repeat产生3个时钟脉冲,产生的波形如下:4)产生占空比非50﹪的时钟initialCLK = 0;alwaysbegin#3 CLK = ~CLK;#2 CLK = ~CLK;end3.2 产生复位信号的几种形式1)异步复位initialbeginRst = 1;#100;Rst = 0;#500;Rst = 1;end2)同步复位1initialbeginRst = 1;@(negedge CLK); // 等待时钟下降沿Rst = 0;#30;@(negedge CLK); // 等待时钟下降沿Rst = 1;end2)同步复位2initialbeginRst = 1;@(negedge CLK); // 等待时钟下降沿repeat (3) @(negedge CLK); // 经过3个时钟下降沿Rst = 1;end4 testbench实例4.1 2-4解码器实例module dec2x4(A, B, Enable, Z);input A, B, Enable;output[3:0] Z;reg [3:0] Z_o;assign Z = Z_o;always@(A or B or Enable)beginif(Enable == 1'b0)Z_o = 4'b1111;elsecase({A, B})2'b00: Z_o = 4'b1110;2'b01: Z_o = 4'b1101;2'b10: Z_o = 4'b1011;2'b11: Z_o = 4'b0111;default: Z_o = 4'b1111;endcaseendendmodule测试模块测试模块::`timescale 1ns/100psmodule testbench;reg a, b, en;wire [3:0] z;//例化被测试模块dec2x4 DUT(.A(a),.B(b),.Enable(en),.Z(z));//产生输入激励initialbeginen = 0;a = 0;b = 0;#10 en = 1;#10 b = 1;#10 a = 1;#10 b = 0;#10 a = 0;#10 $stop;end//显示输出结果always@(en or a or b or z)begin$display("At time %t, input is %b%b%b, output is %b", $time, a, b, en, z);endendmodule下面是测试模块执行时产生的输出和功能仿真波形:4.2 时序检测器下面是一个时序检测器的验证实例。
VHDL Test bench文件的三种生成方式

VHDL TestBench基础TestBench的主要目标Test bench(TB)是一种VHDL代码,目的在于验证HDL模型的功能是否正确。
Test bench是电路规格的一部分,其主要目标是:∙实例化UUT(Unit Under Test, UUT),以前版本也叫DUT(Design Under Test) ∙为UUT产生激励波形∙产生参考输出,并将UUT的输出与参考输出进行比较∙提供测试通过或失败的指示TestBench产生激励的三种方式响应可以在test bench中产生,也可以通过文件进行存储,以备后用。
常用的产生TB的三种方法为:∙直接在testbench中产生∙从矢量中读入∙从单独的激励文件中读入比较流行的做法是使用matlab产生激励文件,由testbench读入该激励文件并将激励馈送到UUT,UUT产生的相应输出以文件的形式存储,由matlab读取并与理想的响应作比较。
1. 简单的TestBench简单的testbench只适合于相对比较简单的设计。
如图1-1所示,在testbench 中只是简单的实例化了一个UUT,激励在testbench中产生,这种方式的testbench 可重用性差。
示意图如下。
UUT tb_adder.vhd代码:仿真结果2. 具有独立激励源的test bench将激励源作为一个文件在test bench中进行实例化,比较适合于具有复杂输入和简单输出的设计,激励源可以是一个实体或者一个进程之类的。
例如下图中adder的输入激励是在一个单独的实体counter中产生的。
激励源tb_counter.vhd代码test bench中的实例化代码(将tb_counter实例化)仿真结果3. 使用TextIO的testbench当设计的输入输出都比较复杂时,尤其是在做复杂的算法仿真时,需要产生多种形式的激励输入,还要对仿真结果输出做复杂的分析时,使用TextIO的test bench具有最高的效率。
如何编写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⼯具查看),适⽤于对较⼤的系统进⾏仿真,速度快,优于全局仿真。
ModelSim环境基于VHDL语言的testbench书写[整理]
testbench顾名思义就是一个测试台,它对外没有接口,所以实体部分为空,但它要对要测试的器件提供激励信号,这其实就是最简单的testbench,以下是具体的操作步骤:1.首先基于QuartusII建立的一个新的工程,编译通过,这其实就是我们要测试的源文件DUT(design under test)counter.vhd.library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;entity counter isport(clk: in std_logic;reset: in std_logic;en: in std_logic;q: out std_logic_vector(3 downto 0));end counter;architecture behave of counter issignal q_n: std_logic_vector(3 downto 0);beginprocess(clk, reset, en, q_n)beginif (reset = '1') thenq_n <= (others => '0');--Òì²½ÇåÁãelsif rising_edge(clk) thenif en = '1' thenq_n <= q_n + 1;end if;end if;end process;q <= q_n;end behave;2.打开ModelSim,指定路径为Quartus工程所在目录;建立新的仿真工程,添加文件(DUT)。
3.编译DUT文件到仿真库中(右键DUT,选择compile).4.写testbench文件(counter_tb.vhd)。
VHDL的testbench的编写
VHDL的testbench的编写大多数硬件设计人员对verilog的testbench比较熟悉,那是因为verilog被设计出来的目的就是为了用于测试使用,也正是因为这样verilog的语法规则才被设计得更像C语言,而verilog发展到后来却因为它更接近C语言的语法规则,设计起来更加方便,不像VHDL那也死板严密,所以verilog 又渐渐受到硬件设计者们的青睐。
但其实VHDL在最开始也是具有测试能力的,而且它的语法严密,但我们同样可以用它来编写我们的测试文件。
下面以一个8bit计数器为例子给出个简单的testbench模板及注释:通过编写testbench来仿真和通过拖波形来仿真,最大的好处就是,当测试数据无比庞大时,可以简易得通过testbench中的算法来实现,而另一个更为重要的方面就是,可以通过testbench对数据文件进行读写操作,从而简化我们的仿真工作。
首先介绍下时间控制语句——wait:(其实wait语句是通过控制仿真的两种状态——执行和挂起,来控制时间的)1.wait——无线等待;语法【wait;】,类似于Verilog中的¥Stop2.wait on——敏感信号量变化;语法【wait on 信号;】,表示当信号发生变化的时候,仿真开始继续执行,从而结束挂起状态3.wait until——条件满足;语法【waituntil 表达式】,表达式为一个布尔表达式,表示当表达式为“真”时,仿真继续执行,结束挂起状态4.wait for——时间控制;语法【waitfor 时间表达式】,例:【wait for 30ns;】VHDL也提供了文件I/O的操作,以下简单介绍在我们大部分情况下如何通过VHDL来进行文件操作。
file类型:文件句柄,用于定义文件。
语法1【file 文件变量名:text is 读取或者写入类型“文件名”;】text——文件类型为文本类型,读取类型为in,写入类型为out;语法2【file 文件变量名:text;】只是定义了文件变量名,并没有给赋予初值。
VerilogHDL及其Testbench编写方法
Verilog HDL及其Testbench总结(欢迎批评指正:jackhuan@)1 Verilog HDL的基本观点1) 观点1:module内每个基本模块之间是并行运行的。
2) 观点2:每个模块相当于一个连续赋值的过程。
3) 观点3:方程和任务是共享代码的最基本方式。
4) 观点4:同语言可用于生成模拟激励和指定测试的验证约束条件。
5) 观点5:库的概念相当于Visual C++中的DLL概念。
6) 观点6:文件与文件之间的关系可以使用C++中的*.h和*.cpp之关系理解。
2 设计建模的三种方式1) 行为描述方式。
过程化结构,每个结构之间是并行的。
2) 数据流方式。
连续赋值语句方式,每个赋值语句之间是并行的,且赋值语句和结构之间是并行的。
3) 结构化方式。
门和模块实例化语句。
3 两者数据类型1) 线网数据类型wire:表示构件间的物理连线;2) 寄存器数据类型reg:表示抽象的数据存储元件。
4 几个概念1) 模块(module)。
模块是Verilog HDL的基本描述耽误,用于描述某个设计的功能或结构及其与其它模块通信的外部端口。
一个设计的结构可以使用开关级原语、门级原语和用户定义的原语方式描述;数据流行为使用使用连续赋值语句进行描述;时序行为使用过程结构描述。
模块的声明部分和语句可以散布在模块中的任何地方,但变量、寄存器、线网和参数说明必须在使用前出现。
2) 只有寄存器类型数据(reg/integer)能够在initial和always语句中被赋值。
3) 阻塞性和非阻塞性赋值。
理解这两个概念在学习verilog HDL中非常重要。
决定了时序的正确与否。
阻塞性赋值的概念是在该条赋值语句执行完成后再执行后面的语句,也就是说在执行该语句时,后面的语句是挂起的。
而非阻塞性赋值的结果在何时执行是不知道的,但是可以预见在某个时间步内该语句一定能够执行完成,从这个意义上来看,非阻塞性赋值的语句类似于并行语句,稍有处理不当,会引发多驱动源问题。
怎样写testbench
怎样写testbench本文的实际编程环境:ISE 6.2i.03ModelSim 5.8 SESynplify Pro 7.6编程语言 VHDL在ISE中调用ModelSim进行仿真一、基本概念和基础知识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所示:图1l Simulator Behavioral Model 也就是所说的功能仿真、行为仿真、前仿真。
验证功能是否正确,这是设计的第一步。
功能仿真正确的程序不一定能被正确综合,也就是硬件实现。
有的在综合时报错误,有的虽然能综合但结果并不正确。
当然,功能仿真如果都不能通过,以后的步骤也就无法进行。
这是必做的仿真。
l Simulator Post-translate VHDL Model 也就是翻译后仿真。
对源程序进行编译后首先排除了语法错误,对一些像类属命令(Generic)、生成语句(Generate)等进行了展开。
不是必做的仿真。
l Simulator Post-Map VHDL Model也就是映射后仿真。
不同的器件内部结构也不尽相同,映射的作用就是将综合后产生的网表文件对应到实际的器件上去。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
use ieee.std_logic_1164.all;use ieee.std_logic_arith.all;--use ieee.std_logic_unsigned.all;entity cnt6 isport(clr,en,clk :in std_logic;q :out std_logic_vector(2 downto 0) );end entity;architecture rtl of cnt6 issignal tmp :std_logic_vector(2 downto 0); beginprocess(clk)-- variable q6:integer;beginif(clk'event and clk='1') thenif(clr='0')thentmp<="000";elsif(en='1') thenif(tmp="101")thentmp<="000";elsetmp<=unsigned(tmp)+'1';end if;end if;end if;q<=tmp;-- qa<=q(0);-- qb<=q(1);-- qc<=q(2);end process;end rtl;二、六进制计数器testbench的代码signal en :std_logic:='0';signal clk :std_logic:='0';signal q :std_logic_vector(2 downto 0);constant clk_period :time :=20 ns;begininstant:cnt6 port map(clk=>clk,en=>en,clr=>clr,q=>q);clk_gen:processbeginwait for clk_period/2;clk<='1';wait for clk_period/2;clk<='0';end process;clr_gen:processbeginclr<='0';wait for 30 ns;clr<='1';wait;end process;en_gen:processbeginen<='0';wait for 50ns;en<='1';wait;end process;end rtl;--测试平台文件(testbench)的基本结构library ieee;use ieee.std_logic_1164.all;entity test_bench is --测试平台文件的空实体(不需要端口定义) end test_bench;architecture tb_behavior of test_bench iscomponent entity_under_test --被测试元件的声明port(list-of-ports-theri-types-and-modes);end component;begininstantiation:entity_under_test port map(port-associations);process() --产生时钟信号……end process;process() --产生激励源……end process;end tb_behavior;------------------------------------------------------------------- --简单计数程序源码library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.std_logic_unsigned.all;entity sim_counter isport(clk :in std_logic;reset :in std_logic;count :out std_logic_vector(3 downto 0));end entity;architecture behavioral of sim_counter issignal temp :std_logic_vector(3 downto 0);beginprocess(clk,reset)beginif reset='1' thentemp<="0000";elsif clk'event and clk='1' thentemp<=temp+1;end if;end process;count<=temp;end behavioral;------------------------------------------------------------------- --简单计数程序,测试文件代码(testbench)library ieee;use ieee.std_logic_1164.all;use ieee.std_logic_unsigned.all;use ieee.numeric_std.all;entity counter_tb_vhd is --测试平台实体end counter_tb_vhd;architecture behavior of counter_tb_vhd is--被测试元件(DUT)的声明component sim_counterport(clk :in std_logic;reset :in std_logic;count :out std_logic_vector(3 downto 0));end component;--输入信号signal clk:std_logic:='0';signal reset :std_logic:='0';--输出信号signal count :std_logic_vector(3 downto 0);constant clk_period :time :=20 ns; --时钟周期的定义begindut:sim_counter port map(clk=>clk,reset=>reset,counter=>counter);clk_gen:processbeginclk='1';wait for clk_period/2;clk='0';wait for clk_period/2;end process;tb:process --激励信号beginwait for 20 ns;reset<='1';wait for 20 ns;reset<='0';wait for 200 ns;wait; --will wait forever;end process;end;--激励信号的产生方式--1.以一定的离散时间间隔产生激励信号的波形--2.基于实体的状态产生激励信号,也就是说基于实体的输出响应产生激励信号--两种常用的复位信号--1.周期性的激励信号,如时钟--2.时序变化的激励型号,如复位--eg.产生不对称时钟信号w_clk<='0' after period/4 when w_clk='1' else'1' after 3*period/4 when w_clk='0' else'0';--eg.产生堆成时钟信号,process语句clk_gen1:processconstan clk_period := 40 ns;beginclk='1';wait for clk_period/2;clk='0';wait for clk_period/2;end process;四、如果自己不想写这些testbench的这些固定格式,可以在quartus 里自动生成testbench文件的模板,然后往里面写信号就行了步骤:processing->start->start test bench template write这里需要注意的是要在仿真选项里选择一个仿真工具,然后才会生成testbench自动生成的testbench模板格式如下:-- Copyright (C) 1991-2008 Altera Corporation-- Your use of Altera Corporation's design tools, logic functions-- and other software and tools, and its AMPP partner logic-- functions, and any output files from any of the foregoing-- (including device programming or simulation files), and any-- associated documentation or information are expressly subject-- to the terms and conditions of the Altera Program License-- Subscription Agreement, Altera MegaCore Function License-- Agreement, or other applicable license agreement, including,-- without limitation, that your use is for the sole purpose of-- programming logic devices manufactured by Altera and sold by-- Altera or its authorized distributors. Please refer to the-- applicable agreement for further details.-- ***************************************************************************-- This file contains a Vhdl test bench template that is freely editable to-- suit user's needs .Comments are provided in each section to help the user -- fill out necessary details.-- ***************************************************************************-- Generated on "03/13/2011 20:05:04"-- Vhdl Test Bench template for design : cnt6---- Simulation tool : ModelSim (VHDL)--LIBRARY ieee;USE ieee.std_logic_1164.all;ENTITY cnt6_vhd_tst ISEND cnt6_vhd_tst;ARCHITECTURE cnt6_arch OF cnt6_vhd_tst IS-- constants-- signalsSIGNAL clk : STD_LOGIC;SIGNAL clr : STD_LOGIC;SIGNAL en : STD_LOGIC;SIGNAL q : STD_LOGIC_VECTOR(2 DOWNTO 0);COMPONENT cnt6PORT (clk : IN STD_LOGIC;clr : IN STD_LOGIC;en : IN STD_LOGIC;q : OUT STD_LOGIC_VECTOR(2 DOWNTO 0));END COMPONENT;BEGINi1 : cnt6PORT MAP (-- list connections between master ports and signalsclk => clk,clr => clr,en => en,q => q);init : PROCESS-- variable declarationsBEGIN-- code that executes only onceWAIT;END PROCESS init;always : PROCESS-- optional sensitivity list-- ( )-- variable declarationsBEGIN-- code executes for every event on sensitivity list WAIT;END PROCESS always;END cnt6_arch;。