Circular Buffer Pointer Math
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_ptrandrd_ptrmust reset to 0. - A pointer must wrap to 0 exactly when its current value is
max_depth - 1and its enable is asserted. wr_ptrandrd_ptrmust be registered outputs.
Topics
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.
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.