Added additional option "sort" to supply a sorting script to specify
the order of files when compiled into a library;  this allows the
Makefile to enforce natural sort order and/or put dependent entries
at the top.  Also added a custom script for sky130 to handle the
assortment of "include" statements in the standard cell verilog
before generating the library files.
diff --git a/README b/README
index 5d63be4..fce389d 100644
--- a/README
+++ b/README
@@ -382,7 +382,7 @@
 
 	 [option_arguments] may be one of the following:
 
-	       up  <number>
+	       up=<number>
 		    Any tool option can use this argument to indicate that
 		    the source hierarchy should be copied entirely, starting
 		    from <number> levels above the files indicated by <path>.
@@ -394,7 +394,7 @@
 		    would install all .lib files directly into
 		    libs.ref/<libname>/liberty/*.lib while
 	
-			-liberty x/y/z/PVT_*/*.lib up 1
+			-liberty x/y/z/PVT_*/*.lib up=1
 	
 		    would install all .lib files into
 		    libs.ref/liberty/<libname>/PVT_*/*.lib.
@@ -425,13 +425,13 @@
 		    them in a separate root directory libs.priv where they
 		    can be given additional read/write restrictions.
 
-	       rename <file_name>
+	       rename=<file_name>
 		    Rename the file being copied to the name of the argument.
 		    This can be used to copy one file into multiple destination
 		    libraries and give each copy a name related to the
 		    destination library.
 
-	       filter <script_file_path>
+	       filter=<script_file_path>
 		    Process all files through the script <script_file_path>,
 		    which is given as a relative path to the directory
 		    containing the Makefile.  The filter script traditionally
@@ -442,6 +442,13 @@
 		    in the common/ directory.  See common/fixspice.py for an
 		    example.
 
+	       sort=<script_file_path>
+		    Generate a list of all files to combine in a library,
+		    called "filelist.txt", then call the script.  The
+		    script should read the "filelist.txt" file and sort
+		    the files according to the order in which they should
+		    appear in the library.
+
 	       noclobber
 		    Mainly diagnostic.  When specified, any temporary files
 		    used during installation will be retained instead of
diff --git a/VERSION b/VERSION
index 7cb055c..4ad595c 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.41
+1.0.42
diff --git a/common/create_gds_library.py b/common/create_gds_library.py
index 34424fb..b02535f 100755
--- a/common/create_gds_library.py
+++ b/common/create_gds_library.py
@@ -45,9 +45,18 @@
     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 file "filelist.txt" exists in the directory, get the list of files from it
+    if os.path.exists(destlibdir + '/filelist.txt'):
+        with open(destlibdir + '/filelist.txt', 'r') as ifile:
+            rlist = ifile.read().splitlines()
+            glist = []
+            for rfile in rlist:
+                glist.append(destlibdir + '/' + rfile)
+    else:
+        glist = glob.glob(destlibdir + '/*.gds')
+        glist.extend(glob.glob(destlibdir + '/*.gdsii'))
+        glist.extend(glob.glob(destlibdir + '/*.gds2'))
+
     if alllibname in glist:
         glist.remove(alllibname)
 
diff --git a/common/create_lef_library.py b/common/create_lef_library.py
index 8a922c8..4a46e5f 100755
--- a/common/create_lef_library.py
+++ b/common/create_lef_library.py
@@ -43,7 +43,17 @@
         os.remove(alllibname)
 
     print('Diagnostic:  Creating consolidated LEF library ' + destlibroot + '.lef')
-    llist = glob.glob(destlibdir + '/*.lef')
+
+    # If file "filelist.txt" exists in the directory, get the list of files from it
+    if os.path.exists(destlibdir + '/filelist.txt'):
+        with open(destlibdir + '/filelist.txt', 'r') as ifile:
+            rlist = ifile.read().splitlines()
+            llist = []
+            for rfile in rlist:
+                llist.append(destlibdir + '/' + rfile)
+    else:
+        llist = glob.glob(destlibdir + '/*.lef')
+
     if alllibname in llist:
         llist.remove(alllibname)
 
diff --git a/common/create_lib_library.py b/common/create_lib_library.py
index bfa773d..1f058c7 100755
--- a/common/create_lib_library.py
+++ b/common/create_lib_library.py
@@ -51,6 +51,16 @@
 
     print('Diagnostic:  Creating consolidated liberty library ' + destlibroot + '.lib')
 
+    # If file "filelist.txt" exists in the directory, get the list of files from it
+    if os.path.exists(destlibdir + '/filelist.txt'):
+        with open(destlibdir + '/filelist.txt', 'r') as ifile:
+            rlist = ifile.read().splitlines()
+            llist = []
+            for rfile in rlist:
+                llist.append(destlibdir + '/' + rfile)
+    else:
+        llist = glob.glob(destlibdir + '/*.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)
diff --git a/common/create_spice_library.py b/common/create_spice_library.py
index ca95fa6..90d4e65 100755
--- a/common/create_spice_library.py
+++ b/common/create_spice_library.py
@@ -55,16 +55,24 @@
     if os.path.isfile(outputname):
         os.remove(outputname)
 
-    if fformat == 'CDL':
-        slist = glob.glob(destlibdir + '/*.cdl')
+    # If file "filelist.txt" exists in the directory, get the list of files from it
+    if os.path.exists(destlibdir + '/filelist.txt'):
+        with open(destlibdir + '/filelist.txt', 'r') as ifile:
+            rlist = ifile.read().splitlines()
+            slist = []
+            for rfile in rlist:
+                slist.append(destlibdir + '/' + rfile)
     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 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)
diff --git a/common/create_verilog_library.py b/common/create_verilog_library.py
index 32ce2c5..55e1c76 100755
--- a/common/create_verilog_library.py
+++ b/common/create_verilog_library.py
@@ -45,7 +45,18 @@
         os.remove(alllibname)
 
     print('Diagnostic:  Creating consolidated verilog library ' + destlibroot + '.v')
-    vlist = glob.glob(destlibdir + '/*.v')
+
+    # If file "filelist.txt" exists in the directory, get the list of files from it
+    if os.path.exists(destlibdir + '/filelist.txt'):
+        print('Diagnostic:  Reading sorted verilog file list.')
+        with open(destlibdir + '/filelist.txt', 'r') as ifile:
+            rlist = ifile.read().splitlines()
+            vlist = []
+            for rfile in rlist:
+                vlist.append(destlibdir + '/' + rfile)
+    else:
+        vlist = glob.glob(destlibdir + '/*.v')
+
     if alllibname in vlist:
         vlist.remove(alllibname)
 
diff --git a/common/foundry_install.py b/common/foundry_install.py
index 7028956..3fa7f1c 100755
--- a/common/foundry_install.py
+++ b/common/foundry_install.py
@@ -79,6 +79,10 @@
 #		    when a foundry library has inconveniently split
 #		    an IP library (LEF, CDL, verilog, etc.) into
 #		    individual files.
+#	compile-only:	Like "compile" except that the individual
+#		    files are removed after the library file has been
+#		    created.
+#
 #	stub :	   Remove contents of subcircuits from CDL or SPICE
 #		    netlist files.
 #
@@ -98,6 +102,20 @@
 #		    "compile" or "compile-only", this refers to the
 # 		    name of the target compiled file.
 #
+#	filter:	   Followed by "=" and the name of a script.
+#		    Each file is passed through the filter script
+#		    before writing into the staging area.
+#
+#	sort:	   Optionally followed by "=" and the name of a script.
+#		    The list of files to process (after applying items
+#		    from "exclude") will be written to a file
+#		    "filelist.txt", which will be used by the
+#		    library compile routines, if present.  If a script
+#		    name is specified, then the sort script will rewrite
+#		    the file with the order in which entries should
+#		    appear in the compiled library.  Only useful when
+#		    used with "compile" or "compile-only".
+#
 #	noconvert : Install only; do not attempt to convert to other
 #		    formats (applies only to GDS, CDL, and LEF).
 #
@@ -669,16 +687,11 @@
         # the source should be copied (or linked) from <number> levels up
         # in the hierarchy (see below).
 
-        if 'up' in option:
-            uparg = option.index('up') 
-            try:
-                hier_up = int(option[uparg + 1])
-            except:
-                print("Non-numeric option to 'up': " + option[uparg + 1])
-                print("Ignoring 'up' option.")
-                hier_up = 0
-        else:
-            hier_up = 0
+        hier_up = 0
+        for item in option:
+            if item.split('=')[0] == 'up':
+                hier_up = int(item.split('=')[1])
+                break
 
         filter_scripts = []
         for item in option:
@@ -713,6 +726,17 @@
         else:
             print('Renaming file to: ' + newname)
 
+        # Option 'sort' may have an argument. . .
+        try:
+            sortscript = list(item.split('=')[1] for item in option if item.startswith('sort'))[0]
+        except IndexError:
+            sortscript = None
+        else:
+            print('Sorting files with script ' + sortscript)
+        # . . . or not.
+        if 'sort' in option:
+            sortscript = True
+
         # 'anno' may be specified for LEF, in which case the LEF is used only
         # to annotate GDS and is not itself installed;  this allows LEF to
         # be generated from Magic and avoids quirky use of obstruction layers.
@@ -791,6 +815,7 @@
                     print('   ' + item)
                 print('(' + str(len(liblist)) + ' files total)')
 
+            destfilelist = []
             for libname in liblist:
                 # Note that there may be a hierarchy to the files in option[1],
                 # say for liberty timing files under different conditions, so
@@ -877,6 +902,19 @@
                     # Apply filter script to all files in the target directory
                     tfilter(targname, filter_script)
 
+                destfilelist.append(os.path.split(targname)[1])
+
+            if sortscript:
+                print('Diagnostic:  Sorting files to compile.')
+                with open(destlibdir + '/filelist.txt', 'w') as ofile:
+                    for destfile in destfilelist:
+                        print(destfile, file=ofile)
+                if os.path.isfile(sortscript):
+                    print('Diagnostic:  Sorting files with ' + sortscript)
+                    subprocess.run([sortscript, destlibdir],
+				stdout = subprocess.DEVNULL,
+				stderr = subprocess.DEVNULL)
+
             if do_compile == True or do_compile_only == True:
                 # NOTE:  The purpose of "rename" is to put a destlib-named
                 # library elsewhere so that it can be merged with another
@@ -946,6 +984,11 @@
                     targrename = destlibdir + destpath + '/' + newname
                     if os.path.isfile(origname):
                         os.rename(origname, targrename)
+      
+            # If "filelist.txt" was created, remove it
+            if sortscript:
+                if os.path.isfile(destlibdir + '/filelist.txt'):
+                    os.remove(destlibdir + '/filelist.txt')
 
         # Find any libraries/options marked as "privileged" (or "private") and
         # move the files from libs.tech or libs.ref to libs.priv, leaving a
diff --git a/sky130/Makefile.in b/sky130/Makefile.in
index 2cfa21e..88ad096 100644
--- a/sky130/Makefile.in
+++ b/sky130/Makefile.in
@@ -353,7 +353,8 @@
 vendor-a:
 	# Install device subcircuits from vendor files
 	${STAGE} -source ${SKYWATER_PATH} -target ${STAGING_PATH}/${SKY130A} \
-		-ngspice sky130_fd_pr/latest/models/* filter=custom/scripts/rename_models.py \
+		-ngspice sky130_fd_pr/latest/models/* \
+		filter=custom/scripts/rename_models.py \
 		|& tee -a ${SKY130A}_install.log
 	# Install base device library from vendor files
 	${STAGE} -source ${SKYWATER_PATH} -target ${STAGING_PATH}/${SKY130A} \
@@ -380,13 +381,22 @@
 	${STAGE} -source ${SKYWATER_PATH} -target ${STAGING_PATH}/${SKY130A} \
 		-techlef %l/latest/tech/*.tlef \
 		-spice %l/latest/cells/*/*.spice compile-only \
+			sort=custom/scripts/sort_pdkfiles.py \
 		-cdl %l/latest/cells/*/*.cdl ignore=topography compile-only \
+			sort=custom/scripts/sort_pdkfiles.py \
 		-lef %l/latest/cells/*/*.magic.lef compile-only \
+			sort=custom/scripts/sort_pdkfiles.py \
 		-doc %l/latest/cells/*/*.pdf \
 		-lib %l/latest/timing/*.lib \
 		-gds %l/latest/cells/*/*.gds compile-only \
-		-verilog %l/latest/models/*/*.v exclude *.*.v compile-only rename test \
-		-verilog %l/latest/cells/*/*.v exclude *.*.v,test,test.v compile-only \
+			sort=custom/scripts/sort_pdkfiles.py \
+		-verilog %l/latest/models/*/*.v exclude=*.*.v compile-only \
+			rename=primitives filter=custom/scripts/inc_verilog.py \
+			sort=custom/scripts/sort_pdkfiles.py \
+		-verilog %l/latest/cells/*/*.*.v \
+		-verilog %l/latest/cells/*/*.v exclude=*.*.v,primitives.v \
+			compile-only filter=custom/scripts/inc_verilog.py \
+			sort=custom/scripts/sort_pdkfiles.py \
 		-library digital sky130_fd_sc_hd \
 		-library digital sky130_fd_sc_hdll \
 		-library digital sky130_fd_sc_hvl \
@@ -394,6 +404,15 @@
 		-library digital sky130_fd_sc_ls \
 		-library digital sky130_fd_sc_ms \
 		-library digital sky130_fd_sc_lp |& tee -a ${SKY130A}_install.log
+	# Remove the base verilog files which have already been included into
+	# the libraries
+	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_hd/verilog/*.*.v
+	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_hdll/verilog/*.*.v
+	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_hvl/verilog/*.*.v
+	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_hs/verilog/*.*.v
+	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_ms/verilog/*.*.v
+	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_ls/verilog/*.*.v
+	${RM} ${STAGING_PATH}/${SKY130A}/libs.ref/sky130_fd_sc_lp/verilog/*.*.v
         # Install OSU digital standard cells.
 	# ${STAGE} -source ${OSU_PATH} -target ${STAGING_PATH}/${SKY130A} \
 	# 	-techlef char/techfiles/scs8.lef rename sky130_osu_sc.tlef \
diff --git a/sky130/custom/scripts/inc_verilog.py b/sky130/custom/scripts/inc_verilog.py
index d34129d..2bcd0a3 100755
--- a/sky130/custom/scripts/inc_verilog.py
+++ b/sky130/custom/scripts/inc_verilog.py
@@ -47,11 +47,23 @@
                 # NOTE:  These files are assumed not to need in-line
                 # includes, but includes of primitives need to be ignored.
 
+                # Quick hack:  Remove this when the filenames are corrected
+                if not os.path.exists(inpath + '/' + incfilename):
+                    print('Detected incorrect filename')
+                    print('   Old filename was: ' + incfilename)
+                    dlist = incfilename.split('.')
+                    ilist = dlist[0:-3]
+                    ilist.append(dlist[-2])
+                    ilist.append(dlist[-3])
+                    ilist.append(dlist[-1])
+                    print('   New filename is: ' + incfilename)
+                    incfilename = '.'.join(ilist)
+
                 with open(inpath + '/' + incfilename, 'r') as incfile:
                     v2text = incfile.read()
                     v2lines = v2text.splitlines()
                     for line2 in v2lines:
-                        i2match = imatch.match(line2)
+                        i2match = increx.match(line2)
                         if not i2match:
                             fixedlines.append(line2)
             else:
diff --git a/sky130/custom/scripts/sort_pdkfiles.py b/sky130/custom/scripts/sort_pdkfiles.py
new file mode 100755
index 0000000..ac0a107
--- /dev/null
+++ b/sky130/custom/scripts/sort_pdkfiles.py
@@ -0,0 +1,55 @@
+#!/usr/bin/env python3
+#
+# sort_pdkfiles.py
+#
+# Read "filelist.txt" which is a list of all files to be compiled.
+# Do a natural sort, which puts the "base" files (those without a
+# drive strength) in front of "top level" files (those with a drive
+# strength), and orders the drive strengths numerically.
+#
+# Note that foundry_install.py executes this script using 'subprocess'
+# in the directory where "filelist.txt" and the files are located.  No
+# path components are in the file list.
+
+import re
+import os
+import sys
+
+# Natural sort thanks to Mark Byers in StackOverflow
+def natural_sort(l):
+    convert = lambda text: int(text) if text.isdigit() else text.lower()
+    alphanum_key= lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
+    return sorted(l, key = alphanum_key)
+
+def pdk_sort(destdir):
+    if not os.path.isfile(destdir + '/filelist.txt'):
+        print('No file "filelist.txt" in ' + destdir + '. . .  Nothing to sort.')
+        sys.exit()
+
+    with open(destdir + '/filelist.txt', 'r') as ifile:
+        vlist = ifile.read().splitlines()
+
+    vlist = natural_sort(vlist)
+    
+    with open(destdir + '/filelist.txt', 'w') as ofile:
+        for vfile in vlist:
+            print(vfile, file=ofile)
+
+if __name__ == '__main__':
+
+    # This script expects to get one argument, which is a path name
+
+    options = []
+    arguments = []
+    for item in sys.argv[1:]:
+        if item.find('-', 0) == 0:
+            options.append(item[1:])
+        else:
+            arguments.append(item)
+
+    if len(arguments) > 0:
+        destdir = arguments[0]
+
+    pdk_sort(destdir)
+    sys.exit(0)
+