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