module fifo_async#( parameter data_width = 32, parameter data_depth = 8, parameter addr_width = 4 ) ( input rst_n, input wr_clk, input wr_en, input [data_width-1:0] din, input rd_clk, input rd_en, output reg valid, output reg [data_width-1:0] dout, output empty, full output ); reg [addr_width:0] wr_addr_ptr;//Address pointer, one more bit than the address, MSB is used to detect in the same circle reg [addr_width:0] rd_addr_ptr; wire [addr_width-1:0] wr_addr;//RAM address wire [addr_width-1:0] rd_addr; wire [addr_width:0] wr_addr_gray;//Gray code corresponding to the address pointer reg [addr_width:0] wr_addr_gray_d1; reg [addr_width:0] wr_addr_gray_d2; wire [addr_width:0] rd_addr_gray; reg [addr_width:0] rd_addr_gray_d1; reg [addr_width:0] rd_addr_gray_d2; reg [data_width-1:0] fifo_ram [data_depth-1:0]; //================================================ =========write fifo always@(posedge wr_clk or negedge rst_n) begin:write_ram integer i; if(!rst_n) for( i = 0; i < data_depth; i = i + 1 ) begin:write_ram_init fifo_ram[i] <= 'h0;//After fifo is reset, the output bus is 0, which is not a real reset in ram. Dispensable end//write_ram_init else if(wr_en & amp; & amp; (~full)) fifo_ram[wr_addr] <= din; else fifo_ram[wr_addr] <= fifo_ram[wr_addr]; end//write_ram //================================================ ========read_fifo always@(posedge rd_clk or negedge rst_n) begin if(!rst_n) begin dout <= 'h0; valid <= 1'b0; end else if(rd_en & amp; & amp; (~empty)) begin dout <= fifo_ram[rd_addr]; valid <= 1'b1; end else begin dout <= dout;//After fifo is reset, the output bus is 0. It is not really reset in ram, it just makes the bus 0; valid <= 1'b0; end end assign wr_addr = wr_addr_ptr[addr_width-1-:addr_width]; assign rd_addr = rd_addr_ptr[addr_width-1-:addr_width]; //================================================ =============Gray code synchronization always@(posedge wr_clk) begin rd_addr_gray_d1 <= rd_addr_gray; rd_addr_gray_d2 <= rd_addr_gray_d1; end always@(posedge wr_clk or negedge rst_n) begin if(!rst_n) wr_addr_ptr <= 'h0; else if(wr_en & amp; & amp; (~full)) wr_addr_ptr <= wr_addr_ptr + 1; else wr_addr_ptr <= wr_addr_ptr; end //================================================ =========rd_clk always@(posedge rd_clk) begin wr_addr_gray_d1 <= wr_addr_gray; wr_addr_gray_d2 <= wr_addr_gray_d1; end always@(posedge rd_clk or negedge rst_n) begin if(!rst_n) rd_addr_ptr <= 'h0; else if(rd_en & amp; & amp; (~empty)) rd_addr_ptr <= rd_addr_ptr + 1; else rd_addr_ptr <= rd_addr_ptr; end //================================================ ========== translation gary code assign wr_addr_gray = (wr_addr_ptr >> 1) ^ wr_addr_ptr; assign rd_addr_gray = (rd_addr_ptr >> 1) ^ rd_addr_ptr; assign full = (wr_addr_gray == {~(rd_addr_gray_d2[addr_width-:2]),rd_addr_gray_d2[addr_width-2:0]}) ;//The upper two digits are different assign empty = ( rd_addr_gray == wr_addr_gray_d2 ); endmodule
module fifo_async_tb(); reg tb_rst_n; reg tb_wr_clk; reg tb_wr_en; reg [31:0] tb_din; reg tb_rd_clk; reg tb_rd_en; wire tb_valid; wire [31:0] tb_dout; wire tb_empty; wire tb_full; task delay; input [31:0] num; begin repeat(num) @(posedge tb_wr_clk); #1; end endtask task delay1; input [31:0] num; begin repeat(num) @(posedge tb_rd_clk); #1; end endtask initial begin tb_wr_clk = 0; end always #40 tb_wr_clk = ~tb_wr_clk; initial begin tb_rd_clk = 0; end always #10 tb_rd_clk = ~tb_rd_clk; initial begin tb_rst_n = 1; delay(1); tb_rst_n = 0; delay(1); tb_rst_n = 1; end initial begin $dumpfile(" async_fifo_tb.vcd "); $dumpvars(); end initial begin tb_wr_en = 0; tb_din = 0; tb_rd_en = 0; delay(3); // write data tb_wr_en = 1; tb_din = 32'haaaa; delay(1); tb_wr_en = 0; delay(5); // read data, empty tb_rd_en = 1; delay1(1); tb_rd_en = 0; delay1(5); // write data1 tb_wr_en = 1; tb_din = 32'hbbbb; delay(1); tb_wr_en = 0; delay(5); // write data2 tb_wr_en = 1; tb_din = 32'hcccc; delay(1); tb_wr_en = 0; delay(5); // write data3 tb_wr_en = 1; tb_din = 32'hdddd; delay(1); tb_wr_en = 0; delay(5); // write data4, full tb_wr_en = 1; tb_din = 32'heeee; delay(1); tb_wr_en = 0; delay(5); // read data1 tb_rd_en = 1; delay1(1); tb_rd_en = 0; delay1(5); // read data2 tb_rd_en = 1; delay1(1); tb_rd_en = 0; delay1(5); // read data3 tb_rd_en = 1; delay1(1); tb_rd_en = 0; delay1(5); // read data4, empty tb_rd_en = 1; delay1(1); tb_rd_en = 0; delay1(5); delay(5); $finish; end fifo_async#( .data_width(32) , .data_depth(4) , .addr_width(2) ) dut1_fifo_async ( .rst_n (tb_rst_n), .wr_clk(tb_wr_clk), .wr_en ( tb_wr_en ) , .din ( tb_din ) , .rd_clk(tb_rd_clk), .rd_en (tb_rd_en), .valid(tb_valid), .dout (tb_dout), .empty (tb_empty), .full (tb_full) ); endmodule