Altera_Forum
Honored Contributor
11 years agoHow do I synchronize gray code counts safely across asynchronous clock domains?
I have a design for a generic asynchronous FIFO that I have used for many years. In this FIFO, I use gray code counters for the read and write pointers to the core memory. These multi-bit pointers must be synchronized to the opposite clock domains to compute full and empty flags (e.g. rdptr is synchronized to wclk to compare against the wptr to determine the full flag.) I am using 2-stage flops in the synchronizer to reduce the metastability.
The problem that I am seeing has to do with the placement (Quartus Fit) of the original gray code pointer in domain 1 and the the first set of flops in the synchronizer in domain 2. For clarity: reg [w:0] rdptr_rclk; // rdptr in the rclk domain always @ (posedge rclk) begin rdptr_rclk <= nx_rdptr_rclk; end reg [w:0] rdptr_wclk_s1; // first stage synchronize of rdptr into the wclk domain reg [w:0] rdptr_wclk; // second (final) stage synchronize of rdptr into the wclk domain always @ (posedge wclk) begin rdptr_wclk_s1 <= rdptr_rclk; rdptr_wclk <= rdptr_wclk_s1; end In the sdc file, I have set_false_path between rclk and wclk. Ideally, all 3 of these synchronizer stages (rdptr_rclk, rdptr_wclk_s1, and rdptr_wclk) would be placed by the fitter as closely together as possible. However, the fitter wants to place the rdptr_rclk flops on one side of the fifo, close to where the empty flag is generated and used, and it wants to place the rdptr_wclk flops on the opposite side of the fifo, close to where the full flag is generated and used. The other register, rdptr_wclk_s1, usually will get placed right next to the rdptr_wclk. The problem occurs when some of the bits of rdptr_wclk_s1 are placed close to their rdptr_rclk counterpart, while other bits are placed far apart, especially when the skew between bits approaches or exceeds the period of the 2 clocks. In this case, the rdptr_wclk_s1 can see a transition on one bit before it sees the earlier transition on a different bit. For example: Correct rdptr_rclk sequence:- 0C:001100
- 0D:001101
- 0F:001111 (bit 1 transitions)
- 0E:001110 (bit 0 transitions)
- 0A:001010 (bit 2 transitions)
- 0C:001100
- 0D:001101
- 0C:001100 (bit 0 transitions)
- 0A:001010 (bit 1 and 2 transition)
- 0A:001010 (no transitions)