FPGA学习系列:仿真测试文件的编写

描述

之前有一篇文章介绍过仿真测试文件编写的步骤:

1.给A模块写测试,其测试模块的模块名为A_tb,比如原模块模块名叫做led,测试模块名就叫 led_tb;
2.复制A模块的所有输入输出端口,也就是I/O声明部分(input和output信号),注意这里不包括中间变量(reg型和wire型信号);将所有的input 改为 reg, output 改为 wire;
3.再把A模块的端口定义部分复制过来,包括 模块名到分号结束,进行模块例化;
4.测试模块的意义就是模拟输入信号,来验证原模块的输出信号是否符合代码逻辑,所以在测试模块里面需要写一个initial块模拟所有的输入变量,进行赋值操作;
5.如果有时钟,需要再产生一个时钟信号;
6.最后添加时间标识。

这篇文章就详细说一下怎么做,举得例子是上一篇二选一数据选择器的例子,大家可以动手做一做。

设计背景:

测试文件在我们的项目中格外的重要,比如我们要验证你的模块的正确性难道要不停的下板来验证吗,如果你的项目小还可以,如果编译一下超过10分钟了你难道不停的等待,修改中循坏下去吗,所以如果我们可以设计出我们的测试文件,那么先验证我们的系统,如果我们的逻辑都正确了,我们就可以下班来查看,如果还不正确那么我们就可以用quartus 中的工具signaltap来捕捉我们信号来验证,这些都会在我们以后的文档中给大家说明。

 

设计原理: 

我们的设计就是一个简单的2选一多路选择器,我们通过给这个简单的多路选择器来写测试文件,让大家对测试有一个简单的认识。

在架构中我们可以明白的看出我们设计的架构,我们的项目中有2个输入数据data_1,data_2,一个输入的选择位select,还有一个输出data_out。其实给这个架构写测试也就是激励,其实说白了就是给其写输入,当给其写好输入后,我们不就可以在仿真工具中验证其逻辑关系了。

 

设计架构图:

sel_1架构

仿真测试

总架构

 

仿真测试

设计代码:

我们写好的代码如下,大家看下,然后我们给大家讲解测试怎么写

模块

0 module sel_1(data_1, data_2, select, data_out);

1 

2  input data_1, data_2;  //数据输入

3  input select;     //选择位

4 

5  output reg data_out;   //数据的输出

6 

7  always @ (*)

8   begin

9    if(select)    //如果选择位为高,输出data_1

10    data_out = data_1;

11   else      //如果选择位为低,输出data_2

12    data_out = data_2;

13  end

14

15 endmodule 

 

 

测试模块

测试的简单写法,测试中模块的输入定义为寄存器reg型,输出定义为wire型,然后加上我们的块 initial ,再加上我们的例化,如下:

0  `timescale 1ns / 1ps

1 

2  module 块名;    

3 

4  reg 块输入;

5  wire 块输出;

6 

7  initial begin

8 

9 

10

11

12 end

13        

14 块名  例化名(

15   .端口(端口),

16   .端口(端口),

17 

18  );

19 

20 endmodule 

 

在测试中我们也有许多的系统比如我们的系统任务$stop等,这些都属于语法知识了,大家可以买一本适合的书来看看,我们为我们的设计写好的激励如下:

 

0  `timescale 1ns / 1ps //这一行中1ns定义我们测试时的时间单位,后面的ps 是精度

1 //前面的timescale英文也就是时间量程的意思

2 

3  module sel_1_tb;    //module 后面跟上我们测试名字,一般我们都写成模块名

4 //加上_tb,如果我们对一个项目的多个模块写测试我们就能清楚的分清

5 

6  reg data_1, data_2;   //定义模块的输入输出

7  reg select;     //模块中的输入定义为寄存器

8         

9  wire data_out;    //输出定义为wire型也就是线型

10

11 initial begin    //initial 是一个串型执行的,在测试中被综合,

12       //如果你写到模块中,可是会报错的

13  data_1 = 0;    //然后我们就可以定义我们的端口,给我们的端口赋初值

14  data_2 = 0;

15  select = 0;

16

17 #200 data_1 = 1; data_2 = 0;   //延迟200ns给输入赋值

18 #100 select = 1;     //延迟200ns后给选择位赋值

19 #100 select = 0;    //延迟200ns后给选择位赋值

20

21 #200 data_1 = 0; data_2 = 1;

22 #100 select = 0;

23 #100 select = 1;

24

25 #300 $stop;   //$stop 系统任务,也就是停止的意思,这句   就是延迟   300ns后,仿真停止

26  end

27  

28  sel_1 sel_1_dut(      //模块的例化,和端口的连接

29   .data_1(data_1),

30   .data_2(data_2),

31   .select(select),

32   .data_out(data_out)

33  );

34 

35 endmodule 

 

 

在测试中如果我们用到时钟了怎么办,我们可以这样写,如下

0  `timescale 1ns / 1ps

1 

2  module 块名;    

3 

4  reg 块输入;

5  wire 块输出;

6  reg clk,rst_n;

7 

8  initial begin

9  clk = 1;

10  rst_n = 0;

11

12  #200.1 rst_n = 1;

13

14 end

15

16 always #10 clk = ~clk;  //always 一直,这样可以写成一个  50M的时钟

17        //说的是延迟10ns翻转一次,也就是一  个周期20ns

18    

19 块名  例化名(

20   .端口(端口),

21   .端口(端口),

22 

23  );

24 

25 endmodule 

 

 

仿真图:

仿真测试 

 

在仿真中我们可以真实的看到,当数据data_1为1,data_2位0的时候,当选择位select为0的时候,输出data_out的值为0也就是data_2的值,当select为1的时候,data_out的值位1,也就是data_1的值,后面的仿真也一样我们可以清楚的看到。

 

以上就是对于二选一数据选择器的仿真测试文件的编写细节,大家可以动手去做一做,加油,各位。

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
评论(0)
发评论
晓灰灰 2018-05-30
0 回复 举报
会持续更新,大家多多关注 收起回复

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分