GLS · Chapter 8 · Timing-Violation Debug
Timing Checks, Notifiers & X-Injection
This lesson connects timing violations to unknown-propagation through the notifier mechanism. A cell's specify block holds timing checks for setup, hold, recovery, removal, and width, each with a notifier register that also feeds the cell's primitive. When a check fires, it toggles the notifier, and the primitive drives the cell output to an unknown. That injected unknown then propagates through downstream logic like any other, so a single timing violation can become a wide propagation problem, sometimes flooding the design from one small violation. This lesson traces the path from check to notifier to unknown to propagation, and shows how to manage the flood without masking real violations by disabling checks wholesale. Static timing analysis remains the arbiter of real timing throughout.
Foundation12 min readGLSNotifierX-InjectionTiming ChecksX-Propagation
Chapter 8 · Section 8.5 · Timing-Violation Debug
Project thread — a $setup/$hold firing on a counter/FSM flop injects X that flows to outputs (as in 6.6). This lesson is the bridge between a timing violation and the X-propagation it causes; 8.6 sees it on a clock-gated block.
1. Why Should I Learn This?
A timing violation rarely stays put — via the notifier it becomes an X that spreads.
- Check → notifier → UDP →
Xis the injection path (2.5). - The injected
Xpropagates (Chapter 6) — one violation can flood downstream. - Managing the flood without disabling real checks is the skill (8.4).
This unifies timing-violation debug (Ch8) with X-propagation (Ch6).
2. Real Silicon Story — one violation, a screen full of X
A single $hold violation on one flop produced a screen full of X downstream — dozens of signals unknown. The team assumed dozens of bugs.
There was one bug. The hold violation injected X on that flop (notifier), and the X propagated through the downstream logic (Chapter 6) — fanning out to everything the flop fed. Fixing the single hold race (add delay, 8.3) cleared the entire flood.
Lesson: a timing violation becomes an X-propagation problem — one injected X can flood the design. Trace the flood back to the single injecting violation; don't count the symptoms as separate bugs.
3. Concept — X-injection and its propagation
The injection path (recap 2.5):
- A cell's
specifyblock has timing checks ($setup/$hold/$recovery/$removal/$width), each with a notifierreg. - On a violation, the check fires → toggles the notifier.
- The notifier is a UDP input, so the toggle drives the cell output to
X— X-injection.
The propagation (Chapter 6):
- The injected
Xflows downstream by the X-flow rules (6.3): muxes propagate on unknown selects, flops captureX, controlling values absorb it. - One injected
Xcan fan out widely — a flood from a single violation.
Managing X-injection (without masking real violations):
- Trace the flood to its source — the single injecting violation (don't count symptoms).
- Fix the injecting violation (real → design, 8.2/8.3; artifact → run, 8.4) — clears the whole flood.
- Selective control exists (per-instance notifier/check control,
+notimingchecks) but is a blunt tool: disabling checks hides real violations (8.4). Use it narrowly and justified, never wholesale.
Framing (accuracy):
- The notifier
Xis a modelling flag (Chapter 6) — investigate the source. - STA is the arbiter of real timing; managing
X-injection changes simulation noise, not the underlying timing (2.5/0.3).
4. Mental Model — one leak floods the whole floor
A timing violation is a single pipe leak (the injected X); propagation is the water spreading across the floor.
- One leak (notifier
X) can soak an entire room (downstream fan-out) — it looks like many problems. - You don't mop every puddle as a separate issue — you find the one leak and fix it (the injecting violation).
- Turning off the water main (disabling all checks) stops the flood and hides the next real leak (8.4) — too blunt.
Trace the water back to the one leak, fix that, and the floor dries.
5. Working Example — one violation, a propagating flood
The injection and its spread (representative):
// X-injection at the source flop — REPRESENTATIVE (2.5)
$hold (posedge CK, D, 0, notify); // hold violation -> notifier toggles -> q = X (injected)
// q feeds a fan-out cone:
assign a = q & sel; // controlling? if sel=0, X absorbed; if sel=1, X propagates (6.3)
assign b = q ^ c; // XOR: no controlling value -> X propagates (6.3)
assign out = {a, b, ...}; // one q=X floods multiple outputs# The flood, traced back (tool-neutral):
# symptom: out[7:0] mostly X (looks like many bugs)
# trace back via X-flow (6.3): out <- a,b <- q (single X source)
# root: ONE $hold violation injecting X on q
# fix: fix that hold race (8.3) -> whole flood clears (do NOT disable checks wholesale, 8.4)Practical context (representative, tool-neutral):
# Manage X-injection (tool-neutral):
# 1) a flood of X? trace back via X-flow (6.3) to the ONE injecting violation
# 2) classify it (8.4): real (design fix, 8.2/8.3) or artifact (run fix)
# 3) fix the SOURCE -> the whole flood clears
# 4) selective check/notifier control is a BLUNT tool -- narrow + justified only; never wholesale
# 5) STA remains the arbiter of real timing (0.3)One injected X flooding downstream, as a real waveform:
One hold violation injects X on a flop; the X propagates and floods downstream outputs
8 cycles6. Debugging Session — a screenful of X from one violation
A single timing violation injects X that propagates and floods dozens of downstream signals, looking like many bugs; tracing the flood back through the X-flow rules reaches the one injecting violation, and fixing it clears the whole flood without disabling checks
ONE INJECTED X FLOODS DOWNSTREAM — TRACE TO THE SOURCEOne timing check fires, and dozens of downstream signals go X. It looks like many separate failures.
One X-injection, propagated. The timing violation fired a check, which toggled the notifier, which drove the cell output to X (2.5) — X-injection. That single X then propagated through the downstream fan-out by the X-flow rules (6.3): non-controlling gates (XOR) and unknown-select muxes pass it, flops capture it — so one injected X floods everything the flop feeds. The dozens of Xs are symptoms of a single violation, not dozens of bugs. Counting them separately (or, worse, disabling checks to silence them, 8.4) misreads a propagation flood as many faults.
Trace the flood back through the X-flow (6.3) to the single injecting violation, then classify and fix that source (8.4): if real (long path / hold race / skew), fix the design (8.2/8.3); if artifact (edge-aligned stimulus, reset-active check, wrong corner), fix the run. Fixing the one source clears the whole flood. Only if the modelling X-pessimism is genuinely excessive should you use narrow, justified check/notifier control — never disable checks wholesale (it hides real violations, 8.4). The lesson: a timing violation injects X via the notifier, and that X propagates like any unknown (Chapter 6) — so one violation can flood the design; trace the flood back to the single injecting violation and fix it, rather than counting symptoms or disabling checks. (The notifier X is a modelling flag; STA is the arbiter of real timing, 2.5/0.3.)
7. Common Mistakes
- Counting propagated
Xs as separate bugs. One injection can flood many signals. - Disabling checks to silence the flood. Hides the real injecting violation (8.4).
- Not tracing the
Xback through the X-flow rules (6.3) to the source. - Fixing symptoms downstream instead of the injecting violation.
- Forgetting the
Xis a modelling flag. Investigate the source (Chapter 6).
8. Industry Best Practices
- Trace an
Xflood back to the single injecting violation (6.3). - Fix the source (real → design, artifact → run, 8.2–8.4) — the flood clears.
- Use check/notifier control narrowly and justified — never wholesale (8.4).
- Treat the notifier
Xas a flag — investigate, don't waive or mask. - Keep STA as the arbiter of real timing.
Senior Engineer Thinking
- Beginner: "Dozens of
Xs — dozens of timing bugs." - Senior: "Or one violation injecting
Xthat propagated. Let me trace the flood back through the X-flow to the source flop — fixing that one violation should clear all of it. I won't disable checks."
The senior reads an X flood as one injected X propagating and fixes the source.
Silicon Impact
Understanding X-injection prevents two failures. First, misattribution: a screenful of X from one violation looks like a catastrophe, and teams may over-react (or, worse, disable checks to quiet it, 8.4 — masking the real source that then ships, 0.3). Second, inefficiency: chasing dozens of propagated symptoms instead of the one source wastes days. Recognising that a timing violation becomes an X-propagation problem — trace the flood back to the single injecting violation, fix it — turns an overwhelming X flood into a single, targeted fix. And keeping checks on (managing injection narrowly, deferring to STA) ensures the next real violation still fires. This is the bridge that makes Ch6 and Ch8 one skill.
Engineering Checklist
- Traced the
Xflood back to the single injecting violation (6.3). - Classified the source (real vs artifact, 8.4).
- Fixed the source (design or run) — confirmed the flood cleared.
- Used check/notifier control narrowly (never wholesale).
- Kept the notifier
Xas a flag; deferred real-timing signoff to STA.
Try Yourself
- Create a
$holdviolation that injectsXon a flop feeding a fan-out cone (anXORand an unknown-select mux). - Observe: the single
Xfloods multiple downstream signals (X-injection + propagation, 6.3). - Change: fix the one hold race (add delay, 8.3).
- Expect: the entire flood clears from one fix — proving it was one injected
X, not many bugs. Confirm you never had to disable a check.
Any free Verilog simulator with SDF timing checks reproduces X-injection and its propagation. No paid tool required.
Interview Perspective
- Weak: "A timing violation just prints a message."
- Good: "A timing check fires, toggles the notifier, and injects
Xon the output, which then propagates downstream." - Senior: "A timing violation becomes an X-propagation problem: the notifier injects
X, and it floods the fan-out by the X-flow rules. So a screenful ofXis often one violation — I trace it back to the single injecting source and fix that (real → design, artifact → run), never disabling checks wholesale (which would mask real ones). TheXis a flag; STA is the arbiter."
9. Interview / Review Questions
10. Key Takeaways
- A timing check that fires toggles a notifier, and because the notifier is a UDP input, the cell output is driven to
X— X-injection (2.5). - The injected
Xthen propagates downstream by the X-flow rules (Chapter 6) — so one timing violation can flood the design withX. - A screenful of
Xis often one injecting violation, not many bugs — trace the flood back through the X-flow (6.3) to the single source. - Fix the source (real → design, 8.2/8.3; artifact → run, 8.4) and the whole flood clears; use check/notifier control narrowly — never disable checks wholesale (masks real violations, 8.4).
- The notifier
Xis a modelling flag (Chapter 6); STA is the arbiter of real timing (2.5/0.3). Next: 8.6 — a clock-gated block violation.
Quick Revision
Timing violation → X-propagation: check fires → notifier toggles → UDP injects
X(X-injection, 2.5) →Xpropagates (Ch6 rules). One violation can flood the design — a screenful ofXis often ONE source. Trace the flood back (6.3) to the single injecting violation; fix IT (real → design, artifact → run, 8.4). Manage injection narrowly — never disable checks wholesale (masks real ones). STA is the arbiter. Next: 8.6 — a clock-gated block violation.