Added a new script in common/ "cleanup_unref.py" which removes all
parameterized cell layouts from a directory that are unreferenced
by any other layout file. These "orphan" cells are commonly left
behind when changing parameter values of parameterized cells.
diff --git a/common/cleanup_unref.py b/common/cleanup_unref.py
new file mode 100755
index 0000000..23f1805
--- /dev/null
+++ b/common/cleanup_unref.py
@@ -0,0 +1,120 @@
+#!/usr/bin/env python3
+#
+# cleanup_unref.py: Look up all .mag files in the indicated path, and
+# parse all files for "use" lines and make a list of all the cells being
+# used. Next, check all files to determine which ones are parameterized
+# PDK cells (those that have "string gencell" in the properties section).
+# Finally, remove all the files which represent parametersized PDK cells
+# that are not used anywhere by any other layout file.
+#
+# The purpose of this script is to reduce the number of cells scattered
+# about the filesystem that come from parameterized cells being modified
+# in place. Eventually, magic will be upgraded to have a way to indicate
+# just the cell name and parameters in the .mag file so that all parameterized
+# cells can be generated on-the-fly and do not need to be saved in .mag files.
+#
+# Note that this routine assumes that all files are local to a single project
+# directory and are not being used by layout in some other directory. So use
+# with caution.
+#
+# Usage, e.g.:
+#
+# cleanup_unref.py <path_to_layout>
+
+import os
+import re
+import sys
+import glob
+
+def usage():
+ print("cleanup_unref.py [-remove] <path_to_layout>")
+ return 0
+
+if __name__ == '__main__':
+
+ if len(sys.argv) == 1:
+ usage()
+ sys.exit(0)
+
+ optionlist = []
+ arguments = []
+
+ testmode = True
+ debugmode = False
+
+ for option in sys.argv[1:]:
+ if option.find('-', 0) == 0:
+ optionlist.append(option)
+ else:
+ arguments.append(option)
+
+ if len(arguments) != 1:
+ print("Wrong number of arguments given to cleanup_unref.py.")
+ usage()
+ sys.exit(0)
+
+ if '-remove' in optionlist or '-delete' in optionlist:
+ testmode = False
+ if '-debug' in optionlist:
+ debugmode = True
+
+ filepath = arguments[0]
+
+ magpath = filepath + '/*.mag'
+ sourcefiles = glob.glob(magpath)
+
+ if len(sourcefiles) == 0:
+ print("Warning: No files were found in the path " + filepath + ".")
+
+ usedfiles = []
+ pdkfiles = []
+
+ for file in sourcefiles:
+ if debugmode:
+ print("Checking file " + file)
+ fileroot = os.path.split(file)[1]
+ cellname = os.path.splitext(fileroot)[0]
+
+ proprex = re.compile('^string[ \t]+gencell[ \t]+([^ \t]+)')
+ userex = re.compile('^use[ \t]+([^ \t]+)')
+
+ with open(file, 'r') as ifile:
+ magtext = ifile.read().splitlines()
+ for line in magtext:
+ pmatch = proprex.match(line)
+ if pmatch:
+ pdkfiles.append(cellname)
+ umatch = userex.match(line)
+ if umatch:
+ cellname = umatch.group(1)
+ if cellname not in usedfiles:
+ usedfiles.append(cellname)
+
+ unusedfiles = list(item for item in pdkfiles if item not in usedfiles)
+
+ if debugmode:
+ print('')
+ print('Parameterized cells found:')
+ for cellname in sorted(pdkfiles):
+ print(cellname)
+
+ print('')
+ print('Used cells found:')
+ for cellname in sorted(usedfiles):
+ print(cellname)
+
+ if testmode:
+ # Just report on files that are unused
+ print('')
+ print('Parameterized cells not used by any layout:')
+ for cellname in sorted(unusedfiles):
+ print(cellname)
+ else:
+ # Remove files that are unused
+ for cellname in sorted(unusedfiles):
+ file = filepath + '/' + cellname + '.mag'
+ os.remove(file)
+ print('Removed unused parameterized cell ' + cellname)
+
+ print('')
+ print('Done!')