OpenFPGA/openfpga_flow/benchmarks/micro_benchmark/fifo/rtl/fifo.v

98 lines
3.6 KiB
Verilog

// FIFO buffer implemented with synchronous dual-port block ram
// Reference:
// https://embeddedthoughts.com/2016/07/13/fifo-buffer-using-block-ram-on-a-xilinx-spartan-3-fpga/
module fifo
#( parameter ADDRESS_WIDTH = 4, // number of words in ram
DATA_WIDTH = 4 // number of bits in word
)
// IO ports
(
input wire clk, reset,
input wire read, write,
input wire [DATA_WIDTH-1:0] write_data,
output wire empty, full,
output wire [DATA_WIDTH-1:0] read_data
);
// internal signal declarations
reg [ADDRESS_WIDTH-1:0] write_address_reg, write_address_next, write_address_after;
reg [ADDRESS_WIDTH-1:0] read_address_reg, read_address_next, read_address_after;
reg full_reg, empty_reg, full_next, empty_next;
wire write_en;
// write enable is asserted when write input is asserted and FIFO isn't full
assign write_en = write & ~full_reg;
// instantiate synchronous block ram
sync_dual_port_ram #(.ADDRESS_WIDTH(ADDRESS_WIDTH), .DATA_WIDTH(DATA_WIDTH)) ram
(.clk(clk), .write_en(write_en), .write_address(write_address_reg),
.read_address(read_address_reg), .write_data_in(write_data),
.write_data_out(), .read_data_out(read_data));
// register for address pointers, full/empty status
always @(posedge clk, posedge reset)
if (reset)
begin
write_address_reg <= 0;
read_address_reg <= 0;
full_reg <= 1'b0;
empty_reg <= 1'b1;
end
else
begin
write_address_reg <= write_address_next;
read_address_reg <= read_address_next;
full_reg <= full_next;
empty_reg <= empty_next;
end
// next-state logic for address index values after read/write operations
always @*
begin
write_address_after = write_address_reg + 1;
read_address_after = read_address_reg + 1;
end
// next-state logic for address pointers
always @*
begin
// defaults
write_address_next = write_address_reg;
read_address_next = read_address_reg;
full_next = full_reg;
empty_next = empty_reg;
// if read input asserted and FIFO isn't empty
if(read && ~empty_reg && ~write)
begin
read_address_next = read_address_after; // read address moves forward
full_next = 1'b0; // FIFO isn't full if a read occured
if (read_address_after == write_address_reg) // if read address caught up with write address,
empty_next = 1'b1; // FIFO is empty
end
// if write input asserted and FIFO isn't full
else if(write && ~full_reg && ~read)
begin
write_address_next = write_address_after; // write address moves forward
empty_next = 1'b0; // FIFO isn't empty if write occured
if (write_address_after == read_address_reg) // if write address caught up with read address
full_next = 1'b1; // FIFO is full
end
// if write and read are asserted
else if(write && read)
begin
write_address_next = write_address_after; // write address moves forward
read_address_next = read_address_after; // read address moves forward
end
end
// assign full/empty status to output ports
assign full = full_reg;
assign empty = empty_reg;
endmodule