In my last post I wrote about writing more compact db access scripts with dbGet's expression-based matching. We found all of the high fanout nets in the design which weren't clock nets:
dbGet [dbGet top.nets {.numInputTerms > 16 && .isClock == 0}].name
This writes the name of each net to the console. But how would we write those nets to a file? Say, for example, if we wanted to call optDesign -selectedNets on them? optDesign expects a file with a list of net names, one per line. How could we create that file? We could use the redirect command along with some clever scripting. More on that in a moment, but let's talk about redirect first.
The Basics
The redirect command as described here is available starting in release EDI release 11.1 (EDI stands for Encounter Digital Implementation System).
In its simplest form redirect takes the output that's written to the Encounter console and writes it to a file. This is useful when you want to process that output programatically and do something based on what's found in that file.
Take for example the checkPinAssignment command. It writes output like this:
encounter 1> checkPinAssignment
Start Checking pins of top cell: [top]
**WARN: (ENCPTN-562): Pin [in] is [PLACED] at location ( 0.330, 50.120 4 ) is NOT ON THE DESIGN BOUNDARY.
Summary report for top level: [top]
Total Pads : 0
Total Pins : 3
Legally Assigned Pins : 2
Illegally Assigned Pins : 0
Unplaced Pins : 0
Constant/Spl Net Pins : 0
Internal Pins : 1
Legally Assigned Feedthrough Pins : 0
Illegally Assigned Feedthrough Pins: 0
End of Summary report
End Checking pins of top cell: [top]
The command doesn't return anything (ie, if you "set x checkPinAssignment", "x" wouldn't have a value) so if we want to query whether checkPinAssignment found any violations -or- check which specific pins were in violation we could do it by redirecting to a file and parsing the output. It's not necessarily pretty but sometimes you've got to do it. Here's how it works:
encounter 1> redirect checkPinAssignment.out checkPinAssignment
**Info: stdout is directed to file 'checkPinAssignment.out'...
Now, you could iterate through each line in checkPinAssignment.out and regexp for "WARN", find a pin name and operate on it in some way.
If the command you want to execute contains options, embed the options in curly brackets:
encounter 1> redirect queryPlaceDensity.out {queryPlaceDensity -userSpecified}
**Info: stdout is directed to file 'queryPlaceDensity.out'...
Intermediate
We've talked before about writing to and reading from a file. I've got a couple more tips that extend on that idea and make things more compact.
First, check out the dbForEachFileLine command. It essentially does the same thing as:
set infile [open checkPinAssignment.out "r"]
while {[gets $infile line] >= 0} {
if {[regexp WARN $line]} {
Puts "$line"
}
}
close $infile
If you're like me and have trouble remembering the infile/open/while/gets/close business try dbForEachFileLine instead:
dbForEachFileLine checkPinAssignment.out line {
if {[regexp WARN $line]} {
Puts "$line"
}
}
But we can get even fancier with this approach, and avoid writing to a file altogether with redirect's -variable option:
redirect x checkPinAssignment -variable
set lines [split $x \n]
foreach line $lines {
if {[regexp WARN $line]} {
Puts "$line"
}
}
Extra Credit
Back to the original puzzler I mentioned previously. How could we write to a file, one net per line, all of the nets with fanout greater than "n" so we could pass it to a command like "optDesign -selectNets <fileName>"? It's a little tricky, and probably exceedingly compound to be honest, but there is a way:
encounter 18> redirect high_fanout.nets {puts "[join [split [dbGet [dbGet top.nets {.numInputTerms > 16 && .isClock == 0}].name]] \n]"}
**Info: stdout is directed to file 'high_fanout.nets'...
encounter 19> more high_fanout.nets
scan_enI
DTMF_INST/TDSP_CORE_INST/MPY_32_INST/n_7295
DTMF_INST/TDSP_CORE_INST/MPY_32_INST/n_6735
{DTMF_INST/TDSP_CORE_INST/MPY_32_INST/ab_a[15]}
{DTMF_INST/TDSP_CORE_INST/MPY_32_INST/ab_b[15]}
Pretty cool!
Here's the full usage for the redirect command:
encounter 1> help redirect
Usage: redirect [-help] [<file_or_var_name>] [<command>] [-tee] [-stdin | -append | -variable ] [-stderr | -stdin ]
-help # Prints out the command usage
<file_or_var_name> # file name or variable name, for outputs to go
# (string, optional)
<command> # command to execute (string, optional)
-append # append stdout/stderr to file or variable
# (bool, optional)
-stderr # redirect stderr also (bool, optional)
-stdin # redirect stdin (bool, optional)
-tee # redirect output to both screen and file or
# variable (bool, optional)
-variable # redirect to a Tcl variable (bool, optional)
I hope there's a useful nugget or two in here.
Question of the Day: Any tips or tricks you'd like to share about reading from/writing to a file, capturing output as a variable, or redirecting it to a file?
-Bob Dwyer