当前位置:   article > 正文

异步FIFO设计

异步fifo设计

1. 应用场景

  异步FIFO用来在两个异步时钟域间传输数据。如图所示是两个系统,分别为“system X”和“system Y”,从“system X”向“system Y”传输数据,两个系统工作在不同时钟域。

ea609b260d19ca31f3b83c087e5f777a.png

  “system X”使用“xclk”将数据写入FIFO,“system Y”使用“yclk”将数据读出,“fifo_full”和“fifo_empty”分别负责监控上溢(overflow)和下溢(underflow)情况。

        “fifo_full”指示上溢情况,拉高时数据不应再写入FIFO,否则会将FIFO内的数据覆盖掉。

“fifo_empty”指示上溢情况,拉高时不应读取FIFO,否则会读出垃圾数据。

与握手信号不用,异步FIFO用于对性能要求较高的设计中,尤其是时钟延迟比系统资源更为重要的环境中。

2. 异步FIFO结构

  与同步FIFO设计原理相似,异步FIFO的结构也可以分为三个部分,如图所示,fifo write control、fifo read control和fifo memory,其中fifo write control和fifo read control分别工作在wr_clk和rd_clk时钟域,fifo memory工作在wr_clk和rd_clk时钟域。

fifo write control:写指针产生、满信号产生和读指针同步器;

fifo read control:读指针产生、空信号产生和写指针同步器;

fifo memory:缓存数据。

1d677c2525dfa759a1b08d6bc9c4bb72.png

3. 关键设计

3.1 异步FIFO与同步FIFO差异

  异步FIFO相较于同步FIFO,主要有两点不同:

Fifo memory工作在两个时钟域;

Wr_ctrl和rd_ctrl工作在不同时钟域;

读、写指针经过两级同步器会存在延迟。

  异步FIFO不能再使用“计数器”产生fifo空、满信号,原因在于计数器不能被两个时钟同时驱动,此时只能通过比较读、写指针来产生空、满信号,将读指针同步到写时钟域,与写指针比较产生满信号;将写指针同步到读时钟域,与读指针比较产生空信号。

  读写指针的同步都需要跨时钟域传输,若使用握手信号的方式同步指针,效率很低;假如指针仍使用“二进制编码”,使用两级同步器同步指针,可能会出现亚稳态导致用于比较的指针出错。

  如指针从“111”→“000”,经过两级同步器,可能的结果有8种,每一个比特都可能存在采样错误,错误的指针会导致fifo空、满信号异常。

读指针同步错误,FIFO满信号未正常拉高,继续写FIFO会覆盖原数据,导致数据传输错误;

写指针同步错误,FIFO空信号为正常拉高,继续读FIFO会读出垃圾数据,导致数据传输错误。

  异步FIFO的指针同步应该避免使用二进制编码。

3.2 格雷码

  实现异步FIFO指针同步的一种方式是使用格雷码,格雷码是“单位间距码”,即相邻值之间只有1bit不同。格雷码与二进制码的对应关系如图所示。格雷码有以下几个特点:

单位间距码:相邻值之间只有1bit不同

中心对称:除MSB外,其余bit中心对称

4b178819c1711363f8c3409cd449900d.png

  指针采用格雷码计数,使用两级同步器同步指针很少会出现亚稳态,此外取样后的值最多只有1bit出现错误,但该错误不会影响空、满信号的正确产生。考虑格雷码读、写指针采样错误的情况:

读指针采样错误:相邻格雷码只有1bit不同,若采样出现亚稳态会出现两种情况,一是采样值保持不变,同步的读指针小于当前的真实值,fifo_full会提前拉高,此时不会出现overflow;二是采样值采样成功,同步的读指针等于当前的真实值。两种结果都不会影响“fifo_full”的正确产生;

写指针采样错误:写指针同理,一是同步的写指针小于当前的真实值, fifo_empty会提前拉高,虽然还有数据未读出,但这种情况也不会造成underflow;二是同步的写指针等于当前的真实值。两种结果都不会影响“fifo_empty”的正确产生。

3.3 同步指针的影响

  比较读、写指针的目的是产生FIFO的空满信号,相较于同步FIFO,异步FIFO在两个时钟域分别比较读、写指针,读、写指针都需要经过两级同步器。

3.3.1 FIFO的“假满”

  由于读指针同步到写时钟域存在2*T_wclk的延迟,此时写时钟域采样到的rd_ptr_sync小于等于读时钟域的rd_ptr。rd_ptr_sync小于rd_ptr的情况如图所示,wr_ptr追赶上rd_ptr_sync(wr_ptr和rd_ptr_sync都转换为二进制码),最高位不同其余位相同,此时会拉高fifo_full信号,但实际上FIFO内还有两个地址空间可以写入数据,这种情况就是FIFO的“假满”。FIFO的“假满”虽然阻止了数据的写入,但是对数据的准确性是没有影响的。只有在FIFO实际已经满了但没阻止数据写入才会出现overflow(原数据未读出就被覆盖)。

478985a2682f4447270bd526453c97d2.png

3.3.2 FIFO的“假空”

  由于写指针同步到读时钟域存在2*T_rclk的延迟,此时读时钟域采样到的wr_ptr_sync小于等于读时钟域的wr_ptr。wr_ptr_sync小于等于wr_ptr的情况如图所示,wr_ptr_sync等于rd_ptr(指针均以转换为二进制码),所有比特位均相等,此时会拉高fifo_empty信号。FIFO的“假空”虽然在实际有数据的情况下拉高了FIFO的空信号,阻止了数据的读出,但是对数据的准确性是没有影响的,直到读时钟域看到的写指针变化才会拉低FIFO的空信号。只有在FIFO为空的时候没有阻止读操作才会产生问题,即underflow问题。

875a2ac06f88cbe8fa89c056e2e97668.png

3.4 格雷码与二进制码转换

  读、写指针有二进制码转为格雷码后经两级同步器同步到写、读时钟域,在读、写时钟域有时还需要将格雷码转为二进制码进行指针的比较以产生FIFO的空、满信号,下面将给出格雷码与二进制码相互转换的方法。

3.4.1 二进制码转格雷码

  二进制码转格雷码的公式如下所示,其中n表示位宽。

63012f4c8cfa2c4107fd8d625fd670ed.png

3.4.2 格雷码转二进制码

  格雷码转二进制码的公式如下所示,其中n表示位宽。

9e58ca03dcc37e30b4704e19dd771b0e.png

3.5 读、写指针产生

  产生读、写指针有两种方法,一种是直接使用格雷码计数器产生读写指针,一种是使用二进制码计数器产生读写指针,再将读写指针转换为格雷码用于跨时钟域的同步,下面将分析这两种设计方法。

3.5.1 格雷码计数器

  格雷码计数器的结构如图所示,由格雷码转二进制码、二进制加法器和二进制码转格雷码组成。

f42f2623ebfe6015587cab6b4238b41b.png

  从面积和工作频率两个方面分析该设计。

面积:格雷码转二进制、二进制转格雷码的组合逻辑,格雷码指针寄存器;

工作频率:寄存器输入信号的组合逻辑较为复杂,该电路工作在较高频率可能存在时序违例的情况。

3.5.2 二进制码计数器

  二进制码计数器的结构如图所示,由二进制转格雷码、二进制码寄存器和格雷码寄存器组成。

84c53fff2cbd0af7fe262ec6a9e36f1a.png

  从面积和工作频率两个方面分析该设计。

面积:二进制转格雷码、两个寄存器;

工作频率:寄存器输入只有加法器或二进制转格雷码,组合逻辑延迟相对较小,该电路可以工作在较高频率。

3.6 空、满信号产生

  FIFO的空、满信号通过比较读、写指针可以得到,下文将讨论两种计数器设计下FIFO的空、满信号产生。

3.6.1 格雷码计数器

3.6.1.1 二进制码产生空、满信号

  N位指针可以覆盖FIFO中的2^N个地址。在两个指针相等时,因为FIFO可能处于空状态也可能处于满状态,所以需要使用额外的位对这两种情况进行区分。

FIFO满:二进制码指针的最高有效位不同,其余比特位相同;

FIFO空:二进制码指针所有比特位相等。

  格雷码计数器设计下,使用二进制码产生空、满信号的结构如图所示。由于读写指针的值都是以格雷码保存,而所有比较和递增是以二进制码形式进行,实现和纠错比较简单。

  读指针经过两级同步后得到rd_ptr_sync,将格雷码转为二进制码rd_ptr_sync_b,在写时钟域还需要将格雷码的wr_ptr转换为二进制码的wr_ptr_b,将rd_ptr_sync_b和wr_ptr_b进行比较,得到FIFO的满信号。

  写指针经过两级同步后得到wr_ptr_sync,将格雷码的wr_ptr_sync转换为二进制码的wr_ptr_sync_b,在读时钟域还需要将格雷码的rd_ptr转为rd_ptr_b,最后将wr_ptr_sync_b和rd_ptr_b进行比较,得到FIFO的空信号。

d25f0b30c5c8b03b9e67a80294622e2d.png

  该设计共使用了4个“格雷码转二进制码”,组合逻辑路径较长,较高频率下工作可能会存在时序违例的情况。如果直接使用格雷码指针产生FIFO的空、满信号,就不需要这些转换器,下文将分析使用格雷码指针产生FIFO的空、满信号。

3.6.1.2 格雷码产生空、满信号

  使用格雷码产生FIFO的空满信号要求使用两个格雷码计数器,分别是N位和N-1位。由于格雷码除最高位镜像对称的特性,可以使用N位格雷码计数器产生N-1位格雷码计数器。N-1位格雷码计数器的产生如图所示,将N位格雷码计数器的2个MSB异或得到的值作为N-1位格雷码计数器的最高位,其余N-2位与N位格雷码的N-2位完全一致。

17cf9eef70b5b7106188191368d5391c.png

  格雷码计数器产生空信号使用N位计数器与二进制码相同,当读写指针完全相同时FIFO为空。

  格雷码计数器产生满信号与二进制码不同。如图所示,当rd_ptr和wr_ptr相等时FIFO为空。wr_ptr加一后,wr_ptr和rd_ptr的最高为不同、其余位相同,按照二进制码的判断标准此时FIFO为满,但此时FIFO并没有满,所以二进制码的FIFO满判断方法不再适用于格雷码。

  双格雷码计数器可以很好地解决该问题。N位计数器用于区分写指针比读指针多回绕一次,N-1位计数器用于确定写指针的真实位置。FIFO的满需要满足三个条件:

N位格雷码指针最高有效位不同;

N-1位格雷码指针最高有效位相同;(该条件等效于N位格雷码指针的次高位不同)

N位格雷码指针剩余N-2位全部相等。

3.6.2 二进制码计数器

  格雷码计数器的两种实现方式都略显复杂,二进制码计数器提供了一种简单的实现方法。如图所示,二进制码计数器使用两个寄存器分别缓存二进制指针和格雷码指针。二进制码计数器产生空、满信号如图所示。

073dc854bbccbd56d3478796a738d2f9.png

  仅需将同步后的指针转为二进制码,然后与二进制码指针比较,按照二进制码FIFO空、满方法产生FIFO空、满信号。

4. 大容量异步FIFO设计

  大容量同步FIFO是使用SRAM作为FIFO memory实现的,大容量异步FIFO仍可以使用该方法,不过更为常用的方法是使用“大容量同步FIFO和小容量异步FIFO”级联来实现的。原因在于异步FIFO的功能只是跨时钟域传输数据,同步FIFO更适合缓存数据,结合这两种FIFO的特点将其级联,得到大容量异步FIFO。

5. 代码实现

5.1 async_fifo_top

  1. //=================================================================================
  2. // module : async_fifo_gray_cnt.v
  3. // description : asynchronous fifo , pointer generate by gray counter
  4. // data : 2022/2/27
  5. // author : souther meditating
  6. //=================================================================================
  7. module async_fifo(
  8. wclk,
  9. wrst_n,
  10. wr_en,
  11. wr_data,
  12. rclk,
  13. rrst_n,
  14. rd_en,
  15. rd_data,
  16. fifo_full,
  17. fifo_empty
  18. );
  19. //=================================================================================
  20. // parameter & localparam
  21. //=================================================================================
  22. //=================================================================================
  23. // parameter
  24. parameter FIFO_DATA_WIDTH = 16;
  25. parameter FIFO_DEPTH = 16;
  26. //=================================================================================
  27. // localparam
  28. localparam FIFO_ADDR_WIDTH = clog2(FIFO_DEPTH);
  29. localparam FIFO_PTR_WIDTH = FIFO_ADDR_WIDTH + 1;
  30. //=================================================================================
  31. // I/O
  32. //=================================================================================
  33. input wclk;
  34. input wrst_n;
  35. input wr_en;
  36. input [FIFO_DATA_WIDTH-1:0] wdata;
  37. input rclk;
  38. input rrst_n;
  39. input rd_en;
  40. output [FIFO_DATA_WIDTH-1:0] rdata;
  41. output fifo_full;
  42. output fifo_empty;
  43. //=================================================================================
  44. // signal
  45. //=================================================================================
  46. // ---- fifo mem ----
  47. wire [FIFO_ADDR_WIDTH-1:0] waddr;
  48. wire [FIFO_ADDR_WIDTH-1:0] raddr;
  49. // ---- wr_sync_cell ----
  50. wire [FIFO_PTR_WIDTH-1:0] rptr_g;
  51. wire [FIFO_PTR_WIDTH-1:0] rptr_g_sync;
  52. // ---- rd_sync_cell ----
  53. wire [FIFO_PTR_WIDTH-1:0] wptr_g;
  54. wire [FIFO_PTR_WIDTH-1:0] wptr_g_sync;
  55. // ---- wr_ptr_full ----
  56. //=================================================================================
  57. // main body
  58. //=================================================================================
  59. //=================================================================================
  60. // 1. fifo_mem
  61. // 2. wr_sync_cell
  62. // 3. rd_sync_cell
  63. // 4. wptr_full
  64. // 5. rptr_empty
  65. //=================================================================================
  66. // fifo_mem
  67. fifo_mem #(
  68. .DSIZE (FIFO_DATA_WIDTH ),
  69. .FIFO_DEPTH (FIFO_DEPTH )
  70. )
  71. u_fifo_mem(
  72. .raddr (raddr ),
  73. .rdata (rdata ),
  74. .wclk (wclk ),
  75. .wr_en (wr_en ),
  76. .waddr (waddr ),
  77. .wdata (wdata ),
  78. .fifo_full (fifo_full )
  79. );
  80. //=================================================================================
  81. // wr_sync_cell
  82. sync_cell #(
  83. .DSIZE (FIFO_DATA_WIDTH)
  84. )
  85. u_rd_ptr_sync(
  86. .dat_i (rptr_g ),
  87. .clk_o (wclk ),
  88. .rst_n_o (wrst_n ),
  89. .dat_o (rptr_g_sync )
  90. );
  91. //=================================================================================
  92. // rd_sync_cell
  93. sync_cell #(
  94. .DSIZE (FIFO_DATA_WIDTH)
  95. )
  96. u_wr_ptr_sync(
  97. .dat_i (wptr_g ),
  98. .clk_o (rclk ),
  99. .rst_n_o (rrst_n ),
  100. .dat_o (wptr_g_sync )
  101. );
  102. //=================================================================================
  103. // wptr_full
  104. wptr_full #(
  105. .FIFO_DEPTH (FIFO_DEPTH )
  106. )
  107. u_wptr_full (
  108. .wclk (wclk ),
  109. .wrst_n (wrst_n ),
  110. .wr_en (wr_en ),
  111. .waddr (waddr ),
  112. .wptr_g (wptr_g ),
  113. .rptr_g_sync (rptr_g_sync ),
  114. .fifo_full (fifo_full )
  115. );
  116. //=================================================================================
  117. // rptr_empty
  118. rptr_empty #(
  119. .FIFO_DEPTH (FIFO_DEPTH )
  120. )
  121. u_rptr_empty(
  122. .rclk (rclk ),
  123. .rrst_n (rrst_n ),
  124. .rd_en (rd_en ),
  125. .raddr (raddr ),
  126. .wptr_g_sync (wptr_g_sync ),
  127. .rptr_g (rptr_g ),
  128. .fifo_empty (fifo_empty )
  129. );
  130. endmodule;

5.2 async_fifo_mem

  1. //=================================================================================
  2. // module : fifo_mem.v
  3. // description : register dpram
  4. // data : 2022/2/27
  5. // author : souther meditating
  6. //=================================================================================
  7. module fifo_mem (
  8. raddr,
  9. rdata,
  10. wclk,
  11. wr_en,
  12. fifo_full,
  13. waddr,
  14. wdata
  15. );
  16. // ==========================================================================
  17. // parameter
  18. // ==========================================================================
  19. parameter DSIZE = 8;
  20. parameter FIFO_DEPTH = 16;
  21. // ==========================================================================
  22. // localpara
  23. // ==========================================================================
  24. localparam FIFO_ADDR_WIDTH = $clog2(FIFO_DEPTH);
  25. // ==========================================================================
  26. // I/O
  27. // ==========================================================================
  28. input [FIFO_ADDR_WIDTH-1:0] raddr;
  29. output [DSIZE-1:0] rdata;
  30. input wclk;
  31. input wr_en;
  32. input [FIFO_ADDR_WIDTH-1:0] waddr;
  33. input [DSIZE-1:0] wdata;
  34. // ==========================================================================
  35. // signal define
  36. // ==========================================================================
  37. reg [DSIZE-1:0] fifo_mem[FIFO_DEPTH-1:0];
  38. // ==========================================================================
  39. // main body
  40. // ==========================================================================
  41. // ==========================================================================
  42. // write fifo_mem
  43. always@(posedge wclk) begin
  44. if((wr_en == 1'b1) && (fifo_full != 1'b1)) begin
  45. fifo_mem[waddr] <= wdata;
  46. end
  47. end
  48. // ==========================================================================
  49. // read fifo_mem
  50. assign rdata = fifo_mem[raddr];
  51. endmodule

5.3 sync_cell

  1. //=================================================================================
  2. // module : sync_cell.v
  3. // description : 2-stage synchronizer
  4. // data : 2022/2/27
  5. // author : souther meditating
  6. //=================================================================================
  7. module sync_cell(
  8. dat_i,
  9. clk_o,
  10. rst_n_o,
  11. dat_o
  12. );
  13. //=================================================================================
  14. // parameter & localparam
  15. //=================================================================================
  16. parameter DSIZE = 16;
  17. //=================================================================================
  18. // I/O
  19. //=================================================================================
  20. input [DSIZE-1:0] dat_i;
  21. input clk_o;
  22. input rst_n_o;
  23. output [DSIZE-1:0] dat_o;
  24. //=================================================================================
  25. // signal
  26. //=================================================================================
  27. // ---- temp flip-flop ----
  28. reg [DSIZE-1:0] dat_i_ff1;
  29. reg [DSIZE-1:0] dat_i_ff2;
  30. //=================================================================================
  31. // main body
  32. //=================================================================================
  33. always@(posedge clk_o or negedge rst_n_o) begin
  34. if(rst_n_o == 1'b0) begin
  35. dat_i_ff1 <= {DSIZE{1'b0}};
  36. dat_i_ff2 <= {DSIZE{1'b0}};
  37. end
  38. else if() begin
  39. dat_i_ff1 <= dat_i;
  40. dat_i_ff2 <= dat_i_ff1;
  41. end
  42. end
  43. assign dat_o = dat_i_ff2;
  44. endmodule

5.4 wptr_full

  1. //=================================================================================
  2. // module : wptr_full.v
  3. // description : async_fifo write ctrl
  4. // data : 2022/2/27
  5. // author : souther meditating
  6. //=================================================================================
  7. module wptr_full(
  8. wclk,
  9. wrst_n,
  10. wr_en,
  11. waddr,
  12. wptr_g,
  13. rptr_g_sync,
  14. fifo_full
  15. );
  16. //=================================================================================
  17. // parameter & localparam
  18. //=================================================================================
  19. parameter FIFO_DEPTH = 16;
  20. localparam FIFO_ADDR_WIDTH = clog2(FIFO_DEPTH) ;
  21. localparam FIFO_PTR_WIDTH = FIFO_ADDR_WIDTH + 1;
  22. //=================================================================================
  23. // I/O
  24. //=================================================================================
  25. input wclk;
  26. input wrst_n;
  27. input wr_en;
  28. output [FIFO_ADDR_WIDTH-1:0] waddr;
  29. output [FIFO_PTR_WIDTH-1:0] wptr_g;
  30. input [FIFO_PTR_WIDTH-1:0] rptr_g_sync;
  31. output fifo_full;
  32. // ==========================================================================
  33. // signal define
  34. // ==========================================================================
  35. reg [FIFO_PTR_WIDTH-1:0] wptr_b;
  36. reg [FIFO_PTR_WIDTH-1:0] wptr_g;
  37. reg fifo_full;
  38. wire [FIFO_PTR_WIDTH-1:0] wptr_bnext;
  39. wire [FIFO_PTR_WIDTH-1:0] wptr_gnext;
  40. //=================================================================================
  41. // main body
  42. //=================================================================================
  43. // ---- binary count ----
  44. assign wptr_bnext = wbin + (wr_en & (~fifo_full));
  45. assign waddr = wptr_b[FIFO_ADDR_WIDTH-1:0];
  46. always @(posedge wclk or negedge wrst_n) begin
  47. if(wrst_n == 1'b0)begin
  48. wptr_b <= {FIFO_PTR_WIDTH{1'b0}};
  49. end
  50. else begin
  51. wptr_b <= wptr_bnext;
  52. end
  53. end
  54. // ---- binary to gray ----
  55. assign wptr_gnext = (wptr_bnext >> 1) ^ (wptr_bnext);
  56. always @(posedge wclk or negedge wrst_n) begin
  57. if(wrst_n == 1'b0) begin
  58. wptr_g <= {FIFO_PTR_WIDTH{1'b0}};
  59. end
  60. else begin
  61. wptr_g <= wptr_gnext;
  62. end
  63. end
  64. // ---- fifo full -----
  65. // three necessary condition
  66. assign fifo_full_val = (wptr_gnext == {~rptr_g_sync[FIFO_PTR_WIDTH-1:FIFO_PTR_WIDTH-2],
  67. rptr_g_sync[FIFO_PTR_WIDTH-3:0]});
  68. always@(posedge wclk or negedge wrst_n) begin
  69. if(wrst_n == 1'b0) begin
  70. fifo_full <= 1'b0;
  71. end
  72. else begin
  73. fifo_full <= fifo_full_val;
  74. end
  75. end
  76. endmodule

5.5 rptr_empty

  1. //=================================================================================
  2. // module : rptr_empty.v
  3. // description : async_fifo read ctrl
  4. // data : 2022/3/2
  5. // author : souther meditating
  6. //=================================================================================
  7. module rptr_empty(
  8. rclk,
  9. rrst_n,
  10. rd_en,
  11. raddr,
  12. wptr_g_sync,
  13. rptr_g,
  14. fifo_empty
  15. );
  16. //=================================================================================
  17. // parameter & localparam
  18. //=================================================================================
  19. parameter FIFO_DEPTH = 16;
  20. localparam FIFO_ADDR_WIDTH = clog2(FIFO_DEPTH) ;
  21. localparam FIFO_PTR_WIDTH = FIFO_ADDR_WIDTH + 1;
  22. //=================================================================================
  23. // I/O
  24. //=================================================================================
  25. input rclk;
  26. input rrst_n;
  27. input rd_en;
  28. output [FIFO_ADDR_WIDTH-1:0] raddr;
  29. input [FIFO_PTR_WIDTH-1:0] wptr_g_sync;
  30. output [FIFO_PTR_WIDTH-1:0] rptr_g;
  31. output fifo_empty;
  32. // ==========================================================================
  33. // signal define
  34. // ==========================================================================
  35. reg [FIFO_PTR_WIDTH-1:0] rptr_b;
  36. reg [FIFO_PTR_WIDTH-1:0] rptr_g;
  37. wire [FIFO_PTR_WIDTH-1:0] rptr_bnext;
  38. wire [FIFO_PTR_WIDTH-1:0] rptr_gnext;
  39. wire fifo_empty_val;
  40. reg fifo_empty;
  41. //=================================================================================
  42. // main body
  43. //=================================================================================
  44. // ---- binary count ----
  45. assign rptr_bnext = rptr_b + (rd_en & (~fifo_empty));
  46. assign raddr = rptr_b[FIFO_ADDR_WIDTH-1:0];
  47. always @(posedge rclk or negedge rrst_n) begin
  48. if(rrst_n == 1'b0) begin
  49. rptr_b <= {FIFO_PTR_WIDTH{1'b0}};
  50. end
  51. else begin
  52. rptr_b <= rptr_bnext;
  53. end
  54. end
  55. // ---- binary to gray ----
  56. assign rptr_gnext = (rptr_bnext >> 1) ^ rptr_bnext;
  57. always@(posedge rclk or negedge rrst_n) begin
  58. if(rrst_n == 1'b0) begin
  59. rptr_g <= {FIFO_PTR_WIDTH{1'b0}};
  60. end
  61. else begin
  62. rptr_g <= rptr_gnext;
  63. end
  64. end
  65. // ---- fifo empty ----
  66. assign fifo_empty_val = (rptr_gnext == wptr_g_sync);
  67. always @(posedge rclk or posedge rrst_n) begin
  68. if(rrst_n == 1'b0) begin
  69. fifo_empty <= 1'b1;
  70. end
  71. else begin
  72. fifo_empty <= fifo_empty_val;
  73. end
  74. end
  75. endmodule

6. 参考资料

[1] 《硬件架构的艺术》

[2] Simulation and Synthesis Techniques for Asynchronous FIFO Design

[3] 同步FIFO设计

来源:https://blog.csdn.net/shiwq1127/article/details/123102904

作者:南风在冥想 版权归作者所有

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

闽ICP备14008679号