1 `timescale 1ns / 1ns 2 module async_fifo #( 3 parameter DP = 8, 4 parameter DW = 32 )( 5 input wr_clk, 6 input wr_reset_n, 7 input wr_en, 8 input [DW-1:0] wr_data, 9 output full, 10 output afull, 11 input rd_clk, 12 input rd_reset_n, 13 input rd_en, 14 output [DW-1:0] rd_data, 15 output empty, 16 output aempty 17 ); 18 19 localparam AW = $clog2(DP); 20 localparam WR_FAST = 1'b1; 21 localparam RD_FAST = 1'b1; 22 23 reg [DW-1:0] mem[DP-1:0]; 24 reg [AW:0] sync_rd_ptr_0, sync_rd_ptr_1; 25 wire [AW:0] sync_rd_ptr; 26 reg full_q; 27 reg [AW:0] wr_ptr, gray_wr_ptr; 28 reg [AW:0] gray_rd_ptr; 29 wire [AW:0] wr_ptr_inc = wr_ptr + 1'b1; 30 wire [AW:0] wr_cnt = get_cnt(wr_ptr, sync_rd_ptr); 31 wire full_c = (wr_cnt == DP) ? 1'b1 : 1'b0; 32 reg [AW:0] sync_wr_ptr_0, sync_wr_ptr_1; 33 wire [AW:0] sync_wr_ptr; 34 reg [AW:0] rd_ptr; 35 reg empty_q; 36 wire [AW:0] rd_ptr_inc = rd_ptr + 1'b1; 37 wire [AW:0] rd_cnt = get_cnt(sync_wr_ptr, rd_ptr); 38 wire empty_c = (rd_cnt == 0) ? 1'b1 : 1'b0; 39 reg [DW-1:0] rd_data_q; 40 wire [DW-1:0] rd_data_c = mem[rd_ptr[AW-1:0]]; 41 42 always @(posedge wr_clk or negedge wr_reset_n) 43 if (!wr_reset_n) begin 44 wr_ptr <= 'd0; 45 gray_wr_ptr <= 'd0; 46 full_q <= 'b0; 47 end 48 else if (wr_en) begin 49 wr_ptr <= wr_ptr_inc; 50 gray_wr_ptr <= bin2gray(wr_ptr_inc); 51 if (wr_cnt == (DP-'d1)) begin 52 full_q <= 'b1; 53 end 54 end 55 else begin 56 if (full_q && (wr_cnt<DP)) begin 57 full_q <= 'b0; 58 end 59 end 60 61 assign full = (WR_FAST == 1) ? full_c : full_q; 62 assign afull = (wr_cnt >= DP/2 - 1) ? 1'b1 : 1'b0; 63 64 always @(posedge wr_clk) 65 if (wr_en) begin 66 mem[wr_ptr[AW-1:0]] <= wr_data; 67 end 68 69 // read pointer synchronizer 70 always @(posedge wr_clk or negedge wr_reset_n) 71 if (!wr_reset_n) begin 72 sync_rd_ptr_0 <= 'b0; 73 sync_rd_ptr_1 <= 'b0; 74 end 75 else begin 76 sync_rd_ptr_0 <= gray_rd_ptr; 77 sync_rd_ptr_1 <= sync_rd_ptr_0; 78 end 79 80 assign sync_rd_ptr = gray2bin(sync_rd_ptr_1); 81 82 always @(posedge rd_clk or negedge rd_reset_n) 83 if (!rd_reset_n) begin 84 rd_ptr <= 'd0; 85 gray_rd_ptr <= 'd0; 86 empty_q <= 'b1; 87 end 88 else begin 89 if (rd_en) begin 90 rd_ptr <= rd_ptr_inc; 91 gray_rd_ptr <= bin2gray(rd_ptr_inc); 92 if (rd_cnt=='d1) begin 93 empty_q <= 'b1; 94 end 95 end 96 else begin 97 if (empty_q && (rd_cnt!='d0)) begin 98 empty_q <= 'b0; 99 end 100 end 101 end 102 103 assign empty = (RD_FAST == 1) ? empty_c : empty_q; 104 assign aempty = (rd_cnt < DP/2 - 'd3) ? 1'b1 : 1'b0; 105 106 always @(posedge rd_clk) 107 rd_data_q <= rd_data_c; 108 109 assign rd_data = (RD_FAST == 1) ? rd_data_c : rd_data_q; 110 111 // write pointer synchronizer 112 always @(posedge rd_clk or negedge rd_reset_n) 113 if (!rd_reset_n) begin 114 sync_wr_ptr_0 <= 'b0; 115 sync_wr_ptr_1 <= 'b0; 116 end 117 else begin 118 sync_wr_ptr_0 <= gray_wr_ptr; 119 sync_wr_ptr_1 <= sync_wr_ptr_0; 120 end 121 122 assign sync_wr_ptr = gray2bin(sync_wr_ptr_1); 123 124 function [AW:0] get_cnt; 125 input [AW:0] wr_ptr, rd_ptr; 126 begin 127 if (wr_ptr >= rd_ptr) begin 128 get_cnt = (wr_ptr - rd_ptr); 129 end 130 else begin 131 get_cnt = DP*2 - (rd_ptr - wr_ptr); 132 end 133 end 134 endfunction 135 136 function [AW:0] bin2gray; 137 input [AW:0] bin; 138 139 bin2gray = (bin >> 1) ^ bin; 140 141 endfunction 142 143 function [AW:0] gray2bin; 144 input [AW:0] gray; 145 integer k; 146 147 for (k = 0; k <= AW; k = k + 1) 148 gray2bin[k] = ^(gray >> k); 149 150 endfunction 151 152 endmodule