Quick Cheat Sheet
What a CDC report line usually means, sorted by how often it actually shows up on a real signoff run. Skim this before triaging a fresh report.
| Category | What the report shows | Where to look |
|---|---|---|
| Structural | Signal crosses domains with no synchronizer flops at all | The source register's fanout — was it wired straight into destination-domain logic instead of a synchronizer? |
| Structural | Combinational logic reported between synchronizer stages | Any gate or mux inserted between the first and second synchronizer flop — remove it, route register-to-register only |
| Structural | Two "safe" synchronized signals still cause a functional bug downstream | Reconvergence — both signals traced back to one source, recombined in a gate after synchronizing independently |
| Structural | A narrow pulse from a fast domain occasionally disappears | Fast-to-slow crossing with a plain flop instead of a pulse synchronizer or toggle/ack scheme |
| Structural | Multi-bit bus flagged as a single unsynchronized crossing | A bus double-flopped as a group instead of gray-coded or handshaked — check whether more than one bit can change per transfer |
| Structural (RDC) | Async reset release flagged as unsynchronized | Reset de-assertion edge, not assertion — needs a reset synchronizer so release lines up with a clock edge |
| Structural (RDC) | Reset domain crossing on a signal you didn't know was a reset | A soft/internally-generated reset (register or IP output used to reset a sub-block) — these don't look like a reset tree structurally |
| Methodology | Report is dominated by reset, config, or scan signals | Signal should likely be declared quasi-static / a functional false path, not left as a live async crossing |
| Methodology | A crossing you know can't happen is still flagged | Structural analysis can't see arbitration/mux exclusivity — needs an explicit waiver or "through"-point constraint, not a code fix |
| Methodology | Huge volume of noise from one third-party block | Missing or overly pessimistic black-box timing/clock model at that block's boundary |
| Methodology | Block-level run was clean, integration-level run isn't | Block and top-level clock-grouping assumptions disagree — re-check which clocks were declared asynchronous at each level |
| Advanced | New crossings appear only after power intent is added | Isolation/retention cell control pins and DVFS domains create new async relationships — re-run CDC with power intent included, not gate-level only |
Two Very Different Kinds of "CDC Violation"
The single biggest source of wasted debug time on a CDC report is treating every line the same way. A CDC signoff run produces two fundamentally different classes of finding, and they need opposite responses.
Structural violations describe an actual defect in the RTL — a missing synchronizer, a glitch path, a reconvergence hazard. These get fixed by changing the design.
Methodology findings describe a problem with how the tool was set up to analyze the design — a clock pair that should have been declared asynchronous and wasn't (or vice versa), a black-boxed block with no timing model, a functionally-impossible path the tool can't see is impossible. These get fixed by changing a constraint, a waiver, or a black-box model — not the RTL.
A high violation count usually means a setup problem, not a hundred real bugs. A first CDC run on a fresh block routinely reports far more crossings than are real, structural hazards — most of it is noise from unclassified reset/config signals and unmodeled exclusivity. Separating structural findings from methodology noise before touching any RTL is the highest-leverage first step on any report.
Structural Violations: What the Report Is Telling You About Your RTL
These are the findings that describe an actual defect the tool found in your RTL. Each one has a fixed, well-known cure — the work is recognizing which pattern you're looking at.
| Violation type | What it means | Fix |
|---|---|---|
| Missing synchronizer | A signal crosses into a different, unrelated clock domain and lands directly on a destination-domain register or logic with no synchronizing flops in between | Add a 2-flop (or 3-flop) synchronizer for a single control bit; gray-code + handshake for multi-bit data |
| Combinational logic in the synchronizer path | A gate or mux sits between the first and second synchronizer stage, so a glitch on that logic can be sampled and latched as a false value | Nothing but a direct register-to-register connection is allowed between synchronizer stages — move any logic before the first flop or after the last |
| Reconvergence | Two or more signals, each individually synchronized correctly, trace back to a common source and recombine in downstream logic — since each resolved independently, they can momentarily disagree even though both look valid | Synchronize the combined/decided value once, not each input separately, or add explicit handshaking so the destination domain knows both arrived together |
| Divergent fanout | A single synchronizer flop's output fans out to multiple independent downstream loads with different logic — under a rare timing corner, different loads can effectively see different resolved values | Buffer the synchronizer output once and fan the buffered copy out, rather than letting every load read the synchronizer flop directly |
| Fast-to-slow pulse loss | A single-cycle pulse generated in a fast domain is narrower than the destination clock period and can be sampled as if it never happened | Stretch the pulse, or replace it with a toggle-and-resynchronize scheme, or a full request/acknowledge handshake |
| Bus / multi-bit coherency | A multi-bit value is synchronized as a plain group of flops; if more than one bit changes at once, the destination can sample an intermediate value that was never actually written | Gray-code the value before crossing (bounds the ambiguity to one bit) or use a full handshake so the whole word is guaranteed stable when sampled |
| Handshake protocol violation | A request/acknowledge crossing where the request can drop before the acknowledge could possibly have propagated back, or the data isn't held stable for the full handshake window | Hold request (and data) until acknowledge returns; verify with an explicit assertion on pulse width and request-to-acknowledge latency, not just flop count |
Reset Domain Crossing (RDC): CDC's Often-Skipped Sibling
A reset domain crossing happens when a source register's asynchronous reset differs from its destination register's reset — or the destination has no reset at all. It is not caught by standard CDC checks, which mostly look at data and clock relationships, and most teams run it as a separate check, if they run it at all.
| RDC issue | Why it's dangerous | Fix |
|---|---|---|
| Unsynchronized reset release | Reset assertion is inherently safe (it forces a known state), but if de-assertion (release) happens close to a destination clock edge, it can violate recovery/removal timing on that flop just like a data setup/hold violation | Assert asynchronously, release synchronously — route the reset through a small reset synchronizer at each domain boundary |
| Soft / internally-generated resets | A register, FSM, or IP output used to reset part of the design (common for selective block restarts) doesn't look like a reset structurally, so it's easy to miss entirely during reset-tree review | Treat any signal driving another flop's reset pin as part of the reset tree, regardless of where it was generated, and run it through the same RDC analysis as primary resets |
| Dual-synchronicity reset use | The same reset signal resets one flop synchronously and a different flop asynchronously elsewhere in the design — an easy, easy-to-miss inconsistency introduced during ECOs | Keep reset usage consistent per domain; if you can't, treat the crossing explicitly rather than assuming both flops behave the same way |
| Reset used as a data signal | An async set/reset pin gets wired to carry functional data instead of a true reset — while reset is asserted, the "data" value can't be controlled, corrupting whatever depends on it | Never reuse a reset/set pin as a data input; if the behavior is intentional, model it explicitly rather than through the reset pin |
Not every reset-domain difference is a real hazard. If the source flop's reset is itself generated synchronously within its own clock domain, the path can behave like an ordinary synchronous timing path rather than a metastability risk — in which case static timing analysis, not a synchronizer, may already cover it. Blanket-treating every reset-domain mismatch as equally dangerous is one of the biggest sources of RDC report noise.
Setup & Methodology Issues: When the Report Itself Is Wrong
A large share of a first CDC report is not describing bugs in your RTL at all — it's describing gaps or mistakes in how the tool was told to analyze the design. Getting these right is what turns a report with thousands of lines into one with a manageable, trustworthy list of real findings.
| Issue | What happens | Fix |
|---|---|---|
| Missing or wrong asynchronous clock-group declaration | Two clocks that are actually unrelated get treated as synchronous, so real crossings between them are silently skipped — a false negative that can hide a genuine bug all the way to silicon | Review every clock pair's declared relationship explicitly; don't inherit a default assumption from an unrelated block or an earlier project |
| Over-broad asynchronous declaration | A clock pair that's actually related (e.g. same source, integer-divided) gets marked asynchronous, flooding the report with crossings that aren't real hazards | Model true clock relationships (divided, generated, gated) accurately instead of defaulting everything unfamiliar to "asynchronous" |
| Un-declared quasi-static signals | Configuration, mode, and one-time-event signals get analyzed as if they toggle every cycle, dominating the report with noise that has no real metastability risk | Explicitly declare genuinely static/quasi-static signals with a constraint, and verify they really are stable for long enough before doing so |
| Functionally-false paths | Structural analysis reports a crossing that can never actually occur — e.g. between two peripherals on a shared bus where the arbiter guarantees only one is ever active — because the tool can't see that functional guarantee | Add an explicit "through"-point exception or documented waiver; don't rely on the tool inferring exclusivity it has no visibility into |
| Incomplete black-box / third-party IP models | A block with no accurate internal timing or clock model forces the tool into pessimistic worst-case assumptions at its boundary, generating a wall of noise that swamps real findings elsewhere | Provide an accurate boundary/timing abstraction for black-boxed IP, or exclude the block's internals once it's independently signed off and focus only on its interface crossings |
| Stale or blanket waivers | A waiver written for one version of the RTL keeps suppressing a report line after the code around it changed — silently hiding a newly introduced real bug behind an old justification | Tie waivers to the specific RTL revision that justified them and re-review at every significant design change, not just at final signoff |
| Block-clean, integration-level violation | A block signs off clean in isolation, but a real crossing only appears once it's integrated into the full chip — usually because a clock assumed synchronous at block level turns out not to be at the top level | Keep block-level and top-level clock-grouping declarations consistent, and re-verify crossings at every integration boundary, not just within each block |
When Design Complexity Raises the Stakes
A few trends in current chip design make CDC verification meaningfully harder than the classic two-clock picture above, and are worth checking for explicitly rather than assuming an old flow still covers them.
| Trend | New CDC exposure |
|---|---|
| Power-managed domains (isolation / retention cells) | An isolation cell's enable signal drives the destination register combinationally — if that enable is asynchronous to the destination clock, its own assertion/de-assertion edge can cause a hazard, separate from the data path it's protecting. Retention cells' save/restore control pins create their own new crossings that a pre-power-aware CDC run won't see at all. |
| Dynamic voltage and frequency scaling (DVFS) | Once a domain's voltage can change, its clock's phase relationship to nominally-related sibling clocks becomes non-deterministic — registers that share a clock name can still need full CDC treatment once one side is on a variable-voltage rail. This is easy to miss because the clock names match. |
| Many-clock-domain SoCs (GALS-style, AI-accelerator-class designs) | Designs built from many independently-clocked tiles or cores multiply both the ordinary CDC surface and the power-domain-crossing surface at once — the volume of crossings to classify grows much faster than the design's overall complexity. |
| Multi-die / chiplet integration | Each die can run its own independent clock domain, and swapping or adding a die can force re-verification of synchronization across the whole assembled system, not just within one die. |
The practical takeaway: run CDC (and RDC) analysis with power intent included, at RTL, rather than waiting for gate-level netlists — by the time these crossings show up in a gate-level-only flow, they're far more expensive to fix.
Triage Tactics: Working a Violation Report Without Losing a Week
- Split structural findings from methodology findings before touching any RTL. They need completely different responses, and mixing them together is the single biggest cause of wasted debug time on a fresh report.
- Start with reset-related crossings. They're usually the majority of raw report volume, and disproportionately contain both the most noise (uninteresting quasi-static resets) and the most dangerous real bugs (unsynchronized reset release) — sort them out early rather than last.
- Check which clock groups were auto-inferred versus user-declared before trusting the crossing count. An auto-inferred "asynchronous" relationship is a good place to look first for both false positives and missed real relationships.
- Sign off reusable blocks once, at the block boundary — carry forward the block's synchronizer structure and interface contract instead of re-flattening and re-classifying its internals at every level of integration.
- Tie every waiver to the RTL revision that justified it. A waiver that silently survives an unrelated code change is a bug hiding behind an old sign-off, not a solved problem.
- For power-managed or DVFS domains, don't trust the clock name alone. Check the voltage-domain relationship explicitly — same clock name across a voltage boundary is not the same guarantee it is on a single-rail design.
- When a reset-domain-difference finding shows up alone, check whether the source reset is itself generated synchronously in that clock domain before assuming it needs a full synchronizer fix — it may already be covered by ordinary timing analysis.
Violation category names, thresholds, and report formats vary between CDC verification tools and methodologies; the underlying failure mechanisms described here — missing or broken synchronization, reconvergence, unsynchronized reset release, and misclassified clock relationships — are common across the industry's static and formal CDC signoff practice.