blob: 567ce2d286a93b42aa6e4235226fab003cf6e914 [file] [log] [blame]
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[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;
assign isData = startPointer != endPointer;
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
assign bufferFull = nextEndPointer == startPointer;
always @(negedge clk) begin
if (rst) begin
startPointer <= {ADDRESS_SIZE{1'b0}};
endPointer <= {ADDRESS_SIZE{1'b0}};
lastWriteLostData <= 1'b0;
end else begin
// Update start pointer first, so that if the buffer is full and we try to write,
// it will still work if we are also reading on this update
if (oe_buffered) begin
if (startPointer != endPointer) begin
startPointer <= nextStartPointer;
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;
end else begin
lastWriteLostData <= 1'b1;
end
end
end
end
assign dataOut = buffer[startPointer];
assign dataLost = lastWriteLostData;
endmodule