Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Parameterized Tcl Scripts for Reproducible Tool Settings and Output Paths

Hello! In the last lesson, you used Tcl variables to hold ICC2 collections and command substitution to inspect design objects. This lesson uses the same language for a different job: making a tool run repeatable. You’ll write a small script whose design name, run stage, and core count can change without editing its path-building logic. It will also record the chosen settings and output locations in a file. Allow about 40 minutes.


From interactive commands to a run configuration

An interactive command is useful for investigation. A script is useful when you need to repeat a result—or explain to a teammate exactly how you produced it. For a physical-design run, “I used four cores and put the reports somewhere under runs” is not enough. The design name, stage, input paths, requested settings, and report locations should be explicit.

Watch the selected parts of Adi Teman’s Introduction to Tcl: The tool command language - Part 1. You have already encountered set and square-bracket substitution in ICC2; concentrate on how they work together when constructing a script.

Introduction to Tcl: The tool command language - Part 1

In Introduction to Tcl: The tool command language - Part 1, Adi Teman demonstrates the Tcl syntax needed to turn individual tool commands into reusable code.

Watch variables for set, $name, and the distinction between quoted text and literal braces. Then watch command substitution for why [command] supplies a value to an outer command. Finish with conditions and procedures; both will help us validate parameters and keep repeated logic in one place.

For example, this is not a path to a report:

set report_path {file join runs placement timing.rpt}

The braces preserve literal text. This version calls file join first and saves its result:

set report_path [file join runs placement timing.rpt]

As with last lesson’s collection variables, what matters is the value stored in the variable. Here it is a filesystem path rather than a collection of design objects.


Choose one root for every path

A frequent scripting failure is dependence on the directory from which someone launched the tool. If a script says source scripts/setup.tcl or writes reports/qor.rpt, those relative paths can point somewhere different after a change of working directory.

Tcl’s file commands let us build paths deliberately. Read the selected subcommands in the Tcl 8.6 file manual page. The important behavior is that file join constructs a path, file normalize makes it absolute, and file mkdir creates required directories.

file manual page - Tcl Built-In Commands

Read the Tcl manual’s descriptions of the filesystem operations we will use, rather than the unrelated deletion and linking commands.

In the subcommand list, find file join and read path joining; notice that an absolute component can replace earlier components. Find file mkdir and read directory creation. Then find file normalize and read path normalization, including the following explanation of absolute paths. Finally, under file readable, note the permission check we will use before an actual tool run.

Our script will normally derive its project root from the script’s own location: place it at PROJECT/scripts/flow_config.tcl, and its default root will be PROJECT. An environment variable can override that root when the same script is used with another project directory. This is more stable than assuming the current working directory is always the project directory.


Write the parameterized script

Save the following as scripts/flow_config.tcl. It uses standard Tcl only, so you can test it with tclsh before you have ICC2 access. Its output is a configuration record, not a claim that placement or timing analysis has run.

# scripts/flow_config.tcl
# Configure one design/stage/run and record the requested settings and paths.

proc env_or {name fallback} {
    if {[info exists ::env($name)] && $::env($name) ne ""} {
        return $::env($name)
    }
    return $fallback
}

# Normally the project root is the parent of this script's directory.
set script_file [file normalize [info script]]
set default_root [file dirname [file dirname $script_file]]
set root [file normalize [env_or PD_ROOT $default_root]]

set design [env_or PD_DESIGN practice_block]
set stage  [env_or PD_STAGE init]
set tag    [env_or PD_RUN_TAG baseline]
set cores  [env_or PD_CORES 4]

if {![file isdirectory $root]} {
    error "Project root is not a directory: $root"
}

# Keep user-supplied names to single, predictable path components.
foreach {label value} [list design $design stage $stage run_tag $tag] {
    if {![regexp {^[A-Za-z][A-Za-z0-9_]*$} $value]} {
        error "Invalid $label '$value': use letters, digits, and underscores"
    }
}
if {![string is integer -strict $cores] || $cores < 1} {
    error "PD_CORES must be a positive integer"
}

# Store configuration in a Tcl array. These are values, not tool commands.
set cfg(project_root) $root
set cfg(design) $design
set cfg(stage) $stage
set cfg(run_tag) $tag
set cfg(requested_max_cores) $cores
set cfg(netlist) [file join $root inputs ${design}.v]
set cfg(sdc) [file join $root inputs ${design}.sdc]

set cfg(run_dir) [file join $root runs $design $stage $tag]
set cfg(report_dir) [file join $cfg(run_dir) reports]
set cfg(log_dir) [file join $cfg(run_dir) logs]
set cfg(checkpoint_dir) [file join $cfg(run_dir) checkpoints]
set cfg(qor_report) [file join $cfg(report_dir) qor.rpt]
set cfg(config_file) [file join $cfg(run_dir) settings.txt]

# Do not silently replace the record for an existing run tag.
if {[file exists $cfg(config_file)]} {
    error "Configuration already exists: $cfg(config_file); choose a new PD_RUN_TAG"
}

file mkdir $cfg(report_dir) $cfg(log_dir) $cfg(checkpoint_dir)

set out [open $cfg(config_file) w]
foreach key [lsort [array names cfg]] {
    puts $out [list $key $cfg($key)]
}
close $out

puts "Configuration saved: $cfg(config_file)"
puts "Reports will go in: $cfg(report_dir)"

There are three design choices worth noticing.

First, the parameters are near the top. PD_DESIGN, PD_STAGE, PD_RUN_TAG, and PD_CORES can be supplied through the environment; otherwise, the script uses visible defaults. No report path needs to be edited when the design or stage changes.

Second, cfg(...) is a Tcl array holding related values. cfg(qor_report) is a planned report filename; it does not create a QoR report. The input paths are planned locations too—the script does not pretend that a netlist or SDC file exists.

Third, the record has a predictable, sorted order. Each line is written as a two-element Tcl list, so a path containing spaces remains one value. settings.txt is data to inspect, not a script to source. Keeping the run tag in the path also separates baseline from a later trial. Reusing the same tag raises an error instead of silently overwriting its configuration record.


Run it and connect it to ICC2

With the file in place, run it from a terminal:

tclsh scripts/flow_config.tcl

With the defaults, the record will be under runs/practice_block/init/baseline/settings.txt. Open it and check that qor_report is inside report_dir, and that both are inside run_dir. If you launch tclsh from a different working directory using the script’s path, the default root still comes from the script’s location.

To make a separate configuration on Linux, supply different environment variables:

PD_DESIGN=practice_block PD_STAGE=placement PD_RUN_TAG=trialA PD_CORES=8 \
    tclsh scripts/flow_config.tcl

The script records requested core count. Recording a request is not the same as proving that ICC2 accepted it. The HDL2Chips Tcl Reference Guide: Part 11 shows the distinction between setting a tool option and directing tool output into a file. Treat its tool-specific examples as patterns to check against the help for your installed ICC2 release.

Tcl Reference Guide: Part 11 Miscellaneous Commands | HDL2Chips

Read the short session example for the host-core setting, then the discussion of redirect for saving tool output. The page illustrates a pattern; your installed tool's help remains authoritative for its exact commands and options.

In the opening Typical Session and Utility Flow example, find the host setting beginning at the core option. In the redirect entry, read output capture, then its single-report example. Focus on why the destination directory must exist before a tool writes a report.

In an ICC2 driver script, you could source this configuration and then apply the requested host setting. Do this in ICC2, not in tclsh, and check help set_host_options in your installed release:

source /path/to/PROJECT/scripts/flow_config.tcl

# Stop before tool work if required inputs are absent or unreadable.
foreach key {netlist sdc} {
    if {![file isfile $cfg($key)] || ![file readable $cfg($key)]} {
        error "Missing or unreadable $key: $cfg($key)"
    }
}

set_host_options -max_cores $cfg(requested_max_cores)

# Record that the setting command completed without an error.
set out [open $cfg(config_file) a]
puts $out [list host_core_option_applied $cfg(requested_max_cores)]
close $out

This is deliberately not a complete ICC2 initialization script: it does not load technology data, import a design, or produce qor.rpt. Those steps come later in the course. Once a design is loaded, a report command can be directed to $cfg(qor_report) using the syntax supported by your ICC2 release.

If input validation or a tool command fails, regard the run as incomplete; a configuration file alone is not evidence of a successful design run. For a stronger handoff record, retain the tool log and version information alongside the configuration. That makes it possible to distinguish the settings you requested from what the tool actually did.


Key takeaways

A reproducible Tcl configuration has explicit parameters, paths derived from a stable root, validation before tool work, and a saved record of its settings and output locations. Use file join rather than assembling paths by hand, and distinguish planned files from reports that have actually been generated.

This completes the tool-foundations module. Next, you’ll begin static timing analysis by calculating arrival time, required time, and setup slack for a register-to-register path—the quantities that later reports and physical-design changes must explain.

Can't find a good explanation? Sign up and we'll make it for you

Sign up