Tcl · Module 17
Tcl Embedded in an EDA Tool
You are dropped at an unfamiliar tool prompt. Three commands tell you what interpreter you are in and what it can do — and one property of tool commands explains most of the confusion that follows.
Intermediate17 min readtcledapart-iitool-shellsinfo-commandsstate
Part II · Module 17 · Chapter 17.1 · Tcl Embedded in an EDA Tool
Chapter 16.1 argued why vendors embed Tcl. This chapter is the practical consequence: you are sitting at a tool prompt you have not used before. What do you type to find out what you have?
And once you know, there is one property of tool commands that is not true of anything in Part I, and getting it wrong is the source of most "but it worked yesterday" confusion.
1. The definition, precisely
A tool shell is a standard Tcl interpreter, plus extra commands, plus extra state.
All three parts matter, and the third is the one people skip.
2. What does not change
Everything from Part I. The parsing rules from Module 2, substitution happening once, foreach and lsort and catch and regexp, procedures, namespaces, exit and its status.
Chapter 16.1 §5 demonstrated this directly: the same standard-Tcl work produced byte-identical output with and without tool commands present. You do not relearn the language. You learn a command set.
3. Finding out what you have
Three questions, three commands. This is the introspection from Chapter 14.10, and it is the single most useful thing to know at an unfamiliar prompt.
Everything below is real output from a teaching mock — toolshell.tcl, a few dozen lines of ordinary Tcl that registers some design-query commands into a plain interpreter. It is not a real tool. The technique is what transfers.
puts " info tclversion : [info tclversion]"
puts " info patchlevel : [info patchlevel]"
puts " info commands set* : [lsort [info commands set*]]"
puts " info commands report_* : [lsort [info commands report_*]]"
puts " info commands get_* : [lsort [info commands get_*]]"
puts " info commands *design* : [lsort [info commands *design*]]" info tclversion : 8.5
info patchlevel : 8.5.9
info commands set* : set
info commands report_* : report_area report_design report_ports
info commands get_* : get_cells get_ports
info commands *design* : current_design read_design report_designRead those six lines as a procedure you can follow anywhere:
info tclversiontells you which language features you have. This matters:try,lmapanddict mapneed 8.6, and plenty of tools ship an 8.5-era interpreter, exactly as Chapter 14.5 §4 warned. Check before you rely on one.info patchlevelis the full version, for a bug report.info commands <pattern>is the discovery tool. A glob over the command set answers "what can this thing do" far faster than any manual.
4. The part that is genuinely different: state
Here is the property no Part I command has.
puts " before loading:"
puts " current_design -> [catch {current_design} e] / $e"
puts " get_cells * -> [catch {get_cells *} e] / $e"
read_design cpu.design
puts " after read_design cpu.design:"
puts " current_design -> [current_design]"
puts " get_cells * -> [get_cells *]"
puts " report_area -> [report_area]" before loading:
current_design -> 1 / no design loaded
get_cells * -> 1 / no design loaded
after read_design cpu.design:
current_design -> cpu_top
get_cells * -> u_fifo u_alu u_ctrl u_decode
report_area -> cells: 4The same command, with the same arguments, raised at one moment and answered at another. Nothing about the command changed; the state behind it did.
Contrast an ordinary Tcl command:
llength $l -> 3
llength $l -> 3 (same input, same answer, always)5. Reading the error when state is wrong
no design loaded is the shape of message you will meet constantly, in many wordings. It is worth recognising as a category rather than as individual errors, because the fix is always the same kind of thing: something earlier in the flow did not happen.
Because these arrive as ordinary Tcl errors, everything from Module 14 applies — they unwind, they can be caught, and they carry a stack trace. So a flow script can check its preconditions rather than discovering them:
proc require_design {} {
if {[catch {current_design} d]} {
error "no design is loaded — did an earlier stage fail?" {} {FLOW NODESIGN}
}
return $d
}That is Chapter 14.11's boundary check, applied to tool state instead of to data.
6. The session is long-lived
One more difference from tclsh. A script you run with tclsh script.tcl starts an interpreter, runs, and exits — the state dies with it.
A tool session typically stays alive across many commands: you load a design once and then work on it for an hour, or a batch run executes a long sequence of stages in one interpreter. The state accumulates.
That has a consequence worth internalising early: in a long session, a variable or a procedure you defined an hour ago is still there. So is a setting you changed and forgot. "It works in my session but not in a fresh batch run" is almost always something defined earlier in the session that the script never defines for itself.
Chapter 17.2 is about exactly that gap, and Chapter 17.4 about the files that widen it.
7. A short orientation routine
What to type at an unfamiliar prompt, in order:
info tclversion ;# which language features exist
info commands get_* ;# what can I query
info commands report_* ;# what can it tell me
current_design ;# is anything loaded yet
info commands ;# the full list, if you dareThen, before relying on anything in a script, check it is there — the preflight from Chapter 14.10 §8:
proc require_commands {args} {
set missing {}
foreach c $args {
if {![llength [info commands $c]]} { lappend missing $c }
}
if {[llength $missing]} {
error "this tool does not provide: [join $missing {, }]" {} \
[list TOOL MISSING $missing]
}
}Five lines of typing replaces an afternoon of assuming.
8. Exercises
Exercise 1. Give the three-part definition of a tool shell.
Exercise 2. Which command tells you whether try and lmap are available, and why would they not be?
Exercise 3. You are at an unfamiliar prompt. How do you find every command that reports something?
Exercise 4. get_cells * worked an hour ago and now raises no design loaded. What changed?
Exercise 5. Why can a tool command not be tested in isolation, and what does that imply about how you structure a flow script?
Exercise 6. get_cells * returns a different set before and after optimisation. Is that a bug?
Exercise 7. A script works in your interactive session and fails in a fresh batch run. What is the most likely cause?
Where this fits
Part of the Tcl curriculum.
