GLS · Chapter 7 · Reset & Initialization Debug
Working Example: Debugging a Stuck Reset
This capstone debugs a stuck reset on the counter using the whole chapter as a differential diagnosis. A counter that never counts can be stuck for several reasons: reset held asserted so the counter freezes at zero, reset never reaching some flops so those bits stay unknown, reset released too near a clock edge and injecting unknowns at deassertion, or a sync-versus-async style or polarity mismatch. The lesson walks that diagnosis, ruling causes in and out from the waveform, and learns to tell frozen-at-zero apart from stuck-at-unknown, since they point to different root causes. It lands on the primary cause, a reset held asserted by a polarity or logic error, and fixes it at the source. It ties together reset behaviour, uninitialised flops, release timing, and sequencing to close the reset chapter.
Foundation13 min readGLSResetCounterDebuggingWorked Example
Chapter 7 · Section 7.5 · Reset & Initialization Debug
Project thread — the counter closes the reset chapter as it opened Chapters 2–4. A clean reset here is the foundation the mini-SoC's multi-domain reset (7.4) builds on. Chapter 8 takes timing violations (recovery/removal, setup/hold) as its whole subject.
1. Why Should I Learn This?
"The counter won't count" has several reset causes — and the differential diagnosis is the chapter as a procedure.
- You rule causes in and out from the waveform (held / gap / recovery / style).
- You practise distinguishing frozen-at-0 from stuck-at-
X— different root causes. - You end with a source fix, having proven the cause, not guessed.
It integrates 7.1–7.4 on the counter and closes the reset chapter.
2. Real Silicon Story — the counter that never left zero
A counter in bring-up never counted — count sat at 0000 forever. The first guess was "the counter logic is broken."
The counter was fine. Reset was held asserted: a polarity error in the reset logic kept rst_n = 0 (asserted) permanently, so every clock edge re-cleared the flops to 0 — a frozen counter, not a broken one. Fixing the polarity so reset released after power-up let the counter count immediately.
Lesson: a counter frozen at 0 (not X) usually means reset is stuck asserted — the logic works, but reset never lets go. Distinguish frozen-at-0 (held reset) from stuck-at-X (coverage/recovery) — they have different causes.
3. Concept — the differential diagnosis
A counter that won't count has distinguishable reset causes. Read the symptom first:
- Frozen at
0000(defined, all zeros) → reset held asserted (A): polarity/logic keepsrst_n = 0; every edge re-clears (7.1). The counter works; reset never releases. - Stuck at
xxxx(or some bitsX) → reset not reaching those flops:- Coverage gap (B): reset net never wired to a subtree (7.4/2.6) —
Xfrom t=0, never clears. - Recovery-window release (C):
Xappears at deassertion, with a$recovery/$removalmessage (7.3).
- Coverage gap (B): reset net never wired to a subtree (7.4/2.6) —
- Clears late / wrong → style/polarity mismatch (D): sync reset expected immediate, or reversed polarity (7.1).
The diagnostic tells:
- Value —
0000(held reset) vsxxxx(gap/recovery). - Timing — from t=0 (gap) vs at deassertion (recovery) vs never releases (held).
- Log —
$recovery/$removalmessage points to release timing (C).
This example's primary cause: (A) reset held asserted — counter frozen at 0000 by a polarity/logic error.
Scope: GLS surfaces the stuck reset; the fix is at the source (reset logic). GLS stays dynamic — STA signs off reset timing (0.3).
4. Mental Model — read the symptom before reaching for a fix
A stuck reset is a diagnosis, and the symptom narrows the cause before you touch anything.
- All zeros, forever → the doctor sees a patient held down (reset asserted) — free them (release reset).
- Unknown (
X), from the start → a limb never got the signal (coverage gap) — connect it. Xright at wake-up → woken too abruptly (recovery violation) — wake gently (synchronize).- Wakes on the wrong cue → wrong alarm type/polarity (style mismatch) — fix the alarm.
Same complaint ("won't count"), four diagnoses — read value, timing, and log first.
5. Working Example — the stuck-reset trace and fix
The counter with reset held asserted (the primary cause):
// Counter reset logic — REPRESENTATIVE. BUG: polarity error holds reset asserted.
// rst_n is active-low; but the reset source drives it the wrong way:
assign rst_n = ~por_done; // BUG: por_done=1 (done) -> rst_n=0 (ASSERTED) forever -> frozen at 0
// The counter flops re-clear every edge:
DFFRX1 u_q0 (.D(n0), .CK(clk), .RN(rst_n), .Q(count[0])); // RN=0 always -> count stays 0000The source fix (correct polarity so reset releases):
// FIX — correct polarity: release reset once power-on reset completes
assign rst_n = por_done; // por_done=1 -> rst_n=1 (RELEASED) -> counter countsThe other causes, distinguished (representative):
# Same symptom "counter won't count", four causes (tool-neutral):
# count = 0000 forever ............ (A) reset HELD asserted (polarity/logic) [THIS case]
# count = xxxx from t=0 ........... (B) coverage GAP — reset net not reaching flops (7.4/2.6)
# count = xxxx at reset RELEASE ... (C) recovery-window release + $recovery msg (7.3)
# count clears late / on wrong cue (D) sync/async style or polarity mismatch (7.1)Practical context (representative, tool-neutral):
# Stuck-reset diagnosis flow (tool-neutral):
# 1) read count VALUE: 0000 (held reset) vs xxxx (gap/recovery)
# 2) read TIMING: from t=0 (gap) / at deassertion (recovery) / never releases (held)
# 3) read LOG: $recovery/$removal -> release timing (7.3)
# 4) fix at SOURCE: reset polarity/logic (A), reset routing (B), synchronizer (C), style (D)The counter stuck at 0, then fixed, as a real waveform:
Stuck reset: counter frozen at 0000 (reset held asserted) → fixed (reset releases, counter counts)
9 cycles6. Debugging Session — the counter that won't count
A counter never counts and the logic is suspected, but a differential diagnosis on value (0000 vs xxxx), timing, and log shows reset is held asserted by a polarity error — the counter works; reset never releases — fixed at the source
FROZEN AT 0 = HELD RESET; xxxx = GAP/RECOVERYThe counter never counts — count sits at 0000. The counter logic is suspected.
Reset held asserted, diagnosed by the symptom value and timing. The counter is frozen at 0000 — a defined value, not xxxx — which rules out a coverage gap (B, would be X from t=0) and a recovery-window release (C, would be X at deassertion with a $recovery message). Frozen at zero means the flops are being re-cleared every edge: reset is stuck asserted. Tracing the reset logic finds a polarity error — the reset source drives rst_n = 0 (asserted) permanently — so RN = 0 on every counter flop holds count at 0. The counter logic is correct; reset simply never releases. This is cause (A), distinguished from the others precisely because the value is 0000, not xxxx.
Fix the reset source so reset releases after power-up (correct the polarity/logic so rst_n goes to 1 once reset should deassert). Re-run: count advances 0,1,2,3,…. Had the symptom been xxxx instead, the diagnosis would branch: from t=0 → coverage gap (route reset to the missing flops, 7.4/2.6); at deassertion + $recovery → recovery-window release (add a reset synchronizer, 7.3); late/wrong cue → sync/async style or polarity (7.1). The lesson: debug a stuck reset as a differential diagnosis — read value (0000 = held reset vs xxxx = gap/recovery), timing, and log to distinguish held-assertion, coverage gap, recovery-window release, and style/polarity — then fix at the source. (GLS surfaced the stuck reset; it stays dynamic — STA signs off reset timing, 0.3.)
7. Common Mistakes
- Blaming the counter logic for a reset problem.
- Confusing frozen-at-
0with stuck-at-X. Different causes (held reset vs gap/recovery). - Skipping the log. A
$recovery/$removalmessage points to release timing (7.3). - Guessing a fix before reading value/timing/log. The symptom narrows the cause.
- Assuming GLS proves reset timing. It surfaces issues; STA signs off (0.3).
8. Industry Best Practices
- Read value + timing + log before diagnosing a stuck reset.
- Distinguish
0000(held) fromxxxx(gap/recovery) — different root causes. - Fix at the source (polarity/logic, routing, synchronizer, style).
- Verify reset release actually happens after power-up.
- Use GLS to surface, STA to sign off reset timing.
Senior Engineer Thinking
- Beginner: "The counter won't count — the increment logic must be broken."
- Senior: "Is it
0000orxxxx?0000means reset is held — the logic's fine, reset never released. Let me check the reset polarity. If it werexxxx, I'd look at coverage or recovery instead."
The senior reads the symptom value first and runs the differential diagnosis before touching the logic.
Silicon Impact
A stuck reset is a bring-up showstopper — a block frozen at 0 or stuck at X simply doesn't function, and in silicon it manifests as a dead or hung block at power-up. The value of the differential diagnosis is speed and accuracy: distinguishing held reset (polarity/logic — a one-line fix) from a coverage gap (routing) from a recovery-window release (synchronizer) from a style mismatch points straight to the right fix, instead of churning on the counter logic. GLS is where these surface cheaply, before tape-out. Mastering the diagnosis — value, timing, log — is what turns "the block is dead" into a targeted, source-level reset fix.
Engineering Checklist
- Read the symptom value (
0000held vsxxxxgap/recovery). - Read the timing (t=0 / deassertion / never releases).
- Read the log (
$recovery/$removal→ release timing, 7.3). - Fixed at the source (polarity/logic, routing, synchronizer, style).
- Confirmed reset releases and the counter counts; deferred reset-timing signoff to STA.
Try Yourself
- Drive the counter with
rst_nheld at0(polarity error) —countis frozen at0000. - Observe: the value is
0000(notxxxx) → reset held, logic fine. - Change: correct the polarity so
rst_nreleases after power-up. - Expect: the counter counts
0,1,2,3. Then create the other symptoms — disconnect one flop's reset (xxxxfrom t=0, gap) and release reset near a clock edge (Xat deassertion, recovery) — and confirm each diagnosis.
Any free Verilog simulator reproduces all four stuck-reset causes. No paid tool required.
Interview Perspective
- Weak: "The counter won't count, so I'd debug the increment logic."
- Good: "I'd check reset first — a counter frozen at
0is usually reset held asserted." - Senior: "I run a differential diagnosis on the symptom:
0000means reset is held (polarity/logic);xxxxfrom t=0 means a coverage gap;Xat deassertion with a$recoverymessage means a recovery-window release; a late/wrong clear means a style/polarity mismatch. Value, timing, and log point to the cause, and I fix at the source. GLS surfaces it; STA signs off reset timing."
9. Interview / Review Questions
10. Key Takeaways
- Debug a stuck reset as a differential diagnosis using the chapter: read the symptom's value, timing, and log to distinguish the cause.
- Frozen at
0000(defined) → reset held asserted (polarity/logic keepsrst_n = 0; every edge re-clears) — the counter works, reset never releases (7.1). (This example's cause.) - Stuck at
xxxx→ reset not reaching those flops: coverage gap (Xfrom t=0, 7.4/2.6) or recovery-window release (Xat deassertion +$recoverymessage, 7.3). - Clears late/wrong → sync/async style or polarity mismatch (7.1).
- Fix at the source (polarity/logic, routing, synchronizer, style); GLS surfaces the stuck reset and stays dynamic — STA signs off reset timing (0.3). This closes Chapter 7; next, Chapter 8 takes timing-violation debug (recovery/removal, setup/hold).
Quick Revision
Stuck reset = differential diagnosis (value + timing + log).
0000forever → reset HELD asserted (polarity/logic; counter fine) [this case].xxxxfrom t=0 → coverage GAP (7.4/2.6).Xat deassertion +$recovery→ recovery-window release (synchronizer, 7.3). Late/wrong clear → style/polarity (7.1). Fix at the source. GLS surfaces it; STA signs off reset timing. Chapter 7 complete; next: Chapter 8 — timing-violation debug.