Skip to content
VLSI Mentor

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 (input pin)Y = A & B (outputpin)B (input pin)(A => Y) = (42, 38)(B => Y) = (45, 40)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.

Continue learning

Standards & specifications

Governing standard
IEEE Std 1800 (SystemVerilog)(opens IEEE in a new tab)

Defines SystemVerilog language semantics — syntax, data types, scheduling and the behaviour a conforming simulator must produce. It does not define tool-specific synthesis support or vendor methodology.

This page also covers RTL structure, verification approach and debugging technique. Those are engineering practice built on the standard, not requirements the standard itself imposes.

Where this fits

Part of the SystemVerilog curriculum.