What do the lines in a timing constraints file actually say?
You hand your RTL to the back-end team, and they ask for one more file. You open the project's constraints file: four lines that read like orders for a tool you have never run. This lesson translates each line, then shows how to read the one headline the timing team cares about.
Your RTL says what happens on every clock edge, but never how far apart those edges sit. Synthesis and timing tools need that number in writing. The constraints file is that writing: a text file the front end hands over next to the RTL.
The format here is SDC, which means Synopsys Design Constraints: a text format that timing and synthesis tools read, one requirement per line. Each line names clocks or ports the design already has and states a number the tools must honor.
You will not run a timing tool in this course. Sign-off timing belongs to the STA course, which means static timing analysis, and its tool of choice, OpenSTA, is not installed here. So this lesson shows no tool output at all. Every number below is illustrative: the project's own file says so in its first comment, and the worked arithmetic uses example values that add up but describe no real chip.
The listing below is the complete constraints file of the example project. Read it top to bottom before the table translates it.
# Timing constraints for mini_controller. ILLUSTRATIVE: the 10 ns period and the delays are
# example values chosen for teaching, not a product requirement.
create_clock -name clk -period 10.0 [get_ports clk]
set_clock_uncertainty 0.2 [get_clocks clk]
set_input_delay -clock clk 2.0 [get_ports {rst_n event_valid clear_count}]
set_output_delay -clock clk 2.0 [get_ports {count[*]}]This listing is the whole file: four commands plus the comment that marks every number as an example for teaching.
Line | What it asks the tools to do |
|---|---|
| Defines the clock on port |
| Holds back 0.2 ns of every period as margin on that clock. |
| Says the three inputs may arrive up to 2.0 ns after the clock edge. |
| Says the count outputs must be stable 2.0 ns before the capturing edge. |
create_clock names the clock port clk and gives it a period of 10.0 ns. Every other line counts time against these edges, so a wrong period here poisons every requirement below it.
set_clock_uncertainty holds back 0.2 ns of every period as margin. A real clock reaches different registers a little early or late, so the tools plan as if each period were 0.2 ns shorter.
set_input_delay says the three inputs, reset, event valid and clear, may arrive up to 2.0 ns after the clock edge. The design must still meet timing with that handicap.
set_output_delay says the count outputs must sit stable 2.0 ns before the capturing edge. That head start belongs to the downstream block, so this line speaks for the neighbor, not for your own logic.
The file never makes any path faster. It states the target the tools and the designer share. When a path misses, the design changes or the target is renegotiated openly; the numbers are never edited to look friendly.
A timing report boils down to one headline per path: slack, which means required time minus arrival time. Arrival is when the signal reaches the end of the path; required is when it must be there for safe capture. Positive slack meets timing; negative fails.
The picture below draws one register-to-register path under this lesson's illustrative numbers. Look at the two edges first, then the arrival and required markers and the slack arrow.
It meets timing with 3.0 ns to spare. Slack is required minus arrival, 9.5 minus 6.5, and a positive answer means the capture edge still has room when the signal lands.
Here is the arithmetic, all illustrative. The period gives 10.0 ns. Uncertainty takes 0.2 ns and the capture register's setup takes 0.3 ns, so the signal must arrive by 10.0 minus 0.2 minus 0.3, which is 9.5 ns. It arrives at 6.5 ns. Slack is 9.5 minus 6.5, which is 3.0 ns: positive, so the path meets timing.
Now make the logic deeper without touching the clock: arrival moves to 10.1 ns while required stays 9.5 ns. Slack is 9.5 minus 10.1, which is minus 0.6 ns: the path fails, by 0.6 ns.
Never fix this by editing the file until the arithmetic looks friendly. That changes the target on paper and leaves the silicon missing timing. Change reality instead: shorten the path, or agree a slower clock and write that number down.
Believing the file makes the design faster. A tighter period in create_clock does not speed up logic; it only moves the required time earlier and turns passing paths into failing ones. The file states the target. The design still has to meet it.
Copying constraints from another block. The period, the margins and the port names describe one block and its neighbors. Pasted into a new block, the get_ports names match nothing and the delays describe someone else's interface. Write each file from its own clock and ports.
Shipping a file with no clock. Every delay in the file hangs off the clock the first line names. Without create_clock, the remaining lines name a clock that no line defines, so the file states no complete requirement. The clock line comes first and is never optional.
Rule: constraints state the timing you must meet; slack proves whether you met it.
Required time is unchanged at 9.5 ns: 10.0 minus 0.2 minus 0.3. Slack is 9.5 minus 9.8, which is minus 0.3 ns. Negative, so the path fails timing by 0.3 ns.
set_clock_uncertainty reserve margin for?The gap between the ideal clock on paper and the real one in silicon, which reaches different registers slightly early or late. The 0.2 ns line tells the tools to hold that slice back, so a path that only just fits the ideal clock still counts as failing.
First, the period still says 10.0 ns, so fine paths fail on paper. Second, the get_ports names list this block's ports, which the new block lacks, so the delay lines constrain nothing real.
An SDC file states the timing target in four kinds of lines: the clock, the margin, the input delays and the output delays.
Slack is required time minus arrival time: positive meets timing, negative fails it, and the number names the margin or the miss.
Constraints never speed up logic; when a path fails, the design or the agreed target changes, not the numbers in the file.