A gate-level netlist simulates with the default delays written in the specify blocks of its cell models. To simulate with the real delays of the chip, the timing calculated after layout has to be loaded from a Standard Delay Format (SDF) file into the simulation. The system task $sdf_annotate does exactly that, and this article shows how it works, how SDF entries are matched to the design, and how to check that the annotation succeeded.
10 min read | Beginner Level
What You'll Learn
- What SDF back-annotation is and when it is used
- How to call
$sdf_annotateand what each of its arguments does - How SDF delay and timing check entries are matched to specify paths and timing checks
- How to read the annotation log, and how SDF can update specparams
What is SDF Backannotation ?
Back-annotation is the process of loading timing data from an SDF file into a netlist during simulation. The data can include path delays, specparam values, timing check limits and interconnect delays. It is most important after synthesis and layout, when the simulation must reflect the real timing of the design rather than estimates.
During back-annotation, each cell instance in the netlist gets its delay values from the matching entry in the SDF file. The values are attached to the corresponding paths and timing checks of that instance, and they replace the default timing that the cell model had in its specify block.
$sdf_annotate
The system task $sdf_annotate performs the back-annotation. It tells the simulator which SDF file to read and to which part of the design hierarchy the data should be applied.
initial begin
$sdf_annotate("/path/to/timing_data.sdf", top_level_instance);
end
Only the first argument is required. The full list of arguments is:
$sdf_annotate ("sdf_file", module_instance, "config_file", "log_file",
"mtm_spec", "scale_factors", "scale_type");
| Argument | Meaning |
|---|---|
| sdf_file | Path of the SDF file to read |
| module_instance | Hierarchical instance that the paths in the SDF file are relative to; by default the module that calls the task |
| config_file | Optional file with extra annotation settings |
| log_file | Optional file in which the annotator lists what it annotated and what it could not |
| mtm_spec | Which value of each min:typ:max triple to use: "MINIMUM", "TYPICAL", "MAXIMUM" or "TOOL_CONTROL" |
| scale_factors | Factors to multiply the min, typ and max values with, such as "1.0:1.0:1.2" |
| scale_type | Which values the scale factors are applied to |
Arguments that are not needed can be left empty between commas, as in $sdf_annotate("top.sdf", tb.u_top, , "sdf.log", "MAXIMUM");. The call is placed in an initial block, so that the delays are in place at time 0, before the design starts switching.
Synthesis result: None. $sdf_annotate is a simulation-only system task used in gate-level testbenches; synthesis tools ignore it.
Quick Check
A testbench instantiates the netlist as chip u_chip();, and the SDF file was written for the design chip. Which instance should be passed to $sdf_annotate?
Show Answer
tb.u_chip, or simply u_chip from inside tb. The instance paths in the SDF file start below the design chip, so the annotation must be anchored at the instance of chip, not at the testbench.
SDF Annotator
An SDF annotator is the part of a simulator, or a separate tool, that reads SDF data and applies it to the Verilog design. It reports a warning for any data that it cannot annotate, for example an entry for an instance whose module has no specify block:
elab: *W, SBNFSDF: Attempt to annotate specify block data of instance tb.DUT.path_to_cell of module example, which has no specify block, line 56531>
An SDF file can also contain constructs that have no meaning for Verilog timing; the annotator ignores those silently. If the SDF file has no value for a path or check, the existing value from the Verilog specify block stays unchanged.
At the end of the annotation, the annotator prints statistics: the SDF file, the annotation scope, and for each kind of item, how many exist in the design and how many received a value:
Annotating SDF timing data:
Compiled SDF file: /path/to/timing_data.sdf
Backannotation scope: tb.DUT.path_to_module_inst
// Other info
SDF statistics:
No of Pathdelays = 12412 ... Annotated = 100.0%
Total Annotated
Path Delays 12412 12412
$period 113 0
$width 1214 0
$setup 63234 62412
$hold 63234 62412
In this example, all 12412 path delays were annotated, and about 98.7% of the setup and hold checks. The 822 setup and hold checks without values, and the $period and $width checks, keep the default limits of the cell models. Always check these statistics, and understand why any item was not annotated, before trusting the results of a gate-level simulation.
Annotation Checks in Signoff Flows
In a signoff gate-level simulation, an unannotated path is not a harmless warning: that cell runs with its default delay, and the simulation no longer shows the real chip. Regression scripts therefore parse the annotation statistics and fail the run if path delays or timing checks fall below an agreed percentage, or if any warning appears that has not been reviewed and waived.
SDF Contents
Timing values in an SDF file are written inside a CELL declaration, which can contain three kinds of sections:
- DELAY: propagation delays for specify paths, and interconnect delays
- TIMINGCHECK: limits for timing checks such as setup, hold and width
- LABEL: new values for specparams
(CELL
(CELLTYPE "a01_ce12v124b")
(INSTANCE u0_path/u1_to/u2_reg)
(DELAY
(ABSOLUTE
(COND en_clk==1'b1 (IOPATH clk_i clk (0.0151::0.0168) (0.0221::0.0235)))
...
)
)
(TIMINGCHECK
(WIDTH (COND some_signal==1'b1 (negedge clk)) (0.0211::0.0514))
(SETUPHOLD (posedge en_clk) (COND some_signal==1'b1 (posedge clk)) (0.0241::0.0255) (-0.0111::-0.0102))
...
)
)
Entries in the DELAY section, other than interconnect delays, are matched to specify paths with the same port names and the same condition. Entries in the TIMINGCHECK section are matched to timing checks of the same type, with the same ports and conditions: the WIDTH entry above updates a $width check on the falling edge of clk, and the SETUPHOLD entry updates a $setuphold check. A negative value, as in the hold limit here, is allowed and means that the data may change slightly before the clock edge.
The INSTANCE path tells the annotator exactly where in the design hierarchy the values belong, relative to the instance given to $sdf_annotate. Here, the values are applied only to the instance u0_path.u1_to.u2_reg.
Mapping of SDF Paths
An IOPATH entry is applied to the specify path between the same two ports. The values in the SDF file replace whatever delay the specify block had:
// SDF file: (IOPATH clk_i clk (0.0151::0.0168) (0.0221::0.0235)) // Verilog specify path: (clk_i => clk) = 0;
After annotation, the path from clk_i to clk no longer has a delay of 0: it rises in 0.0151 to 0.0168 time units and falls in 0.0221 to 0.0235, depending on the selected mtm_spec.
A conditional entry is only applied to a specify path between the same two ports with the same condition:
// SDF file: (COND en_clk==1'b1 (IOPATH clk_i clk (0.0151::0.0168) (0.0221::0.0235))) // Verilog Specify Paths: if (en_clk) (clk_i => clk) = 0;
If the cell model had only an unconditional path (clk_i => clk), this entry would find no match, and the annotator would report it as not annotated. The SDF file and the cell library models must therefore describe the same paths and conditions, which is normally guaranteed when both come from the same library release.
Quick Check
The SDF file contains (IOPATH A Y (0.3::0.4)) for an instance, but its cell model only has (B => Y) = 1;. What delay does the path from A to Y have during simulation?
Show Answer
None from the SDF file: the model has no specify path from A to Y, so the entry cannot be annotated and is reported in the log. The path from B keeps its default delay of 1, and changes on A propagate with no path delay at all.
SDF Annotation of specparams
The LABEL section updates the values of specparams. Every specify path delay or procedural expression that uses an annotated specparam is recalculated with the new value.
// SDF file:
(LABEL
(ABSOLUTE
(high_dc 30)
(low_dc 20)))
// Verilog file:
module my_des (input B, output Y, output reg signal);
specparam high_dc=0, low_dc=0;
specparam xyz=0;
buf (Y, B);
always begin
#high_dc signal = 1;
#low_dc signal = 0;
end
specify
(B => Y) = 0.2 * xyz + 1.0;
endspecify
endmodule
Without annotation, high_dc and low_dc are 0. After the LABEL section is applied, the always block waits 30 time units before setting signal to 1 and 20 before setting it to 0, so it generates a waveform with a period of 50. xyz is not in the LABEL section, so it keeps its value of 0, and the path from B to Y keeps its delay of 1.0. This mechanism lets one cell model use characterization values that are only known after layout.
Corner Simulations from One Netlist
Timing tools write one SDF file per corner, for example slow, typical and fast. The same gate-level netlist and testbench are simulated once per file, selecting the file and the mtm_spec through plusargs. Without any change to the netlist, the team checks setup behavior at the slow corner and hold behavior at the fast corner.
Common Beginner Mistakes
Mistake #1: Ignoring the annotation statistics
Wrong: Starting to debug a gate-level simulation without looking at the annotation log
Right: Check that path delays and timing checks are annotated as expected, and understand every warning
Why? Unannotated cells silently use default delays. The simulation then runs with a mix of real and default timing, and its results are not meaningful.
Mistake #2: Calling $sdf_annotate after time 0
Wrong: initial #100 $sdf_annotate("top.sdf", tb.u_top);
Right: initial $sdf_annotate("top.sdf", tb.u_top);
Why? Until the annotation runs, the design uses the default delays. The reset sequence and the first clock cycles, often where timing problems appear, are then simulated with the wrong timing.
Mistake #3: Mismatched conditions between SDF and cell models
Wrong: Using an SDF file generated with one library version together with cell models from another version
Right: Use the simulation models from the same library release that the timing tool used
Why? Conditional paths and timing checks only match when ports and conditions are identical. A changed condition in a newer library leaves those entries unannotated.
Mistake #4: Annotating at the wrong level of hierarchy
Wrong: $sdf_annotate("top.sdf"); called from the testbench, when the SDF file was written for the design top
Right: $sdf_annotate("top.sdf", tb.u_top);
Why? Without the second argument, the scope is the module that calls the task. The instance paths in the SDF file then start one level too high, and nothing matches.
Practice Exercise
Challenge: Annotate Two Corners
A testbench tb instantiates the netlist as soc u_soc();. Write an initial block that reads the SDF file name from the plusarg +sdf=<file> and the corner from +corner=MIN or +corner=MAX, and annotates the file with the minimum or maximum values, writing a log file sdf.log.
Hint
Read string plusargs into reg vectors with $value$plusargs("sdf=%s", ...). The mtm_spec argument must be "MINIMUM" or "MAXIMUM".
Solution
reg [8*256:1] sdf_file;
reg [8*8:1] corner;
initial begin
if (!$value$plusargs("sdf=%s", sdf_file)) begin
$display("ERROR: no +sdf= given");
$finish;
end
if (!$value$plusargs("corner=%s", corner))
corner = "MAX";
if (corner == "MIN")
$sdf_annotate(sdf_file, tb.u_soc, , "sdf.log", "MINIMUM");
else
$sdf_annotate(sdf_file, tb.u_soc, , "sdf.log", "MAXIMUM");
end
Running the simulation with +sdf=soc_ss.sdf +corner=MAX annotates the slow corner with maximum delays, and +sdf=soc_ff.sdf +corner=MIN the fast corner with minimum delays, without changing any code. The annotation still happens at time 0, because the block has no delays.
Summary
In this tutorial, you learned:
- Back-annotation loads delays, timing check limits and specparam values from an SDF file into a gate-level simulation
$sdf_annotatetakes the SDF file, the instance to annotate, and optional config, log, min:typ:max selection and scaling arguments- DELAY entries are matched to specify paths, and TIMINGCHECK entries to timing checks, by ports and conditions
- Values that cannot be matched are reported, and missing values leave the defaults of the cell model in place
- The annotation statistics must be checked before simulation results are trusted
- The LABEL section updates specparams, and every expression that uses them is recalculated