// For this to be synthesizable on ASICs, do I need to initialize FIFO to be // all 0 initially? Because you'll never read from an uninitialized (written) // address? module fifo #( parameter data_width = 8, parameter fifo_depth = 32, parameter addr_width = $clog2(fifo_depth) ) ( input clk, rst, // Write side input wr_en, input [data_width-1:0] din, output full, // Read side input rd_en, output reg [data_width-1:0] dout, output empty ); reg [data_width-1:0] mem [fifo_depth-1:0]; reg [addr_width:0] read_pntr, write_pntr; // important extra bit // Use the extra bit to keep track of if the buffer is empty or full // If read pointer == write pointer (including extra MSB), we know // the pointers aren't a loop apart. // Address the FIFO itself without the MSB assign empty = (read_pntr[addr_width] == write_pntr[addr_width]) & (read_pntr[addr_width-1:0] == write_pntr[addr_width-1:0]); assign full = (read_pntr[addr_width] != write_pntr[addr_width]) & (read_pntr[addr_width-1:0] == write_pntr[addr_width-1:0]); // Write logic // Update write pointer and memory if wr_en and we're either not full, or // we're full but reading in the same clock cycle. always @(posedge clk) begin if (rst) write_pntr <= 0; else if (wr_en & (!full | rd_en)) begin mem[write_pntr[addr_width-1:0]] <= din; write_pntr <= write_pntr + 1; end end // Read logic // Update read pointer and output of FIFO if rd_en and we're not empty. always @(posedge clk) begin if (rst) begin read_pntr <= 0; dout <= 0; end else if (rd_en & !empty) begin dout <= mem[read_pntr[addr_width-1:0]]; read_pntr <= read_pntr + 1; end end endmodule