Merge branch 'master' of 192.168.0.7:/home/tim/gitsrc/open_pdks/
diff --git a/VERSION b/VERSION
index 5b09c67..b668c3b 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.14
+1.0.16
diff --git a/common/create_gds_library.py b/common/create_gds_library.py
new file mode 100755
index 0000000..23b7553
--- /dev/null
+++ b/common/create_gds_library.py
@@ -0,0 +1,209 @@
+#!/usr/bin/env python3
+#
+# create_gds_library.py
+#
+#----------------------------------------------------------------------------
+# Given a destination directory holding individual GDS files of a number
+# of cells, create a single GDL library file named <alllibname> and place
+# it in the same directory.  This is done for the option "compile" if specified
+# for the "-gds" install.
+#----------------------------------------------------------------------------
+
+import os
+import sys
+import glob
+import fnmatch
+import subprocess
+
+#----------------------------------------------------------------------------
+
+def usage():
+    print('')
+    print('Usage:')
+    print('    create_gds_library <destlibdir> <destlib> <startup_script> ')
+    print('             [-compile-only] [-excludelist="file1,file2,..."] [-keep]')
+    print('')
+    print('Create a single GDS library from a set of individual GDS files.')
+    print('')
+    print('where:')
+    print('    <destlibdir>      is the directory containing the individual GDS files')
+    print('    <destlib>         is the root name of the library file')
+    print('    <startup_script>  is the full path to a magic startup script')
+    print('    -compile-only     removes the indidual files if specified')
+    print('    -excludelist=     is a comma-separated list of files to ignore')
+    print('    -keep             keep the Tcl script used to generate the library')
+    print('')
+
+#----------------------------------------------------------------------------
+
+def create_gds_library(destlibdir, destlib, startup_script, do_compile_only, excludelist, keep):
+
+    alllibname = destlibdir + '/' + destlib + '.gds'
+    if os.path.isfile(alllibname):
+        os.remove(alllibname)
+
+    glist = glob.glob(destlibdir + '/*.gds')
+    glist.extend(glob.glob(destlibdir + '/*.gdsii'))
+    glist.extend(glob.glob(destlibdir + '/*.gds2'))
+    if alllibname in glist:
+        glist.remove(alllibname)
+
+    # Create exclude list with glob-style matching using fnmatch
+    if len(glist) > 0:
+        glistnames = list(os.path.split(item)[1] for item in glist)
+        notglist = []
+        for exclude in excludelist:
+            notglist.extend(fnmatch.filter(glistnames, exclude))
+
+        # Apply exclude list
+        if len(notglist) > 0:
+            for file in glist[:]:
+                if os.path.split(file)[1] in notglist:
+                    glist.remove(file)
+
+    if len(glist) > 1:
+        print('New file is:  ' + alllibname)
+
+        if os.path.isfile(startup_script):
+            # If the symbolic link exists, remove it.
+            if os.path.isfile(destlibdir + '/.magicrc'):
+                os.remove(destlibdir + '/.magicrc')
+            os.symlink(startup_script, destlibdir + '/.magicrc')
+
+        # A GDS library is binary and requires handling in Magic
+        print('Creating magic generation script to generate GDS library.') 
+        with open(destlibdir + '/generate_magic.tcl', 'w') as ofile:
+            print('#!/usr/bin/env wish', file=ofile)
+            print('#--------------------------------------------', file=ofile)
+            print('# Script to generate .gds library from files   ', file=ofile)
+            print('#--------------------------------------------', file=ofile)
+            print('drc off', file=ofile)
+            print('gds readonly true', file=ofile)
+            print('gds flatten true', file=ofile)
+            print('gds rescale false', file=ofile)
+            print('tech unlock *', file=ofile)
+
+            for gdsfile in glist:
+                print('gds read ' + gdsfile, file=ofile)
+
+            print('puts stdout "Creating cell ' + destlib + '"', file=ofile)
+            print('load ' + destlib, file=ofile)
+            print('puts stdout "Adding cells to library"', file=ofile)
+            print('box values 0 0 0 0', file=ofile)
+            for gdsfile in glist:
+                gdsroot = os.path.split(gdsfile)[1]
+                gdsname = os.path.splitext(gdsroot)[0]
+                print('getcell ' + gdsname, file=ofile)
+                # Could properly make space for the cell here. . . 
+                print('box move e 200', file=ofile)
+                                
+            print('puts stdout "Writing GDS library ' + destlib + '"', file=ofile)
+            print('gds library true', file=ofile)
+            print('gds write ' + destlib, file=ofile)
+            print('puts stdout "Done."', file=ofile)
+            print('quit -noprompt', file=ofile)
+
+        # Run magic to read in the individual GDS files and
+        # write out the consolidated GDS library
+
+        print('Running magic to create GDS library.')
+        sys.stdout.flush()
+
+        mproc = subprocess.run(['magic', '-dnull', '-noconsole',
+			destlibdir + '/generate_magic.tcl'],
+			stdin = subprocess.DEVNULL,
+			stdout = subprocess.PIPE,
+			stderr = subprocess.PIPE, cwd = destlibdir,
+			universal_newlines = True)
+
+        if mproc.stdout:
+            for line in mproc.stdout.splitlines():
+                print(line)
+        if mproc.stderr:
+            print('Error message output from magic:')
+            for line in mproc.stderr.splitlines():
+                print(line)
+        if mproc.returncode != 0:
+            print('ERROR:  Magic exited with status ' + str(mproc.returncode))
+        if do_compile_only == True:
+            print('Compile-only:  Removing individual GDS files')
+            for gfile in glist:
+                if os.path.isfile(gfile):
+                    os.remove(gfile)
+            if newname:
+                if os.path.isfile(newname):
+                    os.remove(newname)
+        if not keep:
+            os.remove(destlibdir + '/generate_magic.tcl')
+    else:
+        print('Only one file (' + str(glist) + ');  ignoring "compile" option.')
+
+#----------------------------------------------------------------------------
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    argumentlist = []
+
+    # Defaults
+    do_compile_only = False
+    keep = False
+    excludelist = []
+
+    # Break arguments into groups where the first word begins with "-".
+    # All following words not beginning with "-" are appended to the
+    # same list (optionlist).  Then each optionlist is processed.
+    # Note that the first entry in optionlist has the '-' removed.
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            keyval = option[1:].split('=')
+            if keyval[0] == 'compile-only':
+                if len(keyval) > 0:
+                    if keyval[1].tolower() == 'true' or keyval[1] == 'yes' or keyval[1] == '1':
+                        do_compile_only = True
+                else:
+                    do_compile_only = True
+            elif keyval[1] == 'exclude' or key == 'excludelist':
+                if len(keyval) > 0:
+                    excludelist = keyval[1].trim('"').split(',')
+                else:
+                    print("No items in exclude list (ignoring).")
+            elif keyval[1] == 'keep':
+                keep = True
+            else:
+                print("Unknown option '" + keyval[0] + "' (ignoring).")
+        else:
+            argumentlist.append(option)
+
+    if len(argumentlist) < 3: 
+        print("Not enough arguments given to create_gds_library.py.")
+        usage()
+        sys.exit(1)
+
+    destlibdir = argumentlist[0]
+    destlib = argumentlist[1]
+    startup_script = argumentlist[2]
+
+    print('')
+    print('Create GDS library from files:')
+    print('')
+    print('Path to files: ' + destlibdir)
+    print('Name of compiled library: ' + destlib + '.gds')
+    print('Path to magic startup script: ' + startup_script)
+    print('Remove individual files: ' + 'Yes' if do_compile_only else 'No')
+    if len(excludelist) > 0:
+        print('List of files to exclude: ')
+        for file in excludelist:
+            print(file)
+    print('Keep generating script: ' + 'Yes' if keep else 'No')
+    print('')
+
+    create_gds_library(destlibdir, destlib, startup_script, do_compile_only, excludelist, keep)
+    print('Done.')
+    sys.exit(0)
+
+#----------------------------------------------------------------------------
diff --git a/common/create_lef_library.py b/common/create_lef_library.py
new file mode 100755
index 0000000..2b76f9a
--- /dev/null
+++ b/common/create_lef_library.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+#
+# create_lef_library.py
+#
+#----------------------------------------------------------------------------
+# Given a destination directory holding individual LEF files of a number
+# of cells, create a single LEF library file named <alllibname> and place
+# it in the same directory.  This is done for the option "compile" if specified
+# for the "-lef" install.
+#----------------------------------------------------------------------------
+
+import sys
+import os
+import glob
+import fnmatch
+
+def usage():
+    print('')
+    print('Usage:')
+    print('    create_lef_library <destlibdir> <destlib> [-compile-only]')
+    print('            [-excludelist="file1,file2,..."]')
+    print('')
+    print('Create a single LEF library from a set of individual LEF files.')
+    print('')
+    print('where:')
+    print('    <destlibdir>      is the directory containing the individual LEF files')
+    print('    <destlib>         is the root name of the library file')
+    print('    -compile-only     remove the indidual files if specified')
+    print('    -excludelist=     is a comma-separated list of files to ignore')
+    print('')
+
+def create_lef_library(destlibdir, destlib, do_compile_only, excludelist):
+
+    alllibname = destlibdir + '/' + destlib + '.lef'
+    if os.path.isfile(alllibname):
+        os.remove(alllibname)
+
+    print('Diagnostic:  Creating consolidated LEF library ' + destlib + '.lef')
+    llist = glob.glob(destlibdir + '/*.lef')
+    if alllibname in llist:
+        llist.remove(alllibname)
+
+    # Create exclude list with glob-style matching using fnmatch
+    if len(llist) > 0:
+        llistnames = list(os.path.split(item)[1] for item in llist)
+        notllist = []
+        for exclude in excludelist:
+            notllist.extend(fnmatch.filter(llistnames, exclude))
+
+        # Apply exclude list
+        if len(notllist) > 0:
+            for file in llist[:]:
+                if os.path.split(file)[1] in notllist:
+                    llist.remove(file)
+
+    if len(llist) > 1:
+        print('New file is:  ' + alllibname)
+        with open(alllibname, 'w') as ofile:
+            headerdone = False
+            for lfile in llist:
+                with open(lfile, 'r') as ifile:
+                    # print('Adding ' + lfile + ' to library.')
+                    ltext = ifile.read()
+                    llines = ltext.splitlines()
+                    headerseen = False
+                    for lline in llines:
+                        if headerdone:
+                            if not headerseen:
+                                if not lline.startswith('MACRO'):
+                                    continue
+                                else:
+                                    headerseen = True
+                        ltok = lline.split()
+                        if ltok[0] == 'END' and ltok[1] == 'LIBRARY':
+                            # Remove "END LIBRARY" line from individual files
+                            pass
+                        else:
+                            print(lline, file=ofile)
+                    headerdone = True
+                print('#--------EOF---------\n', file=ofile)
+
+        if do_compile_only == True:
+            print('Compile-only:  Removing individual LEF files')
+            for lfile in llist:
+                if os.path.isfile(lfile):
+                    os.remove(lfile)
+            if newname:
+                if os.path.isfile(newname):
+                    os.remove(newname)
+    else:
+        print('Only one file (' + str(llist) + ');  ignoring "compile" option.')
+
+#----------------------------------------------------------------------------
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    argumentlist = []
+
+    # Defaults
+    do_compile_only = False
+    excludelist = []
+
+    # Break arguments into groups where the first word begins with "-".
+    # All following words not beginning with "-" are appended to the
+    # same list (optionlist).  Then each optionlist is processed.
+    # Note that the first entry in optionlist has the '-' removed.
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            keyval = option[1:].split('=')
+            if keyval[0] == 'compile-only':
+                if len(keyval) > 0:
+                    if keyval[1].tolower() == 'true' or keyval[1] == 'yes' or keyval[1] == '1':
+                        do_compile_only = True
+                else:
+                    do_compile_only = True
+            elif keyval[1] == 'exclude' or key == 'excludelist':
+                if len(keyval) > 0:
+                    excludelist = keyval[1].trim('"').split(',')
+                else:
+                    print("No items in exclude list (ignoring).")
+            else:
+                print("Unknown option '" + keyval[0] + "' (ignoring).")
+        else:
+            argumentlist.append(option)
+
+    if len(argumentlist) < 2: 
+        print("Not enough arguments given to create_lef_library.py.")
+        usage()
+        sys.exit(1)
+
+    destlibdir = argumentlist[0]
+    destlib = argumentlist[1]
+
+    print('')
+    print('Create LEF library from files:')
+    print('')
+    print('Path to files: ' + destlibdir)
+    print('Name of compiled library: ' + destlib + '.lef')
+    print('Remove individual files: ' + 'Yes' if do_compile_only else 'No')
+    if len(excludelist) > 0:
+        print('List of files to exclude: ')
+        for file in excludelist:
+            print(file)
+    print('')
+
+    create_lef_library(destlibdir, destlib, do_compile_only, excludelist)
+    print('Done.')
+    sys.exit(0)
+
+#----------------------------------------------------------------------------
diff --git a/common/create_lib_library.py b/common/create_lib_library.py
new file mode 100755
index 0000000..8f9a39f
--- /dev/null
+++ b/common/create_lib_library.py
@@ -0,0 +1,155 @@
+#!/usr/bin/env python3
+#
+# create_lib_library.py
+#
+#----------------------------------------------------------------------------
+# Given a destination directory holding individual liberty files of a number
+# of cells, create a single liberty library file named <alllibname> and place
+# it in the same directory.  This is done for the option "compile" if specified
+# for the "-lib" install.
+#----------------------------------------------------------------------------
+
+import sys
+import os
+import glob
+import fnmatch
+
+def usage():
+    print('')
+    print('Usage:')
+    print('    create_lib_library <destlibdir> <destlib> [-compile-only] ')
+    print('             [-excludelist="file1,file2,..."]')
+    print('')
+    print('Create a single liberty library from a set of individual liberty files.')
+    print('')
+    print('where:')
+    print('    <destlibdir>      is the directory containing the individual liberty files')
+    print('    <destlib>         is the root name of the library file')
+    print('    -compile-only     remove the indidual files if specified')
+    print('    -excludelist=     is a comma-separated list of files to ignore')
+    print('')
+
+# Warning:  This script is unfinished.  Needs to parse the library header
+# in each cell and generate a new library header combining the contents of
+# all cell headers.  Also:  The library name in the header needs to be
+# changed to the full library name.  Also:  There is no mechanism for
+# collecting all files belonging to a single process corner/temperature/
+# voltage.
+
+def create_lib_library(destlibdir, destlib, do_compile_only, excludelist):
+
+    alllibname = destlibdir + '/' + destlib + '.lib'
+    if os.path.isfile(alllibname):
+        os.remove(alllibname)
+
+    print('Diagnostic:  Creating consolidated liberty library ' + destlib + '.lib')
+
+    # Create exclude list with glob-style matching using fnmatch
+    if len(llist) > 0:
+        llistnames = list(os.path.split(item)[1] for item in llist)
+        notllist = []
+        for exclude in excludelist:
+            notllist.extend(fnmatch.filter(llistnames, exclude))
+
+        # Apply exclude list
+        if len(notllist) > 0:
+            for file in llist[:]:
+                if os.path.split(file)[1] in notllist:
+                    llist.remove(file)
+
+    if len(llist) > 1:
+        print('New file is:  ' + alllibname)
+        with open(alllibname, 'w') as ofile:
+            headerdone = False
+            for lfile in llist:
+                with open(lfile, 'r') as ifile:
+                    # print('Adding ' + lfile + ' to library.')
+                    ltext = ifile.read()
+                    llines = ltext.splitlines()
+                    headerseen = False
+                    for lline in llines:
+                        if headerdone:
+                            if not headerseen:
+                                if not lline.split()[0] == 'cell':
+                                    continue
+                                else:
+                                    headerseen = True
+                        print(lline, file=ofile)
+                    headerdone = True
+                print('/*--------EOF---------*/\n', file=ofile)
+
+        if do_compile_only == True:
+            print('Compile-only:  Removing individual LEF files')
+            for lfile in llist:
+                if os.path.isfile(lfile):
+                    os.remove(lfile)
+            if newname:
+                if os.path.isfile(newname):
+                    os.remove(newname)
+    else:
+        print('Only one file (' + str(llist) + ');  ignoring "compile" option.')
+
+#----------------------------------------------------------------------------
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    argumentlist = []
+
+    # Defaults
+    do_compile_only = False
+    excludelist = []
+
+    # Break arguments into groups where the first word begins with "-".
+    # All following words not beginning with "-" are appended to the
+    # same list (optionlist).  Then each optionlist is processed.
+    # Note that the first entry in optionlist has the '-' removed.
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            keyval = option[1:].split('=')
+            if keyval[0] == 'compile-only':
+                if len(keyval) > 0:
+                    if keyval[1].tolower() == 'true' or keyval[1] == 'yes' or keyval[1] == '1':
+                        do_compile_only = True
+                else:
+                    do_compile_only = True
+            elif keyval[1] == 'exclude' or key == 'excludelist':
+                if len(keyval) > 0:
+                    excludelist = keyval[1].trim('"').split(',')
+                else:
+                    print("No items in exclude list (ignoring).")
+            else:
+                print("Unknown option '" + keyval[0] + "' (ignoring).")
+        else:
+            argumentlist.append(option)
+
+    if len(argumentlist) < 3: 
+        print("Not enough arguments given to create_lib_library.py.")
+        usage()
+        sys.exit(1)
+
+    destlibdir = argumentlist[0]
+    destlib = argumentlist[1]
+    startup_script = argumentlist[2]
+
+    print('')
+    print('Create liberty library from files:')
+    print('')
+    print('Path to files: ' + destlibdir)
+    print('Name of compiled library: ' + destlib + '.lib')
+    print('Remove individual files: ' + 'Yes' if do_compile_only else 'No')
+    if len(excludelist) > 0:
+        print('List of files to exclude: ')
+        for file in excludelist:
+            print(file)
+    print('')
+
+    create_lib_library(destlibdir, destlib, do_compile_only, excludelist)
+    print('Done.')
+    sys.exit(0)
+
+#----------------------------------------------------------------------------
diff --git a/common/create_spice_library.py b/common/create_spice_library.py
new file mode 100755
index 0000000..6b8aa83
--- /dev/null
+++ b/common/create_spice_library.py
@@ -0,0 +1,213 @@
+#!/usr/bin/env python3
+#
+# create_spice_library.py
+#
+#----------------------------------------------------------------------------
+# Given a destination directory holding individual SPICE netlists of a number
+# of cells, create a single SPICE library file named <alllibname> and place
+# it in the same directory.  This is done for the option "compile" if specified
+# for the "-spice" install.
+#----------------------------------------------------------------------------
+
+import sys
+import os
+import re
+import glob
+import fnmatch
+
+#----------------------------------------------------------------------------
+
+def usage():
+    print('')
+    print('Usage:')
+    print('    create_spice_library <destlibdir> <destlib> <spiext>')
+    print('            [-compile-only] [-stub] [-excludelist="file1,file2,..."]')
+    print('')
+    print('Create a single SPICE or CDL library from a set of individual files.')
+    print('')
+    print('where:')
+    print('    <destlibdir>      is the directory containing the individual files')
+    print('    <destlib>         is the root name of the library file')
+    print('    <spiext>          is the extension used (with ".") by the SPICE or CDL files')
+    print('    -compile-only     remove the indidual files if specified')
+    print('    -stub             generate only .subckt ... .ends for each cell')
+    print('    -excludelist=     is a comma-separated list of files to ignore')
+    print('')
+
+#----------------------------------------------------------------------------
+
+def create_spice_library(destlibdir, destlib, spiext, do_compile_only, do_stub, excludelist):
+
+    fformat = 'CDL' if spiext == '.cdl' else 'SPICE'
+
+    allstubname = destlibdir + '/stub' + spiext
+    alllibname = destlibdir + '/' + destlib + spiext
+    if do_stub:
+        outputname = allstubname
+    else:
+        outputname = alllibname
+
+    print('Diagnostic:  Creating consolidated ' + fformat + ' library ' + outputname)
+
+    if os.path.isfile(outputname):
+        os.remove(outputname)
+
+    if fformat == 'CDL':
+        slist = glob.glob(destlibdir + '/*.cdl')
+    else:
+        # Sadly, there is no consensus on what a SPICE file extension should be.
+        slist = glob.glob(destlibdir + '/*.spc')
+        slist.extend(glob.glob(destlibdir + '/*.spice'))
+        slist.extend(glob.glob(destlibdir + '/*.spi'))
+        slist.extend(glob.glob(destlibdir + '/*.ckt'))
+        slist.extend(glob.glob(destlibdir + '/*.cir'))
+        slist.extend(glob.glob(destlibdir + '/*' + spiext))
+
+    if alllibname in slist:
+        slist.remove(alllibname)
+
+    if allstubname in slist:
+        slist.remove(allstubname)
+
+    # Create exclude list with glob-style matching using fnmatch
+    if len(slist) > 0:
+        slistnames = list(os.path.split(item)[1] for item in slist)
+        notslist = []
+        for exclude in excludelist:
+            notslist.extend(fnmatch.filter(slistnames, exclude))
+
+        # Apply exclude list
+        if len(notslist) > 0:
+            for file in slist[:]:
+                if os.path.split(file)[1] in notslist:
+                    slist.remove(file)
+
+    if len(slist) > 1:
+        with open(outputname, 'w') as ofile:
+            allsubckts = []
+            for sfile in slist:
+                with open(sfile, 'r') as ifile:
+                    # print('Adding ' + sfile + ' to library.')
+                    stext = ifile.read()
+                    subckts = re.findall(r'\.subckt[ \t]+([^ \t\n]+)', stext, flags=re.IGNORECASE)
+                    sseen = list(item for item in subckts if item in allsubckts)
+                    allsubckts.extend(list(item for item in subckts if item not in allsubckts))
+                    sfilter = remove_redundant_subckts(stext, allsubckts, sseen)
+                    print(sfilter, file=ofile)
+                print('\n******* EOF\n', file=ofile)
+
+        if do_compile_only == True:
+            print('Compile-only:  Removing individual SPICE files')
+            for sfile in slist:
+                if os.path.isfile(sfile):
+                    os.remove(sfile)
+                elif os.path.islink(sfile):
+                    os.unlink(sfile)
+    else:
+        print('Only one file (' + str(slist) + ');  ignoring "compile" option.')
+
+#----------------------------------------------------------------------------
+# Remove redundant subcircuit entries from a SPICE or CDL netlist file.  "sseen"
+# is a list of subcircuit names gleaned from all previously read files using
+# re.findall(). "slist" is a list of subcircuits including those in "ntext".
+# If a subcircuit is defined outside of "ntext", then remove all occurrences in
+# "ntext".  Otherwise, if a subcircuit is defined more than once in "ntext",
+# remove all but one copy.  The reason for doing this is that some netlists will
+# include primitive device definitions used by all the standard cell subcircuits.
+#
+# It may be necessary to remove redundant .include statements and redundant .model
+# and/or .option statements as well.
+#----------------------------------------------------------------------------
+
+def remove_redundant_subckts(ntext, slist, sseen):
+    updated = ntext
+    for subckt in slist:
+        if subckt in sseen:
+            # Remove all occurrences of subckt
+            updated = re.sub(r'\n\.subckt[ \t]+' + subckt + '[ \t\n]+.*\n\.ends[ \t\n]+', '\n', updated, flags=re.IGNORECASE | re.DOTALL)
+
+        else:
+            # Determine the number of times the subcircuit appears in the text
+            n = len(re.findall(r'\n\.subckt[ \t]+' + subckt + '[ \t\n]+.*\n\.ends[ \t\n]+', updated, flags=re.IGNORECASE | re.DOTALL))
+            # Optimization:  Just keep original text if n < 2
+            if n < 2:
+                continue
+
+            # Remove all but one
+            updated = re.sub(r'\n\.subckt[ \t]+' + subckt + '[ \t\n]+.*\n\.ends[ \t\n]+', '\n', n - 1, updated, flags=re.IGNORECASE | re.DOTALL)
+    return updated
+
+#----------------------------------------------------------------------------
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    argumentlist = []
+
+    # Defaults
+    do_compile_only = False
+    do_stub = False
+    excludelist = []
+
+    # Break arguments into groups where the first word begins with "-".
+    # All following words not beginning with "-" are appended to the
+    # same list (optionlist).  Then each optionlist is processed.
+    # Note that the first entry in optionlist has the '-' removed.
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            keyval = option[1:].split('=')
+            if keyval[0] == 'compile-only':
+                if len(keyval) > 0:
+                    if keyval[1].tolower() == 'true' or keyval[1].tolower() == 'yes' or keyval[1] == '1':
+                        do_compile_only = True
+                else:
+                    do_compile_only = True
+            elif keyval[1] == 'exclude' or key == 'excludelist':
+                if len(keyval) > 0:
+                    excludelist = keyval[1].trim('"').split(',')
+                else:
+                    print("No items in exclude list (ignoring).")
+            elif keyval[1] == 'stub':
+                if len(keyval) > 0:
+                    if keyval[1].tolower() == 'true' or keyval[1].tolower() == 'yes' or keyval[1] == '1':
+                        do_stub = True
+                else:
+                    do_stub = True
+            else:
+                print("Unknown option '" + keyval[0] + "' (ignoring).")
+        else:
+            argumentlist.append(option)
+
+    if len(argumentlist) < 3: 
+        print("Not enough arguments given to create_spice_library.py.")
+        usage()
+        sys.exit(1)
+
+    destlibdir = argumentlist[0]
+    destlib = argumentlist[1]
+    startup_script = argumentlist[2]
+
+    print('')
+    if spiext == '.cdl':
+        print('Create CDL library from files:')
+    else:
+        print('Create SPICE library from files:')
+    print('')
+    print('Path to files: ' + destlibdir)
+    print('Name of compiled library: ' + destlib + spiext)
+    print('Remove individual files: ' + 'Yes' if do_compile_only else 'No')
+    if len(excludelist) > 0:
+        print('List of files to exclude: ')
+        for file in excludelist:
+            print(file)
+    print('')
+
+    create_spice_library(destlibdir, destlib, spiext, do_compile_only, do_stub, excludelist)
+    print('Done.')
+    sys.exit(0)
+
+#----------------------------------------------------------------------------
diff --git a/common/create_verilog_library.py b/common/create_verilog_library.py
new file mode 100755
index 0000000..d8565f4
--- /dev/null
+++ b/common/create_verilog_library.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python3
+#
+# create_verilog_library.py
+#
+#----------------------------------------------------------------------------
+# Given a destination directory holding individual verilog files of a number
+# of modules, create a single verilog library file named <alllibname> and place
+# it in the same directory.  This is done for the option "compile" if specified
+# for the "-verilog" install.
+#----------------------------------------------------------------------------
+
+import sys
+import os
+import re
+import glob
+import fnmatch
+
+#----------------------------------------------------------------------------
+
+def usage():
+    print('')
+    print('Usage:')
+    print('    create_verilog_library <destlibdir> <destlib> [-compile-only]')
+    print('            [-stub] [-excludelist="file1,file2,..."]')
+    print('')
+    print('Create a single verilog library from a set of individual verilog files.')
+    print('')
+    print('where:')
+    print('    <destlibdir>      is the directory containing the individual files')
+    print('    <destlib>         is the root name of the library file')
+    print('    -compile-only     remove the indidual files if specified')
+    print('    -stub             generate only the module headers for each cell')
+    print('    -excludelist=     is a comma-separated list of files to ignore')
+    print('')
+
+#----------------------------------------------------------------------------
+
+def create_verilog_library(destlibdir, destlib, do_compile_only, do_stub, excludelist):
+
+    alllibname = destlibdir + '/' + destlib + '.v'
+    if os.path.isfile(alllibname):
+        os.remove(alllibname)
+
+    print('Diagnostic:  Creating consolidated verilog library ' + destlib + '.v')
+    vlist = glob.glob(destlibdir + '/*.v')
+    if alllibname in vlist:
+        vlist.remove(alllibname)
+
+    # Create exclude list with glob-style matching using fnmatch
+    if len(vlist) > 0:
+        vlistnames = list(os.path.split(item)[1] for item in vlist)
+        notvlist = []
+        for exclude in excludelist:
+            notvlist.extend(fnmatch.filter(vlistnames, exclude))
+
+        # Apply exclude list
+        if len(notvlist) > 0:
+            for file in vlist[:]:
+                if os.path.split(file)[1] in notvlist:
+                    vlist.remove(file)
+
+    if len(vlist) > 1:
+        print('New file is:  ' + alllibname)
+        with open(alllibname, 'w') as ofile:
+            allmodules = []
+            for vfile in vlist:
+                with open(vfile, 'r') as ifile:
+                    # print('Adding ' + vfile + ' to library.')
+                    vtext = ifile.read()
+                    modules = re.findall(r'[ \t\n]module[ \t]+([^ \t\n\(]+)', vtext)
+                    mseen = list(item for item in modules if item in allmodules)
+                    allmodules.extend(list(item for item in modules if item not in allmodules))
+                    vfilter = remove_redundant_modules(vtext, allmodules, mseen)
+                    # NOTE:  The following workaround resolves an issue with iverilog,
+                    # which does not properly parse specify timing paths that are not in
+                    # parentheses.  Easy to work around
+                    vlines = re.sub(r'\)[ \t]*=[ \t]*([01]:[01]:[01])[ \t]*;', r') = ( \1 ) ;', vfilter)
+                    print(vlines, file=ofile)
+                print('\n//--------EOF---------\n', file=ofile)
+
+        if do_compile_only == True:
+            print('Compile-only:  Removing individual verilog files')
+            for vfile in vlist:
+                if os.path.isfile(vfile):
+                    os.remove(vfile)
+                elif os.path.islink(vfile):
+                    os.unlink(vfile)
+    else:
+        print('Only one file (' + str(vlist) + ');  ignoring "compile" option.')
+
+#----------------------------------------------------------------------------
+# Remove redundant module entries from a verilog file.  "m2list" is a list of
+# module names gleaned from all previously read files using re.findall().
+# "mlist" is a list of all module names including those in "ntext".
+# The reason for doing this is that some verilog files may includes modules used
+# by all the files, and if included more than once, then iverilog complains.
+#----------------------------------------------------------------------------
+
+def remove_redundant_modules(ntext, mlist, m2list):
+    updated = ntext
+    for module in mlist:
+        # Determine the number of times the module appears in the text
+        if module in m2list:
+            # This module seen before outside of ntext, so remove all occurrances in ntext
+            new = re.sub(r'[ \t\n]+module[ \t]+' + module + '[ \t\n\(]+.*[ \t\n]endmodule', '\n', updated, flags=re.DOTALL)
+            updated = new
+
+        else:
+            n = len(re.findall(r'[ \t\n]module[ \t]+' + module + '[ \t\n\(]+.*[ \t\n]endmodule', updated, flags=re.DOTALL))
+            # This module defined more than once inside ntext, so remove all but one
+            # Optimization:  Just keep original text if n < 2
+            if n < 2:
+                continue
+
+            # Remove all but one
+            updated = re.sub(r'[ \t\n]+module[ \t]+' + module + '[ \t\n]+.*[ \t\n]endmodule', '\n', n - 1, updated, flags=re.IGNORECASE | re.DOTALL)
+    return updated
+
+#----------------------------------------------------------------------------
+
+if __name__ == '__main__':
+
+    if len(sys.argv) == 1:
+        usage()
+        sys.exit(0)
+
+    argumentlist = []
+
+    # Defaults
+    do_compile_only = False
+    do_stub = False
+    excludelist = []
+
+    # Break arguments into groups where the first word begins with "-".
+    # All following words not beginning with "-" are appended to the
+    # same list (optionlist).  Then each optionlist is processed.
+    # Note that the first entry in optionlist has the '-' removed.
+
+    for option in sys.argv[1:]:
+        if option.find('-', 0) == 0:
+            keyval = option[1:].split('=')
+            if keyval[0] == 'compile-only':
+                if len(keyval) > 0:
+                    if keyval[1].tolower() == 'true' or keyval[1].tolower() == 'yes' or keyval[1] == '1':
+                        do_compile_only = True
+                else:
+                    do_compile_only = True
+            elif keyval[1] == 'exclude' or key == 'excludelist':
+                if len(keyval) > 0:
+                    excludelist = keyval[1].trim('"').split(',')
+                else:
+                    print("No items in exclude list (ignoring).")
+            elif keyval[0] == 'stub':
+                if len(keyval) > 0:
+                    if keyval[1].tolower() == 'true' or keyval[1].tolower() == 'yes' or keyval[1] == '1':
+                        do_stub = True
+                else:
+                    do_stub = True
+            else:
+                print("Unknown option '" + keyval[0] + "' (ignoring).")
+        else:
+            argumentlist.append(option)
+
+    if len(argumentlist) < 3: 
+        print("Not enough arguments given to create_verilog_library.py.")
+        usage()
+        sys.exit(1)
+
+    destlibdir = argumentlist[0]
+    destlib = argumentlist[1]
+    startup_script = argumentlist[2]
+
+    print('')
+    print('Create verilog library from files:')
+    print('')
+    print('Path to files: ' + destlibdir)
+    print('Name of compiled library: ' + destlib + '.v')
+    print('Path to magic startup script: ' + startup_script)
+    print('Remove individual files: ' + 'Yes' if do_compile_only else 'No')
+    if len(excludelist) > 0:
+        print('List of files to exclude: ')
+        for file in excludelist:
+            print(file)
+    print('')
+
+    create_verilog_library(destlibdir, destlib, startup_script, do_compile_only, do_stub, excludelist)
+    print('Done.')
+    sys.exit(0)
+
+#----------------------------------------------------------------------------
diff --git a/common/foundry_install.py b/common/foundry_install.py
index 149c21f..267342b 100755
--- a/common/foundry_install.py
+++ b/common/foundry_install.py
@@ -116,6 +116,13 @@
 import fnmatch
 import subprocess
 
+# Import local routines
+from create_gds_library import create_gds_library
+from create_spice_library import create_spice_library
+from create_lef_library import create_lef_library
+from create_lib_library import create_lib_library
+from create_verilog_library import create_verilog_library
+
 def usage():
     print("foundry_install.py [options...]")
     print("   -copy             Copy files from source to target (default)")
@@ -327,438 +334,6 @@
                         print(line)
 
 #----------------------------------------------------------------------------
-# Given a destination directory holding individual verilog files of a number
-# of modules, create a single verilog library file named <alllibname> and place
-# it in the same directory.  This is done for the option "compile" if specified
-# for the "-verilog" install.
-#----------------------------------------------------------------------------
-
-def create_verilog_library(destlibdir, destlib, do_compile_only, do_stub, excludelist):
-
-    alllibname = destlibdir + '/' + destlib + '.v'
-    if os.path.isfile(alllibname):
-        os.remove(alllibname)
-
-    print('Diagnostic:  Creating consolidated verilog library ' + destlib + '.v')
-    vlist = glob.glob(destlibdir + '/*.v')
-    if alllibname in vlist:
-        vlist.remove(alllibname)
-
-    # Create exclude list with glob-style matching using fnmatch
-    if len(vlist) > 0:
-        vlistnames = list(os.path.split(item)[1] for item in vlist)
-        notvlist = []
-        for exclude in excludelist:
-            notvlist.extend(fnmatch.filter(vlistnames, exclude))
-
-        # Apply exclude list
-        if len(notvlist) > 0:
-            for file in vlist[:]:
-                if os.path.split(file)[1] in notvlist:
-                    vlist.remove(file)
-
-    if len(vlist) > 1:
-        print('New file is:  ' + alllibname)
-        with open(alllibname, 'w') as ofile:
-            allmodules = []
-            for vfile in vlist:
-                with open(vfile, 'r') as ifile:
-                    # print('Adding ' + vfile + ' to library.')
-                    vtext = ifile.read()
-                    modules = re.findall(r'[ \t\n]module[ \t]+([^ \t\n\(]+)', vtext)
-                    mseen = list(item for item in modules if item in allmodules)
-                    allmodules.extend(list(item for item in modules if item not in allmodules))
-                    vfilter = remove_redundant_modules(vtext, allmodules, mseen)
-                    # NOTE:  The following workaround resolves an issue with iverilog,
-                    # which does not properly parse specify timing paths that are not in
-                    # parentheses.  Easy to work around
-                    vlines = re.sub(r'\)[ \t]*=[ \t]*([01]:[01]:[01])[ \t]*;', r') = ( \1 ) ;', vfilter)
-                    print(vlines, file=ofile)
-                print('\n//--------EOF---------\n', file=ofile)
-
-        if do_compile_only == True:
-            print('Compile-only:  Removing individual verilog files')
-            for vfile in vlist:
-                if os.path.isfile(vfile):
-                    os.remove(vfile)
-                elif os.path.islink(vfile):
-                    os.unlink(vfile)
-    else:
-        print('Only one file (' + str(vlist) + ');  ignoring "compile" option.')
-
-#----------------------------------------------------------------------------
-# Remove redundant module entries from a verilog file.  "m2list" is a list of
-# module names gleaned from all previously read files using re.findall().
-# "mlist" is a list of all module names including those in "ntext".
-# The reason for doing this is that some verilog files may includes modules used
-# by all the files, and if included more than once, then iverilog complains.
-#----------------------------------------------------------------------------
-
-def remove_redundant_modules(ntext, mlist, m2list):
-    updated = ntext
-    for module in mlist:
-        # Determine the number of times the module appears in the text
-        if module in m2list:
-            # This module seen before outside of ntext, so remove all occurrances in ntext
-            new = re.sub(r'[ \t\n]+module[ \t]+' + module + '[ \t\n\(]+.*[ \t\n]endmodule', '\n', updated, flags=re.DOTALL)
-            updated = new
-
-        else:
-            n = len(re.findall(r'[ \t\n]module[ \t]+' + module + '[ \t\n\(]+.*[ \t\n]endmodule', updated, flags=re.DOTALL))
-            # This module defined more than once inside ntext, so remove all but one
-            # Optimization:  Just keep original text if n < 2
-            if n < 2:
-                continue
-
-            # Remove all but one
-            updated = re.sub(r'[ \t\n]+module[ \t]+' + module + '[ \t\n]+.*[ \t\n]endmodule', '\n', n - 1, updated, flags=re.IGNORECASE | re.DOTALL)
-    return updated
-
-#----------------------------------------------------------------------------
-# Given a destination directory holding individual LEF files of a number
-# of cells, create a single LEF library file named <alllibname> and place
-# it in the same directory.  This is done for the option "compile" if specified
-# for the "-lef" install.
-#----------------------------------------------------------------------------
-
-def create_lef_library(destlibdir, destlib, do_compile_only, excludelist):
-
-    alllibname = destlibdir + '/' + destlib + '.lef'
-    if os.path.isfile(alllibname):
-        os.remove(alllibname)
-
-    print('Diagnostic:  Creating consolidated LEF library ' + destlib + '.lef')
-    llist = glob.glob(destlibdir + '/*.lef')
-    if alllibname in llist:
-        llist.remove(alllibname)
-
-    # Create exclude list with glob-style matching using fnmatch
-    if len(llist) > 0:
-        llistnames = list(os.path.split(item)[1] for item in llist)
-        notllist = []
-        for exclude in excludelist:
-            notllist.extend(fnmatch.filter(llistnames, exclude))
-
-        # Apply exclude list
-        if len(notllist) > 0:
-            for file in llist[:]:
-                if os.path.split(file)[1] in notllist:
-                    llist.remove(file)
-
-    if len(llist) > 1:
-        print('New file is:  ' + alllibname)
-        with open(alllibname, 'w') as ofile:
-            headerdone = False
-            for lfile in llist:
-                with open(lfile, 'r') as ifile:
-                    # print('Adding ' + lfile + ' to library.')
-                    ltext = ifile.read()
-                    llines = ltext.splitlines()
-                    headerseen = False
-                    for lline in llines:
-                        if headerdone:
-                            if not headerseen:
-                                if not lline.startswith('MACRO'):
-                                    continue
-                                else:
-                                    headerseen = True
-                        print(lline, file=ofile)
-                    headerdone = True
-                print('#--------EOF---------\n', file=ofile)
-
-        if do_compile_only == True:
-            print('Compile-only:  Removing individual LEF files')
-            for lfile in llist:
-                if os.path.isfile(lfile):
-                    os.remove(lfile)
-            if newname:
-                if os.path.isfile(newname):
-                    os.remove(newname)
-    else:
-        print('Only one file (' + str(llist) + ');  ignoring "compile" option.')
-
-#----------------------------------------------------------------------------
-# Given a destination directory holding individual liberty files of a number
-# of cells, create a single liberty library file named <alllibname> and place
-# it in the same directory.  This is done for the option "compile" if specified
-# for the "-lib" install.
-#----------------------------------------------------------------------------
-
-# Warning:  This script is unfinished.  Needs to parse the library header
-# in each cell and generate a new library header combining the contents of
-# all cell headers.  Also:  The library name in the header needs to be
-# changed to the full library name.  Also:  There is no mechanism for
-# collecting all files belonging to a single process corner/temperature/
-# voltage.
-
-def create_lib_library(destlibdir, destlib, do_compile_only, excludelist):
-
-    alllibname = destlibdir + '/' + destlib + '.lib'
-    if os.path.isfile(alllibname):
-        os.remove(alllibname)
-
-    print('Diagnostic:  Creating consolidated liberty library ' + destlib + '.lib')
-
-    # Create exclude list with glob-style matching using fnmatch
-    if len(llist) > 0:
-        llistnames = list(os.path.split(item)[1] for item in llist)
-        notllist = []
-        for exclude in excludelist:
-            notllist.extend(fnmatch.filter(llistnames, exclude))
-
-        # Apply exclude list
-        if len(notllist) > 0:
-            for file in llist[:]:
-                if os.path.split(file)[1] in notllist:
-                    llist.remove(file)
-
-    if len(llist) > 1:
-        print('New file is:  ' + alllibname)
-        with open(alllibname, 'w') as ofile:
-            headerdone = False
-            for lfile in llist:
-                with open(lfile, 'r') as ifile:
-                    # print('Adding ' + lfile + ' to library.')
-                    ltext = ifile.read()
-                    llines = ltext.splitlines()
-                    headerseen = False
-                    for lline in llines:
-                        if headerdone:
-                            if not headerseen:
-                                if not lline.split()[0] == 'cell':
-                                    continue
-                                else:
-                                    headerseen = True
-                        print(lline, file=ofile)
-                    headerdone = True
-                print('/*--------EOF---------*/\n', file=ofile)
-
-        if do_compile_only == True:
-            print('Compile-only:  Removing individual LEF files')
-            for lfile in llist:
-                if os.path.isfile(lfile):
-                    os.remove(lfile)
-            if newname:
-                if os.path.isfile(newname):
-                    os.remove(newname)
-    else:
-        print('Only one file (' + str(llist) + ');  ignoring "compile" option.')
-
-#----------------------------------------------------------------------------
-# Given a destination directory holding individual GDS files of a number
-# of cells, create a single GDL library file named <alllibname> and place
-# it in the same directory.  This is done for the option "compile" if specified
-# for the "-gds" install.
-#----------------------------------------------------------------------------
-
-def create_gds_library(destlibdir, destlib, startup_script, do_compile_only, excludelist):
-
-    alllibname = destlibdir + '/' + destlib + '.gds'
-    if os.path.isfile(alllibname):
-        os.remove(alllibname)
-
-    print('Diagnostic:  Creating consolidated GDS library ' + destlib + '.gds')
-    glist = glob.glob(destlibdir + '/*.gds')
-    glist.extend(glob.glob(destlibdir + '/*.gdsii'))
-    glist.extend(glob.glob(destlibdir + '/*.gds2'))
-    if alllibname in glist:
-        glist.remove(alllibname)
-
-    # Create exclude list with glob-style matching using fnmatch
-    if len(glist) > 0:
-        glistnames = list(os.path.split(item)[1] for item in glist)
-        notglist = []
-        for exclude in excludelist:
-            notglist.extend(fnmatch.filter(glistnames, exclude))
-
-        # Apply exclude list
-        if len(notglist) > 0:
-            for file in glist[:]:
-                if os.path.split(file)[1] in notglist:
-                    glist.remove(file)
-
-    if len(glist) > 1:
-        print('New file is:  ' + alllibname)
-
-        if os.path.isfile(startup_script):
-            # If the symbolic link exists, remove it.
-            if os.path.isfile(destlibdir + '/.magicrc'):
-                os.remove(destlibdir + '/.magicrc')
-            os.symlink(startup_script, destlibdir + '/.magicrc')
-
-        # A GDS library is binary and requires handling in Magic
-        print('Creating magic generation script to generate GDS library.') 
-        with open(destlibdir + '/generate_magic.tcl', 'w') as ofile:
-            print('#!/usr/bin/env wish', file=ofile)
-            print('#--------------------------------------------', file=ofile)
-            print('# Script to generate .gds library from files   ', file=ofile)
-            print('#--------------------------------------------', file=ofile)
-            print('drc off', file=ofile)
-            print('gds readonly true', file=ofile)
-            print('gds flatten true', file=ofile)
-            print('gds rescale false', file=ofile)
-            print('tech unlock *', file=ofile)
-
-            for gdsfile in glist:
-                print('gds read ' + gdsfile, file=ofile)
-
-            print('puts stdout "Creating cell ' + destlib + '"', file=ofile)
-            print('load ' + destlib, file=ofile)
-            print('puts stdout "Adding cells to library"', file=ofile)
-            print('box values 0 0 0 0', file=ofile)
-            for gdsfile in glist:
-                gdsroot = os.path.split(gdsfile)[1]
-                gdsname = os.path.splitext(gdsroot)[0]
-                print('getcell ' + gdsname, file=ofile)
-                # Could properly make space for the cell here. . . 
-                print('box move e 200', file=ofile)
-                                
-            print('puts stdout "Writing GDS library ' + destlib + '"', file=ofile)
-            print('gds library', file=ofile)
-            print('gds write ' + destlib, file=ofile)
-            print('puts stdout "Done."', file=ofile)
-            print('quit -noprompt', file=ofile)
-
-        # Run magic to read in the individual GDS files and
-        # write out the consolidated GDS library
-
-        print('Running magic to create GDS library.')
-        sys.stdout.flush()
-
-        mproc = subprocess.run(['magic', '-dnull', '-noconsole',
-			destlibdir + '/generate_magic.tcl'],
-			stdin = subprocess.DEVNULL,
-			stdout = subprocess.PIPE,
-			stderr = subprocess.PIPE, cwd = destlibdir,
-			universal_newlines = True)
-
-        if mproc.stdout:
-            for line in mproc.stdout.splitlines():
-                print(line)
-        if mproc.stderr:
-            print('Error message output from magic:')
-            for line in mproc.stderr.splitlines():
-                print(line)
-        if mproc.returncode != 0:
-            print('ERROR:  Magic exited with status ' + str(mproc.returncode))
-        if do_compile_only == True:
-            print('Compile-only:  Removing individual GDS files')
-            for gfile in glist:
-                if os.path.isfile(gfile):
-                    os.remove(gfile)
-            if newname:
-                if os.path.isfile(newname):
-                    os.remove(newname)
-    else:
-        print('Only one file (' + str(glist) + ');  ignoring "compile" option.')
-
-#----------------------------------------------------------------------------
-# Given a destination directory holding individual SPICE netlists of a number
-# of cells, create a single SPICE library file named <alllibname> and place
-# it in the same directory.  This is done for the option "compile" if specified
-# for the "-spice" install.
-#----------------------------------------------------------------------------
-
-def create_spice_library(destlibdir, destlib, spiext, do_compile_only, do_stub, excludelist):
-
-    fformat = 'CDL' if spiext == '.cdl' else 'SPICE'
-
-    allstubname = destlibdir + '/stub' + spiext
-    alllibname = destlibdir + '/' + destlib + spiext
-    if do_stub:
-        outputname = allstubname
-    else:
-        outputname = alllibname
-
-    print('Diagnostic:  Creating consolidated ' + fformat + ' library ' + outputname)
-
-    if os.path.isfile(outputname):
-        os.remove(outputname)
-
-    if fformat == 'CDL':
-        slist = glob.glob(destlibdir + '/*.cdl')
-    else:
-        # Sadly, there is no consensus on what a SPICE file extension should be.
-        slist = glob.glob(destlibdir + '/*.spc')
-        slist.extend(glob.glob(destlibdir + '/*.spice'))
-        slist.extend(glob.glob(destlibdir + '/*.spi'))
-        slist.extend(glob.glob(destlibdir + '/*.ckt'))
-
-    if alllibname in slist:
-        slist.remove(alllibname)
-
-    if allstubname in slist:
-        slist.remove(allstubname)
-
-    # Create exclude list with glob-style matching using fnmatch
-    if len(slist) > 0:
-        slistnames = list(os.path.split(item)[1] for item in slist)
-        notslist = []
-        for exclude in excludelist:
-            notslist.extend(fnmatch.filter(slistnames, exclude))
-
-        # Apply exclude list
-        if len(notslist) > 0:
-            for file in slist[:]:
-                if os.path.split(file)[1] in notslist:
-                    slist.remove(file)
-
-    if len(slist) > 1:
-        with open(outputname, 'w') as ofile:
-            allsubckts = []
-            for sfile in slist:
-                with open(sfile, 'r') as ifile:
-                    # print('Adding ' + sfile + ' to library.')
-                    stext = ifile.read()
-                    subckts = re.findall(r'\.subckt[ \t]+([^ \t\n]+)', stext, flags=re.IGNORECASE)
-                    sseen = list(item for item in subckts if item in allsubckts)
-                    allsubckts.extend(list(item for item in subckts if item not in allsubckts))
-                    sfilter = remove_redundant_subckts(stext, allsubckts, sseen)
-                    print(sfilter, file=ofile)
-                print('\n******* EOF\n', file=ofile)
-
-        if do_compile_only == True:
-            print('Compile-only:  Removing individual SPICE files')
-            for sfile in slist:
-                if os.path.isfile(sfile):
-                    os.remove(sfile)
-                elif os.path.islink(sfile):
-                    os.unlink(sfile)
-    else:
-        print('Only one file (' + str(slist) + ');  ignoring "compile" option.')
-
-#----------------------------------------------------------------------------
-# Remove redundant subcircuit entries from a SPICE or CDL netlist file.  "sseen"
-# is a list of subcircuit names gleaned from all previously read files using
-# re.findall(). "slist" is a list of subcircuits including those in "ntext".
-# If a subcircuit is defined outside of "ntext", then remove all occurrences in
-# "ntext".  Otherwise, if a subcircuit is defined more than once in "ntext",
-# remove all but one copy.  The reason for doing this is that some netlists will
-# include primitive device definitions used by all the standard cell subcircuits.
-#
-# It may be necessary to remove redundant .include statements and redundant .model
-# and/or .option statements as well.
-#----------------------------------------------------------------------------
-
-def remove_redundant_subckts(ntext, slist, sseen):
-    updated = ntext
-    for subckt in slist:
-        if subckt in sseen:
-            # Remove all occurrences of subckt
-            updated = re.sub(r'\n\.subckt[ \t]+' + subckt + '[ \t\n]+.*\n\.ends[ \t\n]+', '\n', updated, flags=re.IGNORECASE | re.DOTALL)
-
-        else:
-            # Determine the number of times the subcircuit appears in the text
-            n = len(re.findall(r'\n\.subckt[ \t]+' + subckt + '[ \t\n]+.*\n\.ends[ \t\n]+', updated, flags=re.IGNORECASE | re.DOTALL))
-            # Optimization:  Just keep original text if n < 2
-            if n < 2:
-                continue
-
-            # Remove all but one
-            updated = re.sub(r'\n\.subckt[ \t]+' + subckt + '[ \t\n]+.*\n\.ends[ \t\n]+', '\n', n - 1, updated, flags=re.IGNORECASE | re.DOTALL)
-    return updated
-
-#----------------------------------------------------------------------------
 # This is the main entry point for the foundry install script.
 #----------------------------------------------------------------------------
 
diff --git a/sky130/magic/sky130.tech b/sky130/magic/sky130.tech
index 7f23296..d000ffd 100644
--- a/sky130/magic/sky130.tech
+++ b/sky130/magic/sky130.tech
@@ -10,7 +10,7 @@
 # Revisions:  See below
 #
 # This file is an Open Source foundry process describing
-# the SkyWater S8 hybrid 0.18um / 0.13um fabrication
+# the SkyWater sky130 hybrid 0.18um / 0.13um fabrication
 # process.  The file may be distributed under the terms
 # of the Apache 2.0 license agreement.
 #