• 同步FIFO设计实现(8/7)


    1.    同步FIFO的写时钟和读时钟为同一个时钟,FIFO内部所有逻辑都是同步逻辑,常常用于交互数据缓冲。
    2.    典型同步FIFO有三部分组成: (1) FIFO写控制逻辑; (2)FIFO读控制逻辑;(3)FIFO 存储实体(如Memory、Reg)。

     

    3.    FIFO写控制逻辑主要功能:产生FIFO写地址、写有效信号,同时产生FIFO写满、写错等状态信号;
    4.    FIFO读控制逻辑主要功能:产生FIFO读地址、读有效信号,同时产生FIFO读空、读错等状态信号。

    FIFO基本概念: 

    •    FIFO:先进先出(First-in-first-out)
    •    FIFO的深度(如下), 同一块数据内存的大小
    •    FIFO的宽度
    •    写指针:Write-pointer
    •    读指针:Read-pointer
    •    写数据端口
    •    读数据端口
    •    FIFO空、FIFO满
    •    同步FIFO/异步FIFO
    •    同步:数据写入FIFO的时钟和数据读出FIFO的时钟是同步的(synchronous)

    •    异步:数据写入FIFO的时钟和数据读出FIFO的时钟是异步的(asynchronous)

    一般FIFO使用循环指针(计数溢出自动归零)。一般可以称写指针为头head,读指针为尾tail。初始化时,读写指针指向同一数据地址。
    下图可见,FIFO初始化时,WP和RP指针指向同一数据单元。WP指向下一个将要写入的数据单元,RP指向将要读出的数据单元 

    使用fifo_counter记录FIFO RAM中的数据个数: 

    1.    等于0时,给出empty信号
    2.    等于BUF_LENGTH时,给出full信号

    fifo_counter:

    1.    写而未满时增加1
    2.    读而未空时减1
    3.    同时发生读写操作时,fifo_counter不变

    读写指针宽度

    1.    与地址宽度相当
    2.    地址增加而溢出后,自动变成0
    3.    循环指针(此处地址变化:0-7-0-7-0)

    代码实现 

    RTL

    1. `define BUF_WIDTH 4 //地址宽度为3+1
    2. `define BUF_SIZE 8 //数据个数,FIFO深度
    3. module fifo_counter(clk,rst_n,buf_in,buf_out,wr_en,rd_en,buf_empty,buf_full,fifo_cnt);
    4. input clk,rst_n;
    5. input wr_en,rd_en;
    6. input [7:0] buf_in; //data input to be pushed to buffer
    7. output reg [7:0] buf_out; //port to output the data using pop
    8. output wire buf_empty,buf_full; //buffer empty and full indication
    9. output reg [`BUF_WIDTH-1:0] fifo_cnt; //number of data pushed in to buffer
    10. //当写入数据个数为8时,FIFO为满
    11. reg [`BUF_WIDTH-2:0] rd_ptr,wr_ptr;
    12. //数据指针3位宽度,0-7索引,8个数据深度,循环指针0-7-0-7
    13. reg [7:0] buf_mem [0:`BUF_SIZE-1];
    14. //判断空满
    15. assign buf_empty=(fifo_cnt==0);
    16. assign buf_full=(fifo_cnt==`BUF_SIZE);
    17. always@(posedge clk or negedge rst_n)begin
    18. if(!rst_n)
    19. fifo_cnt<=0;
    20. else if((!buf_full&&wr_en)&&(!buf_empty&&rd_en))//同时读写,counter不变
    21. fifo_cnt<=fifo_cnt;
    22. else if(!buf_full&&wr_en) //写数据
    23. fifo_cnt<=fifo_cnt+1;
    24. else if(!buf_empty&&rd_en) //读数据
    25. fifo_cnt<=fifo_cnt-1;
    26. else
    27. fifo_cnt<=fifo_cnt;
    28. end
    29. always@(posedge clk or negedge rst_n)begin //读数据
    30. if(!rst_n)
    31. buf_out<=0;
    32. else if(rd_en&&!buf_empty)
    33. buf_out<=buf_mem[rd_ptr];
    34. end
    35. always@(posedge clk )begin //写数据
    36. if(wr_en&&!buf_full)
    37. buf_mem[wr_ptr]<=buf_in;
    38. end
    39. always@(posedge clk or negedge rst_n) begin
    40. if(!rst_n) begin
    41. rd_ptr<=0;
    42. wr_ptr<=0;
    43. end
    44. else begin
    45. if(!buf_empty&&rd_en)
    46. rd_ptr<=rd_ptr+1;
    47. if(!buf_full&&wr_en)
    48. wr_ptr<=wr_ptr+1;
    49. end
    50. end
    51. endmodule

    TB: 

    1. //fifi.v TB
    2. `define BUF_WINTH 4 //地址宽度位3+1
    3. `define BUF_SIZE 8 //数据个数,FIFO深度
    4. module tb_fifo_counter;
    5. reg clk,rst_n;
    6. reg wr_en,rd_en;
    7. reg [7:0] buf_in; //data input to be pushed to buffer
    8. wire reg [7:0] buf_out; //port to output the data using pop
    9. wire buf_empty,buf_full; //buffer empty and full indication
    10. wire [`BUF_WIDTH-1:0] fifo_cnt; //number of data pushed in to buffer
    11. //当写入数据个数为8时,FIFO为满
    12. fifo_counter init(clk,rst_n,buf_in,buf_out,wr_en,rd_en,buf_empty,buf_full,fifo_cnt);
    13. always begin
    14. #10 clk=~clk;
    15. end
    16. reg[7:0] tempdata;
    17. initial begin
    18. clk=0;
    19. rst_n=0;
    20. wr_en=0;
    21. rd_en=0;
    22. buf_in=0;
    23. #15;
    24. rst_n=1;
    25. push(1);
    26. fork
    27. push(2);
    28. pop(tempdata);
    29. join
    30. push(10);
    31. push(20);
    32. push(30);
    33. push(40);
    34. push(50);
    35. push(60);
    36. pop(tempdata);
    37. push(70);
    38. push(80);
    39. push(90);
    40. push(100);
    41. push(110);
    42. pop(tempdata);
    43. push(120);
    44. push(130);
    45. push(140);
    46. push(150);
    47. pop(tempdata);
    48. pop(tempdata);
    49. pop(tempdata);
    50. pop(tempdata);
    51. pop(tempdata);
    52. pop(tempdata);
    53. push(160);
    54. pop(tempdata);
    55. pop(tempdata);
    56. pop(tempdata);
    57. pop(tempdata);
    58. pop(tempdata);
    59. pop(tempdata);
    60. pop(tempdata);
    61. pop(tempdata);
    62. pop(tempdata);
    63. push(170);
    64. pop(tempdata);
    65. end
    66. task push(input [7:0] data);
    67. if(buf_full)
    68. $display("---cannot push %d:buffer full", data);
    69. else begin
    70. $display("push",,data);
    71. buf_in =data;
    72. wr_en=1;
    73. @(posedge clk);
    74. #5 wr_en=0;
    75. end
    76. endtask
    77. task pop(output[7:0] data);
    78. if(buf_empty)
    79. $display("---cannot pop %d:buffer empty", data);
    80. else begin
    81. rd_en=1;
    82. @(posedge clk);
    83. #3 rd_en=0;
    84. data=buf_out;
    85. $display("poped",,data);
    86. end
    87. endtask
    88. endmodule

    波形

     

  • 相关阅读:
    【正点原子I.MX6U-MINI应用篇】7、输入设备(鼠标、键盘、触摸屏、按钮)的应用编程和tslib库
    对数据排序
    动态规划——62. 不同路径
    Linux中udp服务端,客户端的开发
    剑指 Offer 15. 二进制中1的个数,位运算,与运算
    JAVA高级——lambda
    linux查看串口信息tty*
    第19章_瑞萨MCU零基础入门系列教程之RTC
    深度解析四大主流软件架构模型:单体架构、分布式应用、微服务与Serverless的优缺点及场景应用
    五年Java编程生涯,大专学历最终逆袭阿里,面试+学习+经历分享
  • 原文地址:https://blog.csdn.net/weixin_45680021/article/details/126202645