EECS151 / fpga_labs_fa20 / lab6 / src / fifo.v
fifo.v
Raw
// 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