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

Circular Buffer Pointer Math

MediumVerilog / SystemVerilogBuild

Every hardware FIFO relies on a circular buffer to store data, requiring read and write pointers that continuously cycle through the available memory addresses. When an address pointer reaches the end of the allocated memory depth, it must seamlessly wrap around to the beginning to maintain the continuous stream of data.

The module tracks independent read and write pointers for a circular buffer. On each positive clock edge, if the write enable is asserted, the write pointer increments by one. Similarly, if the read enable is asserted, the read pointer increments by one. Both pointers independently wrap back to zero when their current value equals max_depth - 1 and their respective enable is asserted. If an enable is not asserted, the corresponding pointer holds its current value. Simultaneous reads and writes are permitted and operate independently on their respective pointers.

Clock edge: posedge clk Reset type: Asynchronous, active-low (rst_n) Reset behavior: Both wr_ptr and rd_ptr reset to 8'h00 when rst_n is asserted.

Worked Trace: Cycle 1: rst_n=0 → wr_ptr=0, rd_ptr=0 Cycle 2: rst_n=1, wr_en=1, rd_en=0, max_depth=4 → wr_ptr=1, rd_ptr=0 Cycle 3: rst_n=1, wr_en=1, rd_en=0, max_depth=4 → wr_ptr=2, rd_ptr=0 Cycle 4: rst_n=1, wr_en=1, rd_en=0, max_depth=4 → wr_ptr=3, rd_ptr=0 Cycle 5: rst_n=1, wr_en=1, rd_en=0, max_depth=4 → wr_ptr=0, rd_ptr=0 (write wrap) Cycle 6: rst_n=1, wr_en=0, rd_en=1, max_depth=4 → wr_ptr=0, rd_ptr=1 Cycle 7: rst_n=1, wr_en=0, rd_en=0, max_depth=4 → wr_ptr=0, rd_ptr=1 (hold)

{ "signal": [
  { "name": "clk",       "wave": "p......" },
  { "name": "rst_n",     "wave": "01....." },
  { "name": "max_depth", "wave": "=.=====", "data": ["4", "4", "4", "4", "4", "4"] },
  { "name": "wr_en",     "wave": "01...0." },
  { "name": "rd_en",     "wave": "0....10" },
  {},
  { "name": "wr_ptr",    "wave": "=.=====", "data": ["0", "1", "2", "3", "0", "0"] },
  { "name": "rd_ptr",    "wave": "=.=====", "data": ["0", "0", "0", "0", "0", "1"] }
], "head": { "text": "Pointer increment and write pointer wrap at max_depth - 1." } }

| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset; pointers go to 0 | | wr_en | input | 1 | Write enable; increments wr_ptr when asserted | | rd_en | input | 1 | Read enable; increments rd_ptr when asserted | | max_depth | input | 8 | The maximum depth of the buffer; defines the wrap boundary | | wr_ptr | output | 8 | Write pointer; wraps to 0 when incremented from max_depth - 1 | | rd_ptr | output | 8 | Read pointer; wraps to 0 when incremented from max_depth - 1 |

Constraints

  • The clock is positive-edge triggered.
  • The reset is asynchronous and active-low.
  • Both wr_ptr and rd_ptr must reset to 0.
  • A pointer must wrap to 0 exactly when its current value is max_depth - 1 and its enable is asserted.
  • wr_ptr and rd_ptr must be registered outputs.

Topics

FIFOSequential LogicPointers

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
  • Combinational ROM InitializationEasy
  • Read First Single Port RAMMedium

Browse all problems · Learning tracks