1#!/usr/local/bin/tclsh8.6 2#--------------------------------------------------------------------------- 3# getpowerground.tcl --- 4# 5# Read LEF file up to the first macro with a PIN record having 6# USE POWER and one having USE GROUND. Return the pin names. 7# If the library has tap cells, then there may be multiple 8# power and ground pins, and all names should be returned. For 9# 4-net power/ground, it is the responsibility of the calling 10# script to use the power/ground names in the setup file to 11# disambiguate between the actual power buses and the tap 12# connections. 13# 14#--------------------------------------------------------------------------- 15namespace path {::tcl::mathop ::tcl::mathfunc} 16 17if {$argc < 1} { 18 puts stdout "Usage: getpowerground <lef_file>" 19 exit 0 20} 21 22puts stdout "Running getpowerground.tcl" 23 24set lefname [lindex $argv 0] 25 26set vddnet {} 27set gndnet {} 28 29#----------------------------------------------------------------- 30# Open lef file for reading 31#----------------------------------------------------------------- 32 33if [catch {open $lefname r} flef] { 34 puts stderr "Error: can't open file $lefname for input" 35 return 36} 37 38#---------------------------------------------------------------- 39# Read through a LEF file section that we don't care about. 40#---------------------------------------------------------------- 41 42proc skip_section {leffile sectionname} { 43 while {[gets $leffile line] >= 0} { 44 if [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch sectiontest] { 45 if {"$sectiontest" != "$sectionname"} { 46 puts -nonewline stderr "Unexpected END statement $line " 47 puts stderr "while reading section $sectionname" 48 } 49 break 50 } 51 } 52} 53 54#---------------------------------------------------------------- 55# Parse the pin contents of the LEF file macro 56#---------------------------------------------------------------- 57 58proc parse_pin {leffile pinname} { 59 global vddnet 60 global gndnet 61 62 set portuse "" 63 while {[gets $leffile line] >= 0} { 64 if [regexp {[ \t]*USE[ \t]+([^ \t]+)[ \t]*;} $line lmatch portuse] { 65 set portuse [string toupper $portuse] 66 if {$portuse == "GROUND"} { 67 if {[lsearch $gndnet $pinname] < 0} { 68 lappend gndnet $pinname 69 } 70 } elseif {$portuse == "POWER"} { 71 if {[lsearch $vddnet $pinname] < 0} { 72 lappend vddnet $pinname 73 } 74 } 75 } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch pintest] { 76 if {"$pintest" == "$pinname"} { 77 break 78 } else { 79 puts stdout "Unexpected END statement $line while parsing pin $pinname" 80 } 81 } 82 } 83} 84 85#---------------------------------------------------------------- 86# Parse the macro contents of the LEF file and retain the information 87# about pin use. 88#---------------------------------------------------------------- 89 90proc parse_macro {leffile macroname} { 91 global vddnet 92 global gndnet 93 94 while {[gets $leffile line] >= 0} { 95 if [regexp {[ \t]*PIN[ \t]+(.+)[ \t]*$} $line lmatch pinname] { 96 parse_pin $leffile $pinname 97 } elseif [regexp {[ \t]*END[ \t]+([^ \t]+)[ \t]*$} $line lmatch macrotest] { 98 if {"$macrotest" == "$macroname"} { 99 break 100 } else { 101 puts stderr "Unexpected END statement $line while reading macro $macroname" 102 } 103 } 104 } 105} 106 107#----------------------------------------------------------------- 108# Read the lef macro file and get the fill cells and their widths 109#----------------------------------------------------------------- 110 111puts stdout "Reading macros from LEF file." 112flush stdout 113 114while {[gets $flef line] >= 0} { 115 if [regexp {[ \t]*MACRO[ \t]+(.+)[ \t]*$} $line lmatch macroname] { 116 # Parse the "macro" statement 117 parse_macro $flef $macroname 118 # Probably the power and ground nets will be set after the first 119 # macro is read. Watch for unbalanced number of vdd net names and 120 # gnd net names caused by having a single-sided tap cell as the 121 # first macro. 122 if {([llength $vddnet] > 1) && ([llength $gndnet] > 1)} { 123 break 124 } elseif {([llength $vddnet] == 1) && ([llength $gndnet] == 1)} { 125 break 126 } 127 } elseif [regexp {[ \t]*LAYER[ \t]+([^ \t]+)} $line lmatch layername] { 128 skip_section $flef $layername 129 } elseif [regexp {[ \t]*VIA[ \t]+([^ \t]+)} $line lmatch vianame] { 130 skip_section $flef $vianame 131 } elseif [regexp {[ \t]*VIARULE[ \t]+([^ \t]+)} $line lmatch viarulename] { 132 skip_section $flef $viarulename 133 } elseif [regexp {[ \t]*SITE[ \t]+(.+)[ \t]*$} $line lmatch sitename] { 134 skip_section $flef $sitename 135 } elseif [regexp {[ \t]*SPACING[ \t]*$} $line lmatch] { 136 skip_section $flef SPACING 137 } elseif [regexp {[ \t]*PROPERTYDEFINITIONS[ \t]*$} $line lmatch] { 138 skip_section $flef PROPERTYDEFINITIONS 139 } elseif [regexp {[ \t]*UNITS[ \t]*$} $line lmatch] { 140 skip_section $flef UNITS 141 } elseif [regexp {[ \t]*END[ \t]+LIBRARY[ \t]*$} $line lmatch] { 142 break 143 } elseif [regexp {^[ \t]*#} $line lmatch] { 144 # Comment line, ignore. 145 } elseif ![regexp {^[ \t]*$} $line lmatch] { 146 # Other things we don't care about 147 set matches 0 148 if [regexp {[ \t]*NAMESCASESENSITIVE} $line lmatch] { 149 incr matches 150 } elseif [regexp {[ \t]*VERSION} $line lmatch] { 151 incr matches 152 } elseif [regexp {[ \t]*BUSBITCHARS} $line lmatch] { 153 incr matches 154 } elseif [regexp {[ \t]*DIVIDERCHAR} $line lmatch] { 155 incr matches 156 } elseif [regexp {[ \t]*USEMINSPACING} $line lmatch] { 157 incr matches 158 } elseif [regexp {[ \t]*CLEARANCEMEASURE} $line lmatch] { 159 incr matches 160 } elseif [regexp {[ \t]*MANUFACTURINGGRID} $line lmatch] { 161 incr matches 162 } 163 } 164} 165 166close $flef 167 168# Use a comma to separate multiple power and ground names 169puts stdout "vddnet=[join $vddnet ","]" 170puts stdout "gndnet=[join $gndnet ","]" 171puts stdout "Done with getpowerground.tcl" 172