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_annotate and 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");
ArgumentMeaning
sdf_filePath of the SDF file to read
module_instanceHierarchical instance that the paths in the SDF file are relative to; by default the module that calls the task
config_fileOptional file with extra annotation settings
log_fileOptional file in which the annotator lists what it annotated and what it could not
mtm_specWhich value of each min:typ:max triple to use: "MINIMUM", "TYPICAL", "MAXIMUM" or "TOOL_CONTROL"
scale_factorsFactors to multiply the min, typ and max values with, such as "1.0:1.0:1.2"
scale_typeWhich 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:

Output
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:

Output
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_annotate takes 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
Did you find what you were looking for?

Quiz

Test Your Knowledge

1 of 5 Score: 0 / 5