Skip to question and answer

Hardware interview practice

How to Build a Synchronous FIFO in SystemVerilog

MediumRTL DesignOpen ended

Design a parameterized synchronous FIFO, then write a small bus-functional model that can reset it, push one item, and pop one item without testbench races.

Worked case

Example

Input
cycle 0: rst_n=0
cycle 1: rst_n=1, push=1, data=0x2A, pop=0
cycle 2: push=1, data=0x7C, pop=1
cycle 3: push=0, pop=1
Output
cycle 0: empty=1, count=0
cycle 1: accept 0x2A, count=1
cycle 2: pop 0x2A and accept 0x7C, count remains 1
cycle 3: pop 0x7C, empty=1, count=0

Explanation: The simultaneous push/pop cycle preserves occupancy, and the race-free BFM samples accepted transfers only on the active clock edge.

Reasoning requirements

  1. Expose full and empty, reject reads while empty, and reject writes while full unless a same-cycle read creates space.
  2. Define registered read-data semantics and handle simultaneous accepted reads and writes without corrupting occupancy.
  3. Support non-power-of-two depths with explicit pointer wrap logic.
  4. Use an interface clocking block so the BFM drives and samples on deterministic scheduler regions.

Concise answer

The answer and the key reason

Model occupancy from accepted reads and writes, not raw requests. Permit a write at full only when a read also succeeds, register the popped word, update count from the push/pop combination, and wrap pointers explicitly at DEPTH - 1. In the BFM, use a clocking block and sample registered read data on the following edge.

Deeper explanation

Work through the implementation and tradeoffs

Define read_accept as rd_en while nonempty. Define write_accept as wr_en when capacity exists, or when a simultaneous accepted read frees one entry. Only these accepted events move pointers. The count increments for write-only, decrements for read-only, and remains constant when both occur, which prevents occupancy drift under concurrent traffic.

Non-power-of-two depths require an explicit comparison against the final legal index before returning a pointer to zero. Because read data is registered, the BFM should issue and hold a request through an acceptance edge, then wait until the register has updated before sampling. Clocking-block skews keep those actions out of DUT scheduling races.

What to remember

  • Count accepted operations
  • Wrap non-power-of-two pointers
  • Sample registered reads later

Practice the complete prompt

Explain it first, then compare the reviewed solution.

Open this exact question in the practice bank to attempt it, check your reasoning, and access the full member solution.Practice this question

Keep practicing

UVM ComponentsHow to Drive a Ready/Valid Interface CorrectlyClock Domain CrossingClock-Domain Crossing Strategies for ASIC InterviewsReset DesignAsync Assert, Sync Deassert Reset