VIVADO中测试仿真代码基本书写规则

在VIVADO中设计好一个小型项目时,为了验证其功能性,最好的测试方法便是使用TestBench和HDL仿真器来验证其正确性。一般TestBench需要包含这些部分:实例化待测试设计、使用测试向量激励设计、将结果输出到终端或波形窗口便于可视化观察、比较实际结果和预期结果。

1.1 生成时钟信号

在时序电路中,首先需要生成时钟信号。
使用系统时钟的设计在TestBench中必须要生成时钟信号,该功能实现起来也非常简单,示例代码如下:
parameter ClockPeriod = 10;//定义变量参数,便于后续修改时钟周期;
always #(ClockPeriod/2) Clock = ~Clock;

1.2 生成测试激励信号

只有给设计激励数据,才能得到验证结果。提供激励的方法有两种,绝对时间激励以仿真时刻0为基准,给信号赋值,示例如下:

initial beginreset = 1;load = 0;count = 0;//仿真0时刻的一系列初始值;#100 reset = 0;//延迟100个单位后变化;#20 load = 1;//再延迟20个单位后变化;#20 count = 1;//再延迟20个单位后变化;
end

“#”用于指定等待的延迟时间,之后才会执行下一个激励。相对时间激励给信号一个初始值,直到某一事件发生后才触发激励赋值,示例如下:

always @ (posedge clk)tb_cnt <= tb_cnt + 1;initial beginif (tb_cnt <= 5) beginreset = 1;load = 0;count = 0;endelse beginreset = 0;load = 1;count = 1;end
end

根据需要,可以同时使用两种方法。每一个initial块、always块之间都是并行工作的关系,但在initial块内部是顺序地处理事件。因此复杂的激励序列应该分散到多个initial或always块中,以提高代码可读性和可维护性。

1.3 实例化待测模块

所谓实例化,便是让测试模块与源文件进行关联,常用格式为:
. 源文件输入或输出端口(测试文件输入输出端口)//点,一定不能省略;

1.4 书写格式

module Test_bench();//声明测试模块名;由于是外部输入,所以括号内什么都不写;
信号或变量声明定义
逻辑设计中输入对应reg型,//便于对其值进行操作;
逻辑设计中输出对应wire型,
使用initial 或者always 语句产生激励,
例化待测试模块,
监控和比较输出响应
endmodule
每个initial块之间都从0时刻开始并行执行。stop用来指示仿真器停止TestBench仿真(建议每个TestBench中都有至少一个stop用来指示仿真器停止TestBench仿真(建议每个TestBench中都有至少一个stop用来指示仿真器停止TestBench仿真(建议每个TestBench中都有至少一个stop)。
注意:
避免使用无限循环:仿真器调度事件时,会增加CPU和内存的使用率,仿真进程也会变慢。尽量不要使用无限循环。
将激励分散到多个逻辑块中:Verilog中的每个initial块都是并行的,相对于仿真时刻0开始运行。将不相关的激励分散到独立的块中,在编写、维护和更新testbench代码时会更有效率。
下面将进行实际的代码举例,注释也尽量通俗易懂:

1.5 四位全加器的实现

(1)源文件代码

`timescale 1ns / 1ps
module add_4(input [3:0] inb,input [3:0] ina,input cin,output [3:0] sum,output cout);assign {cout ,sum} =ina+inb+cin;
endmodule

(2)测试文件代码

`timescale 1ns / 1ps
module add_4_tb;reg [3:0] a,b;//测试输入信号定义为reg型,便于对其值进行操作reg cin;wire [3:0] sum;//测试输出信号定义为wire型wire cout;integer i,j;  add_4 uut(//例化源文件.ina(a),.inb(b),.cin(cin),.sum(sum),.cout(cout));always #5 cin=~cin;//设定cin的取值initial begina=0;b=0;cin=0;for (i=1;i<16;i=i+1)#10 a=i;//设定a 的值endinitial beginfor (j=1;j<16;j=j+1)#10 b=j;//设定b的值end
endmodule

仿真图如下所示

由上图可以很清楚的看出,cin每隔5ns翻转一次,i,j每隔10ns自增一次,并将其值分别赋给a,b;sum为a,b,cin三者之和,当其增加到f时,发生进位,cout加1;i,j至15时,不再改变(刚好为150ns),同时a,b,的值也不再改变,sum的值随着cin而变化;,此时未加$stop可见系统会一直运行下去;

加了#300 ;$stop;之后,可见系统在150ns之后,又延时了300ns,至450ns处停止运行;仿真图如下所示:

1.6四位计数器的实现

(1)源代码

module count4(output[3:0] out,input reset,input clk);reg[3:0] out;always @(posedge clk)//上升沿触发beginif (reset) //高电平复位out<=0; //同步复位else
out<=out+1; //计数end
endmodule

(2)测试代码模块

`timescale 1ns/1ns
module coun4_tp;reg tb_clk,tb_reset; //测试输入信号定义为 reg 型wire[3:0] out; //测试输出信号定义为 wire 型parameter DELY=100;count4 uut(.clk(tb_clk),.reset(tb_reset),.out(out)); //调用测试对象always #(DELY/2) tb_clk = ~tb_clk; //产生时钟波形,每个50ns翻转一次initialbegin //激励信号定义tb_clk =0; tb_reset=0;//初始值#DELY tb_reset=1;//100ns之后,高电平复位#DELY tb_reset=0;//再过100ns后,低电平继续计数#500; $stop;end
endmodule

仿真图如下所示:
加了500ns延迟之后停止

1.7 移位寄存器的实现

(1)源代码

module shift_reg(input clock,input reset,input load,input [1:0] sel,input [4:0] data,output [4:0] shiftreg);reg [4:0] shiftreg;always @ (posedge clock)  begin//上升沿触发if (reset)//高电平复位shiftreg = 0;else if (load)//加载信号shiftreg = data;else//不复位也不加载时,看sel值case (sel)2'b00 : shiftreg = shiftreg;//不变2'b01 : shiftreg = shiftreg << 1;//左移2'b10 : shiftreg = shiftreg >> 1;//右移default : shiftreg = shiftreg;//其他情况也不变endcaseend
endmodule

(2)测试代码

module tb_shift_reg;reg clock;//对reg型变量进行赋值reg load;reg reset; // 申明信号wire [4:0] shiftreg;//wire型为输出结果reg [4:0] data;reg [1:0] sel;shift_reg uut(//例化待测模块.clock (clock),.load (load),.reset (reset),.shiftreg (shiftreg),.data (data),.sel (sel));always # 50 clock=~clock;//建立时钟initial begin   // 提供激励reset = 1;//赋初值,系统处于复位状态data = 5'b00000;load = 0;clock=0;sel = 2'b00;#200//200ns后开始加载数据此时加载的应该全为0,因为data=0reset = 0;load = 1;#200data = 5'b00001;//此时shiftreg值为1#100//再过100ns停止加载,同时给sel赋值sel = 2'b01;//此时shiftreg左移一位,变为10;load = 0;#200sel = 2'b10;//右移变为1;end
endmodule

仿真图如下所示:

由仿真图可以看出:
时钟每个50ns翻转一次,初值load=0,reset=1,data=0,sel=0;shiftreg为wire型,不能对其赋值,所以其初始值为未知xx;延续200ns;
然后,reset=0,load=1,开始讲data内的值加载进shiftreg;data=00=shiftreg;延迟200ns;
然后,data=01,上升沿时,赋给shiftreg延迟100ns,shiftreg=01;此时信号到达500ns;
然后,load=0,停止加载;sel=01,shiftreg左移变为02(550ns上升沿);再左移04,(650ns,因为是延迟200ns)
最后sel=10,开始右移,又变为02(750ns),变为01(850ns)直至变为0(950ns);
展开后仿真图如下所示:

总结:所谓测试仿真代码的书写,就是另外建立一个工程来验证源代码的功能是否能够正确完成;所以必须要有输入输出的例化,起到关联作用。

测试仿真代码Testbanch的编写(一)相关推荐

  1. zedboard板子上呼吸灯的实现(第一版)仿真代码的实现

    为了便于仿真的实现,定义周期数值period_cnt缩小为50,每次改变的数值duty_cycle定义为5,这两个数值本来可以定义在参数中,懒得重写代码直接修改了数值. module breathe_ ...

  2. 如何编写可测试的代码 哈利勒的方法论

    Understanding how to write testable code is one of the biggest frustrations I had when I finished sc ...

  3. 单元测试:如何编写可测试的代码及其重要性

    原文来自互联网,由长沙DotNET技术社区编译.如译文侵犯您的署名权或版权,请联系小编,小编将在24小时内删除.限于译者的能力有限,个别语句翻译略显生硬,还请见谅. 作者:谢尔盖·科洛迪(SERGEY ...

  4. .NET Core TDD前传: 编写易于测试的代码 -- 缝

    有时候不是我们不想做单元测试, 而是这代码写的实在是没法测试.... 举个例子, 如果一辆汽车在产出后没完成测试, 那么没人敢去驾驶它. 代码也是一样的, 如果项目未能进行该做的测试, 那么客户就不敢 ...

  5. 在Diamond编写仿真代码后,通过Modelsim进行仿真,无波形。

    此处展示简单的与非门电路代码 1.设计文件代码 2.测试文件代码(testbench) 如截图所示,两处代码第一行都是AB_not_2, 即如果你所写的测试文件与设计文件的此处代码的名字不相同,那么进 ...

  6. .NET Core TDD 前传: 编写易于测试的代码 -- 全局状态

    第1篇: 讲述了如何创造"缝".  "缝"(seam)是需要知道的概念. 第2篇, 避免在构建对象时写出不易测试的代码. 第3篇, 依赖项和迪米特法则. 本文是 ...

  7. .NET Core TDD 前传: 编写易于测试的代码 -- 依赖项

    第1篇: 讲述了如何创造"缝".  "缝"(seam)是需要知道的概念. 第2篇, 避免在构建对象时写出不易测试的代码. 本文是第3篇, 讲述依赖项和迪米特法则 ...

  8. .NET Core TDD 前传: 编写易于测试的代码 -- 构建对象

    该系列第1篇: 讲述了如何创造"缝".  "缝"(seam)是需要知道的概念. 本文是第2篇, 介绍的是如何避免在构建对象时写出不易测试的代码. 本文的概念性内 ...

  9. 数字集成电路设计(五、仿真验证与 Testbench 编写)(一)

    文章目录 引言 1. Verilog HDL 电路仿真和验证概述 2. Verilog HDL测试程序设计基础 2.1 Testbench及其结构 2.2 测试平台举例 2.2.1 组合电路仿真环境搭 ...

最新文章

  1. SpringMVC之Controller查找(Spring4.0.3/Spring5.0.4源码进化对比)
  2. java--迭代(一)Iterator和Iterable接口
  3. 华为的研发给我们什么启示?
  4. fritzing导入元件_超屌的 fritzing 新建元件
  5. mysql 链式查询_MySQL的链接查询
  6. JavaScript中的arguments对象
  7. ORA-29807: specified operator does not exist
  8. 基于 Flink 构建 CEP 引擎的挑战和实践
  9. 音乐推荐系统参考资料
  10. Dbgview退出再打开无法使用的解决办法
  11. android模拟器root权限获取,如何在Android模拟器上获得root访问权限?
  12. Android Compose 实现渐变背景色
  13. vue.js微信公众号登录,获取当前用户openid等基本信息
  14. Java实现图片与Base64编码互转
  15. python中成语接龙游戏_python——成语接龙小游戏
  16. 构建基于Jenkins + Github的持续集成环境
  17. c语言循环计算分式加减乘除混合运算,计算()_分式的加减乘除混合运算及分式的化简_中学题库-沪江中学学科网...
  18. 华为新系统鸿蒙接入,华为新系统来了!鸿蒙OS+EMUI 11,设备协同无缝连接…
  19. Another exception was thrown: There are multiple heroes that share the same tag w
  20. 如何清洁保养条码扫描器

热门文章

  1. Qt版连连看之极速连连看:界面设计(一)QSS更换主题
  2. 魅蓝note5系统更新服务器异常,魅族魅蓝Note5系统运行速度变慢变的卡顿了_怎么通过刷机解决...
  3. android微信首页切换界面
  4. UIBezierPath CGContextSaveGState: invalid context 0x0. This is a serious error.
  5. 30岁,提了离职。最终还是回老家了,北京攒下回龙观一套房子,一个北京车牌。拜拜!...
  6. firebase到底怎么用android
  7. 社区团购系统社区拼团系统开发需求与开发流程介绍
  8. docker打包报permission denied解决方法
  9. 在Unity2022.3.7中集成ET 7.2 + HybridCLR 0.10.4 + XAsset 2022.2 + EUI 实现ECS编码,C#代码热更,资源热更,UI管理系统的基础框架
  10. ios webView 打开 ppt pdf