Read Pointer Generation and Gray Conversion
Asynchronous FIFOs safely transfer data between independent clock domains. To prevent metastability when calculating the full condition in the write domain, the read domain's pointer must be passed across the clock boundary. Passing a binary counter directly is unsafe because multiple bits can transition simultaneously. Instead, the pointer is converted to Gray code before synchronization.
The read pointer module tracks the current read address of the FIFO. When a read is requested and the FIFO is not empty, the binary read pointer increments by one. The module outputs both this binary pointer (for memory addressing) and its Gray-coded equivalent (for clock domain crossing). If a read is requested while the FIFO is empty, the pointer holds its current value to prevent underflow.
Timing and Reset Rules: • Clock edge: Positive edge of r_clk • Reset type: Asynchronous active-low reset via r_rst_n • Output values on reset: Both r_ptr_bin and r_ptr_gray must reset to 4'b0000 • Priority rules: Asynchronous reset has the highest priority. The r_empty flag being high overrides r_en, preventing any increment. • Registered outputs: Both r_ptr_bin and r_ptr_gray must be registered and update synchronously on the clock edge.
Worked Trace: Cycle 1: r_rst_n=0 → r_ptr_bin=0, r_ptr_gray=0 Cycle 2: r_rst_n=1, r_en=1, r_empty=0 → r_ptr_bin=1, r_ptr_gray=1 Cycle 3: r_en=1, r_empty=0 → r_ptr_bin=2, r_ptr_gray=3 Cycle 4: r_en=1, r_empty=1 → r_ptr_bin=2, r_ptr_gray=3 (hold, empty) Cycle 5: r_en=0, r_empty=0 → r_ptr_bin=2, r_ptr_gray=3 (hold, no enable) Cycle 6: r_en=1, r_empty=0 → r_ptr_bin=3, r_ptr_gray=2
{ "signal": [
{ "name": "r_clk", "wave": "p....." },
{ "name": "r_rst_n", "wave": "01...." },
{ "name": "r_en", "wave": "01.101" },
{ "name": "r_empty", "wave": "00.100" },
{},
{ "name": "r_ptr_bin", "wave": "======", "data": ["0", "1", "2", "2", "2", "3"] },
{ "name": "r_ptr_gray", "wave": "======", "data": ["0", "1", "3", "3", "3", "2"] }
], "head": { "text": "Pointer increments on read enable when not empty, converting to Gray code." } }Port Table:
| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | r_clk | input | 1 | Positive-edge triggered clock | | r_rst_n | input | 1 | Asynchronous active-low reset; clears pointers to 0 | | r_en | input | 1 | Read enable; requests a pointer increment | | r_empty | input | 1 | FIFO empty flag; prevents increment when asserted | | r_ptr_bin | output | 4 | 4-bit binary read pointer | | r_ptr_gray| output | 4 | 4-bit Gray-coded read pointer |
Constraints
- Clock edge and reset polarity: Positive edge
r_clk, asynchronous active-lowr_rst_n. - Output values on reset: Both
r_ptr_binandr_ptr_graymust reset to4'b0000. - Priority:
r_emptybeing high prevents incrementing, even ifr_enis high. - Widths: Both pointers are exactly 4-bit.
- Wrap behavior: The binary pointer must naturally wrap from 15 to 0 on overflow.
- Registered outputs: Both outputs must be driven directly by flip-flops.
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.