The four required inputs, how to run zero-delay and SDF-annotated GLS step by step, reading the elaboration log and annotation statistics, using verbose debug switches, and interpreting the regression loop from first delivery to signoff.
Every GLS run — whether zero-delay or SDF-annotated — requires exactly four inputs. If any one is missing or mismatched, the simulation either fails to compile or produces misleading results.
Four required GLS inputs. The gate-level netlist and cell library models are always required — together they define the structural description and the logical/timing behaviour of every cell. The SDF file is required for SDF-annotated simulation but is ignored (with a warning) in zero-delay mode. The testbench exercises the design; in SDF mode it may contain a $sdf_annotate call, or annotation can be driven externally via an SDF command file.
| Input | What it provides | Who delivers it | Required for zero-delay? |
|---|---|---|---|
| Gate-level netlist | Structural instantiation of all standard cells and their interconnections | Synthesis or P&R tool (backend team) | Yes |
| Cell library models | Verilog simulation models for every cell type, including specify blocks with timing arcs and checks | Standard cell library vendor (process design kit) | Yes — for cell behaviour even without timing |
| SDF timing file | Back-annotated IOPATH delays and timing check values for every instance | P&R or STA tool (backend team) | No — suppressed in zero-delay mode |
| Testbench | Stimulus generation, DUT instantiation, output checking, and optionally $sdf_annotate | Verification team | Yes |
Every GLS run follows the same three-phase sequence regardless of delay mode: compile (parse and check all HDL source files), elaborate (build the design hierarchy, apply delay annotation, compile timing checks), and simulate (run the testbench, evaluate timing checks, report violations).
Three GLS phases. Compile parses and checks all HDL source. Elaborate builds the hierarchy, applies SDF annotation, and compiles timing check infrastructure — delays are annotated here, not at simulation time. Simulate runs the testbench, propagates transitions through cells using annotated delays, and evaluates timing checks at every clock edge. Errors in elaboration must be fixed before simulation can start; timing violations appear during simulation.
Many simulators provide a single-step invocation that performs all three phases in one command, or a three-step invocation (compile, elaborate, simulate as separate commands) that allows incremental re-runs. For large designs, the three-step approach is preferred — recompile only the changed files, re-elaborate only if the hierarchy changed, re-simulate without recompiling when only testbench content changed.
Zero-delay GLS is the simplest and fastest mode. The only timing-specific addition to a standard compilation is the flag that suppresses specify blocks. The design, library, and testbench are compiled and elaborated normally; the specify blocks (which contain path delays and timing checks) are simply not activated.
counter_netlist.vstdcell_lib.vcounter_tb.vThe -nospecify switch is passed at elaboration. It suppresses all specify blocks across all modules, disabling path delays and timing checks. If the testbench contains a $sdf_annotate call, the simulator will warn that it is being ignored — this warning is expected and benign in zero-delay mode.
// Zero-delay GLS: compile, elaborate, simulate // Step 1 — compile all sources compile \ counter_netlist.v \ stdcell_lib.v \ counter_tb.v \ -timescale 1ns/10ps // Step 2 — elaborate with zero-delay switch elaborate \ counter_tb \ -nospecify // suppress all specify blocks // Step 3 — simulate simulate -run
$sdf_annotate("timing.sdf", top.dut) at time 0, the elaborator will print a warning such as: “Ignoring $sdf_annotate on line N because of -nospecify option.” This is the correct and expected behaviour. The SDF file is not read, no delays are annotated, and simulation proceeds in true zero-delay mode. No action is needed.
The elaboration log is the first place to look after every GLS run. For zero-delay mode, the key things to confirm in the log are:
// Example zero-delay elaboration log output (annotated) file: counter_netlist.v module worklib.counter:v errors: 0, warnings: 0 ← netlist compiled cleanly file: counter_tb.v module worklib.counter_tb:v errors: 0, warnings: 0 file: stdcell_lib.v module stdcell_lib.INVX1:v errors: 0, warnings: 0 module stdcell_lib.NAND2X1:v errors: 0, warnings: 0 module stdcell_lib.DFFX1:v errors: 0, warnings: 0 ... (all library cells) Elaborating design hierarchy: Top level: counter_tb *W,SDFSKPA: Ignoring $sdf_annotate on line 12 in counter_tb.v because of -nospecify option. ↑ Expected — confirms zero-delay mode is active Design hierarchy summary: Modules: 24 Unique: 8 Primitives: 79 Registers: 12 Timing checks: 0 ← confirms specify blocks are inactive
The critical indicator for zero-delay mode is “Timing checks: 0” in the design hierarchy summary. This confirms that no specify block timing checks were compiled. If this number is non-zero in a zero-delay run, the -nospecify switch was not applied correctly.
$sdf_annotate call in the testbench was suppressed. It is informational — confirming that zero-delay mode is correctly active. If you do not see this warning and the testbench has a $sdf_annotate call, investigate whether the SDF is being inadvertently annotated.
SDF-annotated GLS is structurally identical to zero-delay GLS except that the -nospecify switch is removed and the SDF file is provided — either via an SDF command file or via a $sdf_annotate call in the testbench. The elaborator reads the SDF file, annotates every timing arc, and compiles the timing checks before simulation begins.
The SDF command file approach keeps annotation configuration external to the testbench. The same testbench runs both zero-delay GLS (without the command file argument) and SDF GLS (with the command file argument) without any testbench modification.
// sdf_cmd_file contents: SDF_FILE "timing.sdf" SCOPE counter_tb.dut // DUT root in the testbench MTM_CONTROL MAXIMUM // use worst-case delays for setup signoff LOG_FILE "sdf_annotate.log" // annotation detail log // Elaboration command: elaborate \ counter_tb \ -sdf_cmd_file sdf_cmd_file // no -nospecify — specify blocks active
The system task approach embeds the annotation instruction directly in the testbench HDL. This is simpler for single-corner runs but requires testbench changes to switch between corners or SDF files.
// Inside the testbench initial block: initial begin $sdf_annotate( "timing.sdf", // SDF file path counter_tb.dut, // annotation scope , // config file (unused) "sdf_annotate.log", // annotation log file "MAXIMUM" // MTM control ); end // Elaboration command (no -nospecify): elaborate counter_tb
$sdf_annotate AND the elaboration command specifies an SDF command file, the command file takes priority and the $sdf_annotate call is suppressed with a warning. The warning will read something like: “Ignoring $sdf_annotate because -sdf_cmd_file was specified.” This precedence rule lets teams use the same testbench for both zero-delay (no command file, $sdf_annotate suppressed by -nospecify) and SDF runs (command file present, overrides the system task).
After SDF annotation during elaboration, the simulator prints a statistics block. This is the most important diagnostic output to examine before trusting any SDF GLS timing results. Never proceed to simulation failure analysis before confirming annotation statistics.
// Example SDF annotation statistics block Reading SDF file: "timing.sdf" Compiled SDF: timing.sdf.X Log file: sdf_annotate.log Annotation scope: counter_tb.dut MTM control: MAXIMUM Scale factors: 1.0 : 1.0 : 1.0 Annotation completed successfully. SDF statistics: Specified Annotated Percentage PathDelays: 57 57 100.00% $setuphold: 96 96 100.00% $recovery: 8 8 100.00% $removal: 8 8 100.00% $hold: 8 0 0.00% $width: 24 0 0.00% Total Annotated: 169 / 201 = 84.08% Design hierarchy summary: Timing checks: 169 ← non-zero confirms SDF mode active Interconnect: 67
Reading this output line by line:
Annotation percentage interpretation guide. Green rows indicate good annotation coverage. Amber rows ($hold 0%, $width 0%) are common and often expected — investigate once to confirm the explanation, then document. Red rows (PathDelays below 100%, or all checks at 0%) indicate a configuration problem that must be resolved before simulation results can be trusted. The hierarchy summary “Timing checks: N” confirms whether the specify blocks are active at all.
When annotation statistics are not as expected, two additional debug options provide more detail: verbose annotation logging and the timing dump file.
Verbose mode writes a detailed record of every annotation attempt to the log file — success or failure, the exact arc annotated, and the value applied. This is indispensable for diagnosing partial annotation percentages.
// Add -sdf_verbose to the elaboration command: elaborate counter_tb \ -sdf_cmd_file sdf_cmd_file \ -sdf_verbose // detailed per-arc annotation log // Example verbose log entries in sdf_annotate.log: Time units: 1ps Annotating to instance counter_tb.dut.u_reg of module DFFX1 ABSOLUTE (IOPATH (posedge CK) Q) = (180:210:260) rise ABSOLUTE (IOPATH (posedge CK) Q) = (175:205:255) fall SETUPHOLD D (posedge CK) = (45:52:68) setup (10:12:15) hold Warning: SDFNEP — path (IOPATH A Y) does not exist in instance counter_tb.dut.u_logic.g7 of module NAND2BX1 ↑ This arc is in the SDF but not in the cell model spec block
The statistics dump option writes a structured file listing the annotation results per instance — useful for identifying which specific instances have low annotation coverage when the summary percentage is good but individual blocks are suspect.
// Add -sdfstats to write a statistics file: elaborate counter_tb \ -sdf_cmd_file sdf_cmd_file \ -sdf_verbose \ -sdfstats annotation_stats.txt
The timing dump option generates a complete listing of the design hierarchy with all annotated timing values after elaboration. Every scope, every timing arc, and every timing check value actually present in the elaborated simulation is written to the file. This is the definitive check — it shows what the simulator is actually using, bypassing any uncertainty about whether the log represents the real simulation state.
// Request a timing dump (shows actual annotated values): elaborate counter_tb \ -sdf_cmd_file sdf_cmd_file \ -dumptiming timing_dump.txt // In timing_dump.txt, look for your instance: // Scope: counter_tb.dut.u_reg // pdelay anno='y' delay="210"/> ← TYP value confirmed // pdelay anno='n' delay="0"/> ← not annotated (problem!)
Symptom: SDF annotation statistics show PathDelays 100%, but probing a flip-flop output in the waveform shows it transitioning with zero delay — exactly at the clock edge with no propagation delay.
Step 1 — Check the verbose annotation log. Find the entry for the flip-flop instance. If the log shows ABSOLUTE (IOPATH (posedge CK) Q) = (0:0:0), the SDF itself contains zero for that arc — it is not a simulation issue but an SDF generation issue. Report to the backend team.
Step 2 — Check if TIMESCALE is the problem. If the log shows IOPATH = (180:210:260) but the waveform shows zero delay, the simulation timescale precision is too coarse. The SDF timescale is 1ps but the simulation is running at 1ns/1ns — 210ps rounds to 0.210ns which rounds to 0 at 1ns precision. Fix: add -timescale 1ns/1ps to ensure 1ps precision, or better, -timescale 1ps/1ps.
Step 3 — Use the timing dump. Run with -dumptiming timing_dump.txt and search for the instance. If the dump shows pdelay anno='y' delay="0", the value was annotated as zero after scaling. If it shows pdelay anno='n', the annotation did not happen despite the statistics reporting success — check for scope or DIVIDER mismatch.
GLS is not a single run — it is an iterative loop that spans the period from first netlist delivery to final signoff. Understanding the loop structure helps teams plan their schedules and respond to failures efficiently.
Full GLS regression loop. The backend delivers netlist and SDF; the verification team checks annotation statistics before running the test suite. Failures are categorised into four types: testbench hierarchy errors (fix in testbench), annotation warnings (joint investigation with backend), genuine timing violations (backend ECO required — new netlist delivered), and expected/known violations (add to tfile with justification). The loop repeats until zero unexpected failures, at which point GLS signoff is granted.
In practice, most teams run zero-delay GLS and SDF GLS as parallel tracks rather than sequential steps:
A failure in the zero-delay track must be resolved before the SDF track results are meaningful — a functional bug in the netlist will contaminate SDF GLS results with irrelevant timing violations on paths that are functionally incorrect anyway.
The first time a team sets up GLS for a design block, the work involves: writing the SDF command file (scope, MTM, log path), configuring the timescale to match the SDF precision, confirming the cell library simulation model paths, updating the testbench to work with the post-synthesis hierarchy, and building the initial tfile for known CDC and IP waivers. This setup work typically takes one to three engineering days for a new block. Once done, the infrastructure is reused for every subsequent GLS run on that block — the command files, tfile skeleton, and testbench updates are permanent. Teams that invest in clean GLS infrastructure early run signoff GLS with confidence; teams that defer it scramble to set it up under tape-out pressure with less time to investigate each failure thoroughly.
The default and strongly preferred behaviour is to annotate the SDF at elaboration time — before simulation begins. This is the fastest and most reliable approach because annotation is done once, the elaborated netlist contains the final delay values, and every simulation run uses those values without re-reading the SDF. However, a few scenarios require annotation to be applied during simulation rather than at elaboration. The most common is a design where different sub-blocks receive different SDF files at different times — for example, an IP block whose SDF is conditionally loaded based on a testbench configuration parameter evaluated at time 0. In these cases, the -sdf_sim_time (or equivalent) switch allows the $sdf_annotate system task to execute after time 0. The performance cost is significant: simulation must pause while annotation is applied, and any checks already evaluated before annotation are done without the correct delays. Simulation-time annotation should be avoided unless architecturally necessary.
At advanced SoC projects with continuous integration (CI) pipelines, zero-delay GLS on the gate-level netlist can be integrated as an automated regression gate. Every time the synthesis tool produces a new netlist (triggered by an RTL commit), the CI system automatically runs the zero-delay GLS test suite and reports results alongside the RTL simulation regression. This “GLS in CI” practice catches synthesis bugs within hours of the RTL change that triggered them — rather than weeks later when the verification team manually kicks off a GLS run. The infrastructure requirement is low: zero-delay GLS is fast enough (similar speed to RTL simulation on the same test suite) to run in CI without blocking the development pipeline. SDF GLS remains a scheduled milestone activity, but zero-delay GLS-in-CI has become a best practice at companies shipping complex SoCs at advanced process nodes.