ise自动生成的testbench没有自己ise添加约束信号名是怎么回事

verilog ise测试文件内怎么定义变量啊_百度知道
verilog ise测试文件内怎么定义变量啊
// Outputs
wire [2:0]
wire [2:0]
wire [1:0]
// Instantiate the Unit Under Test (UUT)
vga5 uut (
.clk(clk),
我有更好的答案
在ISE下创建Verilog Test Fixture其实就是写测试激励文件(TestBench),没区别。Add stimulus这部分是测试激励文件的核心,需要向被测试模块中所涉及的逻辑提供全面的测试激励,以全面验证逻辑设计的正确性。
软件工程师
时钟别这样生成:给你个方式,always #1 clk &= ~
// Wait 100 ns for global reset to finish
always #1 clk &= ~
// Add stimulus here end
endmodule我按你的改了可还是说&E:/ise/vga1/vga5/gj.v& Line 59: Syntax error near &always&.
initial里面是不能套always的,initial的意思是仿真开始时执行一次,always是满足条件一直执行。所以你应该再initial里面赋一下初始值clk &= 0;在initial结束后写上always #1 clk &= ~
为什么输入有了输出没有啊
这么low的问题还没分,孩子,建议你好好看看书,不懂的再来问吧~
书上关于仿真的东西真的很少基本没有我加了10分帮帮忙吧
红线代表的是不定态,这是错误的,从你的timescale来看应该是1ns/1ps吧,你看你截的刻度,一个周期都没有,把时间尺度拉开了看看。然后左边的信号名没截出来,不错问题也很明显,你例化的module uut()连的全是wire,你都没有输入向量怎么测?
谢谢啊可是这个程序输入就只有clk和sw两个啊
不定态肯定是你uut这个模块的问题,你把这个模块好好理解下就知道了。应该不止2个输入
本回答被提问者采纳
reg [15:0] 语句应往前移到initial 语句之前
为您推荐:
其他类似问题
verilog的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。VHDL上机手册(基于Xilinx_ISE)_百度文库
两大类热门资源免费畅读
续费一年阅读会员,立省24元!
评价文档:
VHDL上机手册(基于Xilinx_ISE)
&&VHDL上机手册
大小:747.00KB
登录百度文库,专享文档复制特权,财富值每天免费拿!
你可能喜欢你的位置:
&& 详细内容
赛灵思高层次综合工具加速FPGA设计
热度467票&&浏览5916次
时间:日 17:27
作者:Sharad Sinha博士生新加坡南洋理工大学 sharad_sinha@pmail.ntu.edu.sg
Vivado HLS配合C语言等高级语言能帮助您在FPGA上快速实现算法。 高层次综合(HLS)是指自动综合最初用C、C++或SystemC语言描述的数字设计。工程师之所以对高层次综合如此感兴趣,不仅是因为它能让工程师在较高的抽象层面上工作,而且还因为它能方便地生成多种设计解决方案。利用HLS,您能探索各种可能性,分析面积和性能特点,最终确定一个方案在FPGA芯片上实现算法。举例来说,您能探索将存储器映射到Block RAM(BRAM)或分布式RAM上有什么不同的影响,或者分析回路展开以及其它回路相关优化有什么效果,而且不必手动生成不同的寄存器传输级(RTL)设计。您所要做的仅仅是在C/C++/SystemC设计中设置相关指令而已。 赛灵思在其最新发布的Vivado™工具套件中推出了HLS工具。Vivado HLS是AutoESL工具的品牌转型重塑,可提供众多技术帮助您优化C/C++/SystemC代码以实现目标性能。这样的HLS工具就能帮助您在FPGA上快速实现算法,无需借助基于Verilog和VHDL等硬件描述语言的非常耗时的RTL设计方法。为了帮助用户了解Vivado HLS如何工作,我们不妨以矩阵乘法设计为例逐步剖析从设计描述(C/C++/SystemC)到FPGA实现整个端对端综合流程。矩阵乘法在许多应用中都很常见,并广泛用于图像和视频处理、科学计算和数字通信。本项目中的所有结果均使用Vivado HLS 2012.4生成,搭配使用赛灵思 ISE®软件(14.4版)进行物理综合和布局布线。此外,这一流程还采用了ModelSim和GCC-4.2.1-mingw32vc9进行RTL协同仿真。图1显示了简单的综合流程,从C/C++/SystemC设计开始。C/C++/SystemC testbench用于验证设计功能的正确性,同时还可用于RTL和C的协同仿真。协同仿真包括验证生成的RTL设计(.v或.vhd)功能,这要使用C/C++/SystemC测试平台而不是RTL测试平台或者采用e或Vera验证语言编写的测试平台。时钟周期约束设置了设计应该运行的目标时钟周期。设计将被映射到目标FPGA器件——赛灵思FPGA上。
C语言的矩阵乘法为了充分利用我们的矩阵乘法实例,我们将探索矩阵乘法C语言实现方案的各种修订版本,从而展示它们对综合设计的影响。这一过程将凸显您在使用HLS进行原型设计和实际设计时需要注意的重要问题。我们将跳过创建工程的有关步骤,因为您能很方便地在工具文档中找到相关参考材料。我们将重点介绍设计和实现等方面。在典型的Vivado HLS流程中,我们需要三个C/C++文件:源文件(包括待综合的C函数)、头文件和通过main()函数调用描述testbench的文件。头文件不仅包括源文件中使用的函数的声明,也包括支持具有特定位宽的用户定义数据类型的指令。这也使得设计人员能够采用与C/C++所定义标准位宽不同的位宽。举例来说,整形数据类型(int)在C语言中通常为32位长,但是在Vivado HLS中您可指定用户定义的数据类型,例如只使用16位的“data”。图2显示了用于矩阵乘法的简单C函数。两个矩阵mat1和mat2进行乘法。为了简单起见,两个矩阵大小一样,都是两行两列。 在HLS流程中执行的步骤如下:• 第一步:创建工程• 第二步:测试功能• 第三步:综合• 第四步:RTL协同仿真• 第五步:导出RTL / RTL实现第一步编译工程并在不同的设计文件中测试语法错误等。第二步测试待实现的函数(在源文件中)功能是否正确。在这一步骤中您将使用testbench执行函数调用,验证其功能是否正确。如果功能验证失败,您就需要返回来修改设计文件。第三步进行综合,Vivado HLS综合源文件中定义的函数。这一步的输出包括C函数的Verilog和VHDL代码(RTL设计),也包括目标FPGA的资源利用率估算和时钟周期估算。此外,Vivado HLS还可生成latency估算和回路相关的度量指标等。第四步是使用C testbench仿真生成的RTL。这一步叫做RTL协同仿真,因为工具采用的就是之前用于验证C源代码的testbench,现在则测试RTL的功能正确性。要成功完成这一步,您系统(Windows或Linux)中的PATH环境变量应包含ModelSim安装的路径。此外,您还应在ModelSim安装文件夹中包含GCC-4.2.1-mingw32vc9套件。最后,第五步就要将RTL导出为IP模块,用于更大的设计中,并由其它赛灵思工具进行处理。您可将RTL导出为IP-XACT格式的IP模块,也可导出为System Generator IP模块或pcore格式的IP模块,进而用于赛灵思嵌入式设计套件。导出Vivado生成的RTL时,您可以选择工具的“评估”选项来评估布局布线后的性能并且运行RTL实现。在此情况下, Vivado HLS工具会调用赛灵思ISE工具。要实现这一目的,您的系统PATH环境变量需包括ISE安装路径,Vivado HLS将会搜索ISE安装。当然,您也不一定非要将Vivado生成的RTL导出为以上三种格式之一的IP模块不可。导出的格式文件可放在三个不同路径下://impl/或project_directory&//impl/或//impl/。此外,您也可在较大设计中使用Vivado生成的RTL,或者将其本身用作顶层设计。当较大设计中例化导出的RTL时,您应注意相关接口要求。
当综合图2中的C函数时,您将获得如图3所示的RTL级实现方案。您会发现,实现方案中的矩阵1和矩阵2的元素被读取到函数,并且积矩阵的元素被写出。这样,实现方案假定“矩阵乘法”实体以外的存储器能用来存储矩阵1、矩阵2和乘积矩阵的元素。表1介绍了信号描述,表2则介绍了设计度量指标。表2:用于图3所示设计的设计度量指标 设计度量指标 器件:XC6VCX75TFF784-2 DSP48E 1 查找表 44 触发器 61 实现的最佳时钟周期(ns) 2.856 时延 69 吞吐量(初始间隔) 69 表1:面向图3中设计的信号描述信号 描述 matleft_ce0 矩阵1存储器的芯片使能 matleft_q0[15:0] 矩阵1的16位元素 matleft_address[1:0] 矩阵1存储器的读地址 matright_ce0 矩阵2存储器的芯片使能 matright_q0[15:0] 矩阵2的16位元素 matright_address[1:0] 矩阵2存储器的读地址 product_ce0 积矩阵的存储器的芯片使能 product_we0 积矩阵的存储器的写使能 product_d0[15:0] 积矩阵存储器的写数据 product_q0[15:0] 积矩阵存储器的读数据 product_address0[1:0] 积矩阵要读写数据的地址 ap_clk 设计的时钟信号 ap_rst 设计的高有效同步复位信号 ap_start 开始计算的开始信号 ap_done 计算结束和输出就绪的完成信号 ap_idle 表示实体(设计)空闲的空闲信号 ap_ready 表示设计为新输入数据做好准备,与ap_idle配合使用 在表1中,start、done和idle信号与设计中控制数据路径的有限状态机(FSM)有关。您会发现,Vivado HLS生成的Verilog假定运算始于start信号,并且输出数据在ap_done信号从低变高开始有效。Vivado HLS生成的Verilog/VHDL将始终保持至少三个基本信号:ap_start、ap_done和ap_idle,此外还有ap_clk信号。这意味着不管您使用Vivado HLS实现什么设计,设计latency都会限制您的流吞吐量。图2中的设计latency为69个时钟周期,目标时钟周期为3纳秒。这意味着在此特定案例中,所有积矩阵元素需要69个时钟周期可输出。这样,您在至少69个时钟周期前不能为设计提供新一组的输入矩阵。图3中所示的实现方案现在可能并不是您在FPGA上实现矩阵乘法时所预想的结果。您或许希望一款实现方案能让您输入矩阵,并在内部进行存储和计算,随后读取积矩阵元素。这显然是图2所示实现方案无法做到的。该实现方案需要外部存储器提供矩阵数据的输入和输出。 调整代码图4中的代码能够满足您的需求,它是源文件的一部分,应该属于C++文件而非此前的C文件。您应在头文件matrixmultiply.h中包含另外两个相关头文件:hls_stream.h和ap_int.h。请注意,在图2中,当源文件为C文件时,头文件包含了ap_cint.h。头文件ap_int.h和ap_cint.h有助于分别为C++和C源文件定义用户定义的任意位宽的数据类型。需要头文件hls_stream.h来充分利用流接口,并且只有在源文件为C++语言时才能使用。图4:用于矩阵乘法的重组源代码 为了让设计只接收输入矩阵流,并输出积矩阵流,您应在代码中实现读和写数据流。流接口就像FIFO。默认情况下这个FIFO的深度为1。 表3 - 图5中设计的信号描述信号 &描述 d_mat1_V_read &设计为矩阵1(左侧矩阵)输入做好准备时的信号 d_mat1_V_dout [15:0] &矩阵1的16位流元素 d_mat1_V_empty &通知设计矩阵1没有更多元素的信号 d_mat2_V_read &设计为矩阵2(右侧矩阵)输入做好准备时的信号 d_mat2_V_dout [15:0] &矩阵2的16位流元素 d_mat2_V_empty &通知设计矩阵2没有更多元素的信号 d_product_V_din [15:0] &积矩阵的16位输出元素 d_product_V_full_n &通知设计积矩阵应该被写入的信号 d_product_V_write &显示积矩阵正在被写入数据的信号 ap_clk &设计的时钟信号 ap_rst &设计的高有效同步复位信号 ap_start &开始计算的开始信号 ap_done &计算结束和准备好信号输出的完成信号 ap_idle &表明实体(设计)空闲的空闲信号 ap_ready &表示设计为新输入数据做好准备,与ap_idle配合使用 表4:图5所示设计的设计度量指标 器件:XC6VCX75TFF784-2设计参数 无BRAM或无分布式RAM存储矩阵 单端口BRAM存储矩阵 分布式RAM(LUT实现)存储矩阵 DSP48E 1 1 1 查询表 185 109 179 触发器 331 102 190 BRAM 0 3 0 实现的最佳时钟周期(纳秒) 2.886 3.216 2.952 时延 84 116 104 吞吐量(初始间隔) 84 116 104 为了让设计只接受输入矩阵流,并输出积矩阵流,您应在代码中实现读和写数据流。代码hls::stream&& stream_name用于为读和写数据流命名。这样,d_mat1和d_mat2为读取流而d_product为写入流。流接口就像FIFO那样工作。默认情况下,FIFO的深度为1。您应在Vivado HLS指令面板中通过选择定义的数据流设置深度。对于图4中的代码而言,每个数据流的深度都为4个数据单元。请注意,这里的(i,j)回路在(p,q)回路之前执行,这是C++代码的顺序特性使然。因此,d_mat2数据流会在d_mat1数据流之后填满。完成数据流接口后,您可应用指令RESOURCE并通过指令面板选择一个核,从而选择将矩阵映射到BRAM。否则将用触发器和查找表(LUT)实现矩阵。请注意,指令面板只有当源文件在综合视图中保持有效时才是有效的。 图5显示了图4中代码的设计实现情况。表3介绍了设计接口上可用的信号情况。在表3中,d_product_V_full_n是低有效信号,当需要通知内核积矩阵已满时该信号为低。但在实现方案中通常不需要这样。表4显示了3纳秒时钟周期约束下布局布线后的不同设计度量指标,包含了矩阵阵列映射到BRAM或分布式RAM的情况和未映射的情况。您从表4中可以看到,矩阵映射到单端口BRAM时,设计无法满足3纳秒的时序约束。表中专门包含了这个结果,说明您可用这种方法生成具有不同面积—时序参数的各种设计。此外,您也可从表1看出,虽然图2中代码的时延为69个时钟周期,低于图4中调整后的代码的设计方案,但这种设计需要矩阵乘法实体以外的存储器,这一点我们在上面已经解释过了。 实现方案的精度就这里显示的结果而言,我将“data”这种数据类型定义为16位宽。因此,所有矩阵元素(左、右和积矩阵)都为16位宽。矩阵乘法和加法运算不能实现全精度。您可选择在头文件中定义另一种32位宽的数据类型data_t1,积矩阵的所有元素都采用这种数据类型,因为16位数(左侧矩阵元素)乘以另一个16位数(右侧矩阵元素)最多得到32位宽。这样,资源利用率和时序结果将不同于表1和表4中的结果。调整后的源代码显示出同样的源文件会带来多种不同设计解决方案。在本例中,一个设计解决方案采用BRAM,而另一个没有采用。在每个Vivado HLS工程目录中,您会看到Vivado HLS为不同的解决方案生成了不同的目录。在每个解决方案目录中都有一个名叫impl(也就是implementation,实现方案)的子目录。在这个子目录中,您会看到名为Verilog或VHDL的目录,具体取决于RTL实现阶段使用什么样的源代码。这个子目录中也包含赛灵思ISE工程文件(文件扩展名为.xise)。如果Vivado HLS生成的设计是您的顶层设计,那么您可以双击这个文件来启动赛灵思ISE运行这个解决方案,并生成用于门级时序和功能仿真的布局布线后模型。但您在Vivado HLS中不能做这种仿真。在ISE中启动解决方案后,您应给设计分配I/O引脚。随后您可在ISE Project Navigator中选择“Generating Programming File”以生成比特流。在这一练习中,我们一步步完成了Vivado HLS一个实际的端对端流程,并在FPGA上实现算法。对于Vivado HLS中的许多高级特性而言,您应了解您需要什么样的硬件架构,从而进行源代码的调整。如需了解更多详情,《Vivado高层次综合教程》(UG871;
http://www.xilinx.com/support/documentation/sw_manuals/xilinx2012_2/ug87... )和《Vivado设计套件用户指南》(UG002;
http://www.xilinx.com/support/documentation/sw_manuals/xil-inx2012_2/ug9...
)这两个技术文档对您大有裨益。
对本篇资讯内容的质量打分:
当前平均分:0.1 (160次打分)
【已经有210人表态】
[感动最多的]
[路过最多的]
[高兴最多的]
[难过最多的]
[搞笑最多的]
[愤怒最多的]
[无聊最多的]
[同情最多的]Testbench学习笔记
书写testbench是数字电路设计中不可或缺的一项设计方法,主要是提供的是激励。尽管现在各种开发工具都通过绘制波形图的方法生成测试激励,测试书写的代码,但是其不可移植性,不可通用性,还有有些功能无法是实现,如监视变量的值的变化,显示数据的状态等。
一个完整的testbench包含下列几个部分:
(1)module的定义,一般无输入输出端口。
(2)信号的定义,定义哪些是你要输入,输入的定义为reg类型,输出的定义为wire型
(3)实例化待测试的模块
(4)提供测试激励
1.如何书写测试激励;
(1)时钟信号的产生
&&&initial
&&&&&&begin
&&&&&&&&&clk&=&0;
&&&&&&forever
&&&&&&&&&#clk_period/2&clk&=&~&&
&&&&begin&
&&&&&&&#clk_period/2&clk&=&0;
&&&&&&&#clk_period/2&clk&=&1;&
&&&&&&&end
&&&&产生时钟的原理,是利用always或者是initial&+&forever产生不断重复的信号,构成时钟信号。
(2)复位信号的产生
复位信号就是在复位电平下延时一段时间,然后再将复位电平信号取反即可。如:
&&&&initial&
&&&&rst&=&0;
&&&&#&100;
&&&rst&=&1;
在实际应用将其封装为task,使用时掉调用即可。
&&调用如下:
&&&sys_time(100);&//复位100个时间单位
&任务的定义如下:
task&&sys_rst&;
&input&&[10:0]&rst_&&&//调用task的时候,将参数赋值给rst_time
&&&&rst&=&0;
&&&&#rst_time;
&rst_time&=&1;
(3)产生一种复杂的信号。如下面的实例产生一个vs和hs信号
//-------------------------------------------------------------------------------------
&parameter&&n&=&10;
//-------------------------------------------------------------------------------------&&
&&&&cmos_hs&=&1'b0;&&&//&time&0&时刻
&cmos_vs&=&1'b0;
&repeat(n)&&//重复n次
&&&&&&&begin
&&&&&#&200&&&cmos_vs&=&1'b1;&&&&//&time&200&
&&repeat(10*n)
&&&&&&begin
&&#100&&&cmos_hs&=&1'b1;&&&//time&300
&&#100&&&cmos_hs&=&1'b0;&&&//time&&700
&&#100&&&cmos_vs&=&1'b0;&&
&&&&&该程序段可以生成10个vs信号,每个vs信号下有100个hs信号。由于initial信号只能执行一次,所以为了得到有限的重复信号,可以采用repeat关键词得到。
这样基本上就可以完成一些简单的测试testbench了。
2.如何将我们的测试尽可能的简单明了化
&&&用Modelsim对Verilog&HDL进行仿真的人都会知道,看一大堆波形会很麻烦,如果代码变量很多,很复杂,出了问题都不知道问你在哪里,或者看了半天,发现图形是个错的。运用合适的方法将自己需要的变量以文本方式显示,监视变量的变化不很好嘛?
下面介绍几种常用的系统函数
&&(1)$time
&&&作用:返回所在模块的仿真时间,可以查看信号的出现的时间,用来把握信号的时序。
&&&如:$display(''the&time&is&%t'',$time)&;//显示当时的时间
&(2)$display
作用:&将需要显示的内容在命令栏显示出来
如:&$display("the&signal&is&%&d",ad);&//将ad信号以十进制的方式显示出来
&(3)$monitor
作用:监视变量的变化,一旦变量变化,则将变量显示出来
如:$monitor&("at&time&is&%t&and&the&signal&is&%b\n",$time&,&signal)&;
&&(3)&文件操作类
&&&&&$fopen
作用:打开一个文件面,对文件的操作
&$fdisplay
作用:在打开的文件里,写入显示的内容
&$fmonitor
作用:在打开的文件里,写入监视的变量变化时的内容
作用:关闭当前的内容
如:initial
&&&&&&Begin&:block&&//可以在内部声明局部变量
&&&&&&Integer&&out_file;
&&&&&&out_file&=&$fopen("data.out","w")&;&//打开data.out这个文件后,从第一行开始写,如果该文件没有,则首先创建该文件,然后再写。打开文件后返回out_file这个文件整形指针
&&&&&&$fdisplay(out_file,"at&the&time&is&%t&",$time);
&&&&&&.....
&&&&&&$fmonitor(out_file,"at&the&time&is&%t&and&the&signal&is&%b\n&",$time&,signal);
&&&&&&&......
&&&&&&$fclose(out_file);
我们为什么要写testbench?
经常看到论坛里有人问我们为什么要写testbench,总是觉得不好回答,下面是整理出来的一些理由供大家参考。与写testbench相对应的功能手段还有画波形图,两者相比,画波形图的方法更加直观和易于入门,那为什么我们还要写Testbench呢?原因有以下五点:第一,画波形图只能提供极低的功能覆盖。& & 画波形无法产生复杂的激励,因此它只产生极其有限的输入,从而只能对电路的极少数功能进行测试;而testbench以语言的方式描述激励源,容易进行高层次的抽象,可以产生各种激励源,轻松地实现远高于画波形图所能提供的功能覆盖率。以PCI转以太网电路设计为例,该设计并不复杂,但却已经需要考虑多种情况:PCI的配置读写、存储器读写等操作;以太网的短包、长包等。如果这些激励都用画波形图完成,其工作量是难以想象的;用testbench则可以轻松完成这些工作。第二,画波形无法实现验证自动化。& & 对于规模设计来说,仿真时间很长,如果一个需要仿真一天设计在检错时仅通过画波形图来观测,将几乎不能检查出任何错误;而testbench是以语言的方式进行描述的,能够很方便地实现对仿真结果的自动比较,并以文字的方式报告仿真结果。我们甚至可以在下班时开始仿真,然后第二天早上上班时再查看验证结果。第三,画波形图难于定位错误。& & 用画波形图进行仿真是一种原始的墨盒验证法,无法使用新的验证技术;而testbench可以通过在内部设置观测点,或者使用断言等技术,快速地定位问题。第四,画波形的可重用性和平台移植性极差。& & 如果将一个PCI转100Mb以太网的设计升级到PCI转1000Mb以太网,这时原来画的波形图将不得不重新设计,耗费大量的人力物力及时间;但若使用testbench,只需要进行一些小的修改就可以完成一个新的测试平台,极大地提高了验证效率。第五,通过画波形的验证速度极慢。& & Testbench的仿真速度比画波形图的方式快几个数量级,在Quartus下画波形需半个小时才能跑出来的仿真结果,在ModelSim下使用testbench可能只需几秒钟就可以完成。&
& 所以,在设计中除了那些极简单的设计(如调用厂商提供的MegaCore),推荐通过写testbench的方法来做功能验证。
=================================概念=========================
testbench是一种验证的手段。
首先,任何设计都是会有输入输出的。但是在软环境中没有激励输入,也不会对你设计的输出正确性进行评估。那么此时便有一种,模拟实际环境的输入激励和输出校验的一种“虚拟平台”的产生。在这个平台上你可以对你的设计从软件层面上进行分析和校验,这个就是testbench的含义。
==============================================================
======================初步认识=================================就初学而言,testbench更像一个激励的产生器。举例:一个ram,可能有几个input和output。分别列在下面。
clk,时钟输入
addr,地址输入
wen,写使能
data,数据输入
然后还有一个dataout的数据输出。那么你可以写一个文件,给clk,addr,wen,data送入你预想的一些信号,然后观察q的输出,看看ram是否工作正常。那么这个文件从一定意义上可以叫做"testbench"。
联想(帮助理解):从quartus里面你仿真,你可能对着那个画图一样的东西画上输入,然后编译以后看他的输出。对吧。那么在modelsim里面,我告诉你,可以不用画图了~,你只需要按照一定规则写一个.v或者.vhd的文件,这个文件可以给你的设计提供你预想的输入。这个就是testbench的文件。然后在modelsim这个特定的软件环境下,这个软件能根据你的代码给你的设计提供输入,又可以把你设计的输出在屏幕上显示出来给你debug。那么这个时候,一个在modelsim上的testbench就完成了。
狭义的总结一下:FPGA的testbench就是一个.v(verilog)或者.vhd(vhdl)的文件。这个文件能给你的设计提供激励,并能在一些专用的软件中提供良好的debug接口。这个就是一个testbench。
==============================================================
=====================高级应用================================关于testbench的高级应用。刚才说了初步的testbench。其实testbench是verification(验证)中的一个手段。验证是什么呢?举例:做鱼了,你往里面加了调料,然后再尝尝味道,这个就是验证的过程。同样你可以分成几个部分,一条鱼,好比你的设计,然后你给他一定的激励,也就是调料啦。然后你再尝一尝,看看鱼是不是达到你想要的味道了。那就是一种验证的手段,如果淡了。那么加点盐,再尝尝,这个就是反复验证。
testbench里面包含了三个东西:
1、激励生成。也就是我们刚才初级时候说的所谓的“testbench”。英文么就是simulator,这个只用来生成输出,他自己没有输入,只是按照一定的规律去给你的设计激励,激励通过设计的输入端口送到你的设计中。其余的事情不管。这里的激励,都是预先设想好的,比如根据某个协议,或者某种通信方式传递。
2、你的设计。英文可以叫做DUT:design under testbench或者DUV:design under verification。当然咯。这个是你主要目标。
3、输出校验。校验你的输出。英文叫markerboard,他所管的事情就是,接收你设计的输入,然后通过校验,找出对应的问题。然后报错,或者统计错误。等等。通俗的讲,你设计它就是把你自己解脱出来,让他来帮你找错误。他输出给你的可能就是通过打印啊,通知啊,等等方法了解你设计的正确性。
那么你有可能问了,这个东西用verilog或者VHDL能写么,modelsim里能用么?的确是可以的,有写甚至可以用c的代码通过程序接口来转换到modelsim里面来帮助验证。
========================高级应用结束==========================
最后小说两句:testbench是一个平台,帮助你从软件方面验证的。对于这个概念不需强求,等你自己的验证写多了,自然而然就会了解其中深刻的含义。先开始慢慢的写一些激励,然后再写写校验。到时候你收获的东西自然而然的能帮助你理解testbench和verification
测试平台是个没有输入输出端口的模块testbench
与输入端口相连接的变量定义为reg
与输出端口相连的定义为wire
$stop$finish
wait(z==1’b1);//
repeat(13) #5 clk =~ //13
forever @ (posedge clk) #3 x = $
initial$monitor (“%d is changed at
%t”,MUT.current,$time);//
initial$monitorMUTcurrent$monitor$monitor$monitoron
$monitoroff
@(z) $display(“Output changed at %t to
%b”,$time,z);zz,
@(z) $strobe(“Output changed at %t to
%b”,$time,z);//
repeat(5) #7 x = $
$random`; //-59~59
{$random}`; //0~59
初学TestBench
`timescale 1ns/10ps
//单位时间/精度
`include "adder.v"
module adder_
adder adder_t(&&
//调用待测模块
.sum(sum),
.c(count),
initial begin
a = 0; //初始值a=0
forever #20 a = ~a; //每经过20个单位时间,a取反
&& initial
b = 0;& //初始值b=0
forever #10 b = ~b; //每经过10个单位时间,b取反
initial begin
$monitor ($time,,,"%d + %d = {%d,%d}",a,b,cout,sum);
//监控输出
$monitor 输出打印显示
$stop停止当前仿真
$finish结束仿真,询问是否退出ModelSim
时钟产生方法:
&&&1.用intial语句
initial begin
&&&&&&&&&&&
clock = 0;
&&&&&&&&&&&
forever #10 clock = ~
2.用always语句
&&&&&&&&&&&
clock = 0;
&&&&&&&&&&&
#10 clock = ~
以上写法产生的时钟如下:
如何编写testbench的总结
如何编写testbench的总结(非常实用的总结)
1.激励的设置
相应于被测试模块的输入激励设置为reg型,输出相应设置为wire类型,双向端口inout在测试中需要进行处理。
方法1:为双向端口设置中间变量inout_reg作为该inout的输出寄存,inout口在testbench中要定义为wire型变量,然后用输出使能控制传输方向。
inout [0:0] bi_dir_
wire [0:0] bi_dir_
reg [0:0] bi_dir_port_
reg bi_dir_port_
bi_dir_port=bi_dir_port_oe?bi_dir_port_reg:1'
用bi_dir_port_oe控制端口数据方向,并利用中间变量寄存器改变其值。等于两个模块之间用inout双向口互连。往端口写(就是往模块里面输入)
方法2:使用force和release语句,这种方法不能准确反映双向端口的信号变化,但这种方法可以反映块内信号的变化。具体如示:
module test();
wire data_
force data_inout=1' //强制作为输入端口
...............
release data_ //释放输入端口
从文本文件中读取和写入向量
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_ // out_file
是一个文件描述,需要定义为 integer类型
out_file = $fopen ( " 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
C -- Ports of the specified scope and below, including library
AS -- Signals of the specified scope and below, excluding library
AC -- Signals of the specified scope and below, including library
cells 还有一个 M
,表示当前scope的memories, 可以跟上面的结合使用, "AM" "AMS" "AMC" 什么都不加表示当前scope的
$shm_close //关闭数据库
2). VCD数据库也可以记录在设计仿真过程中信号的变化. 它只记录你选择的信号的变化.
ex). $dumpfile("filename"); //打开数据库
$dumpvars(1, top.u1); //scope = top.u1, depth = 1
第一个参数表示深度, 为0时记录所有深度; 第二个参数表示scope,省略时表当前的scope.
$ //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“);
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的波形输出
$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之下所有层的所有数据信号
//产生随机数,seed是种子
$random(seed);
ex: din &= $random(20);
//仿真时间,为unsigned型的64位数据
time condition_happen_
condition_happen_time = $
$monitor($time,"data output = %d",
parameter para1 = 10,
para2 = 20,
para3 = 30;
//显示任务
$display();
//监视任务
$monitor();
//延迟模型
//describ pin-to-pin delay
endspecify
module nand_or(Y,A,B,C);
input A,B,C;
AND2 #0.2 (N,A,B);
OR2 #0.1 (Y,C,N);
(A*-&Y) = 0.2;
(B*-&Y) = 0.3;
(C*-&Y) = 0.1;
endspecify
//时间刻度
`timescale
单位时间/时间精确度
1.打开文件
integer file_
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_
file_id = $fread("file_path/file_name",
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循环的指标
generate for(i = 0; i & 4; i = i +
assign = din[i] = i % 2;
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)
tmp1 = sel ? A:C;
tmp2 = sel ? B:D;
always @(tmp1 or tmp2)
sum = tmp1 + tmp2;
******************************************************************************
//定义一个没有输入输出的module
reg …… //将DUT的输入定义为reg类型
wire…… //将DUT的输出定义为wire类型
//在这里例化DUT
…… //在这里添加激励(可以有多个这样的结构)
always…… //通常在这里定义时钟信号
//在这里添加比较语句(可选)
//在这里添加输出语句(在屏幕上显示仿真结果)
以下介绍一些书写Testbench的技巧:
1.如果激励中有一些重复的项目,可以考虑将这些语句编写成一个task,这样会给书写和仿真带来很大方便。例如,一个存储器的testbench的激励可以包含write,read等task。
2.如果DUT中包含双向信号(inout),在编写testbench时要注意。需要一个reg变量来表示其输入,还需要一个wire变量表示其输出。
3.如果initial块语句过于复杂,可以考虑将其分为互补相干的几个部分,用数个initial块来描述。在仿真时,这些initial块会并发运行。这样方便阅读和修改。
4.每个testbench都最好包含$stop语句,用以指明仿真何时结束。
最后提供一个简单的示例(转自Xilinx文档):
module shift_reg (clock, reset, load, sel, data,
shiftreg);
input [1:0]
input [4:0]
output [4:0]
always @ (posedge clock)
if (reset)
shiftreg = 0;
else if (load)
shiftreg =
case (sel)
2’b00 : shiftreg =
2’b01 : shiftreg = shiftreg
2’b10 : shiftreg = shiftreg
default : shiftreg =
Testbench:
// declare testbench
// declaration of signals
wire [4:0]
// instantiation of the shift_reg design
shift_reg dut(.clock (clock),
.load (load),
.reset (reset),
.shiftreg (shiftreg),
.data (data),
.sel (sel));
//this process block sets up the free running
initial begin
clock = 0;
forever #50 clock = ~
initial begin// this process block specifies the
reset = 1;
data = 5’b00000;
sel = 2’b00;
reset = 0;
data = 5’b00001;
sel = 2’b01;
sel = 2’b10;
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
$monitor("%t %b %b %b %b %b %b",
$realtime,
clock, reset, load, shiftreg, data,
有关testbench的一些问题
test_//task的定义,以task关键字开始,紧接后面是task的id,名字
input [1:0]&
//task的输入输出定义,用来和外面的变量进行交换,是通向外面的接口
output [1:0]
reg [1:0] task_a;
reg [1:0] task_b;& //因为task必须在过程语句中调用,所以其实参必须为reg类型的
&&& task_a =
&&& test_task
(task_a,task_b);//task的调用,直接调用,没有什么像module一样例化的东西
&&& #10 task_a =
&&& #20 task_a =
&&& test_task
(task_a,task_b);//同样可以改变task内部的值,和module不同,这是同一个task
&&& #10 task_a =
reg [1:0] task1_a;
reg [1:0] task1_b;
task test_task1;
output [1:0]
assign b = ~task1_a;//可以使用全局变量,不一定是task内部的变量
&& task1_a = 2'd0;
test_task1(task1_b);
&& #10 task1_a = 2'd1;
test_task1(task1_b);
&& #10 task1_a = 2'd2;
test_task1(task1_b);
&& #10 task1_a = 2'd3;
test_task1(task1_b);
task和module有点类似,都可以通过输入输出来和外面发生关系,这个时候module可以例化多次,这样就是不同的单元,和task还是有区别的。
1,task只能定义在module内部,不能单独在一个文件中,不能定义在module外面。
2,在task调用的是必须在过程性语句内部使用,initial,begin
3,task可以没有参数,直接使用全局变量来实现功能。
4,可以使用延时控制,可以调用其他task和函数。
函数:可以调用函数,不能调用任务,不可有时序控制。
function [1:0]
//只有一个返回值,invert,寄存器类型的
//input [1:0]
a;&&&&&&&&
//可以有一个输入,或者多个,或者没有输入
invert = 2'd3;
endfunction
reg [1:0] fun_a;
reg [1:0] fun_
&&& fun_a =
&&& fun_out =
invert();//(fun_a);//调用函数,函数返回一个值,必须在过程性语句中调用。
&&& #50 fun_a =
fun_out = invert();//(fun_a);
&&& #50 fun_a =
fun_out = invert();//(fun_a);
&&& #50 fun_a =
fun_out = invert();//(fun_a);
task test_task1;&&
//任务调用函数
output [1:0]
b = ~add(task1_a);
function [1:0]
//函数调用函数
input [1:0]
&invert = ~add(a);
endfunction
//显示和文件操作
& for(i=0;i&100;i=i+1)
if(a1 == 8'd50)
&&&&&&&&&&
$write("a1 is %d",a1);&&
&&&&&&&&&&
$write("\n\n\n\n\n\n");
&&&&&&&&&&
&&&&&&&&&&
$fwrite(f_id,"a1 is %d",a1);//写入文件
&&&&&&&&&&
$fwrite(f_id,"\n\n\n\n\n\n");
else if(a1 == 8'd70)
&&&&&&&&&&
$display("a1 is %d\n\n",a1);//显示
&&&&&&&&&&
$fdisplay(f_id,"a1 is %d\n\n",a1);//写入文件
else if (a1 == 8'd90)
$fclose(f_id);
#2 a1 = a1 +1;
&& $monitor("test
%d\n",a1);//变量变化就会显示
integer f_
&&& f_id =
$fopen("./test.txt");//打开一个文件
&& $strobe("tes1t
%d\n",a1);& //在时间步0结束的时候显示这一句
&&& cool =
4;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//这是时间步0要执行的,
&&& $strobe
("strobe cool1 is %d at time
%t\n",cool,$time);//这是时间步0要执行的,在时间步的最后显示
$display("cool1 is %d at time
%t\n",cool,$time);&&
//这是时间步0要执行的,
&&& #4 cool =
8;&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
//这是时间步4要执行的,
&&& $strobe
("strobe2 cool1 is %d at time
%t\n",cool,$time);//这是时间步4要执行的,
$display("cool2 is %d at time
%t\n",cool,$time);&&&&&&&&
//这是时间步4要执行的,
标签: &&&&
testbench的实现方法多样,而且还不断涌现出新方法,这些都是人们在为更好的验证设计做的努力。如og,systemC,systemverilog均可以,但是真正的实际应用中绝对不是单独应用,而是将他们结合起来,使你的验证更方便,更全面。
由于系统验证的庞大,我们还是从最简单的,最熟悉的上手,就先单独用VHDL语言来写仿真语言,当然VHDL语言我们已经比较熟悉了,但是有个比较大的区别是,我们以前都是尽量学习能够综合的语言,但是在仿真中经常会用到一些行为级描述的语言,他们是不能被综合成逻辑的,但是却绝对可以让我们的验证更加高效方便,但是我们也不单独来讨论VHDL中哪些语言是能够综合,哪些语言是不能综合的,重点将会放在testbench的一般结构,编写testbench的一般思想,以及更多的是实际接触,以实际的例子与前面的可综合逻辑相结合达到完整的系统设计的上的!
testbench的几种思路:
一、只在testbench中实例化DUT(design under
test),激励输入是在testbench中临时产生的,只能用于简单逻辑。优点:简单,易操作。缺点:复用性差
,效率低&& 模型如图1所示
二、DUT的输入由单独的一个文件产生,在testbench中实例化两上entity,可以复杂输入,简单输出的模块。模型如图2所示
三、DUT的输入与测试输出各由单独文件产生,在testbench由三个实例化模块产生,用于具有复杂输入以及输出的模块,模型如图3所示。
四、可以根据仿真输出来修改输入激励的,可以自动通过输出来修改输入,使验证更加准确。如图4所示的模型
五、有文件做为testbench的输入,输出的模型。仿真中需要顺序的输入大量数据,以及接收相应的数据,可以通过从文件中读入数据,然后将产生的数据存入文件,使复杂系统验证更加方便。模型如图5所示。
六、可以将激励同时输入自己设计的模块和已经验证了相同模块,比较二者输出。模型如图6所示。
本文来源于:电子工程世界
Testbench写法简要介绍
TestbenchQuartusTestbench
&&&&&&&&&&&&&&&&&&&&
&&&&&&&&&&&&&
&&&&&&&&&&&&&
&&&&&&&&&&&&&&&&&&&&&&&&
.Input_1&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
.Input_2&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
.Input_3&&&&&&&&&&&&&&&&&&&&&&&&&&&&&
.Output_1&&&&&&&&&&&&&&&&&&&&&&&&&&&
.Output_2&&&&&&&&&&&&&&&&&&&&&&&&&&&
.Output_3&&&&&&&&&&&&&&&&&&&&&&&&&&&
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

我要回帖

更多关于 ise添加ip 的文章

 

随机推荐