summaryrefslogtreecommitdiff
path: root/qrouter.tcl.in
blob: 192ac33ea285f268493257d771c662f7e503bfd9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
#------------------------------------------------------
# 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 "<instance_name> <congestion_value>" 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} <Expose> redraw
   bind ${appframe} <Visibility> redraw
   bind ${appframe} <Configure> 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 <file>", so autoroute should be set

if {$autoroute == 0} {
   if [file exists route.cfg] {
      set autoroute 1
   }
}

if {$autoquit} quit 
if {$autoroute} {
   qrouter::standard_route
}