← Home Design Constraints (SDC)
15 Design Constraints (SDC)

Managing & Reusing Constraints

Timing constraints — clocks, generated clocks, I/O delays, exceptions, OCV and MCMM setup

Managing & Reusing Constraints

Constraints are not write-once files. A real chip has one set of timing rules that must follow the design from the first synthesis run all the way to sign-off. If the rules drift between steps, the chip you tape out is not the chip you analyzed. This chapter explains how teams keep one trusted set of constraints, how they split work between blocks and the top level, how they budget the timing at block boundaries, and how they keep everything under version control.

One Golden SDC for the Whole Flow

The flow that builds a chip has many steps. Logic synthesis turns code into gates. Placement decides where each gate sits. Routing draws the wires. Static timing analysis (STA, the math that checks every path meets its clock) runs at several points. Each of these steps reads timing constraints. The safest practice is one "golden" SDC. This is the single source of truth. Every step reads the same file, or a file generated from it by a known script. You do not hand-edit a copy for placement and a different copy for routing. When the numbers differ between steps, you can no longer trust any of them. A golden SDC has a few habits that keep it clean:

  • It is plain text and readable. A reviewer can scan it.
  • It avoids tool-only shortcuts that other steps cannot parse.
  • It is parameterized. Clock periods and delays come from variables, not scattered magic numbers.
  • It is checked in to version control next to the design code.
Technical diagram

When a constraint must change, you change the golden file once. Then every step that re-reads it sees the new value. This is the whole point: a single edit propagates everywhere instead of being copied by hand into five places where four of them will be forgotten.

Block-Level vs Top-Level Constraints

Big chips are built from blocks. A block is a self-contained piece of logic that is constrained, synthesized, and timed on its own. The top level is the full chip that stitches blocks together. Both levels need constraints, but they are not the same constraints.

AspectBlock-level SDCTop-level SDC
ClocksOften defined locally at the block clock portDefined at the true source, then propagated into blocks
I/O delaysBudgeted estimates at the blockReal delays from neighboring logic

boundary

False/multicycle Only paths inside the block Cross-block paths plus inside-block paths

Scope One block's pins and cells Entire chip hierarchy one flat blob early in the project. Teams cut it into blocks, give each block its own budget, and let separate engineers work in parallel. Each block must meet its own constraints before it is trusted at the top. The danger is that the block's local view of the world disagrees with the top-level reality. A block might assume its input arrives 0.45 ns after the clock edge. The top level might actually deliver it 0.78 ns after the edge. If nobody reconciles those numbers, the block passes alone and fails when assembled.

Budgeting Block I/O Delays

Budgeting is how you split a chip-level timing path that crosses a block boundary into pieces each block can be timed against. The path from a flip-flop in block A, through the wires between blocks, to a flip-flop in block B must fit in one clock period. You divide that period into shares. A simple budgeting story. Say the clock period is 2.50 ns. A path leaves block A, crosses the top level, and enters block B. You decide:

  • Block A internal logic gets 0.90 ns to produce its output.
  • The wire and any glue between blocks gets 0.40 ns.
  • Block B internal logic gets the remaining 1.20 ns to capture. Now you turn those shares into constraints each block can use. For block A, the output must be ready early enough, so you set an output delay describing how much of the period the downstream needs. For block B, the input arrives late, so you set an input delay describing how much of the period was already spent upstream. # standard SDC — portable across compliant tools # Block A: downstream (wire + block B) needs 0.40 + 1.20 = 1.60 ns of the period create_clock -name clk -period 2.50 [get_ports clk] set_output_delay -clock clk -max 1.60 [get_ports dataA_out] # Block B: upstream (block A + wire) already used 0.90 + 0.40 = 1.30 ns set_input_delay -clock clk -max 1.30 [get_ports dataB_in] The two budgets must add up. Block A's internal share (0.90) plus the wire (0.40) plus block B's internal share (1.20) equals 2.50, the full period. If the shares sum to more than the period, no real chip can ever meet them. Budgeting is bookkeeping: every nanosecond of the period is assigned to exactly one owner.
Technical diagram

Good budgets start as estimates and get refined. Early in the project nobody knows the real wire delays. You guess, you give each block a fair share, and you tighten the numbers as the floorplan and

routing become real. The output-delay number on block A and the input-delay number on block B are two views of the same boundary, so they must always be edited together.

Keeping Constraints Consistent

Consistency means the same intent is described the same way everywhere. Three rules help. First, name things once. If a clock is called core_clk at the top, do not call it clk_core in a block. Mismatched names break path matching and silently drop exceptions. Second, derive, do not duplicate. If a divided-by-two clock exists, create it with a generated clock from its source rather than declaring a fresh independent clock. A generated clock automatically tracks the source. Two independent declarations drift apart the moment someone edits one. Third, centralize shared values. Put the clock period in one variable used by every clock that depends on it.

# standard SDC — portable across compliant tools
set CORE_PERIOD 2.50
create_clock -name core_clk -period $CORE_PERIOD [get_ports core_clk]
create_generated_clock -name core_clk_div2 \
-source [get_ports core_clk] -divide_by 2 [get_pins div_reg/Q]
InconsistencyWhat goes wrongFix
Clock named differently per blockExceptions miss their targetSingle naming scheme
Technical diagram

Constraints are source code. They deserve the same discipline as the design files. Keep the golden SDC in the same repository as the design. Every commit message should say what changed and why: "relaxed core_clk to 2.55 ns to close timing in block B." When sign-off timing changes between two runs, the version history tells you which constraint edit caused it. Without history, you are guessing. Partitioning is splitting both the design and its constraints into manageable, reusable pieces. A wellpartitioned constraint set has a shared file for things common to the whole chip (the main clock, global false paths) and per-block files for things local to each block. The top-level file sources the shared file and adds the cross-block rules.

FileHoldsRead by
common.sdcMain clocks, global exceptionsEvery step, every block
Technical diagram

A worked partition example. A team has a chip with two blocks sharing a 2.50 ns clock. The clock lives in common.sdc so both blocks and the top see the identical period. Block A's output budget of 1.60 ns lives in block_a.sdc . Block B's matching input budget of 1.30 ns lives in block_b.sdc . When the team later tightens the clock to 2.40 ns, they edit one line in common.sdc . Both blocks and the top pick up the change on their next run. The boundary budgets are then revisited together because the shrinking period changes every share. This structure is what makes constraints reusable. A block that has been carefully constrained and closed can be dropped into the next chip with its block_x.sdc intact, as long as the new chip honors the same boundary budget. Reuse is only safe when the constraints travel with the block and the budgets still add up.

Interview Q&A

Q
What is a "golden" SDC and why does it matter? It is the single trusted set of constraints that

every flow step reads, so synthesis, placement, routing, and STA all judge the design against identical rules. It matters because if different steps use different constraints, the chip you tape out is not the chip you analyzed. One edit to the golden file propagates everywhere automatically.

Q
How do block-level and top-level constraints differ? Block-level constraints cover one block's

pins, internal paths, and budgeted I/O delays, often with a locally defined clock. Top-level constraints cover the whole chip, define clocks at their true source, use real I/O delays, and add cross-block exceptions. The block view is an estimate that must be reconciled with top-level reality.

Q
What does it mean to budget block I/O delays? You take a clock period that a cross-block path

must fit in, then split it into shares: the source block's internal time, the wire between blocks, and the destination block's internal time. Each share becomes an input or output delay. The shares must sum to the full period or no real chip can meet them.

Q
If the clock is 2.50 ns and you give block A 0.90 ns internal and the wire 0.40 ns, what input

delay does block B see? Block B's input delay is 0.90 + 0.40 = 1.30 ns, the time already consumed upstream. That leaves block B 1.20 ns of internal time, and all three shares add to 2.50 ns. The output delay on block A and the input delay on block B describe the same boundary, so they must always match.

Q
Why prefer a generated clock over a second independent clock for a divided clock? A

generated clock is derived from its source, so when the source period changes the divided clock tracks it automatically. Two independent declarations drift apart the instant someone edits one and forgets the other. Deriving instead of duplicating keeps the constraint intent consistent.

Q
Why keep constraints under version control with the design? Constraints are source code

that directly determines sign-off results. When timing changes between runs, the commit history shows which constraint edit caused it. Without history you cannot tell whether a regression came from the design or from a quietly changed number.

Key Takeaways

  • Keep one golden SDC that every flow step reads, so all steps judge the design against identical rules.
  • Block and top constraints differ: blocks use budgeted estimates, the top uses real source clocks and real delays.
  • Budgeting splits one clock period into source, wire, and destination shares that must sum to the full period.
  • Derive, do not duplicate: use generated clocks and central variables so one edit propagates everywhere.
  • Version-control constraints with the design and partition them into shared and per-block files for safe reuse.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

Replying to