Skip to content
VLSI Mentor

awk Part III · Module 10 · Timing and STA Report Analysis

Understanding Timing Report Structure

Module 9's logs had one record per line, so one awk rule could handle one kind of record. A timing report does not work that way. A single path's startpoint, its endpoint, its clock group, its delay table and its slack are all separate lines spread over twenty or more, and none of them means much without the others. That makes this the hardest parsing job in the track, and it starts the same way Module 9 did — by reading the file's shape before writing a pattern, because the structure is what decides that state has to be carried between lines rather than matched within one.

Advanced17 min readawkPart IIISTATimingMulti-Line Records

Part III · Module 10 · Chapter 10.1 · Understanding Timing Report Structure

1. Why This Matters

A report_timing block is the densest structured text in the flow, and the number everybody wants from it — the slack — sits twenty lines away from the path it belongs to.

That distance is the whole difficulty. Module 9's approach was one pattern per record type, because a UVM log line is self-contained: it carries its own severity, time, component and message. A timing report's slack line carries a number and a verdict and nothing identifying the path, so a parser that matches it alone produces a column of unattributed numbers.

2. A Report, Whole

Three paths, in the shape the rest of the module uses:

Azvya Education Pvt. Ltd.VLSI Mentor
timing.rpt — synthetic teaching data. Modelled on the common report_timing shape; wording and layout are illustrative only.
****************************************
Report : timing
Design : alu_core
****************************************

  Startpoint: u_regfile/dout_reg[3]
              (rising edge-triggered flip-flop clocked by clk_core)
  Endpoint: u_alu/sum_reg[7]
            (rising edge-triggered flip-flop clocked by clk_core)
  Path Group: clk_core
  Path Type: max

  Point                                    Incr       Path
  ----------------------------------------------------------
  clock clk_core (rise edge)               0.000      0.000
  u_regfile/dout_reg[3]/CK (DFFX1)         0.000      0.000 r
  u_regfile/dout_reg[3]/Q (DFFX1)          0.112      0.112 f
  u_alu/U17/Z (AND2X2)                     0.085      0.197 f
  u_alu/sum_reg[7]/D (DFFX1)               0.041      0.238 f
  data arrival time                                   0.238
  ----------------------------------------------------------
  clock clk_core (rise edge)               0.250      0.250
  library setup time                      -0.030      0.220
  data required time                                  0.220
  ----------------------------------------------------------
  data required time                                  0.220
  data arrival time                                  -0.238
  ----------------------------------------------------------
  slack (VIOLATED)                                   -0.018

  Startpoint: u_ctrl/state_reg[1]
              (rising edge-triggered flip-flop clocked by clk_core)
  Endpoint: u_alu/flag_reg[0]
            (rising edge-triggered flip-flop clocked by clk_core)
  Path Group: clk_core
  Path Type: max

  Point                                    Incr       Path
  ----------------------------------------------------------
  clock clk_core (rise edge)               0.000      0.000
  u_ctrl/state_reg[1]/Q (DFFX1)            0.098      0.098 r
  u_alu/flag_reg[0]/D (DFFX1)              0.055      0.153 r
  data arrival time                                   0.153
  ----------------------------------------------------------
  data required time                                  0.220
  ----------------------------------------------------------
  slack (MET)                                         0.067

  Startpoint: u_io/pad_reg[0]
              (rising edge-triggered flip-flop clocked by clk_io)
  Endpoint: u_io/out_reg[0]
            (rising edge-triggered flip-flop clocked by clk_io)
  Path Group: clk_io
  Path Type: min

  Point                                    Incr       Path
  ----------------------------------------------------------
  clock clk_io (rise edge)                 0.000      0.000
  u_io/pad_reg[0]/Q (DFFX1)                0.045      0.045 r
  u_io/out_reg[0]/D (DFFX1)                0.012      0.057 r
  data arrival time                                   0.057
  ----------------------------------------------------------
  data required time                                  0.080
  ----------------------------------------------------------
  slack (VIOLATED)                                   -0.023
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
wc -l < timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
      65

Sixty-five lines for three paths — roughly twenty-two each, of which four carry the identity and one carries the answer.

3. The Markers Are Consistent

Counting the structural lines confirms the shape before anything is extracted:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *Startpoint:/ { s++ } /^ *Endpoint:/ { e++ } /^ *Path Group:/ { g++ } /^ *Path Type:/ { t++ } /^ *slack/ { k++ } END { printf "Startpoint=%d Endpoint=%d PathGroup=%d PathType=%d slack=%d\n", s + 0, e + 0, g + 0, t + 0, k + 0 }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Startpoint=3 Endpoint=3 PathGroup=3 PathType=3 slack=3

All five counts equal. That is the single most useful thing to check about a timing report, and Chapter 10.2 section 7 turns it into an assertion — because the moment they disagree, any parser that pairs them is pairing the wrong things.

The leading ^ * matters. These lines are indented, so an unanchored /Startpoint:/ would also match the text Startpoint: wherever else it appeared, and an anchor without the space allowance would match nothing at all.

One logical timing path fanning out into three groups of lines. The header group holds the startpoint, endpoint, path group and path type. The delay table holds the per-point incremental and cumulative delays plus the arrival and required times. The slack line holds the verdict and the final number.One logical path22 lines in the fixtureHeader: 4 linesidentity, no numbersDelay table rowsnumbers, no identityThe slack linethe answer, nothing else12
Figure 1 — one logical path, three groups of lines. The header carries the identity and nothing numeric; the delay table carries the arithmetic and nothing identifying; the slack line carries the answer and nothing else. No single line is a usable record, which is why a timing parser needs state where a log parser did not.

4. The Four Header Lines

The lines that identify a path:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *(Startpoint|Endpoint|Path Group|Path Type):/ { printf "%2d: %s\n", NR, $0 }' timing.rpt | head -8
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
 6:   Startpoint: u_regfile/dout_reg[3]
 8:   Endpoint: u_alu/sum_reg[7]
10:   Path Group: clk_core
11:   Path Type: max
31:   Startpoint: u_ctrl/state_reg[1]
33:   Endpoint: u_alu/flag_reg[0]
35:   Path Group: clk_core
36:   Path Type: max

Four pieces, and each is worth something different:

  • Startpoint — the launching flip-flop or input port. $2 after the colon.
  • Endpoint — the capturing flip-flop or output port. The thing a fix usually targets.
  • Path Group — the clock domain, which Chapter 10.6 groups on.
  • Path Type — max for a setup check, min for a hold check. Chapter 10.4's subject, and the field most often ignored.

Note lines 7 and 9: each of the first two is followed by a parenthesised continuation describing the clock. That continuation is not matched by the patterns above, which is deliberate — it is a different line and extracting the clock from it is a separate decision from extracting it from Path Group.

5. The Slack Line

The one line that carries the answer:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *slack/ { printf "%2d: NF=%d  $1=[%s]  $2=[%s]  $NF=[%s]\n", NR, NF, $1, $2, $NF }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
29: NF=3  $1=[slack]  $2=[(VIOLATED)]  $NF=[-0.018]
47: NF=3  $1=[slack]  $2=[(MET)]  $NF=[0.067]
65: NF=3  $1=[slack]  $2=[(VIOLATED)]  $NF=[-0.023]

Three fields on every slack line: the word slack, the parenthesised verdict, and the value. Despite the wide run of spaces before the number, the default FS collapses it — Chapter 3.1's rule — so $NF is the slack and $2 is the verdict.

Two independent pieces of information on one line. The tool computed the verdict and printed the number, and they are separate facts. Chapter 10.3 is about why you should read both rather than deriving the verdict from the number's sign.

NF = 3 on every slack line is convenient and it is a property of this fixture's wording. A report writing Slack: -0.018, or slack -0.018 (VIOLATED), or padding the verdict differently, has a different layout — which is section 8's point and the reason the profiler there checks the field count rather than assuming it.

6. Why Paragraph Mode Does Not Help

The obvious idea for a multi-line record is Chapter 3.4's paragraph mode — set RS = "" and let a blank line separate records. On this report it does not work:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'BEGIN { RS = "" } { n++ } /Startpoint:/ && /slack/ { both++ } END { printf "%d paragraph(s), %d containing BOTH a Startpoint and a slack\n", n, both + 0 }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
7 paragraph(s), 0 containing BOTH a Startpoint and a slack

Seven paragraphs and not one of them is a path. Listing them shows why:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'BEGIN { RS = ""; FS = "\n" } { printf "record %d: %2d line(s), starts [%s]\n", NR, NF, substr($1, 1, 44) }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
record 1:  4 line(s), starts [****************************************]
record 2:  6 line(s), starts [  Startpoint: u_regfile/dout_reg[3]]
record 3: 17 line(s), starts [  Point                                    I]
record 4:  6 line(s), starts [  Startpoint: u_ctrl/state_reg[1]]
record 5: 10 line(s), starts [  Point                                    I]
record 6:  6 line(s), starts [  Startpoint: u_io/pad_reg[0]]
record 7: 10 line(s), starts [  Point                                    I]

Record 2 is the first path's header; record 3 is its delay table and slack. A blank line sits between them, so paragraph mode cuts every path in half — three header paragraphs and three table paragraphs, plus the report banner.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'BEGIN { RS = "" } /Startpoint:/ { st++ } /slack/ { sl++ } END { printf "paragraphs with a Startpoint=%d, with a slack=%d\n", st + 0, sl + 0 }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
paragraphs with a Startpoint=3, with a slack=3

Three and three, in six different paragraphs.

That is not a flaw in paragraph mode; it is a mismatch between the tool's blank-line placement and what a path is. Chapter 10.7 measures the alternative properly on a report shape where paragraph mode does work, and the conclusion there is that state-carrying survives both shapes while paragraph mode survives one — which makes Chapter 10.2's approach the default.

7. One Path Spans Many Lines

The consequence, stated plainly. The startpoint and the slack of the first path:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'NR == 6 || NR == 29 { printf "line %2d: %s\n", NR, $0 }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
line  6:   Startpoint: u_regfile/dout_reg[3]
line 29:   slack (VIOLATED)                                   -0.018

Twenty-three lines apart, and neither line references the other.

So matching the slack line alone gives a number with no path:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *slack/ { print $NF }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
-0.018
0.067
-0.023

Three numbers in report order. Useful for a worst-case (Chapter 10.5 does exactly this) and useless for anything that must name a path.

And matching the startpoint alone gives a path with no number:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *Startpoint:/ { print $2 }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
u_regfile/dout_reg[3]
u_ctrl/state_reg[1]
u_io/pad_reg[0]

Joining them is the job, and awk's only mechanism for it is a variable that survives between records — Chapter 5.1's between-records persistence, which has been a convenience everywhere else in this track and is load-bearing here.

8. Profiling a Real Report

The commands to run against a report you have not seen, before writing anything:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'NR <= 5 { printf "%d: [%s]\n", NR, $0 } NR == 6 { exit }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
1: [****************************************]
2: [Report : timing]
3: [Design : alu_core]
4: [****************************************]
5: []

How long is the preamble? Five lines here; a real report's header can carry the tool version, the design, every constraint file and the operating conditions.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *(Startpoint|Endpoint|Path Group|Path Type|slack)/ { k[$1 " " $2]++ } END { for (x in k) printf "%-28s %d\n", x, k[x] | "sort" }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Endpoint: u_alu/flag_reg[0]  1
Endpoint: u_alu/sum_reg[7]   1
Endpoint: u_io/out_reg[0]    1
Path Group:                  3
Path Type:                   3
Startpoint: u_ctrl/state_reg[1] 1
Startpoint: u_io/pad_reg[0]  1
Startpoint: u_regfile/dout_reg[3] 1
slack (MET)                  1
slack (VIOLATED)             2

What marker spellings exist? Grouping on the first two fields shows the exact wording — including that Path Group: and Path Type: have a constant second field while slack does not, which tells you where the values sit.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *slack/ { n[NF]++ } END { for (k in n) printf "slack lines with NF=%s: %d\n", k, n[k] }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
slack lines with NF=3: 3

Is the slack line's field count stable? If it varies, the value is not reliably $NF and Chapter 10.3 section 5's pattern-based extraction is required.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *Startpoint:/ { s++ } /^ *slack/ { k++ } END { printf "startpoints=%d slack lines=%d %s\n", s + 0, k + 0, (s == k ? "-> can be paired" : "-> MISMATCH, pairing is unsafe") }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
startpoints=3 slack lines=3 -> can be paired

Do the counts match? This is the precondition for everything in Chapter 10.2, and it is one rule.

9. Common Mistakes

Writing the pattern before reading the file. The structure decides the whole approach.

Treating a line as a record. A slack line has no path; a startpoint has no number — section 7.

An unanchored /Startpoint:/. The lines are indented; use ^ *.

Reaching for RS = "" first. A blank line inside each path splits it — section 6.

Assuming $NF is the slack. It is here; a different wording puts it elsewhere — section 5.

Deriving the verdict from the slack's sign. The line states it independently — Chapter 10.3.

Ignoring Path Type. max and min are setup and hold, and mixing them is Chapter 10.4's subject.

Extracting the clock from the parenthesised continuation line when Path Group states it directly.

Assuming the marker counts match. Check — section 8.

Copying these patterns into a production script. Profile the real report first — section 1.

10. Exercises

Exercise 1 — Count the markers

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *Startpoint:/ { s++ } /^ *Endpoint:/ { e++ } /^ *Path Group:/ { g++ } /^ *Path Type:/ { t++ } /^ *slack/ { k++ } END { printf "%d %d %d %d %d\n", s + 0, e + 0, g + 0, t + 0, k + 0 }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
3 3 3 3 3

Five equal counts — the precondition for pairing them.

Exercise 2 — Read a slack line

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *slack/ { printf "NF=%d verdict=%-11s value=%s\n", NF, $2, $NF }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
NF=3 verdict=(VIOLATED)  value=-0.018
NF=3 verdict=(MET)       value=0.067
NF=3 verdict=(VIOLATED)  value=-0.023

Two independent facts per line: the verdict the tool computed and the number.

Exercise 3 — Show the distance

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *Startpoint:/ { last = NR } /^ *slack/ { printf "startpoint at line %2d, slack at line %2d -- %d lines apart\n", last, NR, NR - last }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
startpoint at line  6, slack at line 29 -- 23 lines apart
startpoint at line 31, slack at line 47 -- 16 lines apart
startpoint at line 49, slack at line 65 -- 16 lines apart

The distance is not even constant — the first path's delay table is longer.

Exercise 4 — Prove paragraph mode splits a path

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'BEGIN { RS = "" } /Startpoint:/ { st++ } /slack/ { sl++ } /Startpoint:/ && /slack/ { both++ } END { printf "Startpoint=%d slack=%d BOTH=%d\n", st + 0, sl + 0, both + 0 }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
Startpoint=3 slack=3 BOTH=0

Three and three, and never together.

Exercise 5 — Engineering application

Write a report profiler: given a timing report you have not seen, report its preamble length, its marker spellings and counts, its slack-line field counts, and whether pairing is safe.

Azvya Education Pvt. Ltd.VLSI Mentor
profile.awk — synthetic teaching script.
# profile.awk — describe a timing report before parsing it.
# Usage: awk -f profile.awk timing.rpt
# Exit:  0 marker counts agree, pairing looks safe
#        1 marker counts disagree
#        2 report is empty

/^ *Startpoint:/ { st++; if (!first_marker) first_marker = NR }
/^ *Endpoint:/   { en++ }
/^ *Path Group:/ { pg++ }
/^ *Path Type:/  { pt++; types[$3]++ }
/^ *slack/       { sl++; nf[NF]++; verdict[$2]++ }
{ total++ }

END {
    if (!total) { print "ERROR: report is empty" > "/dev/stderr"; exit 2 }
    printf "%d line(s); first path marker at line %d (preamble %d line(s))\n", total, first_marker + 0, first_marker - 1
    printf "markers: Startpoint=%d Endpoint=%d PathGroup=%d PathType=%d slack=%d\n", st + 0, en + 0, pg + 0, pt + 0, sl + 0
    printf "path types: max=%d min=%d\n", types["max"] + 0, types["min"] + 0
    printf "slack verdicts: MET=%d VIOLATED=%d\n", verdict["(MET)"] + 0, verdict["(VIOLATED)"] + 0
    printf "slack line field counts:"
    n = 0; for (k in nf) n++
    printf " %d distinct (", n
    for (k in nf) printf "NF=%s x%d ", k, nf[k]
    print ")"
    if (st == sl && st == en && st == pg && st == pt) print "pairing: all five counts agree"
    else { print "pairing: COUNTS DISAGREE -- see Chapter 10.2 section 7"; exit 1 }
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk -f profile.awk timing.rpt
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
65 line(s); first path marker at line 6 (preamble 5 line(s))
markers: Startpoint=3 Endpoint=3 PathGroup=3 PathType=3 slack=3
path types: max=2 min=1
slack verdicts: MET=1 VIOLATED=2
slack line field counts: 1 distinct (NF=3 x3 )
pairing: all five counts agree
status: 0

Everything needed before writing a parser: the preamble length so a header cannot be mistaken for data, the five marker counts so pairing is known to be safe, the path types so Chapter 10.4's setup-versus-hold split is known to be present, the verdict spellings so Chapter 10.3's pattern is known to match, and the slack field count so $NF is known to be reliable.

Note two deliberate choices in that script. The path types and verdicts are printed by naming the keys rather than with for (t in types), because Chapter 7.7 established that array iteration has no defined order and a profiler whose output row order varies between runs cannot be diffed. And the pairing check compares all five counts rather than two, because a truncated report breaks a different subset than a missing header line does — Exercise 6 shows both.

path types: max=2 min=1 says the report mixes setup and hold checks, which Chapter 10.5 shows makes a single "worst path" number meaningless.

The engineering caveat this whole module carries: these counts describe the report, not the design. 3 path(s) is three paths the tool was asked to print, and a report_timing without -max_paths prints only one path per group by default — so a clean-looking report with three paths may be hiding thousands.

Exercise 6 — Challenge: detect a report whose pairing is unsafe

The profiler's last check exists to be triggered. Make it fire, two different ways.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'NR != 31' timing.rpt > nostart.rpt
awk -f profile.awk nostart.rpt
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
64 line(s); first path marker at line 6 (preamble 5 line(s))
markers: Startpoint=2 Endpoint=3 PathGroup=3 PathType=3 slack=3
path types: max=2 min=1
slack verdicts: MET=1 VIOLATED=2
slack line field counts: 1 distinct (NF=3 x3 )
pairing: COUNTS DISAGREE -- see Chapter 10.2 section 7
status: 1

Deleting one Startpoint line gives 2 startpoints against 3 of everything else, and the profiler refuses.

That matters because of what Chapter 10.2 section 6 shows happens otherwise: a parser carrying state across these lines will pair two different slack values with the same startpoint and report both with complete confidence. The count check is one rule and it is the cheapest protection against that in the module.

A truncated report breaks a different subset:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
head -50 timing.rpt > truncated.rpt
awk -f profile.awk truncated.rpt
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
50 line(s); first path marker at line 6 (preamble 5 line(s))
markers: Startpoint=3 Endpoint=2 PathGroup=2 PathType=2 slack=2
path types: max=2 min=0
slack verdicts: MET=1 VIOLATED=1
slack line field counts: 1 distinct (NF=3 x2 )
pairing: COUNTS DISAGREE -- see Chapter 10.2 section 7
status: 1

3 startpoints against 2 of everything else — the last path has a header and no answer, because the report was cut off. A disk-full or a killed tool produces this routinely, and Chapter 10.2 section 5 shows that path silently vanishing from a parser's output.

Compare the two failure signatures: a missing header line leaves the startpoint count low, and a truncation leaves it high. That is why the check compares all five counts rather than just two — the direction of the discrepancy tells you which fault you have, and a two-count check would catch both as the same thing.

11. Summary

  • A timing path spans many lines — 22 here, with the startpoint and slack 16 to 23 lines apart.
  • No single line is a usable record. The header has identity and no numbers; the slack line has the answer and no identity.
  • So state must be carried between records, which is Chapter 10.2 and the module's recurring difficulty.
  • Four header lines carry the identity: Startpoint, Endpoint, Path Group, Path Type.
  • Path Type is max for setup and min for hold, and it is the field most often ignored.
  • The slack line states the verdict independently of the value — two facts, not one.
  • Anchor the patterns with ^ *; the lines are indented.
  • Paragraph mode does not align with paths here: 7 paragraphs, none containing both a startpoint and a slack.
  • Check that the marker counts match before pairing anything — one rule, and the precondition for the whole module.
  • Profile a real report first. Everything except the broad shape is tool-specific.

The structure is now known. Chapter 10.2 — Extracting Startpoints and Endpoints does the pairing: carrying the header forward so it is still in hand when the slack line arrives, and the two ways that state silently produces a wrong answer when a line is missing.

Where this fits

Part of the awk curriculum.