Lot more hacks.
diff --git a/scripts/python-skywater-pdk/generate_metadata_json.py b/scripts/python-skywater-pdk/generate_metadata_json.py
index e057762..e02bfa1 100755
--- a/scripts/python-skywater-pdk/generate_metadata_json.py
+++ b/scripts/python-skywater-pdk/generate_metadata_json.py
@@ -16,6 +16,7 @@
 import re
 import sys
 import traceback
+from collections import defaultdict
 
 from skywater_pdk import base, corners, drives
 
@@ -73,6 +74,8 @@
     re.compile('lpflow_'),
     re.compile('macro_sparecell'),
     re.compile('macro_sync'),
+    re.compile('lsbuflv2hv_simple'),
+    re.compile('_lp'),
 ]
 
 def should_ignore(f, x=IGNORE):
@@ -131,10 +134,11 @@
     assert fname is None, (cellpath, dcell, fname)
 
     extensions = set()
-    dcorners = set()
+    dcorners = defaultdict(list)
     ddrives = set()
     checksums = {}
     errors = []
+    warnings = []
     for fname, fpath in files:
         if should_ignore(fpath):
             continue
@@ -159,8 +163,9 @@
             continue
 
         try:
-            fcorner = corners.parse_filename(fextra)
-            dcorners.add(fcorner)
+            fcorner, corner_extra = corners.parse_filename(fextra)
+            corner_extra = "_".join(corner_extra)
+            dcorners[corner_extra].append(fcorner)
         except Exception as e:
             traceback.print_exc()
             errors.append('Invalid corner: {} -- {} (from {})'.format(e, fextra, fpath))
@@ -184,18 +189,18 @@
 
     if 'full.v' in extensions:
         o = None
-        for ext in ['full.v', 'simple.v']:
-            fname = os.path.join(cellpath, "{}.{}".format(dcell.fullname, ext))
+        for ext in ['.full.v', '.simple.v', '_1.full.v', '_1.simple.v']:
+            fname = os.path.join(cellpath, "{}{}".format(dcell.fullname, ext))
             if not os.path.exists(fname):
-                errors.append("Missing {} file".format(fname))
+                warnings.append("Missing {} file".format(fname))
                 continue
             o = vlog_ex.extract_objects(fname)
             if not o or len(o) != 1:
-                errors.append("Invalid {} file ({})".format(fname, o))
+                warnings.append("Invalid {} file ({})".format(fname, o))
                 continue
             o = o[0]
             if not o:
-                errors.append("Invalid {} file ({})".format(fname, o))
+                warnings.append("Invalid {} file ({})".format(fname, o))
             break
         if o:
             assert dcell.fullname in o.name, (dcell.fullname, o)
@@ -222,6 +227,9 @@
                 'signal': non_pwr,
                 'power': pwr,
             }
+        else:
+            errors.extend(warnings)
+            warnings.clear()
 
     extensions.add('metadata.json')
 
@@ -230,7 +238,16 @@
     else:
         metadata['files'] = checksums
     if dcorners:
-        metadata['corners'] = [d.to_dict() for d in sorted(dcorners)]
+        if len(dcorners) > 1:
+            print(dcorners.keys())
+        o = []
+        for k in dcorners:
+            x = [d.to_dict() for d in sorted(dcorners[k])]
+            if k != '':
+                for i in range(0, len(x)):
+                    x[i]['extra'] = k
+            o.extend(x)
+        metadata['corners'] = o
     else:
         errors.append('Missing corners for: {}\n'.format(cellpath))
 
@@ -246,6 +263,15 @@
         json.dump(metadata, f, sort_keys=True, indent="   ")
     print("Wrote:", mdata_file)
 
+    if warnings:
+        sys.stderr.flush()
+        sys.stdout.flush()
+        print("Warnings:")
+        print("   ", "\n    ".join(warnings))
+        print()
+        sys.stderr.flush()
+        sys.stdout.flush()
+
     if errors:
         raise ValueError("\n".join(str(e) for e in errors))
 
@@ -259,9 +285,20 @@
             process(p)
         except Exception as e:
             if not should_ignore(p, ALLOW_ERRORS):
+                sys.stderr.flush()
+                sys.stdout.flush()
+                print('\n'*4, file=sys.stderr)
+                print("FATAL ERROR while processing:", p, file=sys.stderr)
+                print('-'*75, file=sys.stderr)
+                sys.stderr.flush()
+                sys.stdout.flush()
                 raise
-            print("Failed to process ignorable:", p)
+            print(file=sys.stderr)
+            print("Failed to process ignorable:", p, file=sys.stderr)
+            print('-'*75, file=sys.stderr)
             traceback.print_exc()
+            print('-'*75, file=sys.stderr)
+            sys.stderr.flush()
 
 
 if __name__ == "__main__":
diff --git a/scripts/python-skywater-pdk/generate_top_verilog.py b/scripts/python-skywater-pdk/generate_top_verilog.py
index e2df032..ef8d07c 100755
--- a/scripts/python-skywater-pdk/generate_top_verilog.py
+++ b/scripts/python-skywater-pdk/generate_top_verilog.py
@@ -145,6 +145,19 @@
         assert len(d) == 1, d
         drive_name = list(d.keys())[0]
         drive_value = list(d.values())[0]
+        if drive_name == 'units':
+            pass
+        elif drive_name == 'lp_variant':
+            if drive_value == 0:
+                drive_value = 'lp'
+            else:
+                drive_value = 'lp'+str(drive_value+1)
+        elif drive_name == "minimum":
+            assert drive_value is None
+            drive_value = "m"
+        else:
+            raise TypeError("Unknown drive:"+repr(d))
+
         dvfile = os.path.join(cellpath, "{}_{}.v".format(mdata['fullname'], drive_value))
         write_verilog(mdata, dvfile, list(d.items())[0])
         echo_file(dvfile)
diff --git a/scripts/python-skywater-pdk/skywater_pdk/analyze.py b/scripts/python-skywater-pdk/skywater_pdk/analyze.py
index 44c0ce8..148cc3c 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/analyze.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/analyze.py
@@ -42,8 +42,8 @@
 
     if extension in ('wrap.lib', 'wrap.json', 'cell.lib', 'cell.json'):
         try:
-            corners = parse_filename_corners(extra)
-            print(corners)
+            corners, extra = parse_filename_corners(extra)
+            print(corners, extra)
         except Exception as e:
             traceback.print_exc()
             return
diff --git a/scripts/python-skywater-pdk/skywater_pdk/base.py b/scripts/python-skywater-pdk/skywater_pdk/base.py
index 07b4708..6c6c561 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/base.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/base.py
@@ -172,7 +172,7 @@
     Cell(name='top_powerhv_hvc_wpad', library=Library(node=LibraryNode.SKY130, source=LibrarySource('fd'), type=LibraryType.io, name='', version=LibraryVersion(milestone=0, major=1, minor=0, commits=0, hash='')))
     >>> from skywater_pdk.corners import parse_filename as pf_corners
     >>> pf_corners(t.pop(0))
-    Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3), temps=(100,), flags=None)
+    (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3), temps=(100,), flags=None), [])
     >>> t.pop(0)
     'wrap.json'
 
diff --git a/scripts/python-skywater-pdk/skywater_pdk/corners.py b/scripts/python-skywater-pdk/skywater_pdk/corners.py
index 184218b..214a8fb 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/corners.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/corners.py
@@ -33,6 +33,15 @@
 # "ws" is "worst-case speed" and corresponds to "ss"
 CornerTypeMappings["ws"] = "ss"
 
+CornerTypeValues = [
+    'ff',
+    'ss',
+    'tt',
+    'fs',
+    'sf',
+]
+CORNER_TYPE_REGEX = re.compile('[tfs][tfs]')
+
 
 class CornerType(OrderedFlag):
     """
@@ -77,6 +86,7 @@
     nointpr = 'No internal power'
     lv = 'Low voltage'
     hv = 'High voltage'
+    lowhv = 'Low High Voltage'
     ccsnoise = 'Composite Current Source Noise'
     pwr = 'Power'
     xx = 'xx'
@@ -124,34 +134,40 @@
     """Extract corner information from a filename.
 
     >>> parse_filename('tt_1p80V_3p30V_3p30V_25C')
-    Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None)
+    (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None), [])
 
     >>> parse_filename('sky130_fd_io__top_ground_padonlyv2__tt_1p80V_3p30V_3p30V_25C.wrap.lib')
-    Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None)
+    (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8, 3.3, 3.3), temps=(25,), flags=None), [])
 
     >>> parse_filename('sky130_fd_sc_ms__tt_1p80V_100C.wrap.json')
-    Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None)
+    (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None), [])
 
     >>> parse_filename('sky130_fd_sc_ms__tt_1p80V_100C.wrap.lib')
-    Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None)
+    (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(100,), flags=None), [])
 
     >>> parse_filename('sky130_fd_sc_ms__tt_1p80V_25C_ccsnoise.wrap.json')
-    Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(25,), flags=(CornerFlag.ccsnoise,))
+    (Corner(corner=(CornerType.t, CornerType.t), volts=(1.8,), temps=(25,), flags=(CornerFlag.ccsnoise,)), [])
 
     >>> parse_filename('sky130_fd_sc_ms__wp_1p65V_n40C.wrap.json')
-    Corner(corner=(CornerType.f, CornerType.f), volts=(1.65,), temps=(-40,), flags=None)
+    (Corner(corner=(CornerType.f, CornerType.f), volts=(1.65,), temps=(-40,), flags=None), [])
 
     >>> parse_filename('sky130_fd_sc_ms__wp_1p95V_85C_pwr.wrap.lib')
-    Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(85,), flags=(CornerFlag.pwr,))
+    (Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(85,), flags=(CornerFlag.pwr,)), [])
 
     >>> parse_filename('sky130_fd_sc_ms__wp_1p95V_n40C_ccsnoise.wrap.json')
-    Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.ccsnoise,))
+    (Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.ccsnoise,)), [])
 
     >>> parse_filename('sky130_fd_sc_ms__wp_1p95V_n40C_pwr.wrap.lib')
-    Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.pwr,))
+    (Corner(corner=(CornerType.f, CornerType.f), volts=(1.95,), temps=(-40,), flags=(CornerFlag.pwr,)), [])
 
     >>> parse_filename('sky130_fd_sc_hd__a2111o_4__ss_1p76V_n40C.cell.json')
-    Corner(corner=(CornerType.s, CornerType.s), volts=(1.76,), temps=(-40,), flags=None)
+    (Corner(corner=(CornerType.s, CornerType.s), volts=(1.76,), temps=(-40,), flags=None), [])
+
+    >>> parse_filename('sky130_fd_sc_ls__lpflow_lsbuf_lh_1__lpflow_wc_lh_level_shifters_ss_1p95V_n40C.cell.json')
+    (Corner(corner=(CornerType.s, CornerType.s), volts=(1.95,), temps=(-40,), flags=None), ['wc', 'lh', 'level', 'shifters'])
+
+    >>> parse_filename('sky130_fd_sc_hvl__lsbufhv2hv_hl_1__ff_5p50V_lowhv_1p65V_lv_ss_1p60V_100C.cell.json')
+    (Corner(corner=(CornerType.f, CornerType.s), volts=(5.5, 1.65, 1.6), temps=(100,), flags=(CornerFlag.lowhv, CornerFlag.lv)), [])
 
     """
     if base.SEPERATOR in pathname:
@@ -178,6 +194,15 @@
     kw['temps'] = []
 
     bits = extra.split("_")
+    random = []
+    while len(bits) > 0:
+        b = bits.pop(0)
+        try:
+            kw['corner'] = CornerType.parse(b)
+            break
+        except TypeError as e:
+            random.append(b)
+
     while len(bits) > 0:
         b = bits.pop(0)
 
@@ -187,11 +212,19 @@
         elif TEMP_REGEX.match(b):
             assert b.endswith('C'), b
             kw['temps'].append(int(b[:-1].replace('n', '-')))
+        elif CORNER_TYPE_REGEX.match(b):
+            # FIXME: These are horrible hacks that should be removed.
+            assert len(b) == 2, b
+            assert b[0] == b[1], b
+            assert 'corner' in kw, kw['corners']
+            assert len(kw['corner']) == 2, kw['corners']
+            assert kw['corner'][0] == kw['corner'][1], kw['corners']
+            other_corner = CornerType.parse(b)
+            assert len(other_corner) == 2, other_corner
+            assert other_corner[0] == other_corner[1], other_corner
+            kw['corner'][1] = other_corner[0]
         else:
-            if 'corner' not in kw:
-                kw['corner'] = CornerType.parse(b)
-            else:
-                kw['flags'].append(CornerFlag.parse(b))
+            kw['flags'].append(CornerFlag.parse(b))
 
     for k, v in kw.items():
         kw[k] = tuple(v)
@@ -199,7 +232,10 @@
     if not kw['flags']:
         del kw['flags']
 
-    return Corner(**kw)
+    if 'corner' not in kw:
+        raise TypeError('Invalid corner value: '+extra)
+
+    return Corner(**kw), random
 
 
 
diff --git a/scripts/python-skywater-pdk/skywater_pdk/drives.py b/scripts/python-skywater-pdk/skywater_pdk/drives.py
index b26c2d4..e2db6c5 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/drives.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/drives.py
@@ -39,10 +39,10 @@
     InvalidSuffixError: Invalid suffix: _abc
     >>> l = [d1, d2, d3, d4]
     >>> l
-    [DriveStrengthNumeric(units=1), DriveStrengthLowPower(variant=0), DriveStrengthMinimum(), DriveStrengthNumeric(units=2)]
+    [DriveStrengthNumeric(units=1), DriveStrengthLowPower(lp_variant=0), DriveStrengthMinimum(), DriveStrengthNumeric(units=2)]
     >>> l.sort()
     >>> l
-    [DriveStrengthNumeric(units=1), DriveStrengthNumeric(units=2), DriveStrengthLowPower(variant=0), DriveStrengthMinimum()]
+    [DriveStrengthNumeric(units=1), DriveStrengthNumeric(units=2), DriveStrengthLowPower(lp_variant=0), DriveStrengthMinimum()]
     """
 
     @abc.abstractmethod
@@ -171,11 +171,11 @@
         ...
     InvalidSuffixError: Invalid suffix: _ld
     >>> lp
-    DriveStrengthLowPower(variant=0)
+    DriveStrengthLowPower(lp_variant=0)
     >>> lp2
-    DriveStrengthLowPower(variant=1)
+    DriveStrengthLowPower(lp_variant=1)
     >>> lp3
-    DriveStrengthLowPower(variant=2)
+    DriveStrengthLowPower(lp_variant=2)
     >>> str(lp)
     'drive strength Low Power'
     >>> str(lp2)
@@ -195,25 +195,25 @@
     >>> lp3.suffix
     '_lp3'
     """
-    variant: int = 0
+    lp_variant: int = 0
 
     def describe(self):
-        if self.variant == 0:
+        if self.lp_variant == 0:
             suffix = ""
-        elif self.variant == 1:
+        elif self.lp_variant == 1:
             suffix = " (alternative)"
         else:
-            assert self.variant >= 2, self.variant
-            suffix = " (extra alternative {})".format(self.variant-2)
+            assert self.lp_variant >= 2, self.lp_variant
+            suffix = " (extra alternative {})".format(self.lp_variant-2)
         return "Low Power"+suffix
 
     @property
     def suffix(self):
-        if self.variant == 0:
+        if self.lp_variant == 0:
             return "_lp"
         else:
-            assert self.variant > 0, self.variant
-            return "_lp{}".format(self.variant+1)
+            assert self.lp_variant > 0, self.lp_variant
+            return "_lp{}".format(self.lp_variant+1)
 
     @classmethod
     def from_suffix(cls, s):
@@ -277,6 +277,10 @@
     def __hash__(self):
         return id(self)
 
+    def to_dict(self):
+        return {'minimum': None}
+
+
 DriveStrengthMinimum._object = DriveStrengthMinimum()