Skip to content

SystemVerilog · Module 17

Specify Blocks & Path Delays

SystemVerilog specify blocks — model real pin-to-pin propagation delays and timing checks for gate-level simulation. Simple/full/edge-sensitive path forms, specparam vs parameter, the system timing checks ($setup, $hold, $setuphold, $width, $period, $recovery, $removal), SDF back-annotation, and the full GLS flow with min/typ/max corners.

Module 17 · Page 17.4

RTL simulation is zero-delay: assign y = a & b; makes y change the instant a or b does. Real silicon does not work that way — every gate has a pin-to-pin propagation delay, and every flip-flop has setup/hold requirements. The specify block is how a Verilog/SystemVerilog model carries that timing: it declares path delays (how long a transition takes to travel from an input pin to an output pin) and timing checks ($setup, $hold, …) that flag violations during simulation. Its values are named with specparam, which a Standard Delay Format (SDF) file from place-and-route can override at runtime — and that mechanism is the backbone of gate-level simulation (GLS), where the post-layout netlist runs with the chip's real delays. This lesson covers the three path-delay forms, specparam, the full timing-check set, and the SDF/GLS flow.

1. Engineering Problem — Zero-Delay RTL Hides Real Timing

Functionally-correct RTL can still fail on silicon because of timing. A combinational cone that is too deep does not meet the clock period; a data path that arrives too close to the clock edge violates setup; a fast path that arrives too early violates hold. None of this is visible in zero-delay RTL simulation, where every signal settles instantly.

You need a model that carries real delays so the simulator can show the truth: y changing 45 ps after its input, a flip-flop's Q arriving 340 ps after the clock edge, a register sampling stale data because setup was missed. That model is the specify block. Cell-library vendors ship it inside every standard-cell model (AND2X1, DFFX1, …); the place-and-route tool measures the actual post-layout delays and emits them as SDF; the simulator back-annotates the SDF onto the cells and runs gate-level simulation with the chip's true timing. Setup/hold violations then surface as X on the output — the same X that becomes a real functional failure on silicon.

2. Mental Model — Timing Layered Over Zero-Delay Function

The picture every engineer carries:

A specify block adds a timing skin over a module's zero-delay function. The logic (and (Y,A,B) or assign) still computes what the output is; the specify block declares when it gets there — a pin-to-pin path delay for each arc — plus timing checks that watch the relationship between signals and fire on a violation. Delay values are named with specparam, and unlike a parameter, a specparam can be overridden at simulation runtime by an SDF file without recompiling. That single property is the whole reason specify exists: it lets one netlist run with min, typical, or max post-layout delays selected at the command line.

Four invariants this picture preserves:

  • specify is module-scope and simulation-only. It sits beside always/assign, never inside them, and synthesis ignores it entirely — it is a timing model, not logic.
  • Paths are pin-to-pin (port-to-port). A path delay connects module ports, never internal wires.
  • specparam is the SDF hook. Timing constants must be specparam (not parameter) for SDF back-annotation to reach them.
  • Timing checks need real delays to mean anything. $setup/$hold on a zero-delay netlist never fire; they earn their keep in GLS with SDF-annotated delays, where the static counterpart is STA (static timing analysis).

3. Visual Explanation — Pin-to-Pin Path Delays

The functional and still decides Y's value; the specify block puts a measured delay on each input-to-output arc.

Inputs A and B drive output Y through a 2-input AND gate; the A-to-Y arc carries a 42/38 rise/fall delay and the B-to-Y arc a 45/40 delay.(A => Y) = (42,38)(B => Y) = (45,40)A (input pin)Y = A & B (outputpin)B (input pin)12
Figure 1 — path delays are pin-to-pin arcs. The gate's function sets Y's value; the specify block sets how long each input takes to reach Y, as (rise, fall) delays. Synthesis ignores this; gate-level simulation uses it.

The payoff is concrete: in RTL, assign Y = A & B makes Y change the moment B does; with the specify arc (B => Y) = (45, 40), Y's rise lands 45 time units after B rises. GLS adds exactly this realism so paths that miss the target frequency become visible.

4. The Three Path-Delay Forms

4.1 Simple (parallel) path — in => out

Connects sources to destinations 1-to-1 by position. The delay value can be 1, 2, 3, or 6 numbers depending on how much transition detail you model.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
specify
    (in_a => out_y) = 5;                    // one value: rise = fall = z
    (in_a => out_y) = (10, 8);              // two: (rise, fall) — most common
    (in_a => out_y) = (10, 8, 9);           // three: (rise, fall, z-transition)
    (in_a => out_y) = (10, 8, 9, 7, 9, 7);  // six: (01,10,0z,z1,1z,z0)
    (in_a, in_b => out_y, out_z) = 10;      // paired 1:1 — a→y, b→z
endspecify

4.2 Full path — in *> out

The *> operator connects every source to every destination (a cross-product) — one line instead of one per input when several inputs share a delay to the same output.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module mux4 (input logic a, b, c, d, sel0, sel1, output logic y);
    assign y = sel1 ? (sel0 ? d : c) : (sel0 ? b : a);
    specify
        (a, b, c, d *> y) = 12;   // all data inputs → y, same 12-unit delay
        (sel0, sel1 *> y) = 15;   // select inputs → y, slightly longer
    endspecify
endmodule

4.3 Edge-sensitive path — for flip-flops

A clock edge triggers the output transition. (posedge clk => (q : d)) = delay reads "on posedge clk, output q takes the value of d after delay" — exactly the clk-to-Q propagation of a flop.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
module dff (input logic clk, rst_n, d, output logic q, qn);
    always_ff @(posedge clk or negedge rst_n)
        if (!rst_n) q <= 1'b0;
        else        q <= d;
    assign qn = ~q;
 
    specify
        specparam tCQR = 7,   // clk-to-q rising
                  tCQF = 6,   // clk-to-q falling
                  tPCQ = 8;   // async clear-to-q
 
        (posedge clk   => (q  : d))   = (tCQR, tCQF);  // clk-to-Q
        (posedge clk   => (qn : d))   = (tCQF, tCQR);  // qn is the complement
        (negedge rst_n => (q  : 1'b0)) = tPCQ;          // async reset clears q
 
        $setup(d, posedge clk, 5);   // timing checks — §6
        $hold (posedge clk, d, 3);
    endspecify
endmodule

5. specparam — Timing Parameters the SDF Can Override

specparam is the timing-specific cousin of parameter: it names delay values so you write tRISE instead of a bare 10. The decisive difference — specparam values can be overridden at runtime by an SDF file without recompiling, which is how post-layout timing is injected into GLS.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
specify
    specparam tRISE = 10, tFALL = 8, tSETUP = 5, tHOLD = 3;
 
    (in_a => out_y) = (tRISE, tFALL);      // named delays in a path
    $setup(d, posedge clk, tSETUP);        // named delays in a check
    $hold (posedge clk, d, tHOLD);
endspecify
parameterspecparam
PurposeDesign structure — widths, depthsTiming — delays, setup/hold limits
Overridden by#( ) at instantiationSDF file at runtime (no recompile)
ScopeModuleInside (or at module scope for) specify

6. System Timing Checks

System timing checks are special system tasks inside a specify block that enforce temporal relationships between signals and report a violation during simulation. The canonical pair is setup (data stable before the clock edge) and hold (data stable after it); a violation models metastability and drives the output to X.

TaskChecksSyntax
$setupdata stable before the reference edge by ≥ limit$setup(data_event, ref_event, limit)
$holddata stable after the reference edge for ≥ limit$hold(ref_event, data_event, limit)
$setupholdboth, in one statement$setuphold(ref_event, data_event, t_su, t_hold)
$widthpulse stays high/low ≥ limit$width(event, limit)
$periodclock period ≥ limit$period(ref_event, limit)
$recoveryasync-reset release ≥ limit before next clock edge$recovery(ref_event, data_event, limit)
$removalasync reset held ≥ limit after clock edge$removal(ref_event, data_event, limit)
$skewedge-to-edge skew ≤ limit$skew(ref_event, data_event, limit)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
specify
    specparam tSETUP = 5, tHOLD = 3, tWIDTH = 10, tPERIOD = 20, tRECOV = 4, tREMOV = 2;
 
    $setup(d, posedge clk, tSETUP);          // d stable tSETUP before posedge clk
    $hold (posedge clk, d, tHOLD);           // d stable tHOLD after  posedge clk
    $setuphold(posedge clk, d, tSETUP, tHOLD);
 
    $width (posedge clk, tWIDTH);            // clk-high pulse width
    $period(posedge clk, tPERIOD);           // clk period
 
    $recovery(posedge rst_n, posedge clk, tRECOV);  // async-reset recovery
    $removal (posedge rst_n, posedge clk, tREMOV);  // async-reset removal
endspecify
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
$ vcs -v2k -sdf max:top:top.sdf top_netlist.v tb_top.v -o sim_gls && ./sim_gls
SDF annotation complete (2847 instances, 12341 arcs)
SETUP VIOLATION on d in dff (top.u_core.u_reg_A)
   At time 4250ns  Setup time: 5ns  Actual: 3ns  → output q set to X (metastability)
Total timing violations: 3   →   PASS (functional) / FAIL (timing)

7. SDF Back-Annotation — The Gate-Level Simulation Flow

SDF (Standard Delay Format) is a text file emitted by place-and-route containing the actual post-layout delays for every cell and interconnect. Back-annotation loads it into the simulator, overriding the specparam values in the cell models with real numbers.

The flow is three steps: (1) synthesis + place-and-route map RTL to cells, route wires, and compute real delays → gate-level netlist + SDF; (2) the simulator loads the SDF and netlist, overriding every cell's specparam at the named hierarchy; (3) GLS runs with real timing, and setup/hold violations appear as X on outputs.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
(DELAYFILE
  (SDFVERSION "3.0") (DESIGN "top") (TIMESCALE 1ps)
  (CELL
    (CELLTYPE "DFFX1")
    (INSTANCE top.u_core.u_reg_A)
    (DELAY (ABSOLUTE
      (IOPATH CLK Q (312:340:370) (298:325:355)))   // (min:typ:max) rise / fall
    )
    (TIMINGCHECK
      (SETUP D (posedge CLK) (85:95:110))            // min:typ:max
      (HOLD  (posedge CLK) D (40:45:52)))
  )
)
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# VCS — back-annotate with the max corner
vcs -v2k -negdelay -timescale=1ns/1ps -sdf max:top:top.sdf \
    top_netlist.v prim_lib.v tb_top.v -o sim_gls
./sim_gls +notimingchecks   # functional GLS — path delays only, no setup/hold
./sim_gls                   # full GLS — includes timing-check violations
 
# Questa
vsim -sdfmax /top=top.sdf top
# Xcelium
xrun -v2k -negdelay -sdf_file top.sdf top_netlist.v prim_lib.v tb_top.v

8. Full Working Example — Standard-Cell AND Gate with Timing

The shape of a real standard-cell model: zero-delay function plus a specify block of specparams and path delays.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
// AND2X1 — the kind of model a cell library (TSMC, GF, …) ships
module AND2X1 (input logic A, B, output logic Y);
    and (Y, A, B);   // gate primitive — the zero-delay function
 
    specify
        // Named delays — overridden by SDF at runtime (ps in a real library)
        specparam A_Y_RISE = 42, A_Y_FALL = 38,
                  B_Y_RISE = 45, B_Y_FALL = 40;
 
        (A => Y) = (A_Y_RISE, A_Y_FALL);   // pin-to-pin arcs
        (B => Y) = (B_Y_RISE, B_Y_FALL);
        // No timing checks — $setup/$hold apply only to sequential cells
    endspecify
endmodule
 
module tb_and;
    logic a, b, y;
    AND2X1 u_and (.A(a), .B(b), .Y(y));
    initial begin
        a = 0; b = 0;
        #10 a = 1;            // Y stays 0 (b still 0)
        #10 b = 1;            // at t=20 both are 1, but Y not yet risen
        #50 $display("t=%0t  A=%b B=%b Y=%b", $time, a, b, y);
    end
endmodule
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
t=0   A=0 B=0 Y=0
t=10  A=1 B=0 Y=0   ← Y stays 0 (b still 0)
t=20  A=1 B=1 Y=0   ← delay not elapsed yet
t=65  A=1 B=1 Y=1   ← Y rises at t=20+45 (B→Y rise delay = 45)

9. Industry Usage — Where Specify Blocks Live

  • Standard-cell libraries. Every cell model (AND2X1, DFFX1, MUX2X1, …) from TSMC, GlobalFoundries, Samsung, etc. ships with a specify block; the specparams are placeholders the SDF overwrites.
  • Gate-level simulation (GLS) sign-off. Post-layout netlist + SDF is simulated to confirm the design still functions and meets timing after place-and-route — catching X-propagation and reset/clock issues that pure STA can miss.
  • The STA relationship. Static timing analysis is the static counterpart — it checks every path's setup/hold against constraints without simulation. specify timing checks are the dynamic counterpart, firing on the specific vectors GLS exercises. Real flows use both: STA for exhaustive coverage, GLS for X/reset/async behaviour.
  • ASIC bring-up. $recovery/$removal checks on async reset release are a frequent source of real silicon bugs, and GLS is where they first show up.

Specify blocks are simulation-only — synthesis ignores them. They model timing; they never become gates.

10. Debugging Guide — The Mistakes Everyone Makes Once

specify blocks — bugs every engineer hits the first time

1. Putting specify inside a procedural block

Symptom: Syntax error at the specify keyword.

Cause: specify is a module-scope item, parallel to always/assign — it cannot live inside an always/initial block.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
always @(posedge clk) begin specify ... endspecify end   // ❌ illegal

Fix: move specify … endspecify to module scope, between the ports and endmodule, alongside the always/assign statements.

Guardrail: a specify block is a sibling of always, never a child.

2. Using parameter instead of specparam for delays

Symptom: SDF back-annotation runs but the delays never change — GLS uses the hard-coded values.

Cause: SDF can only override specparam. A parameter (or a literal) in a path delay is invisible to SDF annotation.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
specify parameter tRISE = 10; (a => y) = tRISE; endspecify   // ❌ SDF can't reach it

Fix: use specparam for every timing constant; reserve parameter for structural values (widths, depths).

Guardrail: if a number is a delay or a setup/hold limit, it is a specparam.

3. Running GLS with +notimingchecks and forgetting to remove it

Symptom: GLS passes clean, yet silicon has setup/hold failures.

Cause: +notimingchecks skips all $setup/$hold evaluation — you get path delays but no violation detection, defeating the purpose of full GLS.

Fix: run at least the critical tests without +notimingchecks. If false X-propagation floods the log, fix it with SDF scoping or X-pessimism options — not by disabling all checks.

Guardrail: +notimingchecks is for early bring-up only; sign-off GLS runs checks on.

4. Swapping $setup and $hold argument order

Symptom: Violation reports that point at the wrong signal or never fire.

Cause: $setup(data, ref, limit) lists data first; $hold(ref, data, limit) lists the reference first. Swapping them inverts the check.

Fix: remember setup = data arrives before clock (data first); hold = clock already fired (ref first). Or use $setuphold(ref, data, t_su, t_hold) to avoid the trap.

Guardrail: when in doubt, $setuphold — one consistent argument order for both.

5. Path delay on an internal wire

Symptom: Compile error — the path's signal "is not a port."

Cause: Specify-block paths are pin-to-pin (port-to-port) only; an internal wire cannot be a path endpoint.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
(internal_wire => out_y) = 5;   // ❌ internal_wire is not a module port

Fix: model the composite delay as a single port-to-port arc, or (rarely) promote the internal signal to a port if the timing must be exposed.

Guardrail: path endpoints are always module ports — specify describes the cell's external timing, not its internals.

11. Q & A

12. Cross-References & What's Next

This lesson covered specify blocks — the three path-delay forms, specparam, the system timing checks, and the SDF/GLS flow.

Related material elsewhere in the curriculum:

  • Input & Output Skews — clocking-block skews are the testbench-side timing-margin control; specify timing checks are the design-model side.
  • Clocking Blocks — Deep Dive — sampling/driving timing in the testbench, the dynamic-verification companion to gate-level timing.

13. Quick Reference

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
specify
  // ── specparam (SDF-overridable timing constants) ──────────────────
  specparam tRISE = 10, tFALL = 8, tSU = 5, tHD = 3, tW = 20;
 
  // ── Simple (parallel) path — 1-to-1 ───────────────────────────────
  (in_a => out_y) = 10;                  // single delay
  (in_a => out_y) = (tRISE, tFALL);      // (rise, fall)
  (in_a => out_y) = (10, 8, 9);          // (rise, fall, z)
 
  // ── Full path — all-to-all ────────────────────────────────────────
  (in_a, in_b, in_c *> out_y) = 12;
 
  // ── Edge-sensitive path (flip-flop) ───────────────────────────────
  (posedge clk   => (q : d))   = (tRISE, tFALL);  // clk-to-Q
  (negedge rst_n => (q : 1'b0)) = tFALL;           // async reset-to-Q
 
  // ── Timing checks (mind $setup vs $hold arg order) ────────────────
  $setup    (d, posedge clk, tSU);
  $hold     (posedge clk, d, tHD);
  $setuphold(posedge clk, d, tSU, tHD);
  $width    (posedge clk, tW);
  $period   (posedge clk, 20);
  $recovery (posedge rst_n, posedge clk, 4);
  $removal  (posedge rst_n, posedge clk, 2);
endspecify
 
// GLS: vcs -sdf max:top:top.sdf ... (max for setup, min for hold)
// specify is module-scope + simulation-only; synthesis ignores it.

14. Summary

A specify block layers real timing over a module's zero-delay function: path delays declare how long each pin-to-pin arc takes, and timing checks ($setup, $hold, $setuphold, $width, $period, $recovery, $removal, $skew) flag temporal violations. Paths come in three forms — simple => (1-to-1), full *> (all-to-all), and edge-sensitive (posedge clk => (q : d)) for flops — with 1/2/3/6-value delay specifications.

Timing constants must be specparam, not parameter, because only specparam can be overridden by an SDF file at runtime — the mechanism that injects post-layout delays into gate-level simulation without recompiling. Run GLS at both corners (max for setup, min for hold), keep timing checks on for sign-off, and mind the mirror-image argument order of $setup and $hold. specify is module-scope and simulation-only — synthesis ignores it — and it is the dynamic complement to STA: STA proves every path statically, while specify/SDF/GLS exposes the X-propagation, reset, and async behaviour that only a real-delay simulation reveals.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet