| module FIFO | |
| #( | |
| parameter WORD_SIZE = 8, | |
| parameter BUFFER_SIZE = 256 // If this is not a power of two, the actual buffer size will be the smallest power of two greater than BUFFER_SIZE | |
| )( | |
| input wire clk, | |
| input wire rst, | |
| input wire [WORD_SIZE-1:0] dataIn, | |
| input wire we, | |
| output wire [WORD_SIZE-1:0] dataOut, | |
| input wire oe, | |
| output wire isData, | |
| output wire bufferFull, | |
| output wire dataLost | |
| ); | |
| localparam ADDRESS_SIZE = $clog2(BUFFER_SIZE); | |
| localparam DEPTH = 1 << ADDRESS_SIZE; | |
| reg we_buffered = 1'b0; | |
| reg oe_buffered = 1'b0; | |
| reg[WORD_SIZE-1:0] dataIn_buffered = {WORD_SIZE{1'b0}}; | |
| reg[WORD_SIZE-1:0] dataOut_buffered; | |
| reg[ADDRESS_SIZE-1:0] startPointer = {ADDRESS_SIZE{1'b0}}; | |
| reg[ADDRESS_SIZE-1:0] endPointer = {ADDRESS_SIZE{1'b0}}; | |
| reg[WORD_SIZE-1:0] buffer [0:DEPTH-1]; | |
| wire[ADDRESS_SIZE-1:0] nextStartPointer = startPointer + 1; | |
| wire[ADDRESS_SIZE-1:0] nextEndPointer = endPointer + 1; | |
| reg lastWriteLostData = 1'b0; | |
| always @(posedge clk) begin | |
| if (rst) begin | |
| we_buffered <= 1'b0; | |
| oe_buffered <= 1'b0; | |
| dataIn_buffered <= {WORD_SIZE{1'b0}}; | |
| end else begin | |
| we_buffered <= we; | |
| oe_buffered <= oe; | |
| dataIn_buffered <= dataIn; | |
| end | |
| end | |
| always @(negedge clk) begin | |
| if (rst) begin | |
| startPointer <= {ADDRESS_SIZE{1'b0}}; | |
| endPointer <= {ADDRESS_SIZE{1'b0}}; | |
| lastWriteLostData <= 1'b0; | |
| dataOut_buffered <= {WORD_SIZE{1'b0}}; | |
| end else begin | |
| if (oe_buffered) begin | |
| if (isData) begin | |
| startPointer <= nextStartPointer; | |
| dataOut_buffered <= buffer[nextStartPointer]; | |
| end else begin | |
| dataOut_buffered <= {WORD_SIZE{1'b0}}; | |
| end | |
| end | |
| if (we_buffered) begin | |
| // TODO: Should we allow the buffer to overwrite itself when a write occurs and it is already full | |
| if (!bufferFull) begin | |
| buffer[endPointer] <= dataIn_buffered; | |
| endPointer <= nextEndPointer; | |
| lastWriteLostData <= 1'b0; | |
| if (!isData) dataOut_buffered <= dataIn_buffered; | |
| end else begin | |
| lastWriteLostData <= 1'b1; | |
| end | |
| end | |
| end | |
| end | |
| assign dataOut = dataOut_buffered; | |
| assign isData = startPointer != endPointer; | |
| assign bufferFull = nextEndPointer == startPointer; | |
| assign dataLost = lastWriteLostData; | |
| endmodule |