CodiodeCodiode
Home
Problem Solving
Skill Tracks
My Assignments
Contests
Leaderboard
Community
Settings
Codiode/Problems/Memory Design

FIFO Simultaneous Read Write when Empty

HardVerilog / SystemVerilogBuild

High-performance pipelines often use FIFOs to buffer data between stages. However, a standard FIFO introduces a one-cycle stall when a consumer attempts to read exactly as the FIFO becomes empty, even if a producer is writing new data in the same cycle. A bypass FIFO (sometimes called a fall-through FIFO) solves this by forwarding the incoming write data directly to the read port without writing it to memory.

The bypass_fifo module maintains a circular buffer of 8-bit words with a depth of exactly 8. Under normal operation, it functions as a standard synchronous FIFO. Data is written to memory when write_en is asserted, and read from memory into a registered output when read_en is asserted.

When the FIFO is empty and a simultaneous read and write occur, the module enters bypass mode. The write data is immediately passed to the output register, bypassing the memory array entirely, saving a clock cycle and preventing a pipeline stall.

Timing and Reset Rules

  • Clock edge: posedge clk
  • Reset type: Asynchronous, active-low (rst_n)
  • Reset values: empty = 1, full = 0, data_out = 8'h00. Internal pointers reset to 0.
  • Bypass condition: If empty is 1, and both write_en and read_en are 1, data_out updates to data_in on the next clock edge. The internal read/write pointers do not increment, and empty remains 1.
  • Simultaneous read/write when full: If full is 1, and both write_en and read_en are 1, both operations succeed. The read pointer increments, the write pointer increments, and full remains 1. The new data is written into the location just vacated by the read.
  • Standard write: If write_en = 1 and full = 0, the write pointer increments and data is stored.
  • Standard read: If read_en = 1 and empty = 0, the read pointer increments and data_out updates with the read data on the next clock edge.
  • Invalid operations: Read when empty (and write_en = 0) does nothing to pointers, and data_out holds its previous value. Write when full (and read_en = 0) does nothing to pointers.

Worked Trace

Cycle 1: rst_n=0 → empty=1, full=0, data_out=8'h00 Cycle 2: rst_n=1, write_en=0, read_en=0 → empty=1, full=0, data_out=8'h00 Cycle 3: write_en=1, read_en=1, data_in=8'hAA → empty=1, full=0, data_out=8'h00 (Bypass detected) Cycle 4: write_en=1, read_en=0, data_in=8'hBB → empty=1, full=0, data_out=8'hAA (Write BB; bypass data AA appears) Cycle 5: write_en=0, read_en=1 → empty=0, full=0, data_out=8'hAA (Read BB; FIFO was not empty) Cycle 6: write_en=1, read_en=1, data_in=8'hCC → empty=1, full=0, data_out=8'hBB (Bypass detected; read data BB appears) Cycle 7: write_en=0, read_en=0 → empty=1, full=0, data_out=8'hCC (Bypass data CC appears)

Diagram

{ "signal": [
  { "name": "clk",      "wave": "p........" },
  { "name": "rst_n",    "wave": "01......." },
  { "name": "write_en", "wave": "0.1101..." },
  { "name": "read_en",  "wave": "0.1011..." },
  { "name": "data_in",  "wave": "x.=.=x=..", "data": ["AA", "BB", "CC"] },
  {},
  { "name": "empty",    "wave": "1..01...." },
  { "name": "data_out", "wave": "=.=.=.=.=", "data": ["00", "AA", "AA", "BB", "CC"] }
], "head": { "text": "Bypass on cycle 3 and 6; normal write/read on 4/5." } }

Port Table

| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset; resets pointers, sets empty to 1, full to 0, data_out to 0 | | write_en | input | 1 | Write enable; active high | | read_en | input | 1 | Read enable; active high | | data_in | input | 8 | Data input to be written to the FIFO | | data_out | output | 8 | Data output read from the FIFO; registered on posedge clk | | empty | output | 1 | High when the FIFO contains no data | | full | output | 1 | High when the FIFO contains 8 elements |

Constraints

  • The FIFO depth must be exactly 8 elements.
  • data_out must be a registered output, updating only on posedge clk or asynchronous reset.
  • The internal pointers must not change during a bypass operation (when empty=1, write_en=1, read_en=1).
  • If full=1, a simultaneous read and write must be permitted without dropping the write or corrupting unread data.
  • Underflow and overflow attempts must be ignored, preserving the current state and pointers.

Topics

FIFOMemorySequential LogicEdge Cases

Solve this problem

Write the module in Verilog, SystemVerilog or VHDL. Your submission is compiled and simulated against a real testbench — you get the waveform back, not a stored answer.

This problem is part of Codiode Pro. The statement above is free to read.

Sign in to solveSee what Pro unlocks

The circuit builder and code editor need a desktop screen. On a phone, read the problem here and open it on a laptop to solve.

Related problems

  • Shift Register Based FIFOMedium
  • Asymmetric Data Width FIFOHard
  • True Dual Port RAM 2RWHard
  • Circular Buffer with OverwriteMedium
  • Synchronous Single Port RAMEasy
  • Stack Overflow and Underflow ProtectionMedium
  • Circular Buffer Pointer MathMedium
  • Read First Single Port RAMMedium

Browse all problems · Learning tracks