1#!/usr/local/bin/tclsh8.6
2#
3# Usage:
4#	powerbus.tcl <rootname> <leffile> <fillcell>
5#
6# Take the existing <rootname>.cel file for graywolf input,
7# and add fixed-placement fill cells for power bus stripes.
8#
9#------------------------------------------------------------
10# Written by Tim Edwards, July 17, 2016
11#------------------------------------------------------------
12# LEF dimensions are microns unless otherwise stated.
13#------------------------------------------------------------
14namespace path {::tcl::mathop ::tcl::mathfunc}
15
16if {$argc != 3} {
17   puts stderr "Bad argument list"
18   puts stderr "Usage: powerbus.tcl <rootname> <leffile> <fillcell>"
19   exit 1
20}
21
22set units 100
23
24set cellname [file rootname [lindex $argv 0]]
25
26set celfile ${cellname}.cel
27set annofile ${cellname}.acel
28set lefname [lindex $argv 1]
29set fillcell [lindex $argv 2]
30
31if [catch {open $lefname r} flef] {
32   puts stderr "Error: can't open file $lefname for input"
33   return
34}
35
36if [catch {open $celfile r} fcel] {
37   puts stderr "Error: can't open file $celfile for input"
38   return
39}
40
41if [catch {open $annofile w} fanno] {
42   puts stderr "Error: can't open file $annofile for output"
43   return
44}
45
46#----------------------------------------------------------------
47# Read through a LEF file section that we don't care about.
48#----------------------------------------------------------------
49
50proc skip_section {leffile sectionname} {
51   while {[gets $leffile line] >= 0} {
52      if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] {
53         if {"$sectiontest" != "$sectionname"} {
54            puts -nonewline stderr "Unexpected END statement $line "
55            puts stderr "while reading section $sectionname"
56         }
57         break
58      }
59   }
60}
61
62#----------------------------------------------------------------
63# Parse the macro contents of the LEF file and retain the information
64# about cell size and pin positions.
65#----------------------------------------------------------------
66
67proc parse_macro {leffile macroname} {
68   global $macroname units
69
70   while {[gets $leffile line] >= 0} {
71      if [regexp {[ \t]*SYMMETRY[ \t]+(.+)[ \t]*;} $line lmatch symmetry] {
72         set ${macroname}(symmetry) $symmetry
73      } elseif [regexp {[ \t]*ORIGIN[ \t]+(.+)[ \t]+(.+)[ \t]*;} $line lmatch x y] {
74         set x [expr {int($x * $units + 0.5)}]
75         set y [expr {int($y * $units + 0.5)}]
76         set ${macroname}(x) $x
77         set ${macroname}(y) $y
78      } elseif [regexp {[ \t]*SIZE[ \t]+(.+)[ \t]+BY[ \t]+(.+)[ \t]*;} \
79                        $line lmatch w h] {
80         set w [expr {int($w * $units + 0.5)}]
81         set h [expr {int($h * $units + 0.5)}]
82         set ${macroname}(w) $w
83         set ${macroname}(h) $h
84
85      } elseif [regexp {[ \t]*PIN[ \t]+(.+)[ \t]*$} $line lmatch pinname] {
86	 # The fill cell is not expected to have any usable pins
87	 skip_section $leffile $pinname
88      } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch macrotest] {
89         if {"$macrotest" == "$macroname"} {
90            break
91         } else {
92            puts stderr "Unexpected END statement $line while reading macro $macroname"
93         }
94      }
95   }
96}
97
98#-----------------------------------------------------------------
99# Read the lef macro file and get the fill cells and their widths
100#-----------------------------------------------------------------
101
102puts stdout "Reading ${fillcell} macros from LEF file."
103flush stdout
104
105set fillcells {}
106
107while {[gets $flef line] >= 0} {
108   if [regexp {[ \t]*MACRO[ \t]+(.+)[ \t]*$} $line lmatch macroname] {
109      # Parse the "macro" statement
110      parse_macro $flef $macroname
111      if {[regexp "^$fillcell" $macroname] == 1} {
112	 # Remember this for later if it's a fill cell
113	 lappend fillcells $macroname
114      }
115   } elseif [regexp {[ \t]*LAYER[ \t]+([^ \t]+)} $line lmatch layername] {
116      skip_section $flef $layername
117   } elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)} $line lmatch vianame] {
118      skip_section $flef $vianame
119   } elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] {
120      skip_section $flef $viarulename
121   } elseif [regexp {[ \t]*SITE[ \t]+(.+)[ \t]*$} $line lmatch sitename] {
122      skip_section $flef $sitename
123   } elseif [regexp {[ \t]*UNITS[ \t]*$} $line lmatch] {
124      skip_section $flef UNITS
125   } elseif [regexp {[ \t]*PROPERTYDEFINITIONS[ \t]*$} $line lmatch] {
126      skip_section $flef PROPERTYDEFINITIONS
127   } elseif [regexp {[ \t]*SPACING[ \t]*$} $line lmatch] {
128      skip_section $flef SPACING
129   } elseif [regexp {[ \t]*END[ \t]+LIBRARY[ \t]*$} $line lmatch] {
130      break
131   } elseif [regexp {^[ \t]*#} $line lmatch] {
132      # Comment line, ignore.
133   } elseif ![regexp {^[ \t]*$} $line lmatch] {
134      # Other things we don't care about
135      set matches 0
136      if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] {
137         incr matches
138      } elseif [regexp {[ \t]*VERSION} $line lmatch] {
139         incr matches
140      } elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] {
141         incr matches
142      } elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] {
143         incr matches
144      } elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] {
145         incr matches
146      } elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] {
147         incr matches
148      } elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] {
149         incr matches
150      } else {
151         puts stderr "Unexpected input in LEF file:  Only macro defs were expected!"
152         puts -nonewline stdout "Line is: $line"
153	 flush stdout
154      }
155   }
156}
157
158# If the macro file doesn't define any fill cells, there's not a
159# whole lot we can do. . .
160
161if {[llength $fillcells] == 0} {
162   puts stdout "No fill cells (${fillname}) found in macro file ${lefname}!"
163   exit 1
164}
165
166close $flef
167
168# Sort array of fill cells by width
169
170set fillwidths {}
171foreach macro $fillcells {
172   lappend fillwidths [list $macro [subst \$${macro}(w)]]
173}
174set fillwidths [lsort -decreasing -index 1 -real $fillwidths]
175set fillinfo [lindex $fillwidths 0]
176set fillmacro [lindex $fillinfo 0]
177set fillvalue [lindex $fillinfo 1]
178
179#------------------------------------------------------------------------
180# Determine what width of fill cell and how many are needed to
181# accomodate VDD and GND stripes.
182# Add these cells as "fixed" types on the right and left sides
183# (to-do:  add additional stripes at intervals depending on the
184# estimated layout size based on cell height, total cell width, and
185# aspect ratio or number of rows)
186#------------------------------------------------------------------------
187
188# NOTE:  "500" here is a temporary hack
189
190foreach fillinfo $fillwidths {
191   if {[lindex $fillinfo 1] < 500} {break}
192   set pwrbusmacro [lindex $fillinfo 0]
193   set pwrbuswidth [lindex $fillinfo 1]
194}
195
196# Get dimensions of the powerbus fill cell
197
198set right [/ [subst \$${pwrbusmacro}(w)] 2]
199set left [- $right [subst \$${pwrbusmacro}(w)]]
200set top [/ [subst \$${pwrbusmacro}(h)] 2]
201set bottom [- $top [subst \$${pwrbusmacro}(h)]]
202
203# Find the number of rows in the layout;  estimate if aspect ratio
204# given.
205# NOTE:  "10" here is a temporary hack
206
207set est_numrows 10
208
209#------------------------------------------------------------------------
210# Now read the contents of the cel file.  When a cell is found that is
211# in the "instlist" list of cells, annotate the next line to increase
212# the width by an amount equal to the width of a fill cell.
213#
214# To do:  Use different fill cell widths according to congestion amount;
215# or use multiple fill cells (if different widths are not available).
216#------------------------------------------------------------------------
217
218set done_pwrbus 0
219while {[gets $fcel line] >= 0} {
220   if [regexp {[ \t]*pad[\t]*[0-9]+} $line lmatch] {
221
222      if {$done_pwrbus == 0} {
223         puts $fanno ""
224
225         set j 1
226         for {set b 1} {$b <= $est_numrows} {incr b} {
227            puts $fcel ""
228            puts $fcel "cell $i PWRBUS_$j"
229            puts $fcel "initially fixed 0 from left of block $b
230            puts $fcel "left $left right $right bottom $bottom top $top"
231            puts $fcel ""
232            incr i
233            incr j
234         }
235
236         for {set b 1} {$b <= $est_numrows} {incr b} {
237            puts $fcel ""
238            puts $fcel "cell $i PWRBUS_$j"
239            puts $fcel "initially fixed 0 from right of block $b
240            puts $fcel "left $left right $right bottom $bottom top $top"
241            puts $fcel ""
242            incr i
243            incr j
244         }
245
246         puts $fanno ""
247	 set done_pwrbus 1
248      }
249      puts $fanno $line	  ;# append the pad line and continue
250
251   } else {
252      puts $fanno $line	  ;# append the line and continue
253   }
254}
255
256puts stdout "Done!"
257