Skip to content

GLS · Chapter 4 · SDF Annotation

Working Example: Annotating the Counter with SDF

This capstone applies the whole SDF flow to the counter you read earlier in the track. It walks a representative counter SDF carrying cell delays, net interconnect delays, and flop timing checks as min, typical, and max triplets. It back-annotates that SDF at time zero, bound to the correct scope, selects the max values for a setup-flavoured run, and verifies full coverage with zero unmatched instances. A before-and-after waveform shows the counter shift from zero-delay to real clock-to-output timing, with count transitions now delayed. The debug session shows what a partially annotated counter looks like when one flop is silently left at zero delay while its siblings are timed, producing subtly inconsistent count timing that only the coverage log can name. This closes the SDF chapter and prepares you to adapt a testbench for gate-level runs.

Foundation13 min readGLSSDFCounterBack-AnnotationWorked Example

Chapter 4 · Section 4.6 · SDF Annotation

Project thread — the counter has travelled from RTL (2.6) through timing concepts (Ch3) to a real annotated run here. Chapter 5 adapts the testbench so this timed counter runs cleanly (reset, X, strobing); the counter carries on toward the FSM and mini-SoC later.

1. Why Should I Learn This?

This is where the chapter's pieces become one repeatable procedure: SDF → annotate → select → verify → timed run.

  • You take the counter from zero-delay to timed with confidence.
  • You verify it (coverage, 0 unmatched) rather than assume it.
  • You recognise a partially annotated counter on sight.

It integrates 4.1–4.5 and closes the SDF chapter.

2. Real Silicon Story — the counter bit that stayed instant

A counter's timed run looked right — most bits updated a clk-to-Q delay after the clock. But one bit kept updating instantly, and an occasional glitch-capture on a decode of that bit slipped through.

That flop's instance had been left unmatched in annotation (a scope/name issue, 4.5), so it ran zero-delay while its siblings were timed. The mixed timing was subtle in the waveform and invisible in the pass/fail — only the coverage log's unmatched line named it.

Lesson: verify the whole counter annotated. One silently-zero flop makes the timed run partly fake — read coverage, demand 0 unmatched.

3. Concept — the counter annotation, end to end

The procedure (integrating the chapter):

  1. SDF (4.1/4.2): a file for this counter netlist — IOPATH (flops + increment cells), INTERCONNECT (nets), TIMINGCHECK (flop setup/hold), each MIN:TYP:MAX.
  2. Annotate (4.3): $sdf_annotate("counter4.sdf", u_dut) at time 0, scope = the counter instance.
  3. Select (4.4): MAX for a setup-flavoured run (or MIN for hold), stated explicitly.
  4. Verify (4.5): read the coverage log — matched counts, 0 unmatched across all four flops and the increment logic.
  5. Run: the counter now shows real clk-to-Q delay; transitions land a delay after each edge.

What you should see: xxxx at power-up until reset (2.6), then 0,1,2,3,… — but now each count transition occurs a clk-to-Q delay after the clock edge, not instantly.

Scope: representative; a verified annotated run is timed but dynamic — STA (all corners) is signoff (0.3).

Counter fully annotated: SDF IOPATH on flops and increment cells, INTERCONNECT on nets, SETUP/HOLD checks on flops, verified 0 unmatchedcheckIOPATH/checksIOPATH/netcounter4.sdfIOPATH + INTERCONNECT +TIMINGCHECK (MIN:TYP:MAX)$sdf_annotate @ time0scope = counter; select MAX(4.4)Verify coverage0 unmatched across allflops + gates (4.5)4x DFFRX1 (timed)CK=>Q delay + setup/holdchecksIncrement cells(timed)IOPATH + INTERCONNECT netdelaycount[3:0] (timed)transitions a clk-to-Qdelay after CK12
Figure 1 — the counter, fully annotated (representative). The SDF supplies IOPATH cell delays for the four DFFRX1 flops and the XOR/AND increment cells, INTERCONNECT net delays between them, and SETUP/HOLD timing checks on each flop — all MIN:TYP:MAX. $sdf_annotate binds it at time 0 to the counter scope; MAX is selected for a setup-flavoured run; coverage is verified at 0 unmatched. Every flop and net is timed, so count transitions land a real clk-to-Q delay after each edge.

4. Mental Model — the counter gets a stopwatch

Pre-annotation, the counter is a silent film — everything happens on the exact clock frame (zero-delay).

  • Annotation gives every flop and wire a stopwatch — the SDF delays.
  • Now each count transition happens a measured moment after the clock, and data must respect the setup/hold windows.
  • Verify every stopwatch is running (0 unmatched) — one stopped stopwatch (unmatched flop) and that bit is back in the silent film while the rest is timed.

5. Working Example — the counter SDF, annotation, coverage, waveform

A representative counter SDF (trimmed to shape):

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# counter4.sdf — REPRESENTATIVE, tool-neutral. Values are MIN:TYP:MAX (4.4).
(DELAYFILE (SDFVERSION "3.0") (DESIGN "counter4") (TIMESCALE 1ns) (DIVIDER /)
  (CELL (CELLTYPE "DFFRX1") (INSTANCE u_cnt/u_q0)
    (DELAY (ABSOLUTE (IOPATH CK Q (0.08:0.11:0.15))))
    (TIMINGCHECK (SETUP D (posedge CK) (0.04:0.05:0.06))
                 (HOLD  D (posedge CK) (0.02:0.02:0.03))))
  (CELL (CELLTYPE "DFFRX1") (INSTANCE u_cnt/u_q1) (DELAY (ABSOLUTE (IOPATH CK Q (0.08:0.11:0.15)))))
  (CELL (CELLTYPE "DFFRX1") (INSTANCE u_cnt/u_q2) (DELAY (ABSOLUTE (IOPATH CK Q (0.08:0.11:0.15)))))
  (CELL (CELLTYPE "DFFRX1") (INSTANCE u_cnt/u_q3) (DELAY (ABSOLUTE (IOPATH CK Q (0.08:0.11:0.15)))))
  (CELL (CELLTYPE "XOR2X1") (INSTANCE u_cnt/u_x1)
    (DELAY (ABSOLUTE (INTERCONNECT u_cnt/u_i0/Y u_cnt/u_x1/A (0.03:0.04:0.06))
                     (IOPATH A Y (0.05:0.06:0.08))))))

The annotation call and the coverage you must confirm:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// TB — REPRESENTATIVE, tool-neutral
initial begin
  $sdf_annotate("sdf/counter4.sdf", u_dut);   // time 0, scope = counter (4.3)
  // ... reset, then stimulus ...
end
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# Coverage log — REPRESENTATIVE — the check that makes it real (4.5)
SDF: annotated 10 IOPATH, 1 INTERCONNECT, 2 TIMINGCHECK  (selection: MAXDELAYS)
SDF: 0 unmatched instances     <-- every flop (u_q0..u_q3) + increment cells timed

Practical context (representative, tool-neutral):

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
gls/
  netlist/counter4.vg     # synthesized counter (2.6)
  lib/cells.v             # cell models with specify arcs (2.3/2.4)
  sdf/counter4.sdf        # THIS lesson's artifact
  tb/tb_counter4.v        # $sdf_annotate + stimulus
# Flow:  compile(vg+cells+tb) -> $sdf_annotate @0 (scope u_dut, MAXDELAYS)
#        -> confirm 0 unmatched -> run -> timed counter waveform

The counter, zero-delay vs SDF-annotated, as a real waveform:

Counter: zero-delay run vs SDF-annotated (count transitions land a clk-to-Q delay after CK)

9 cycles
After reset the counter counts; without SDF bits change on the clock edge, with SDF they change a clk-to-Q delay laterreset → 0reset → 0SDF: toggles laterSDF: toggles laterCKrst_ncount[0] (no SDF)Xcount[0] (SDF)XXt0t1t2t3t4t5t6t7t8
Representative. Both runs show xxxx at power-up until reset, then counting (2.6). Without SDF, count[0] toggles exactly on the clock edge (zero-delay). With the annotated SDF (MAX selected), count[0] toggles a real clk-to-Q delay AFTER the edge — the visible effect of the whole chapter, verified at 0 unmatched.

6. Debugging Session — a partially annotated counter

1

A timed counter run has one bit updating instantly while the others show clk-to-Q delay — that flop's instance was silently left unmatched during annotation, so it ran zero-delay, and only the coverage log's unmatched line names it

ONE UNMATCHED FLOP = A PARTLY-FAKE TIMED COUNTER
Symptom

The counter's annotated run mostly shows real clk-to-Q delay, but one bit updates instantly. An occasional glitch-capture on a decode of that bit slips through, and pass/fail looks clean.

Root Cause

Partial annotation (4.5) on the counter. One flop's CELL block did not match — a wrong scope, a DIVIDER/path mismatch (4.2), or a post-ECO rename — so that instance was silently left at zero delay while u_q0..u_q3's siblings were timed. The mixed timing (one bit instant, the rest delayed) is the visible signature; the definitive evidence is the coverage log's unmatched line naming that flop. Nothing errored — the counter was partly timed and fully trusted, exactly the false-confidence trap of 4.5, now on the running design.

Fix

Read the coverage log; treat the unmatched flop as a failure. Fix the root cause (correct the $sdf_annotate scope, the DIVIDER, or the renamed instance path so every counter flop matches), re-run, and confirm 0 unmatched across u_q0..u_q3 and the increment cells. Enforce it as policy — fail the run if any counter instance is unannotated. The lesson: annotating the counter is only done when every flop and net is verified matched (0 unmatched); one silently-zero flop makes the timed counter partly fake — the coverage log, not the pass/fail, is the proof. (Verified timed, it is still dynamic — STA closes timing, 0.3.)

7. Common Mistakes

  • Trusting a timed counter without coverage. One unmatched flop runs zero-delay silently.
  • Annotating at the wrong scope for the counter instance (4.3).
  • Not selecting the triplet value (MAX for setup) explicitly (4.4).
  • Reading only matched counts, not the unmatched list (4.5).
  • Calling the verified timed counter "timing closed." STA is signoff (0.3).

8. Industry Best Practices

  • Verify 0 unmatched across all counter flops and increment cells before trusting the run.
  • Annotate at time 0, correct scope, explicit MAX/MIN selection.
  • Keep the counter's power-up-X-until-reset signature (2.6) intact under timing.
  • Fail the run on any unmatched counter instance (policy).
  • Defer timing closure to STA (all corners); use the timed counter for function-with-delay.

Senior Engineer Thinking

  • Beginner: "The counter shows delays now — it's a timed run."
  • Senior: "Every flop? One bit updating instantly means an unmatched instance running zero-delay. I read the coverage log, demand 0 unmatched across u_q0..u_q3, and only then call it timed — and still not closed; that's STA."

The senior verifies whole-counter coverage and separates a verified timed run from timing closure.

Silicon Impact

The counter is the smallest design where the whole SDF flow — and its pitfalls — shows up concretely. A verified annotated counter exercises real clk-to-Q delays, setup/hold windows, and net delays, revealing timing-dependent functional issues (glitch capture, reset-release races) under realistic timing. A partially annotated counter hides them behind a mostly-timed waveform — a silently-zero flop's timing behaviour never gets exercised, and a real bug there can reach silicon as an intermittent failure (0.3). Verifying 0 unmatched is what makes the timed counter trustworthy; STA across corners is what proves its margins.

Engineering Checklist

  • Annotated counter4.sdf at time 0, scope = counter, explicit selection (4.3/4.4).
  • Verified 0 unmatched across u_q0..u_q3 and the increment cells (4.5).
  • Confirmed the timed signature: xxxx → reset 0 → counting, transitions a clk-to-Q delay after CK.
  • Failed the run on any unmatched counter instance (policy).
  • Treated the verified timed run as dynamic — deferred closure to STA (0.3).

Try Yourself

  1. Compile the counter netlist + cell models + TB and annotate counter4.sdf at time 0 (scope = u_dut, +maxdelays).
  2. Observe: after reset, each count bit toggles a clk-to-Q delay after the clock edge, and the coverage log reports 0 unmatched.
  3. Change: rename one flop (e.g. u_q2) in the netlist to simulate an ECO and re-run.
  4. Expect: that bit reverts to zero-delay (updates instantly), and the log lists it as unmatched — the partially-annotated counter, reproduced. Fix the name and confirm 0 unmatched again.

Any free Verilog simulator runs this end-to-end ($sdf_annotate + coverage log). Real SDF is tool-generated, but the flow is identical. No paid tool required.

Interview Perspective

  • Weak: "You give the simulator the counter's SDF and it's timed."
  • Good: "You back-annotate the counter SDF at time 0, select MAX/MIN, and the flops show clk-to-Q delay with setup/hold checks."
  • Senior: "I annotate at the right scope and time 0, select the triplet value for the check, and — crucially — verify 0 unmatched across every counter flop and net before calling it timed. One silently-zero flop makes it partly fake. And a verified timed counter is still dynamic; STA across corners is closure."

9. Interview / Review Questions

10. Key Takeaways

  • Annotating the counter integrates the chapter: SDF (cell + net delays + flop checks, MIN:TYP:MAX) → $sdf_annotate at time 0, correct scopeselect MAX/MINverify coverage (0 unmatched) → timed run.
  • The timed counter keeps its power-up-X-until-reset signature (2.6), but now each count transition lands a clk-to-Q delay after the clock edge.
  • Verification is the point: read the coverage log and demand 0 unmatched across all flops and increment cells — do not trust a mostly-timed waveform.
  • A partially annotated counter (one flop silently zero-delay) is the on-design form of 4.5's trap — one bit updates instantly while the rest is timed; the unmatched line, not pass/fail, names it.
  • A verified annotated counter is timed but still dynamicSTA (all corners) is the timing signoff (0.3). This closes Chapter 4; next, Chapter 5 adapts the testbench for GLS.

Quick Revision

Annotate the counter: SDF (cell+net delays+flop checks, MIN:TYP:MAX) → $sdf_annotate @ time 0, counter scope, select MAX/MINverify 0 unmatched (4.5) → timed run. Signature: xxxx → reset 0 → count, now each transition a clk-to-Q delay after CK. One bit instant = an unmatched flop (partial annotation). Verified timed ≠ closed — STA signs off. Chapter 4 complete; next: Chapter 5 — GLS testbench adaptation.