当前位置:   article > 正文

FIFO小总结

fifo
  • 什么是FIFO?

FIFO:first in,first out;数据先进先出,后进后出,是一种传统的顺序执行方法,本质上是一种双口数据缓存器,没有外部地址(由内部指针递增来充当数据地址),只能顺序写入,顺序读取,因此不能写入或读取指定地址里的数据。

  • 为什么需要FIFO?

在系统设计时,包含很多工作在不同时钟频率下的元件,如处理器、外设等,可能有自己的时钟振荡器,不同模块处理速度有快有慢,但是每个模块各自时钟不间歇,如果模块之间有数据交互,会造成计算紊乱,这也就是跨时钟域要解决的问题,当数据量很大,数据传输速率要求高,需要匹配不同传输速率的系统时,FIFO是处理此类问题的优解。

  • FIFO与串口的区别

Uart全称为通用异步收发器(Universal Asynchronous Receiver/Transmitter),是一种通用串行数据总线,先将接收到的并行数据转成串行进行传输,然后再将串行转成并行数据,在两个uart设备之间通信,指定相同传输速率(波特率)、起始位结束位等,遵循同一通信协议。

FIFO本质上只是一个缓冲器,如果CPU处理uart数据绰绰有余,可以不用FIFO的帮助,如果在复杂系统中,CPU工作量太大,那么CPU在处理别的任务时,就会时常被收发数据中断,导致CPU工作效率很低,这时通过FIFO来缓冲,存下若干数据再集中处理就很有必要了。

FIFO和uart可以联合工作,提高收发效率。

  • FIFO的分类
  1. 同步FIFO

读取与写入的时钟相同,可以用计数器或读写指针来判断空满

  1. 异步FIFO

读取与写入的时钟不同,需要用到同步器、gray码来减少亚稳态的产生,用指针的gray来判断空满,避免使用二进制指针比较空满,这会导致指针值取样错误。

  • 异步(双时钟)FIFO主要参数

宽度:FIFO存储的每个数据的位宽

深度:FIFO存储数据的个数

写满标志:满标志拉高,则无法继续写入

                  若[写域写指针(gray)== 写域读指针(gray)],则full==1

读空标志:空标志拉高,则无法继续读取

                  若[读域读指针(gray)== 读域写指针(gray)],则null==1

写指针(写域):每存入一个数据,写指针递增1,

读指针(读域):每读取一个数据,读指针递增1

写指针(读域):将写域写指针转化成gray码同步到读域

读指针(写域):将读域读指针转化成gray码同步到写域

指针位数要比FIFO深度多一位用来判断空满!

产生可靠的空满标志是设计FIFO的关键!

  • gray码与二进制

格雷码是一种绝对编码方式,它的循环、单步特性消除了随机取数时出现重大误差的可能,是一种可靠的、错误最小化的编码方式,在相邻位间转换时,只有一位产生变化,出错可能大大降低。

        框与绿框里的格雷码体现了极美的对称性,最高位MSB红框为0,绿框为1,剩下的3位LSB相同。

转化公式:

bnary to Gray

g(3) = b(3) ^ 0

g(2) = b(3) ^ b(2)

g(1) = b(2) ^ b(1)

g(0) = b(1) ^ b(0)

g(n) = b(n+1) ^ b(n)

Gray to Binary

b(3) = g(3)

b(2) = g(3) ^ g(2)

b(1) = g(3) ^ g(2) ^ g(1)

b(0) = g(3) ^ g(2) ^ g(1) ^ g(0)

  • 空满判断(gray)

FIFO读空条件:write pointer == read pointer

FIFO写满条件

        1、FIFO的深度==2的幂次

        假设深度为8的FIFO一开始就只写不读,写满8个后,写指针gray码为4’b1100,此时读指针是4’b0000; 再假设读指针停在4’b0011,写指针写到4‘b1111,

        则此时FIFO写满。可以读写指针看到高两位相反,剩下位数相同。因此写满标志条件: (写域写指针高两位==~写域读指针高两位)&&(写域写指针剩余LSB==写域读指针剩余LSB)

          2、FIFO的深度!=2的幂次

        若FIFO深度为7,则首尾向内收缩一位,即4’b0001与4‘b1001,这样可以保证只有最高位取反,其余相等,深度为6同理,如红色箭头所示,收缩两位。

  • 写在最后

        仿真时,如果写时钟快于读时钟,仿真图里将写指针同步到读域时,发现漏读了指针,不要惊慌!这个问题肯定会发生,基本无法解决,但是不会对读取数据产生影响,因为同步写指针到读域时,写指针还在按自己的时钟递增,读域采到的写指针数值肯定不会大于此刻写域的写指针。

        这个主要影响判断读空的条件,可能会产生假空的状态,而实际上FIFO并没有空,此时读数据就会停止,直到空标志拉低,再继续读即可。

        同理,如果读时钟快于写时钟,可能会出现假满状态,也不会影响读数据。

代码

  1. module fifo #(
  2. parameter WSIZE = 8, //the width of fifo
  3. parameter DSIZE = 5 //the depth of fifo
  4. )
  5. (
  6. input sys_rst_n,
  7. //write
  8. input wclk, //clk of writing
  9. input w_en, //en of writing
  10. input wire [WSIZE-1:0]wdata, //data of writing
  11. output w_full, //the signal of writing fully
  12. //read
  13. input rclk, //clk of reading
  14. input r_en, //en of reading
  15. output reg [WSIZE-1:0]rdata, //data of reading
  16. output r_null, //the signal of reading nully
  17. output reg r_valid //Read the data validly
  18. );
  19. //buffer
  20. reg [WSIZE-1:0]buffer[(1<<DSIZE)-1:0]; //Pay attention to this writing
  21. //reg of write
  22. wire [DSIZE:0]gwptr; //gray code of Writing pointer
  23. reg [DSIZE:0]bwptr, //binary code of Writing pointer
  24. bwptr_rclk, //binary code of Writing pointer of reading clk
  25. gwptr_wclk_1, //gray code of Writing pointer for hitting 1 beat
  26. gwptr_rclk_1, //gray code of reading pointer for hitting 1 beat
  27. gwptr_rclk_2; //gray code of reading pointer for hitting 2 beat
  28. //reg of read
  29. wire [DSIZE:0]grptr; //gray code of reading pointer
  30. reg [DSIZE:0]brptr, //binary code of reading pointer
  31. brptr_wclk, //binary code of reading pointer of writing clk
  32. grptr_rclk_1, //gray code of reading pointer for hitting 1 beat
  33. grptr_wclk_1, //gray code of Writing pointer for hitting 1 beat
  34. grptr_wclk_2; //gray code of Writing pointer for hitting 2 beat
  35. //b to g
  36. assign gwptr = (bwptr >> 1) ^ bwptr; //write pointers to convert to Gray code
  37. assign grptr = (brptr >> 1) ^ brptr; //read pointers to convert to Gray code
  38. //write the pointer Gray code in the read field to play two beats
  39. always @(posedge rclk, negedge sys_rst_n) begin
  40. if(~sys_rst_n) begin
  41. gwptr_rclk_1 <= 0;
  42. gwptr_rclk_2 <= 0;
  43. end
  44. else begin
  45. gwptr_rclk_1 <= gwptr;
  46. gwptr_rclk_2 <= gwptr_rclk_1;
  47. end
  48. end
  49. //read the pointer Gray code in the write field to play two beats
  50. always @(posedge wclk, negedge sys_rst_n) begin
  51. if(~sys_rst_n) begin
  52. grptr_wclk_1 <= 0;
  53. grptr_wclk_2 <= 0;
  54. end
  55. else begin
  56. grptr_wclk_1 <= grptr;
  57. grptr_wclk_2 <= grptr_wclk_1;
  58. end
  59. end
  60. //Judge full
  61. assign w_full = ((gwptr[DSIZE:DSIZE-1] == ~grptr_wclk_2[DSIZE:DSIZE-1]) && (gwptr[DSIZE-2:0] == grptr_wclk_2[DSIZE-2:0]));
  62. //Judge null
  63. assign r_null = (grptr == gwptr_rclk_2)? 1'd1 : 1'd0;
  64. //write pointer
  65. always @(posedge wclk, negedge sys_rst_n) begin
  66. if(~sys_rst_n) begin
  67. bwptr <= 0;
  68. end
  69. else if(~w_full && w_en) begin
  70. bwptr <= bwptr + 1;
  71. end
  72. else begin
  73. bwptr <= bwptr;
  74. end
  75. end
  76. //read pointer
  77. always @(posedge rclk, negedge sys_rst_n) begin
  78. if(~sys_rst_n) begin
  79. brptr <= 0;
  80. end
  81. else if(~r_null && r_en) begin
  82. brptr <= brptr + 1;
  83. end
  84. else begin
  85. brptr <= brptr;
  86. end
  87. end
  88. //module memory ();
  89. initial begin
  90. $readmemb("C:/Users/86152/Desktop/FIFO/CODE/doc/memory.txt", buffer);
  91. end
  92. //write data
  93. always @(posedge wclk, negedge sys_rst_n) begin
  94. if(~w_full && w_en) begin
  95. buffer[bwptr[DSIZE-1:0]] <= wdata; //!This expression is ture
  96. end
  97. end
  98. //read data
  99. always @(posedge rclk, negedge sys_rst_n) begin
  100. if(~r_null && r_en) begin
  101. rdata <= buffer[brptr[DSIZE-1:0]];
  102. r_valid <= 1'd1;
  103. end
  104. else begin
  105. r_valid <= 1'd0;
  106. rdata <= rdata;
  107. end
  108. end
  109. endmodule

tb

  1. `timescale 1ns/1ns
  2. module fifo_tb;
  3. //SIZE
  4. parameter WSIZE = 8; //the width of fifo
  5. parameter DSIZE = 5; //the depth of fifo
  6. //system
  7. reg sys_rst_n;
  8. //write
  9. reg wclk; //clk of writing
  10. reg w_en; //en of writing
  11. reg [WSIZE-1:0]wdata; //data of writing
  12. wire w_full; //the signal of writing fully
  13. //read
  14. reg rclk; //clk of reading
  15. reg r_en; //en of reading
  16. wire [WSIZE-1:0]rdata; //data of reading
  17. wire r_null; //the signal of reading nully
  18. wire r_valid; //Read the data validly
  19. initial begin
  20. sys_rst_n <= 1'b0;
  21. //clk
  22. wclk <= 1'b0;
  23. rclk <= 1'b0;
  24. //en
  25. w_en <= 1'b0;
  26. r_en <= 1'b0;
  27. #10
  28. sys_rst_n <= 1'b1;
  29. w_en <= 1'b1; //just write
  30. r_en <= 1'b0;
  31. #64
  32. w_en <= 1'd0; //write fully and then read completely
  33. r_en <= 1'b1;
  34. #192
  35. w_en <= 1'd1; //just write
  36. r_en <= 1'b0;
  37. #40
  38. w_en <= 1'd1; //write and read
  39. r_en <= 1'b1;
  40. #36
  41. w_en <= 1'd0; //just read
  42. r_en <= 1'b1;
  43. #40
  44. w_en <= 1'd1; //just
  45. r_en <= 1'b1;
  46. end
  47. //wclk
  48. always #1 wclk <= ~wclk;
  49. //rclk
  50. always #3 rclk <= ~rclk;
  51. //wdata
  52. always @(posedge wclk, negedge sys_rst_n) begin
  53. if(~sys_rst_n) begin
  54. wdata <= 8'b000_1111;
  55. end
  56. else begin
  57. wdata <= wdata + 8'd1;
  58. end
  59. end
  60. fifo fifo_tb(
  61. .sys_rst_n(sys_rst_n),
  62. .wclk(wclk),
  63. .w_en(w_en),
  64. .wdata(wdata),
  65. .w_full(w_full),
  66. .rclk(rclk),
  67. .r_en(r_en),
  68. .rdata(rdata),
  69. .r_null(r_null),
  70. .r_valid(r_valid)
  71. );
  72. endmodule

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

闽ICP备14008679号