当前位置:   article > 正文

FPGA中FIFO IP核配置与调用_scfifo

scfifo

目录

一、FIFO IP核简介

 二、SCFIFO IP核配置

三、SCFIFO IP核调用

3.1 顶层设计

 3.2 RTL代码

3.3 仿真

四、DCFIFO IP 核配置

五、DCFIFO IP 核调用

5.1 整体设计

5.2 RTL代码

5.3仿真验证

说明:

本人使用的是野火家Xilinx Spartan6系列开发板及配套教程,写博客记录自己的学习。

开发软件:ise14.7     仿真:modelsim 10.5 

一、FIFO IP核简介

      FIFO(First In First Out,即先入先出),是一种数据缓冲器,用来实现数据先入先出的读写。与 ROM 或 RAM 的按地址读写方式不同, FIFO 的读写遵循“先进先出”的原则,即数据按顺序写入 FIFO,先被写入的数据同样在读取的时候先被读出,所以 FIFO存储器没有地址线。 FIFO 有一个写端口和一个读端口外部无需使用者控制地址,使用方便。
      FIFO 存储器主要是作用为缓存,应用在同步时钟系统和异步时钟系统中,在很多的设计中都会使用如:多比特数据做跨时钟域的转换、前后带宽不同步等都用到了异步FIFO,示意图如下。 FIFO 根据读写时钟是否相同,分为 SCFIFO(同步 FIFO)和 DCFIFO(异步FIFO),SCFIFO 的读写为同一时钟,应用在同步时钟系统中; DCFIFO 的读写时钟不同,应用在异步时钟系统中。

 

 二、SCFIFO IP核配置

配置过程比较简单,故不展示这里注意选择时钟统一。

三、SCFIFO IP核调用

   实验目标:实现数据0-255的数据缓冲。

3.1 顶层设计

 3.2 RTL代码

  1. `timescale 1ns/1ns
  2. module fifo
  3. (
  4. input wire sys_clk ,
  5. input wire [7:0] pi_data , //输入数据
  6. input wire pi_flag , //输入数据有效标志信号
  7. input wire rd_en , //FIFO读数据有效信号
  8. output wire empty , //FIFO空标志信号,高有效
  9. output wire full , //FIFO满标志信号,高有效
  10. output wire [7:0] po_data , //输出数据
  11. output wire [7:0] data_count //FIFO中存在的数据个数
  12. );
  13. //调用FIFOip核
  14. scfifo_256X8 scfifo_256X8_inst
  15. (
  16. .clk (sys_clk ),
  17. .din (pi_data ),
  18. .wr_en (pi_flag ),
  19. .rd_en (rd_en ),
  20. .dout (po_data ),
  21. .full (full ),
  22. .empty (empty ),
  23. .data_count(data_count)
  24. );
  25. endmodule

3.3 仿真

仿真代码:

  1. `timescale 1ns/1ns
  2. module tb_fifo();
  3. reg sys_clk ;
  4. reg [7:0] pi_data ;
  5. reg pi_flag ;
  6. reg rd_en ;
  7. reg sys_rst_n ;
  8. reg [1:0] cnt_baud ;
  9. wire [7:0] po_data ;
  10. wire empty ;
  11. wire full ;
  12. wire [7:0] data_count ;
  13. initial begin
  14. sys_clk = 1'b1;
  15. sys_rst_n <= 1'b0;
  16. #100;
  17. sys_rst_n <= 1'b1;
  18. end
  19. always #10 sys_clk = ~sys_clk;
  20. //cnt_baud:计数从0到3的计数器,用于产生输入数据间的间隔
  21. always@(posedge sys_clk or negedge sys_rst_n)
  22. if(sys_rst_n == 1'b0)
  23. cnt_baud <= 2'b0;
  24. else if(&cnt_baud == 1'b1)
  25. cnt_baud <= 2'b0;
  26. else
  27. cnt_baud <= cnt_baud + 1'b1;
  28. //pi_flag:输入数据写请求信号
  29. always@(posedge sys_clk or negedge sys_rst_n)
  30. if(sys_rst_n == 1'b0)
  31. pi_flag <= 1'b0;
  32. //4个时钟周期且没有读请求时产生一个数据有效标志信号
  33. else if((cnt_baud == 2'd0) && (rd_en == 1'b0))
  34. pi_flag <= 1'b1;
  35. else
  36. pi_flag <= 1'b0;
  37. //pi_data:输入数据
  38. always@(posedge sys_clk or negedge sys_rst_n)
  39. if(sys_rst_n == 1'b0)
  40. pi_data <= 8'b0;
  41. else if((pi_data == 8'd225) && (pi_flag == 1'b1))
  42. pi_data <= 8'b0;
  43. else if(pi_flag == 1'b1) //每当pi_flag有效时产生一个数据
  44. pi_data <= pi_data + 1'b1;
  45. //rd_en:FIFO读请求信号
  46. always@(posedge sys_clk or negedge sys_rst_n)
  47. if(sys_rst_n == 1'b0)
  48. rd_en <= 1'b0;
  49. else if(full == 1'b1) //当FIFO中的数据存满时,开始读取FIFO中的数据
  50. rd_en <= 1'b1;
  51. else if(empty == 1'b1) //当FIFO中的数据被读空时停止读取FIFO中的数据
  52. rd_en <= 1'b0;
  53. fifo fifo_inst
  54. (
  55. .sys_clk (sys_clk ),
  56. .pi_data (pi_data ),
  57. .pi_flag (pi_flag ),
  58. .rd_en (rd_en ),
  59. .po_data (po_data ),
  60. .empty (empty ),
  61. .full (full ),
  62. .data_count (data_count )
  63. );
  64. endmodule

仿真结果:

 从上图中可以看出full为高电平时,rd_en也在下一个节拍拉高,fifo开始读数据。

  从上图中可以看出empty为高电平时,rd_en也在下一个节拍拉低并且pi_flag为高电平,fifo开始写数据。

四、DCFIFO IP 核配置

配置过程比较简单,故不展示这里注意选择时钟统一。

五、DCFIFO IP 核调用

实验目标:实现输入 256 个深度 8 位宽、 输出 128个深度 16 位宽的数据缓存器。

5.1 整体设计

5.2 RTL代码

  1. `timescale 1ns/1ns
  2. module fifo
  3. (
  4. input wire [7:0] pi_data , //FIFO写入的数据,同步于wrclk时钟
  5. input wire wr_clk , //同步于FIFO 写数据 的时钟 50MHz
  6. input wire pi_flag , //输入数据有效标志信号,同步于wr_clk时钟
  7. output wire full , //满标志信号,高有效
  8. output wire [7:0] wr_data_count, //FIFO写端口中存在的数据个数,
  9. //同步于wrclk时钟
  10. output wire [15:0] po_data , //FIFO读出的数据,同步于rdclk时钟
  11. input wire rd_clk , //同步于FIFO 读数据 的时钟 25MHz
  12. input wire rd_en , //FIFO读请求信号,同步于rdclk时钟
  13. output wire empty , //空标志信号,高有效,
  14. output wire [6:0] rd_data_count //FIFO读端口中存在的数据个数,
  15. //同步于rdclk时钟
  16. );
  17. //调用FIFO ip核
  18. dcfifo_256x8to128x16 dcfifo_256x8to128x16_inst
  19. (
  20. .din (pi_data),
  21. .rd_clk (rd_clk ),
  22. .rd_en (rd_en ),
  23. .wr_clk (wr_clk ),
  24. .wr_en (pi_flag),
  25. .dout (po_data),
  26. .empty (empty ),
  27. .full (full ),
  28. .rd_data_count (rd_data_count),
  29. .wr_data_count (wr_data_count)
  30. );
  31. endmodule

5.3仿真验证

仿真代码:

  1. `timescale 1ns/1ns
  2. module tb_fifo();
  3. reg wr_clk ;
  4. reg [7:0] pi_data ;
  5. reg pi_flag ;
  6. reg rd_clk ;
  7. reg rd_en ;
  8. reg sys_rst_n ;
  9. reg [1:0] cnt_baud ;
  10. reg full_reg0 ;
  11. reg full_reg1 ;
  12. wire empty ;
  13. wire full ;
  14. wire [7:0] wr_data_count ;
  15. wire [15:0] po_data ;
  16. wire [6:0] rd_data_count ;
  17. initial begin
  18. wr_clk = 1'b1;
  19. rd_clk = 1'b1;
  20. sys_rst_n <= 1'b0;
  21. #100;
  22. sys_rst_n <= 1'b1;
  23. end
  24. //wr_clk:模拟FIFO的写时钟,每10ns电平翻转一次,周期为 20ns,频率为50MHz
  25. always #10 wr_clk = ~wr_clk;
  26. //rd_clk:模拟FIFO的读时钟,每20ns电平翻转一次,周期为40ns,频率为25MHz
  27. always #20 rd_clk = ~rd_clk;
  28. //cnt_baud:计数从0到3的计数器,用于产生输入数据间的间隔
  29. always@(posedge wr_clk or negedge sys_rst_n)
  30. if(sys_rst_n == 1'b0)
  31. cnt_baud <= 2'b0;
  32. else if(cnt_baud == 2'd3)
  33. cnt_baud <= 2'b0;
  34. else
  35. cnt_baud <= cnt_baud + 1'b1;
  36. always@(posedge wr_clk or negedge sys_rst_n)
  37. if(sys_rst_n == 1'b0)
  38. pi_flag <= 1'b0;
  39. else if((cnt_baud == 2'd0) && (rd_en == 1'b0))
  40. pi_flag <= 1'b1;
  41. else
  42. pi_flag <= 1'b0;
  43. //pi_data:输入顶层模块的数据,要写入到FIFO中的数据
  44. always@(posedge wr_clk or negedge sys_rst_n)
  45. if(sys_rst_n == 1'b0)
  46. pi_data <= 8'b0;
  47. pi_data的值为0~255依次循环
  48. else if((pi_data == 8'd255) && (pi_flag == 1'b1))
  49. pi_data <= 8'b0;
  50. else if(pi_flag == 1'b1) //每当pi_flag有效时产生一个数据
  51. pi_data <= pi_data + 1'b1;
  52. //将同步于rd_clk时钟的写满标志信号full在rd_clk时钟下打两拍
  53. always@(posedge rd_clk or negedge sys_rst_n)
  54. if(sys_rst_n == 1'b0)
  55. begin
  56. full_reg0 <= 1'b0;
  57. full_reg1 <= 1'b0;
  58. end
  59. else
  60. begin
  61. full_reg0 <= full;
  62. full_reg1 <= full_reg0;//打两拍
  63. end
  64. //rd_en:FIFO读请求信号同步于rd_clk时钟
  65. always@(posedge rd_clk or negedge sys_rst_n)
  66. if(sys_rst_n == 1'b0)
  67. rd_en <= 1'b0;
  68. else if(full_reg1 == 1'b1)
  69. rd_en <= 1'b1;
  70. else if(empty == 1'b1)//当FIFO中的数据被读空时停止读取FIFO中的数据
  71. rd_en <= 1'b0;
  72. fifo fifo_inst
  73. (
  74. .wr_clk (wr_clk ),
  75. .pi_data (pi_data ),
  76. .pi_flag (pi_flag ),
  77. .rd_clk (rd_clk ),
  78. .rd_en (rd_en ),
  79. .po_data (po_data ),
  80. .empty (empty ),
  81. .full (full ),
  82. .rd_data_count(rd_data_count),
  83. .wr_data_count(wr_data_count)
  84. );
  85. endmodule

仿真结果:

整体波形变化:

 数据输入部分:

 数据输出部分:

由上可知读写位宽不同的FIFO,数据输入输出顺序是当输入位宽小于输出位宽时,先入存高位后入存低位。反之则,先入存低位后入存高位。 

学完fifo,简单总结三点:

1. 合理控制 IP核大小(数据深度与位宽),避免资源浪费。

2. 注意利用好 FIFO 的关键信号,如读写时钟、读写使能、空满标志信号。

3. 写数据的总带宽一定要等于读数据的总带宽,否则一定会存在写满或读空的现象。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/206799?site
推荐阅读
相关标签
  

闽ICP备14008679号