Added a new script that can remove wildcarded labels from .mag
files after running foundry_install.py.  Applied the script to
the GF SRAM cell, which has labels that virtually merge a number
of bit lines if "extract unique" is not used.
diff --git a/VERSION b/VERSION
index 65dac43..dfa6bf0 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-1.0.429
+1.0.430
diff --git a/common/remove_label.py b/common/remove_label.py
new file mode 100755
index 0000000..96b81c9
--- /dev/null
+++ b/common/remove_label.py
@@ -0,0 +1,142 @@
+#!/usr/bin/env python3
+#
+# remove_label.py:  For the given install path, library name, and cellname,
+# find the Magic layout of the cell, and remove any label equal to the
+# given label text (which may contain glob-syntax wildcards).  Ensure that
+# any port designation for any deleted label is also removed.
+# The label is remove from layout in both the mag/ (full) and maglef/
+# (abstract) directories.  Option "-maglef" or "-mag" will restrict the
+# use to only the view indicated by the option.
+#
+# The cell name may also be wildcarded with glob-style syntax.
+# 
+# e.g.:
+#
+# remove_label.py /path/to/gf180mcu \
+#	gf180mcu_fd_ip_sram rarray4\* BL\* -mag
+
+import os
+import re
+import sys
+import glob
+import fnmatch
+
+def removelabel(filename, text):
+    filelist = glob.glob(filename)
+    for file in filelist:
+        with open(file, 'r') as ifile:
+            magtext = ifile.read().splitlines() 
+
+        sectionrex = re.compile('<< ')
+        labelsrex = re.compile('<< labels >>')
+
+        in_labels = False
+        ignore = False
+        watch = False
+
+        with open(file, 'w') as ofile:
+            for line in magtext:
+                watch = True if ignore else False
+                ignore = False
+                lmatch = labelsrex.match(line)
+                if lmatch:
+                    in_labels = True
+                elif in_labels:
+                    smatch = sectionrex.match(line)
+                    if smatch:
+                        in_labels = False
+                    else:
+                        label = line.split()[-1]
+                        if fnmatch.fnmatch(label, text):
+                            ignore = True
+                        elif watch:
+                            if line.startswith('port'):
+                                ignore = True
+
+                if not ignore:
+                    print(line, file=ofile)
+
+def usage():
+    print("remove_label.py <path_to_pdk> <libname> <cellname> <text> [option]")
+    print("  options:")
+    print("   -mag      do only for the view in the mag/ directory")
+    print("   -maglef   do only for the view in the maglef/ directory")
+    return 0
+
+if __name__ == '__main__':
+
+    options = []
+    arguments = []
+    for item in sys.argv[1:]:
+        if item.find('-', 0) == 0:
+            options.append(item)
+        else:
+            arguments.append(item)
+
+    if len(arguments) < 4:
+        print("Not enough options given to remove_label.py.")
+        usage()
+        sys.exit(0)
+
+    source = arguments[0]
+    libname = arguments[1]
+    cellname = arguments[2]
+    text = arguments[3]
+
+    # Diagnostic
+    print('remove_label.py:')
+    print('   source   = ' + source)
+    print('   library  = ' + libname)
+    print('   cell     = ' + cellname)
+    print('   text     = ' + text)
+
+    fail = 0
+
+    efformat = True if '-ef_format' in options else False
+
+    domag = True
+    domaglef = True
+    if '-mag' in options and '-maglef' not in options:
+        domaglef = False
+    if '-maglef' in options and '-mag' not in options:
+        domag = False
+
+    if domag:
+        if efformat:
+            filename = source + '/libs.ref/mag/' + libname + '/' + cellname + '.mag'
+        else:
+            filename = source + '/libs.ref/' + libname + '/mag/' + cellname + '.mag'
+
+        if os.path.isfile(filename):
+            removelabel(filename, text)
+        elif len(glob.glob(filename)) > 0:
+            removelabel(filename, text)
+        else:
+            fail += 1
+    else:
+        fail += 1
+
+    if domaglef:
+        if efformat:
+            filename = source + '/libs.ref/maglef/' + libname + '/' + cellname + '.mag'
+        else:
+            filename = source + '/libs.ref/' + libname + '/maglef/' + cellname + '.mag'
+
+        if os.path.isfile(filename):
+            removelabel(filename, text)
+        elif len(glob.glob(filename)) > 0:
+            removelabel(filename, text)
+        else:
+            fail += 1
+    else:
+        fail += 1
+
+    if fail == 2:
+        print('Error:  No matching layout file in either mag/ or maglef/', file=sys.stderr)
+        if efformat:
+            print('(' + source + '/libs.ref/mag[lef]/' + libname +
+		    '/' + cellname + '.mag)', file=sys.stderr)
+        else:
+            print('(' + source + '/libs.ref/' + libname + '/mag[lef]/'
+		    + cellname + '.mag)', file=sys.stderr)
+
diff --git a/gf180mcu/Makefile.in b/gf180mcu/Makefile.in
index 865f3e5..87afbde 100644
--- a/gf180mcu/Makefile.in
+++ b/gf180mcu/Makefile.in
@@ -431,6 +431,7 @@
 # The script(s) below are used for custom changes to the vendor PDK files
 PORTORDER = ../common/port_order.py ${EF_FORMAT}
 ADDPROP = ../common/insert_property.py ${EF_FORMAT}
+REMOVELAB = ../common/remove_label.py ${EF_FORMAT}
 
 # List the EDA tools to install local setup files for
 TOOLS =
@@ -1192,6 +1193,10 @@
 		-lef cells/*/*.lef \
 		-verilog cells/*/*.v \
 		-library general gf180mcu_fd_ip_sram 2>&1 | tee -a ${GF180MCU$*}_make.log
+	# Remove "BL" labels from the rarray4_* cells, otherwise extraction
+	# of the SRAMs without using "extract unique" will fail.
+	${REMOVELAB} ${STAGING_PATH}/${GF180MCU$*} gf180mcu_fd_ip_sram \
+		rarray4_\* BL\* -mag
 
 install: $(foreach var, ${VARIANTS}, install-$(var))
 
diff --git a/gf180mcu/gf180mcu.json b/gf180mcu/gf180mcu.json
index cb7d71a..fa51485 100644
--- a/gf180mcu/gf180mcu.json
+++ b/gf180mcu/gf180mcu.json
@@ -89,8 +89,8 @@
         "magic": "MAGIC_COMMIT"
     },
     "reference": {
-        "open_pdks": "3607aec4e558da5f060623e9e62ba10d094b5a5e",
-        "magic": "8b3bb1ae771da1673ac148987466ff31c63513cd",
+        "open_pdks": "405227f0d564aa8a291b91365a561ccd468b1dbe",
+        "magic": "89f1c4ee67ceb834ceeba352192d8f9aa51fbd93",
         "gf180mcu_pdk": "a897aa30369d3bcec87d9d50ce9b01f320f854ef",
         "gf180mcu_fd_pr": "7e276a7c9c20c113d37e43ad6bfc1825b9613d7b",
         "gf180mcu_fd_pv": "bc0385ef83280999f7fc332512d91ca73008f701",
diff --git a/sky130/sky130.json b/sky130/sky130.json
index e61f532..3d2c388 100644
--- a/sky130/sky130.json
+++ b/sky130/sky130.json
@@ -93,8 +93,8 @@
         "magic": "MAGIC_COMMIT"
     },
     "reference": {
-        "open_pdks": "05fda41fac52b44772d1b8467b1c184fdc7aa7c4",
-        "magic": "8b3bb1ae771da1673ac148987466ff31c63513cd",
+        "open_pdks": "405227f0d564aa8a291b91365a561ccd468b1dbe",
+        "magic": "89f1c4ee67ceb834ceeba352192d8f9aa51fbd93",
         "sky130_fd_pr": "7e2bb61f58345c203b693b2fcc178896965616d7",
         "sky130_fd_io": "2b8ce839a273734b2b1ec51b632c948f31814eb5",
         "sky130_fd_sc_hs": "51e41a54135f6f345f415f1f7a19c59a4d363c23",
@@ -110,8 +110,8 @@
         "sky130_sram_macros": "c2333394e0b0b9d9d71185678a8d8087715d5e3b",
         "sky130_fd_bd_sram": "be33adbcf188fdeab5c061699847d9d440f7a084",
         "sky130_ml_xx_hd": "6eb3b0718552b034f1bf1870285ff135e3fb2dcb",
-        "xschem_sky130": "8fee6119d3cb1eab1da1406d033d6a870ca9f6c4",
+        "xschem_sky130": "5f818f03969e91a71529cddf4cd930c8a2c97ac6",
         "klayout_sky130": "5e6e2b29d2b9f8d0f2de1b5d5f649f33017dac75",
-        "precheck_sky130": "2a975ce36453fd4fe734f32b3a9bbc512c4e2347"
+        "precheck_sky130": "22568499b792afbd6f962decf3d8e6c1184dfb1e"
     }
 }