Add classes for the drive strengths.
diff --git a/scripts/python-skywater-pdk/skywater_pdk/drives.py b/scripts/python-skywater-pdk/skywater_pdk/drives.py
new file mode 100644
index 0000000..6176c6e
--- /dev/null
+++ b/scripts/python-skywater-pdk/skywater_pdk/drives.py
@@ -0,0 +1,262 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020 The SkyWater PDK Authors.
+#
+# Use of this source code is governed by the Apache 2.0
+# license that can be found in the LICENSE file or at
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import abc
+import os
+import operator
+
+from dataclasses import dataclass
+
+
+class InvalidSuffixError(ValueError):
+    def __init__(self, s):
+        ValueError.__init__(self, "Invalid suffix: {}".format(s.strip()))
+
+
+class DriveStrength(abc.ABC):
+    """Drive strength variants of a given cell.
+
+    >>> d1 = DriveStrength.from_suffix("_1")
+    >>> d2 = DriveStrength.from_suffix("_lp")
+    >>> d3 = DriveStrength.from_suffix("_m")
+    >>> d4 = DriveStrength.from_suffix("_2")
+    >>> DriveStrength.from_suffix("_abc")
+    Traceback (most recent call last):
+        ...
+    InvalidSuffixError: Invalid suffix: _abc
+    >>> l = [d1, d2, d3, d4]
+    >>> l
+    [DriveStrengthNumeric(units=1), DriveStrengthLowPower(variant=0), DriveStrengthMinimum(), DriveStrengthNumeric(units=2)]
+    >>> l.sort()
+    >>> l
+    [DriveStrengthNumeric(units=1), DriveStrengthNumeric(units=2), DriveStrengthLowPower(variant=0), DriveStrengthMinimum()]
+    """
+
+    @abc.abstractmethod
+    def describe(self):
+        raise NotImplementedError
+
+    @property
+    @abc.abstractmethod
+    def suffix(self):
+        raise NotImplementedError
+
+    @classmethod
+    def from_suffix(cls, s):
+        errors = []
+        for subcls in cls.__subclasses__():
+            try:
+                return subcls.from_suffix(s)
+            except (ValueError, AssertionError) as e:
+                errors.append((subcls.__name__, e))
+        assert errors, ("Unknown error!?", s)
+        msg = [s, '']
+        for cls_name, e in errors:
+            if isinstance(e, ValueError):
+                continue
+            msg.append("{} failed with: {}".format(cls_name, e))
+        raise InvalidSuffixError("\n".join(msg))
+
+    def __str__(self):
+        return "drive strength {}".format(self.describe())
+
+    def _cmp(self, op, o):
+        if not isinstance(o, DriveStrength):
+            return False
+        return op(self.suffix, o.suffix)
+
+    # Comparison operators
+    def __lt__(self, o):
+        return self._cmp(operator.lt, o)
+
+    def __le__(self, o):
+        return self._cmp(operator.le, o)
+
+    def __eq__(self, o):
+        return self._cmp(operator.eq, o)
+
+    def __ne__(self, o):
+        return self._cmp(operator.ne, o)
+
+    def __ge__(self, o):
+        return self._cmp(operator.ge, o)
+
+    def __gt__(self, o):
+        return self._cmp(operator.gt, o)
+
+
+@dataclass(frozen=True)
+class DriveStrengthNumeric(DriveStrength):
+    """
+    >>> s1 = DriveStrengthNumeric.from_suffix("_1")
+    >>> s2 = DriveStrengthNumeric.from_suffix("_2")
+    >>> s3 = DriveStrengthNumeric.from_suffix("_3")
+    >>> DriveStrengthNumeric.from_suffix("_0")
+    Traceback (most recent call last):
+        ...
+    InvalidSuffixError: Invalid suffix: _0
+    >>> s1
+    DriveStrengthNumeric(units=1)
+    >>> s2
+    DriveStrengthNumeric(units=2)
+    >>> s3
+    DriveStrengthNumeric(units=3)
+    >>> str(s1)
+    'drive strength 1 units'
+    >>> str(s2)
+    'drive strength 2 units'
+    >>> str(s3)
+    'drive strength 3 units (invalid?)'
+    >>> s1.describe()
+    '1 units'
+    >>> s2.describe()
+    '2 units'
+    >>> s3.describe()
+    '3 units (invalid?)'
+    >>> s1.suffix
+    '_1'
+    >>> s2.suffix
+    '_2'
+    >>> s3.suffix
+    '_3'
+    """
+    units: int
+
+    def describe(self):
+        suffix = ""
+        if self.units not in (1, 2, 4):
+            suffix = " (invalid?)"
+
+        return "{} units{}".format(self.units, suffix)
+
+    @property
+    def suffix(self):
+        return "_{}".format(self.units)
+
+    @classmethod
+    def from_suffix(cls, s):
+        if not s.startswith("_"):
+            raise InvalidSuffixError(s)
+        i = int(s[1:])
+        if i <= 0:
+            raise InvalidSuffixError(s)
+        return cls(i)
+
+
+@dataclass(frozen=True)
+class DriveStrengthLowPower(DriveStrength):
+    """
+    >>> lp = DriveStrengthLowPower.from_suffix("_lp")
+    >>> lp2 = DriveStrengthLowPower.from_suffix("_lp2")
+    >>> lp3 = DriveStrengthLowPower.from_suffix("_lp3")
+    >>> DriveStrengthLowPower.from_suffix("_ld")
+    Traceback (most recent call last):
+        ...
+    InvalidSuffixError: Invalid suffix: _ld
+    >>> lp
+    DriveStrengthLowPower(variant=0)
+    >>> lp2
+    DriveStrengthLowPower(variant=1)
+    >>> lp3
+    DriveStrengthLowPower(variant=2)
+    >>> str(lp)
+    'drive strength Low Power'
+    >>> str(lp2)
+    'drive strength Low Power (alternative)'
+    >>> str(lp3)
+    'drive strength Low Power (extra alternative 0)'
+    >>> lp.describe()
+    'Low Power'
+    >>> lp2.describe()
+    'Low Power (alternative)'
+    >>> lp3.describe()
+    'Low Power (extra alternative 0)'
+    >>> lp.suffix
+    '_lp'
+    >>> lp2.suffix
+    '_lp2'
+    >>> lp3.suffix
+    '_lp3'
+    """
+    variant: int = 0
+
+    def describe(self):
+        if self.variant == 0:
+            suffix = ""
+        elif self.variant == 1:
+            suffix = " (alternative)"
+        else:
+            assert self.variant >= 2, self.variant
+            suffix = " (extra alternative {})".format(self.variant-2)
+        return "Low Power"+suffix
+
+    @property
+    def suffix(self):
+        if self.variant == 0:
+            return "_lp"
+        else:
+            assert self.variant > 0, self.variant
+            return "_lp{}".format(self.variant+1)
+
+    @classmethod
+    def from_suffix(cls, s):
+        if not s.startswith("_lp"):
+            raise InvalidSuffixError(s)
+        if s == "_lp":
+            return cls()
+        elif s == "_lp2":
+            return cls(1)
+        else:
+            try:
+                i = int(s[3:])
+            except ValueError as e:
+                raise InvalidSuffixError(s)
+            assert i > 2, (s, i)
+            return cls(i-1)
+
+
+class DriveStrengthMinimum(DriveStrength):
+    """
+    >>> m = DriveStrengthMinimum.from_suffix("_m")
+    >>> DriveStrengthMinimum.from_suffix("_m2")
+    Traceback (most recent call last):
+        ...
+    InvalidSuffixError: Invalid suffix: _m2
+    >>> m
+    DriveStrengthMinimum()
+    >>> str(m)
+    'drive strength minimum'
+    >>> m.describe()
+    'minimum'
+    >>> m.suffix
+    '_m'
+    """
+
+    def __repr__(self):
+        return "DriveStrengthMinimum()"
+
+    def describe(self):
+        return "minimum"
+
+    @property
+    def suffix(self):
+        return "_m"
+
+    @classmethod
+    def from_suffix(cls, s):
+        if s != "_m":
+            raise InvalidSuffixError(s)
+        return cls()
+
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()