Skip to content
VLSI Mentor

awk Part IV · Module 13 · Real-World AWK Engineering Projects

Project: Timing Violation Extractor

The second script a timing flow keeps: it walks a report, emits one row per violated path with its endpoint, clock and slack, and reports the worst negative slack — which is where the design decision lives. A single worst-slack figure is the number everyone asks for and the one thing this script refuses to produce, because on this report it would be a setup failure on one clock standing in for a hold failure on another. Every rule in it answers a failure measured in Module 10, and the report's own marker counts decide whether any of it is trustworthy.

Advanced19 min readawkPart IVProjectSTATiming

Part IV · Module 13 · Chapter 13.2 · Project: Timing Violation Extractor

1. What the Script Has to Do

Three outputs, and the third is the one with a judgement in it:

  1. One row per violated path — startpoint, endpoint, clock, which check, and the slack. This is what gets handed to whoever fixes it.
  2. A violation count against the path count, so the row list has a denominator.
  3. The worst negative slack. Everyone wants one number. Module 10.5 measured why there isn't one, and this script reports it per (check, clock) instead.

2. The Report

No STA tool runs in this environment, so the report is generated — eight paths in the standard report_timing shape, across three clocks and both check types:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'BEGIN {
  n = split("u_regfile/dout_reg[3]:u_alu/sum_reg[7]:clk_core:max:-0.018|u_ctrl/state_reg[1]:u_alu/flag_reg[0]:clk_core:max:0.067|u_dma/len_reg[4]:u_dma/cnt_reg[4]:clk_core:max:-0.112|u_alu/acc_reg[0]:u_alu/acc_reg[1]:clk_core:min:-0.041|u_io/pad_reg[0]:u_io/out_reg[0]:clk_io:min:-0.023|u_io/cfg_reg[2]:u_io/shift_reg[0]:clk_io:max:0.031|u_mem/rd_reg[0]:u_mem/dout_reg[0]:clk_ddr:max:-0.205|u_mem/wr_reg[1]:u_mem/din_reg[1]:clk_ddr:min:0.014", p, "|")
  print "****************************************"
  print "Report : timing"
  print "Design : soc_top"
  print "****************************************"
  print ""
  for (i = 1; i <= n; i++) {
    split(p[i], f, ":")
    v = (f[5] + 0 < 0 ? "VIOLATED" : "MET")
    printf "  Startpoint: %s\n", f[1]
    printf "              (rising edge-triggered flip-flop clocked by %s)\n", f[3]
    printf "  Endpoint: %s\n", f[2]
    printf "            (rising edge-triggered flip-flop clocked by %s)\n", f[3]
    printf "  Path Group: %s\n", f[3]
    printf "  Path Type: %s\n", f[4]
    print ""
    print "  Point                                    Incr       Path"
    print "  ----------------------------------------------------------"
    print "  data required time                                  0.220"
    print "  data arrival time                                  -0.238"
    print "  ----------------------------------------------------------"
    printf "  slack (%s) %38.3f\n", v, f[5]
    print ""
  }
}' > timing.rpt
wc -l < timing.rpt | awk '{ printf "  %d lines\n", $1 }'
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  117 lines

One path of it, read back from the file rather than quoted separately — so what the chapter shows and what the commands read cannot drift apart:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sed -n '6,18p' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  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
  ----------------------------------------------------------
  data required time                                  0.220
  data arrival time                                  -0.238
  ----------------------------------------------------------
  slack (VIOLATED)                                 -0.018
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *slack/ { nk++ } /^ *slack \(VIOLATED\)/ { nv++ } /^ *Path Group:/ { g[$3]++; if (!($3 in gs)) { gs[$3]=1; go[++ng]=$3 } } /^ *Path Type:/ { t[$3]++; if (!($3 in ts)) { ts[$3]=1; to[++nt]=$3 } }
 END { printf "  %d path(s), %d violating\n", nk, nv
       printf "  clocks:"; for (i=1;i<=ng;i++) printf " %s(%d)", go[i], g[go[i]]; print ""
       printf "  types: "; for (i=1;i<=nt;i++) printf " %s(%d)", to[i], t[to[i]]; print "" }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  8 path(s), 5 violating
  clocks: clk_core(4) clk_io(2) clk_ddr(2)
  types:  max(5) min(3)

Five violating of eight, four paths on clk_core, two each on clk_io and clk_ddr, five setup checks and three hold. The clock and type listings are built from insertion-ordered arrays rather than for (k in …), because that has no defined order — Chapter 10.4 section 8 — and an unordered listing here would differ between runs.

3. The Pipeline

Six-step timing extraction: carry the header forward and clear it on use, classify by the verdict word, separate setup from hold by path type, emit one row per violated path, report worst negative slack per check and clock, and refuse the report if the marker counts disagree.01CARRY, THEN CLEARWithout the clear, a missing Startpoint pairs two slacks with oneregister.02CLASSIFY BY THE WORDA report rounds a sub-precision violation to minus zero, so the signlies.03SPLIT SETUP FROM HOLDPath Type max or min. A stale value reports hold failures as setup.04ONE ROW PER VIOLATIONStartpoint, endpoint, clock, check, slack — what a fixer needs.05WORST PER CHECK AND CLOCKNever one figure: the worst path overall need not belong to a check youcan act on.06COUNT THE MARKERSMore startpoints than slacks means truncation; fewer means a missingheader.
Figure 1 — The extractor. Steps 1 to 3 recover one logical path from many lines; step 5 is the design decision the chapter is about; step 6 decides whether anything above it may be believed.

4. Why There Is No Single Worst Slack

The three groupings of the same five violations:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *Path Group:/ { g = $3 } /^ *Path Type:/ { ty = $3 } /^ *slack \(VIOLATED\)/ {
   c = (ty == "max" ? "setup" : "hold")
   if (!(c in wt) || $3 + 0 < wt[c]) wt[c] = $3 + 0; nt[c]++
   if (!(g in wg) || $3 + 0 < wg[g]) wg[g] = $3 + 0; ng[g]++
   k = c "/" g; if (!(k in wb) || $3 + 0 < wb[k]) wb[k] = $3 + 0; nb[k]++
   if ($3 + 0 < (ov == "" ? 1 : ov)) { ov = $3 + 0; ovc = c; ovg = g }
   g = ""; ty = "" }
 END { printf "  by check only: setup %.3f (n=%d), hold %.3f (n=%d)\n", wt["setup"], nt["setup"], wt["hold"], nt["hold"]
       printf "  by clock only: clk_core %.3f (n=%d), clk_io %.3f (n=%d), clk_ddr %.3f (n=%d)\n", wg["clk_core"], ng["clk_core"], wg["clk_io"], ng["clk_io"], wg["clk_ddr"], ng["clk_ddr"]
       printf "  worst overall: %.3f -- a %s check on %s\n", ov, ovc, ovg }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  by check only: setup -0.205 (n=3), hold -0.041 (n=2)
  by clock only: clk_core -0.112 (n=3), clk_io -0.023 (n=1), clk_ddr -0.205 (n=1)
  worst overall: -0.205 -- a setup check on clk_ddr

5. The Complete Script

Azvya Education Pvt. Ltd.VLSI Mentor
viol.awk — synthetic teaching script.
# viol.awk — timing violation extractor.
#
# Usage:  awk -f viol.awk timing.rpt
#         awk -v fmt=tsv -f viol.awk timing.rpt
# Exit:   0 no violations   1 violations present
#         2 the report's structure is inconsistent -- nothing can be trusted
#
# Design notes, each from a measured failure in Module 10:
#   - Carries the header forward and CLEARS IT on use; without the clear a
#     missing Startpoint line pairs two slacks with one register.   (10.2)
#   - Classifies pass/fail by the VERDICT WORD, never by the sign: a report
#     rounds a sub-precision violation to -0.000.                    (10.3)
#   - Separates setup (max) from hold (min). A stale Path Type reports hold
#     violations as setup and shows a design with no hold checks.    (10.4)
#   - Reports worst negative slack PER (check, clock), never one figure: the
#     worst path overall need not belong to a check you can act on.  (10.5)
#   - Counts the markers as a precondition; the DIRECTION of a mismatch names
#     the fault.                                                     (10.2 s8)

BEGIN { if (fmt == "") fmt = "table"; TOL = 1e-6 }

/^ *Startpoint:/ { s = $2; nstart++ }
/^ *Endpoint:/   { e = $2; nend++ }
/^ *Path Group:/ { g = $3 }
/^ *Path Type:/  { ty = $3 }

/^ *slack/ {
    nslack++
    if (NF < 3) { shape++; s = ""; e = ""; g = ""; ty = ""; next }

    word = $2; gsub(/[()]/, "", word)
    val = $3 + 0
    chk = (ty == "max" ? "setup" : (ty == "min" ? "hold" : "unknown"))
    if (chk == "unknown") shape++

    npath++
    if (word == "VIOLATED") {
        nviol++
        key = chk "/" (g == "" ? "<none>" : g)
        cnt[key]++
        if (!(key in worst) || val < worst[key]) { worst[key] = val; where[key] = e }
        if (!(key in kseen)) { kseen[key] = 1; korder[++nk] = key }
        row[nviol] = sprintf("%-20s %-20s %-9s %-6s %8.3f", (s == "" ? "<MISSING>" : s), (e == "" ? "<MISSING>" : e), g, chk, val)
        tsv[nviol] = sprintf("%s\t%s\t%s\t%s\t%.3f", s, e, g, chk, val)
    }
    s = ""; e = ""; g = ""; ty = ""
}

END {
    if (nslack == 0) { print "ERROR: no slack lines -- is this a timing report?" > "/dev/stderr"; exit 2 }
    if (nstart != nslack) {
        printf "ERROR: %d startpoint(s) but %d slack line(s) -- %s\n", nstart, nslack,
               (nstart > nslack ? "report looks truncated" : "a header line is missing") > "/dev/stderr"
        exit 2
    }
    if (nstart != nend) { printf "ERROR: %d startpoint(s) but %d endpoint(s)\n", nstart, nend > "/dev/stderr"; exit 2 }
    if (shape) { printf "ERROR: %d path(s) with an unreadable shape or unknown Path Type\n", shape > "/dev/stderr"; exit 2 }

    if (fmt == "tsv") {
        print "startpoint\tendpoint\tclock\tcheck\tslack"
        for (i = 1; i <= nviol; i++) print tsv[i]
    } else {
        printf "VIOLATED PATHS  (%d of %d)\n", nviol + 0, npath
        if (nviol) printf "  %-20s %-20s %-9s %-6s %8s\n", "startpoint", "endpoint", "clock", "check", "slack"
        for (i = 1; i <= nviol; i++) printf "  %s\n", row[i]

        print ""
        print "WORST NEGATIVE SLACK  (per check and clock -- never one figure)"
        printf "  %-18s %6s %9s  %s\n", "check/clock", "count", "worst", "endpoint"
        for (i = 1; i <= nk; i++) { k = korder[i]
            printf "  %-18s %6d %9.3f  %s\n", k, cnt[k], worst[k], where[k] }

        print ""
        printf "SUMMARY  paths=%d violating=%d groups=%d\n", npath, nviol + 0, nk + 0
    }
    if (nviol) exit 1
}

Two structural choices worth naming. All four preconditions run before any output, so a report that cannot be trusted produces a diagnostic and nothing else — a partial table is worse than none. And the rows are built into an array and printed in END, rather than streamed, because the (check, clock) summary cannot be computed until every path has been seen and the two must not be interleaved.

6. Running It

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk -f viol.awk timing.rpt
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
VIOLATED PATHS  (5 of 8)
  startpoint           endpoint             clock     check     slack
  u_regfile/dout_reg[3] u_alu/sum_reg[7]     clk_core  setup    -0.018
  u_dma/len_reg[4]     u_dma/cnt_reg[4]     clk_core  setup    -0.112
  u_alu/acc_reg[0]     u_alu/acc_reg[1]     clk_core  hold     -0.041
  u_io/pad_reg[0]      u_io/out_reg[0]      clk_io    hold     -0.023
  u_mem/rd_reg[0]      u_mem/dout_reg[0]    clk_ddr   setup    -0.205

WORST NEGATIVE SLACK  (per check and clock -- never one figure)
  check/clock         count     worst  endpoint
  setup/clk_core          2    -0.112  u_dma/cnt_reg[4]
  hold/clk_core           1    -0.041  u_alu/acc_reg[1]
  hold/clk_io             1    -0.023  u_io/out_reg[0]
  setup/clk_ddr           1    -0.205  u_mem/dout_reg[0]

SUMMARY  paths=8 violating=5 groups=4
status: 1

Four groups, four pieces of work. setup/clk_ddr at −0.205 is the largest number and setup/clk_core has twice as many paths — which of those is more urgent is an engineering judgement the script deliberately does not make.

The first row's startpoint overflows its column (u_regfile/dout_reg[3] is 21 characters in a 20-wide field), which %-20s does not truncate — it pushes the rest of the row right. That is the correct behaviour for a report a person reads: losing a character of a register name would be worse than losing the alignment.

The delimited form, for anything downstream:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk -v fmt=tsv -f viol.awk timing.rpt > viol.tsv
echo "status: $?"
head -3 viol.tsv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
status: 1
startpoint	endpoint	clock	check	slack
u_regfile/dout_reg[3]	u_alu/sum_reg[7]	clk_core	setup	-0.018
u_dma/len_reg[4]	u_dma/cnt_reg[4]	clk_core	setup	-0.112

Note the redirect rather than a pipe into head. Chapter 12.1 section 7 measured that $? after a pipeline is the last command's, and an earlier draft of this chapter reported status: 0 for exactly that reason — head succeeded while awk exited 1.

7. The Refusals

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'NR <= 100' timing.rpt > trunc.rpt
awk -f viol.awk trunc.rpt 2>&1 >/dev/null
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ERROR: 7 startpoint(s) but 6 slack line(s) -- report looks truncated
status: 2
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
grep -v 'Startpoint: u_dma' timing.rpt > nostart.rpt
awk -f viol.awk nostart.rpt 2>&1 >/dev/null
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ERROR: 7 startpoint(s) but 8 slack line(s) -- a header line is missing
status: 2

The direction of the mismatch names the fault — Chapter 10.2 section 8. More startpoints than slacks is a truncation; fewer is a missing header line, which is the condition that would otherwise pair two slacks with one register.

And a report with nothing wrong:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sed 's/(VIOLATED)/(MET)   /' timing.rpt | sed 's/\(slack (MET)   *\)-/\1 /' > clean.rpt
awk -f viol.awk clean.rpt | tail -2
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet

SUMMARY  paths=8 violating=0 groups=0
status: 0

Zero violations and status 0 — the case a gate needs to be able to return, and the one Chapter 8.7 argued must be demonstrated rather than assumed.

8. Every Decision and Its Source

decisionalternative that failsmeasured in
carry the header, clear on usetwo slacks pair with one startpoint10.2
classify by the verdict word-0.000 is a violation the report rounded10.3
guard NF < 3 before reading $3$NF on a valueless line is the verdict word10.3
Path Type for setup/holdthe slack sign cannot distinguish them10.4
clear ty toohold violations get reported as setup10.4
worst per (check, clock)one figure mixes incomparable quantities10.5
a count beside every extremuma misfiled value that is not the extremum vanishes10.4
insertion-ordered output arraysfor (k in …) has no defined order10.4
marker counts before any outputa partial table is worse than none10.2
redirect, not a pipe, when reading $?head replaces awk's status12.1

9. Common Mistakes

One worst-slack figure. It was a setup check here and a hold check in Module 10.5 — section 4.

Comparing setup against hold. Different causes, different fixes, frequency-independent in one case.

Classifying by the slack sign. A sub-precision violation prints as -0.000.

Not clearing the carried header. A missing line pairs two slacks with one register.

Not clearing Path Type. Hold failures are reported as setup and the design appears to have no hold checks.

Reporting a worst slack with no count. A misfiled value that is not the extremum leaves no trace.

Emitting rows before the preconditions run. A refusal has to refuse everything.

Piping into head when you need awk's status. Redirect instead — section 6.

10. Exercises

Exercise 1 — Violations by check

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk '/^ *Path Type:/ { ty = $3 } /^ *slack \(VIOLATED\)/ { c = (ty == "max" ? "setup" : "hold"); n[c]++; if (!(c in w) || $3 + 0 < w[c]) w[c] = $3 + 0; ty = "" }
 END { printf "  setup %d violation(s), worst %.3f\n  hold  %d violation(s), worst %.3f\n", n["setup"], w["setup"], n["hold"], w["hold"] }' timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  setup 3 violation(s), worst -0.205
  hold  2 violation(s), worst -0.041

Exercise 2 — The TSV stream

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk -v fmt=tsv -f viol.awk timing.rpt > v.tsv
awk -F'\t' 'NR > 1 { n++; if ($5 + 0 < w) { w = $5 + 0; k = $4 "/" $3 } } END { printf "  %d row(s); worst %.3f in %s\n", n, w, k }' v.tsv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  5 row(s); worst -0.205 in setup/clk_ddr

Five rows and the worst named with its group — the downstream consumer never needs to parse the formatted table.

Exercise 3 — Debug a report that is refused

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'NR <= 100' timing.rpt > trunc.rpt
awk '/^ *Startpoint:/ { ns++ } /^ *Endpoint:/ { ne++ } /^ *slack/ { nk++ } END { printf "  startpoints=%d endpoints=%d slack=%d\n", ns, ne, nk }' trunc.rpt
awk -f viol.awk trunc.rpt 2>&1 >/dev/null
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  startpoints=7 endpoints=7 slack=6
ERROR: 7 startpoint(s) but 6 slack line(s) -- report looks truncated

Seven paths started and six reached a slack line, so the eighth path's delay table was cut off. The counts are the diagnosis.

Exercise 4 — Debug hold violations reported as setup

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
grep -v 'Path Type: min' timing.rpt > noty.rpt
awk '/^ *Path Type:/ { ty = $3 } /^ *slack \(VIOLATED\)/ { c = (ty == "max" ? "setup" : (ty == "min" ? "hold" : "unknown")); n[c]++ } END { printf "  WITHOUT clearing ty: setup=%d hold=%d unknown=%d\n", n["setup"]+0, n["hold"]+0, n["unknown"]+0 }' noty.rpt
awk '/^ *Path Type:/ { ty = $3 } /^ *slack \(VIOLATED\)/ { c = (ty == "max" ? "setup" : (ty == "min" ? "hold" : "unknown")); n[c]++; ty = "" } END { printf "  WITH    clearing ty: setup=%d hold=%d unknown=%d\n", n["setup"]+0, n["hold"]+0, n["unknown"]+0 }' noty.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  WITHOUT clearing ty: setup=5 hold=0 unknown=0
  WITH    clearing ty: setup=3 hold=0 unknown=2

Five setup and no hold without the clear, on a report containing two hold violations — Chapter 10.4's result, reproduced here. With the clear they become unknown, which is honest: the information is not in the file.

The script itself refuses this report outright, because all three paths that lost their Path Type line trip its shape guard:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk -f viol.awk noty.rpt 2>&1 >/dev/null
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
ERROR: 3 path(s) with an unreadable shape or unknown Path Type
status: 2

Exercise 5 — Engineering application

Wiring it into a flow, with the three statuses routed:

Azvya Education Pvt. Ltd.VLSI Mentor
check_timing.sh — synthetic teaching script.
#!/bin/sh
# check_timing.sh — run the extractor and route the outcome.
#
# Two disciplines from Chapter 12.1 section 7:
#   - awk is NOT at the end of a pipeline, so $? is awk's own status.
#   - `status=$?` is captured on the line immediately after the command whose
#     status it is; everything afterwards uses the VARIABLE, not $?, which is
#     overwritten by every command in between.

awk -f viol.awk timing.rpt > timing_report.txt 2> timing_errors.txt
status=$?

awk -v fmt=tsv -f viol.awk timing.rpt > timing_viol.tsv 2>/dev/null
nviol=$(awk -F'\t' 'END { print NR - 1 }' timing_viol.tsv)

case $status in
  0) echo "TIMING CLEAN: no violated paths" ;;
  1) echo "TIMING VIOLATIONS: $nviol path(s); see timing_report.txt" ;;
  2) echo "TIMING REPORT UNUSABLE:"; cat timing_errors.txt ;;
  *) echo "EXTRACTOR FAILED (status $status)" ;;
esac
exit $status
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sh check_timing.sh
echo "status: $?"
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
TIMING VIOLATIONS: 5 path(s); see timing_report.txt
status: 1

Status 1 reaches the caller intact. Three things make that work, and all three were measured earlier: awk is not at the end of a pipeline, status is captured on the very next line, and the case reads the variable rather than $? — which by then belongs to the awk and the command substitution that ran in between.

On a report the extractor refuses:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk 'NR <= 100' timing.rpt > trunc.rpt
cp timing.rpt timing_full.rpt && cp trunc.rpt timing.rpt
sh check_timing.sh
echo "status: $?"
cp timing_full.rpt timing.rpt
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
TIMING REPORT UNUSABLE:
ERROR: 7 startpoint(s) but 6 slack line(s) -- report looks truncated
status: 2

The flow gets 2 and the diagnostic, rather than a violation count computed from a truncated report. The file is swapped back afterwards so the remaining fences see the full report — a chapter's fixtures are shared state, which is itself a reason a real script takes its input path as an argument rather than hardcoding it.

Exercise 6 — Challenge: show that the four groups cannot be reduced to one number

The script reports four (check, clock) groups. Show that no single figure derived from them preserves what a reviewer needs.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk -v fmt=tsv -f viol.awk timing.rpt > v.tsv 2>/dev/null
awk -F'\t' 'NR > 1 { n++; s += $5; if (NR == 2 || $5 + 0 < mn) mn = $5 + 0; k = $4 "/" $3; c[k]++ }
 END { printf "  count            %d\n", n
       printf "  minimum          %.3f\n", mn
       printf "  mean             %.3f\n", s / n
       printf "  sum              %.3f\n", s
       m = 0; for (g in c) m++
       printf "  distinct groups  %d\n", m }' v.tsv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  count            5
  minimum          -0.205
  mean             -0.080
  sum              -0.399
  distinct groups  4

Five candidate headlines, and each loses the thing that matters:

  • count = 5 — five paths to fix, with no idea whether that is one problem or four.
  • minimum = -0.205 — the worst number, which belongs to setup/clk_ddr and says nothing about the two setup/clk_core paths or either hold failure.
  • mean = -0.080 — averages a setup failure on one clock against a hold failure on another. Chapter 11.8's error exactly.
  • sum = -0.399 — has no physical meaning at all; slacks do not add.
  • distinct groups = 4 — the most honest single number, and it still omits every magnitude.

What a reviewer needs is the mapping from group to worst slack and count, which is a relation of four rows. Chapter 13.1 Exercise 6 reached the same conclusion about failure signatures: some findings are relations, not figures, and a reduction that insists on one number has to discard one of the two axes.

The practical compromise, when a single cell is unavoidable, is the one Chapter 11.8 section 6 recommended — name the governing group rather than blend:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
awk -F'\t' 'NR > 1 { k = $4 "/" $3; if (!(k in w) || $5 + 0 < w[k]) w[k] = $5 + 0; c[k]++ }
 END { for (k in w) if (bk == "" || w[k] < bw) { bw = w[k]; bk = k }
       printf "  governing group: %s at %.3f over %d path(s)\n", bk, bw, c[bk] }' v.tsv
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  governing group: setup/clk_ddr at -0.205 over 1 path(s)

"setup/clk_ddr, −0.205, 1 path" survives being questioned: it names the check, the clock, the magnitude and how much work it represents, and it is reproducible. −0.205 alone does not.

11. Summary

  • Three outputs: the violated-path rows, the count against the path count, and the worst slack — which is the one with a decision in it.
  • There is no single worst slack. It was a setup check on clk_ddr here and a hold check in Module 10.5; the answer is a property of the report.
  • Setup and hold are not comparable — different causes, different fixes, and hold is frequency-independent.
  • Report per (check, clock) with a count — four rows here, four pieces of work.
  • Carry the header and clear it; classify by the verdict word, not the sign; guard NF < 3 before reading $3.
  • Clear Path Type too. Without it this report shows 5 setup and 0 hold violations while containing 2 hold failures.
  • Run every precondition before any output. A refusal must refuse the whole table.
  • The direction of a marker mismatch names the fault — truncation against a missing header.
  • Redirect rather than pipe when you need awk's status, and capture $? immediately — Exercise 5's script exited 5 instead of 1 because a command substitution overwrote it.
  • Some findings are relations, not figures. Count, minimum, mean, sum and group count each discard what a reviewer needs; naming the governing group is the honest single cell.

Chapter 13.3 — Project: Coverage Summary Generator builds the third script: per-block coverage aggregated the way the tool weights it, the blocks below target flagged, and both a readable table and a CSV from one pass.

Where this fits

Part of the awk curriculum.