当前位置:   article > 正文

异步fifo设计_异步fifo full写时钟

异步fifo full写时钟

异步FIFO:顾名思义就是读写时钟属于不同时钟域,为了解决读写两端时序一不一致而广泛应用。异步fifo相对于同步FIFO的难点就是处理fifo的读写指针,以及相对应的空满标志。

1、原理

1.1、异步fifo的结构图如下:

        由图可知,异步FIFO主要划分两个时钟域,

        写时钟域:

        mem_wr_en=wr_en & ~fifo_full,表示只要MEM非满,即可往MEM写数据;而fifo_full=(wr_addr_gray == {~(rd_addr_gray_d2[addr_width-:2]),rd_addr_gray_d2[addr_width-2:0]}) ,表示读写指针之间的位移等于FIFO的最大深度,至于gray码高2bit相反原因下面详解。

读时钟域:

        mem_rd_en=rd_en & ~fifo_empty,表示只要MEM非空,即可往MEM读数据;而fifo_empty=( rd_addr_gray == wr_addr_gray_d2 ),表示读指针追上写指针,即MEM内没有数据。

1.2、满标志判断,gray码高2bit相反分析

        由上图可知,当写指针填满整个FIFO,rd_addr=0011, rd_gray=0010, wr_addr=1011, wr_gray=1110, 故高2bit相反。

2、verilog 代码

  1. module fifo_async#(
  2. parameter data_width = 16,
  3. parameter data_depth = 256,
  4. parameter addr_width = 8
  5. ) (
  6. input wire wr_clk, //write signal of write clock domain
  7. input wire wr_rst_n,
  8. input wire wr_en,
  9. input wire [data_width-1:0] din,
  10. input wire rd_clk, //read signal of read clock domain
  11. input wire rd_rst_n,
  12. input wire rd_en,
  13. output reg [data_width-1:0] dout,
  14. output wire empty, //fifo empty
  15. output wire full //fifo full
  16. );
  17. reg [addr_width:0] wr_addr_ptr; //地址指针,比地址多一位,MSB用于检测在同一圈
  18. reg [addr_width:0] rd_addr_ptr;
  19. wire [addr_width-1:0] wr_addr; //RAM 地址
  20. wire [addr_width-1:0] rd_addr;
  21. wire [addr_width:0] wr_addr_gray; //地址指针对应的格雷码
  22. reg [addr_width:0] wr_addr_gray_d1;
  23. reg [addr_width:0] wr_addr_gray_d2;
  24. wire [addr_width:0] rd_addr_gray;
  25. reg [addr_width:0] rd_addr_gray_d1;
  26. reg [addr_width:0] rd_addr_gray_d2;
  27. reg [data_width-1:0] fifo_ram [data_depth-1:0]; //store data
  28. //--------------------------write side----------------------------
  29. //write data to memory
  30. always@(posedge wr_clk or negedge wr_rst_n) begin
  31. if(~wr_rst_n)
  32. fifo_ram[wr_addr] <= 'h0; //fifo复位后输出总线上是0,并非ram中真的复位。可无
  33. else if(wr_en && (~full))
  34. fifo_ram[wr_addr] <= din;
  35. end
  36. //count write pointer
  37. always@(posedge wr_clk or negedge wr_rst_n) begin
  38. if(~wr_rst_n)
  39. wr_addr_ptr <= 'h0;
  40. else if(wr_en && (~full))
  41. wr_addr_ptr <= wr_addr_ptr + 1;
  42. end
  43. assign wr_addr = wr_addr_ptr[addr_width-1-:addr_width];
  44. //gray code process
  45. assign wr_addr_gray = (wr_addr_ptr >> 1) ^ wr_addr_ptr;
  46. always@(posedge wr_clk ) begin : sync_to_wr_domain
  47. rd_addr_gray_d1 <= rd_addr_gray;
  48. rd_addr_gray_d2 <= rd_addr_gray_d1;
  49. end
  50. assign full = (wr_addr_gray == {~(rd_addr_gray_d2[addr_width-:2]),rd_addr_gray_d2[addr_width-2:0]}) ;//高两位不同
  51. //--------------------------write side----------------------------
  52. //read data from memory
  53. always@(posedge rd_clk or negedge rd_rst_n) begin
  54. if(~rd_rst_n)
  55. dout <= 'h0;
  56. else if(rd_en && (~empty))
  57. dout <= fifo_ram[rd_addr];
  58. end
  59. //count read pointer
  60. always@(posedge rd_clk or negedge rd_rst_n) begin
  61. if(~rd_rst_n)
  62. rd_addr_ptr <= 'h0;
  63. else if(rd_en && (~empty))
  64. rd_addr_ptr <= rd_addr_ptr + 1;
  65. end
  66. assign rd_addr = rd_addr_ptr[addr_width-1-:addr_width];
  67. //gray code process
  68. assign rd_addr_gray = (rd_addr_ptr >> 1) ^ rd_addr_ptr;
  69. always@(posedge rd_clk) begin : sync_to_rd_domain
  70. wr_addr_gray_d1 <= wr_addr_gray;
  71. wr_addr_gray_d2 <= wr_addr_gray_d1;
  72. end
  73. assign empty = ( rd_addr_gray == wr_addr_gray_d2 );

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

闽ICP备14008679号