CodiodeCodiode
Home
Problem Solving
Skill Tracks
My Assignments
Contests
Leaderboard
Community
Settings
Codiode/Problems/Sequential Logic

Synchronizing Write Pointer to Read Domain

MediumVerilog / SystemVerilogBuild

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_WIDTH with 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_rptr must be directly driven by the second synchronizer stage

Topics

ParameterizedFIFOCDCSynchronizer

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

  • Basic D Flip FlopEasy
  • Debug: Missing Edge in Sensitivity ListMedium
  • Read After Write Hazard DetectionEasy
  • Parameterized Interface with ModportsHard
  • Struct Array PipelineHard
  • T Flip Flop from D Flip Flop TemplateEasy
  • Recursive Generate Reduction TreeHard
  • Four Stage Shift RegisterEasy

Browse all problems · Learning tracks