Tcl · Module 22
Reading the SDC
The constraints decide what the timing numbers mean. A difference between the ones synthesis used and the ones sign-off uses is sometimes correct — and looks exactly like the bug.
Intermediate16 min readtcledapart-iistasdcsignoffverification
Part II · Module 22 · Chapter 22.4 · Reading the SDC
The constraints decide what every timing number means. Applying them is the same source as everywhere else, and the same hazard applies — but this chapter is mostly about a question that only arises at signoff.
1. Applying them, and verifying
source $SDC
verify_constraints $EXPECTED_CLOCKSChapter 21.6 established this in full and it is unchanged here: source succeeding means the script ran, not that anything was constrained.
=== source succeeded. did anything land? ===
good.sdc source rc=0 clocks defined afterwards: 1
typo.sdc source rc=0 clocks defined afterwards: 0If anything, it matters more in STA than in synthesis. An unconstrained path in synthesis produces a badly optimised result somebody may notice. An unconstrained path at signoff produces no violation, because there is no requirement — and signoff is where people stop looking.
2. Run the constraint review here too
Chapter 20.8's review checked a constraint set for completeness. Run it against the live timing session, not just against the file:
source $SDC
verify_constraints $EXPECTED_CLOCKS
review_constraintsThat catches both failure modes at once — a constraint set that is incomplete, and a complete one that did not apply to this netlist because a port name changed between synthesis and here.
The second is specific to STA: the netlist you are analysing was produced by synthesis, which may have changed names. A signoff SDC written against the RTL port names can fail to match the gate-level netlist, silently.
3. Which SDC?
Often not the same file synthesis used, and the provenance record from Chapter 22.2 §3 says which that was:
sdc constraints.sdcCompare it with what this session is about to read. A difference is the subject of the rest of this chapter.
4. The staleness case
First, the bug — Chapter 22.2 §4:
netlist is newer than the sdc: NO — the SDC changed after synthesisSomebody edited the constraints after synthesis ran. The netlist was optimised toward the old ones, and timing is now checking it against new ones. If the change loosened something, the report is clean and wrong.
5. When a difference is legitimate
And now the case the registry purpose asks about, which looks identical from the outside.
Signoff constraints can correctly differ from synthesis constraints, for reasons that are deliberate engineering:
Synthesis constraints are often tightened on purpose. A block constrained at a slightly faster period during synthesis leaves margin for the delays place-and-route will add. Signing off against that same tightened number would be checking the design against a requirement nobody asked for.
Signoff adds what synthesis could not use. Clock uncertainty that reflects measured jitter, derating, and analysis settings that only mean something once the design is placed and routed.
Exceptions can differ. A false path that synthesis needed, because the structure it referred to did not exist yet, may be unnecessary or wrong at gate level.
The names can differ. A signoff SDC may refer to gate-level objects that only exist after synthesis.
6. Make the intent recordable
The resolution is to stop relying on judgement at the point of reading, and record the intent where a script can check it:
# sdc_policy.tcl — what this block's constraints are supposed to look like
set SDC_SIGNOFF [file join $ROOT sdc signoff.sdc]
set SDC_SYNTHESIS [file join $ROOT sdc synthesis.sdc]
# Declared, deliberate differences. Anything else is a finding.
set SDC_EXPECTED_DIFFERENCES {
"signoff period is 2.00; synthesis used 1.90 to leave place-and-route margin"
"signoff adds measured clock uncertainty; synthesis used the budget figure"
}Then the check becomes mechanical and the report becomes informative:
if {$SDC ne [dict get $prov sdc]} {
puts stderr " NOTE signoff SDC differs from the synthesis SDC:"
puts stderr " synthesis: [dict get $prov sdc]"
puts stderr " signoff : [file tail $SDC]"
foreach d $SDC_EXPECTED_DIFFERENCES { puts stderr " expected: $d" }
if {[llength $SDC_EXPECTED_DIFFERENCES] == 0} {
error "SDC differs from synthesis with no declared reason" {} {STA SDCDIFF}
}
}7. What to print
Four lines that make a timing report interpretable six months later:
puts " sdc read : [file tail $SDC]"
puts " sdc at synth : [dict get $prov sdc]"
puts " clocks applied: [llength $::sdc::clocks]"
puts " constraint review: [review_constraints] problem(s)"The third is the 21.6 verification; the second is what makes the comparison possible at all.
8. Exercises
Exercise 1. Why does source returning 0 not mean the design is constrained?
Exercise 2. Why is an unconstrained path worse at signoff than at synthesis?
Exercise 3. Give an STA-specific reason a complete SDC might fail to apply to the netlist.
Exercise 4. Name two legitimate reasons signoff constraints differ from synthesis constraints.
Exercise 5. Why is "the SDC differs" not by itself a bug report?
Exercise 6. How do you make an undeclared difference detectable?
Exercise 7. Which earlier chapters use the same record-the-intent move?
Where this fits
Part of the Tcl curriculum.
