-
Notifications
You must be signed in to change notification settings - Fork 19
/
powerbus.tcl
executable file
·254 lines (217 loc) · 8.36 KB
/
powerbus.tcl
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
#!/usr/bin/tclsh
#
# Usage:
# powerbus.tcl <rootname> <leffile> <fillcell>
#
# Take the existing <rootname>.cel file for graywolf input,
# and add fixed-placement fill cells for power bus stripes.
#
#------------------------------------------------------------
# Written by Tim Edwards, July 17, 2016
#------------------------------------------------------------
# LEF dimensions are microns unless otherwise stated.
#------------------------------------------------------------
namespace path {::tcl::mathop ::tcl::mathfunc}
if {$argc != 3} {
puts stderr "Bad argument list"
puts stderr "Usage: powerbus.tcl <rootname> <leffile> <fillcell>"
exit 1
}
set units 100
set cellname [file rootname [lindex $argv 0]]
set celfile ${cellname}.cel
set annofile ${cellname}.acel
set lefname [lindex $argv 1]
set fillcell [lindex $argv 2]
if [catch {open $lefname r} flef] {
puts stderr "Error: can't open file $lefname for input"
return
}
if [catch {open $celfile r} fcel] {
puts stderr "Error: can't open file $celfile for input"
return
}
if [catch {open $annofile w} fanno] {
puts stderr "Error: can't open file $annofile for output"
return
}
#----------------------------------------------------------------
# Read through a LEF file section that we don't care about.
#----------------------------------------------------------------
proc skip_section {leffile sectionname} {
while {[gets $leffile line] >= 0} {
if [regexp {[ \t]*END[ \t]+(.+)[ \t]*$} $line lmatch sectiontest] {
if {"$sectiontest" != "$sectionname"} {
puts -nonewline stderr "Unexpected END statement $line "
puts stderr "while reading section $sectionname"
}
break
}
}
}
#----------------------------------------------------------------
# Parse the macro contents of the LEF file and retain the information
# about cell size and pin positions.
#----------------------------------------------------------------
proc parse_macro {leffile macroname} {
global $macroname units
while {[gets $leffile line] >= 0} {
if [regexp {[ \t]*SYMMETRY[ \t]+(.+)[ \t]*;} $line lmatch symmetry] {
set ${macroname}(symmetry) $symmetry
} elseif [regexp {[ \t]*ORIGIN[ \t]+(.+)[ \t]+(.+)[ \t]*;} $line lmatch x y] {
set x [expr {int($x * $units + 0.5)}]
set y [expr {int($y * $units + 0.5)}]
set ${macroname}(x) $x
set ${macroname}(y) $y
} elseif [regexp {[ \t]*SIZE[ \t]+(.+)[ \t]+BY[ \t]+(.+)[ \t]*;} \
$line lmatch w h] {
set w [expr {int($w * $units + 0.5)}]
set h [expr {int($h * $units + 0.5)}]
set ${macroname}(w) $w
set ${macroname}(h) $h
} elseif [regexp {[ \t]*PIN[ \t]+(.+)[ \t]*$} $line lmatch pinname] {
# The fill cell is not expected to have any usable pins
skip_section $leffile $pinname
} elseif [regexp {[ \t]*END[ \t]+(.+)[ \t]*$} $line lmatch macrotest] {
if {"$macrotest" == "$macroname"} {
break
} else {
puts stderr "Unexpected END statement $line while reading macro $macroname"
}
}
}
}
#-----------------------------------------------------------------
# Read the lef macro file and get the fill cells and their widths
#-----------------------------------------------------------------
puts stdout "Reading ${fillcell} macros from LEF file."
flush stdout
set fillcells {}
while {[gets $flef line] >= 0} {
if [regexp {[ \t]*MACRO[ \t]+(.+)[ \t]*$} $line lmatch macroname] {
# Parse the "macro" statement
parse_macro $flef $macroname
if {[string first $fillcell $macroname] == 0} {
# Remember this for later if it's a fill cell
lappend fillcells $macroname
}
} elseif [regexp {[ \t]*LAYER[ \t]+([^ \t]+)} $line lmatch layername] {
skip_section $flef $layername
} elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)} $line lmatch vianame] {
skip_section $flef $vianame
} elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] {
skip_section $flef $viarulename
} elseif [regexp {[ \t]*SITE[ \t]+(.+)[ \t]*$} $line lmatch sitename] {
skip_section $flef $sitename
} elseif [regexp {[ \t]*UNITS[ \t]*$} $line lmatch] {
skip_section $flef UNITS
} elseif [regexp {[ \t]*SPACING[ \t]*$} $line lmatch] {
skip_section $flef SPACING
} elseif [regexp {[ \t]*END[ \t]+LIBRARY[ \t]*$} $line lmatch] {
break
} elseif [regexp {^[ \t]*#} $line lmatch] {
# Comment line, ignore.
} elseif ![regexp {^[ \t]*$} $line lmatch] {
# Other things we don't care about
set matches 0
if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] {
incr matches
} elseif [regexp {[ \t]*VERSION} $line lmatch] {
incr matches
} elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] {
incr matches
} elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] {
incr matches
} elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] {
incr matches
} elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] {
incr matches
} elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] {
incr matches
} else {
puts stderr "Unexpected input in LEF file: Only macro defs were expected!"
puts -nonewline stdout "Line is: $line"
flush stdout
}
}
}
# If the macro file doesn't define any fill cells, there's not a
# whole lot we can do. . .
if {[llength $fillcells] == 0} {
puts stdout "No fill cells (${fillname}) found in macro file ${lefname}!"
exit 1
}
close $flef
# Sort array of fill cells by width
set fillwidths {}
foreach macro $fillcells {
lappend fillwidths [list $macro [subst \$${macro}(w)]]
}
set fillwidths [lsort -decreasing -index 1 -real $fillwidths]
set fillinfo [lindex $fillwidths 0]
set fillmacro [lindex $fillinfo 0]
set fillvalue [lindex $fillinfo 1]
#------------------------------------------------------------------------
# Determine what width of fill cell and how many are needed to
# accomodate VDD and GND stripes.
# Add these cells as "fixed" types on the right and left sides
# (to-do: add additional stripes at intervals depending on the
# estimated layout size based on cell height, total cell width, and
# aspect ratio or number of rows)
#------------------------------------------------------------------------
# NOTE: "500" here is a temporary hack
foreach fillinfo $fillwidths {
if {[lindex $fillinfo 1] < 500} {break}
set pwrbusmacro [lindex $fillinfo 0]
set pwrbuswidth [lindex $fillinfo 1]
}
# Get dimensions of the powerbus fill cell
set right [/ [subst \$${pwrbusmacro}(w)] 2]
set left [- $right [subst \$${pwrbusmacro}(w)]]
set top [/ [subst \$${pwrbusmacro}(h)] 2]
set bottom [- $top [subst \$${pwrbusmacro}(h)]]
# Find the number of rows in the layout; estimate if aspect ratio
# given.
# NOTE: "10" here is a temporary hack
set est_numrows 10
#------------------------------------------------------------------------
# Now read the contents of the cel file. When a cell is found that is
# in the "instlist" list of cells, annotate the next line to increase
# the width by an amount equal to the width of a fill cell.
#
# To do: Use different fill cell widths according to congestion amount;
# or use multiple fill cells (if different widths are not available).
#------------------------------------------------------------------------
set done_pwrbus 0
while {[gets $fcel line] >= 0} {
if [regexp {[ \t]*pad[\t]*[0-9]+} $line lmatch] {
if {$done_pwrbus == 0} {
puts $fanno ""
set j 1
for {set b 1} {$b <= $est_numrows} {incr b} {
puts $fcel ""
puts $fcel "cell $i PWRBUS_$j"
puts $fcel "initially fixed 0 from left of block $b"
puts $fcel "left $left right $right bottom $bottom top $top"
puts $fcel ""
incr i
incr j
}
for {set b 1} {$b <= $est_numrows} {incr b} {
puts $fcel ""
puts $fcel "cell $i PWRBUS_$j"
puts $fcel "initially fixed 0 from right of block $b"
puts $fcel "left $left right $right bottom $bottom top $top"
puts $fcel ""
incr i
incr j
}
puts $fanno ""
set done_pwrbus 1
}
puts $fanno $line ;# append the pad line and continue
} else {
puts $fanno $line ;# append the line and continue
}
}
puts stdout "Done!"