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).

Verified by Tapeo353 generic cells at the defaultsFIFObuffer

Instantiate it

Paste into your design and connect the signals.

systemverilog
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

NameDefaultMeaning
WIDTH8Bits per entry.
DEPTH16Number of entries, a power of two.

Ports

NameDirectionWidthMeaning
clkinput1Clock; everything changes on its rising edge.
rstinput1Synchronous reset, active high.
wr_eninput1Write wr_data this cycle (ignored when full).
wr_datainputWIDTHEntry to write.
fulloutput1High when DEPTH entries are stored.
rd_eninput1Remove the oldest entry this cycle (ignored when empty).
rd_dataoutputWIDTHThe oldest entry, valid while empty is low.
emptyoutput1High when nothing is stored.
countoutput$clog2(DEPTH)+1Entries 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:

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

sync_fifo.sv
// 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

← Every block in Tapeo Hub