• FPGA原理与结构(13)——FIFO IP核的使用与测试


    系列文章目录:FPGA原理与结构(0)——目录与传送门

    一、前言

            本文介绍FIFO Generator v13.2 IP核的具体使用与例化,在学习一个IP核的使用之前,首先需要对于IP核的具体参数和原理有一个基本的了解,具体可以参考:

    FPGA原理与结构——FIFO IP核原理学习icon-default.png?t=N7T8https://blog.csdn.net/apple_53311083/article/details/132378996?spm=1001.2014.3001.5501

    二、FIFO IP核定制

    1、FIFO IP核

    step1 打开vivado工程,点击左侧栏中的IP Catalog

    c1987bb2bcf249be8d0ca5f847744a0c.jpeg

    step2 在搜索栏搜索FIFO,找到FIFO Generator核

    99ad759bbe6a4661b465b48f57064dc5.jpeg

    2、IP核定制 

    step3 Basic 界面定制

    f0f81c6c86c54f9ca5078d8b1ee0dfbf.jpeg

    ①Component Name :自定义FIFO的名称 

    ②Interface Type :接口类型,我们知道FIFO可以支持Native接口和AXI接口,其中AXI接口包括AXI3,AXI4,AXI Stream类型,这里我们选择Native。

        Fifo Implementation :用于选择我们想要实现的是同步 FIFO 还是异步 FIFO 以及使用哪
    种资源实现 FIFO,这里我们选择“Independent Clocks Block RAM”,即使用块 RAM 来实现的异步 FIFO。
        Synchronization Stages :同步级数,这里保持默认为2,如果有更高的频率要求,可以提升。
    ③FIFO Implementation Options :不同资源类型实现FIFO所能支持的功能列表,大家根据表格自行观察连接即可。


    step4 Native Ports 界面设计

    5cb4107a8efc498ead60d87e7a8d816a.jpeg

    ①Read Mode :用于设置读 FIFO 时的读模式,可选的有标准模式和前显模式,一般没有特殊需求的前提下,我们推荐标准模式。这里我们选择默认的“Standard FIFO”。
    ②Data Port Parameters :用于设置读写端口的数据总线的宽度以及 FIFO 的深度,写宽度“Write Width”我们设置为 8 位,写深度“Write Depth”我们设置为 256,注意此时 FIFO IP 核所能实现的实际深度却是 255;虽然读宽度“Read Width”能够设置成和 写宽度不一样的位宽,且此时读深度“Read Depth”会根据上面三个参数被动地自动设置成相应的值;但是我们还是将读宽度“Read Width”设置成和写宽度“Write Width”一样的位宽,这也是在实际应用中最常用的情况。
    ③ ECC模式:在本次的FIFO测试中不使用
    ④ Initiazation :用于设置FIFO的复位等相关内容,默认同步复位,安全复位,full在复位时保持高电平有效。

    step5 Status Flags 界面定制

    a0527277fa314254b78eb21c51ed18b7.jpeg

    “Status Flags”界面,这个界面用于设置用户自定义接口或者用于设定专用的输入口。
    ① Optional Flags : 可选信号,在这里可以勾选将空和将满信号,这里我们都勾上。
    ② Handshaking Options :握手信号,这里我们使用不到,就不勾选了。
    ③ Programmable Flags : 可编程阈值,这里我们也不做选择。

    step6 Data Counts

    3abd803c1c1948d9906d08033aab49fe.jpeg

            Data Counts界面用于设置 FIFO 内数据计数的输出信号,此信号表示当前在 FIFO 内存在多少个有效数据。为了更加方便地观察读/写过程,这里我们把读/写端口的数据计数都打开,且计数值总线的位宽设置为满位宽,即 8 位。

    step7 Summary 5615d074617449bcaa49ddc8e40c1ce3.jpeg

             IP核定制的最后一面永远是Summary界面,帮助我们进行一个回顾和检查。

    三、IP核测试

            首先设计了写FIFO模块和读FIFO模块:

    3.1 写fifo模块

    1. //-------------------------------------<写fifo模块>--------------------------------
    2. module fifo_wr(
    3. //-------------------<信号输入>-----------------------
    4. input clk, //系统时钟
    5. input rst, //复位信号
    6. input almost_empty, //FIFO将空信号
    7. input almost_full , //FIFO将满信号
    8. //-------------------<信号输出>-----------------------
    9. output reg fifo_wr_en, //FIFO写使能
    10. output reg [7:0] fifo_wr_data //写入FIFO的数据
    11. );
    12. //reg define
    13. reg [1:0] state ; //动作状态
    14. reg almost_empty_d0 ; //almost_empty 延迟一拍
    15. reg almost_empty_syn ; //almost_empty 延迟两拍
    16. reg [3:0] dly_cnt ; //延迟计数器
    17. //因为 almost_empty 信号是属于FIFO读时钟域的
    18. //所以要将其同步到写时钟域中
    19. always@( posedge clk ) begin
    20. if( rst ) begin
    21. almost_empty_d0 <= 1'b0 ;
    22. almost_empty_syn <= 1'b0 ;
    23. end
    24. else begin
    25. almost_empty_d0 <= almost_empty ;
    26. almost_empty_syn <= almost_empty_d0 ;
    27. end
    28. end
    29. //向FIFO中写入数据
    30. always @(posedge clk ) begin
    31. if(rst) begin
    32. fifo_wr_en <= 1'b0;
    33. fifo_wr_data <= 8'd0;
    34. state <= 2'd0;
    35. dly_cnt <= 4'd0;
    36. end
    37. else begin
    38. case(state)
    39. 2'd0: begin
    40. if(almost_empty_syn) begin //如果检测到FIFO将被读空
    41. state <= 2'd1; //就进入延时状态
    42. end
    43. else
    44. state <= state;
    45. end
    46. 2'd1: begin
    47. if(dly_cnt == 4'd10) begin //延时10
    48. //原因是FIFO IP核内部状态信号的更新存在延时
    49. //延迟10拍以等待状态信号更新完毕
    50. dly_cnt <= 4'd0;
    51. state <= 2'd2; //开始写操作
    52. fifo_wr_en <= 1'b1; //打开写使能
    53. end
    54. else
    55. dly_cnt <= dly_cnt + 4'd1;
    56. end
    57. 2'd2: begin
    58. if(almost_full) begin //等待FIFO将被写满
    59. fifo_wr_en <= 1'b0; //关闭写使能
    60. fifo_wr_data <= 8'd0;
    61. state <= 2'd0; //回到第一个状态
    62. end
    63. else begin //如果FIFO没有被写满
    64. fifo_wr_en <= 1'b1; //则持续打开写使能
    65. fifo_wr_data <= fifo_wr_data + 1'd1; //且写数据值持续累加
    66. end
    67. end
    68. default : state <= 2'd0;
    69. endcase
    70. end
    71. end
    72. endmodule

    3.2 读FIFO模块

    1. //-------------------------------------<读fifo模块>--------------------------------
    2. module fifo_rd(
    3. //-------------------<信号输入>-----------------------
    4. input clk , // 时钟信号
    5. input rst , // 复位信号
    6. input [7:0] fifo_dout , // 从FIFO读出的数据
    7. input almost_full ,// FIFO将满信号
    8. input almost_empty,// FIFO将空信号
    9. //-------------------<信号输出>-----------------------
    10. output reg fifo_rd_en // FIFO读使能
    11. );
    12. //reg define
    13. reg [1:0] state ; // 动作状态
    14. reg almost_full_d0 ; // fifo_full 延迟一拍
    15. reg almost_full_syn ; // fifo_full 延迟两拍
    16. reg [3:0] dly_cnt ; // 延迟计数器
    17. //因为 fifo_full 信号是属于FIFO写时钟域的
    18. //所以要将其同步到读时钟域中
    19. always@( posedge clk ) begin
    20. if( rst ) begin
    21. almost_full_d0 <= 1'b0 ;
    22. almost_full_syn <= 1'b0 ;
    23. end
    24. else begin
    25. almost_full_d0 <= almost_full ;
    26. almost_full_syn <= almost_full_d0 ;
    27. end
    28. end
    29. //读出FIFO的数据
    30. always @(posedge clk ) begin
    31. if(rst) begin
    32. fifo_rd_en <= 1'b0;
    33. state <= 2'd0;
    34. dly_cnt <= 4'd0;
    35. end
    36. else begin
    37. case(state)
    38. 2'd0: begin
    39. if(almost_full_syn) //如果检测到FIFO将被写满
    40. state <= 2'd1; //就进入延时状态
    41. else
    42. state <= state;
    43. end
    44. 2'd1: begin
    45. if(dly_cnt == 4'd10) begin //延时10拍
    46. //原因是FIFO IP核内部状态信号的更新存在延时
    47. //延迟10拍以等待状态信号更新完毕
    48. dly_cnt <= 4'd0;
    49. state <= 2'd2; //开始读操作
    50. end
    51. else
    52. dly_cnt <= dly_cnt + 4'd1;
    53. end
    54. 2'd2: begin
    55. if(almost_empty) begin //等待FIFO将被读空
    56. fifo_rd_en <= 1'b0; //关闭读使能
    57. state <= 2'd0; //回到第一个状态
    58. end
    59. else //如果FIFO没有被读空
    60. fifo_rd_en <= 1'b1; //则持续打开读使能
    61. end
    62. default : state <= 2'd0;
    63. endcase
    64. end
    65. end
    66. endmodule

    3.3 顶层模块

    1. module fifo_top(
    2. //-------------------<信号输入>-----------------------
    3. input sys_clk, //系统时钟
    4. input rst //复位信号
    5. );
    6. wire [7:0] din; //fifo的输入数据(写入的数据)
    7. wire wr_en; //写使能
    8. wire rd_en; //读使能
    9. wire [7:0] dout; //fifo的输出数据(读出的数据)
    10. wire full; //fifo满信号
    11. wire almost_full; //fifo将满标志
    12. wire empty; //fifo空标志
    13. wire almost_empty; //fifo将空标志
    14. wire [7:0]rd_data_count; //fifo写时钟域的数据计数
    15. wire [7:0]wr_data_count; //fifo读时钟域的数据计数
    16. wire wr_rst_busy;
    17. wire rd_data_count;
    18. //-------------------<IP核例化>-----------------------
    19. fifo_exp1 fifo1 (
    20. .rst (rst), // input wire rst
    21. .wr_clk (sys_clk), // input wire wr_clk
    22. .rd_clk (sys_clk), // input wire rd_clk
    23. .din (din), // input wire [7 : 0] din
    24. .wr_en (wr_en), // input wire wr_en
    25. .rd_en (rd_en), // input wire rd_en
    26. .dout (dout), // output wire [7 : 0] dout
    27. .full (full), // output wire full
    28. .almost_full (almost_full), // output wire almost_full
    29. .empty (empty), // output wire empty
    30. .almost_empty (almost_empty), // output wire almost_empty
    31. .rd_data_count (rd_data_count), // output wire [7 : 0] rd_data_count
    32. .wr_data_count (wr_data_count), // output wire [7 : 0] wr_data_count
    33. .wr_rst_busy (wr_rst_busy), // output wire wr_rst_busy
    34. .rd_rst_busy (rd_rst_busy) // output wire rd_rst_busy
    35. );
    36. //例化写FIFO模块
    37. fifo_wr fifo_wr_u1(
    38. .clk ( sys_clk ), // 写时钟
    39. .rst ( rst ), // 复位信号
    40. .fifo_wr_en ( wr_en ) , // fifo写请求
    41. .fifo_wr_data ( din ) , // 写入FIFO的数据
    42. .almost_empty ( almost_empty ), // fifo空信号
    43. .almost_full ( almost_full ) // fifo满信号
    44. );
    45. //例化读FIFO模块
    46. fifo_rd fifo_rd_u1(
    47. .clk ( sys_clk ), // 读时钟
    48. .rst ( rst ), // 复位信号
    49. .fifo_rd_en ( rd_en ), // fifo读请求
    50. .fifo_dout ( dout ), // 从FIFO输出的数据
    51. .almost_empty ( almost_empty ), // fifo空信号
    52. .almost_full ( almost_full ) // fifo满信号
    53. );
    54. endmodule

    3.4 测试模块

    1. `timescale 1ns / 1ps
    2. module tb_ip_fifo( );
    3. // Inputs
    4. reg sys_clk;
    5. reg rst;
    6. // Instantiate the Unit Under Test (UUT)
    7. fifo_top tb1_fifo_top (
    8. .sys_clk (sys_clk),
    9. .rst (rst)
    10. );
    11. //Genarate the clk
    12. parameter PERIOD = 20;
    13. always begin
    14. sys_clk = 1'b0;
    15. #(PERIOD/2) sys_clk = 1'b1;
    16. #(PERIOD/2);
    17. end
    18. initial begin
    19. // Initialize Inputs
    20. rst = 1;
    21. // Wait 100 ns for global reset to finish
    22. #100 ;
    23. rst = 0;
    24. // Add stimulus here
    25. end
    26. endmodule

    3.4 测试结果

    4e6a307bdfe14cad9d529680c41836ab.jpeg

            通过看到FIFO如我们预期的写入和读出数据,读出的数据满足先入先出的原则。

    四、总结 

            本文总结了FIFO IP核的使用方法,给出了各个配置参数的具体含义及配置方式,并对相关的设计进行了测试。

  • 相关阅读:
    如何理解printf变参函数的实现
    基于Java+Spring Boot+MySQL的课程设计选题管理
    五、Javascript 空间坐标[尺寸、滑动]
    【Flink】入门Demo实现、Flink运行架构之运行时组件,任务提交流程,任务调度原理
    Solon2 常用注解之 @ProxyComponent 用法说明
    java计算机毕业设计健身俱乐部管理系统MyBatis+系统+LW文档+源码+调试部署
    IP可视对讲实时录制系统
    spring 只读事务 设置异常回滚事务
    【前端设计模式】之访问者模式
    【计算机基础】Git系列3:常用操作
  • 原文地址:https://blog.csdn.net/apple_53311083/article/details/132471818