GLS · Chapter 4 · SDF Annotation
Anatomy of an SDF File
An SDF file becomes readable once you know its skeleton. A header sets the global context, giving the version, design, timescale, the hierarchy divider character, and often the voltage and temperature that name the corner. Then come a series of cell blocks, one per instance, each naming a cell type and an exact instance path and holding delay entries and timing-check entries. The delay entries cover pin-to-pin cell delays and net interconnect delays, while the timing checks cover setup, hold, and width. This lesson walks that structure and shows why the instance paths and the divider must match the netlist exactly. A mismatched path does not error loudly; the entry simply fails to match and that instance is silently left at zero delay.
Foundation11 min readGLSSDFIOPATHINTERCONNECTHierarchy
Chapter 4 · Section 4.2 · SDF Annotation
Project thread — this is the exact file that will annotate the counter in 4.6. Reading its structure now is what lets you verify, later, that every counter flop and net was actually matched.
1. Why Should I Learn This?
To trust an annotated run, you must be able to read the SDF and confirm it matched your netlist.
- The header tells you the timescale, divider, and corner.
- Each
CELLblock ties a delay to an exact instance path. - A path that doesn't match is silently zero — a trap you can only catch by reading structure and coverage.
This sets up the annotation flow (4.3), triplet selection (4.4), and debugging failed/partial annotation (4.5).
2. Real Silicon Story — the block that annotated to zero
A team annotated an SDF and saw a healthy timed run — mostly. One subblock behaved with zero delay while the rest was timed.
The SDF's instance paths for that block used a different divider than the netlist's hierarchy expected, so none of its CELL blocks matched. There was no hard error — the unmatched instances were left at zero delay, and only careful reading of the header DIVIDER and the annotation coverage revealed it.
Lesson: the SDF's instance paths and divider must match the netlist exactly. A mismatch is silent — it leaves instances at zero delay, not an error.
3. Concept — the SDF skeleton
Header (global context):
SDFVERSION— format version.DESIGN— the design name.TIMESCALE— the time unit for all values (e.g.1ns).DIVIDER— hierarchy separator (/or.) used in instance paths.VOLTAGE/TEMPERATURE/PROCESS— the characterisation corner (3.4).
CELL blocks (one per type+instance):
CELLTYPE "DFFRX1"— the library cell.INSTANCE u_cnt/u_q1— the exact hierarchical path in your netlist.DELAY (ABSOLUTE …)— the delay entries:IOPATH CK Q (…)— a cell pin-to-pin delay (3.1).INTERCONNECT src dst (…)— a net delay (3.3).
TIMINGCHECK (…)—SETUP/HOLD/WIDTH/ … values (3.2).
Matching rule: each INSTANCE path (using the DIVIDER) must resolve to a real instance. No match → that instance stays zero-delay, silently (deep debug in 4.5).
4. Mental Model — an SDF is an address book of delays
Read an SDF like an address book: the header sets the addressing scheme (the divider), and each CELL block is an entry addressed to one instance.
- If the address (instance path) is right, the delay is delivered to that instance.
- If the address is wrong (bad divider, wrong scope), the letter is undeliverable — but instead of bouncing, it's silently dropped (zero delay).
- So reading the header's divider and each block's instance path tells you who actually gets timed.
5. Working Example — a full SDF skeleton, annotated
A representative SDF with header and two CELL blocks:
# SDF — REPRESENTATIVE, tool-neutral
(DELAYFILE
(SDFVERSION "3.0")
(DESIGN "counter4")
(TIMESCALE 1ns) # all values are in ns
(DIVIDER /) # hierarchy separator -> instance paths use '/'
(VOLTAGE 0.90::0.90) # corner context (3.4)
(TEMPERATURE 125::125)
(CELL (CELLTYPE "DFFRX1")
(INSTANCE u_cnt/u_q1) # EXACT path in this netlist
(DELAY (ABSOLUTE (IOPATH CK Q (0.08:0.11:0.15)))) # cell delay (3.1)
(TIMINGCHECK
(SETUP D (posedge CK) (0.04:0.05:0.06)) # check value (3.2)
(HOLD D (posedge CK) (0.02:0.02:0.03))))
(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)) # net delay (3.3)
(IOPATH A Y (0.05:0.06:0.08)))))
)Practical context (representative, tool-neutral):
# Quick structural sanity checks before trusting an SDF:
# header: TIMESCALE matches your intent? DIVIDER matches netlist hierarchy ('/' vs '.')?
# corner: VOLTAGE/TEMPERATURE the corner you meant (3.4)?
# coverage: do the INSTANCE paths (u_cnt/u_q0 ..) exist in the netlist?
# The annotation log (4.5) reports how many matched — read it, don't assume.The delay from a matched block, as a real waveform:
A matched CELL block applies its IOPATH delay; an unmatched one leaves the instance at zero
8 cycles6. Debugging Session — a subblock silently annotated to zero
Part of the design runs zero-delay after annotation because its SDF instance paths use a divider (or scope) that does not match the netlist, so those CELL blocks never match and are silently left at zero delay
INSTANCE PATH / DIVIDER MISMATCH = SILENT ZEROAn annotated run is mostly timed, but one subblock behaves with zero delay. No hard error is reported.
The SDF's INSTANCE paths for that block did not resolve against the netlist — commonly a DIVIDER mismatch (/ vs .), a wrong hierarchical scope in the annotation call (4.3), or a name difference between netlist and SDF. When a CELL block's instance path fails to match, the annotator does not error — it simply does not apply that block, leaving the instance at its default zero delay. So a structurally valid SDF can still leave part of the design untimed, and the only signals are the header DIVIDER, the instance paths, and the annotation coverage log (4.5).
Read the header DIVIDER and confirm it matches the netlist hierarchy; confirm the annotation scope (4.3) points at the right instance; and check the annotation coverage log (4.5) for unmatched instances. Correct the divider/scope/names so every intended CELL block matches. The lesson: an SDF binds delays to exact instance paths, and a path/divider mismatch is silent — it leaves instances at zero delay, not an error. (Deep failure/partial-annotation debugging is 4.5.)
7. Common Mistakes
- Ignoring the header
DIVIDER./vs.mismatch silently unmatches instances. - Not checking
TIMESCALE. Wrong unit scales every delay. - Assuming a valid-looking SDF fully matched. Read the coverage log (4.5).
- Overlooking the corner fields (
VOLTAGE/TEMPERATURE) — that's which corner it is (3.4). - Treating unmatched as an error. It is silent zero-delay.
8. Industry Best Practices
- Sanity-check the header (timescale, divider, corner) before trusting an SDF.
- Verify instance paths exist in the netlist; confirm the divider.
- Always read the annotation coverage log (4.5) — never assume full match.
- Keep netlist and SDF hierarchy consistent across the flow.
- Confirm the corner fields match your intended corner (3.4).
Senior Engineer Thinking
- Beginner: "The SDF parsed, so it's annotated."
- Senior: "Parsed isn't matched. What's the header
DIVIDER? Do the instance paths resolve? What does the coverage log say? Unmatched instances are silently zero — I verify, I don't assume."
The senior reads header + instance paths + coverage, knowing mismatches are silent.
Silicon Impact
A silently zero-delayed subblock is a false-confidence trap: the run looks timed, so its timing-dependent behaviour (glitches, races, check firings) in that block is never exercised with real delays — and a bug there can slip to silicon as an intermittent failure (0.3). Because the failure mode is silent (no error, just zero delay), the only defence is reading the SDF structure and the coverage log. Understanding the anatomy — header divider, instance paths, coverage — is what turns "it annotated" into "I verified every block is timed."
Engineering Checklist
- Checked the header:
TIMESCALE,DIVIDER, corner (VOLTAGE/TEMPERATURE). - Confirmed
INSTANCEpaths resolve against the netlist (divider matches). - Read the annotation coverage log for unmatched instances (4.5).
- Confirmed the corner fields match the intended corner (3.4).
- Did not treat "parsed" as "fully matched."
Try Yourself
- Write the representative SDF above and annotate it onto a small two-flop netlist — one instance path correct, one deliberately wrong-divider.
- Observe: the correct instance is timed (clk-to-Q delay); the wrong-divider one runs zero-delay.
- Change: fix the divider/path on the second instance.
- Expect: now both are timed. Then read the simulator's annotation log and see the matched-vs-unmatched count change — proving coverage, not just parse.
Any free Verilog simulator reports SDF annotation coverage. Real SDF is tool-generated, but the header/CELL structure is standardised. No paid tool required.
Interview Perspective
- Weak: "An SDF is just a list of delays."
- Good: "It has a header (version, timescale, divider, corner) and
CELLblocks with instance paths,DELAY(IOPATH/INTERCONNECT), andTIMINGCHECK." - Senior: "Each
CELLblock binds delays to an exact instance path via the headerDIVIDER. A path/divider mismatch is silent — the instance stays zero-delay — so I read the header, verify paths, and check the coverage log rather than trusting a clean parse."
9. Interview / Review Questions
10. Key Takeaways
- An SDF has a header (
SDFVERSION,DESIGN,TIMESCALE,DIVIDER, cornerVOLTAGE/TEMPERATURE) and a series ofCELLblocks. - Each
CELLblock pairs aCELLTYPEwith an exactINSTANCEpath and holdsDELAY(IOPATHcell delays,INTERCONNECTnet delays) andTIMINGCHECK(SETUP/HOLD/WIDTH) entries. - Instance paths use the
DIVIDERand must match the netlist exactly. - A path/divider mismatch is silent — the instance is left at zero delay, not flagged as an error.
- Verify an SDF by reading the header, checking instance paths, and reading the annotation coverage log (4.5) — never assume "parsed" means "matched." Next: 4.3 — the SDF back-annotation flow.
Quick Revision
SDF skeleton: header (
TIMESCALE,DIVIDER, corner) +CELLblocks (CELLTYPE, exactINSTANCE,DELAYIOPATH/INTERCONNECT,TIMINGCHECK). Instance paths must match the netlist via the divider. Mismatch = silent zero-delay (no error). Verify with header + paths + coverage log (4.5). Next: 4.3 — the back-annotation flow.