Skip to content

Instantly share code, notes, and snippets.

@brabect1
Last active July 6, 2025 14:41
Show Gist options
  • Save brabect1/7d76f02f75a8ad88d76f7827400c9e42 to your computer and use it in GitHub Desktop.
Save brabect1/7d76f02f75a8ad88d76f7827400c9e42 to your computer and use it in GitHub Desktop.
SDF delay annotation #sdf #sta #sim

SDF Delay Annotation

SDF (Standard Delay Format) is a text format for storing time delays across elements of a (digital) circuit. The collection of these delays then represents the timing of the circuit. SDF is primarily an interchange format to communicate circuit timing among EDA tools, with STA tools being the typical producers and (digital) simulators being the typical consumers.

sdf_annotation_process.png

SDF syntax and semantics follows the same principles as the other formats for modeling delay aspects of (digital) IP cells (incl. standard gates). That is, like Liberty timing models and Verilog gate/cell models, SDF represents the delays at the cell level, either as wire delays between cells or as (propagation) delays from cell inputs to cell outputs.

From the many elements that SDF can describe, these are the key ones:

  • Wire delays with the INTERCONNECT construct.
  • Propagation delays with the IOPATH construct.
  • (Cell) timing constraints with variety of constructs, SETUPHOLD, RECREM, WIDTH, etc.

TODO: ... SDF consistency with design data ... SDF consistency with

IEEE Std 1800-2012:

SDF files contain timing values for specify path delays, specparam values, timing check constraints, and interconnect delays.

SDF Syntax

Example from SDF 3.0 std.:

(DELAYFILE
(SDFVERSION "3.0")
(DESIGN "BIGCHIP")
(DATE "March 12, 1995 09:46")
(VENDOR "Southwestern ASIC")
(PROGRAM "Fast program")
(VERSION "1.2a")
(DIVIDER /)
(VOLTAGE 5.5:5.0:4.5)
(PROCESS "best:nom:worst")
(TEMPERATURE -40:25:125)
(TIMESCALE 100 ps)
(CELL
 (CELLTYPE "BIGCHIP")
 (INSTANCE top)
 (DELAY
  (ABSOLUTE
   (INTERCONNECT mck b/c/clk (.6:.7:.9))
   (INTERCONNECT d[0] b/c/d (.4:.5:.6))
  )
 )
)
(CELL
 (CELLTYPE "AND2")
 (INSTANCE top/b/d)
 (DELAY
  (ABSOLUTE
   (IOPATH a y (1.5:2.5:3.4) (2.5:3.6:4.7))
   (IOPATH b y (1.4:2.3:3.2) (2.3:3.4:4.3))
  )
 )
)
(CELL
 (CELLTYPE "DFF")
 (INSTANCE top/b/c)
 (DELAY
  (ABSOLUTE
   (IOPATH (posedge clk) q (2:3:4) (5:6:7))
   (PORT clr (2:3:4) (5:6:7))
  )
 )
 (TIMINGCHECK
  (SETUPHOLD d (posedge clk) (3:4:5) (-1:-1:-1))
  (WIDTH clk (4.4:7.5:11.3))
 )
)
)

Annotating from within Sim

Using $sdf_annotate(<file_path>, <inst_path>, , , "<delay_type>");, where <delay_type> is one of maximum, minimum and typical.

Questa example:

( mkdir -p questa && cd questa && \
  (test -d work || vlib work) && \
  vlog -work work ../myip.v ../stdlib.v && \
  vlog -work work ../top.v && \
  vlog -work work -sv ../tb.sv && \
  vsim -voptargs=+acc \
    -L work work.tb \
    +SDF_PATH=../top.sdf \
    -do "run -all; quit;" \
    -c \
)

Annotating through Simulator Options

Questa example:

( mkdir -p questa && cd questa && \
  (test -d work || vlib work) && \
  vlog -work work ../myip.v ../stdlib.v && \
  vlog -work work ../top.v && \
  vlog -work work -sv ../tb.sv && \
  vsim -voptargs=+acc \
    -L work work.tb \
    -sdfmax dut=../top.sdf \
    +sdf_verbose \
    -sdfannotatepercentage \
    -do "run -all; quit;" \
    -c \
)

Exporting SDF from STA Tool

PrimeTime script example:

set link_path [list myip.lib stdlib.lib]
read_verilog top.v
link

if {[file exists constraints.sdc]} {
    source constraints.sdc
}

write_sdf \
   -context verilog \
   -no_edge \
   -version 3.0 \
   -exclude {checkpins} \
   -include { SETUPHOLD RECREM } \
   "[get_object_name [current_design]].export.sdf"

Correlation between Model Elements

pin(Y) {
  timing () {                                                                              specify
    related_pin: "A" ;                                                                       specparam tdlh = 1.3;
    cell_fall(scalar) { values("1.7"); }             ((IOPATH A Y (1.3)(1.7))                specparam tdhl = 1.7;
    cell_rise(scalar) { values("1.3"); }                                                     (A => Y) = (tdlh, tdhl);
  }                                                                                        endspecify


pin(Y) {
  timing () {
    related_pin: "A" ;
    when: "B & !C";                                                                        specify
    sdf_cond: "B==1'b1 && C==1'b0";                                                          specparam tdlh = 1.3;
    cell_fall(scalar) { values("1.7"); }             (COND (B==1'b1 && C==1'b0               specparam tdhl = 1.7;
    cell_rise(scalar) { values("1.3"); }                  ((IOPATH A Y (1.3)(1.7))           if (B==1'b1 && C==1'b0) (A => Y) = (tdlh, tdhl);
  }                                                   )                                    endspecify


pin(D) {
  direction: input;
  capacitance: 0.001;                                                                      reg ntfr;
        timing() {                                                                         specify
    related_pin: "CK";                               (SETUPHOLD (posedge D)                  specparam tsr = 0.3;
    timing_type: hold_rising;                          (posedge CK) (0.3) (0.7)              specparam thr = 0.7;
    rise_constraint(scalar) { values("0.3"); }       )                                       specparam tsf = 0.2;
    fall_constraint(scalar) { values("0.2"); }       (SETUPHOLD (negedge D)                  specparam thf = 0.8;
  }                                                    (posedge CK) (0.2) (0.8)              $setuphold (posedge CK, posedge D, tsr, thr, ntfr);
  timing() {                                         )                                       $setuphold (posedge CK, negedge D, tsf, thf, ntfr);
    related_pin: "CK";                                                                     endspecify
    timing_type: setup_rising;
    rise_constraint(scalar) { values("0.7"); }
    fall_constraint(scalar) { values("0.8"); }
  }
}

Observations

  • Single SDF is typically bound to a specific PVT and RC combination.
  • Multiple SDF files can be annotated to the same design element/module.
  • SDF may act as an input to STA tools for its delays being annotated to timing arcs.

References

https://web.archive.org/web/20190215003139/https://www2.ece.ohio-state.edu/~bibyk/ee683/BolinM_part2_timing.pdf

/*
* Copyright 2025 Tomas Brabec
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
library(myip) {
/* general attributes */
technology (cmos);
delay_model: table_lookup;
/* units attributes*/
time_unit: "1ns";
voltage_unit: "1V";
current_unit: "1mA";
pulling_resistance_unit: "1ohm";
leakage_power_unit: "1nW";
capacitive_load_unit (1,pf);
/* thresholds */
slew_upper_threshold_pct_rise: 80;
slew_lower_threshold_pct_rise: 20;
slew_upper_threshold_pct_fall: 80;
slew_lower_threshold_pct_fall: 20;
input_threshold_pct_rise: 50;
input_threshold_pct_fall: 50;
output_threshold_pct_rise: 50;
output_threshold_pct_fall: 50;
/* process attributes */
nom_process: 1.0;
nom_voltage: 1.5;
nom_temperature: 25.0;
operating_conditions (tc_1p5v_25c) {
process: 1;
voltage: 1.5;
temperature: 25;
}
default_operating_conditions : tc_1p5v_25c;
/* default attributes */
default_input_pin_cap: 1.0;
default_inout_pin_cap: 1.0;
default_output_pin_cap: 1.0;
default_fanout_load: 1.0;
default_max_transition: 1.0;
default_cell_leakage_power: 0.0;
default_leakage_power_density: 0.0;
/* declare user attributes */
define(CELL_DESCR,cell,string);
/* ---------------- *
* myip
* ---------------- */
cell(myip) {
CELL_DESCR: "Custom macro cell.";
area: 200.0;
interface_timing: true;
cell_leakage_power: 1.0;
pin(A) {
direction: input;
capacitance: 0.001;
}
pin(B) {
direction: input;
capacitance: 0.001;
}
pin(C) {
direction: input;
capacitance: 0.001;
}
pin(Y) {
direction: output;
max_capacitance: 0.05;
timing () {
related_pin : "A" ;
timing_type : combinational ;
timing_sense : positive_unate ;
cell_fall(scalar) { values("2.0"); }
cell_rise(scalar) { values("2.0"); }
fall_transition(scalar) { values("0.25"); }
rise_transition(scalar) { values("0.25"); }
}
timing () {
related_pin : "B" ;
timing_type : combinational ;
timing_sense : positive_unate ;
when: "C";
sdf_cond: "C==1'b1";
cell_fall(scalar) { values("3.0"); }
cell_rise(scalar) { values("3.0"); }
fall_transition(scalar) { values("0.25"); }
rise_transition(scalar) { values("0.25"); }
}
}
}
}
/*
* Copyright 2025 Tomas Brabec
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`timescale 1ns/1ps
module myip(A, B, C, Y);
input A, B, C;
output Y;
reg Y;
reg n1;
always @(*) #0.5 n1 = A ^ B;
always @(*) #0.5 Y = C ^ n1;
specify
specparam td_a2y_hl = 1.0;
specparam td_a2y_lh = 1.0;
specparam td_b2y_hl = 1.0;
specparam td_b2y_lh = 1.0;
specparam td_c2y = 1.0;
(A *> Y) = (td_a2y_hl, td_a2y_lh);
if (C==1'b1) (B *> Y) = (td_b2y_hl, td_b2y_lh);
(C *> Y) = (td_c2y, td_c2y);
endspecify
endmodule
/*
* Copyright 2025 Tomas Brabec
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/* copied and edited from https://github.com/brabect1/sta_basics_course/blob/master/src/prime_time/sample_lib1.lib */
library(stdlib) {
/* general attributes */
technology (cmos);
delay_model: table_lookup;
/* units attributes*/
time_unit: "1ns";
voltage_unit: "1V";
current_unit: "1mA";
pulling_resistance_unit: "1ohm";
leakage_power_unit: "1nW";
capacitive_load_unit (1,pf);
/* thresholds */
slew_upper_threshold_pct_rise: 80;
slew_lower_threshold_pct_rise: 20;
slew_upper_threshold_pct_fall: 80;
slew_lower_threshold_pct_fall: 20;
input_threshold_pct_rise: 50;
input_threshold_pct_fall: 50;
output_threshold_pct_rise: 50;
output_threshold_pct_fall: 50;
/* process attributes */
nom_process: 1.0;
nom_voltage: 1.5;
nom_temperature: 25.0;
operating_conditions (tc_1p5v_25c) {
process: 1;
voltage: 1.5;
temperature: 25;
}
default_operating_conditions : tc_1p5v_25c;
/* default attributes */
default_input_pin_cap: 1.0;
default_inout_pin_cap: 1.0;
default_output_pin_cap: 1.0;
default_fanout_load: 1.0;
default_max_transition: 1.0;
default_cell_leakage_power: 0.0;
default_leakage_power_density: 0.0;
/* declare user attributes */
define(CELL_DESCR,cell,string);
/* ---------------- *
* Buffer (x1 drive strength)
* ---------------- */
cell(bufx1) {
CELL_DESCR: "Non-inverting x1 buffer.";
area: 1.2;
cell_leakage_power: 0.1;
pin(A) {
direction: input;
capacitance: 0.001;
}
pin(Y) {
direction: output;
max_capacitance: 0.05;
function: "A";
timing () {
related_pin : "A" ;
timing_type : combinational ;
timing_sense : positive_unate ;
cell_fall(scalar) { values("0.0"); }
cell_rise(scalar) { values("0.0"); }
fall_transition(scalar) { values("0.3"); }
rise_transition(scalar) { values("0.3"); }
}
}
}
}
/*
* Copyright 2025 Tomas Brabec
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`timescale 1ns/1ps
module bufx1(A, Y);
input A;
output Y;
buf b(Y, A);
specify
(A => Y) = (0, 0);
endspecify
endmodule
/*
* Copyright 2025 Tomas Brabec
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
`timescale 1ns/1ps
module tb;
logic A, B, C, Y;
top dut( .A, .B, .C, .Y );
initial begin: test
$timeformat(-9, 5, " ns", 10);
$display("%t: Stimulus started ...", $realtime);
A = 0;
B = 0;
C = 0;
#10ns;
A = 1;
#10ns;
C = 1;
#10ns;
A = 0;
#10ns;
B = 0;
#10ns;
$display("%t: Stimulus finished.", $realtime);
$stop;
end:test
initial begin
string sdf_file_path;
int fd;
if ($value$plusargs("SDF_PATH=%s",sdf_file_path)) begin
fd = $fopen (sdf_file_path, "r");
if (fd) begin
$sdf_annotate(sdf_file_path, tb.dut, , , "MAXIMUM");
end
$fclose(fd);
end
end
always @(*) $display("%t: A = %b", $realtime, A);
always @(*) $display("%t: B = %b", $realtime, B);
always @(*) $display("%t: C = %b", $realtime, C);
always @(*) $display("%t: Y = %b", $realtime, Y);
endmodule
/*
* Copyright 2025 Tomas Brabec
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
module top(A, B, C, Y);
input A, B, C;
output Y;
wire n1;
myip u_ip( .A(A), .B(B), .C(C), .Y(n1) );
bufx1 g1( .A(n1), .Y(Y) );
endmodule
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment