Additional work on the GF PDK.  This includes updating the OSU
standard cells for changes made to the repository.  Also:
SRAM now imported in such a way that the .mag view produced
can be extracted and passes LVS.  For the SRAM and the standard
cells, switching from layout-extracted SPICE to converted CDL
from GF.  Started a method for building open_pdks from commit
numbers pulled from the JSON file "reference" section;  this
work is unfinished.
diff --git a/Makefile.in b/Makefile.in
index e63efb8..348ddd9 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -38,7 +38,9 @@
 #
 #	annotate the technology JSON file with the current
 #	commit state of all repositories used by the PDK to
-#	create a reference set of PDKs.
+#	create a reference set of PDKs.  Can be used with
+#	the configure --with-reference option to compile
+#	to sources from a specific set of commits.
 #
 #---------------------------------------------------
 #
diff --git a/common/foundry_install.py b/common/foundry_install.py
index 969908f..bcb17e6 100755
--- a/common/foundry_install.py
+++ b/common/foundry_install.py
@@ -128,10 +128,13 @@
 #
 #	rename :   Followed by "=" and an alternative name.  For any
 #		    file that is a single entry, change the name of
-#		    the file in the target directory to this (To-do:
-#		    take regexps for multiple files).  When used with
-#		    "compile" or "compile-only", this refers to the
-# 		    name of the target compiled file.
+#		    the file in the target directory to this.  If the
+#		    alternative name is a file extension (optionally
+#		    preceded by '*', as in "rename=*.spice", then all
+#		    input files are renamed with the indicated file
+#		    extension (To-do: take regexps for multiple files).
+#		    When used with "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
@@ -1008,6 +1011,10 @@
 
                     if len(liblist) == 1:
                         destfile = newname
+                    elif newname.startswith('*.'):
+                        destfile = os.path.splitext(libfile)[0] + newname[1:]
+                    elif newname.startswith('.'):
+                        destfile = os.path.splitext(libfile)[0] + newname
                     else:
                         if not do_compile and not do_compile_only:
                             print('Error:  rename specified but more than one file found!')
diff --git a/gf180mcu/Makefile.in b/gf180mcu/Makefile.in
index 9741d6f..be9cf7b 100644
--- a/gf180mcu/Makefile.in
+++ b/gf180mcu/Makefile.in
@@ -157,6 +157,8 @@
 GF180MCU_SRAM_PATH = @GF180MCU_FD_IP_SRAM_PATH@
 GF180MCU_OSU_SC_PATH = @GF180MCU_OSU_SC_PATH@
 
+USE_REFERENCE = @USE_REFERENCE@
+
 # Path to GF180MCU library sources
 PDK_URL = https://github.com/google
 OSU_URL = https://github.com/stineje
@@ -428,6 +430,8 @@
         TOOLS += xcircuit
 endif
 
+all: $(foreach var, ${VARIANTS}, all-$(var))
+
 reference: ${TECH}.json
 	# Rewrite the ${TECH}.json file to change the commit values in
 	# "reference" to reflect the state of the system when  "make
@@ -436,8 +440,6 @@
 	# tools.
 	../common/save_commit_refs.py ${COMMIT_DEFS} ${TECH}.json
 
-all: $(foreach var, ${VARIANTS}, all-$(var))
-
 # Handle prerequisites
 prerequisites: pr-repo io-repo sc-7t-repo sc-9t-repo sram-repo osu-sc-repo
 
@@ -821,6 +823,8 @@
 			filter=custom/scripts/fix_related_bias_pins.py \
                         header=liberty/gf180mcu_fd_sc_mcu9t5v0__tt_025C_5v00.lib \
 			rename=gf180mcu_fd_sc_mcu9t5v0__tt_025C_5v00 \
+		-spice cells/*/*.cdl compile-only \
+			filter=custom/scripts/convert_sc_cdl.py \
 		-gds cells/*/*.gds compile-only \
 			options=custom/scripts/gds_import_sc.tcl \
 			filter=custom/scripts/fix_stdcell_gds.py \
@@ -834,6 +838,7 @@
 	# Create minimum/maximum technology LEF files
 	./custom/scripts/make_minmax_techlef.py ${EF_FORMAT} -variant=${GF180MCU$*} \
 		-library=9t5v0 2>&1 | tee -a ${GF180MCU$*}_make.log || true
+
 digital-7t5v0-%:
         # Install 5V 7-track digital standard cells from vendor files
 	${STAGE} -source ${GF180MCU_SC_7T5V0_PATH} \
@@ -902,6 +907,8 @@
 			filter=custom/scripts/fix_related_bias_pins.py \
 			header=liberty/gf180mcu_fd_sc_mcu7t5v0__tt_025C_5v00.lib \
 			rename=gf180mcu_fd_sc_mcu7t5v0__tt_025C_5v00 \
+		-spice cells/*/*.cdl compile-only \
+			filter=custom/scripts/convert_sc_cdl.py \
 		-gds cells/*/*.gds compile-only \
 			options=custom/scripts/gds_import_sc.tcl \
 			filter=custom/scripts/fix_stdcell_gds.py \
@@ -919,34 +926,32 @@
 digital-osu-%:
         # Install OSU 3.3V digital standard cells from vendor files
 	# NOTE: Work in progress (to be completed)
-	${STAGE} -source ${GF180MCU_OSU_SC_PATH} \
+	${STAGE} -source ${GF180MCU_OSU_SC_PATH}/gf180mcu_osu_sc_gp9t3v3 \
 		-target ${STAGING_PATH}/${GF180MCU$*} \
-		-techlef lib/9T/tlef/gf180mcu_*_tech.lef \
-			rename=gf180mcu_osu_sc_9T.tlef \
-		-liberty lib/9T/lib/gf180mcu_9T_TT_3P3_25C*.lib \
-			rename=gf180mcu_osu_sc_9T__tt_025C_3v30 \
-		-verilog lib/9T/verilog/*.v \
-			rename=gf180mcu_osu_sc_9T \
-		-lef lib/9T/lef/*.lef \
-		-gds lib/9T/*/*.gds compile-only \
-		-spice lib/9T/*/*.spice compile-only \
-		-xschem lib/9T/*/*.sch \
-		-library digital gf180mcu_osu_sc_9T 2>&1 | \
+		-techlef ../tlef/gf180mcu_5LM_1TM_9K_9t.tlef \
+			rename=gf180mcu_fd_sc_mcu7t5v0__nom.tlef \
+		-liberty lib/gf180mcu_osu_sc_gp9t3v3_TT_3P3_25C.ccs.lib \
+			rename=gf180mcu_osu_sc_gp9t3v3__tt_025C_3v30 \
+		-verilog cells/*/*.v compile-only \
+		-lef cells/*/*.lef compile-only \
+		-gds cells/*/*.gds compile-only \
+		-spice cells/*/*.spice compile-only \
+		-xschem cells/*/*.sch \
+		-library digital gf180mcu_osu_sc_gp9t3v3 2>&1 | \
 		tee -a ${GF180MCU$*}_make.log
 
-	${STAGE} -source ${GF180MCU_OSU_SC_PATH} \
+	${STAGE} -source ${GF180MCU_OSU_SC_PATH}/gf180mcu_osu_sc_gp12t3v3 \
 		-target ${STAGING_PATH}/${GF180MCU$*} \
-		-techlef lib/12T/tlef/gf180mcu_*_tech.lef \
-			rename=gf180mcu_osu_sc_12T.tlef \
-		-liberty lib/12T/lib/gf180mcu_12T_TT_3P3_25C*.lib \
-			rename=gf180mcu_osu_sc_12T__tt_025C_3v30 \
-		-verilog lib/12T/verilog/*.v \
-			rename=gf180mcu_osu_sc_12T \
-		-lef lib/12T/lef/*.lef \
-		-gds lib/12T/*/*.gds compile-only \
-		-spice lib/12T/*/*.spice compile-only \
-		-xschem lib/12T/*/*.sch \
-		-library digital gf180mcu_osu_sc_12T 2>&1 | \
+		-techlef ../tlef/gf180mcu_5LM_1TM_9K_12t.tlef \
+			rename=gf180mcu_fd_sc_mcu7t5v0__nom.tlef \
+		-liberty lib/gf180mcu_osu_sc_gp12t3v3_TT_25C.ccs.lib \
+			rename=gf180mcu_osu_sc_gp12t3v3__tt_025C_3v30 \
+		-verilog cells/*/*.v compile-only \
+		-lef cells/*/*.lef compile-only \
+		-gds cells/*/*.gds compile-only \
+		-spice cells/*/*.spice compile-only \
+		-xschem cells/*/*.sch \
+		-library digital gf180mcu_osu_sc_gp12t3v3 2>&1 | \
 		tee -a ${GF180MCU$*}_make.log
 
 io-%:
@@ -976,9 +981,9 @@
 		-liberty cells/*/*_ff_n40C_5v50.lib compile-only \
                         header=liberty/gf180mcu_fd_io__ff_n40C_5v50.lib \
 			rename=gf180mcu_fd_io__ff_n40C_5v50 \
-		-liberty cells/*/*_ss_125C_2v50.lib compile-only \
-                        header=liberty/gf180mcu_fd_io__ss_125C_2v50.lib \
-			rename=gf180mcu_fd_io__ss_125C_2v50 \
+		-liberty cells/*/*_ss_125C_2v25.lib compile-only \
+                        header=liberty/gf180mcu_fd_io__ss_125C_2v25.lib \
+			rename=gf180mcu_fd_io__ss_125C_2v25 \
 		-liberty cells/*/*_ss_125C_2v97.lib compile-only \
                         header=liberty/gf180mcu_fd_io__ss_125C_2v97.lib \
 			rename=gf180mcu_fd_io__ss_125C_2v97 \
@@ -1010,6 +1015,9 @@
 		-target ${STAGING_PATH}/${GF180MCU$*} \
 		-cdl cells/*/*.cdl noconvert \
 		-liberty cells/*/*.lib \
+		-spice cells/*/*.cdl \
+			filter=custom/scripts/convert_sram_cdl.py \
+			rename=*.spice \
 		-gds cells/*/*.gds \
 			options=custom/scripts/gds_import_sram.tcl \
 			filter=custom/scripts/fix_sram_gds.py \
diff --git a/gf180mcu/custom/scripts/convert_sc_cdl.py b/gf180mcu/custom/scripts/convert_sc_cdl.py
new file mode 100755
index 0000000..8a9fcbd
--- /dev/null
+++ b/gf180mcu/custom/scripts/convert_sc_cdl.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+#
+# convert_sc_cdl.py ---
+#
+# This script converts the GF CDL for the standard cells to turn them into
+# valid SPICE (ngspice) syntax, using regular expression parsing.
+
+# This script is a filter to be run by setting the name of this script as
+# the value to "filter=" for the model install in the sky130 Makefile.
+
+import re
+import os
+import sys
+
+def filter(inname, outname):
+
+    # Read input
+    try:
+        with open(inname, 'r') as inFile:
+            spitext = inFile.read()
+            # (Don't) unwrap continuation lines
+            # spilines = spitext.replace('\n+', ' ').splitlines()
+            spilines = spitext.splitlines()
+    except:
+        print('convert_sc_cdl.py: failed to open ' + inname + ' for reading.', file=sys.stderr)
+        return 1
+
+    fixedlines = []
+    modified = False
+
+    for line in spilines:
+        fixedline = line
+
+        # 1) Lines starting with M --> change to X
+        fixedline = re.sub('^M', 'X', fixedline, flags=re.IGNORECASE)
+        # 2) 5V transistor models --> change to 6V
+        fixedline = re.sub('_05v0', '_06v0', fixedline, flags=re.IGNORECASE)
+	# 3) Uppercase diode "d" for consistency
+        fixedline = re.sub('^d', 'D', fixedline)
+	# 4) Convert $m to M
+        fixedline = re.sub('\$m=', 'M=', fixedline, flags=re.IGNORECASE)
+	# 5) Fix incorrect endcap (endcap does not have VNW VPW)
+        fixedline = re.sub('endcap VDD VNW VPW', 'endcap VDD', fixedline, flags=re.IGNORECASE)
+
+        if line != fixedline:
+            modified = True
+        fixedlines.append(fixedline)
+
+    # Write output
+    if outname == None:
+        for i in fixedlines:
+            print(i)
+    else:
+        # If the output is a symbolic link but no modifications have been made,
+        # then leave it alone.  If it was modified, then remove the symbolic
+        # link before writing.
+        if os.path.islink(outname):
+            if not modified:
+                return 0
+            else:
+                os.unlink(outname)
+        try:
+            with open(outname, 'w') as outFile:
+                for i in fixedlines:
+                    print(i, file=outFile)
+        except:
+            print('convert_sc_cdl.py: failed to open ' + outname + ' for writing.', file=sys.stderr)
+            return 1
+
+
+if __name__ == '__main__':
+
+    # This script expects to get one or two arguments.  One argument is
+    # mandatory and is the input file.  The other argument is optional and
+    # is the output file.  The output file and input file may be the same
+    # name, in which case the original input is overwritten.
+
+    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:
+        infilename = arguments[0]
+
+    if len(arguments) > 1:
+        outfilename = arguments[1]
+    else:
+        outfilename = None
+
+    result = filter(infilename, outfilename)
+    sys.exit(result)
diff --git a/gf180mcu/custom/scripts/convert_sram_cdl.py b/gf180mcu/custom/scripts/convert_sram_cdl.py
new file mode 100755
index 0000000..b07c09b
--- /dev/null
+++ b/gf180mcu/custom/scripts/convert_sram_cdl.py
@@ -0,0 +1,95 @@
+#!/usr/bin/env python3
+#
+# convert_sram_cdl.py ---
+#
+# This script converts the GF CDL for the SRAM macros to turn them into valid
+# SPICE syntax, using regular expression parsing.
+
+# This script is a filter to be run by setting the name of this script as
+# the value to "filter=" for the model install in the sky130 Makefile.
+
+import re
+import os
+import sys
+
+def filter(inname, outname):
+
+    # Read input
+    try:
+        with open(inname, 'r') as inFile:
+            spitext = inFile.read()
+            # (Don't) unwrap continuation lines
+            # spilines = spitext.replace('\n+', ' ').splitlines()
+            spilines = spitext.splitlines()
+    except:
+        print('convert_sram_cdl.py: failed to open ' + inname + ' for reading.', file=sys.stderr)
+        return 1
+
+    fixedlines = []
+    modified = False
+
+    for line in spilines:
+        fixedline = line
+
+        # 1) Lines starting with M --> change to X
+        fixedline = re.sub('^M', 'X', fixedline, flags=re.IGNORECASE)
+        # 2) 5V transistor models --> change to 6V
+        fixedline = re.sub('_05v0', '_06v0', fixedline, flags=re.IGNORECASE)
+        # 3) Remove $X, $Y, $D, and $T parameters
+        fixedline = re.sub('\$X=-?[0-9]+', '', fixedline, flags=re.IGNORECASE)
+        fixedline = re.sub('\$Y=-?[0-9]+', '', fixedline, flags=re.IGNORECASE)
+        fixedline = re.sub('\$D=-?[0-9]+', '', fixedline, flags=re.IGNORECASE)
+        fixedline = re.sub('\$T=-?[0-9]+ -?[0-9]+ -?[0-9]+ -?[0-9]+', '',
+			fixedline, flags=re.IGNORECASE)
+
+        if line != fixedline:
+            modified = True
+        fixedlines.append(fixedline)
+
+    # Write output
+    if outname == None:
+        for i in fixedlines:
+            print(i)
+    else:
+        # If the output is a symbolic link but no modifications have been made,
+        # then leave it alone.  If it was modified, then remove the symbolic
+        # link before writing.
+        if os.path.islink(outname):
+            if not modified:
+                return 0
+            else:
+                os.unlink(outname)
+        try:
+            with open(outname, 'w') as outFile:
+                for i in fixedlines:
+                    print(i, file=outFile)
+        except:
+            print('convert_sram_cdl.py: failed to open ' + outname + ' for writing.', file=sys.stderr)
+            return 1
+
+
+if __name__ == '__main__':
+
+    # This script expects to get one or two arguments.  One argument is
+    # mandatory and is the input file.  The other argument is optional and
+    # is the output file.  The output file and input file may be the same
+    # name, in which case the original input is overwritten.
+
+    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:
+        infilename = arguments[0]
+
+    if len(arguments) > 1:
+        outfilename = arguments[1]
+    else:
+        outfilename = None
+
+    result = filter(infilename, outfilename)
+    sys.exit(result)
diff --git a/gf180mcu/custom/scripts/gds_import_sram.tcl b/gf180mcu/custom/scripts/gds_import_sram.tcl
index bbb0f15..26b625d 100644
--- a/gf180mcu/custom/scripts/gds_import_sram.tcl
+++ b/gf180mcu/custom/scripts/gds_import_sram.tcl
@@ -11,5 +11,18 @@
 gds flatglob pmos_1p2*
 gds flatglob via1_*
 gds flatglob ypass_gate*
+# These additional cells must be flattened to get rid of 3.3V devices
+# (DUALGATE drawn into high-level cells)
+gds flatglob dcap_103*
+gds flatglob din_*
+gds flatglob mux821_*
+gds flatglob rdummy_*
+gds flatglob pmoscap_*
+gds flatglob xdec_*
+gds flatglob ypredec*
+gds flatglob xpredec*
+gds flatglob xdec8_*
+gds flatglob prexdec_*
+gds flatglob xdec32_*
 # Ensure unique cell names when reading multiple GDS files
 calma unique true
diff --git a/gf180mcu/magic/gf180mcu.tech b/gf180mcu/magic/gf180mcu.tech
index f437eb7..0de72ef 100644
--- a/gf180mcu/magic/gf180mcu.tech
+++ b/gf180mcu/magic/gf180mcu.tech
@@ -3429,18 +3429,18 @@
  routing mtp	MetalTop Metal6 METAL6 METTP mtp mettp MET6 m6 met6 metal6
 #endif (METALS6)
 
- cut m2c  Via1 VIA1 via1 cont2 via12
+ cut m2c  Via1 VIA1 via1 cont2 via12 VIA12
 #ifdef METALS3 || METALS4 || METALS5 || METALS6
- cut m3c  Via2 VIA2 via2 cont3 via23
+ cut m3c  Via2 VIA2 via2 cont3 via23 VIA23
 #endif (METALS3 || METALS4 || METALS5 || METALS6)
 #ifdef METALS4 || METALS5 || METALS6
- cut via3 Via3 VIA3 via3 cont4 via34
+ cut via3 Via3 VIA3 via3 cont4 via34 VIA34
 #endif (METALS4 || METALS5 || METALS6)
 #ifdef METALS5 || METALS6
- cut via4 Via4 VIA4 via4 cont5 via45
+ cut via4 Via4 VIA4 via4 cont5 via45 VIA45
 #endif (METALS5 || METALS6)
 #ifdef METALS6
- cut viatp Via5 viatp VIATP VIA5 vtp via5 cont6 via56
+ cut viatp Via5 viatp VIATP VIA5 vtp via5 cont6 via56 VIA56
 #endif (METALS6)
 
  obs obsm1   Metal1
diff --git a/scripts/configure.ac b/scripts/configure.ac
index ce8662a..f1852ff 100755
--- a/scripts/configure.ac
+++ b/scripts/configure.ac
@@ -275,6 +275,22 @@
 
 AC_MSG_NOTICE([Tools enabled for PDK setup installation: M4_GET_TOOLS()])
 
+# Check for "--with-reference"
+USE_REFERENCE=0
+AC_ARG_WITH(
+    [reference],
+    AS_HELP_STRING(
+        [--with-reference],
+        [Use PDK JSON file reference commit values for sources @<:@default=no@:>@]
+    ), [
+        pdks_reference=$withval
+        if test "$withval" == "yes" -o "$withval" == "YES"; then
+            USE_REFERENCE=1
+        fi
+    ],
+)
+AC_SUBST(USE_REFERENCE)
+
 # Check for "--with-ef-style"
 EF_STYLE=0
 AC_ARG_WITH(
@@ -289,8 +305,8 @@
         fi
     ],
 )
-
 AC_SUBST(EF_STYLE)
+
 # Export the list of enabled technologies to the Makefile
 AC_SUBST(ENABLED_TECHS)
 # Export the top level directory of open_pdks
diff --git a/scripts/download.sh b/scripts/download.sh
index 56af3ea..660c978 100755
--- a/scripts/download.sh
+++ b/scripts/download.sh
@@ -5,7 +5,7 @@
 #	directory, untar it, and remove the tarball file.  If the URL is
 #	a repository and not a file, then clone it.
 #
-#	Usage:  download.sh <url> <target_dir> [<strip>]
+#	Usage:  download.sh <url> <target_dir> [<strip>|<commit>|<tag>]
 #
 # where:
 #
@@ -19,6 +19,8 @@
 #	<strip> is the number of directory levels to strip off the front of the
 #		tarball contents.  Defaults to 1 if not specified (only
 #		applicable if <url> points to a tarball).
+#	<commit> or <tag> is a specific reference commit to clone.  If the
+#		<url> is not a git repository, then this option has no effect.
 #
 
 # Check if <url> points to a tarball or a repository (note:  this assumes
@@ -68,7 +70,14 @@
 
     if type "git" > /dev/null; then
         echo "Cloning $1 to $2"
-        git clone --depth 1 $1 $2
+    	if [ $# -gt 2 ]; then
+            # git clone $1 $2
+	    # git checkout $3
+	    git clone --branch $3 --single-branch $1 $2
+	else
+            git clone --depth 1 $1 $2
+    	fi
+
     else
         echo "ERROR: \"git\" is required to automatically install tools."
         exit 1
diff --git a/sky130/Makefile.in b/sky130/Makefile.in
index a0cfd35..d2336be 100644
--- a/sky130/Makefile.in
+++ b/sky130/Makefile.in
@@ -245,6 +245,8 @@
 OSU_T15_URL = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_osu_sc_t15
 OSU_T18_URL = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_osu_sc_t18
 
+USE_REFERENCE = @USE_REFERENCE@
+
 # NOTE:  Install destination is the git repository of the technology platform.
 # Once updated in git, the git project can be distributed to all hosts.
 #
@@ -589,6 +591,8 @@
 	SPIEXT = spice
 endif
 
+all: $(foreach var, ${VARIANTS}, all-$(var))
+
 reference: ${TECH}.json
 	# Rewrite the ${TECH}.json file to change the commit values in
 	# "reference" to reflect the state of the system when  "make
@@ -597,8 +601,6 @@
 	# tools.
 	../common/save_commit_refs.py ${COMMIT_DEFS} ${TECH}.json
 
-all: $(foreach var, ${VARIANTS}, all-$(var))
-
 # Handle prerequisites (fetch and install the PDK and requested libraries)
 prerequisites: pdk-repo alpha-repo xschem-repo klayout-repo precheck-repo sram-repo osu-t12-repo osu-t15-repo osu-t18-repo