Skip to content
VLSI Mentor

Tcl · Module 16

Tcl, Bash and Python: Which Does What

This is not a question of taste. Only one of the three can talk to the design database, only one is good at starting processes, and only one is pleasant for arithmetic over a pile of reports.

Foundation18 min readtclbashpythonedapart-iiautomation

Part II · Module 16 · Chapter 16.3 · Tcl, Bash and Python: Which Does What

You will meet this argument in every team, usually phrased as which language is better. That framing has no answer, because the three are not competing for the same job.

The useful framing is three prepositions:

Tcl runs inside the tool. Bash runs around it. Python runs over the data it produced.

Each describes a different relationship to the tool process, and that relationship — not preference — decides which you use.

1. The division

Three stages left to right. Bash runs around the tool, launching runs and reading exit statuses. Tcl runs inside the tool, where it can query the design database and decide what to do. Python runs over the data afterwards, reading the reports the run wrote and computing statistics across them.Around the toolBash — launch runs, readexit statusesInside the toolTcl — query the design,decide, reportOver the dataPython — statistics acrossmany runs12
Figure 1 — the three languages and where each one sits relative to the tool. Bash starts the tool and reads its exit status. Tcl runs inside the tool, where the design database is. Python reads the files the run produced, after it has finished.

The arrows are the real sequence: Bash starts the tool, the tool runs your Tcl, the Tcl leaves files behind, and Python reads them afterwards.

2. The example

Three blocks, each timed, one of which fails. Each language does its own part, and all three of the scripts below really ran.

The only thing stubbed is the tool command itself — report_timing_stub reads a file instead of analysing a design, because no EDA tool exists here. Everything around it is real.

3. Tcl, inside

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
# inside.tcl — the shape of a script that runs INSIDE the tool.
proc report_timing_stub {block} {
    # a real tool would compute this from the design database
    set fp [open "runs/$block/timing.rpt" r]
    set d [dict create]
    while {[gets $fp line] >= 0} {
        if {[llength $line] == 2} { lassign $line k v ; dict set d $k $v }
    }
    close $fp
    return $d
}

set block [lindex $argv 0]
set d [report_timing_stub $block]
puts "  $block: worst_slack [dict get $d worst_slack], violations [dict get $d violations]"
if {[dict get $d violations] > 0} { exit 1 }
exit 0
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  cpu_top: worst_slack 0.142, violations 0
    [exit status 0]
  fifo_ctrl: worst_slack -0.067, violations 14
    [exit status 1]
  alu_core: worst_slack 0.031, violations 0
    [exit status 0]

Why this part must be Tcl: it is the only one that can be inside the tool. The design database lives in the tool's process, and the only way to ask it anything is through the interpreter the tool embedded. Bash cannot reach it. Python cannot reach it. No amount of preference changes that.

Note what the script ends with: an exit status, from Chapter 15.4. That is the interface to the next layer.

4. Bash, around

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
#!/bin/bash
# around.sh — the shape of a script that runs AROUND the tool.
# It never looks inside a report; it launches runs and reads exit statuses.
failed=0
for block in cpu_top fifo_ctrl alu_core; do
    if tclsh inside.tcl "$block" > "runs/$block/run.log" 2>&1; then
        echo "  $block: PASS"
    else
        echo "  $block: FAIL (see runs/$block/run.log)"
        failed=$((failed + 1))
    fi
done
echo "  $failed block(s) failed"
[ "$failed" -eq 0 ] || exit 1
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  cpu_top: PASS
  fifo_ctrl: FAIL (see runs/fifo_ctrl/run.log)
  alu_core: PASS
  1 block(s) failed
  [exit status 1]

Why this part is Bash: starting processes, redirecting output to log files, and branching on exit statuses is what a shell is for. The whole loop is five lines because every one of those operations is a primitive.

Notice it never opens timing.rpt. It does not know what a slack is. It knows tclsh inside.tcl cpu_top either succeeded or did not — which is exactly the contract the Tcl script's exit established, and precisely why that status had to be honest.

5. Python, over

Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
#!/usr/bin/env python3
"""Runs OVER the data the tool produced. It never talks to the tool."""
import pathlib, statistics

rows = []
for rpt in sorted(pathlib.Path("runs").glob("*/timing.rpt")):
    d = dict(line.split() for line in rpt.read_text().split("\n") if len(line.split()) == 2)
    rows.append((d["block"], float(d["worst_slack"]), int(d["endpoints"]), int(d["violations"])))

print(f"  {'block':<12}{'slack':>9}{'endpoints':>11}{'viol':>6}")
for b, s, e, v in rows:
    print(f"  {b:<12}{s:>9.3f}{e:>11,}{v:>6}")
slacks = [s for _, s, _, _ in rows]
print(f"  worst  {min(slacks):+.3f}   mean {statistics.mean(slacks):+.3f}   "
      f"total endpoints {sum(e for _,_,e,_ in rows):,}   total violations {sum(v for _,_,_,v in rows)}")
Azvya Education Pvt. Ltd.VLSI Mentor
Snippet
  block           slack  endpoints  viol
  alu_core        0.031      7,733     0
  cpu_top         0.142     18,422     0
  fifo_ctrl      -0.067      2,910    14
  worst  -0.067   mean +0.035   total endpoints 29,065   total violations 14

Why this part is Python: by the time you want a mean, a sort by severity, a comparison against last week and a thousand-separated total, you want a language with a standard library for exactly that. statistics.mean, the :, thousands separator and the glob are all one-liners.

The same work in Tcl is possible and unpleasant — and it has no reason to be in Tcl, because the tool has already exited. The data is on disk. Nothing about it requires the design database.

6. How to decide

Three questions, in order. The first one that applies decides it:

  1. Does it need the design database? Only Tcl can reach it. Anything that queries cells, ports, timing or physical data is Tcl, inside the tool.
  2. Does it start, sequence or supervise processes? That is the shell's job — Bash, Make, or a scheduler.
  3. Is it computation over data already on disk? Python, after the tool has exited.
JobLanguageWhy
Query the netlistTclonly it is inside the tool
Apply constraintsTclthe commands exist only there
Decide whether to continue mid-flowTclneeds the tool's state
Launch forty runsBash / Makeprocess management
Retry a failed jobBash / schedulerreads exit statuses
Move, archive, clean up filesBashfile primitives
Statistics across runsPythonstandard library
Compare two weeks of resultsPythondata structures
Charts, spreadsheets, dashboardsPythonlibraries exist

7. Where the argument comes from

The disagreement is usually about a real frustration pointed at the wrong target.

Someone who dislikes Tcl is often describing a four-thousand-line flow script that does string processing, report parsing and statistics in the hardest possible language for those things. They are right that it is painful. The fix is not a different language inside the tool — that is not on offer. The fix is to move the parts that do not need the tool out of it.

Someone who wants to do everything in Python usually has not hit the wall yet: the design database is not reachable from outside the tool process. You can call the tool from Python, but what runs inside it is still Tcl.

You do not choose. You use all three, and the skill is knowing which part of the problem belongs where.

8. A practical rule for your own scripts

When a Tcl flow script starts to grow, ask of each section: does this line need the tool to be running?

  • Querying the design, applying a constraint, reading a timing path — yes.
  • Formatting a table, computing an average, deciding which of fifty runs was worst — no.

Write the first kind in Tcl. Have it emit a small, machine-readable file — one name value pair per line is enough, as in this chapter's example. Then let the tool exit, and do the second kind outside.

That one habit keeps Tcl scripts short, keeps tool licences free, and makes the analysis testable without a tool licence at all.

9. Exercises

Exercise 1. Give the one-line division of labour in three prepositions.

Exercise 2. Why can the design query not be done in Python?

Exercise 3. The Bash script never opens timing.rpt. What does it use instead, and why is that better?

Exercise 4. Name two reasons not to compute statistics inside the tool.

Exercise 5. Which language launches forty runs and retries the failures?

Exercise 6. A colleague says Tcl is a bad language, citing a 4,000-line flow script. What is actually wrong?

Exercise 7. What two things form the interface between the three layers?

Where this fits

Part of the Tcl curriculum.