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.
#