Skip to content
VLSI Mentor

Perl Part II · Module 23 · Static Timing Analysis Report Parsing

Startpoint, Endpoint and Path Group

A slack value on its own is a number nobody can act on. The same number attached to an endpoint, a path group and a path type can be routed to a block owner, checked against a constraint, and read correctly even when it is positive and failing. This chapter captures those fields, shows the two different groupings one set of violations supports, and measures the two fields whose format quietly defeats the pattern most people write for them.

Intermediate11 min readPerlPart IISTA Reports

Part II · Module 23 · Chapter 23.4 · Startpoint, Endpoint and Path Group

1. Six Paths, Five Fields

Azvya Education Pvt. Ltd.VLSI Mentor
attribute.pl
use strict;
use warnings;

# attribution.pt.rpt uses slack VALUES from the generated corner reports with
# startpoints, path groups and path types that exercise attribution: two
# cores, an input-port startpoint, a **default** group, a hold (min) path and
# a generated-clock group.
my $RPT = "reports/attribution.pt.rpt";
open my $fh, "<", $RPT or die "$RPT: $!";
local $/;
my $text = <$fh>;
close $fh;

my ($corner) = $text =~ /^Corner[ \t]*:[ \t]*(\S+)/m;     # 23.1: from the HEADER
my @blocks = split /(?=^[ \t]*Startpoint:)/m, $text;
shift @blocks while @blocks && $blocks[0] !~ /Startpoint:/;

my %F = (
  startpoint => qr/^[ \t]*Startpoint:[ \t]*(\S+)/m,
  endpoint   => qr/^[ \t]*Endpoint:[ \t]*(\S+)/m,
  group      => qr/^[ \t]*Path Group:[ \t]*(\S+)/m,
  type       => qr/^[ \t]*Path Type:[ \t]*(\S+)/m,
);
my $SLACK = qr/^[ \t]*slack[ \t]*(?:\((\w+)\))?[ \t]*(-?[\d.]+|INFINITY)[ \t]*$/m;

# the BLOCK of a path: the leading hierarchy of its endpoint
sub block_of {
    my ($ep) = @_;
    my @parts = split m{/}, $ep;
    return @parts > 2 ? join("/", @parts[0 .. $#parts - 2]) : "(top)";
}

my @paths;
for my $b (@blocks) {
    my %p = (corner => $corner);
    $p{$_} = ($b =~ $F{$_})[0] for keys %F;
    my ($ann, $val) = $b =~ $SLACK;
    @p{qw(annot slack)} = ($ann, $val);
    $p{block} = block_of($p{endpoint} // "");
    push @paths, \%p;
}

printf "corner from the header: %s\n", $corner;
printf "%d path(s)\n\n", scalar @paths;
printf "%-14s %-14s %-12s %-5s %-9s %-9s %s\n",
    "STARTPOINT", "ENDPOINT", "GROUP", "TYPE", "ANNOT", "SLACK", "BLOCK";
printf "%-14s %-14s %-12s %-5s %-9s %-9s %s\n",
    $_->{startpoint}, $_->{endpoint}, $_->{group}, $_->{type},
    $_->{annot}, $_->{slack}, $_->{block} for @paths;

# ---- what each field lets you answer
print "\nviolations grouped BY PATH GROUP:\n";
my %by_group;
push @{ $by_group{ $_->{group} } }, $_ for grep { $_->{annot} eq "VIOLATED" } @paths;
printf "  %-12s %d: %s\n", $_, scalar @{ $by_group{$_} },
    join(", ", map { $_->{endpoint} } @{ $by_group{$_} }) for sort keys %by_group;

print "\nviolations grouped BY BLOCK (from the endpoint hierarchy):\n";
my %by_block;
push @{ $by_block{ $_->{block} } }, $_ for grep { $_->{annot} eq "VIOLATED" } @paths;
printf "  %-12s %d: %s\n", $_, scalar @{ $by_block{$_} },
    join(", ", map { $_->{endpoint} } @{ $by_block{$_} }) for sort keys %by_block;

print "\nand BY PATH TYPE, which is what separates setup from hold:\n";
my %by_type;
$by_type{ $_->{type} }++ for @paths;
printf "  %-5s %d path(s)\n", $_, $by_type{$_} for sort keys %by_type;
my @hold_viol = grep { $_->{type} eq "min" && $_->{annot} eq "VIOLATED" } @paths;
printf "  hold (min) violations: %d -- %s\n", scalar @hold_viol,
    join(", ", map { "$_->{endpoint} slack=$_->{slack}" } @hold_viol);
print "  note the POSITIVE slack on a VIOLATED hold path (23.3), which is\n";
print "  only interpretable because Path Type was captured.\n";

# ---- the fields that are NOT a plain token
print "\nfields that are not a plain token:\n";
my @dflt = grep { $_->{group} eq "**default**" } @paths;
printf "  a path group can be '%s' -- asterisks, not a name\n",
    (@dflt ? $dflt[0]{group} : "none here");
print "  so a /^(\\w+)\$/ pattern on the group drops it, and the paths in the\n";
print "  default group are the UNCONSTRAINED ones most worth seeing.\n";
my @port = grep { $_->{startpoint} !~ m{/} } @paths;
printf "  a startpoint can be an input PORT with no '/': %s\n",
    (@port ? $port[0]{startpoint} : "none here");
print "  so a pattern requiring inst/pin drops input-to-flop paths entirely.\n";
Azvya Education Pvt. Ltd.VLSI Mentor
Captured output
corner from the header: slow_0v90_125c
6 path(s)

STARTPOINT     ENDPOINT       GROUP        TYPE  ANNOT     SLACK     BLOCK
core0/bit1/Q   core0/bit3/D   clk          max   VIOLATED  -0.0900   core0
core0/bit0/Q   core0/bit2/D   clk          max   MET       0.0925    core0
core1/bit1/Q   core1/bit3/D   clk          max   VIOLATED  -0.0900   core1
enable         core0/bit0/D   **default**  max   MET       0.4650    core0
core0/bit0/Q   core0/bit0/D   clk          min   VIOLATED  0.0120    core0
clk_gate/ECK   core1/bit2/D   gclk         max   MET       0.2750    core1

violations grouped BY PATH GROUP:
  clk          3: core0/bit3/D, core1/bit3/D, core0/bit0/D

violations grouped BY BLOCK (from the endpoint hierarchy):
  core0        2: core0/bit3/D, core0/bit0/D
  core1        1: core1/bit3/D

and BY PATH TYPE, which is what separates setup from hold:
  max   5 path(s)
  min   1 path(s)
  hold (min) violations: 1 -- core0/bit0/D slack=0.0120
  note the POSITIVE slack on a VIOLATED hold path (23.3), which is
  only interpretable because Path Type was captured.

fields that are not a plain token:
  a path group can be '**default**' -- asterisks, not a name
  so a /^(\w+)$/ pattern on the group drops it, and the paths in the
  default group are the UNCONSTRAINED ones most worth seeing.
  a startpoint can be an input PORT with no '/': enable
  so a pattern requiring inst/pin drops input-to-flop paths entirely.

Five fields per path, and the fifth is not in the path block at all:

Startpoint and endpoint — where the path launches and captures.

Path group — which constraint claims it.

Path type — max for setup, min for hold. Section 3 is about this one.

The corner, read from the report header exactly as Chapter 23.1 established, and attached to every path the block yields.

2. One Set Of Violations, Two Groupings

The same three violated endpoints support two different questions:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
violations grouped BY PATH GROUP:
  clk          3: core0/bit3/D, core1/bit3/D, core0/bit0/D

violations grouped BY BLOCK:
  core0        2: core0/bit3/D, core0/bit0/D
  core1        1: core1/bit3/D

By path group is a constraint question. All three failures are in the clk group, which says the clock period or its uncertainty is the thing under pressure — not that any one block is at fault.

By block is an ownership question. Two failures in core0, one in core1, which is how the work gets assigned.

Neither grouping is derivable from the other, and the second one is not a field the report prints. It comes from the endpoint's hierarchy:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
sub block_of {
    my ($ep) = @_;
    my @parts = split m{/}, $ep;
    return @parts > 2 ? join("/", @parts[0 .. $#parts - 2]) : "(top)";
}

The last two components of core0/bit3/D are the instance and the pin, so everything before them is the enclosing hierarchy. Chapter 11.14's split on a literal / — and the @parts > 2 guard is what keeps a top-level endpoint like bit0/D from producing an empty block name.

That derivation is an assumption about naming, and it is worth being honest that it is one: a flat netlist has no hierarchy in its endpoint names, and Chapter 20.4's point applies — the hierarchy was in the netlist, and a post-flatten report has thrown it away.

3. Path Type Makes A Hold Slack Readable

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
by PATH TYPE: max 5, min 1
hold (min) violations: 1 -- core0/bit0/D slack=0.0120

A violated hold path with a slack of +0.0120. Chapter 23.3 measured that the sign rule cannot handle this, and Path Type is the field that explains why: the number in a min path's slack line is a different quantity, and max and min paths cannot be compared, sorted together, or thresholded with one rule.

Three practical consequences:

Never mix them in one worst-slack list. A min path with slack 0.0120 and a max path with slack 0.0120 are not equally close to failing — one is failing.

Report them as two populations. setup: 2 violated of 5 ; hold: 1 violated of 1 is readable; 3 violated of 6 hides that a hold failure is present.

Capture Path Type even when you only care about setup, so you can exclude hold paths rather than silently averaging them in. A parser that ignores the field is not setup-only — it is both, mixed.

4. Two Fields That Are Not Plain Tokens

The last block of the measurement is the pattern trap:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
a path group can be '**default**' -- asterisks, not a name
a startpoint can be an input PORT with no '/': enable

**default** is what a tool calls the group for paths no constraint claimed. A pattern of /^[ \t]*Path Group:[ \t]*(\w+)/ matches nothing on that line, so those paths get no group — and the default group is precisely where the unconstrained paths live, which Chapter 23.2 established are among the most valuable findings in the report. The pattern drops the rows most worth having.

(\S+) is the fix, and it is the right level of permissiveness: a group name is one whitespace-delimited token, whatever characters it contains.

A bare port startpoint — enable, with no / — breaks any pattern that requires an instance-and-pin shape. Input-to-flop paths are a whole category (they are where set_input_delay lands), and a parser built around (\S+)/(\S+) loses all of them.

5. What To Remember

  • A slack value alone is a number nobody can act on.
  • Five fields per path: startpoint, endpoint, path group, path type — and the corner, from the report header (23.1).
  • Measured: the same 3 violations group two useful ways — by path group and by block.
  • By path group is a constraint question: all three in clk points at the period, not at a block.
  • By block is an ownership question, and that is how work gets assigned.
  • The block is NOT a field the report prints — derive it from the endpoint's hierarchy with split m{/}.
  • Guard the derivation (@parts > 2), or a top-level endpoint yields an empty block name.
  • A flattened report has no hierarchy in its names — the derivation assumes the netlist kept it (20.4).
  • Measured: a VIOLATED hold path with slack +0.0120.
  • Path Type is what makes that readable — min and max slacks are different quantities (23.3).
  • Never sort or threshold min and max paths together, and report them as two populations.
  • Capture Path Type even if you only want setup, so hold paths can be excluded rather than mixed in.
  • A path group can be **default** — asterisks defeat \w+, and the default group holds the unconstrained paths.
  • A startpoint can be a bare input port with no / — a pattern requiring inst/pin loses every input-to-flop path.
  • Capture as (\S+), interpret afterwards — the same fix as 22.3's cell names and 20.2's escaped identifiers.
  • \w+ reads like "a name" and means letters, digits and underscore — EDA tools use slashes, dots, hyphens, brackets and asterisks.

Chapter 23.5 moves from paths to the clocks they are measured against. A per-clock inventory is what a constraint review starts from, and it has to be built from two files that disagree about what a clock is.

Where this fits

Part of the Perl curriculum.