
Is this path asynchronous and does it need a fix?
The supplied sketch asks a useful design-review question: sig_a is registered by CLK_A, sig_b by CLK_B, and each passes through a two-flop synchronizer clocked by CLK_C. The synchronized outputs then meet at a combinational function f(a, b).
Assuming the source clocks are asynchronous to CLK_C, both source-to-destination transfers are clock-domain crossings. The logic after the final synchronizer stages is in the CLK_C domain and can be timed normally. The remaining question is functional: does that logic tolerate the two inputs updating in different destination cycles?
If the inputs represent independent status levels and every intermediate combination is acceptable, separate synchronizers may be appropriate. If they represent one decision, transaction, or mutually exclusive state, the design needs a protocol that preserves their intended relationship. Signals coming from different clock names alone do not prove the clocks are asynchronous; generated-clock relationships and constraints must also be checked.
Synchronization and coherency solve different problems
A synchronizer gives an asynchronous single-bit level time to settle before downstream use, reducing the probability that metastability propagates. It does not guarantee that independent transitions will be recognized on the same CLK_C edge. Source timing, clock phase, and sampling uncertainty can make one value visible earlier than the other. The sketch’s “T or T+1” is an illustration, not a universal latency bound.
When the two synchronized paths meet, the destination can temporarily see an old value from one source alongside a new value from the other. This is a reconvergence or coherency concern. Each bit can be a valid logic level while the pair is invalid for the application. It differs from a short combinational propagation glitch: the mixed state can remain for a full destination cycle or longer. Registering the function output alone can therefore capture the wrong combination.
A concrete example: a false AND condition
Suppose the application intends to move from (a, b) = (1, 0) to (0, 1) as one logical update. The function a AND b should be zero for both committed pairs. If the rising b is observed before the falling a, the receiver can see (1, 1) between them and assert its output.
This example assumes those values belong to one coordinated update. For genuinely independent producers, a simultaneous logical update is not defined until the system supplies a pairing rule.
EXPLORE ARRIVAL ORDER
| Observation | a_sync | b_sync | a AND b | Interpretation |
|---|---|---|---|---|
| C0 | 1 | 0 | 0 | Old pair |
| C1 | 1 | 1 | 1 | Mixed pair: false assertion |
| C2 | 0 | 1 | 0 | New pair |
B arrives first: the intermediate pair is 11, so AND asserts even though both intended pairs produce zero.
Conceptual cycle illustration, not a metastability simulation. Different arrival orders expose different intermediate states.
Solution 1: a handshake around a stable payload
For an occasional update owned by one source clock, bundle the related values into one payload register. Hold that payload stable, send a request through a suitable synchronizer, and let the destination capture the complete payload only after the protocol guarantees that it has settled. The destination acknowledges receipt. The source keeps the payload unchanged until the handshake completes, and follows the protocol’s re-arm sequence before another transfer.
A correctly designed bundled-data handshake synchronizes the control and uses guaranteed payload stability and timing constraints; independently synchronizing each data bit is not a substitute. AMD’s XPM_CDC_HANDSHAKE documentation describes a bus transfer with a full request/acknowledgement cycle. Use the macro and its integration requirements appropriate to the target device.
In the original picture, there is no single source clock owning both values. Do not simply concatenate the asynchronous signals and drive that bus into a handshake. First establish ownership or transfer each producer’s value safely to a coordinating domain. That coordinator can then form a coherent pair.
Solution 2: valid means a protocol, not an extra wire
A destination-side pair_valid or commit enable is useful when it means both matched values are safely captured and stable. Store incoming values in pending registers; update the committed pair and enable the consumer only when the defined pairing condition is satisfied.
Adding a two-flop synchronizer to a separate valid signal does not by itself make an unstable bus coherent. A narrow valid pulse can also be missed. The sender must hold data for the specified interval, and the control must cross using a protocol that cannot lose or duplicate the event. If backpressure is possible, acknowledgement or buffering is needed. “Both signals are high” is a data condition, not a substitute for “both transfers have arrived.”
Solution 3: asynchronous FIFOs for streams
For a stream of related values produced in one domain, place the complete pair and any metadata in one FIFO word. An asynchronous FIFO crosses that word between its write and read clocks, preserving word boundaries and order within the channel. The consumer follows the FIFO’s documented empty, read-enable, and data-valid behavior; output latency depends on the selected read mode. See AMD’s asynchronous FIFO interface documentation.
Two unrelated source clocks require separate ingress channels or an earlier coordination stage. One conventional asynchronous FIFO has one write clock and one read clock; it cannot directly accept writes from both CLK_A and CLK_B. Two FIFOs preserve order independently but do not automatically align their outputs. Match transaction IDs, sample epochs, or another explicit rule before consuming a pair.
Define which A belongs with which B
The corrected architecture below gives each producer a CDC-safe transfer channel. In CLK_C, pending values are collected, matched, and committed together. A shared transaction identifier is one possible rule, provided both producers already have a coordinated way to assign it. Arbitrary local counters do not create that relationship.
Another valid specification is “use the latest acknowledged value from each producer.” That gives a well-defined destination snapshot, but does not prove the two original physical events happened simultaneously. If the application requires simultaneous measurements, the acquisition system needs a coordinated sampling scheme and a stated timing tolerance. A handshake or FIFO cannot recover timing information that was never captured.
How to review and verify the fix
- Check clock definitions and relationships, synchronizer placement, attributes, and timing constraints using the device vendor’s CDC flow.
- State which intermediate combinations are allowed, what pairs the values, and what happens when one producer is late or absent.
- Vary clock frequencies, relative phases, event spacing, and backpressure. Model independent capture delays to exercise both arrival orders.
- Check that held payloads remain stable until acknowledgement, updates are consumed once, and unmatched transactions never reach the consumer.
- Exercise reset during a transfer, FIFO full/empty conditions, and restart behavior so stale data is not paired with a new transaction.
RTL simulation can expose protocol and coherency errors, but ordinary digital simulation does not establish metastability MTBF or prove physical CDC safety. Combine functional verification with structural CDC analysis, implementation constraints, and device-specific synchronizer guidance. AMD’s CDC methodology guide provides the broader design context.
A concise answer to the original question
sig_a and sig_b originate in different clock domains. When those clocks are asynchronous to CLK_C, independently synchronizing the signals does not guarantee that they arrive in the same destination cycle. If the logic requires a coherent pair, temporary mixed combinations can produce an incorrect result. Define which values belong together, transfer them through CDC-safe handshakes or FIFOs, and use a destination-valid or commit condition only after both matching values have been captured.
The key design decision is whether the receiver needs independent status levels or one coherent transaction. That requirement determines whether separate synchronizers are sufficient or an explicit transfer and pairing protocol is required.