/* * This file is based on "Asynchronous FIFO" by Alex Claros F., * itself based on the article "Asynchronous FIFO in Virtex-II FPGAs" * by Peter Alfke. */ module asfifo #( parameter data_width = 8, parameter address_width = 4, parameter fifo_depth = (1 << address_width) ) ( /* Read port */ output reg [data_width-1:0] data_out, output reg empty, input read_en, input clk_read, /* Write port */ input [data_width-1:0] data_in, output reg full, input write_en, input clk_write, /* Asynchronous reset */ input rst ); reg [data_width-1:0] mem[fifo_depth-1:0]; wire [address_width-1:0] write_index, read_index; wire equal_addresses; wire write_en_safe, read_en_safe; wire set_status, clear_status; reg status; wire preset_full, preset_empty; reg [data_width-1:0] data_out0; always @(posedge clk_read) begin data_out0 <= mem[read_index]; data_out <= data_out0; end always @(posedge clk_write) begin if(write_en & !full) mem[write_index] <= data_in; end assign write_en_safe = write_en & ~full; assign read_en_safe = read_en & ~empty; asfifo_graycounter #( .width(address_width) ) counter_write ( .gray_count(write_index), .ce(write_en_safe), .rst(rst), .clk(clk_write) ); asfifo_graycounter #( .width(address_width) ) counter_read ( .gray_count(read_index), .ce(read_en_safe), .rst(rst), .clk(clk_read) ); assign equal_addresses = (write_index == read_index); assign set_status = (write_index[address_width-2] ~^ read_index[address_width-1]) & (write_index[address_width-1] ^ read_index[address_width-2]); assign clear_status = ((write_index[address_width-2] ^ read_index[address_width-1]) & (write_index[address_width-1] ~^ read_index[address_width-2])) | rst; always @(posedge clear_status, posedge set_status) begin if(clear_status) status <= 1'b0; else status <= 1'b1; end assign preset_full = status & equal_addresses; always @(posedge clk_write, posedge preset_full) begin if(preset_full) full <= 1'b1; else full <= 1'b0; end assign preset_empty = ~status & equal_addresses; always @(posedge clk_read, posedge preset_empty) begin if(preset_empty) empty <= 1'b1; else empty <= 1'b0; end endmodule