testbench万能模版
- 格式:doc
- 大小:23.50 KB
- 文档页数:2
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;。
testbench常⽤语法总结1.testbench总体代码结构`timescale 1ns/1ps //时间精度`define clk_perilod 20 //时钟周期可变module test_file_tb;//==================<端⼝>==================================================reg clk ; //时钟,50Mhzreg rst_n ; //复位,低电平有效reg [XX:0] in ; //wire [XX:0] out ; ////--------------------------------------------------------------------------//-- 模块例化//--------------------------------------------------------------------------my_design u_my_design(.clk (clk ),.rst_n (rst_n ),.in (in ),.out (out ));//----------------------------------------------------------------------//-- 时钟信号和复位信号//----------------------------------------------------------------------initial beginclk = 0;forever#(`Clock/2) clk = ~clk;endinitial beginrst_n = 0; #(`Clock*20+1);rst_n = 1;end//----------------------------------------------------------------------//-- 设计输⼊信号//----------------------------------------------------------------------initial beginin = 0;#(`Clock*20+2); //初始化完成$stop;endendmodule在这⾥插⼊代码⽚2.时钟激励的编写`timescale 1ns/1ps //时间精度`define Clock 20 //时钟周期//========================================================================== //== ⽅法⼀,50%占空⽐//========================================================================== initial beginclk = 0;forever#(`Clock/2) clk = ~clk;end//========================================================================== //== ⽅法⼆,50%占空⽐//========================================================================== initial beginclk = 0;always#(`Clock/2) clk = ~clk;end//========================================================================== //== ⽅法三,产⽣固定输⼊的时钟脉冲//========================================================================== initial beginclk = 0;repeat(6)#(`Clock/2) clk = ~clk;end//========================================================================== //== ⽅法四,⾮50%占空⽐//========================================================================== initial beginclk = 0;forever begin#((`Clock/2)-2) clk = 0;#((`Clock/2)+2) clk = 1;endend3.复位信号`timescale 1ns/1ps //时间精度`define Clock 20 //时钟周期//========================================================================== //== ⽅法⼀,异步复位//========================================================================== initial beginrst_n = 0; #(`Clock*20+1);rst_n = 1;end//========================================================================== //== ⽅法⼆,同步复位//========================================================================== initial beginrst_n = 0; #(`Clock*20);rst_n = 1;end4.task使⽤//========================================================================== //== 输⼊信号任务封装//========================================================================== task i_data;input [7:0] dut_data;begin@(posedge data_en); send_data=0;@(posedge data_en); send_data=dut_data[0];@(posedge data_en); send_data=dut_data[1];@(posedge data_en); send_data=dut_data[2];@(posedge data_en); send_data=dut_data[3];@(posedge data_en); send_data=dut_data[4];@(posedge data_en); send_data=dut_data[5];@(posedge data_en); send_data=dut_data[6];@(posedge data_en); send_data=dut_data[7];@(posedge data_en); send_data=1;#100;endendtask//调⽤⽅法:i_data(8'hXX);//========================================================================== //== 多输⼊信号任务封装//========================================================================== task more_input;input [ 7:0] a;input [ 7:0] b;input [31:0] times;output [ 8:0] c;beginrepeat(times) @(posedge clk) //等待 times 个时钟上升沿c=a+b;endendtask//调⽤⽅法:more_input(x,y,t,z); //按声明顺序5.repeat ,wait函数//==========================================//== repeat重复执⾏//==========================================initial beginstart = 1;repeat(5) @(posedge clk) //等待5个时钟上升沿start = 0;endinitial beginrepeat(10)begin...//执⾏10次endend//===========================================//== wait为电平触发//==========================================initial beginstart = 1;wait(en); //等待en==1start = 0;end6.随机数产⽣$random //产⽣随机数$random % n //产⽣范围 {-n,n} 的随机数{$random} % n //产⽣范围 { 0,n} 的随机数7.⽂本输⼊输出reg [a:0] data_mem [0:b]; //定义位宽为(a+1)深度为(b+1)的存储器$readmemb/$readmemh("<读⼊⽂件名>",<存储器名>);$readmemb/$readmemh("<读⼊⽂件名>",<存储器名>,<起始地址>);$readmemb/$readmemh("<读⼊⽂件名>",<存储器名>,<起始地址>,<结束地址>);$readmemb/*------------------------------------------------------------------------*\读取⼆进制数据,读取⽂件内容只能包含:空⽩位置,注释⾏,⼆进制数数据中不能包含位宽说明和格式说明,每个数字必须是⼆进制数字。
最近项目上要用到FPGA,之前用的一直是verilog,后面换成了VHDL。
对ISE一窍不通啊,研究了一些testbench文件的编写,record一下。
借用一下博文/lovelink/item/ff34ce9b12f45988581461ac的话。
首先对TESTBENCH作一个形象一些的比喻吧,它就象是一个面包板(做过电路实验吧),他对外没有任何接口,但它要向要插在他上面的器件提供接口,这样才能正确的插入,还有它必须对插在它上面的器件提供正常的信号。
当然在它上面还必须要有这个器件。
这时就完成了一个TESTBENCH。
应该大概明白了其中的意思了吧。
好了,根据上面的比喻我们可以非常明确的知道一个TESTBENCH要写一些什么东西,首先它对外无接口,所以它的实体部分是空的。
在它上面要有相应的器件,所以在它的结构体中要申明我们要测试的器件,也就是component的申明。
还有就是它要对器件提供接口,所以它的结构体应该提供一些信号,并且要对这些信号进行正确的测试赋值。
当然还要进行一些插入工作,就是信号的对应工作。
这样一个TESTBENCH就完成了。
原理很简单的,应该很容易明白。
不过在真正的测试中可能不会用太多的这种方式吧,应该会选用测试向量吧,这个的准确性更高一些。
不过怎么样写测试向量,这到是一个有大学问的东西,因为当我们的管脚很多的时候,测试的向量数目是要心指数增长的,当然不可能把所有的情况都测试完成了,只有是测试其中的一部分,这儿怎么样写出有代表性的一组测试向量是很有学问的,应该说是研究的热点吧。
几个testbench要用到的重要语句:(1)wait:无限等待,表示永远挂起,对于汉语wait语句的进程来说,进程在一开始执行一次后面就不执行了;(2)wait on 信号表:敏感信号等待语句,等待敏感信号表中的信号发生变化才执行;(3)wait until 表达式:条件等待语句,当条件表达式中所含的信号发生了变化,并为true时,进程才脱离等待状态;(4)wait for 时间表达式:此语句中声明了一个时间段,从从执行到当前的wait语句开始,只要这个时间段内,进程处于等待状态,超过这段时间,进程自动恢复执行该等待语句的下一条语句。
Quartus自从9.0版本以后就没有自带仿真工具。
需要进行仿真要另外安装仿真工具。
下面就以altera-modelsim6.6d 版本介绍一个简单的VHDL语言编写的程序的仿真步骤。
Quartus 工具为11.0版本。
1).新建一个工程。
以与非门为例。
打开quartus11.0工具栏的file->new->New Quartus II Project.点击OK。
点Next创建工程文件夹,如andnotgate。
输入工程名称。
点Next先别管它,点Next选择芯片型号,因为是只是仿真,可以随便选。
或者默认。
点Next.选择仿真工具,这里选择ModelSim-Altera.点Next.点Finish。
新建了一个工程。
2).向新建工程添加VHDL源文件File->new->VHDL File->OK编写源程序:library ieee;use ieee.std_logic_1164.all;entity andnotgate isport(a,b:in std_logic;c:out std_logic);end entity andnotgate;architecture rt1 of andnotgate is beginc<=not(a and b);end rt1;保存源程序在新建的工程中File->save as保存。
编译源文件:点击Start compilation编译成功。
3).利用modelsim进行波形仿真要进行仿真必须先创建一个testbench的仿真激励文件。
testbench文件的编写可以利用软件提供的模板进行修改。
生成testbench模板processing->start->start test bench template writer->OK打开新生成的testbench模板。
在新建工程里的simulation->modelsim里的后缀为.vht的文件。
重温了基本的Quartus操作和语法后,需要对手头的工作进行仿真验证,Quartus 9.x自带的Vector Waveform已经淘汰掉了,必须用 ModelSim进行仿真。
现在就开始一步步入手ModelSim,并通过与Quartus无缝衔接实现仿真。
本文使用了ModelSim10.0c + QuartusII 10.0,其他版本基本雷同,请自行研究。
源程序如下:module add(mclk,rst_n,a_in,b_in,c_out);input mclk, rst_n;input[7:0] a_in, b_in;output[8:0] c_out;reg[8:0] c_out;always@(posedge mclk, negedge rst_n)beginif(!rst_n)c_out <= 9'h0;elsec_out <= a_in + b_in;endendmodule请建立工程,将源程序编译通过.1.设置第三方EDA工具在Tools -> Options中设置ModelSim的安装路径,注意要设置到win32文件夹(64位软件对应的就是win64)。
建立一个工程(依然以加法器为例)。
在Assignments -> Settings中设置仿真工具为ModelSim。
这样Quartus就能无缝调用ModelSim了。
当然也可以在建立工程的时候就设置仿真工具。
2.编写Testbench说到Testbench,你可以叫它Testbench,或者Testbenches,但不是Test Bench。
说起来,就连Quartus也没注意这个问题,至于原因嘛参见Common Mistakes In Technical Texts一文。
文章中还列举了些别的错误用语,包括Flip-flop不能写成Flipflop,等等。
文章链接:/papers/Technical_Text_Mistakes.pdf我们可以通过Quartus自动生成一个Testbench的模板,选择Processing -> Start -> Start Test Bench Template Writer,等待完成后,在导航栏中打开刚才生成的Testbench,默认是保存在simulation\modelsim文件夹下的.vt格式文件。
testbench与dut最常用仿真软件教学摘要:1.引言2.testbench 的定义和作用3.DUT 的定义和作用4.最常用的仿真软件5.教学方法与实践6.总结正文:1.引言随着电子技术的快速发展,FPGA 设计和验证方法也在不断进步。
在FPGA 设计过程中,testbench 和DUT 仿真扮演着非常重要的角色。
本文将介绍testbench 与DUT 的概念,以及最常用的仿真软件,并探讨如何进行有效的教学。
2.testbench 的定义和作用Testbench(测试平台)是一种用于验证FPGA 设计的工具,它包含了一个激励源、激励源产生器、激励发射器、监控器、计分板和算法模型等组件。
Testbench 的主要作用是生成测试数据,并将测试数据输入到DUT(设备底层模型)中,通过对比DUT 的输出结果和预期结果,来判断FPGA 设计是否正确。
3.DUT 的定义和作用DUT(Device Under Test)是指在测试过程中需要验证的设备或电路。
在FPGA 设计中,DUT 通常是指设计人员所设计的FPGA 硬件电路。
测试过程中,DUT 将接收到来自testbench 的测试数据,并根据这些数据产生相应的输出结果。
通过比较DUT 的输出结果与预期结果,可以评估FPGA 设计的正确性。
4.最常用的仿真软件在FPGA 设计过程中,最常用的仿真软件包括ModelSim、Quartus 和VCS 等。
这些仿真软件可以模拟DUT 的行为,并提供与实际硬件相似的仿真环境。
设计人员可以在这些软件中编写testbench,并进行仿真验证。
5.教学方法与实践在进行testbench 与DUT 仿真教学时,应首先介绍testbench 和DUT 的基本概念,以及它们在FPGA 设计中的作用。
然后,通过实例演示如何使用仿真软件编写testbench,并进行仿真验证。
在学生掌握基本方法后,可以让他们自己编写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;】只是定义了文件变量名,并没有给赋予初值。
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具有最高的效率。
`timescale 1ns/1ps // 定义时间单位和精度
//定义仿真时间
initial begin
#10000 finish;
end
//设计顶层模块testbench
module testbench;
//定义内部的信号变量以及类型
wire [7:0]count; //线型定义输出端,连接各模块的输出端口,用线连接没有记忆reg clk; //寄存器定义激励信号,连接各模块的输入端口,具有记忆功能reg reset; //两个最基本的激励信号
//固定参数的赋值,状态的编码
/***parameter tpd_reset_to_count = 3 ;
parameter tpd_clk_to_count = 2 ; **/
//变量初始化
/**initial begin
a=b;
b=c;
c=d;
end **/
//时钟设置
always #500 clk=~clk;
initial
begin
clk =1;
reset=0; //一般是低电平复位
#100
clk =0;
reset=1;
end
//调用函数用modelsim生成fsdb文件
initial
begin
$fsdbDumpfile("wave_test.fsdb");
$fsdbDumpvars(0);
end
//调用模块与顶层模块的各个端口的连接(一一对应时自动连接)
filename u1(
.cp(clk),
.clr(reset),
.RSTSM(),
.DQ_IN(),
.MASTER_CNT(),
.SLA VE_CNT()
);
//调用输出图像的函数
integer fid;
initial
begin
fid=$fopen("report.txt","w+");
#1000000
$fclose(fid);
end
always @ (posedge clk negedge reset) $display(fid,"timerh=%d",timerh);
endmodule //结束顶层模块。