Skip to content
VLSI Mentor

Tcl · Module 24

Parsing an Area Report

Every field sits on its own line, so no state is needed and the regexps are simple. What is not simple is making two runs' numbers comparable — and noticing the field that is not a number at all.

Intermediate17 min readtcledapart-iireportsarearegex

Part II · Module 24 · Chapter 24.2 · Parsing an Area Report

Area is the simplest report in the flow to parse. Every value sits on its own line, labelled, with nothing to pair it against — so none of Chapter 24.1 §4's state machinery is needed.

It is also the report people compare most carelessly, which is where this chapter spends its time.

1. The parser

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc parse_area {path} {
    set fh [open $path r]
    set a [dict create]
    while {[gets $fh line] >= 0} {
        if {[regexp {^Combinational area:\s+(\d+\.?\d*)}    $line -> v]} { dict set a combinational $v }
        if {[regexp {^Noncombinational area:\s+(\d+\.?\d*)} $line -> v]} { dict set a sequential    $v }
        if {[regexp {^Buf/Inv area:\s+(\d+\.?\d*)}          $line -> v]} { dict set a bufinv        $v }
        if {[regexp {^Macro/Black Box area:\s+(\d+\.?\d*)}  $line -> v]} { dict set a macro         $v }
        if {[regexp {^Total cell area:\s+(\d+\.?\d*)}       $line -> v]} { dict set a total         $v }
        if {[regexp {^Number of (\S+) cells:\s+(\d+)}       $line -> k n]} { dict set a cells_$k    $n }
    }
    close $fh
    return $a
}
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== area, as data ===
    bufinv               6190.144531
    cells_combinational  11908
    cells_sequential     4318
    combinational        41820.726562
    macro                88000.000000
    sequential           29447.281250
    total                159268.007812

The report is a teaching mock written for this module — its own Version: line says so, and field names differ between tools and releases. The technique is what transfers.

Three details worth naming.

^ on every pattern. Combinational area: also appears inside Noncombinational area:, so an unanchored pattern for the first would match the second line too — and since the if chain has no continue, both assignments would fire, leaving combinational holding the sequential number. Anchoring is not stylistic here; it is the difference between right and wrong. (The reason there is no continue is §2.)

(\d+\.?\d*) not (\d+\.\d+). Cell counts are integers and areas are floats, and \.?\d* accepts both. A pattern demanding a decimal point silently skips every integer field — the Number of lines above.

dict set a cells_$k $n builds the key from the match. One pattern captures combinational and sequential from the label itself, giving cells_combinational and cells_sequential without a line per field. Chapter 7.2 is the mechanism; the idea is that a report with a regular label format can often be parsed with fewer patterns than it has fields.

2. Why there is no continue here

Chapter 24.1 §4 put continue after every match, because a line that is a Startpoint: cannot also be a slack line.

Here the patterns are mutually exclusive by their anchored labels, so continue would be correct but would buy nothing except speed — and leaving it out makes the overlap hazard in §1 visible rather than hidden behind an early exit. In a real parser with dozens of fields, add the continue: it both documents exclusivity and stops a misanchored pattern from doing damage.

3. The field whose value is not a number

Real area reports contain this:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== the field that is not a number ===
    report says : 'Net Interconnect area:           undefined  (Wire load has zero net area)'
    parsed key 'interconnect' exists : 0
    numeric pattern matched          : 0

Two habits follow, and they are the same two from Chapter 7.3:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc area_field {a key} {
    if {![dict exists $a $key]} {
        error "area report did not supply '$key'" {} [list RPT MISSINGFIELD $key]
    }
    return [dict get $a $key]
}

Ask before reading, and raise with the report's vocabulary rather than the dictionary's. area report did not supply 'interconnect' points at the file; key not known in dictionary points at your data structure.

And if the field is genuinely optional, say so explicitly with a default rather than discovering it is missing:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set ic [expr {[dict exists $a interconnect] ? [dict get $a interconnect] : 0.0}]

The honest caveat: a default of 0.0 for interconnect area is defensible only because undefined here means there is no wire load model, so the true value is not merely unknown — it is absent from the model. A default that papers over a genuinely unknown number is worse than the error it replaced.

4. Cross-check the parse for free

The report prints both the parts and the total, so the parse can check itself:

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
set c [dict get $a combinational] ; set s [dict get $a sequential]
set m [dict get $a macro]         ; set t [dict get $a total]
puts [format "    comb + seq + macro : %.6f" [expr {$c + $s + $m}]]
puts [format "    total cell area    : %.6f" $t]
puts [format "    difference         : %.6f" [expr {$c + $s + $m - $t}]]
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
=== the arithmetic the report does not print ===
    comb + seq + macro : 159268.007812
    total cell area    : 159268.007812
    difference         : 0.000000
    sequential share   : 18.5% of total
    buf/inv share      : 14.8% of combinational

difference : 0.000000 to the last digit. That is not decoration — it is a correctness test of the parse that costs nothing and needs no reference data.

If a pattern had picked up the wrong line, matched a truncated number (Chapter 24.1 §7's greediness trap), or missed a component, the sum would not land on the total. A report that states a total next to its parts hands you a free assertion, and Chapter 24.7 generalises exactly this into the module's closing idea.

Note that bufinv is deliberately not in the sum. Buffers and inverters are combinational cells, so their area is already inside combinational — adding it would double-count. Knowing which reported figures are components and which are subsets of other components is report knowledge, not Tcl knowledge, and getting it wrong produces a cross-check that fails on a correct parse.

5. The numbers the report does not print

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
puts [format "    sequential share   : %.1f%% of total" [expr {100.0 * $s / $t}]]
puts [format "    buf/inv share      : %.1f%% of combinational" [expr {100.0 * [dict get $a bufinv] / $c}]]

Those two ratios are the reason to parse an area report at all, because they are what a human actually wants:

  • Sequential share, 18.5%. Flip-flop area is the floor — optimisation moves combinational logic, not registers. A design that is mostly registers has little headroom, and the number tells you before you spend a week finding out.
  • Buf/inv share of combinational, 14.8%. Buffers do no logic; they exist to drive loads. A high share says the design is spending area on distribution rather than computation, which usually points at high-fanout nets or a floorplan that makes everything far apart.

Neither appears in the report. Both are one division away once the fields are in a dict.

6. What makes two runs comparable

The registry's phrase for this chapter is "values a script can compare between runs", and the comparison is where the real mistakes live.

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
proc compare_area {before after} {
    foreach k {combinational sequential macro total} {
        set b [dict get $before $k] ; set a [dict get $after $k]
        set d [expr {$a - $b}]
        puts [format "    %-14s %14.3f -> %14.3f   %+10.3f  %+6.2f%%" \
                  $k $b $a $d [expr {100.0 * $d / $b}]]
    }
}

The arithmetic is trivial. The preconditions are not, and most of them cannot be checked from the area report:

  • Same technology library. Area is in library units. Two runs against different libraries produce numbers that subtract cleanly and mean nothing. The report names its library — capture that string and compare it too, before comparing any number.
  • Same tool release. What counts as combinational area has changed across releases of real tools. The Version: line is worth parsing for the same reason.
  • Cell area, not total area. Total cell area is the sum of the cells. Total area includes interconnect estimates and in this report is undefined. Comparing one run's cell area against another's total area is a comparison nobody intends and nothing prevents.
  • Same design intent. A 3% area increase accompanying a timing fix is a trade, not a regression. The area number alone cannot tell you which.

7. Exercises

Exercise 1. Why must ^ anchor the Combinational area: pattern?

Exercise 2. Why (\d+\.?\d*) rather than (\d+\.\d+)?

Exercise 3. What does the parser do with Net Interconnect area: undefined, and where does the problem surface?

Exercise 4. Why raise area report did not supply 'interconnect' rather than letting dict get raise?

Exercise 5. Why is bufinv excluded from the sum that cross-checks the total?

Exercise 6. What does difference : 0.000000 actually test?

Exercise 7. Name two preconditions for comparing area between runs that the area report cannot verify on its own.

Exercise 8. Why is a 3% area increase not necessarily a regression?

Where this fits

Part of the Tcl curriculum.