From the last post, you know how to use a 2-Flop Synchronizer for single control bits, and you know how to use Handshakes and Asynchronous FIFOs for multi-bit data buses.
But there is one specific, highly common scenario that will silently break a standard 2-Flop Synchronizer: passing a single-cycle pulse from a very fast clock domain to a very slow clock domain.
Let's dive into the "Disappearing Pulse" problem and the clever hardware tricks VLSI engineers use to solve it.
The Disappearing Pulse Problem
Imagine you have a high-speed networking chip. A packet arrives, and the 1GHz receiver logic generates a single-cycle packet_received pulse. You need to send this pulse to a 100MHz microcontroller on the same chip so it can log the event.
You route the 1GHz pulse directly into a standard 2-Flop Synchronizer running at 100MHz. You run the simulation, and... nothing happens. The microcontroller never sees the pulse. What went wrong?
It comes down to simple math and timing:
A single clock cycle at 1GHz is exactly 1 nanosecond long. Your pulse exists for exactly 1ns.
A 100MHz clock only ticks once every 10 nanoseconds.
If the 1ns pulse fires and disappears between the 10ns ticks of the slow clock, the slow clock's flip-flops will never see it. The data violates the fundamental rule of sampling: the signal must be stable long enough for the destination clock to actually sample it.
The Solution: Pulse-to-Toggle Synchronization
To fix this, we cannot just send the raw pulse. We need to "stretch" the event so the slow clock has time to notice it. The most elegant, open-loop way to do this is using a Pulse-to-Toggle Synchronizer.
Instead of trying to catch a fleeting pulse, we convert the pulse into a permanent state change (a toggle). The slow domain then looks for that state change and converts it back into a pulse.
Here is the step-by-step architecture:
Step 1: The Toggle Flip-Flop (Fast Domain)
In the fast domain (1GHz), we route the incoming pulse into the enable pin of a Toggle Flip-Flop (T-Flop) or a simple XOR gate.
Every time a
packet_receivedpulse arrives, the output of this register flips its state (from0to1, or from1to0).Because the state stays flipped forever (until the next pulse), we have effectively stretched a 1ns event into a permanent level change.
Step 2: The 2-Flop Synchronizer
Now that we have a stable, long-lasting level change, we can safely pass it through a standard 2-Flop Synchronizer into the slow domain (100MHz). Because the signal is now a continuous level, the slow clock is guaranteed to capture it, completely avoiding the disappearing pulse problem.
Step 3: The Edge Detector (Slow Domain)
Once the synchronized toggled signal is safely inside the slow domain, we need to turn it back into a single-cycle pulse.
Remember the Rising and Falling Edge Detector code I shared on this blog back in November? This is exactly where you use it!
We run the synchronized signal through an edge detector in the 100MHz domain.
Whenever the edge detector sees the signal change (either rising or falling), it generates a clean, single-cycle pulse in the 100MHz domain.
The event has successfully crossed the chasm!
Alternative: Closed-Loop Pulse Stretching (The Handshake)
If you absolutely cannot afford to miss a pulse, and you need confirmation that the slow domain received it, you can use a closed-loop handshake.
The fast domain receives the pulse and sets a
req(request) signal to1. It holds this signal high indefinitely.The slow domain captures the
reqsignal through a 2-Flop Synchronizer and generates a pulse.The slow domain then sends an
ack(acknowledge) signal back to the fast domain through another 2-Flop Synchronizer.Once the fast domain sees the
ack, it finally drops thereqsignal to0.
While this is incredibly safe, it requires the fast domain to wait several slow-clock cycles before it can send a second pulse. If your fast domain is generating rapid-fire pulses (e.g., multiple packets arriving back-to-back), the handshake mechanism will bottleneck your system. In those cases, a fast-to-slow Asynchronous FIFO is required.
The Practical Takeaway
When designing RTL, you must always look at the frequencies of your clock domains.
Going from Slow to Fast: A 2-Flop synchronizer usually works fine, because a slow pulse is naturally wide enough for a fast clock to sample it multiple times (though you will need an edge detector to prevent a single slow pulse from turning into multiple fast pulses!).
Going from Fast to Slow: Never send a raw pulse. You must use a Pulse-to-Toggle circuit, a Handshake, or an Async FIFO to stretch the data so the slow clock can actually see it.
Mastering these topologies ensures your chips won't just work in perfectly timed academic simulations, but in the chaotic, multi-frequency reality of physical silicon.
No comments:
Post a Comment