当前位置:   article > 正文

异步FIFO设计详解_异步fifo空满判断

异步fifo空满判断

目录

一、FIFO介绍

二、FIFO的“空”/“满”检测

 三、同步化分析

四、异步FIFO设计与结构


一、FIFO介绍

FIFO存储器概念介绍_的博客-CSDN博客

二、FIFO的“空”/“满”检测

FIFO设计的关键:产生可靠的FIFO读写指针和生成FIFO“空”/“满”状态标志。

当读写指针相等时,表明FIFO为空,这种情况发生在复位操作时,或者当读指针读出FIFO中最后一个字后,追赶上了写指针时,如下图所示:

当读写指针再次相等时,表明FIFO为满,这种情况发生在,当写指针转了一圈,折回来(wrapped around)又追上了读指针,如下图:

为了区分到底是满状态还是空状态,可以采用以下方法:

方法1在指针中添加一个额外的位(extra bit)

当写指针增加并越过最后一个FIFO地址时,就将写指针这个未用的MSB加1,其它位回零。对读指针也进行同样的操作。此时,对于深度为2的n次方的FIFO,需要的读/写指针位宽为(n+1)位,如对于深度为8的FIFO,需要采用4bit的计数器,0000~1000、1001~1111,MSB作为折回标志位,而低3位作为地址指针。

        如果两个指针的MSB不同,说明写指针比读指针多折回了一次;如r_addr=0000,而w_addr = 1000,为满。
        如果两个指针的MSB相同,则说明两个指针折回的次数相等,其余位也相等,即两个指针相等说明FIFO为空;

这个办法主要用于同步FIFO判断空满

将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。

方法2使用gray码进行对比,如何判断“空”与“满”

使用gray码解决了一个问题,但同时也带来另一个问题,即在格雷码域如何判断空与满。

对于“空”的判断依然依据二者完全相等(包括MSB);

而对于“满”的判断,如下图,由于gray码除了MSB外,具有镜像对称的特点,当读指针指向7,写指针指向8时,除了MSB,其余位皆相同,不能说它为满。因此不能单纯的只检测最高位了,在gray码上判断为满必须同时满足以下3条:

  • wptr和同步过来的rptr的MSB不相等,因为wptr必须比rptr多折回一次。
  • wptr与rptr的次高位不相等,如上图位置7和位置15,转化为二进制对应的是0111和1111,MSB不同说明多折回一次,111相同代表同一位置。
  •  剩下的其余位完全相等

 三、同步化分析

由于是异步FIFO的设计,读写时钟不一样,在产生读空信号和写满信号时,会涉及到跨时钟域的问题,如何解决?
跨时钟域的问题:由于读指针是属于读时钟域的,写指针是属于写时钟域的,而异步FIFO的读写时钟域不同,是异步的,要是将读时钟域的读指针与写时钟域的写指针不做任何处理直接比较肯定是错误的,因此我们需要进行同步处理以后仔进行比较
解决方法: 加两级寄存器同步 + 格雷码(目的都是消除亚稳态)
 
1.使用异步信号进行使用的时候,好的设计都会对异步信号进行同步处理,同步一般采用多级D触发器级联处理,如下图。这种模型大部分资料都说的是第一级寄存器产生亚稳态后,第二级寄存器稳定输出概率为90%,第三极寄存器稳定输出的概率为99%,如果亚稳态跟随电路一直传递下去,那就会另自我修护能力较弱的系统直接崩溃

2.将一个二进制的计数值从一个时钟域同步到另一个时钟域的时候很容易出现问题,因为采用二进制计数器时所有位都可能同时变化,在同一个时钟沿同步多个信号的变化会产生亚稳态问题。而使用格雷码只有一位变化,因此在两个时钟域间同步多个位不会产生问题。所以需要一个二进制到gray码的转换电路,将地址值转换为相应的gray码,然后将该gray码同步到另一个时钟域进行对比,作为空满状态的检测。
那么,多位二进制码如何转化为格雷码?

verilog代码实现就一句:assign  gray_code = (bin_code>>1)  ^  bin_code;

顺便提一下,多位格雷码如何转化为二进制码

格雷码域如何判断空与满?前面已经讨论过,简单来说就是:

读空时:需要读时钟域的格雷码rgray_next和被同步到读时钟域的写指针rd2_wp每一位完全相同;

写满时:需要写时钟域的格雷码wgray_next和被同步到写时钟域的读指针wr2_rp高两位不相同,其余各位完全相同;

assign full = (wr_addr_gray == {~(rd_addr_gray_d2[addr_width-:2]),rd_addr_gray_d2[addr_width-2:0]}) ;//高两位不同

assign empty = ( rd_addr_gray == wr_addr_gray_d2 );

四、异步FIFO设计与结构

  • 总体结构

  • 设计代码
  1. module asyn_fifo #(
  2. parameter DATA_WIDTH = 4'd8;
  3. parameter DATA_DEPTH = 5'd16;
  4. parameter ADDR_WIDTH = 4'd4;
  5. )(
  6. input [DATA_WIDTH-1:0] data_in;
  7. input wr_clk;
  8. input rst_n;
  9. input wr_en;
  10. output full;
  11. input rd_clk;
  12. input rd_en;
  13. output reg [DATA_WIDTH-1:0] data_out;
  14. output empty
  15. );
  16. wire [ADDR_WIDTH - 1'd1 : 0] wr_addr;
  17. reg [ADDR_WIDTH : 0] wr_ptr;
  18. wire [ADDR_WIDTH : 0] wr_gray;
  19. reg [ADDR_WIDTH : 0] wr_gray_d1;
  20. reg [ADDR_WIDTH : 0] wr_gray_d2;
  21. wire [ADDR_WIDTH - 1'd1 : 0] rd_addr;
  22. reg [ADDR_WIDTH : 0] rd_ptr;
  23. wire [ADDR_WIDTH : 0] rd_gray;
  24. reg [ADDR_WIDTH : 0] rd_gray_d1;
  25. reg [ADDR_WIDTH : 0] rd_gray_d2;
  26. reg [DATA_WIDTH - 1'd1 : 0] fifo_ram [DATA_DEPTH - 1'd1 : 0];
  27. assign wr_addr = wr_ptr[data_addr - 1'd1 : 0];
  28. assign rd_addr = rd_ptr[data_addr - 1'd1 : 0];
  29. //写指针
  30. always @(posedge wr_clk or negedge rst_n )
  31. begin
  32. if (!rst_n)
  33. wr_ptr <= 'd0;
  34. else if ( (wr_en) && (!full) )
  35. wr_ptr <= 'd1 + wr_ptr;
  36. else
  37. wr_ptr <= wr_ptr;
  38. end
  39. //读指针
  40. always @(posedge rd_clk or negedge rst_n )
  41. begin
  42. if (!rst_n)
  43. rd_ptr <= 'd0;
  44. else if ( (rd_en) && (!empty) )
  45. rd_ptr <= 'd1 + rd_ptr;
  46. else
  47. rd_ptr <= rd_ptr;
  48. end
  49. //---------------------------------------------------------------
  50. assign wr_gray = (wr_ptr >> 1'd1) ^ wr_ptr;
  51. assign rd_gray = (rd_ptr >> 1'd1) ^ rd_ptr;
  52. always @(posedge rd_clk )
  53. begin
  54. wr_gray_d1 <= wr_gray;
  55. wr_gray_d2 <= wr_gray_d1;
  56. end
  57. always @(posedge wr_clk )
  58. begin
  59. rd_gray_d1 <= rd_gray;
  60. rd_gray_d2 <= rd_gray_d1;
  61. end
  62. //------------------------------------------------------------------
  63. assign full = (wr_gray == {~(rd_gray_d2[ADDR_WIDTH :ADDR_WIDTH-1 ]),rd_gray_d2[ADDR_WIDTH-2:0]});
  64. assign empty = (rd_gray == wr_gray_d2);
  65. //-------------------------------------------------------------write operation
  66. always @(posedge wr_clk or negedge rst_n)
  67. begin
  68. if(!rst_n)
  69. begin
  70. fifo_ram [wr_addr] <= 'h0;
  71. end
  72. else if ( (wr_en) && (!full) )
  73. fifo_ram[wr_addr] <= data_in;
  74. else
  75. fifo_ram[wr_addr] <= fifo_ram[wr_addr];
  76. end
  77. //--------------------------------------------------------------read operation
  78. always @(posedge rd_clk or negedge rst_n)
  79. begin
  80. if(!rst_n)
  81. data_out <= 'h0;
  82. else if( (rd_en) && (!empty) )
  83. data_out <= fifo_ram[rd_addr];
  84. else
  85. data_out <= data_out;
  86. end
  87. endmodule
  •  测试代码
  1. module asyn_fifo_tb;
  2. parameter DATA_W = 8 ;
  3. parameter ADDR_W = 4 ;
  4. parameter data_hight = 16 ;
  5. reg wr_clk ;
  6. reg rd_clk ;
  7. reg rst_n ;
  8. reg wr_en ;
  9. reg [DATA_W-1:0] wr_data ;
  10. reg rd_en ;
  11. wire [DATA_W-1:0] rd_data ;
  12. wire empty ;
  13. wire full ;
  14. asyn_fifo u_FIFO_asyn
  15. (
  16. .data_out (rd_data),
  17. .data_in (wr_data),
  18. .wr_clk (wr_clk) ,
  19. .rst_n (rst_n) ,
  20. .full (full) ,
  21. .empty (empty) ,
  22. .rd_clk (rd_clk) ,
  23. .rd_en (rd_en) ,
  24. .wr_en (wr_en)
  25. );
  26. always #10 wr_clk = ~wr_clk;
  27. always #5 rd_clk = ~rd_clk;
  28. initial begin
  29. wr_clk = 1;
  30. rd_clk = 0;
  31. rst_n = 0;
  32. wr_en = 0;
  33. wr_data = 0;
  34. rd_en = 0;
  35. #101;
  36. rst_n = 1;
  37. #20;
  38. gen_data;
  39. @(posedge rd_clk);
  40. rd_en=1;
  41. #1000 $finish;
  42. end
  43. task gen_data;
  44. integer i;
  45. begin
  46. for(i=0;i<15;i=i+1)
  47. begin
  48. wr_en = 1;
  49. wr_data = i;
  50. #20;
  51. end
  52. wr_en = 0;
  53. wr_data = 0;
  54. end
  55. endtask
  56. /*initial
  57. begin
  58. `ifdef DUMP_VPD
  59. $vcdpluson();
  60. `endif
  61. end*/
  62. initial begin
  63. $fsdbDumpfile("asy_fifo.fsdb");
  64. $fsdbDumpvars(0);
  65. end
  66. endmodule

 理论参考:

Clifford E. Cummings《Simulation and Synthesis Techniques for Asynchronous FIFO Design》

https://blog.csdn.net/alangaixiaoxiao/article/details/81432144

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

闽ICP备14008679号