1#!/usr/local/bin/tclsh8.6
2#---------------------------------------------------------------------------
3# addspacers.tcl ---
4#
5# Read LEF file and parse for fill cells;  get the number and width of
6#	the different fill cells available.
7# Read the DEF file once, to find the number of rows and the endpoint
8#	of each row.  This is not a general purpose script. . . we assume
9#	output is from GrayWolf and place2def, so cells are aligned on
10#	the left, and components appear in order, row by row, from left
11#	to right.
12# Read the DEF file again, up to the COMPONENTS section.
13# Modify the COMPONENTS section to add the spacer cells, and write out
14#	the annotated DEF file.
15#
16# Updated 6/7/2017 to add option to split layout at intervals and
17# insert a stripe of minimum size for the addition of a power bus.
18# This is an ad hoc solution that does not consider how the overall
19# timing is affected by stretching routes that have to cross this
20# stripe.  Use of "-nostretch" will place the stripes over the existing
21# layout without making extra space with fill.  This is generally
22# preferred unless it makes the cell unroutable.
23#
24# Updated 5/18/2018 to generate an output file with the instances
25# added to the design, so these can be incorporated into the netlist.
26#---------------------------------------------------------------------------
27
28namespace path {::tcl::mathop ::tcl::mathfunc}
29
30if {$argc < 3} {
31    puts stdout "Usage:  addspacers \[<options>\] <project_name> <lef_file> <fill_cell>"
32    puts stdout "Options:"
33    puts stdout "  -stripe <width> <pitch> <pattern> \[-nostretch\] \[-techlef <tech.lef>\]"
34    puts stdout "  \[-v <pwr_name>\] \[-g <gnd_name>\]"
35    exit 0
36}
37
38# NOTE:  DEF values are by default centimicrons (UNITS DISTANCE MICRONS 100)
39# but may be in nanometers if the LEF file declares a manufacturing grid
40# that is smaller than centimicrons.  Pick up the scalefactor (100 or 1000)
41# from the DEF file written by the place2def script.
42
43set argidx 0
44set dostripes false	;# no power bus striping by default
45set stripewidth 0
46set stripepitch 0
47set stripeoffset 0
48set numstripes 0
49set dostretch true
50set techlef ""
51set hardlef []
52set pitchx 0
53set layers {}
54set vias {}
55set viarules {}
56set obslist {}
57
58while true {
59    set arg0 [lindex $argv $argidx]
60    if {$arg0 == "-stripe"} {
61	incr argidx
62	set dostripes true
63	set stripewidth [lindex $argv $argidx]
64	set stripewidthreq $stripewidth
65	incr argidx
66	set stripepitch [lindex $argv $argidx]
67	incr argidx
68	set stripepattern [lindex $argv $argidx]
69    } elseif {$arg0 == "-stripewidth"} {
70	incr argidx
71	set dostripes true
72	set stripewidthreq $stripewidth
73	set stripewidth [lindex $argv $argidx]
74    } elseif {$arg0 == "-stripepitch"} {
75	incr argidx
76	set dostripes true
77	set stripepitch [lindex $argv $argidx]
78    } elseif {$arg0 == "-stripepattern"} {
79	incr argidx
80	set dostripes true
81	set stripepattern [lindex $argv $argidx]
82    } elseif {$arg0 == "-techlef"} {
83	incr argidx
84	set techlef [lindex $argv $argidx]
85    } elseif {$arg0 == "-hardlef"} {
86	incr argidx
87	lappend hardlef [lindex $argv $argidx]
88    } elseif {$arg0 == "-nostretch"} {
89	set dostretch false
90    } else {
91	break
92    }
93    incr argidx
94}
95
96set topname [file rootname [lindex $argv $argidx]]
97incr argidx
98set lefname [lindex $argv $argidx]
99incr argidx
100set fillcell [lindex $argv $argidx]
101
102set defname ${topname}.def
103set defoutname ${topname}_filled.def
104
105set units 100		;# write centimicron units into the DEF file (default)
106
107# Input arguments are assumed to be in microns.  Convert them to the
108# DEF file units.
109
110set diexlow 0
111set diexhigh 0
112set dieylow 0
113set dieyhigh 0
114
115#-----------------------------------------------------------------
116# Open all files for reading and writing
117#-----------------------------------------------------------------
118
119if [catch {open $lefname r} flef] {
120    puts stderr "Error: can't open LEF file $lefname for input"
121    exit 1
122}
123
124if [catch {open $defname r} fdef] {
125    puts stderr "Error: can't open DEF file $defname for input"
126    exit 1
127}
128
129if {$techlef != ""} {
130    if [catch {open $techlef r} ftech] {
131	puts stderr "Warning: can't open LEF tech file $techlef for input"
132	puts stderr "Will add obstruction layers but no power/ground stripes"
133	set techlef ""
134    }
135}
136
137#----------------------------------------------------------------
138# Initial read of top of DEF file to determine what the units
139# conversion is going to be.
140#----------------------------------------------------------------
141
142while {[gets $fdef line] >= 0} {
143    if [regexp {[ \t]*#} $line lmatch] {
144	continue
145    } elseif [regexp {[ \t]*UNITS[ \t]+DISTANCE[ \t]+MICRONS[ \t]+([^ \t]+)} $line lmatch dunits] {
146        # Units are expected to be 100 (centimicrons) but may be divided further
147	# and affect how we generate geometry for the power and ground nets.
148	set units $dunits
149	break
150    }
151}
152# Close and reopen the file for the second pass
153close $fdef
154set fdef [open $defname r]
155
156# Multiply stripe width and pitch values by units to get output values
157set stripewidth [expr {round($units * $stripewidth)}]
158set stripepitch [expr {round($units * $stripepitch)}]
159
160#----------------------------------------------------------------------
161# Parse a viarule section for generating power bus connections
162# Cut layer has "RECT" and "SPACING".  Metal layers have "ENCLOSURE"
163# (new style) or "OVERHANG" (old style).  The old style is unclear,
164# so only support what's in the OSU standard cells, which have overhang
165# in all directions (METALOVERHANG is zero).  May add support for more
166# varieties if the interpretation of the unclear syntax is known.
167#----------------------------------------------------------------------
168
169proc parse_viarule {leffile viarulename} {
170    global units
171
172    set viarulerec [dict create]
173    dict set viarulerec name $viarulename
174    set llx 0
175    set lly 0
176    set urx 0
177    set ury 0
178    set xspace 0
179    set yspace 0
180
181    while {[gets $leffile line] >= 0} {
182	if [regexp {[ \t]*LAYER[ \t]+([^ \t]+)[ \t]*;} $line lmatch layername] {
183	    # Pick up layername
184	    continue
185	} elseif [regexp {[ \t]*RECT[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*;} $line lmatch llx lly urx ury] {
186	    set llx [expr {round($llx * $units)}]
187	    set lly [expr {round($lly * $units)}]
188	    set urx [expr {round($urx * $units)}]
189	    set ury [expr {round($ury * $units)}]
190	    dict set viarulerec ${layername} [list $llx $lly $urx $ury $xspace $yspace]
191	} elseif [regexp {[ \t]*SPACING[ \t]+([^ \t]+)[ \t]+BY[ \t]+([^ \t]+)[ \t]*;} $line lmatch xspace yspace] {
192            set xspace [expr {round($xspace * $units)}]
193            set yspace [expr {round($yspace * $units)}]
194	    dict set viarulerec ${layername} [list $llx $lly $urx $ury $xspace $yspace]
195	} elseif [regexp {[ \t]*METALOVERHANG[ \t]+([^ \t]+)[ \t]*;} $line lmatch overhang] {
196            # Ignore this.
197            continue
198	} elseif [regexp {[ \t]*OVERHANG[ \t]+([^ \t]+)[ \t]*;} $line lmatch overhang] {
199            # NOTE:  Assuming METALOVERHANG is 0 and OVERHANG is on all sides.
200            set overhang [expr {round($overhang * $units)}]
201	    dict set viarulerec ${layername} [list $overhang $overhang]
202	} elseif [regexp {[ \t]*ENCLOSURE[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*;} $line lmatch xencl yencl] {
203            set xencl [expr {round($xencl * $units)}]
204            set yencl [expr {round($yencl * $units)}]
205	    dict set viarulerec ${layername} [list $xencl $yencl]
206	} elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch viaruletest] {
207	    if {"$viaruletest" != "$viarulename"} {
208	        puts -nonewline stderr "Unexpected END statement $line while "
209	        puts stderr "reading viarule $viarulename"
210	    }
211	    break
212	}
213    }
214    if {[dict size $viarulerec] == 0} {
215	return ""
216    } else {
217	return $viarulerec
218    }
219}
220
221
222#----------------------------------------------------------------
223# Parse a via section for routing information
224#
225# (Note:  this routine only saves one RECT entry for each layer.
226# The intention is only to capture the name of the via, the
227# overall dimension, and the layers used.)
228#----------------------------------------------------------------
229
230proc parse_via {leffile vianame} {
231    global units
232
233    set viarec [dict create]
234    set type NONE
235    dict set viarec name $vianame
236
237    while {[gets $leffile line] >= 0} {
238	if [regexp {[ \t]*LAYER[ \t]+([^ \t]+)[ \t]*;} $line lmatch layername] {
239	    continue
240	} elseif [regexp {[ \t]*RECT[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*;} $line lmatch llx lly urx ury] {
241	    set llx [expr {round($llx * $units)}]
242	    set lly [expr {round($lly * $units)}]
243	    set urx [expr {round($urx * $units)}]
244	    set ury [expr {round($ury * $units)}]
245	    dict set viarec ${layername} [list $llx $lly $urx $ury]
246	} elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch viatest] {
247	    if {"$viatest" != "$vianame"} {
248	        puts -nonewline stderr "Unexpected END statement $line while "
249	        puts stderr "reading via $vianame"
250	    }
251	    break
252	}
253    }
254    return $viarec
255}
256
257#----------------------------------------------------------------
258# Parse a layer section for routing information
259#----------------------------------------------------------------
260
261proc parse_layer {leffile layername layernum} {
262    global units
263
264    set layerrec [dict create]
265    set pitch 0
266    set type NONE
267    dict set layerrec name $layername
268    dict set layerrec number 0
269
270    # Diagnostic
271    puts stdout "Reading layer name $layername"
272
273    while {[gets $leffile line] >= 0} {
274	if [regexp {[ \t]*TYPE[ \t]+([^ \t]+)[ \t]*;} $line lmatch type] {
275	    dict set layerrec type $type
276	    if {$type == "ROUTING"} {
277		incr layernum
278		dict set layerrec number $layernum
279	    }
280	    if {$type == "CUT"} {
281		dict set layerrec number $layernum
282	    }
283	} elseif [regexp {[ \t]*DIRECTION[ \t]+([^ \t]+)[ \t]*;} $line lmatch direc] {
284	    dict set layerrec direction $direc
285	} elseif [regexp {[ \t]*WIDTH[ \t]+([^ \t]+)[ \t]*;} $line lmatch width] {
286	    dict set layerrec width [expr {round($width * $units)}]
287	} elseif [regexp {[ \t]*SPACING[ \t]+([^ \t]+)[ \t]*;} $line lmatch space] {
288	    dict set layerrec spacing [* $space $units]
289	} elseif [regexp {[ \t]*PITCH[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*;} $line \
290		lmatch xpitch ypitch] {
291	    dict set layerrec xpitch [expr {round($xpitch * $units)}]
292	    dict set layerrec ypitch [expr {round($ypitch * $units)}]
293	} elseif [regexp {[ \t]*PITCH[ \t]+([^ \t]+)[ \t]*;} $line lmatch pitch] {
294	    set pitch [expr {round($pitch * $units)}]
295	    continue
296	} elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch layertest] {
297	    if {"$layertest" != "$layername"} {
298	        puts -nonewline stderr "Unexpected END statement $line while "
299	        puts stderr "reading layer $layername"
300	    }
301	    break
302	}
303    }
304
305    if {$pitch != 0} {
306	set orient [dict get $layerrec direction]
307	if {$orient == "VERTICAL"} {
308	    dict set layerrec xpitch $pitch
309	    dict set layerrec ypitch 0
310	} elseif {$orient == "HORIZONTAL"} {
311	    dict set layerrec ypitch $pitch
312	    dict set layerrec xpitch 0
313	}
314    }
315    return $layerrec
316}
317
318#----------------------------------------------------------------
319# Parse port information for a macro pin from the LEF MACRO block
320# Here, needed only for power and ground pins.
321# Assume that the power and ground ports define one rectangle that
322# reaches from end to end of the cell, and record that rectangle.
323# There are vaious contingencies in case the power rail does not
324# reach the cell bounds (which shouldn't happen), and in case the
325# power rail is a polygon that contains internal geometry.
326#----------------------------------------------------------------
327
328proc parse_port {pinname macroname leffile ox oy} {
329    global $macroname units
330
331    set x2 [+ $ox [set ${macroname}(w)]]
332
333    while {[gets $leffile line] >= 0} {
334        if [regexp {[ \t]*LAYER[ \t]+([^ \t]+)[\t ]*;} $line lmatch layername] {
335            if {![regexp {.*(\d).*} $layername lmatch layernum]} {set layernum 0}
336            set ${macroname}(${pinname},layer) $layernum
337        } elseif [regexp {[ \t]*RECT[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*;} \
338                        $line lmatch llx lly urx ury] {
339	    set llx [expr {round($llx * $units)}]
340	    set lly [expr {round($lly * $units)}]
341	    set urx [expr {round($urx * $units)}]
342	    set ury [expr {round($ury * $units)}]
343	    if {$llx < $ox} {set llx $ox}
344	    if {$urx > $x2} {set urx $x2}
345	    if {($llx == $ox) && ($urx == $x2)} {
346		set ${macroname}(${pinname},llx) $llx
347		set ${macroname}(${pinname},lly) $lly
348		set ${macroname}(${pinname},urx) $urx
349		set ${macroname}(${pinname},ury) $ury
350	    }
351	    # To do:  If bus is made of more than one rectangle, merge
352	    # leftmost and rightmost rectangles into one entry.
353
354	} elseif [regexp {[ \t]*POLYGON[ \t]+(.*)[ \t]*;} $line lmatch rest] {
355
356	    # parse POLYGON records.  To capture the main power stripe
357	    # from a polygon, look for one line stretching from beginning
358	    # to end of the cell.  Then find the one or two lines attached
359	    # to the long one at the corners.  Assume the power stripe
360	    # height is the shorter of the two lines.
361
362	    # Sort polygon points into X and Y arrays
363	    set i 0
364	    set xvals {}
365	    set yvals {}
366	    foreach coord $rest {
367		if {$i == 0} {
368		    lappend xvals $coord
369		} else {
370		    lappend yvals $coord
371		}
372		set i [expr 1 - $i]
373	    }
374
375	    # This code is based on the fact that standard cells are not
376	    # going to have metal jutting up or down from the power rails
377	    # at the extremities, because there the cells overlap other
378	    # cells (problem would be if *all* cells have a metal tab at
379	    # the overlap).  There are more complicated ways to extract
380	    # the largest rectangle of a polygon, but this should suffice
381	    # until a counterexample arises.
382
383	    # Find indexes of points at minimum and maximum X
384	    set minx [lindex $xvals 0]
385	    set maxx $minx
386	    set minxidx {}
387	    set maxxidx {}
388	    for {set i 0} {$i < [llength $xvals]} {incr i} {
389		set testx [lindex $xvals $i]
390		if {$testx <= $ox} {lappend minxidx $i}
391		if {$testx >= $x2} {lappend maxxidx $i}
392		if {$testx < $minx} {set minx $testx}
393		if {$testx > $maxx} {set maxx $testx}
394	    }
395	    # Clip extrema to cell bounds, if needed
396	    if {$minx < $ox} {set minx $ox}
397	    if {$maxx > $x2} {set maxx $x2}
398
399	    # If minxidx or maxxidx are empty, then set to the minx
400	    # and maxx indices.
401	    if {[llength $minxidx] == 0} {
402		for {set i 0} {$i < [llength $xvals]} {incr i} {
403		    set testx [lindex $xvals $i]
404		    if {$testx == $minx} {lappend minxidx $i}
405		}
406	    }
407	    if {[llength $maxxidx] == 0} {
408		for {set i 0} {$i < [llength $xvals]} {incr i} {
409		    set testx [lindex $xvals $i]
410		    if {$testx == $maxx} {lappend maxxidx $i}
411		}
412	    }
413
414	    # Find Y value minimum and maximum at both extrema
415	    set ymin [lindex $yvals 0]
416	    set ymax $ymin
417	    for {set i 0} {$i < [llength $minxidx]} {incr i} {
418		set j [lindex $minxidx $i]
419		set testy [lindex $yvals $j]
420		if {$testy < $ymin} {set ymin $testy}
421		if {$testy > $ymax} {set ymax $testy}
422	    }
423	    for {set i 0} {$i < [llength $maxxidx]} {incr i} {
424		set j [lindex $maxxidx $i]
425		set testy [lindex $yvals $j]
426		if {$testy < $ymin} {set ymin $testy}
427		if {$testy > $ymax} {set ymax $testy}
428	    }
429
430	    set llx [expr {round($minx * $units)}]
431	    set lly [expr {round($ymin * $units)}]
432	    set urx [expr {round($maxx * $units)}]
433	    set ury [expr {round($ymax * $units)}]
434
435	    set ${macroname}(${pinname},llx) $llx
436	    set ${macroname}(${pinname},lly) $lly
437	    set ${macroname}(${pinname},urx) $urx
438	    set ${macroname}(${pinname},ury) $ury
439
440        } elseif [regexp {[ \t]*END[ \t]*$} $line lmatch] { break }
441    }
442}
443
444#----------------------------------------------------------------
445# Parse pin information from the LEF MACRO block
446#----------------------------------------------------------------
447
448proc parse_pin {pinname macroname leffile ox oy} {
449    global $macroname
450
451    set portuse ""
452    while {[gets $leffile line] >= 0} {
453        if [regexp {[ \t]*PORT} $line lmatch] {
454	    if {($portuse == "POWER") || ($portuse == "GROUND") || ($portuse == "")} {
455	        parse_port $pinname $macroname $leffile $ox $oy
456	    }
457        } elseif [regexp {[ \t]*DIRECTION[ \t]+([^ \t]+)[ \t]*;} $line lmatch porttype] {
458	    set porttype [string toupper $porttype]
459            set ${macroname}(${pinname},type) $porttype
460        } elseif [regexp {[ \t]*DIRECTION[ \t]+([^:]+);} $line lmatch porttype] {
461	    set porttype [string toupper $porttype]
462            set ${macroname}(${pinname},type) $porttype
463        } elseif [regexp {[ \t]*USE[ \t]+([^ \t]+)[ \t]*;} $line lmatch portuse] {
464	    set portuse [string toupper $portuse]
465            set ${macroname}(${pinname},use) $portuse
466        } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch pintest] {
467            if {"$pintest" == "$pinname"} {
468                break
469            } else {
470                puts stdout "Unexpected END statement $line while parsing pin $pinname"
471            }
472        }
473    }
474}
475
476#----------------------------------------------------------------
477# Read through a LEF file section that we don't care about.
478#----------------------------------------------------------------
479
480proc skip_section {leffile sectionname} {
481    while {[gets $leffile line] >= 0} {
482	if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] {
483	    if {"$sectiontest" != "$sectionname"} {
484		puts -nonewline stderr "Unexpected END statement $line "
485		puts stderr "while reading section $sectionname"
486	    }
487	    break
488	}
489    }
490}
491
492#----------------------------------------------------------------
493# Read through a NONDEFAULTRULE section, which can have layers
494# and vias which should be ignored.
495#----------------------------------------------------------------
496
497proc skip_nondefaultrule {leffile sectionname} {
498    while {[gets $leffile line] >= 0} {
499	if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] {
500	    if {"$sectiontest" == "$sectionname"} {
501	        return
502	    }
503	}
504    }
505}
506
507#----------------------------------------------------------------
508# Parse the macro contents of the LEF file and retain the information
509# about cell size and pin positions.
510#----------------------------------------------------------------
511
512proc parse_macro {leffile macroname} {
513    global $macroname units
514
515    while {[gets $leffile line] >= 0} {
516	if [regexp {[ \t]*SYMMETRY[ \t]+([^ \t]+)[ \t]*;} $line lmatch symmetry] {
517	    set ${macroname}(symmetry) $symmetry
518	} elseif [regexp {[ \t]*ORIGIN[ \t]+(.+)[ \t]+(.+)[ \t]*;} $line lmatch x y] {
519	    set x [expr {round($x * $units)}]
520	    set y [expr {round($y * $units)}]
521	    set ${macroname}(x) $x
522	    set ${macroname}(y) $y
523	} elseif [regexp {[ \t]*SIZE[ \t]+(.+)[ \t]+BY[ \t]+(.+)[ \t]*;} \
524                        $line lmatch w h] {
525	    set w [expr {round($w * $units)}]
526	    set h [expr {round($h * $units)}]
527	    set ${macroname}(w) $w
528	    set ${macroname}(h) $h
529
530	} elseif [regexp {[ \t]*PIN[ \t]+([^ \t]+)[ \t]*$} $line lmatch pinname] {
531	    # Get power and ground information, the values in the fill cell
532	    # will be used to generate power and ground stripes
533	    parse_pin $pinname $macroname $leffile $x $y
534	} elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch macrotest] {
535	    if {"$macrotest" == "$macroname"} {
536		break
537	    } else {
538		puts stderr "Unexpected END statement $line while reading macro $macroname"
539	    }
540	}
541    }
542}
543
544#-----------------------------------------------------------------
545# Read a LEF file.  Returns a list of fill cells if the LEF file
546# was a standard cell set macro file.
547# NOTE:  Route layers are assumed to be listed from bottom to top,
548# so that the layer number can be determined by the position that
549# the layer description occurs in the LEF file.
550#-----------------------------------------------------------------
551
552proc read_lef {flef fillcell} {
553    global layers vias viarules
554    set layernum 0
555    set fillcells {}
556    while {[gets $flef line] >= 0} {
557        # Ignore comment lines
558        if [regexp {[ \t]*#} $line lmatch] {
559	    continue
560	} elseif [regexp {[ \t]*MACRO[ \t]+([^ \t]+)[ \t]*$} $line lmatch macroname] {
561	    # Parse the "macro" statement
562	    parse_macro $flef $macroname
563	    if {[regexp "^$fillcell" $macroname] == 1} {
564		# Remember this for later if it's a fill cell
565		lappend fillcells $macroname
566	    }
567	} elseif [regexp {[ \t]*LAYER[ \t]+([^ \t]+)} $line lmatch layername] {
568	    set newlayer [parse_layer $flef $layername $layernum]
569	    lappend layers $newlayer
570	    set newnum [dict get $newlayer number]
571	    if {$newnum != 0} {set layernum $newnum}
572	} elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)} $line lmatch vianame] {
573	    lappend vias [parse_via $flef $vianame]
574	} elseif [regexp {[ \t]*NONDEFAULTRULE[ \t]+([^ \t]+)} $line lmatch rulename] {
575	    skip_nondefaultrule $flef $rulename
576	} elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] {
577	    set result [parse_viarule $flef $viarulename]
578	    if {$result != ""} {
579		lappend viarules $result
580	    }
581	} elseif [regexp {[ \t]*SITE[ \t]+([^ \t]+)[ \t]*$} $line lmatch sitename] {
582	    skip_section $flef $sitename
583	} elseif [regexp {[ \t]*UNITS[ \t]*$} $line lmatch] {
584	    skip_section $flef UNITS
585	} elseif [regexp {[ \t]*PROPERTYDEFINITIONS[ \t]*$} $line lmatch] {
586	    skip_section $flef PROPERTYDEFINITIONS
587	} elseif [regexp {[ \t]*SPACING[ \t]*$} $line lmatch] {
588	    skip_section $flef SPACING
589	} elseif [regexp {[ \t]*END[ \t]+LIBRARY[ \t]*$} $line lmatch] {
590	    break
591	} elseif [regexp {^[ \t]*#} $line lmatch] {
592	    # Comment line, ignore.
593	} elseif ![regexp {^[ \t]*$} $line lmatch] {
594	    # Other things we don't care about
595	    set matches 0
596	    if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] {
597		incr matches
598	    } elseif [regexp {[ \t]*VERSION} $line lmatch] {
599		incr matches
600	    } elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] {
601		incr matches
602	    } elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] {
603		incr matches
604	    } elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] {
605		incr matches
606	    } elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] {
607		incr matches
608	    } elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] {
609		incr matches
610	    } elseif {$fillcell != ""} {
611		puts stderr "Unexpected input in LEF file:  Only macro defs were expected!"
612		puts -nonewline stdout "Line is: $line"
613		flush stdout
614	    }
615	}
616    }
617    return $fillcells
618}
619
620#-----------------------------------------------------------------
621# Read the tech LEF file for via and layer information
622#-----------------------------------------------------------------
623
624if {$techlef != ""} {
625    puts stdout "Reading technology LEF file ${techlef}."
626    read_lef $ftech ""
627}
628
629if {[llength $hardlef] > 0} {
630    foreach leffile $hardlef {
631	puts stdout "Reading hard macro LEF file ${leffile}."
632	if [catch {open $leffile r} fhard] {
633	    puts stderr "Error: can't open LEF file $lefname for input"
634	} else {
635	    read_lef $fhard ""
636	    close $fhard
637	}
638    }
639}
640
641#-----------------------------------------------------------------
642# Read the LEF macro file and get the fill cells and their widths
643#-----------------------------------------------------------------
644
645puts stdout "Reading ${fillcell} macros from LEF file."
646flush stdout
647
648set fillcells [read_lef $flef $fillcell]
649
650# If the macro file doesn't define any fill cells, there's not a
651# whole lot we can do, unless we're adding power stripes without
652# stretching.
653
654if {[llength $fillcells] == 0} {
655    puts stdout "No fill cells (${fillname}) found in macro file ${lefname}!"
656    if {$dostripes == false || $dostretch == true} {exit 1}
657}
658
659# Get routing grid X pitch from the layer information
660
661set testpitch 0
662foreach layer $layers {
663    if [catch {dict get $layer type}] {
664	puts stderr "Warning:  Layer {dict get $layer name} in techLEF file does not declare a type!"
665	continue
666    }
667    if {[dict get $layer type] != "ROUTING"} {continue}
668    set layerpitch [dict get $layer xpitch]
669    if {$layerpitch > 0} {
670	if {$testpitch == 0} {
671	    set testpitch $layerpitch
672	} elseif {$layerpitch < $testpitch} {
673	    set testpitch $layerpitch
674	}
675    }
676}
677set pitchx $testpitch
678
679# If neither LEF file defined layers, then set "needspecial" to false,
680# because there is not enough information to know how to write the
681# specialnets section.  Flag a warning.
682
683if {$pitchx == 0} {
684    puts stderr "No technology layer information in LEF files."
685    puts stderr "Cannot create physical geometry for power and ground."
686    set needspecial false
687}
688
689#-----------------------------------------------------------------
690# Parse the COMPONENTS section of the DEF file
691# Assuming this file was generated by place2def, each component
692# should be on a single line.
693#-----------------------------------------------------------------
694
695proc parse_components {deffile rows} {
696    upvar $rows rdict
697    while {[gets $deffile line] >= 0} {
698        if [regexp {[ \t]*#} $line lmatch] {
699	    continue
700	} elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] {
701	    if {"$sectiontest" != "COMPONENTS"} {
702		puts -nonewline stderr "Unexpected END statement $line "
703		puts stderr "while reading section COMPONENTS"
704	    }
705	    break
706	} elseif [regexp {[ \t]*-[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+\+[ \t]+PLACED[ \t]+\([ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+\)[ \t]+([^ \t]+)[ \t]+;} $line lmatch \
707		instance macro px py orient] {
708	    if [catch {set row [dict get $rdict $py]}] {
709		dict set rdict $py [list $px $instance $macro $orient]
710	    } else {
711		set rowmax [lindex $row 0]
712		if {$px > $rowmax} {
713		    dict set rdict $py [list $px $instance $macro $orient]
714		}
715	    }
716	} else {
717	    puts -nonewline stderr "Unexpected statement $line "
718	    puts stderr "while reading section COMPONENTS"
719	}
720    }
721}
722
723#-----------------------------------------------------------------
724# Get the power pin name from a macro
725#-----------------------------------------------------------------
726
727proc get_power {macroname} {
728    global $macroname
729    foreach name [array names $macroname] {
730	if {[set ${macroname}(${name})] == "POWER"} {
731            set cidx [- [string first "," $name] 1]
732 	    return [string range $name 0 $cidx]
733        }
734    }
735    return ""
736}
737
738#-----------------------------------------------------------------
739# Get the ground pin name from a macro
740#-----------------------------------------------------------------
741
742proc get_ground {macroname} {
743    global $macroname
744    foreach name [array names $macroname] {
745	if {[set ${macroname}(${name})] == "GROUND"} {
746            set cidx [- [string first "," $name] 1]
747 	    return [string range $name 0 $cidx]
748        }
749    }
750    return ""
751}
752
753#-----------------------------------------------------------------
754# Get the first input pin name from a macro.  This is for use in
755# writing fillcells.txt, for which a cell with no input pin
756# should write PIN=-, so return "-" if there is no input pin.
757#-----------------------------------------------------------------
758
759proc get_inputpin {macroname} {
760    global $macroname
761    foreach name [array names $macroname] {
762	if {[set ${macroname}(${name})] == "INPUT"} {
763            set cidx [- [string first "," $name] 1]
764 	    return [string range $name 0 $cidx]
765        }
766    }
767    return "-"
768}
769
770#-----------------------------------------------------------------
771# Write entries for SPECIALNETS corresponding to the power and
772# ground stripes.  If we have VIARULE statements, then the power
773# posts are constructed from the VIARULE vias.  Where layers
774# are missing, or if there were no VIARULE statements, then the
775# power posts are constructed from known VIA types.
776#-----------------------------------------------------------------
777
778proc write_special {stripeinfo stripefills stripewidth stripepattern
779		rows dieylow dieyhigh fanno} {
780    global fmin vias viarules layers pitchx obslist
781
782    # Take 1st fill cell and find name of power and ground buses
783    set fillmacro [lindex $stripefills 0]
784    global $fillmacro
785
786    # Parse layers for topmost vertical route layer.  LEF syntax
787    # apparently depends on route layers to be described in order
788    # bottom to top in the LEF file, so we rely on this convention.
789
790    set tnum 0
791    set topmet 0
792    foreach layer $layers {
793	if {[dict get $layer type] != "ROUTING"} {continue}
794	if {[dict get $layer direction] == "VERTICAL"} {
795	    set lnum [dict get $layer number]
796	    if {$lnum > $tnum} {
797		set tnum $lnum
798	    }
799	}
800	set lnum [dict get $layer number]
801	if {$lnum > $topmet} {
802	    set topmet $lnum
803	}
804    }
805    if {$tnum == 0} {
806	puts stdout "Error in metal layer definitions. . . cannot continue."
807	exit 1
808    } elseif {$tnum < 3} {
809	puts stderr "Warning:  No vertical routing layer at metal 3 or above"
810	puts stderr "Only posts will be placed, and not connected"
811    }
812
813    # Create list of route layers in order.
814    set layerlist {}
815    for {set i 1} {$i <= $topmet} {incr i} {
816	foreach layer $layers {
817	    if {[dict get $layer type] == "ROUTING"} {
818		set lnum [dict get $layer number]
819		if {$lnum == $i} {
820		    lappend layerlist [dict get $layer name]
821		}
822	    }
823	}
824    }
825
826    # Parse vias for the smallest size via on each metal layer (except top)
827    # These will only be used if no viagen statement exists.
828
829    set basevias {}
830    set baseviarules {}
831    set viaoffsets {}
832    set viaheights {}
833    set viaspaces {}
834    set nvias {}
835    set blayer ""
836    set tlayer ""
837    set clayer ""
838    set cwidth 0
839    set cspace 0
840    for {set i 1} {$i <= [- $topmet 1]} {incr i} {
841	foreach layer $layers {
842	    if {[dict get $layer type] == "ROUTING"} {
843		set lnum [dict get $layer number]
844		if {$lnum == $i} {
845		    set blayer [dict get $layer name]
846		} elseif {$lnum == [+ $i 1]} {
847		    set tlayer [dict get $layer name]
848		}
849	    } elseif {[dict get $layer type] == "CUT"} {
850		set lnum [dict get $layer number]
851		if {$lnum == $i} {
852		    set clayer [dict get $layer name]
853		    if [catch {set cwidth [dict get $layer width]}] {set cwidth 0}
854		    if [catch {set cspace [dict get $layer spacing]}] {set cspace 0}
855		}
856	    }
857	}
858
859	set bestvia ""
860	set bestarea 0
861	set bestwidth 0
862	set bestheight 0
863	set bestcutwidth 0
864	set bestcutsep 0
865
866	# First look in the VIARULE records, then fall back on VIA records.
867
868	foreach viarule $viarules {
869	    set viarulename [dict get $viarule name]
870            set match 0
871	    dict for {layername viarulespec} $viarule {
872		if {$layername == $tlayer} {
873		    incr match
874		} elseif {$layername == $blayer} {
875		    incr match
876		}
877	    }
878	    if {$match == 2} {		;# Found matching VIARULE
879		lappend baseviarules ${viarulename}
880		lappend basevias ""
881		lappend viaoffsets 0
882		lappend viaheights [dict get $viarule height]
883		lappend viaspaces 0
884		lappend nvias 0
885		break
886	    }
887	}
888
889	if {$match != 2} {
890	    foreach via $vias {
891		set areab 0
892		set areat 0
893		foreach vlayer [dict keys $via] {
894		    if {$vlayer == $blayer} {
895			set coords [dict get $via $vlayer]
896			set llx [lindex $coords 0]
897			set lly [lindex $coords 1]
898			set urx [lindex $coords 2]
899			set ury [lindex $coords 3]
900			set widthb [expr ($urx - $llx)]
901			set heightb [expr ($ury - $lly)]
902			set areab [expr $widthb * $heightb]
903		    } elseif {$vlayer == $tlayer} {
904			set coords [dict get $via $vlayer]
905			set llx [lindex $coords 0]
906			set lly [lindex $coords 1]
907			set urx [lindex $coords 2]
908			set ury [lindex $coords 3]
909			set widtht [expr ($urx - $llx)]
910			set heightt [expr ($ury - $lly)]
911			set areat [expr $widtht * $heightt]
912		    }
913		}
914		if {($areab > 0) && ($areat > 0)} {
915		    set area [max $areab $areat]
916		    set width [max $widthb $widtht]
917		    set height [max $heightb $heightt]
918		    if {($bestvia == "") || ($area < $bestarea)} {
919			set bestvia [dict get $via name]
920			set bestarea $area
921			set bestwidth $width
922			set bestheight $height
923			if {$cwidth == 0} {
924			    set coords [dict get $via $clayer]
925			    set llx [lindex $coords 0]
926			    set urx [lindex $coords 2]
927			    set bestcutwidth [- $urx $llx]
928			} else {
929			    set bestcutwidth $cwidth
930			}
931			if {$cspace != 0} {
932			    set bestcutsep $cspace
933			}
934		    }
935		}
936	    }
937
938	    if {$bestvia == ""} {
939		puts stdout "Warning:  no via found between $blayer and $tlayer"
940		continue
941	    }
942
943	    if {$bestcutsep == 0} {
944		# If no cut spacing info, assume that abutting vias satisfy
945		# the spacing minimum.
946		set bestcutsep [- $bestwidth $cwidth]
947	    }
948
949	    # Find the minimum separation between these vias.  Find the
950	    # minimum separation of the cuts within the via, and then
951	    # use that to determine the number of vias across a power bus
952
953	    lappend basevias $bestvia
954	    lappend baseviarules ""
955	    lappend viaheights $bestheight
956	    set vspace [expr $bestcutwidth + $bestcutsep]
957	    if {$vspace > 0} {
958		lappend viaspaces $vspace
959
960		# Two computations:  One is simply the available with divided by
961		# the spacing between contacts, with half the space on either
962		# side.  However, if there is a metal overlap that is large,
963		# then the overlap will limit the number of vias, so take the
964		# smaller of the two calculations.
965
966		set numvias1 [expr int(floor($stripewidth / $vspace))]
967		set numvias2 [expr int(floor((($stripewidth - $bestwidth) / ($bestcutwidth + $bestcutsep)) + 1))]
968		set numvias [expr min($numvias1, $numvias2)]
969		if {$numvias2 < $numvias1} {
970		    set voffset [/ [+ $vspace $bestwidth] 2]
971		} else {
972		    set voffset [/ $vspace 2]
973		}
974		lappend viaoffsets $voffset
975		lappend nvias $numvias
976
977		puts stdout "Stripe width $stripewidth fits $numvias $bestvia at cut width $bestcutwidth separation $bestcutsep"
978	    } else {
979		puts stdout "Warning: couldn't get cut size and spacing for via $bestvia"
980		lappend viaspaces $bestwidth
981		lappend nvias [expr floor($stripewidth / $bestwidth)]
982		lappend viaoffsets [/ $bestwidth 2]
983	    }
984	}
985    }
986
987    # topmet will be used to index basevias and layerlist, which are
988    # 0 to tnum - 1, not 1 to tnum, unless there is no top metal to
989    # use for the vertical power bus, in which case it is 1 to tnum.
990
991    if {$tnum >= 3} {
992	set topmet [- $tnum 1]
993    } else {
994	set topmet $tnum
995    }
996
997    set powername [get_power $fillmacro]
998
999    set pllx [set ${fillmacro}(${powername},llx)]
1000    set plly [set ${fillmacro}(${powername},lly)]
1001    set purx [set ${fillmacro}(${powername},urx)]
1002    set pury [set ${fillmacro}(${powername},ury)]
1003    set h [set ${fillmacro}(h)]
1004    set y [/ [+ $plly $pury] 2.0]
1005
1006    puts $fanno "- ${powername}"
1007    set j 0
1008    set first true
1009    foreach stripe $stripeinfo {
1010	set smean [lindex $stripe 0]
1011	set slow  [lindex $stripe 1]
1012	set shigh [lindex $stripe 2]
1013
1014	if {[- $shigh $slow] > 0} {
1015	   set smean [/ [+ $shigh $slow] 2.0]
1016	}
1017	# Make sure smean is on pitch
1018	set nw [expr int($smean / $fmin)]
1019	set smean [* $nw $fmin]
1020
1021	set slow [- $smean [/ $stripewidth 2.0]]
1022	set shigh [+ $smean [/ $stripewidth 2.0]]
1023
1024	set pattern [string index $stripepattern $j]
1025	if {$pattern == "P"} {
1026	    set drows [dict keys $rows]
1027	    foreach rowy $drows {
1028		set orient [lindex [dict get $rows $rowy] 3]
1029		if {$orient == "S" || $orient == "FS"} {
1030		    set ay [- $h $y]
1031		} else {
1032		    set ay $y
1033		}
1034		for {set i 0} {$i < $topmet} {incr i} {
1035		    set ry [+ $rowy $ay]
1036		    set layer [lindex $layerlist $i]
1037		    set via [lindex $basevias $i]
1038		    set viarule [lindex $baseviarules $i]
1039		    set vh [lindex $viaheights $i]
1040		    set ovh [expr int($vh)]
1041
1042		    # If post is in an obstruction area, then skip it.
1043		    set dopost true
1044		    foreach obs $obslist {
1045		       set obsllx [lindex $obs 0]
1046		       set obslly [lindex $obs 1]
1047		       set obsurx [lindex $obs 2]
1048		       set obsury [lindex $obs 3]
1049		       if {$smean > $obsllx && $smean < $obsurx &&
1050				$ry > $obslly && $ry < $obsury} {
1051			  set dopost false
1052			  puts stdout "No post here!"
1053			  break
1054		       }
1055		    }
1056		    if {!$dopost} {continue}
1057
1058		    if $first {
1059		        puts -nonewline $fanno "+ FIXED "
1060		        set first false
1061		    } else {
1062		        puts -nonewline $fanno "  NEW "
1063		    }
1064
1065		    if {$viarule != ""} {
1066                        # Simply put a single VIARULE via
1067			set ory [expr int($ry)]
1068			set osmean [expr int($smean)]
1069			puts $fanno "$layer $ovh ( $osmean $ory ) ( * * ) ${viarule}_post"
1070		    } else {
1071			# No VIARULE, so drop down a number of vias
1072
1073			set vs [lindex $viaspaces $i]
1074			set vo [lindex $viaoffsets $i]
1075			set nv [lindex $nvias $i]
1076			set x1 $slow
1077			set oshigh [expr int($shigh)]
1078			set ory [expr int($ry)]
1079			set ox1 [expr int($x1)]
1080
1081			puts $fanno "$layer $ovh ( $oshigh $ory ) ( $ox1 * )"
1082			set x2 [+ $x1 $vo]
1083			for {set k 0} {$k < $nv} {incr k} {
1084			    set ox1 [expr int($x1)]
1085	    		    set ox2 [expr int($x2)]
1086	    		    puts $fanno "  NEW $layer $ovh ( $ox1 $ory ) ( $ox2 * ) $via"
1087			    set x1 $x2
1088			    set x2 [+ $x1 $vs]
1089			}
1090		    }
1091		}
1092		if {$tnum < 3} {
1093		    # Top metal is just a post.
1094		    set layer [lindex $layerlist $tnum]
1095
1096		    set outvh [expr int($vh)]
1097		    set outshigh [expr int($shigh)]
1098		    set outslow [expr int($slow)]
1099		    set outry [expr int($ry)]
1100
1101		    puts $fanno "  NEW $layer $outvh ( $outslow $outry ) ( $outshigh $outry )"
1102		}
1103	    }
1104	    # At the end, put top vertical metal stripe from top to bottom
1105	    if {$tnum >= 3} {
1106		set layer [lindex $layerlist [- $tnum 1]]
1107
1108		set osmean [expr int($smean)]
1109		puts $fanno "  NEW $layer $stripewidth ( $osmean $dieylow ) ( * $dieyhigh )"
1110	    }
1111	}
1112	incr j
1113    }
1114    puts $fanno " ;"
1115
1116    set groundname [get_ground $fillmacro]
1117
1118    set gllx [set ${fillmacro}(${groundname},llx)]
1119    set glly [set ${fillmacro}(${groundname},lly)]
1120    set gurx [set ${fillmacro}(${groundname},urx)]
1121    set gury [set ${fillmacro}(${groundname},ury)]
1122    set w [- $gury $glly]
1123    set y [/ [+ $glly $gury] 2.0]
1124
1125    puts $fanno "- ${groundname}"
1126    set j 0
1127    set first true
1128    foreach stripe $stripeinfo {
1129	set smean [lindex $stripe 0]
1130	set slow  [lindex $stripe 1]
1131	set shigh [lindex $stripe 2]
1132
1133	if {[- $shigh $slow] > 0} {
1134	   set smean [/ [+ $shigh $slow] 2.0]
1135	}
1136	# Make sure smean is on pitch
1137	set nw [expr int($smean / $fmin)]
1138	set smean [* $nw $fmin]
1139
1140	set slow [- $smean [/ $stripewidth 2.0]]
1141	set shigh [+ $smean [/ $stripewidth 2.0]]
1142
1143	set pattern [string index $stripepattern $j]
1144	if {$pattern == "G"} {
1145	    set drows [dict keys $rows]
1146	    foreach rowy $drows {
1147		set orient [lindex [dict get $rows $rowy] 3]
1148		if {$orient == "S" || $orient == "FS"} {
1149		    set ay [- $h $y]
1150		} else {
1151		    set ay $y
1152		}
1153		for {set i 0} {$i < $topmet} {incr i} {
1154		    set ry [+ $rowy $ay]
1155		    set layer [lindex $layerlist $i]
1156		    set via [lindex $basevias $i]
1157		    set viarule [lindex $baseviarules $i]
1158		    set vh [lindex $viaheights $i]
1159		    set ovh [expr int($vh)]
1160
1161		    # If post is in an obstruction area, then skip it.
1162		    set dopost true
1163		    foreach obs $obslist {
1164		       set obsllx [lindex $obs 0]
1165		       set obslly [lindex $obs 1]
1166		       set obsurx [lindex $obs 2]
1167		       set obsury [lindex $obs 3]
1168		       if {$smean > $obsllx && $smean < $obsurx &&
1169				$ry > $obslly && $ry < $obsury} {
1170			  set dopost false
1171			  break
1172		       }
1173		    }
1174		    if {!$dopost} {continue}
1175
1176		    if $first {
1177		    	puts -nonewline $fanno "+ FIXED "
1178			set first false
1179		    } else {
1180			puts -nonewline $fanno "  NEW "
1181		    }
1182
1183		    if {$viarule != ""} {
1184                        # Simply put a single VIARULE via
1185			set ory [expr int($ry)]
1186			set osmean [expr int($smean)]
1187			puts $fanno "$layer $ovh ( $osmean $ory ) ( * * ) ${viarule}_post"
1188		    } else {
1189			# No VIARULE, so drop down a number of vias
1190
1191			set vs [lindex $viaspaces $i]
1192			set vo [lindex $viaoffsets $i]
1193			set nv [lindex $nvias $i]
1194			set x1 $slow
1195			set oshigh [expr int($shigh)]
1196			set ory [expr int($ry)]
1197			set ox1 [expr int($x1)]
1198
1199			puts $fanno "$layer $ovh ( $oshigh $ory ) ( $ox1 * )"
1200			set x2 [+ $x1 $vo]
1201			for {set k 0} {$k < $nv} {incr k} {
1202			    set ox1 [expr int($x1)]
1203			    set ox2 [expr int($x2)]
1204			    puts $fanno "  NEW $layer $ovh ( $ox1 $ory ) ( $ox2 * ) $via"
1205			    set x1 $x2
1206			    set x2 [+ $x1 $vs]
1207			}
1208		    }
1209		}
1210		if {$tnum < 3} {
1211		    # Top metal is just a post.
1212		    set layer [lindex $layerlist $tnum]
1213		    set ovh [expr int($vh)]
1214		    set oshigh [expr int($shigh)]
1215		    set oslow [expr int($slow)]
1216		    set ory [expr int($ry)]
1217		    puts $fanno "  NEW $layer $ovh ( $oslow $ory ) ( $oshigh $ory )"
1218		}
1219	    }
1220	    # At the end, put top vertical metal stripe from top to bottom
1221	    if {$tnum >= 3} {
1222		set layer [lindex $layerlist [- $tnum 1]]
1223		set osmean [expr int($smean)]
1224		puts $fanno "  NEW $layer $stripewidth ( $osmean $dieylow ) ( * $dieyhigh )"
1225	    }
1226	}
1227	incr j
1228    }
1229    puts $fanno " ;"
1230}
1231
1232#-----------------------------------------------------------------
1233# Write the VIA sections for the power bus posts.
1234#-----------------------------------------------------------------
1235
1236proc write_viarules {fanno stripewidth} {
1237    global viarules
1238
1239    # First pass over rules:  count valid rules
1240    set numvias 0
1241    foreach viarule $viarules {
1242        set llx 0
1243        set lly 0
1244        set urx 0
1245        set ury 0
1246
1247        dict for {layername layerspec} $viarule {
1248            if {[llength $layerspec] == 6} {
1249		# Cut and spacing rule
1250                set llx [lindex $layerspec 0]
1251                set lly [lindex $layerspec 1]
1252                set urx [lindex $layerspec 2]
1253                set ury [lindex $layerspec 3]
1254	    }
1255        }
1256
1257	# Check on bad entries
1258	if {($llx != $urx) && ($lly != $ury)} {incr numvias}
1259    }
1260    if {$numvias == 0} {return}
1261
1262    puts -nonewline $fanno "VIAS $numvias"
1263
1264    set newviarules {}
1265    foreach viarule $viarules {
1266	set viarulename [dict get $viarule name]
1267        # First pass of rule:  Make sure we know the cut size, spacing,
1268        # and overhang.
1269        set xencl 0
1270        set yencl 0
1271        set xspace 0
1272        set yspace 0
1273        set llx 0
1274        set lly 0
1275        set urx 0
1276        set ury 0
1277
1278        dict for {layername layerspec} $viarule {
1279            if {[llength $layerspec] == 2} {
1280		# Enclosure rule (use maximum for top and bottom layers)
1281		set xencl [expr max([lindex $layerspec 0], $xencl)]
1282		set yencl [expr max([lindex $layerspec 1], $yencl)]
1283            } elseif {[llength $layerspec] == 6} {
1284		# Cut and spacing rule
1285                set llx [lindex $layerspec 0]
1286                set lly [lindex $layerspec 1]
1287                set urx [lindex $layerspec 2]
1288                set ury [lindex $layerspec 3]
1289                set xspace [lindex $layerspec 4]
1290                set yspace [lindex $layerspec 5]
1291	    }
1292        }
1293
1294	# Check on bad entries
1295	if {($llx == $urx) || ($lly == $ury)} {continue}
1296
1297        puts -nonewline $fanno " ;\n- ${viarulename}_post"
1298
1299        # Determine post size, and how many via cuts are going to fit.
1300	set posturx [expr int(floor($stripewidth / 2))]
1301	set postllx -$posturx
1302        set postury [expr int($ury + $yencl)]
1303	set postlly [expr int($lly - $yencl)]
1304        # Add record for "height" to the viarule
1305        dict set viarule height [expr $postury - $postlly]
1306	lappend newviarules $viarule
1307	set lly [expr int($lly)]
1308	set ury [expr int($ury)]
1309	set numvias [expr int(floor(($stripewidth - (2 * $xencl) + $xspace) / ($urx - $llx + $xspace)))]
1310        # Determine width from first via cut left side to last via cut right side
1311        set reqwidth [expr int((($urx - $llx) * $numvias) + ($xspace * ($numvias - 1)))]
1312        # Determine the offset from the left side needed to center the vias
1313	set xoffset [expr int($postllx + (($stripewidth - $reqwidth) / 2.0))]
1314
1315        # Second pass of rule:  Write out the via geometry.
1316        dict for {layername layerspec} $viarule {
1317	    if {$layername == "name"} {continue}
1318            if {[llength $layerspec] == 2} {
1319		# Enclosure rule, so this is a metal layer.  Write the bounds.
1320		puts -nonewline $fanno "\n+ RECT ${layername} ( $postllx $postlly ) ( $posturx $postury )"
1321	    } elseif {[llength $layerspec] == 6} {
1322		# Cut and spacing rule, so this is a cut layer.  Write all the cuts
1323		for {set i 0} {$i < $numvias} {incr i} {
1324                    set xnext [expr int($xoffset + $urx - $llx)]
1325		    puts -nonewline $fanno "\n+ RECT ${layername} ( $xoffset $lly ) ( $xnext $ury )"
1326                    set xoffset [expr int($xnext + $xspace)]
1327		}
1328	    }
1329        }
1330    }
1331
1332    puts $fanno " ;\nEND VIAS"
1333    puts $fanno ""
1334    set viarules $newviarules
1335}
1336
1337#-----------------------------------------------------------------
1338# Read the DEF file once to get the number of rows and the length
1339# of each row
1340#-----------------------------------------------------------------
1341
1342puts stdout "Reading DEF file ${defname}. . ."
1343flush stdout
1344
1345while {[gets $fdef line] >= 0} {
1346    if [regexp {[ \t]*#} $line lmatch] {
1347	continue
1348    } elseif [regexp {[ \t]*COMPONENTS[ \t]+([^ \t]+)[ \t]*;} $line lmatch number] {
1349	set rows [dict create]
1350	# Parse the "COMPONENTS" statement
1351	parse_components $fdef rows
1352    } elseif [regexp {[ \t]*NETS[ \t]+([^ \t]+)} $line lmatch netnums] {
1353	skip_section $fdef NETS
1354    } elseif [regexp {[ \t]*SPECIALNETS[ \t]+([^ \t]+)} $line lmatch netnums] {
1355	skip_section $fdef SPECIALNETS
1356    } elseif [regexp {[ \t]*PINS[ \t]+([^ \t]+)} $line lmatch pinnum] {
1357	skip_section $fdef PINS
1358    } elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] {
1359	skip_section $fdef $viarulename
1360    } elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)[ \t]*$} $line lmatch vianame] {
1361	lappend vias [parse_via $fdef $vianame]
1362    } elseif [regexp {[ \t]*END[ \t]+DESIGN[ \t]*$} $line lmatch] {
1363	break
1364    } elseif [regexp {^[ \t]*#} $line lmatch] {
1365	# Comment line, ignore.
1366    } elseif ![regexp {^[ \t]*$} $line lmatch] {
1367	# Other things we don't care about
1368	set matches 0
1369	if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] {
1370	    incr matches
1371	} elseif [regexp {[ \t]*VERSION} $line lmatch] {
1372	    incr matches
1373	} elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] {
1374	    incr matches
1375	} elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] {
1376	    incr matches
1377	} elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] {
1378	    incr matches
1379	} elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] {
1380	    incr matches
1381	} elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] {
1382	    incr matches
1383	} elseif [regexp {[ \t]*DESIGN} $line lmatch] {
1384	    incr matches
1385	} elseif [regexp {[ \t]*UNITS} $line lmatch] {
1386	    incr matches
1387	} elseif [regexp {[ \t]*DIEAREA} $line lmatch] {
1388	    incr matches
1389	} elseif [regexp {[ \t]*TRACKS} $line lmatch] {
1390	    incr matches
1391	} elseif [regexp {[ \t]*ROW} $line lmatch] {
1392	    incr matches
1393	} else {
1394	    puts stderr "Unexpected input in DEF file:"
1395	    puts stdout "Line is: $line"
1396	}
1397    }
1398}
1399
1400close $flef
1401close $fdef
1402
1403# Sort array of fill cells by width
1404
1405set fillwidths {}
1406foreach macro $fillcells {
1407    lappend fillwidths [list $macro [set ${macro}(w)]]
1408}
1409set fillwidths [lsort -decreasing -index 1 $fillwidths]
1410
1411# puts stdout "Here are the fill cell widths:  $fillwidths"
1412
1413# For each row, add the width of the last cell in that row
1414# to get the row end X value
1415
1416dict for {row rowvals} $rows {
1417    set xmax [lindex $rowvals 0]
1418    set macro [lindex $rowvals 2]
1419    set xmax [+ $xmax [set ${macro}(w)]]
1420    set rowvals [lreplace $rowvals 0 0 $xmax]
1421    dict set rows $row $rowvals
1422}
1423
1424# Find number of rows and longest row
1425set numrows 0
1426set rowmax 0
1427dict for {row rowvals} $rows {
1428    incr numrows
1429    set xmax [lindex $rowvals 0]
1430    if {$xmax > $rowmax} {set rowmax $xmax}
1431}
1432puts stdout "Number of rows is $numrows"
1433puts stdout "Longest row has width [/ $rowmax [+ $units 0.0]] um"
1434
1435# Now, for each row, find the difference between the row end and row max,
1436# and create a list of how many of each fill macro it takes to fill the
1437# row out to the maximum distance
1438
1439set numfills 0
1440dict for {row rowvals} $rows {
1441    set xmax [lindex $rowvals 0]
1442    set xd [- $rowmax $xmax]
1443    set fills {}
1444    foreach fillset $fillwidths {
1445	set fw [lindex $fillset 1]
1446	set fn [floor [/ $xd $fw]]
1447	lappend fills [list [lindex $fillset 0] [int $fn]]
1448	set xd [- $xd [* $fn $fw]]
1449	incr numfills [int $fn]
1450    }
1451    lappend rowvals $fills
1452    dict set rows $row $rowvals
1453}
1454set numcomps [+ $number $numfills]
1455
1456# Analyze design for power striping
1457
1458if {$dostripes} {
1459    set stripefills {}
1460}
1461
1462if {$dostripes} {
1463
1464    # What sizes of fill make up the stripe width, to the nearest unit cell?
1465
1466    set xtot 0
1467    while {1} {
1468	set fidx 0
1469	set fmax 0
1470	set fmin -1
1471	set fmidx -1
1472	set i 0
1473	foreach fillset $fillwidths {
1474	    set fw [lindex $fillset 1]
1475	    set ftest [+ $fw $xtot]
1476	    if {($ftest <= $stripewidth) && ($ftest > $fmax)} {
1477		set fmax $fw
1478		set fidx $i
1479	    }
1480	    if {$fmin < 0} {
1481		set fmin $fw
1482		set fmidx $i
1483	    } elseif {$fmin > $fw} {
1484		set fmin $fw
1485		set fmidx $i
1486	    }
1487	    incr i
1488	}
1489	if {$fmax == 0} {
1490	    # If xtot is zero, then there were no fill cells narrower than
1491	    # the stripe width, so just choose the smallest fill cell.
1492	    if {$xtot == 0} {
1493		lappend stripefills [lindex [lindex $fillwidths $fmidx] 0]
1494		set xtot [+ $xtot $fmin]
1495	    }
1496	    break
1497	}
1498	lappend stripefills [lindex [lindex $fillwidths $fidx] 0]
1499	set xtot [+ $xtot $fmax]
1500
1501	puts stdout "Added to stripe filler [lindex [lindex $fillwidths $fidx] 0]"
1502	puts stdout "Total stripe width now $xtot"
1503    }
1504    # Reduce final stripe width to xtot so that it is equal to the
1505    # best compatible fill size and is a multiple of the unit cell
1506    # size.
1507    set stripewidth $xtot
1508
1509    # If pitchx was given in the tech LEF file, then use that as the
1510    # minimum pitch to snap values to.  If not, use the minimum fill
1511    # cell size.
1512    if {$pitchx > 0} {set fmin $pitchx}
1513
1514    # Reduce stripepitch to a multiple of the minimum cell size
1515    # (note:  should change this to a multiple of track pitch)
1516    set nw [expr int($stripepitch / $fmin)]
1517    set stripepitch [* $nw $fmin]
1518
1519    # How many stripes need to be added?  Allow +/-50% (max) to
1520    # accomodate layout widths that are not a multiple of the
1521    # stripe pitch.  "numstripes" does not include power stripes
1522    # outside of the track area on right and left sides.
1523
1524    set gunits [+ $units 0.0]
1525    if $dostretch {
1526	set numstripes [expr int($rowmax / $stripepitch) - 1]
1527	while true {
1528	    set rowmaxeff [+ $rowmax [* $numstripes $stripewidth]]
1529	    set newstripes [expr int(($rowmaxeff + 0.5 * $stripepitch) / $stripepitch) - 1]
1530	    if {$newstripes == $numstripes} {break}
1531	    set numstripes $newstripes
1532	}
1533	if {$numstripes < 2} {
1534	    # Recalculate to make sure there are at least one stripe each
1535	    # for power and ground.
1536	    set oldpitch $stripepitch
1537	    set oldpattern $stripepattern
1538            if {[string range $stripepattern 0 0] == "G"} {
1539	        set stripepattern "GP"
1540	    } else {
1541	        set stripepattern "PG"
1542	    }
1543	    set stripepitch [expr ($rowmax + 2 * $stripewidth) / 2.5]
1544	    set numstripes 2
1545	    puts stdout "addspacers:  No room for stripes, pitch reduced from ${oldpitch} to ${stripepitch}."
1546	}
1547	set stripeoffset [expr $stripepitch - (($stripepitch * ($numstripes + 1)) - $rowmax) / 2]
1548	set nw [expr int($stripeoffset / $fmin)]
1549	set stripeoffset [* $nw $fmin]
1550
1551	# Number of components increases by number of fill cells per stripe *
1552	# number of stripes * number of rows.
1553	set numfills [* [llength $stripefills] $numstripes $numrows]
1554	set numcomps [+ $numcomps $numfills]
1555	puts stdout "addspacers:  Inserting $numstripes stripes of width [/ $stripewidth $gunits] um ($stripewidthreq um requested)"
1556	puts stdout "  Pitch [/ $stripepitch $gunits] um, offset [/ $stripeoffset $gunits] um"
1557	puts stdout "stretch:  Number of components is $numcomps"
1558    } else {
1559	set numstripes [expr int(($rowmax + 0.5 * $stripepitch) / $stripepitch) - 1]
1560	if {$numstripes == 0} {
1561	    set stripewidth 0
1562	    set dostripes false
1563	    puts stdout "addspacers:  No room for stripes, none added."
1564	} else {
1565	    set stripeoffset [expr $stripepitch - (($stripepitch * ($numstripes + 1)) - $rowmax) / 2]
1566	    set nw [expr int($stripeoffset / $fmin)]
1567	    set stripeoffset [* $nw $fmin]
1568	    puts stdout "addspacers:  Inserting $numstripes stripes of width [/ $stripewidth $gunits] um ($stripewidthreq um requested)"
1569	    puts stdout "  Pitch [/ $stripepitch $gunits] um, offset [/ $stripeoffset $gunits] um"
1570	}
1571    }
1572
1573    # Analyze design for the number of power bus stripes to add
1574
1575    # Duplicate "stripepattern" to (at least) the length of (numstripes + 2)
1576    set pattern ""
1577    while {[string length $pattern] < [+ $numstripes 2]} {
1578	append pattern $stripepattern
1579    }
1580    set stripepattern $pattern
1581}
1582
1583# Diagnostic
1584puts stdout "Analysis of DEF file:"
1585puts stdout "Number of components = $number"
1586puts stdout "New number of components = $numcomps"
1587puts stdout "Number of rows = [llength [dict keys $rows]]"
1588
1589set fdef [open $defname r]
1590
1591if [catch {open $defoutname w} fanno] {
1592    puts stderr "Error: can't open file $defoutname for output"
1593    exit 1
1594}
1595
1596#-----------------------------------------------------------------
1597# Read the DEF file a second time to get the number of rows and the length
1598# of each row
1599#-----------------------------------------------------------------
1600
1601# Each stripe has a record of center point and width of free space from
1602# cell top to bottom (list over rows)
1603set stripeinfo {}
1604# Each row has a record of X position of the stripe fill (list over stripes).
1605set rowstripeinfo {}
1606
1607set needspecial $dostripes
1608
1609if {$dostretch == false} {
1610    # If not stretching the area under the power stripes with fill, the
1611    # stripeinfo record needs to be filled with the position of each
1612    # stripe so that write_special gets this information
1613
1614    set xpos $stripeoffset
1615    set ns 0
1616    while {$ns < $numstripes} {
1617	set sinfo $xpos
1618	lappend sinfo [- $xpos [/ $stripewidth 2.0]]
1619	lappend sinfo [+ $xpos [/ $stripewidth 2.0]]
1620	lappend stripeinfo $sinfo
1621	set xpos [+ $xpos $stripepitch]
1622	incr ns
1623    }
1624}
1625
1626#-----------------------------------------------------------------
1627# If there is a ${topname}.obs file, read it in and adjust the
1628# X values to account for the spacers.  This also records the
1629# obstruction areas so the script does not place power posts in
1630# them.
1631#-----------------------------------------------------------------
1632
1633if {$dostripes && $dostretch} {
1634
1635    # Cast values back into microns, which are the units used by the .obs file
1636    set gunits [+ $units 0.0]
1637    set gwidth [/ $stripewidth $gunits]
1638    set gpitch [/ $stripepitch $gunits]
1639    set goffset [/ $stripeoffset $gunits]
1640
1641    if [catch {open ${topname}.obs r} infobs] {
1642	# No .obs file, no action needed.
1643	puts stdout "No file ${topname}.obs, so no adjustment required."
1644	exit 0
1645    }
1646    if [catch {open ${topname}.obsx w} outfobs] {
1647	puts stout "Error:  Cannot open file ${topname}.obsx for writing!"
1648	exit 1
1649    }
1650    puts stdout "Adjusting obstructions for power striping"
1651    # puts stdout "numstripes = $numstripes"
1652    # puts stdout "stripewidth = $gwidth um"
1653    # puts stdout "stripepitch = $gpitch um"
1654    # puts stdout "stripeoffset = $goffset um"
1655
1656    while {[gets $infobs line] >= 0} {
1657	if [regexp {[ \t]*obstruction[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]*$} $line \
1658			lmatch xlow ylow xhigh yhigh layer] {
1659            # puts stdout "In: $xlow $ylow $xhigh $yhigh $layer"
1660	    if {$xlow > $goffset} {
1661		set ns [expr int(($xlow - $goffset + $gpitch) / $gpitch)]
1662		if {$ns > $numstripes} {set ns $numstripes}
1663		set nw [* $ns $gwidth]
1664		set xlow [+ $xlow $nw]
1665		# puts stdout "xlow adjust ns = $ns nw = $nw"
1666	    }
1667	    if {$xhigh > $goffset} {
1668		set ns [expr int(($xhigh - $goffset + $gpitch) / $gpitch)]
1669		if {$ns > $numstripes} {set ns $numstripes}
1670		set nw [* $ns $gwidth]
1671		set xhigh [+ $xhigh $nw]
1672		# puts stdout "xhigh adjust ns = $ns nw = $nw"
1673	    }
1674            # Ensure numerical precision matches DEF file units
1675	    set xlow [expr round($xlow * $gunits) / $gunits]
1676	    set xhigh [expr round($xhigh * $gunits) / $gunits]
1677            # puts stdout "Out: $xlow $ylow $xhigh $yhigh $layer"
1678	    puts $outfobs "obstruction $xlow $ylow $xhigh $yhigh $layer"
1679	    # obslist shows where to NOT put power posts.  It is layer independent.
1680	    lappend obslist [list $xlow $ylow $xhigh $yhigh]
1681	} else {
1682	    puts $outfobs $outline
1683	}
1684    }
1685    close $outfobs
1686    close $infobs
1687}
1688
1689# Convert obslist to DEF units and remove redundant entries
1690set newlist {}
1691set obslast {}
1692foreach obs $obslist {
1693    set xlow [lindex $obs 0]
1694    set ylow [lindex $obs 1]
1695    set xhigh [lindex $obs 2]
1696    set yhigh [lindex $obs 3]
1697    if {($xlow != [lindex $obslast 0]) || ($ylow != [lindex $obslist 1]) ||
1698		($xhigh == [lindex $obslast 2]) || ($yhigh != [lindex $obslist 3])} {
1699	set xlow [expr {round($xlow * $units)}]
1700	set ylow [expr {round($ylow * $units)}]
1701	set xhigh [expr {round($xhigh * $units)}]
1702	set yhigh [expr {round($yhigh * $units)}]
1703	lappend newlist [list $xlow $ylow $xhigh $yhigh]
1704        set obslast $obs
1705    }
1706}
1707set obslist $newlist
1708
1709set newinstlist {}
1710
1711while {[gets $fdef line] >= 0} {
1712    if [regexp {[ \t]*#} $line lmatch] {
1713	continue
1714    } elseif [regexp {[ \t]*DIEAREA[ \t]*\([ \t]*([^ \t]+)[ \t]+([^ \t]+)[ \t]*\)[ \t]*\([ \t]*([^ \t]+)[ \t]+([^ \t]+)[ \t]*\)[ \t]*;} $line lmatch \
1715		diexlow dieylow diexhigh dieyhigh] {
1716
1717	# Add stripe width to die area total
1718	if $dostretch {
1719	    set diexhigh [+ $diexhigh [* $stripewidth $numstripes]]
1720	    puts $fanno "DIEAREA ( $diexlow $dieylow ) ( $diexhigh $dieyhigh ) ;"
1721	} else {
1722	    puts $fanno $line
1723	}
1724
1725    } elseif [regexp {[ \t]*TRACKS[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+DO[ \t]+([^ \t]+)[ \t]+STEP[ \t]+([^ \t]+)[ \t]+LAYER[ \t]+([^ \t]+)[ \t]*;} $line lmatch \
1726		orient low num step layer] {
1727
1728	if {$dostretch && ($stripewidth > 0) && ($orient == "X")} {
1729	    # Add number of tracks to cover the added area of the stripes
1730	    set ntracks [expr int(($stripewidth * $numstripes) / $step)]
1731	    set num [+ $num $ntracks]
1732	    puts $fanno "TRACKS X $low DO $num STEP $step LAYER $layer ;"
1733	} else {
1734	    puts $fanno $line
1735	}
1736
1737    } elseif [regexp {[ \t]*PINS[ \t]+([^ \t]+)[ \t]*;} $line lmatch number] {
1738
1739	# Add space to pins to match the addition of stripes
1740	set extrapins false
1741	if {$dostripes} {
1742
1743	    # Note:  This duplicates code in write_special.  Needs to be
1744	    # consolidated into one routine.
1745
1746	    set tnum 0
1747	    foreach layer $layers {
1748		if {[dict get $layer type] != "ROUTING"} {continue}
1749		if {[dict get $layer direction] == "VERTICAL"} {
1750		    set lnum [dict get $layer number]
1751		    if {$lnum > $tnum} {
1752			set tnum $lnum
1753			set toplayer [dict get $layer name]
1754		    }
1755		}
1756	    }
1757	    if {$tnum >= 3} {set extrapins true}
1758	}
1759	if {$extrapins} {
1760
1761	    puts $fanno "PINS [+ $number 2] ;"
1762	    set i 0
1763	    set donepower false
1764	    set doneground false
1765	    set fillmacro [lindex $stripefills 0]
1766	    foreach stripe ${stripeinfo} {
1767
1768		set stripetype [string index $stripepattern $i]
1769		set smean [lindex $stripe 0]
1770		set slow [lindex $stripe 1]
1771		set shigh [lindex $stripe 2]
1772		if {[- $shigh $slow] > 0} {
1773		    set smean [/ [+ $shigh $slow] 2.0]
1774		}
1775		set nw [expr int($smean / $fmin)]
1776		set smean [* $nw $fmin]
1777		set hw [/ $stripewidth 2.0]
1778		set qw [/ $hw 2.0]
1779		set qw [expr int($qw + 0.5)]	;# ensure qw is integer
1780		set slow [- $smean $hw]
1781		set shigh [+ $smean $hw]
1782		set cy [+ $dieylow $qw]
1783
1784		set ohw [expr int($hw)]
1785		set osmean [expr int($smean)]
1786
1787		if {!$donepower && ($stripetype == "P")} {
1788		    set powername [get_power $fillmacro]
1789		    puts $fanno "- $powername + NET $powername"
1790		    puts $fanno "  + LAYER $toplayer ( -$ohw -$qw ) ( $ohw $qw )"
1791		    puts $fanno "  + PLACED ( $osmean $cy ) N ;"
1792		    set donepower true
1793		} elseif {!$doneground && ($stripetype == "G")} {
1794		    set groundname [get_ground $fillmacro]
1795		    puts $fanno "- $groundname + NET $groundname"
1796		    puts $fanno "  + LAYER $toplayer ( -$ohw -$qw ) ( $ohw $qw )"
1797		    puts $fanno "  + PLACED ( $osmean $cy ) N ;"
1798		    set doneground true
1799		}
1800		incr i
1801		if {$donepower && $doneground} {break}
1802	    }
1803	} else {
1804	    puts $fanno $line
1805	}
1806
1807	if {$dostripes && $dostretch} {
1808	    while {[gets $fdef line] >= 0} {
1809		if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] {
1810		    puts $fanno $line
1811		    break
1812		} elseif [regexp {[ \t]*\+[ \t]+PLACED[ \t]+\([ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+\)[ \t]+([^ \t]+)[ \t]+;} $line lmatch \
1813			px py orient] {
1814
1815		    # Check if instance px exceeds xbreak and adjust accordingly
1816		    if {$px > $stripepitch} {
1817			set ns [expr int($px / $stripepitch)]
1818			if {$ns > $numstripes} {set ns $numstripes}
1819			set nw [* $ns $stripewidth]
1820			set xpos [+ $px $nw]
1821			puts $fanno "  + PLACED ( $xpos $py ) $orient ;"
1822		    } else {
1823			puts $fanno $line
1824		    }
1825		} else {
1826		    puts $fanno $line
1827		}
1828	    }
1829	}
1830
1831    } elseif [regexp {[ \t]*COMPONENTS[ \t]+([^ \t]+)[ \t]*;} $line lmatch number] {
1832
1833        # Prior to writing components, check if there are viarules and write VIA
1834        # entries for the power bus post contacts.
1835        if {$dostripes && ([llength $viarules] > 0)} {
1836	    write_viarules $fanno $stripewidth
1837        }
1838
1839	puts $fanno "COMPONENTS $numcomps ;"
1840	set r 0
1841	set s 0
1842	set xadd 0
1843	if {$dostripes && $dostretch} {
1844	    set xbreak $stripeoffset
1845	} else {
1846	    set xbreak $rowmax
1847	}
1848	while {[gets $fdef line] >= 0} {
1849	    if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] {
1850		puts $fanno $line
1851
1852		if {$dostripes} {
1853		    # Finish computing values of internal stripes
1854		    # replace total with mean, and copy the bounds values
1855		    set newinfo {}
1856		    foreach stripe ${stripeinfo} {
1857			set smean [lindex $stripe 0]
1858			set slow [lindex $stripe 1]
1859			set shigh [lindex $stripe 2]
1860			set smean [/ $smean $numrows]
1861			lappend newinfo [list $smean $slow $shigh]
1862		    }
1863		    set stripeinfo $newinfo
1864		}
1865		break
1866
1867	    } elseif [regexp {[ \t]*-[ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+\+[ \t]+PLACED[ \t]+\([ \t]+([^ \t]+)[ \t]+([^ \t]+)[ \t]+\)[ \t]+([^ \t]+)[ \t]+;} $line lmatch \
1868			instance macro px py orient] {
1869
1870		# Quick check if the right side of instance exceeds xbreak and
1871		# if placing the stripe before the instance will put the stripe
1872		# closer to the ideal position.
1873
1874		set pw [set ${macro}(w)]
1875		set right [+ $px $pw]
1876
1877		# Check if instance position px exceeds xbreak and adjust accordingly
1878		if {($px >= $xbreak) || ([- $xbreak $px] < [- [+ $px $pw] $xbreak])} {
1879
1880		    if {[llength $rowstripeinfo] < $numstripes} {
1881
1882			# Add to row stripe info
1883			lappend rowstripeinfo [+ $px $xadd]
1884
1885			# Add fill in the stripe area
1886			set i 0
1887			foreach fmacro $stripefills {
1888			    set fw [set ${fmacro}(w)]
1889			    set xpos [+ $px $xadd]
1890			    set newinstname ${fmacro}_${r}_${s}_${i}
1891			    puts $fanno "- ${newinstname} ${fmacro} + PLACED ( $xpos $py ) $orient ;"
1892			    set fpin [get_inputpin ${fmacro}]
1893			    lappend newinstlist [list $newinstname $fmacro $fpin]
1894			    set xadd [+ $xadd $fw]
1895			    incr i
1896			}
1897			if {$s < $numstripes} {
1898			    set xbreak [+ $xbreak $stripepitch]
1899			    incr s
1900			} else {
1901			    set xbreak $rowmax
1902			}
1903		    }
1904		}
1905		set px [+ $px $xadd]
1906		puts $fanno "- $instance $macro + PLACED ( $px $py ) $orient ;"
1907
1908		# Check if there is a match to the last instance in the row
1909		set rowvals [dict get $rows $py]
1910		set rowinst [lindex $rowvals 1]
1911		if {[string equal $instance $rowinst]} {
1912		    incr r
1913		    set xpos [lindex $rowvals 0]
1914		    if {$dostripes && $dostretch} {
1915			# puts stdout "stripewidth = $stripewidth"
1916			# puts stdout "numstripes = $numstripes"
1917			# puts stdout "xpos in = $xpos"
1918			set xpos [+ $xpos [* $stripewidth $numstripes]]
1919			# puts stdout "xpos out = $xpos"
1920		    }
1921		    set fills [lindex $rowvals 4]
1922		    # Get orientation of row (N or S);
1923		    # remove "F" if last cell was flipped
1924		    set orient [string index [lindex $rowvals 3] end]
1925		    foreach fpair $fills {
1926			set fmacro [lindex $fpair 0]
1927			set fw [set ${fmacro}(w)]
1928			set fn [lindex $fpair 1]
1929			for {set i 1} {$i <= $fn} {incr i} {
1930			    set newinstname ${fmacro}_${r}_${i}
1931			    puts $fanno "- ${newinstname} ${fmacro} + PLACED ( $xpos $py ) $orient ;"
1932			    set fpin [get_inputpin ${fmacro}]
1933			    lappend newinstlist [list $newinstname $fmacro $fpin]
1934			    set xpos [+ $xpos $fw]
1935			}
1936		    }
1937		    # Add rowstripeinfo values to stripeinfo
1938		    # Reset xbreak, xadd, and rowstripeinfo
1939		    if {$dostretch && ($xadd > 0)} {
1940			set xadd 0
1941			set xbreak $stripeoffset
1942			set i 0
1943			set newstripeinfo {}
1944			if {[llength $stripeinfo] == 0} {
1945			    foreach sx $rowstripeinfo {
1946				set slow $sx
1947				set shigh [+ $sx $stripewidth]
1948				set smean [+ $sx [/ $stripewidth 2.0]]
1949				lappend newstripeinfo [list $smean $slow $shigh]
1950			    }
1951			} else {
1952			    foreach sx $rowstripeinfo {
1953				if {[catch {set sinfo [lindex $stripeinfo $i]}] || \
1954					[llength $sinfo] == 0} {
1955				    set slow $sx
1956				    set shigh [+ $sx $stripewidth]
1957				    set smean [+ $sx [/ $stripewidth 2.0]]
1958				} else {
1959				    set slow  [max [lindex $sinfo 1] $sx]
1960				    set shigh [min [lindex $sinfo 2] [+ $sx $stripewidth]]
1961				    set smean [+ [lindex $sinfo 0] [+ $sx [/ $stripewidth 2.0]]]
1962				}
1963				incr i
1964				lappend newstripeinfo [list $smean $slow $shigh]
1965			    }
1966			}
1967			set stripeinfo $newstripeinfo
1968			set rowstripeinfo {}
1969			set s 0
1970		    }
1971		}
1972 	    }
1973	}
1974    } elseif [regexp {[ \t]*END[ \t]+DESIGN} $line lmatch] {
1975	if {$needspecial == true} {
1976	    puts $fanno "SPECIALNETS 2 ;"
1977	    write_special $stripeinfo $stripefills $stripewidth $stripepattern \
1978			$rows $dieylow $dieyhigh $fanno
1979	    puts $fanno "END SPECIALNETS"
1980	}
1981	puts $fanno $line
1982    } elseif [regexp {[ \t]*SPECIALNETS[ \t]+([^ \t]+)} $line lmatch netnums] {
1983	if {$needspecial == true} {
1984	    puts $fanno "SPECIALNETS [+ 2 $netnums] ;"
1985	    write_special $stripeinfo $stripefills $stripewidth $stripepattern \
1986			$rows $dieylow $dieyhigh $fanno
1987	    set needspecial false
1988	}
1989    } else {
1990	puts $fanno $line
1991    }
1992}
1993
1994close $fanno
1995close $fdef
1996if {$techlef != ""} {
1997    close $ftech
1998}
1999
2000# Output the list of new instances added.  The file will have already
2001# been created by the "decongest" script if density reducing fill was
2002# added, so open in "append" mode.
2003
2004if [catch {open fillcells.txt a} ffill] {
2005    puts stderr "Error: can't open file fillcells.txt for output (ignoring)"
2006    # Not a fatal error, although it will cause issues with LVS if
2007    # antenna cells are used.
2008} else {
2009    # Note that the net name is unused, but must be unique to be parsed
2010    # correctly by the annotation script.
2011    set ncnet __spacer_nc_
2012    set ncnum 0
2013    foreach triplet $newinstlist {
2014	puts $ffill "Net=$ncnet$ncnum Instance=[lindex $triplet 0] Cell=[lindex $triplet 1] Pin=[lindex $triplet 2]"
2015	incr ncnum
2016    }
2017    close $ffill
2018}
2019
2020puts stdout "Done with addspacers.tcl"
2021