Removed all of the routines that generate compiled libraries from
individual files for various file formats (GDS, LEF, SPICE/CDL,
and verilog (liberty is unfinished and probably never will be), and
put the in individual files that can be either run separately from
the command line or included into the foundry_install.py script and
run internally.
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)
+
+#----------------------------------------------------------------------------