Pointer Wrapping with MSB Toggle
Synchronous FIFOs require a mechanism to distinguish between completely full and completely empty states, as the read and write pointers will point to the exact same physical memory address in both scenarios. The industry-standard solution to this ambiguity uses an extra Most Significant Bit (MSB) in the pointers to track the wrap-around status of the memory array.
The module maintains two pointers, a write pointer and a read pointer. Each pointer increments by 1 when its respective enable signal is asserted and the operation is valid. The pointers are ADDR_WIDTH + 1 bits wide. The lower ADDR_WIDTH bits represent the physical memory address, while the MSB acts as a toggle bit.
The FIFO is empty when both pointers are exactly equal across all bits. The FIFO is full when the lower ADDR_WIDTH bits are equal, but the MSB toggle bits are different. This indicates the write pointer has wrapped around exactly one more time than the read pointer.
Positive-edge triggered clock (clk). Asynchronous active-low reset (rst_n). On reset, both pointers become 0, empty becomes 1, and full becomes 0.
Cycle 1: rst_n=0 → wr_ptr=0, rd_ptr=0, full=0, empty=1 Cycle 2: rst_n=1, wr_en=1, rd_en=0 → wr_ptr=1, rd_ptr=0, full=0, empty=0 Cycle 3: wr_en=1, rd_en=0 → wr_ptr=2, rd_ptr=0, full=0, empty=0 Cycle 4: wr_en=1, rd_en=0 → wr_ptr=3, rd_ptr=0, full=0, empty=0 Cycle 5: wr_en=1, rd_en=0 → wr_ptr=4, rd_ptr=0, full=1, empty=0 Cycle 6: wr_en=1, rd_en=0 → wr_ptr=4, rd_ptr=0, full=1, empty=0 (overflow prevented)
{ "signal": [
{ "name": "clk", "wave": "p......" },
{ "name": "rst_n", "wave": "01....." },
{ "name": "wr_en", "wave": "01...0." },
{ "name": "rd_en", "wave": "0......" },
{},
{ "name": "wr_ptr", "wave": "=.====.", "data": ["0","1","2","3","4"] },
{ "name": "rd_ptr", "wave": "=......", "data": ["0"] },
{ "name": "full", "wave": "0....1." },
{ "name": "empty", "wave": "10....." }
], "head": { "text": "Cycle-by-cycle trace of writing to a full state (ADDR_WIDTH=2)" } }| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | clk | input | 1 | Positive-edge triggered clock | | rst_n | input | 1 | Asynchronous active-low reset; pointers reset to 0, empty to 1, full to 0 | | wr_en | input | 1 | Write enable; increments wr_ptr on posedge clk unless full | | rd_en | input | 1 | Read enable; increments rd_ptr on posedge clk unless empty | | wr_ptr | output | ADDR_WIDTH+1 | Write pointer including MSB toggle bit | | rd_ptr | output | ADDR_WIDTH+1 | Read pointer including MSB toggle bit | | full | output | 1 | Asserted when FIFO is full (MSBs differ, lower bits match) | | empty| output | 1 | Asserted when FIFO is empty (all bits match) |
Constraints
- The
ADDR_WIDTHmust be parameterized with a default value of 3. - The testbench will override
ADDR_WIDTHduring testing; you must use it to size your registers and logic dynamically. wr_ptrandrd_ptrmust be exactlyADDR_WIDTH + 1bits wide.- Clock edge is
posedge, reset is asynchronous active-low. - Do not increment
wr_ptriffullis 1, even ifwr_enis 1 (overflow protection). - Do not increment
rd_ptrifemptyis 1, even ifrd_enis 1 (underflow protection). fullandemptymust reflect the state of the pointers in the current clock cycle.
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.