Asynchronous FIFO

Posted by Liang Chen on July 25, 2021

Reference: https://www.cnblogs.com/mikewolf2002/p/10945488.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
// HAVE BUG, WAITING FOR DEBUG !!!
module async # (
  parameter FIFO_WIDTH  = 8,  
            FIFO_DEPTH  = 16,
            ADDR_WIDTH  = 4 
)
(
  input                       wclk, wrst_n, wq,
  input                       rclk, rrst_n, rq,
  input      [FIFO_WIDTH-1:0] wdata,
  output reg [FIFO_WIDTH-1:0] rdata,
  output                      wfull, rempty
);

reg  [FIFO_WIDTH-1:0] mem [FIFO_DEPTH-1:0];
wire [ADDR_WIDTH-1:0] waddr, raddr;
reg  [ADDR_WIDTH:0] waddr_bin, raddr_bin;
wire [ADDR_WIDTH:0] waddr_gray, raddr_gray;
reg  [ADDR_WIDTH:0] wptr, rptr;
reg  [ADDR_WIDTH:0] w1_rptr, w2_rptr;
reg  [ADDR_WIDTH:0] r1_wptr, r2_wptr;

assign waddr = waddr_bin[ADDR_WIDTH-1:0];
assign raddr = raddr_bin[ADDR_WIDTH-1:0];

always @ (posedge rclk or negedge rrst_n)
begin
  if (!rrst_n)
    rdata <= 0;
  else
  begin
    if (rq && !rempty)
      rdata <= mem[raddr];
    else
      rdata = rdata;
  end
end

always @ (posedge wclk)
begin
  if (wq && !wfull)
    mem[waddr] <= wdata;
  else
    mem[waddr] <= mem[waddr];
end

always @ (posedge wclk or negedge wrst_n)
begin
  if (!wrst_n)
  begin
    w1_rptr <= 0;
    w2_rptr <= 0;
  end
  else
  begin
    w1_rptr <= rptr;
    w2_rptr <= w1_rptr;
  end
end

always @ (posedge rclk or negedge rrst_n)
begin
  if (!rrst_n)
  begin
    r1_wptr <= 0;
    r2_wptr <= 0;
  end
  else
  begin
    r1_wptr <= wptr;
    r2_wptr <= r1_wptr;
  end
end

assign raddr_gray = raddr_bin ^ (raddr_bin >> 1);
always @ (posedge rclk or negedge rrst_n)
begin
  if (!rrst_n)
  begin
    raddr_bin <= 0;
    rptr      <= 0;
  end
  else
  begin
    if (rq & !rempty)
    begin
      raddr_bin  <= raddr_bin + 1'b1;
      rptr       <= raddr_gray;
    end
  end
end


assign waddr_gray = waddr_bin ^ (waddr_bin>>1);
always @ (posedge wclk or negedge wrst_n)
begin
  if (!wrst_n)
  begin
    waddr_bin <= 0;
    wptr      <= 0;
  end
  else
  begin
    if (wq & !wfull)
    begin
      waddr_bin <= waddr_bin + 1'b1;
      wptr      <= waddr_gray;
    end
  end
end

assign rempty = (rptr==r2_wptr);
assign wfull = (w2_rptr == {~wptr[ADDR_WIDTH], ~wptr[ADDR_WIDTH-1], wptr[ADDR_WIDTH-2:0]});

endmodule