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