Memory
Synchronous FIFO
sync_fifo
First-word fall-through FIFO: rd_data shows the oldest entry whenever empty is low, and rd_en removes it. Writes while full and reads while empty are ignored, so the buffer never corrupts. DEPTH must be a power of two (2 or more).
Instantiate it
Paste into your design and connect the signals.
sync_fifo #(.WIDTH(8), .DEPTH(16)) u_fifo (
.clk(clk), .rst(rst),
.wr_en(push), .wr_data(push_data), .full(fifo_full),
.rd_en(pop), .rd_data(pop_data), .empty(fifo_empty), .count(fifo_count)
);Parameters
| Name | Default | Meaning |
|---|---|---|
| WIDTH | 8 | Bits per entry. |
| DEPTH | 16 | Number of entries, a power of two. |
Ports
| Name | Direction | Width | Meaning |
|---|---|---|---|
| clk | input | 1 | Clock; everything changes on its rising edge. |
| rst | input | 1 | Synchronous reset, active high. |
| wr_en | input | 1 | Write wr_data this cycle (ignored when full). |
| wr_data | input | WIDTH | Entry to write. |
| full | output | 1 | High when DEPTH entries are stored. |
| rd_en | input | 1 | Remove the oldest entry this cycle (ignored when empty). |
| rd_data | output | WIDTH | The oldest entry, valid while empty is low. |
| empty | output | 1 | High when nothing is stored. |
| count | output | $clog2(DEPTH)+1 | Entries stored. |
Add it to a project
It is copied to ip/sync_fifo/sync_fifo.sv with a README (ip/sync_fifo/README.md). When your design needs it, the Architect (new designs) or the Architect (changes) suggests it and asks before using it. Or add it yourself:
- In the workspace: the Tapeo Hub button in the project header, then Add to project.
- In a terminal (in the project folder):
$ tapeo hub add sync_fifo - In VS Code: Tapeo: Add from Tapeo Hub in the Command Palette.
How it is verified
Before every release Tapeo checks this block: its self-checking testbench passes in Icarus Verilog, Verilator -Wall reports nothing, and Yosys synthesizes it (353 generic cells at the default parameters). That shows it works for the tested cases; your copy is part of your project, and your own testbench checks it in your design.
Source
// Synchronous FIFO, one clock. First-word fall-through: `rd_data` shows the
// oldest entry whenever `empty` is low, and `rd_en` removes it. Writes when
// full and reads when empty are ignored. DEPTH must be a power of two (2 or
// more). Tapeo Hub (verified by Tapeo).
module sync_fifo #(
parameter integer WIDTH = 8,
parameter integer DEPTH = 16
) (
input logic clk,
input logic rst,
input logic wr_en,
input logic [WIDTH-1:0] wr_data,
output logic full,
input logic rd_en,
output logic [WIDTH-1:0] rd_data,
output logic empty,
output logic [$clog2(DEPTH):0] count
);
localparam integer ADDR = $clog2(DEPTH);
logic [WIDTH-1:0] mem [DEPTH];
logic [ADDR:0] wr_ptr, rd_ptr;
wire do_write = wr_en && !full;
wire do_read = rd_en && !empty;
always_ff @(posedge clk) begin
if (do_write) mem[wr_ptr[ADDR-1:0]] <= wr_data;
end
always_ff @(posedge clk) begin
if (rst) begin
wr_ptr <= '0;
rd_ptr <= '0;
end else begin
if (do_write) wr_ptr <= wr_ptr + 1'b1;
if (do_read) rd_ptr <= rd_ptr + 1'b1;
end
end
assign empty = (wr_ptr == rd_ptr);
assign full = (wr_ptr[ADDR] != rd_ptr[ADDR]) && (wr_ptr[ADDR-1:0] == rd_ptr[ADDR-1:0]);
assign count = wr_ptr - rd_ptr;
assign rd_data = mem[rd_ptr[ADDR-1:0]];
endmodule