How to Read an OpenSTA Timing Report (Line by Line)

How to read an OpenSTA timing report line by line, using a small SKY130 design you synthesise with Yosys, time, break on purpose and then fix.

By BitForBytes Editorial & Hardware Research Team, Official BitForBytes Hardware Publication · · 12 min read

⚡ Quick Summary

An OpenSTA timing report lists one timing path in two halves: the data arrival time, built up cell by cell from the launch clock edge, and the data required time, derived from the capture clock edge and the flip-flop's setup or hold time. Slack is required minus arrival for setup. Negative slack means the path is violated.


1. Introduction & Core Motivation

Simulation tells you a design is functionally right for the vectors you tried. It says nothing about whether every signal settles before the next clock edge. Static timing analysis (STA) answers that question for every path at once, without vectors, and the timing report is how it tells you the result. A physical-design or synthesis engineer reads these reports all day.

Students usually meet their first report as a wall of numbers from a lab script someone else wrote, with no way to change the design and see what moves. Tutorials that do exist tend to paste one sample report without a design you can rerun, so you cannot test your understanding.

This article gives you a design small enough to hold in your head, exact commands for Yosys 0.33 and OpenSTA 3.1.0 on the SkyWater SKY130 library, and the real output. Then you break timing on purpose and read the failure. OpenSTA's report format is deliberately close to the sign-off tools used in industry, so the skill transfers. After reading, you will be able to explain every line of a setup and a hold report and compute the slack yourself.


2. Detailed Technical Breakdown

What Does OpenSTA Need Before It Can Report Timing?

OpenSTA needs three inputs: a Liberty library with cell delays, a gate-level netlist, and SDC constraints that define the clock.

  acc8.v (RTL)
      |
      |  Yosys: synth + dfflibmap + abc
      v
  acc8_netlist.v ----------+
  (gates, SKY130 cells)    |
                           v
  sky130hd_tt.lib ----> +---------+      setup report
  (cell timing, TT)     | OpenSTA |----> hold report
                        +---------+      WNS, TNS, min period
  acc8.sdc -------------^
  (clock, I/O delays)

The design is an 8-bit accumulator with a registered input, so there is a clear register-to-register path through an adder.

`default_nettype none
// acc8: 8-bit accumulator with a registered input.
// Reset: synchronous, active-high.
// Latency: din reaches sum after 2 clock edges.
module acc8 (
    input  wire       clk,
    input  wire       rst,
    input  wire [7:0] din,
    output wire [7:0] sum
);
    reg [7:0] din_q;
    reg [7:0] sum_q;

    always @(posedge clk) begin
        if (rst) begin
            din_q <= 8'h00;
            sum_q <= 8'h00;
        end else begin
            din_q <= din;             // input register: path start
            sum_q <= sum_q + din_q;   // 8-bit adder between registers
        end
    end

    assign sum = sum_q;
endmodule
`default_nettype wire

This infers 16 D flip-flops (sky130_fd_sc_hd__dfxtp_1), an 8-bit ripple-carry adder that Yosys builds from six maj3_1 carry cells plus XOR and XNOR gates, and NOR-type gates that implement the synchronous reset in front of each D pin (54 cells in total). No latch is inferred because both registers are assigned in both branches of the if.

How Do You Synthesise the Design and Run OpenSTA?

You synthesise with a five-line Yosys script and run OpenSTA with a short TCL script. The Liberty file sky130hd_tt.lib.gz is in the examples folder of the OpenSTA repository; unzip it next to your files.

gunzip -c OpenSTA/examples/sky130hd_tt.lib.gz > sky130hd_tt.lib
yosys -q synth.ys
sta -no_init -no_splash -exit run_sta.tcl
# synth.ys
read_verilog acc8.v
synth -top acc8
dfflibmap -liberty sky130hd_tt.lib
abc -liberty sky130hd_tt.lib
opt_clean -purge
write_verilog -noattr acc8_netlist.v
# acc8.sdc - timing constraints for the acc8 tutorial design
set clk_period 10.0
create_clock -name clk -period $clk_period [get_ports clk]

# Outside world uses 20% of the cycle on each side of the block
set io_delay [expr {0.2 * $clk_period}]
set_input_delay  $io_delay -clock clk [get_ports {rst din[*]}]
set_output_delay $io_delay -clock clk [get_ports {sum[*]}]
# run_sta.tcl - load the design and report timing
read_liberty sky130hd_tt.lib
read_verilog acc8_netlist.v
link_design acc8
read_sdc acc8.sdc

report_checks -path_delay max     ;# worst setup path
report_checks -path_delay min     ;# worst hold path
report_wns
report_tns
report_clock_min_period

Yosys prints a list of warnings about flip-flop cells in the Liberty file whose functions it does not support (scan and enable flops); they do not affect this design. OpenSTA builds from source with CMake and needs Tcl, SWIG, Bison, Flex, Eigen and the CUDD library. The same commands also work at the openroad prompt, because OpenROAD embeds OpenSTA.

How Do You Read the Setup Report Line by Line?

You read the setup report top to bottom as two sums: arrival first, required second. This is the unedited report_checks -path_delay max output for a 10 ns clock.

Startpoint: _90_ (rising edge-triggered flip-flop clocked by clk)
Endpoint: _89_ (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: max

  Delay    Time   Description
---------------------------------------------------------
   0.00    0.00   clock clk (rise edge)
   0.00    0.00   clock network delay (ideal)
   0.00    0.00 ^ _90_/CLK (sky130_fd_sc_hd__dfxtp_1)
   0.28    0.28 v _90_/Q (sky130_fd_sc_hd__dfxtp_1)
   0.18    0.46 v _44_/X (sky130_fd_sc_hd__and2_0)
   0.39    0.85 v _50_/X (sky130_fd_sc_hd__maj3_1)
   0.39    1.25 v _54_/X (sky130_fd_sc_hd__maj3_1)
   0.39    1.64 v _58_/X (sky130_fd_sc_hd__maj3_1)
   0.39    2.03 v _62_/X (sky130_fd_sc_hd__maj3_1)
   0.39    2.42 v _66_/X (sky130_fd_sc_hd__maj3_1)
   0.37    2.79 v _70_/X (sky130_fd_sc_hd__maj3_1)
   0.15    2.95 ^ _72_/Y (sky130_fd_sc_hd__xnor2_1)
   0.04    2.99 v _73_/Y (sky130_fd_sc_hd__nor2_1)
   0.00    2.99 v _89_/D (sky130_fd_sc_hd__dfxtp_1)
           2.99   data arrival time

  10.00   10.00   clock clk (rise edge)
   0.00   10.00   clock network delay (ideal)
   0.00   10.00   clock reconvergence pessimism
          10.00 ^ _89_/CLK (sky130_fd_sc_hd__dfxtp_1)
  -0.11    9.89   library setup time
           9.89   data required time
---------------------------------------------------------
           9.89   data required time
          -2.99   data arrival time
---------------------------------------------------------
           6.90   slack (MET)
Report lineWhat it means
Startpoint / EndpointThe launch flop _90_ (bit 0 of din_q) and the capture flop _89_ (the top bit of sum_q). Yosys generated these instance names.
Path Type: maxA setup check: the tool used the slowest delays.
Delay columnDelay added by this pin or cell, in ns.
Time columnRunning total since the launch clock edge.
^ and vRising or falling transition at that pin.
clock clk (rise edge) 0.00The launch edge is at time 0.
clock network delay (ideal)No clock tree exists yet, so clock arrival is assumed instant.
_90_/Q 0.28Clock-to-Q delay of the launch flop.
six maj3_1 linesThe carry rippling through the adder, about 0.39 ns per bit.
data arrival time 2.99When the data reaches _89_/D.
clock clk (rise edge) 10.00The capture edge, one period later.
clock reconvergence pessimismCredit for clock path shared by launch and capture; zero with an ideal clock.
library setup time -0.11Setup requirement of dfxtp_1, subtracted from the capture edge.
data required time 9.89Latest moment the data may arrive.
slack 6.90 (MET)Required minus arrival.

The arithmetic is the setup equation with the terms laid out vertically:

slack_setup = (T_clk + T_skew - T_setup) - (T_clk→q + T_comb)

where T_clk is the clock period, T_skew the capture-minus-launch clock arrival difference, T_setup the capture flop's setup time, T_clk→q the launch flop's clock-to-Q delay and T_comb the logic delay, all in ns. Here: (10.00 + 0 - 0.11) - (0.28 + 2.71) = 9.89 - 2.99 = 6.90 ns.

How Is the Hold Report Different?

The hold report differs in three places: it uses the fastest path, the capture edge is the same edge as the launch, and slack is arrival minus required.

Startpoint: _90_ (rising edge-triggered flip-flop clocked by clk)
Endpoint: _82_ (rising edge-triggered flip-flop clocked by clk)
Path Group: clk
Path Type: min

  Delay    Time   Description
---------------------------------------------------------
   0.00    0.00   clock clk (rise edge)
   0.00    0.00   clock network delay (ideal)
   0.00    0.00 ^ _90_/CLK (sky130_fd_sc_hd__dfxtp_1)
   0.28    0.28 v _90_/Q (sky130_fd_sc_hd__dfxtp_1)
   0.07    0.35 ^ _45_/Y (sky130_fd_sc_hd__nor2_1)
   0.04    0.39 v _46_/Y (sky130_fd_sc_hd__nor3_1)
   0.00    0.39 v _82_/D (sky130_fd_sc_hd__dfxtp_1)
           0.39   data arrival time

   0.00    0.00   clock clk (rise edge)
   0.00    0.00   clock network delay (ideal)
   0.00    0.00   clock reconvergence pessimism
           0.00 ^ _82_/CLK (sky130_fd_sc_hd__dfxtp_1)
  -0.06   -0.06   library hold time
          -0.06   data required time
---------------------------------------------------------
          -0.06   data required time
          -0.39   data arrival time
---------------------------------------------------------
           0.45   slack (MET)

The capture clock line reads 0.00, not 10.00, because hold compares against the same edge that launched the data. The path is short, two gates to sum bit 0. The library hold time is negative here (-0.06 ns), which means this flop tolerates data changing slightly before the edge; the check becomes 0.39 - (-0.06) = 0.45 ns.

What Do WNS, TNS and Minimum Period Tell You?

WNS is the worst negative slack, TNS is the sum of all negative endpoint slacks, and minimum period is the fastest clock the design can meet. At 10 ns the run prints:

wns max 0.00
tns max 0.00
clk period_min = 3.10 fmax = 322.09

Both are 0.00 because nothing is violated; OpenSTA reports zero, not the positive slack. The minimum period of 3.10 ns is the arrival time plus setup, 2.99 + 0.11, which gives 322.09 MHz.

What Happens When You Break Timing on Purpose?

When you set the clock faster than 3.10 ns, the setup path fails and the hold result does not change. Edit one line in acc8.sdc to set clk_period 2.0 and rerun.

Metric10.0 ns clock2.0 ns clock3.2 ns clock
Worst setup slack6.90 ns (MET)-1.10 ns (VIOLATED)0.10 ns (MET)
Worst hold slack0.45 ns0.45 ns0.45 ns
WNS0.00-1.100.00
TNS0.00-2.190.00
Minimum period3.10 ns3.10 ns3.10 ns

At 2.0 ns the required time becomes 2.00 - 0.11 = 1.89 ns against the same 2.99 ns arrival, so slack is -1.10 ns. Adding -group_path_count 4 -format summary to report_checks shows which endpoints fail:

EndpointSum bitSlack at 2.0 ns
_89_/D7-1.10 ns
_88_/D6-0.74 ns
_87_/D5-0.35 ns
_86_/D40.04 ns

Three endpoints fail, and -1.10 - 0.74 - 0.35 = -2.19 ns is exactly the TNS. Each higher sum bit is one carry stage, about 0.39 ns, later than the one below it. That pattern tells you the fix is structural: shorten the carry chain with a faster adder, split the addition across two pipeline stages, or accept a period of at least 3.10 ns. Hold slack stayed at 0.45 ns in all three runs, because the hold check has no clock period in it.


3. Practical Takeaways for Students

  • Exam angle: If asked to "explain a timing report", draw the two-column structure: arrival path (launch clock, clock-to-Q, logic) and required path (capture clock, minus setup), then slack. Use the numbers 2.99, 9.89 and 6.90 as your example.
  • Interview angle: "WNS is -1.10 ns and TNS is -2.19 ns. What does that tell you?" Few endpoints fail, by a large margin each, so it is one deep path, not a design-wide problem. "Why did hold not change when you changed the period?" The hold check uses the same clock edge for launch and capture.
  • Common mistake: Reading only the slack line. The path lines show where the time went. A single 0.39 ns step repeated six times points at the carry chain; one large step points at a weak cell or high fanout. Add -fields {slew cap fanout} to see why a cell is slow.
  • Try it yourself: Change the adder to sum_q + din_q + 8'd1, predict whether the critical path grows, then rerun. Check your edited RTL in the BitForBytes Verilog Judge before synthesis.

4. Frequently Asked Questions

What does "clock network delay (ideal)" mean in a timing report?

It means the tool is treating the clock as arriving at every flip-flop at the same instant, with zero delay, because no clock tree has been built or annotated. This is normal before clock tree synthesis, when the netlist has a single clock net driving all flops.

After clock tree synthesis you run set_propagated_clock, and the line changes to "(propagated)" with real buffer delays. Skew then appears as a difference between the launch and capture clock network delays.

Is an OpenSTA report the same as a PrimeTime or Tempus report?

The structure is the same: startpoint, endpoint, an arrival section, a required section, and slack. OpenSTA reads the standard inputs, Liberty, Verilog, SDC and SPEF, and its report_checks output is laid out like the path reports from Synopsys PrimeTime and Cadence Tempus.

Command names and options differ; PrimeTime uses report_timing, for example. Sign-off tools also add foundry-qualified variation models. The reading skill carries over directly.

Why is the slack positive at 10 ns when the design only needs 3.10 ns?

Slack measures the margin against the clock you constrained, not against the design's limit. With a 10 ns period the data is required at 9.89 ns and arrives at 2.99 ns, so 6.90 ns is unused. The design could run faster; report_clock_min_period shows how much.

Large positive slack is not automatically good. In a real flow it can mean the constraint is too loose, and the synthesis tool will have optimised for area instead of speed.

How do I see more than the single worst path in OpenSTA?

Use the path-count options of report_checks. -group_path_count N reports the N worst paths in each path group, and -endpoint_path_count N reports several paths into the same endpoint. Adding -format summary prints one line per path, which is easier to scan.

For a quick list of failing endpoints only, report_check_types -max_delay -violators prints each violated setup check with its slack.


5. References & Further Reading

  • OpenSTA, Parallax Software, github.com/parallaxsw/OpenSTA (README build instructions, doc/OpenSTA.pdf command reference, examples/sky130hd_tt.lib.gz).
  • The OpenROAD Project documentation, openroad.readthedocs.io (timing commands shared with OpenSTA).
  • YosysHQ, Yosys documentation (synth, dfflibmap, abc, write_verilog).
  • SkyWater SKY130 open-source PDK, sky130_fd_sc_hd high-density standard-cell library.
  • J. Bhasker and R. Chadha, "Static Timing Analysis for Nanometer Designs: A Practical Approach", Springer, 2009.

Frequently Asked Questions

What does "clock network delay (ideal)" mean in a timing report?

It means the tool is treating the clock as arriving at every flip-flop at the same instant, with zero delay, because no clock tree has been built or annotated. This is normal before clock tree synthesis, when the netlist has a single clock net driving all flops.

Is an OpenSTA report the same as a PrimeTime or Tempus report?

The structure is the same: startpoint, endpoint, an arrival section, a required section, and slack. OpenSTA reads the standard inputs, Liberty, Verilog, SDC and SPEF, and its report_checks output is laid out like the path reports from Synopsys PrimeTime and Cadence Tempus.

Why is the slack positive at 10 ns when the design only needs 3.10 ns?

Slack measures the margin against the clock you constrained, not against the design's limit. With a 10 ns period the data is required at 9.89 ns and arrives at 2.99 ns, so 6.90 ns is unused. The design could run faster; report_clock_min_period shows how much.

How do I see more than the single worst path in OpenSTA?

Use the path-count options of report_checks. -group_path_count N reports the N worst paths in each path group, and -endpoint_path_count N reports several paths into the same endpoint. Adding -format summary prints one line per path, which is easier to scan.