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