Synchronizing Write Pointer to Read Domain
Asynchronous FIFOs rely on accurate pointer exchange to safely calculate full and empty status flags. The read domain needs continuous visibility into the write pointer to determine when new data is available. Because the write pointer is generated in a completely independent clock domain, it cannot be sampled directly by the read logic without risking metastability and setup/hold violations.
This module captures a Gray-coded write pointer generated in the write clock domain and safely transitions it into the read clock domain. It uses a standard two-stage flip-flop synchronizer clocked by the read clock. Because the input pointer is Gray-coded, only one bit transitions at a time. This guarantees that if a timing violation occurs on the sampling edge, the synchronizer will resolve to either the old pointer value or the new pointer value, both of which are safe and valid states for the FIFO logic.
The module operates on the positive edge of the read clock and uses an asynchronous, active-low reset. Both synchronizer stages must be cleared to 0 upon reset. The pointer width is parameterized to support FIFOs of varying depths.
Cycle-by-cycle trace showing the two-cycle propagation delay:
Cycle 1: rrst_n=0 → internal_stage=0, wq2_rptr=0
Cycle 2: rrst_n=1, wptr=1 → internal_stage=0, wq2_rptr=0 (wptr changes asynchronously)
Cycle 3: wptr=1 → internal_stage=1, wq2_rptr=0 (first stage captures wptr)
Cycle 4: wptr=1 → internal_stage=1, wq2_rptr=1 (second stage captures internal_stage)
Cycle 5: wptr=3 → internal_stage=1, wq2_rptr=1 (wptr changes asynchronously)
Cycle 6: wptr=3 → internal_stage=3, wq2_rptr=1
Cycle 7: wptr=3 → internal_stage=3, wq2_rptr=3{ "signal": [
{ "name": "rclk", "wave": "p......." },
{ "name": "rrst_n", "wave": "01......" },
{ "name": "wptr", "wave": "x2..4...", "data": ["1", "3"] },
{ "name": "stage1", "wave": "0.2..4..", "data": ["1", "3"] },
{ "name": "wq2_rptr", "wave": "0..2..4.", "data": ["1", "3"] }
], "head": { "text": "Two-stage synchronization of the write pointer into the read domain." } }| Signal | Direction | Width | Description | |--------|-----------|-------|-------------| | rclk | input | 1 | Read domain clock; positive-edge triggered | | rrst_n | input | 1 | Read domain asynchronous active-low reset | | wptr | input | PTR_WIDTH | Gray-coded write pointer from the write domain | | wq2_rptr | output | PTR_WIDTH | Write pointer synchronized to the read domain |
Constraints
- The module must include a parameter named
PTR_WIDTHwith a default value of 4 - The circuit must use exactly two sequential flip-flop stages
- Clock edge: positive edge of
rclk - Reset: asynchronous, active-low on
rrst_n - Reset value: all bits of both synchronizer stages must be driven to 0 when reset is asserted
- The output
wq2_rptrmust be directly driven by the second synchronizer stage
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.