搜索
bottom↓
回复: 0

【正点原子FPGA连载】第十八章IP核之FIFO实验

[复制链接]

出0入234汤圆

发表于 2021-1-28 11:00:33 | 显示全部楼层 |阅读模式
本帖最后由 正点原子 于 2021-1-28 11:00 编辑

1)实验平台:正点原子超越者FPGA开发板
2)  章节摘自【正点原子】超越者之FPGA开发指南
3)购买链接:https://item.taobao.com/item.htm?&id=631660290421
4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/fpga/zdyz-chaoyuezhe.html
5)正点原子官方B站:https://space.bilibili.com/394620890
6)正点原子FPGA技术交流群:905624739
QQ群头像.png

100846rel79a9p4uelap24.jpg

100846f1ce1fg14zbg0va4.png

第十八章IP核之FIFO实验


FIFO的英文全称是First In First Out,即先进先出。FPGA使用的FIFO一般指的是对数据的存储具有先进先出特性的一种缓存器,常被用于数据的缓存,或者高速异步数据的交互(即跨时钟域信号传递)。FIFO与FPGA内部的RAM和ROM的区别是FIFO没有外部读写地址线,采取顺序写入数据,顺序读出数据的方式,使用起来简单方便,由此带来的缺点就是不能像RAM和ROM那样可以由地址线决定读取或写入某个指定的地址。本章将通过对ISE软件自带的FIFO IP核进行读写测试,来向大家介绍Xilinx FIFO IP核的使用方法。
本章包括以下几个部分:
1818.1  简介
18.2  实验任务
18.3  硬件设计
18.4  程序设计
18.5  下载验证


18.1简介
根据FIFO工作的时钟域,可以将FIFO分为同步FIFO和异步FIFO。同步FIFO是指读时钟和写时钟为同一个时钟,在时钟沿来临时同时发生读写操作。异步FIFO是指读写时钟不一致,读写时钟是互相独立的。Xilinx的FIFO IP核可以被配置为同步FIFO或异步FIFO,其信号框图如下图所示。从图中可以了解到,当被配置为同步FIFO时,只使用WR_CLK,所有的输入输出信号都同步于WR_CLK信号。而当被配置为异步FIFO时,写端口和读端口分别有独立的时钟,所有与写相关的信号都是同步于写时钟WR_CLK,所有与读相关的信号都是同步于读时钟RD_CLK。
18611.png

图 18.1.1 FIFO IP核示意图

对于FIFO需要了解一些常见参数。
FIFO的宽度:FIFO一次读写操作的数据位宽N。
FIFO的深度:FIFO可以存储多少个宽度为N位的数据。
空标志:empty。FIFO已空时由FIFO的状态电路送出的一个信号,用以阻止FIFO的读操作继续从FIFO中读出数据从而造成无效数据的读出。
将空标志:almost_empty。FIFO即将被读空。
满标志:full。FIFO已满时由FIFO的状态电路送出的一个信号,用以阻止FIFO的写操作继续向FIFO中写数据从而造成溢出。
将满标志:almost_full。FIFO即将被写满。
读时钟:读FIFO时所遵循的时钟,读操作在时钟的上升沿触发。
请注意,“almost_empty”和“almost_full”这两个信号分别被看作“empty”和“full”的警告信号,它们距离真正的空(empty)和满(full)都会提前一个时钟周期拉高。本实验将使用这两个信号。
写时钟:写FIFO时所遵循的时钟,写操作在每个时钟的上升沿触发。
对于FIFO的基本知识先了解这些就足够了,可能有人会好奇为什么会有同步FIFO和异步FIFO,它们各自的用途是什么。之所以有同步FIFO和异步FIFO是因为各自的作用不同,同步FIFO常用于同步时钟的数据缓存,异步FIFO常用于跨时钟域的数据信号的传递。例如时钟域A下的数据data1传递给异步时钟域B,当data1为连续变化信号时,如果直接传递给时钟域B则可能会导致所收非所送的情况(即在采集过程中会出现包括亚稳态问题在内的一系列问题),使用异步FIFO能够将不同时钟域中的数据同步到所需的时钟域中。
18.2实验任务
本节的实验任务是使用ISE生成FIFO IP核,并实现以下功能:当FIFO为空时,向FIFO中写入数据,写入的数据量和FIFO深度一致,即FIFO被写满;然后从FIFO中读出数据,直到FIFO被读空为止,以此向大家详细介绍一下FIFO IP核的使用方法。
18.3硬件设计
本章实验只用到了输入的时钟信号和按键复位信号,没有用到其它硬件外设。本实验中各端口信号的管脚分配如下表所示:
表18.3.1 引脚分配表
1831.png

对应的UCF约束语句如下所示:
  1. NET sys_clk                       TNM_NET = sys_clk_pin;
  2. TIMESPEC TS_sys_clk_pin = PERIOD sys_clk_pin 50000 kHz;

  3. NET sys_clk                       LOC = N8  | IOSTANDARD = "LVCMOS33";
  4. NET sys_rst_n                     LOC = G16 | IOSTANDARD = "LVCMOS33";
复制代码

18.4程序设计
根据实验任务要求和模块化的设计思想,我们需要4个模块:fifo IP核、写fifo模块、读fifo模块以及顶层例化模块,其中顶层例化模块主要用来实现前三个模块的信号交互。由于FIFO多用于跨时钟域信号的处理,所以本实验使用异步FIFO来向大家详细介绍双时钟FIFO IP核的创建和使用。为了方便大家理解,这里将读/写时钟都用系统时钟来驱动。系统的功能框图如下图所示:
182189.png

图 18.4.1系统框图

首先创建一个名为ip_fifo的工程,接下来创建fifo IP核。在ISE软件的左侧“Design”栏中右击工程名按钮,打开添加新文件选项栏,我们选择New Source,如下图所示:
182340.png

图 18.4.2 “New Source”按钮

打开New Source之后选择IP(CORE Generator&Architecture Wizard),然后将FIFO IP核命名为fifo(也可以命名成别的名字,但是必须是英文命名),路径放在工程文件夹下,ISE会自动创建一个ipcore_dir文件夹用来存放IP核文件,如下图所示:
182556.png

图 18.4.3 创建FIFO IP核

如上图所示步骤设置完成后点击Next,进入IP核选择界面。在Search IP Catalog搜索栏中搜索fifo,然后选择FIFO Generator,如下图所示:
182705.png

图 18.4.4创建FIFO IP核

按上图所示步骤操作之后点击Next进入Summary界面,如下图所示:
182805.png

图 18.4.5 Summary界面

在Summary界面直接点击Finish,接下来就是配置IP核参数的过程,如下图所示:
182913.png

图 18.4.6 参数配置

在上图中:
Component Name:FIFO IP核的命名,这里会直接显示之前创建IP时的命名。
Interface Type:Native本机接口FIFO,可以利用区块RAM、分布式RAM或内置的FIFO资源;AX14除了支持Native的应用功能外,还可以用于AX14系统总线和点对点高速应用程序,但是AX14 FIFO不支持内置的FIFO与移位寄存器的FIFO设置。
选择Native类型然后点击Next,进入下一页参数设置,如下图所示:
183198.png

图 18.4.7参数配置

上图中:
Block RAM:FPGA内部硬件存在的块RAM资源。
Distribute RAM:分布式RAM资源,使用FPGA内部的寄存器和查找表搭建起来的RAM,当深度要求小于32的时候可以使用。
Shift Register:使用FIFO产生一个移位寄存器。
Common clock:同步时钟。
Independent clock:异步时钟。
选择Independent clocks选项并使用Block RAM资源,然后点击Next进入下一页参数设置,如下图所示:
183494.png

图 18.4.8参数配置

上图中:
Read Mode:选择Standard FIFO,标准FIFO模型。
Write Width:写数据位宽。
Write Depth:写数据深度,可以理解为FIFO的数据容量。
Read Width:读数据位宽。
这里按照上图所示设置好后,点击Next进入下一个参数页面设置,如下图所示:
183702.png

图 18.4.9参数配置

上图中:
Almost Full Flag:将满标志。
Almost Empty Flag:将空标志。
Write Acknowledge Flag:写应答标志,可以在其下方设置高电平有效(Active High)还是低电平有效(Active Low)。
Overflow Flag:当写指针追到了读指针,然后还继续写就会给出Overflow Flag标志,可以在其下方设置高电平有效(Active High)或低电平有效(Active Low)用来表示写错误。
Vaild Flag:读有效,可以在其下方设置高电平有效(Active High)还是低电平有效(Active Low)。
Underflow Flag:当读指针追到了写指针,然后还继续读就会给出underflow Flag标志,可以在其下方设置高电平有效(Active High)或低电平有效(Active Low)用来表示读错误。
按照上图所示设置后,点击Next进入下一参数设置页面,如下图所示:
184194.png

图 18.4.10参数配置

上图所示的这一页主要是复位的设置,这里我们不用作修改,保持默认,直接点击Next进入下一参数设置页面,如下图所示:
184311.png

图 18.4.11参数配置

上图所示把Write Data Count和Read Data Count读写计数器选上,主要用来观察写进去了多少个数据,还剩多少个数据可读。注意读写计数器的位宽要足够大,保证计数器的最大值大于fifo的深度,否则计数器会溢出。之后点击Next进入下一参数设置页面,如下图所示:
184510.png

图 18.4.12参数配置

上图所示的是要创建的FIFO IP核的Summary界面,检查一下设置,如果有问题就点击Back返回重新设置参数,如果没问题就点击Generate生成FIFO IP核。
回到Design工具栏下可以看到创建的FIFO IP核已经出现在工程栏下了,如下图所示:
184699.png

图 18.4.13 FIFO创建完成

现在就可以添加设计源文件了。本次是对FIFO IP核进行读写,所以需要一个读模块、一个写模块还要一个顶层例化模块。下面先来看顶层例化模块:
  1. 1  module fifo_top(
  2. 2     input    sys_clk   , // 时钟信号
  3. 3     input    sys_rst_n   // 复位信号   
  4. 4  
  5. 5     );
  6. 6  
  7. 7  wire [7:0] fifo_din                  ;
  8. 8  wire fifo_wr_en                      ;
  9. 9  wire fifo_rd_en                      ;
  10. 10 wire [7:0] fifo_dout                 ;
  11. 11 wire fifo_full                       ;
  12. 12 wire almost_full                     ;
  13. 13 wire wr_ack                          ;
  14. 14 wire overflow                        ;
  15. 15 wire fifo_empty                      ;
  16. 16 wire almost_empty                    ;
  17. 17 wire valid                           ;
  18. 18 wire underflow                       ;
  19. 19 wire [7:0] fifo_wr_data_count        ;
  20. 20 wire [7:0] fifo_rd_data_count        ;
  21. 21
  22. 22 fifo u_fifo        (
  23. 23   .wr_clk            (sys_clk            ), // input wr_clk
  24. 24   .rd_clk            (sys_clk            ), // input rd_clk
  25. 25   .din               (fifo_din           ), // input [7 : 0] din
  26. 26   .wr_en             (fifo_wr_en         ), // input wr_en
  27. 27   .rd_en             (fifo_rd_en         ), // input rd_en
  28. 28 .dout              (fifo_dout          ), // output [7 : 0] dout
  29. 29   .full              (fifo_full          ), // output full
  30. 30   .almost_full       (almost_full        ), // output almost_full
  31. 31   .wr_ack            (wr_ack             ), // output wr_ack
  32. 32   .overflow          (overflow           ), // output overflow
  33. 33   .empty             (fifo_empty         ), // output empty
  34. 34   .almost_empty      (almost_empty       ), // output almost_empty
  35. 35   .valid             (valid              ), // output valid
  36. 36   .underflow         (underflow          ), // output underflow
  37. 37   .rd_data_count     (fifo_wr_data_count ), // output [7 : 0] rd_data_count
  38. 38   .wr_data_count     (fifo_rd_data_count )  // output [7 : 0] wr_data_count
  39. 39 );
  40. 40
  41. 41 fifo_wr  u_fifo_wr (
  42. 42    .clk            ( sys_clk           ), // 写时钟
  43. 43    .rst_n          ( sys_rst_n         ), // 复位信号
  44. 44        
  45. 45    .fifo_wr_en     ( fifo_wr_en        ), // fifo写请求
  46. 46    .fifo_wr_data   ( fifo_din          ), // 写入FIFO的数据
  47. 47    .almost_empty   ( almost_empty      ), // fifo空信号
  48. 48    .almost_full    ( almost_full       )  // fifo满信号
  49. 49 );     
  50. 50
  51. 51 fifo_rd  u_fifo_rd (
  52. 52    .clk            ( sys_clk           ), // 读时钟
  53. 53    .rst_n          ( sys_rst_n         ), // 复位信号
  54. 54
  55. 55    .fifo_rd_en     ( fifo_rd_en        ), // fifo读请求
  56. 56    .fifo_dout      ( fifo_dout         ), // 从FIFO输出的数据
  57. 57    .almost_empty   ( almost_empty      ), // fifo空信号
  58. 58    .almost_full    ( almost_full       )  // fifo满信号
  59. 59 );
  60. 60
  61. 61 endmodule
复制代码

顶层模块主要是对FIFO IP核、写FIFO模块和读FIFO模块进行例化。需要注意的是从整个顶层来看,工程对外没有任何输出,所有的数据读写都是在FPGA内部进行的,编译器会认为我们的代码端口对外界不起作用,所以ISE会编译报错,不过没关系,我们可以将需要观察的信号设置成output型,这样既可以防止在Chipscope中信号被综合优化,又可以使工程编译通过。当然你也可以不设置为输出,创建一个Chipscope的在线调试文件(可以参考软件使用篇),将待观察信号接到在线调试IP核上,这样编译也可以编译通过,然后通过Chipscope观察信号。(特别注意:刚拿到我们的例程是没有对端口作处理的,直接编译会报错)。
顶层模块完成后,接着看看例化的子模块代码。fifo ip核模块就不用看了,因为fifoip核是我们配置参数后软件自动生成的,主要来看看读写模块的代码。下面是写FIFO模块(fifo_wr.v)源文件的代码:
  1. 1  module fifo_wr(
  2. 2      input                  clk    ,          // 时钟信号
  3. 3      input                  rst_n  ,          // 复位信号
  4. 4      
  5. 5      input                  almost_empty,     // FIFO将空信号
  6. 6      input                  almost_full ,     // FIFO将满信号
  7. 7      output    reg          fifo_wr_en ,      // FIFO写使能
  8. 8      output    reg  [7:0]   fifo_wr_data      // 写入FIFO的数据
  9. 9  );
  10. 10
  11. 11 //reg define
  12. 12 reg  [1:0]  state            ;  //动作状态
  13. 13 reg         almost_empty_d0  ;  //almost_empty 延迟一拍
  14. 14 reg         almost_empty_syn ;  //almost_empty 延迟两拍
  15. 15 reg  [3:0]  dly_cnt          ;  //延迟计数器
  16. 16 //*****************************************************
  17. 17 //**                    main code
  18. 18 //*****************************************************
  19. 19
  20. 20 //因为 almost_empty 信号是属于FIFO读时钟域的
  21. 21 //所以要将其同步到写时钟域中
  22. 22 always@( posedge clk ) begin
  23. 23  if( !rst_n ) begin
  24. 24      almost_empty_d0  <= 1'b0 ;
  25. 25      almost_empty_syn <= 1'b0 ;
  26. 26  end
  27. 27  else begin
  28. 28      almost_empty_d0  <= almost_empty ;
  29. 29      almost_empty_syn <= almost_empty_d0 ;
  30. 30  end
  31. 31 end
  32. 32
  33. 33 //向FIFO中写入数据
  34. 34 always @(posedge clk ) begin
  35. 35     if(!rst_n) begin
  36. 36         fifo_wr_en   <= 1'b0;
  37. 37         fifo_wr_data <= 8'd0;
  38. 38         state        <= 2'd0;
  39. 39      dly_cnt      <= 4'd0;
  40. 40     end
  41. 41     else begin
  42. 42         case(state)
  43. 43             2'd0: begin
  44. 44                 if(almost_empty_syn) begin  //如果检测到FIFO将被读空(下一拍就会空)
  45. 45                     state <= 2'd1;          //就进入延时状态
  46. 46                 end
  47. 47                 else
  48. 48                     state <= state;
  49. 49             end
  50. 50          2'd1: begin
  51. 51                 if(dly_cnt == 4'd10) begin  //延时10拍
  52. 52                                             //原因是FIFO IP核内部状态信号的更新存在延时
  53. 53                                             //延迟10拍以等待状态信号更新完毕                  
  54. 54                  dly_cnt    <= 4'd0;     
  55. 55                  state      <= 2'd2;        //开始写操作
  56. 56                  fifo_wr_en <= 1'b1;        //打开写使能
  57. 57              end
  58. 58              else
  59. 59                  dly_cnt <= dly_cnt + 4'd1;
  60. 60             end            
  61. 61          2'd2: begin
  62. 62                 if(almost_full) begin      //等待FIFO将被写满(下一拍就会满)
  63. 63                     fifo_wr_en   <= 1'b0;  //关闭写使能
  64. 64                     fifo_wr_data <= 8'd0;
  65. 65                     state        <= 2'd0;  //回到第一个状态
  66. 66                 end
  67. 67                 else begin                 //如果FIFO没有被写满
  68. 68                     fifo_wr_en   <= 1'b1;  //则持续打开写使能
  69. 69                     fifo_wr_data <= fifo_wr_data + 1'd1;  //且写数据值持续累加
  70. 70                 end
  71. 71             end
  72. 72          default : state <= 2'd0;
  73. 73         endcase
  74. 74     end
  75. 75 end
  76. 76
  77. 77 endmodule
复制代码

fifo_wr模块的核心部分是一个不断进行状态循环的状态机,如果检测到FIFO为空,则先延时10拍,这里注意,由于FIFO的内部信号的更新比实际的数据读/写操作有所延时,所以延时10拍的目的是等待FIFO的空/满状态信号、数据计数信号等信号更新完毕之后再进行FIFO写操作。如果写满,则回到状态0,即等待FIFO被读空,进行下一轮的写操作。
读FIFO模块fifo_rd.v源文件的代码如下:
  1. 1  module fifo_rd(
  2. 2      input               clk          ,   // 时钟信号
  3. 3      input               rst_n        ,   // 复位信号
  4. 4  
  5. 5      input        [7:0]  fifo_dout    ,   // 从FIFO读出的数据
  6. 6      input               almost_full  ,   // FIFO将满信号
  7. 7      input               almost_empty ,   // FIFO将空信号
  8. 8      output  reg         fifo_rd_en       // FIFO读使能
  9. 9  );
  10. 10
  11. 11 //reg define
  12. 12 reg  [1:0]  state           ;  //动作状态
  13. 13 reg         almost_full_d0  ;  //almost_full延迟一拍
  14. 14 reg         almost_full_syn ;  //almost_full延迟两拍
  15. 15 reg  [3:0]  dly_cnt         ;  //延迟计数器
  16. 16
  17. 17 //*****************************************************
  18. 18 //**                    main code
  19. 19 //*****************************************************
  20. 20
  21. 21 //因为 fifo_full 信号是属于FIFO写时钟域的
  22. 22 //所以要将其同步到读时钟域中
  23. 23 always@( posedge clk ) begin
  24. 24  if( !rst_n ) begin
  25. 25      almost_full_d0  <= 1'b0 ;
  26. 26      almost_full_syn <= 1'b0 ;
  27. 27  end
  28. 28  else begin
  29. 29      almost_full_d0  <= almost_full ;
  30. 30      almost_full_syn <= almost_full_d0 ;
  31. 31  end
  32. 32 end
  33. 33
  34. 34 //读出FIFO的数据
  35. 35 always @(posedge clk ) begin
  36. 36     if(!rst_n) begin
  37. 37         fifo_rd_en <= 1'b0;
  38. 38         state      <= 2'd0;
  39. 39         dly_cnt    <= 4'd0;
  40. 40     end
  41. 41     else begin
  42. 42         case(state)
  43. 43             2'd0: begin                     
  44. 44                 if(almost_full_syn)        //如果检测到FIFO被写满
  45. 45                     state <= 2'd1;         //就进入延时状态
  46. 46                 else
  47. 47                     state <= state;
  48. 48             end
  49. 49          2'd1: begin
  50. 50                 if(dly_cnt == 4'd10) begin //延时10拍
  51. 51                                            //原因是FIFO IP核内部状态信号的更新存在延时
  52. 52                                            //延迟10拍以等待状态信号更新完毕
  53. 53                     dly_cnt <= 4'd0;
  54. 54                  state   <= 2'd2;          //开始读操作
  55. 55              end
  56. 56              else
  57. 57                  dly_cnt <= dly_cnt + 4'd1;
  58. 58             end
  59. 59          2'd2: begin
  60. 60                 if(almost_empty) begin     //等待FIFO将被读空(下一拍就会空)
  61. 61                     fifo_rd_en <= 1'b0;    //关闭读使能
  62. 62                     state      <= 2'd0;    //回到第一个状态
  63. 63                 end
  64. 64                 else                       //如果FIFO没有被读空
  65. 65                     fifo_rd_en <= 1'b1;    //则持续打开读使能
  66. 66             end
  67. 67          default : state <= 2'd0;
  68. 68         endcase
  69. 69     end
  70. 70 end
  71. 71
  72. 72 endmodule
复制代码

读模块的代码结构与写模块几乎一样,也是使用一个不断进行状态循环的状态机来控制操作过程,代码比较简单,这里就不再赘述。
下面我们来对写好的工程进行仿真验证一下功能,在仿真前我们先对顶层文件(fifo_top)做一下处理如下图所示:
1813178.png

图 18.4.14 对顶层模块做处理

将需要观察的信号全部重新定义一遍,并加上后缀为“_tb”,然后使用assign语句把原信号赋值给重新定义的待观察信号,最后把所有带后缀“_tb”的待观察信号当作输出端口输出,这样无论是写Tsetbench仿真文件还是使用Chipscope在线调试都比较方便,编译不会报错,抓取信号也不会被综合优化。
将顶层文件处理好后就可以生成Testbench文件了(不会生成Testbench文件的可以参考软件使用篇),模板生成完后写激励如下所示:
  1. 1 `timescale 1ns / 1ps
  2. 2
  3. 3 module fifo_top_tb;
  4. 4     // Inputs
  5. 5     reg sys_clk;
  6. 6     reg sys_rst_n;
  7. 7     
  8. 8     wire [7:0] fifo_din_tb                   ;//仿真在线调试专用
  9. 9     wire fifo_wr_en_tb                       ;
  10. 10    wire fifo_rd_en_tb                       ;
  11. 11    wire [7:0] fifo_dout_tb                  ;
  12. 12    wire fifo_full_tb                        ;   
  13. 13    wire almost_full_tb                      ;
  14. 14    wire wr_ack_tb                           ;
  15. 15    wire overflow_tb                         ;   
  16. 16    wire fifo_empty_tb                       ;
  17. 17    wire almost_empty_tb                     ;   
  18. 18    wire valid_tb                            ;   
  19. 19    wire underflow_tb                        ;   
  20. 20    wire [7:0] fifo_wr_data_count_tb         ;   
  21. 21    wire [7:0] fifo_rd_data_count_tb         ;      
  22. 22  
  23. 23    // Instantiate the Unit Under Test (UUT)
  24. 24    fifo_top uut (
  25. 25        .sys_clk                (sys_clk                ),
  26. 26        .sys_rst_n              (sys_rst_n              ),
  27. 27        . fifo_din_tb           (fifo_din_tb            ),
  28. 28        . fifo_wr_en_tb         (fifo_wr_en_tb          ),  
  29. 29        . fifo_rd_en_tb         (fifo_rd_en_tb          ),  
  30. 30        . fifo_dout_tb          (fifo_dout_tb           ),
  31. 31        . fifo_full_tb          (fifo_full_tb           ),  
  32. 32        . almost_full_tb        (almost_full_tb         ),      
  33. 33        . wr_ack_tb             (wr_ack_tb              ),  
  34. 34        . overflow_tb           (overflow_tb            ),  
  35. 35        . fifo_empty_tb         (fifo_empty_tb          ),  
  36. 36        . almost_empty_tb       (almost_empty_tb        ),  
  37. 37        . valid_tb              (valid_tb               ),   
  38. 38        . underflow_tb          (underflow_tb           ),  
  39. 39        . fifo_wr_data_count_tb (fifo_wr_data_count_tb  ),
  40. 40        . fifo_rd_data_count_tb (fifo_rd_data_count_tb  )      
  41. 41        
  42. 42    );
  43. 43  
  44. 44    initial begin
  45. 45        // Initialize Inputs
  46. 46        sys_clk = 0;
  47. 47        sys_rst_n = 0;
  48. 48  
  49. 49        // Wait 100 ns for global reset to finish
  50. 50        #100;
  51. 51        sys_rst_n=1;
  52. 52        // Add stimulus here
  53. 53  
  54. 54    end
  55. 55    always #10 sys_clk=~sys_clk;
  56. 56endmodule
复制代码

Testbench文件完成后点击保存,然后点击Modelsim仿真按钮,调用Modelsim进行仿真(不熟悉的可以参考Modelsim章节)。
仿真波形如下图所示:
1815769.png

图 18.4.15 仿真波形图

上图是整体波形,从图中可以看到读写是交替进行的,处于写状态时写使能打开(fifo_wr_en_tb)、写数据跳变(fifo_din_tb)、写有效标志拉高(wr_ack_tb)、写数据计数器计数(fifo_wr_data_count_tb)、没有出现写错误,写错误信号保持低电平(overflow_tb),当数据写结束时先提前一个时钟拉高将满信号(almost_full_tb),再拉高写满信号(fifo_full_tb);读也是一样的,处于读状态时读使能打开(fifo_rd_en_tb)、读数据读出(fifo_dout_tb)、读有效标志拉高(valid_tb)、读数据计数器计数(fifo_rd_data_count_tb)、没有出现读错误,读错误信号保持低电平(underflow_tb)、当数据读结束时先提前一个时钟拉高将空信号(almost_empty_tb),再拉高读空信号(fifo_empty_tb);
我们放大波形图来看一下细节如下图所示:
1816261.png

图 18.4.16仿真波形细节图

上图是处于写状态时的细节,可以看到一共写了255个数(0~254),在快写满时确实是先拉高将满信号,再拉高写满信号;看完了写状态的细节我们再看看读状态的细节,如下图所示:
1816409.png

图 18.4.17仿真波形细节图

读状态也可以看到它读出的数据跟写入的一模一样,也是先拉高将空信号,再拉高读空信号。这就说明我们的FIFO IP核工程目前仿真功能是完全正常的,接下来就可以添加UCF文件进行管脚分配和时序约束了(不熟悉的可以参考软件使用篇),最后我们使用Chipscope工具进行下板子实际验证一下功能是否正确。
18.5下载验证
首先将下载器与超越者开发板上的JTAG接口连接,下载器另外一端与电脑连接,然后连接开发板的电源,并打开电源开关。
打开Chipscope工具,将刚刚生成好的逻辑分析仪IP核下载到板子上去,然后运行如下图所示:
1816729.png

图 18.5.1在线调试波形图

上图中可以看到波形与仿真的波形是一样的,为了进一步确认功能,可以将波形放大看一下细节如下图所示:
1816839.png

图 18.5.2在线调试波形细节图

上图是写数据时的细节,跟我们仿真图是一样的,说明写数据没有问题,我们再看看读数据时的波形细节,如下图所示:
1816956.png

图 18.5.3在线调试波形细节图

可以看到读状态波形的细节也是符合预期,到此就可以说明本次FIFO IP核的功能是正常的,本次例程实验成功。

回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-10 23:33

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表