#------------------------------------------------------ # Tcl startup script for qrouter #------------------------------------------------------ namespace path {::tcl::mathop ::tcl::mathfunc} set tcllibdir [array get env "QROUTER_LIB_DIR"] if {$tcllibdir == {}} { set QROUTER_LIB_DIR LIBDIR } else { set QROUTER_LIB_DIR [lindex $tcllibdir 1] } unset tcllibdir if {[string compare $tcl_platform(platform) "windows"] == 0} { set libext .dll } else { set libext .so } if {${tcl_version} >= 8.6} { if {[catch {load ${QROUTER_LIB_DIR}/qrouter$libext}]} { load -lazy ${QROUTER_LIB_DIR}/qrouter$libext } } else { load ${QROUTER_LIB_DIR}/qrouter$libext } package require Qrouter proc pushnamespace { name } { set y [namespace eval ${name} info commands ::${name}::*] set z [info commands] foreach v $y { regsub -all {\*} $v {\\*} i set x [namespace tail $i] if {[lsearch $z $x] < 0} { namespace import $i } else { puts "Warning: ${name} command '$x' use fully-qualified name '$v'" } } } proc popnamespace { name } { set z [info commands] set l [expr [string length ${name}] + 5] while {[set v [lsearch $z ${name}_tcl_*]] >= 0} { set y [lindex $z $v] set w [string range $y $l end] interp alias {} ::$w {} rename ::$y ::$w puts "Info: replacing ::$w with ::$y" } namespace forget ::${name}::* } set auto_noexec 1 ;# don't EVER call UNIX commands w/o "shell" in front #--------------------------------------------------------- # Internally-defined procedures (equivalent to commands) #--------------------------------------------------------- #--------------------------------------------------------- # Write the result of the "congested" command out to a # file, with " " per # line of output, one for each instance, ordered. #--------------------------------------------------------- proc qrouter::write_congested {filename} { puts stdout "Writing congestion information into $filename" if {![catch {open $filename w} fcon]} { puts $fcon "Qrouter congestion summary" puts $fcon "--------------------------" set flist [failing summary] set failures [lindex $flist 0] set numnets [lindex $flist 1] puts $fcon "Failures: $failures $numnets" puts $fcon "--------------------------" set clist [congested] foreach cpair $clist { set inst [lindex $cpair 0] set value [lindex $cpair 1] puts $fcon "$inst $value" } close $fcon } else { puts stderr "Error: can't open file $filename for output" } } #------------------------------------------------------ # Standard routing script #------------------------------------------------------ proc qrouter::standard_route {{filename ""} {doquit true} {nocleanup false}} { puts stdout "*** Running stage1 routing with defaults" # Pull root name from filename set rootname [file root $filename] set deffilename ${rootname}.def set rcfilename ${rootname}.rc set result [stage1] if {$result > 0} { set msize 10 while {$msize <= 100} { set lastresult $result puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask $msize, effort 10" set result [stage2 mask $msize effort 10] if {!$result} {break} if {$result > $lastresult} { puts -nonewline stdout "*** Running stage2 routing" set tempmsize [expr $msize + 80] puts stdout " with options mask $tempmsize, effort 20" set result [stage2 mask $tempmsize effort 20] if {!$result} {break} if {$result < 5} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none, effort 50" set result [stage2 mask none effort 50] } if {!$result} {break} } incr msize 10 } } # Attempt a few runs at "mask none" if not solved yet if {$result > 0} { set esize 20 while {$esize <= 100} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none, effort $esize" set result [stage2 mask none effort $esize] if {!$result} {break} incr esize 20 } } # There is no point in running a cleanup stage if there are lots of # unrouted nets. if {$nocleanup == true} { puts stdout "*** Cleanup stage (stage3) bypassed" } elseif {$result < 10} { puts stdout "*** Running stage3 routing with defaults, 1st round" set result [stage3] if {$result > 0} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none" set result [stage2 mask none] } puts stdout "*** Running stage3 routing with defaults, 2nd round" set result [stage3] set i 0 while {$result > 0} { puts -nonewline stdout "*** Running stage2 routing" puts stdout " with options mask none" set result [stage2 mask none] incr i if {$i == 5} { break } } } cleanup all if {$result == 0} { if {![catch {antenna init}]} { puts stdout "*** Running antenna violation checks" antenna fix } } if {${rootname} != ""} { puts stdout "*** Writing DEF file $deffilename" write_def $deffilename } else { puts stdout "*** Writing DEF file (default)" write_def } if {$result > 0} { write_failed fail.out } if {${rootname} != ""} { puts stdout "*** Writing RC file $rcfilename" write_delays $rcfilename } else { puts stdout "*** Writing RC file (default)" write_delays } if {(!$result) && $doquit} {quit} } #--------------------------------------------------------- # Simple sequence of events (subject to change): # Upon first success, write the DEF file output and quit. # If "stage2 mask none" leaves failing routes, then write # the routes done so far to the DEF file output and remain # in the interpreter. If "stage2 mask none" leaves fewer # than five routes (a very ad hoc number), give it a # second try. #--------------------------------------------------------- proc qrouter::simple_route {} { if {![stage1]} {write_def; quit} if {![stage2]} {write_def; quit} set result [stage2 mask none] if {$result < 5} {set result [stage2 mask none]} write_def if {$result == 0} {quit} } #------------------------------------------------------ # First alternative routing script. Do the quickest # (default) stage1 and stage2 routes. If stage2 # leaves route failures, then write out the list of # instances with congestion information, so that this # information can be fed back to the placement tool # in hopes of producing a routable layout on the next # iteration. Rather than returning to the interpreter # on route failure, it always quits. #------------------------------------------------------ proc qrouter::congestion_route {filename} { if {![stage1]} {write_def; quit} set result [stage2 mask none] if {$result < 5} {set result [stage2 mask none]} if {$result != 0} { qrouter::write_congested $filename } write_def if {$result > 0} { write_failed fail.out } quit } #------------------------------------------------------ pushnamespace qrouter #------------------------------------------------------ # GUI setup #------------------------------------------------------ set appname .qrouter set appframe ${appname}.dframe set drawwindow ${appframe}.drawing if {![catch {toplevel ${appname}}]} { frame ${appframe} pack ${appframe} -side left -expand true -fill both simple ${drawwindow} -width 1000 -height 800 pack ${drawwindow} -expand true -fill both bind ${appframe} redraw bind ${appframe} redraw bind ${appframe} redraw wm withdraw . } proc qrouter::lowerconsole {} { consoledown } puts stdout "Qrouter detail maze router version VERSION.REVISION.T" set autoquit 0 set autoroute 0 set argafter {start} for {set i 0} {$i < $argc} {incr i 1} { set x [lindex $argv $i] switch $x { "-i" - "-h" {set autoquit 1} "-c" {set autoroute 1} } lappend argafter $x } eval $argafter # NOTE: Having a file "route.cfg" in the current directory is # equivalent to specifying "-c ", so autoroute should be set if {$autoroute == 0} { if [file exists route.cfg] { set autoroute 1 } } if {$autoquit} quit if {$autoroute} { qrouter::standard_route }