Merge pull request #60 from cclauss/patch-1

Makefile: Add a make lint-python command
diff --git a/.github/autolabeler.yml b/.github/autolabeler.yml
index 0403d85..ad51615 100644
--- a/.github/autolabeler.yml
+++ b/.github/autolabeler.yml
@@ -5,6 +5,7 @@
 files-layout-gds:               ["*.gds"]
 files-layout-lef-magic:         ["*.magic.lef"]
 files-layout-lef:               ["*.lef"]
+files-layout-tlef:              ["*.tlef"]
 
 files-model-behavioral-verilog: ["*.behavioral.v"]
 files-model-functional-verilog: ["*.functional.v"]
diff --git a/.github/labels.yml b/.github/labels.yml
index 7d5587e..9bd2400 100644
--- a/.github/labels.yml
+++ b/.github/labels.yml
@@ -69,6 +69,10 @@
   description: "Issues related to Library Exchange Format (LEF) files."
   color: "d61dae"
 
+- name: "files-layout-tlef"
+  description: "Issues related to Technology Library Exchange Format (TLEF) files."
+  color: "d61dae"
+
 - name: "files-model-behavioral-verilog"
   description: "Issues related to the Verilog behavioural models."
   color: "d61dae"
@@ -182,7 +186,7 @@
   color: "c5d53c"
 
 - name: "lib-sky130_osu_sc"
-  description: "Issues with the IO and periphery cells provided by Oklahoma State University."
+  description: "Issues with the digital standard cells provided by Oklahoma State University."
   color: "004e6f"
 
 # Build spaces
diff --git a/.gitignore b/.gitignore
index a81c8ee..902f9e6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -136,3 +136,6 @@
 
 # Cython debug symbols
 cython_debug/
+
+
+**/timing/*.lib
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..cc709d8
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,96 @@
+# sky130_fd_sc_hd
+[submodule "libraries/sky130_fd_sc_hd/latest"]
+	path = libraries/sky130_fd_sc_hd/latest
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hd.git
+	branch = master
+	shallow = true
+[submodule "libraries/sky130_fd_sc_hd/v0.0.2"]
+	path = libraries/sky130_fd_sc_hd/v0.0.2
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hd.git
+	branch = branch-0.0.2
+	shallow = true
+[submodule "libraries/sky130_fd_sc_hd/v0.0.1"]
+	path = libraries/sky130_fd_sc_hd/v0.0.1
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hd.git
+	branch = branch-0.0.1
+	shallow = true
+
+# sky130_fd_sc_hdll
+[submodule "libraries/sky130_fd_sc_hdll/latest"]
+	path = libraries/sky130_fd_sc_hdll/latest
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hdll.git
+	branch = master
+	shallow = true
+	fetchRecurseSubmodules = true
+[submodule "libraries/sky130_fd_sc_hdll/v0.1.1"]
+	path = libraries/sky130_fd_sc_hdll/v0.1.1
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hdll.git
+	branch = branch-0.1.1
+	shallow = true
+	fetchRecurseSubmodules = false
+[submodule "libraries/sky130_fd_sc_hdll/v0.1.0"]
+	path = libraries/sky130_fd_sc_hdll/v0.1.0
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hdll.git
+	branch = branch-0.1.0
+	shallow = true
+	fetchRecurseSubmodules = false
+
+# sky130_fd_sc_hs
+[submodule "libraries/sky130_fd_sc_hs/latest"]
+	path = libraries/sky130_fd_sc_hs/latest
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hs.git
+	branch = master
+	shallow = true
+	fetchRecurseSubmodules = true
+[submodule "libraries/sky130_fd_sc_hs/v0.0.2"]
+	path = libraries/sky130_fd_sc_hs/v0.0.2
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hs.git
+	branch = branch-0.0.2
+	shallow = true
+	fetchRecurseSubmodules = false
+[submodule "libraries/sky130_fd_sc_hs/v0.0.1"]
+	path = libraries/sky130_fd_sc_hs/v0.0.1
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_hs.git
+	branch = branch-0.0.1
+	shallow = true
+	fetchRecurseSubmodules = false
+
+# sky130_fd_sc_ms
+[submodule "libraries/sky130_fd_sc_ms/latest"]
+	path = libraries/sky130_fd_sc_ms/latest
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_ms.git
+	branch = master
+	shallow = true
+	fetchRecurseSubmodules = true
+[submodule "libraries/sky130_fd_sc_ms/v0.0.2"]
+	path = libraries/sky130_fd_sc_ms/v0.0.2
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_ms.git
+	branch = branch-0.0.2
+	shallow = true
+	fetchRecurseSubmodules = false
+[submodule "libraries/sky130_fd_sc_ms/v0.0.1"]
+	path = libraries/sky130_fd_sc_ms/v0.0.1
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_ms.git
+	branch = branch-0.0.1
+	shallow = true
+	fetchRecurseSubmodules = false
+
+# sky130_fd_sc_ls
+[submodule "libraries/sky130_fd_sc_ls/latest"]
+	path = libraries/sky130_fd_sc_ls/latest
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_ls.git
+	branch = master
+	shallow = true
+	fetchRecurseSubmodules = true
+[submodule "libraries/sky130_fd_sc_ls/v0.1.1"]
+	path = libraries/sky130_fd_sc_ls/v0.1.1
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_ls.git
+	branch = branch-0.1.1
+	shallow = true
+	fetchRecurseSubmodules = false
+[submodule "libraries/sky130_fd_sc_ls/v0.1.0"]
+	path = libraries/sky130_fd_sc_ls/v0.1.0
+	url = https://foss-eda-tools.googlesource.com/skywater-pdk/libs/sky130_fd_sc_ls.git
+	branch = branch-0.1.0
+	shallow = true
+	fetchRecurseSubmodules = false
diff --git a/Makefile b/Makefile
index b9aeac3..a235a27 100644
--- a/Makefile
+++ b/Makefile
@@ -64,4 +64,25 @@
 all: README.rst
 	@true
 
+
+LIBRARIES = $(sort $(notdir $(wildcard libraries/sky130_*_sc_*)))
+
+$(LIBRARIES): | $(CONDA_ENV_PYTHON)
+	@$(IN_CONDA_ENV) for V in libraries/$@/*; do \
+		python -m skywater_pdk.liberty $$V; \
+		python -m skywater_pdk.liberty $$V all; \
+		python -m skywater_pdk.liberty $$V all --ccsnoise; \
+	done
+
+sky130_fd_sc_ms-leakage: | $(CONDA_ENV_PYTHON)
+	 @$(IN_CONDA_ENV) for V in libraries/sky130_fd_sc_ms/*; do \
+		python -m skywater_pdk.liberty $$V all --leakage; \
+	done
+
+sky130_fd_sc_ms: sky130_fd_sc_ms-leakage
+
+timing: $(LIBRARIES) | $(CONDA_ENV_PYTHON)
+	@true
+
+
 .PHONY: all
diff --git a/docs/analog.rst b/docs/analog.rst
new file mode 100644
index 0000000..676e16b
--- /dev/null
+++ b/docs/analog.rst
@@ -0,0 +1,13 @@
+Analog Design
+=============
+
+.. toctree::
+    :caption: Analog Design
+    :name: analog
+
+    With Cadence Virtuoso <analog/virtuoso>
+    With MAGIC <analog/magic>
+    With Klayout <analog/klayout>
+    With Berkeley Analog Generator (BAG) <analog/bag>
+    With FASoC <analog/fasoc>
+    With your design flow? <analog/new>
diff --git a/docs/analog/bag.rst b/docs/analog/bag.rst
new file mode 100644
index 0000000..a8b8297
--- /dev/null
+++ b/docs/analog/bag.rst
@@ -0,0 +1,2 @@
+TODO: analog/bag
+================
diff --git a/docs/analog/fasoc.rst b/docs/analog/fasoc.rst
new file mode 100644
index 0000000..c69f7f4
--- /dev/null
+++ b/docs/analog/fasoc.rst
@@ -0,0 +1,2 @@
+TODO: analog/fasoc
+==================
diff --git a/docs/analog/klayout.rst b/docs/analog/klayout.rst
new file mode 100644
index 0000000..6ca919d
--- /dev/null
+++ b/docs/analog/klayout.rst
@@ -0,0 +1,2 @@
+TODO: analog/klayout
+====================
diff --git a/docs/analog/magic.rst b/docs/analog/magic.rst
new file mode 100644
index 0000000..8e8d6b5
--- /dev/null
+++ b/docs/analog/magic.rst
@@ -0,0 +1,2 @@
+TODO: analog/magic
+==================
diff --git a/docs/analog/new.rst b/docs/analog/new.rst
new file mode 100644
index 0000000..f9403bc
--- /dev/null
+++ b/docs/analog/new.rst
@@ -0,0 +1,2 @@
+TODO: analog/new
+================
diff --git a/docs/analog/virtuoso.rst b/docs/analog/virtuoso.rst
new file mode 100644
index 0000000..0b862ee
--- /dev/null
+++ b/docs/analog/virtuoso.rst
@@ -0,0 +1,2 @@
+TODO: analog/virtuoso
+=====================
diff --git a/docs/contents/libraries/sky130_fd_sc_hd b/docs/contents/libraries/sky130_fd_sc_hd
new file mode 120000
index 0000000..a7a488f
--- /dev/null
+++ b/docs/contents/libraries/sky130_fd_sc_hd
@@ -0,0 +1 @@
+../../../libraries/sky130_fd_sc_hd/latest
\ No newline at end of file
diff --git a/docs/contents/libraries/sky130_fd_sc_hdll b/docs/contents/libraries/sky130_fd_sc_hdll
new file mode 120000
index 0000000..7635ecd
--- /dev/null
+++ b/docs/contents/libraries/sky130_fd_sc_hdll
@@ -0,0 +1 @@
+../../../libraries/sky130_fd_sc_hdll/latest
\ No newline at end of file
diff --git a/docs/contents/libraries/sky130_fd_sc_hs b/docs/contents/libraries/sky130_fd_sc_hs
new file mode 120000
index 0000000..1963458
--- /dev/null
+++ b/docs/contents/libraries/sky130_fd_sc_hs
@@ -0,0 +1 @@
+../../../libraries/sky130_fd_sc_hs/latest
\ No newline at end of file
diff --git a/docs/contents/libraries/sky130_fd_sc_ls b/docs/contents/libraries/sky130_fd_sc_ls
new file mode 120000
index 0000000..961e95a
--- /dev/null
+++ b/docs/contents/libraries/sky130_fd_sc_ls
@@ -0,0 +1 @@
+../../../libraries/sky130_fd_sc_ls/latest
\ No newline at end of file
diff --git a/docs/digital.rst b/docs/digital.rst
new file mode 100644
index 0000000..0b66880
--- /dev/null
+++ b/docs/digital.rst
@@ -0,0 +1,10 @@
+Digital Design
+==============
+
+.. toctree::
+    :caption: Digital Design
+    :name: digital
+
+    With Cadence Innovus <digital/innovus>
+    With OpenROAD <digital/openroad>
+    With your design flow? <digital/new>
diff --git a/docs/digital/innovus.rst b/docs/digital/innovus.rst
new file mode 100644
index 0000000..3977f32
--- /dev/null
+++ b/docs/digital/innovus.rst
@@ -0,0 +1,2 @@
+TODO: digital/innovus
+=====================
diff --git a/docs/digital/new.rst b/docs/digital/new.rst
new file mode 100644
index 0000000..9a03b37
--- /dev/null
+++ b/docs/digital/new.rst
@@ -0,0 +1,2 @@
+TODO: digital/new
+=================
diff --git a/docs/digital/openroad.rst b/docs/digital/openroad.rst
new file mode 100644
index 0000000..40b64b4
--- /dev/null
+++ b/docs/digital/openroad.rst
@@ -0,0 +1,2 @@
+TODO: digital/openroad
+======================
diff --git a/docs/glossary.rst b/docs/glossary.rst
new file mode 100644
index 0000000..553fde5
--- /dev/null
+++ b/docs/glossary.rst
@@ -0,0 +1,165 @@
+Glossary
+========
+
+.. Companies
+
+.. glossary::
+
+    SkyWater
+    SkyWater Technology
+      `SkyWater Technology <https://www.SkyWatertechnology.com/>`_
+
+    Cypress
+    Cypress Technologies
+      `Cypress Technologies <http://cypress.com/>`_
+
+    Linear ASICs
+      `Linear ASICs <https://linearasics.com/>`_
+
+    Mentor
+    Mentor Graphics
+      `Mentor, a Siemens Business is a US-based electronic design automation (EDA) multinational corporation for electrical engineering and electronics. <https://en.wikipedia.org/wiki/Mentor_Graphics>`
+
+    OSU
+       Oklahoma State University
+
+.. Acronyms
+
+.. glossary::
+
+    sc
+    Standard Cell
+        The basic building blocks of digital circuit design.
+
+    ce
+        Memory Core
+
+    DRC
+    Design Rule Check
+    Design Rule Checking
+       Design rule checking or check(s) is the process of determing whether the
+       physical layout of a particular chip layout satisfies a series of
+       required parameters called design rules.
+
+    LVS
+    Layout Verse Schematic
+       Layout Versus Schematic (LVS) verification is the process of determining
+       whether a particular integrated circuit layout corresponds to the
+       original :ref:`schematic` or :ref:`circuit diagram` of the design.
+
+    PEX
+    Parasitic Extraction
+       Parasitic extraction is calculation of the parasitic effects in both the
+       designed devices and the required wiring interconnects of an electronic
+       circuit. This includes all parasitic components (often called parasitic
+       devices) including parasitic;
+
+        * capacitances,
+        * resistances, and
+        * inductances.
+
+    NLDM
+      Non-Linear Delay Model
+
+    CCS
+    ECSM
+      Current Source Models
+
+
+    CIF
+    Caltech Intermediate Form
+        From the 1990's, the CIF format has largely been replaced by the GDS
+        format.
+    MiM
+    MIM
+    MiM caps
+        Stands for "metal-insulator-metal" and is a type of IC capacitor
+        structure.
+
+        These are capacitors that are made between two metal route layers,
+        usually close to the top of the metal stack.
+
+        Generally they are around 1fF/um^2, a lot better than MoM caps.
+
+        The capacitance of MiM caps is on the top and bottom of the metal
+        (while the capacitance of MoM caps is sidewall cap).
+
+    MoM
+    MoM caps
+    VPP
+    VPP capacitor
+        Stands for "metal-oxide-metal" and is a type of IC capacitor structure.
+
+        These are capacitors which are made by interleaving fingers of metal.
+
+        Sometimes MoM caps are referred to as "VPP" capacitors (stands for
+        "vertical parallel plate").
+
+        The capacitance of MoM caps is capacitance of the metal sidewalls which
+        is significantly lower than that provided MiM caps.
+
+
+
+.. File formats
+
+.. glossary::
+
+    .lef
+    LEF
+    Library Exchange Format
+      Abstract description of the layout for place and route.
+
+    .lib
+    Liberty Models
+    Liberty Timing Models
+    Liberty Wire Load Models
+      Liberty Files are a IEEE Standard for defining: PVT Characterization,
+      Relating Input and Output Characteristics, Timing, Power, Noise.
+
+      Wire Load Models estimate the parasitics based on the fanout of a net.
+
+    CALMA
+    Calma
+    Calma Format
+      Calma was the company behind the development of GDS. 
+      https://en.wikipedia.org/wiki/Calma
+
+
+.. Tools
+
+.. glossary::
+
+    Mentor Calibre
+      The Calibre® product suite developed by :term:`Mentor Graphics`. Heavily
+      used for IC Verification and Signoff.
+
+    MAGIC
+      `MAGIC <http://opencircuitdesign.com/magic/>`_
+
+    ngspice
+      `ngspice <http://ngspice.sourceforge.net/>`_
+
+    OpenRoad
+      The digital design flow developed by
+      `The OpenRoad Project <https://theopenroadproject.org/>`_
+
+
+.. Terms specific to this documentation
+
+.. glossary::
+
+    s8phirs_10r
+    SkyWater S8
+    SkyWater SKY130 technology
+    SkyWater SKY130 process
+      The SkyWater SKY130 130nm process with 5 metal layers.
+
+    s8_osu130
+      The Oklahoma State University Digital Standard Cells.
+
+    s8_schd
+      The SkyWater High Density Digital Standard Cells.
+
+    license
+    Apache 2.0 license
+      The Apache 2.0 license.
diff --git a/docs/index.rst b/docs/index.rst
index 7e4cc70..1d30453 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -3,18 +3,28 @@
 .. toctree::
     :hidden:
 
-    Design Rules <rules>
-
-    contents
-
     versioning
     Current Status <status>
     known_issues
 
+    Design Rules <rules>
+
+    contents
+
+    analog
+    digital
+    sim
+    verification
+
+    Python API <python-api/index>
+
+    previous
+    glossary
+
     contributing
     partners
 
-    Python API <python-api/index>
+
 
 
 Welcome to SkyWater SKY130 PDK's documentation!
@@ -40,6 +50,7 @@
 Indices and tables
 ==================
 
+* :ref:`glossary`
 * :ref:`genindex`
 * :ref:`modindex`
 * :ref:`search`
diff --git a/docs/previous.rst b/docs/previous.rst
new file mode 100644
index 0000000..2c87fcb
--- /dev/null
+++ b/docs/previous.rst
@@ -0,0 +1,59 @@
+Previous Nomenclature
+=====================
+
+During the process of preparing the SkyWater SKY130 PDK for public release, consistency around naming, documentation and data cross checking was performed. This attempted to make sure that all references have been updated but despite the SkyWater PDK Author's best efforts, some references may have been missed.
+
+This section of the document include information about previous nomenclature around both the SkyWater PDK, related process and technologies developed both by Cypress Technology, SkyWater Technology and their partners.
+
+.. note::
+    If you find any references to these terms inside the current documentation,
+    please create an issue so we can update the documentation!
+
+This section should also help people who have previously had access (under NDA) to Cypress and SkyWater PDK files or older documentation and want to migrate to this new open source PDK.
+
+.. warning::
+    Despite this repository being released under an open source license, you
+    should **not** publish publically any Cypress or SkyWater IP you have been
+    given access to under NDA.
+
+    If the IP you are looking at includes references to terms found in this
+    Previous Nomenclature section, it is a good indication that the IP you have
+    can only be shared under appropriate NDAs and clearances you should **not**
+    be publically publishing it.
+
+
+.. glossary::
+
+    :lib_process:`s8`
+        The old Cypress and SkyWater name for the :lib_process:`SKY130`
+        process. It stood for the "8th generation" of the SONOS technology
+        developed originally by Cypress.
+
+    :lib_process:`s8phrc`
+    :lib_process:`s180`
+        The name for using 180nm technology on the 130nm process.
+
+
+    :lib_process:`s8phirs`
+
+    :lib_process:`s8pfhd`
+        The base process.  5 metal layer backend stack, 16V devices, deep
+        nwell.
+
+    :lib_process:`s8phirs`
+        The base process plus rdl layer and rdl metal inductors.
+
+    :lib_process:`s8phrc`
+        The base process plus dual MiM cap layers on metal 3 and metal 4
+
+    :lib_process:`s8pfn-20`
+        The base process plus UHV (ultra-high voltage) implants for 20V device
+        support.
+
+
+    :lib_name:`s8iom0s8`
+        An earlier name for the :lib:`sky130_fd_io` library.
+
+    :lib_name:`scs8hd`
+        An earlier name for the :lib:`sky130_fd_sc_hd` library.
+
diff --git a/docs/sim.rst b/docs/sim.rst
new file mode 100644
index 0000000..10891b2
--- /dev/null
+++ b/docs/sim.rst
@@ -0,0 +1,17 @@
+Simulation
+==========
+
+.. toctree::
+    :caption: Simulation
+    :name: sim
+
+    With Cadence Spectre <sim/spectre>
+    With ngspice <sim/ngspice>
+    With your design flow? <analog/new>
+
+.. todo::
+
+    The SkyWater SKY130 PDK provides simulation two types of simulation models.
+    :term:`Spectre models` for usage with :term:`Cadence Spectre` and
+    :term:`Spice models` which are compatible with popular open source spice
+    simulators like :term:`ngspice`.
diff --git a/docs/sim/ngspice.rst b/docs/sim/ngspice.rst
new file mode 100644
index 0000000..0136168
--- /dev/null
+++ b/docs/sim/ngspice.rst
@@ -0,0 +1,2 @@
+TODO: sim/ngspice
+=================
diff --git a/docs/sim/spectre.rst b/docs/sim/spectre.rst
new file mode 100644
index 0000000..5090786
--- /dev/null
+++ b/docs/sim/spectre.rst
@@ -0,0 +1,2 @@
+TODO: sim/spectre
+=================
diff --git a/docs/sim/spice.rst b/docs/sim/spice.rst
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/docs/sim/spice.rst
diff --git a/docs/verification.rst b/docs/verification.rst
new file mode 100644
index 0000000..8308157
--- /dev/null
+++ b/docs/verification.rst
@@ -0,0 +1,46 @@
+Physical & Design Verification
+==============================
+
+.. toctree::
+    :caption: Physical & Design Verification
+    :name: verification
+
+    Automated Design Rule (DRC) Checking <verification/drc>
+    - With Mentor Calibre
+    - With MAGIC
+    - With Klayout
+    Layout Versus Schematic (LVS) Checking <verification/lvs>
+    - With Mentor Calibre
+    - With netgen
+    Parasitic Extraction (PEX) <verification/pex>
+    - With Calibre xRC
+    - With MAGIC
+
+
+.. todo::
+    The SkyWater SKY130 PDK provides automated physical and design rule checking decks.
+
+    These verification rules provide;
+
+     * :term:`Design Rule Checking` (:term:`DRC`) against rules described in the
+       :ref:`SkyWater SKY130 Process Design Rules` documentation.
+
+       .. warning::
+
+           There are some design rules which can not be verified with these decks.
+           They are clearly marked in the :ref:`SkyWater SKY130 Process Design Rules`
+           documentation and should be manually verified by the designer.
+
+     * :term:`Layout Verse Schematic` (:term`LVS`) Verification
+     * :term:`Parasitic Extraction` (:term:`PEX`)
+
+TODO: Calibre Decks
+-------------------
+
+Put stuff here.
+
+TODO: MAGIC Decks
+-----------------
+
+Put stuff here.
+
diff --git a/docs/verification/drc.rst b/docs/verification/drc.rst
new file mode 100644
index 0000000..10f9b4a
--- /dev/null
+++ b/docs/verification/drc.rst
@@ -0,0 +1,8 @@
+Design Rule Verification
+========================
+
+.. toctree::
+
+    With Mentor Calibre <drc/calibre>
+    With Magic <drc/magic>
+    With KLayout <drc/klayout>
diff --git a/docs/verification/drc/calibre.rst b/docs/verification/drc/calibre.rst
new file mode 100644
index 0000000..6d9d555
--- /dev/null
+++ b/docs/verification/drc/calibre.rst
@@ -0,0 +1,2 @@
+TODO: verification/drc/calibre
+==============================
diff --git a/docs/verification/drc/klayout.rst b/docs/verification/drc/klayout.rst
new file mode 100644
index 0000000..0c5ac3d
--- /dev/null
+++ b/docs/verification/drc/klayout.rst
@@ -0,0 +1,2 @@
+TODO: verification/drc/klayout
+==============================
diff --git a/docs/verification/drc/magic.rst b/docs/verification/drc/magic.rst
new file mode 100644
index 0000000..838293e
--- /dev/null
+++ b/docs/verification/drc/magic.rst
@@ -0,0 +1,2 @@
+TODO: verification/drc/magic
+============================
diff --git a/docs/verification/lvs.rst b/docs/verification/lvs.rst
new file mode 100644
index 0000000..829f6c9
--- /dev/null
+++ b/docs/verification/lvs.rst
@@ -0,0 +1,8 @@
+Layout verse Schematic (LVS) Verification
+=========================================
+
+.. toctree::
+
+    With Mentor Calibre <lvs/calibre>
+    With Magic <lvs/magic>
+    With KLayout <lvs/klayout>
diff --git a/docs/verification/lvs/calibre.rst b/docs/verification/lvs/calibre.rst
new file mode 100644
index 0000000..0e71ef5
--- /dev/null
+++ b/docs/verification/lvs/calibre.rst
@@ -0,0 +1,2 @@
+TODO: verification/lvs/calibre
+==============================
diff --git a/docs/verification/lvs/klayout.rst b/docs/verification/lvs/klayout.rst
new file mode 100644
index 0000000..14a46a2
--- /dev/null
+++ b/docs/verification/lvs/klayout.rst
@@ -0,0 +1,2 @@
+TODO: verification/lvs/klayout
+==============================
diff --git a/docs/verification/lvs/magic.rst b/docs/verification/lvs/magic.rst
new file mode 100644
index 0000000..6de3819
--- /dev/null
+++ b/docs/verification/lvs/magic.rst
@@ -0,0 +1,2 @@
+TODO: verification/lvs/magic
+============================
diff --git a/docs/verification/pex.rst b/docs/verification/pex.rst
new file mode 100644
index 0000000..3260394
--- /dev/null
+++ b/docs/verification/pex.rst
@@ -0,0 +1,8 @@
+Parasitics Extraction (PEX)
+===========================
+
+.. toctree::
+
+    With Mentor Calibre <pex/calibre>
+    With Magic <pex/magic>
+    With KLayout <pex/klayout>
diff --git a/docs/verification/pex/calibre.rst b/docs/verification/pex/calibre.rst
new file mode 100644
index 0000000..17de3f6
--- /dev/null
+++ b/docs/verification/pex/calibre.rst
@@ -0,0 +1,2 @@
+TODO: verification/pex/calibre
+==============================
diff --git a/docs/verification/pex/klayout.rst b/docs/verification/pex/klayout.rst
new file mode 100644
index 0000000..f633ac7
--- /dev/null
+++ b/docs/verification/pex/klayout.rst
@@ -0,0 +1,2 @@
+TODO: verification/pex/klayout
+==============================
diff --git a/docs/verification/pex/magic.rst b/docs/verification/pex/magic.rst
new file mode 100644
index 0000000..d055a0d
--- /dev/null
+++ b/docs/verification/pex/magic.rst
@@ -0,0 +1,2 @@
+TODO: verification/pex/magic
+============================
diff --git a/libraries/sky130_fd_sc_hd/latest b/libraries/sky130_fd_sc_hd/latest
new file mode 160000
index 0000000..7f79525
--- /dev/null
+++ b/libraries/sky130_fd_sc_hd/latest
@@ -0,0 +1 @@
+Subproject commit 7f795252dcbf6909aea6bd5eb9c5ea98b2ae7a74
diff --git a/libraries/sky130_fd_sc_hd/v0.0.1 b/libraries/sky130_fd_sc_hd/v0.0.1
new file mode 160000
index 0000000..4cbecdc
--- /dev/null
+++ b/libraries/sky130_fd_sc_hd/v0.0.1
@@ -0,0 +1 @@
+Subproject commit 4cbecdca96976da7730fa1141910b8995dc70346
diff --git a/libraries/sky130_fd_sc_hd/v0.0.2 b/libraries/sky130_fd_sc_hd/v0.0.2
new file mode 160000
index 0000000..7f79525
--- /dev/null
+++ b/libraries/sky130_fd_sc_hd/v0.0.2
@@ -0,0 +1 @@
+Subproject commit 7f795252dcbf6909aea6bd5eb9c5ea98b2ae7a74
diff --git a/libraries/sky130_fd_sc_hdll/latest b/libraries/sky130_fd_sc_hdll/latest
new file mode 160000
index 0000000..c4512ed
--- /dev/null
+++ b/libraries/sky130_fd_sc_hdll/latest
@@ -0,0 +1 @@
+Subproject commit c4512ed05f2211985f984c12ecfa819604af9318
diff --git a/libraries/sky130_fd_sc_hdll/v0.1.0 b/libraries/sky130_fd_sc_hdll/v0.1.0
new file mode 160000
index 0000000..60697a7
--- /dev/null
+++ b/libraries/sky130_fd_sc_hdll/v0.1.0
@@ -0,0 +1 @@
+Subproject commit 60697a72b40969b7818cae0efb79b66e2cd93e74
diff --git a/libraries/sky130_fd_sc_hdll/v0.1.1 b/libraries/sky130_fd_sc_hdll/v0.1.1
new file mode 160000
index 0000000..c4512ed
--- /dev/null
+++ b/libraries/sky130_fd_sc_hdll/v0.1.1
@@ -0,0 +1 @@
+Subproject commit c4512ed05f2211985f984c12ecfa819604af9318
diff --git a/libraries/sky130_fd_sc_hs/latest b/libraries/sky130_fd_sc_hs/latest
new file mode 160000
index 0000000..8bc807e
--- /dev/null
+++ b/libraries/sky130_fd_sc_hs/latest
@@ -0,0 +1 @@
+Subproject commit 8bc807e704409ec72223e1e7b9462ea9dd81e5a3
diff --git a/libraries/sky130_fd_sc_hs/v0.0.1 b/libraries/sky130_fd_sc_hs/v0.0.1
new file mode 160000
index 0000000..73908d9
--- /dev/null
+++ b/libraries/sky130_fd_sc_hs/v0.0.1
@@ -0,0 +1 @@
+Subproject commit 73908d9138e521567132102472622e5fc534fe0d
diff --git a/libraries/sky130_fd_sc_hs/v0.0.2 b/libraries/sky130_fd_sc_hs/v0.0.2
new file mode 160000
index 0000000..8bc807e
--- /dev/null
+++ b/libraries/sky130_fd_sc_hs/v0.0.2
@@ -0,0 +1 @@
+Subproject commit 8bc807e704409ec72223e1e7b9462ea9dd81e5a3
diff --git a/libraries/sky130_fd_sc_ls/latest b/libraries/sky130_fd_sc_ls/latest
new file mode 160000
index 0000000..b8d4fa7
--- /dev/null
+++ b/libraries/sky130_fd_sc_ls/latest
@@ -0,0 +1 @@
+Subproject commit b8d4fa73fb356364f01439adf6fae5d0187a4094
diff --git a/libraries/sky130_fd_sc_ls/v0.1.0 b/libraries/sky130_fd_sc_ls/v0.1.0
new file mode 160000
index 0000000..06ffd21
--- /dev/null
+++ b/libraries/sky130_fd_sc_ls/v0.1.0
@@ -0,0 +1 @@
+Subproject commit 06ffd21614b39f9d1a6b100e29f6813fcd01ed75
diff --git a/libraries/sky130_fd_sc_ls/v0.1.1 b/libraries/sky130_fd_sc_ls/v0.1.1
new file mode 160000
index 0000000..b8d4fa7
--- /dev/null
+++ b/libraries/sky130_fd_sc_ls/v0.1.1
@@ -0,0 +1 @@
+Subproject commit b8d4fa73fb356364f01439adf6fae5d0187a4094
diff --git a/libraries/sky130_fd_sc_ms/latest b/libraries/sky130_fd_sc_ms/latest
deleted file mode 120000
index 5eb312c..0000000
--- a/libraries/sky130_fd_sc_ms/latest
+++ /dev/null
@@ -1 +0,0 @@
-v0.0.0
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/latest b/libraries/sky130_fd_sc_ms/latest
new file mode 160000
index 0000000..7ef2bc9
--- /dev/null
+++ b/libraries/sky130_fd_sc_ms/latest
@@ -0,0 +1 @@
+Subproject commit 7ef2bc933dd3dba52b1a3abbc741e5130ae034d3
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/README.rst b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/README.rst
deleted file mode 100644
index bd52d32..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/README.rst
+++ /dev/null
@@ -1,33 +0,0 @@
-
-:cell_name:`sky130_fd_sc_ms__xor3`
-==================================
-
-.. list-table::
-   :header-rows: 1
-   :widths: 50 50
-
-   * - Without Power Pins
-     - With Power Pins
-
-   * -
-       .. no-license:: sky130_fd_sc_ms__xor3.blackbox.v
-          :language: verilog
-          :linenos:
-
-     -
-       .. no-license:: sky130_fd_sc_ms__xor3.pp.blackbox.v
-          :language: verilog
-          :linenos:
-
-   * -
-       .. image:: sky130_fd_sc_ms__xor3.symbol.svg
-     -
-       .. image:: sky130_fd_sc_ms__xor3.pp.symbol.svg
-
-   * - .. image:: sky130_fd_sc_ms__xor3.schematic.svg
-     - .. image:: sky130_fd_sc_ms__xor3.pp.schematic.svg
-
-   * - .. image:: sky130_fd_sc_ms__xor3.schematic.svg
-     - .. image:: sky130_fd_sc_ms__xor3.pp.schematic.svg
-
-
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.behavioral.pp.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.behavioral.pp.v
deleted file mode 100644
index 6b47ebb..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.behavioral.pp.v
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
-*/
-
-
-`ifndef SKY130_FD_SC_MS__XOR3_BEHAVIORAL_PP_V
-`define SKY130_FD_SC_MS__XOR3_BEHAVIORAL_PP_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog simulation functional model.
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-// Import user defined primitives.
-`include "../../models/udp_pwrgood_pp_pg/sky130_fd_sc_ms__udp_pwrgood_pp_pg.v"
-
-`celldefine
-module sky130_fd_sc_ms__xor3 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    // Module ports
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-
-    // Local signals
-    wire xor0_out_X       ;
-    wire pwrgood_pp0_out_X;
-
-    //                                 Name         Output             Other arguments
-    xor                                xor0        (xor0_out_X       , A, B, C               );
-    sky130_fd_sc_ms__udp_pwrgood_pp$PG pwrgood_pp0 (pwrgood_pp0_out_X, xor0_out_X, VPWR, VGND);
-    buf                                buf0        (X                , pwrgood_pp0_out_X     );
-
-endmodule
-`endcelldefine
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_BEHAVIORAL_PP_V
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.behavioral.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.behavioral.v
deleted file mode 100644
index 92d45e1..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.behavioral.v
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
-*/
-
-
-`ifndef SKY130_FD_SC_MS__XOR3_BEHAVIORAL_V
-`define SKY130_FD_SC_MS__XOR3_BEHAVIORAL_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog simulation functional model.
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-`celldefine
-module sky130_fd_sc_ms__xor3 (
-    X,
-    A,
-    B,
-    C
-);
-
-    // Module ports
-    output X;
-    input  A;
-    input  B;
-    input  C;
-
-    // Module supplies
-    supply1 VPWR;
-    supply0 VGND;
-    supply1 VPB ;
-    supply0 VNB ;
-
-    // Local signals
-    wire xor0_out_X;
-
-    //  Name  Output      Other arguments
-    xor xor0 (xor0_out_X, A, B, C        );
-    buf buf0 (X         , xor0_out_X     );
-
-endmodule
-`endcelldefine
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_BEHAVIORAL_V
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.blackbox.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.blackbox.v
deleted file mode 100644
index b198396..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.blackbox.v
+++ /dev/null
@@ -1,57 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_BLACKBOX_V
-`define SKY130_FD_SC_MS__XOR3_BLACKBOX_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog stub definition (black box without power pins).
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-(* blackbox *)
-module sky130_fd_sc_ms__xor3 (
-    X,
-    A,
-    B,
-    C
-);
-
-    output X;
-    input  A;
-    input  B;
-    input  C;
-
-    // Voltage supply signals
-    supply1 VPWR;
-    supply0 VGND;
-    supply1 VPB ;
-    supply0 VNB ;
-
-endmodule
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_BLACKBOX_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.functional.pp.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.functional.pp.v
deleted file mode 100644
index 4a2b9ef..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.functional.pp.v
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
-*/
-
-
-`ifndef SKY130_FD_SC_MS__XOR3_FUNCTIONAL_PP_V
-`define SKY130_FD_SC_MS__XOR3_FUNCTIONAL_PP_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog simulation functional model.
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-// Import user defined primitives.
-`include "../../models/udp_pwrgood_pp_pg/sky130_fd_sc_ms__udp_pwrgood_pp_pg.v"
-
-`celldefine
-module sky130_fd_sc_ms__xor3 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    // Module ports
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-
-    // Local signals
-    wire xor0_out_X       ;
-    wire pwrgood_pp0_out_X;
-
-    //                                 Name         Output             Other arguments
-    xor                                xor0        (xor0_out_X       , A, B, C               );
-    sky130_fd_sc_ms__udp_pwrgood_pp$PG pwrgood_pp0 (pwrgood_pp0_out_X, xor0_out_X, VPWR, VGND);
-    buf                                buf0        (X                , pwrgood_pp0_out_X     );
-
-endmodule
-`endcelldefine
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_FUNCTIONAL_PP_V
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.functional.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.functional.v
deleted file mode 100644
index 0f3372a..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.functional.v
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
-*/
-
-
-`ifndef SKY130_FD_SC_MS__XOR3_FUNCTIONAL_V
-`define SKY130_FD_SC_MS__XOR3_FUNCTIONAL_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog simulation functional model.
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-`celldefine
-module sky130_fd_sc_ms__xor3 (
-    X,
-    A,
-    B,
-    C
-);
-
-    // Module ports
-    output X;
-    input  A;
-    input  B;
-    input  C;
-
-    // Local signals
-    wire xor0_out_X;
-
-    //  Name  Output      Other arguments
-    xor xor0 (xor0_out_X, A, B, C        );
-    buf buf0 (X         , xor0_out_X     );
-
-endmodule
-`endcelldefine
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_FUNCTIONAL_V
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.blackbox.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.blackbox.v
deleted file mode 100644
index c964bb8..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.blackbox.v
+++ /dev/null
@@ -1,58 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_PP_BLACKBOX_V
-`define SKY130_FD_SC_MS__XOR3_PP_BLACKBOX_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog stub definition (black box with power pins).
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-(* blackbox *)
-module sky130_fd_sc_ms__xor3 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-endmodule
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_PP_BLACKBOX_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.symbol.svg b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.symbol.svg
deleted file mode 100644
index c69dc71..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.symbol.svg
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created by Symbolator http://kevinpt.github.io/symbolator -->
-<svg xmlns="http://www.w3.org/2000/svg"
-xmlns:xlink="http://www.w3.org/1999/xlink"
-xml:space="preserve"
-width="191" height="295" viewBox="-25 -56 191.0 295.0" version="1.1">
-<style type="text/css">
-<![CDATA[
-.fnt1 { fill:#000000; font-family:Times; font-size:12pt; font-weight:normal; font-style:italic; }
-.fnt2 { fill:#000000; font-family:Helvetica; font-size:12pt; font-weight:normal; font-style:normal; }
-.fnt3 { fill:#000000; font-family:Helvetica; font-size:16pt; font-weight:bold; font-style:normal; }
-.fnt4 { fill:#000000; font-family:Helvetica; font-size:10pt; font-style:normal; }
-.label {fill:#000;
-  text-anchor:middle;
-  font-size:16pt; font-weight:bold; font-family:Sans;}
-.link {fill: #0D47A1;}
-.link:hover {fill: #0D47A1; text-decoration:underline;}
-.link:visited {fill: #4A148C;}
-]]>
-</style>
-<defs>
-
-</defs>
-<rect x="-25" y="-56" width="100%" height="100%" fill="white"/><g transform="translate(0,0)">
-<rect x="0" y="-21.0" width="140" height="105.0" stroke="#000000" fill="#CCFED2" stroke-width="1"/>
-<text class="fnt1" x="70.0" y="-5.0" text-anchor="middle" dy="5.5">Data Signals</text>
-<g transform="translate(0,19)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">A</text>
-</g>
-<g transform="translate(0,41)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">B</text>
-</g>
-<g transform="translate(0,63)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">C</text>
-</g>
-<g transform="translate(140,19)">
-<line x1="20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="-10" y="0" text-anchor="end" dy="5.5">X</text>
-</g>
-</g>
-<g transform="translate(0,105.0)">
-<rect x="0" y="-21.0" width="140" height="127.0" stroke="#000000" fill="#FFBBBB" stroke-width="1"/>
-<text class="fnt1" x="70.0" y="-5.0" text-anchor="middle" dy="5.5">Power</text>
-<g transform="translate(0,19)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">VPB</text>
-</g>
-<g transform="translate(0,41)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">VPWR</text>
-</g>
-<g transform="translate(0,63)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">VGND</text>
-</g>
-<g transform="translate(0,85)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">VNB</text>
-</g>
-</g>
-<rect x="1.0" y="-20.0" width="138.0" height="230.0" stroke="#000000" fill="none" stroke-width="3"/>
-<text class="fnt3" x="70.0" y="-30.0" text-anchor="middle" dy="-1.0">xor3</text>
-<text class="fnt4" x="70.0" y="230.0" text-anchor="middle" dy="1.0">sky130_fd_sc_ms</text>
-</svg>
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.symbol.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.symbol.v
deleted file mode 100644
index 1473fef..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.pp.symbol.v
+++ /dev/null
@@ -1,53 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_PP_SYMBOL_V
-`define SKY130_FD_SC_MS__XOR3_PP_SYMBOL_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog stub (with power pins) for graphical symbol definition
- * generation.
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-(* blackbox *)
-module sky130_fd_sc_ms__xor3 (
-    //# {{data|Data Signals}}
-    input  A   ,
-    input  B   ,
-    input  C   ,
-    output X   ,
-
-    //# {{power|Power}}
-    input  VPB ,
-    input  VPWR,
-    input  VGND,
-    input  VNB
-);
-endmodule
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_PP_SYMBOL_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.schematic.svg b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.schematic.svg
deleted file mode 100644
index 73ff300..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.schematic.svg
+++ /dev/null
@@ -1,75 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:s="https://github.com/nturley/netlistsvg" width="255" height="129">
-  <style>svg {
-    stroke:#000;
-    fill:none;
-  }
-  text {
-    fill:#000;
-    stroke:none;
-    font-size:10px;
-    font-weight: bold;
-    font-family: "Courier New", monospace;
-  }
-  .nodelabel {
-    text-anchor: middle;
-  }
-  .inputPortLabel {
-    text-anchor: end;
-  }
-  .splitjoinBody {
-    fill:#000;
-  }</style>
-  <g s:type="reduce_xor" transform="translate(77,27)" s:width="33" s:height="25" id="cell_$xor$../skywater-pdk-scratch-new/skywater-pdk/libraries/sky130_fd_sc_ms/v0.0.1/cells/xor3/sky130_fd_sc_ms__xor3.functional.v:52$1">
-    <s:alias val="$xor"/>
-    <s:alias val="$reduce_xor"/>
-    <s:alias val="$_XOR_"/>
-    <path d="M3,0 A30 25 0 0 1 3,25 A30 25 0 0 0 33,12.5 A30 25 0 0 0 3,0" class="cell_$xor$../skywater-pdk-scratch-new/skywater-pdk/libraries/sky130_fd_sc_ms/v0.0.1/cells/xor3/sky130_fd_sc_ms__xor3.functional.v:52$1"/>
-    <path d="M0,0 A30 25 0 0 1 0,25" class="cell_$xor$../skywater-pdk-scratch-new/skywater-pdk/libraries/sky130_fd_sc_ms/v0.0.1/cells/xor3/sky130_fd_sc_ms__xor3.functional.v:52$1"/>
-    <g s:x="3" s:y="5" s:pid="A"/>
-    <g s:x="3" s:y="20" s:pid="B"/>
-    <g s:x="33" s:y="12.5" s:pid="Y"/>
-  </g>
-  <g s:type="reduce_xor" transform="translate(145,34.5)" s:width="33" s:height="25" id="cell_$xor$../skywater-pdk-scratch-new/skywater-pdk/libraries/sky130_fd_sc_ms/v0.0.1/cells/xor3/sky130_fd_sc_ms__xor3.functional.v:52$2">
-    <s:alias val="$xor"/>
-    <s:alias val="$reduce_xor"/>
-    <s:alias val="$_XOR_"/>
-    <path d="M3,0 A30 25 0 0 1 3,25 A30 25 0 0 0 33,12.5 A30 25 0 0 0 3,0" class="cell_$xor$../skywater-pdk-scratch-new/skywater-pdk/libraries/sky130_fd_sc_ms/v0.0.1/cells/xor3/sky130_fd_sc_ms__xor3.functional.v:52$2"/>
-    <path d="M0,0 A30 25 0 0 1 0,25" class="cell_$xor$../skywater-pdk-scratch-new/skywater-pdk/libraries/sky130_fd_sc_ms/v0.0.1/cells/xor3/sky130_fd_sc_ms__xor3.functional.v:52$2"/>
-    <g s:x="3" s:y="5" s:pid="A"/>
-    <g s:x="3" s:y="20" s:pid="B"/>
-    <g s:x="33" s:y="12.5" s:pid="Y"/>
-  </g>
-  <g s:type="outputExt" transform="translate(213,37)" s:width="30" s:height="20" id="cell_X">
-    <text x="15" y="-4" class="nodelabel cell_X" s:attribute="ref">X</text>
-    <s:alias val="$_outputExt_"/>
-    <path d="M30,0 L30,20 L15,20 L0,10 L15,0 Z" class="cell_X"/>
-    <g s:x="0" s:y="10" s:pid="A"/>
-  </g>
-  <g s:type="inputExt" transform="translate(12,22)" s:width="30" s:height="20" id="cell_A">
-    <text x="15" y="-4" class="nodelabel cell_A" s:attribute="ref">A</text>
-    <s:alias val="$_inputExt_"/>
-    <path d="M0,0 L0,20 L15,20 L30,10 L15,0 Z" class="cell_A"/>
-    <g s:x="28" s:y="10" s:pid="Y"/>
-  </g>
-  <g s:type="inputExt" transform="translate(12,87)" s:width="30" s:height="20" id="cell_B">
-    <text x="15" y="-4" class="nodelabel cell_B" s:attribute="ref">B</text>
-    <s:alias val="$_inputExt_"/>
-    <path d="M0,0 L0,20 L15,20 L30,10 L15,0 Z" class="cell_B"/>
-    <g s:x="28" s:y="10" s:pid="Y"/>
-  </g>
-  <g s:type="inputExt" transform="translate(80,97)" s:width="30" s:height="20" id="cell_C">
-    <text x="15" y="-4" class="nodelabel cell_C" s:attribute="ref">C</text>
-    <s:alias val="$_inputExt_"/>
-    <path d="M0,0 L0,20 L15,20 L30,10 L15,0 Z" class="cell_C"/>
-    <g s:x="28" s:y="10" s:pid="Y"/>
-  </g>
-  <line x1="40" x2="80" y1="32" y2="32" class="net_3"/>
-  <line x1="40" x2="52" y1="97" y2="97" class="net_4"/>
-  <line x1="52" x2="52" y1="97" y2="47" class="net_4"/>
-  <line x1="52" x2="80" y1="47" y2="47" class="net_4"/>
-  <line x1="110" x2="148" y1="39.5" y2="39.5" class="net_6"/>
-  <line x1="108" x2="120" y1="107" y2="107" class="net_5"/>
-  <line x1="120" x2="120" y1="107" y2="54.5" class="net_5"/>
-  <line x1="120" x2="148" y1="54.5" y2="54.5" class="net_5"/>
-  <line x1="178" x2="213" y1="47" y2="47" class="net_2"/>
-</svg>
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.specify.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.specify.v
deleted file mode 100644
index 4d2849c..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.specify.v
+++ /dev/null
@@ -1,32 +0,0 @@
-/*
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
-*/
-
-specify
-if ((!B&!C)) (A +=> X) = (0:0:0,0:0:0);
-if ((!B&C)) (A -=> X) = (0:0:0,0:0:0);
-if ((B&!C)) (A -=> X) = (0:0:0,0:0:0);
-if ((B&C)) (A +=> X) = (0:0:0,0:0:0);
-if ((!A&!C)) (B +=> X) = (0:0:0,0:0:0);
-if ((!A&C)) (B -=> X) = (0:0:0,0:0:0);
-if ((A&!C)) (B -=> X) = (0:0:0,0:0:0);
-if ((A&C)) (B +=> X) = (0:0:0,0:0:0);
-if ((!A&!B)) (C +=> X) = (0:0:0,0:0:0);
-if ((!A&B)) (C -=> X) = (0:0:0,0:0:0);
-if ((A&!B)) (C -=> X) = (0:0:0,0:0:0);
-if ((A&B)) (C +=> X) = (0:0:0,0:0:0);
-endspecify
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.symbol.svg b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.symbol.svg
deleted file mode 100644
index ec8a1bd..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.symbol.svg
+++ /dev/null
@@ -1,47 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" standalone="no"?>
-<!-- Created by Symbolator http://kevinpt.github.io/symbolator -->
-<svg xmlns="http://www.w3.org/2000/svg"
-xmlns:xlink="http://www.w3.org/1999/xlink"
-xml:space="preserve"
-width="191" height="168" viewBox="-25 -56 191.0 168.0" version="1.1">
-<style type="text/css">
-<![CDATA[
-.fnt1 { fill:#000000; font-family:Times; font-size:12pt; font-weight:normal; font-style:italic; }
-.fnt2 { fill:#000000; font-family:Helvetica; font-size:12pt; font-weight:normal; font-style:normal; }
-.fnt3 { fill:#000000; font-family:Helvetica; font-size:16pt; font-weight:bold; font-style:normal; }
-.fnt4 { fill:#000000; font-family:Helvetica; font-size:10pt; font-style:normal; }
-.label {fill:#000;
-  text-anchor:middle;
-  font-size:16pt; font-weight:bold; font-family:Sans;}
-.link {fill: #0D47A1;}
-.link:hover {fill: #0D47A1; text-decoration:underline;}
-.link:visited {fill: #4A148C;}
-]]>
-</style>
-<defs>
-
-</defs>
-<rect x="-25" y="-56" width="100%" height="100%" fill="white"/><g transform="translate(0,0)">
-<rect x="0" y="-21.0" width="140" height="105.0" stroke="#000000" fill="#CCFED2" stroke-width="1"/>
-<text class="fnt1" x="70.0" y="-5.0" text-anchor="middle" dy="5.5">Data Signals</text>
-<g transform="translate(0,19)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">A</text>
-</g>
-<g transform="translate(0,41)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">B</text>
-</g>
-<g transform="translate(0,63)">
-<line x1="-20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="10" y="0" text-anchor="normal" dy="5.5">C</text>
-</g>
-<g transform="translate(140,19)">
-<line x1="20" y1="0" x2="0" y2="0" stroke="#000000" fill="none" stroke-width="1"/>
-<text class="fnt2" x="-10" y="0" text-anchor="end" dy="5.5">X</text>
-</g>
-</g>
-<rect x="1.0" y="-20.0" width="138.0" height="103.0" stroke="#000000" fill="none" stroke-width="3"/>
-<text class="fnt3" x="70.0" y="-30.0" text-anchor="middle" dy="-1.0">xor3</text>
-<text class="fnt4" x="70.0" y="103.0" text-anchor="middle" dy="1.0">sky130_fd_sc_ms</text>
-</svg>
\ No newline at end of file
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.symbol.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.symbol.v
deleted file mode 100644
index 7abe57e..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.symbol.v
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_SYMBOL_V
-`define SKY130_FD_SC_MS__XOR3_SYMBOL_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog stub (without power pins) for graphical symbol definition
- * generation.
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-(* blackbox *)
-module sky130_fd_sc_ms__xor3 (
-    //# {{data|Data Signals}}
-    input  A,
-    input  B,
-    input  C,
-    output X
-);
-
-    // Voltage supply signals
-    supply1 VPWR;
-    supply0 VGND;
-    supply1 VPB ;
-    supply0 VNB ;
-
-endmodule
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_SYMBOL_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.tb.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.tb.v
deleted file mode 100644
index 645ffed..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.tb.v
+++ /dev/null
@@ -1,104 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_TB_V
-`define SKY130_FD_SC_MS__XOR3_TB_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Autogenerated test bench.
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-`include "sky130_fd_sc_ms__xor3.v"
-
-module top();
-
-    // Inputs are registered
-    reg A;
-    reg B;
-    reg C;
-    reg VPWR;
-    reg VGND;
-    reg VPB;
-    reg VNB;
-
-    // Outputs are wires
-    wire X;
-
-    initial
-    begin
-        // Initial state is x for all inputs.
-        A    = 1'bX;
-        B    = 1'bX;
-        C    = 1'bX;
-        VGND = 1'bX;
-        VNB  = 1'bX;
-        VPB  = 1'bX;
-        VPWR = 1'bX;
-
-        #20   A    = 1'b0;
-        #40   B    = 1'b0;
-        #60   C    = 1'b0;
-        #80   VGND = 1'b0;
-        #100  VNB  = 1'b0;
-        #120  VPB  = 1'b0;
-        #140  VPWR = 1'b0;
-        #160  A    = 1'b1;
-        #180  B    = 1'b1;
-        #200  C    = 1'b1;
-        #220  VGND = 1'b1;
-        #240  VNB  = 1'b1;
-        #260  VPB  = 1'b1;
-        #280  VPWR = 1'b1;
-        #300  A    = 1'b0;
-        #320  B    = 1'b0;
-        #340  C    = 1'b0;
-        #360  VGND = 1'b0;
-        #380  VNB  = 1'b0;
-        #400  VPB  = 1'b0;
-        #420  VPWR = 1'b0;
-        #440  VPWR = 1'b1;
-        #460  VPB  = 1'b1;
-        #480  VNB  = 1'b1;
-        #500  VGND = 1'b1;
-        #520  C    = 1'b1;
-        #540  B    = 1'b1;
-        #560  A    = 1'b1;
-        #580  VPWR = 1'bx;
-        #600  VPB  = 1'bx;
-        #620  VNB  = 1'bx;
-        #640  VGND = 1'bx;
-        #660  C    = 1'bx;
-        #680  B    = 1'bx;
-        #700  A    = 1'bx;
-    end
-
-    sky130_fd_sc_ms__xor3 dut (.A(A), .B(B), .C(C), .VPWR(VPWR), .VGND(VGND), .VPB(VPB), .VNB(VNB), .X(X));
-
-endmodule
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_TB_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.v
deleted file mode 100644
index 7383dd3..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3.v
+++ /dev/null
@@ -1,54 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_V
-`define SKY130_FD_SC_MS__XOR3_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog top module.
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-`ifdef USE_POWER_PINS
-
-`ifdef FUNCTIONAL
-`include "sky130_fd_sc_ms__xor3.pp.functional.v"
-`else  // FUNCTIONAL
-`include "sky130_fd_sc_ms__xor3.pp.behavioral.v"
-`endif // FUNCTIONAL
-
-`else  // USE_POWER_PINS
-
-`ifdef FUNCTIONAL
-`include "sky130_fd_sc_ms__xor3.functional.v"
-`else  // FUNCTIONAL
-`include "sky130_fd_sc_ms__xor3.behavioral.v"
-`endif // FUNCTIONAL
-
-`endif // USE_POWER_PINS
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_1.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_1.v
deleted file mode 100644
index 92c4a80..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_1.v
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_1_V
-`define SKY130_FD_SC_MS__XOR3_1_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog wrapper for xor3 with size of 1 units.
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-`include "sky130_fd_sc_ms__xor3.v"
-
-`ifdef USE_POWER_PINS
-/*********************************************************/
-
-`celldefine
-module sky130_fd_sc_ms__xor3_1 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-    sky130_fd_sc_ms__xor3 cell (
-        .X(X),
-        .A(A),
-        .B(B),
-        .C(C),
-        .VPWR(VPWR),
-        .VGND(VGND),
-        .VPB(VPB),
-        .VNB(VNB)
-    );
-
-endmodule
-`endcelldefine
-
-/*********************************************************/
-`else // If not USE_POWER_PINS
-/*********************************************************/
-
-`celldefine
-module sky130_fd_sc_ms__xor3_1 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-
-    // Voltage supply signals
-    supply1 VPWR;
-    supply0 VGND;
-    supply1 VPB ;
-    supply0 VNB ;
-
-    sky130_fd_sc_ms__xor3 cell (
-        .X(X),
-        .A(A),
-        .B(B),
-        .C(C)
-    );
-
-endmodule
-`endcelldefine
-
-/*********************************************************/
-`endif // USE_POWER_PINS
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_1_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_2.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_2.v
deleted file mode 100644
index 675d438..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_2.v
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_2_V
-`define SKY130_FD_SC_MS__XOR3_2_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog wrapper for xor3 with size of 2 units.
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-`include "sky130_fd_sc_ms__xor3.v"
-
-`ifdef USE_POWER_PINS
-/*********************************************************/
-
-`celldefine
-module sky130_fd_sc_ms__xor3_2 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-    sky130_fd_sc_ms__xor3 cell (
-        .X(X),
-        .A(A),
-        .B(B),
-        .C(C),
-        .VPWR(VPWR),
-        .VGND(VGND),
-        .VPB(VPB),
-        .VNB(VNB)
-    );
-
-endmodule
-`endcelldefine
-
-/*********************************************************/
-`else // If not USE_POWER_PINS
-/*********************************************************/
-
-`celldefine
-module sky130_fd_sc_ms__xor3_2 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-
-    // Voltage supply signals
-    supply1 VPWR;
-    supply0 VGND;
-    supply1 VPB ;
-    supply0 VNB ;
-
-    sky130_fd_sc_ms__xor3 cell (
-        .X(X),
-        .A(A),
-        .B(B),
-        .C(C)
-    );
-
-endmodule
-`endcelldefine
-
-/*********************************************************/
-`endif // USE_POWER_PINS
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_2_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_4.v b/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_4.v
deleted file mode 100644
index 0e9db33..0000000
--- a/libraries/sky130_fd_sc_ms/v0.0.0/cells/xor3/sky130_fd_sc_ms__xor3_4.v
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * Copyright 2020 The SkyWater PDK Authors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     https://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * SPDX-License-Identifier: Apache-2.0
- */
-
-`ifndef SKY130_FD_SC_MS__XOR3_4_V
-`define SKY130_FD_SC_MS__XOR3_4_V
-
-/**
- * xor3: 3-input exclusive OR.
- *
- *       X = A ^ B ^ C
- *
- * Verilog wrapper for xor3 with size of 4 units.
- *
- * WARNING: This file is autogenerated, do not modify directly!
- */
-
-`timescale 1ns / 1ps
-`default_nettype none
-
-`include "sky130_fd_sc_ms__xor3.v"
-
-`ifdef USE_POWER_PINS
-/*********************************************************/
-
-`celldefine
-module sky130_fd_sc_ms__xor3_4 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-    sky130_fd_sc_ms__xor3 cell (
-        .X(X),
-        .A(A),
-        .B(B),
-        .C(C),
-        .VPWR(VPWR),
-        .VGND(VGND),
-        .VPB(VPB),
-        .VNB(VNB)
-    );
-
-endmodule
-`endcelldefine
-
-/*********************************************************/
-`else // If not USE_POWER_PINS
-/*********************************************************/
-
-`celldefine
-module sky130_fd_sc_ms__xor3_4 (
-    X   ,
-    A   ,
-    B   ,
-    C   ,
-    VPWR,
-    VGND,
-    VPB ,
-    VNB
-);
-
-    output X   ;
-    input  A   ;
-    input  B   ;
-    input  C   ;
-    input  VPWR;
-    input  VGND;
-    input  VPB ;
-    input  VNB ;
-
-    // Voltage supply signals
-    supply1 VPWR;
-    supply0 VGND;
-    supply1 VPB ;
-    supply0 VNB ;
-
-    sky130_fd_sc_ms__xor3 cell (
-        .X(X),
-        .A(A),
-        .B(B),
-        .C(C)
-    );
-
-endmodule
-`endcelldefine
-
-/*********************************************************/
-`endif // USE_POWER_PINS
-
-`default_nettype wire
-`endif  // SKY130_FD_SC_MS__XOR3_4_V
diff --git a/libraries/sky130_fd_sc_ms/v0.0.1 b/libraries/sky130_fd_sc_ms/v0.0.1
new file mode 160000
index 0000000..5825c0b
--- /dev/null
+++ b/libraries/sky130_fd_sc_ms/v0.0.1
@@ -0,0 +1 @@
+Subproject commit 5825c0bd2c1b5156b7a3f671b94d2ebeacbb43e3
diff --git a/libraries/sky130_fd_sc_ms/v0.0.2 b/libraries/sky130_fd_sc_ms/v0.0.2
new file mode 160000
index 0000000..7ef2bc9
--- /dev/null
+++ b/libraries/sky130_fd_sc_ms/v0.0.2
@@ -0,0 +1 @@
+Subproject commit 7ef2bc933dd3dba52b1a3abbc741e5130ae034d3
diff --git a/scripts/python-skywater-pdk/docs/skywater_pdk.rst b/scripts/python-skywater-pdk/docs/skywater_pdk.rst
index 8488d1e..0e832dd 100644
--- a/scripts/python-skywater-pdk/docs/skywater_pdk.rst
+++ b/scripts/python-skywater-pdk/docs/skywater_pdk.rst
@@ -12,6 +12,14 @@
    :undoc-members:
    :show-inheritance:
 
+skywater\_pdk.corners module
+----------------------------
+
+.. automodule:: skywater_pdk.corners
+   :members:
+   :undoc-members:
+   :show-inheritance:
+
 skywater\_pdk.sizes module
 ---------------------------
 
diff --git a/scripts/python-skywater-pdk/skywater_pdk/corners.py b/scripts/python-skywater-pdk/skywater_pdk/corners.py
new file mode 100644
index 0000000..6e212a1
--- /dev/null
+++ b/scripts/python-skywater-pdk/skywater_pdk/corners.py
@@ -0,0 +1,292 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020 SkyWater PDK Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import re
+import os
+
+from enum import Flag
+from dataclasses import dataclass
+from dataclasses_json import dataclass_json
+from typing import Tuple, Optional
+
+from . import base
+from .utils import OrderedFlag
+from .utils import comparable_to_none
+from .utils import dataclass_json_passthru_sequence_config as dj_pass_cfg
+
+
+CornerTypeMappings = {}
+# "wo" is "worst-case one" and corresponds to "fs"
+CornerTypeMappings["wo"] = "fs"
+# "wz" is "worst-case zero" and corresponds to "sf"
+CornerTypeMappings["wz"] = "sf"
+# "wp" is "worst-case power" and corresponds to "ff"
+CornerTypeMappings["wp"] = "ff"
+# "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):
+    """
+
+    See Also
+    --------
+    skywater_pdk.corners.Corner
+    skywater_pdk.corners.CornerFlag
+
+    Examples
+    --------
+
+    >>> CornerType.parse('t')
+    CornerType.t
+    >>> CornerType.parse('tt')
+    [CornerType.t, CornerType.t]
+    >>> CornerType.parse('wp')
+    [CornerType.f, CornerType.f]
+    """
+    t = 'Typical'  # all  nominal (typical) values
+    f = 'Fast'     # fast, that is, values that make transistors run faster
+    s = 'Slow'     # slow
+
+    @classmethod
+    def parse(cls, s):
+        if s in CornerTypeMappings:
+            return cls.parse(CornerTypeMappings[s])
+        if len(s) > 1:
+            try:
+                o = []
+                for c in s:
+                    o.append(cls.parse(c))
+                return o
+            except TypeError:
+                raise TypeError("Unknown corner type: {}".format(s))
+        if not hasattr(cls, s):
+            raise TypeError("Unknown corner type: {}".format(s))
+        return getattr(cls, s)
+
+    def __repr__(self):
+        return 'CornerType.'+self.name
+
+    def __str__(self):
+        return self.value
+
+    def to_json(self):
+        return self.name
+
+
+class CornerFlag(OrderedFlag):
+    """
+
+    See Also
+    --------
+    skywater_pdk.corners.Corner
+    skywater_pdk.corners.CornerType
+    """
+
+    nointpr = 'No internal power'
+    lv = 'Low voltage'
+    hv = 'High voltage'
+    lowhv = 'Low High Voltage'
+    ccsnoise = 'Composite Current Source Noise'
+    pwr = 'Power'
+    xx = 'xx'
+    w = 'w'
+
+    @classmethod
+    def parse(cls, s):
+        if hasattr(cls, s):
+            return getattr(cls, s)
+        else:
+            raise TypeError("Unknown CornerFlags: {}".format(s))
+
+    def __repr__(self):
+        return 'CornerFlag.'+self.name
+
+    def __str__(self):
+        return self.value
+
+    def to_json(self):
+        return self.name
+
+
+@comparable_to_none
+class OptionalTuple(tuple):
+    pass
+
+
+@comparable_to_none
+@dataclass_json
+@dataclass(frozen=True, order=True)
+class Corner:
+    """
+
+    See Also
+    --------
+    skywater_pdk.corners.parse_filename
+    skywater_pdk.base.Cell
+    skywater_pdk.corners.CornerType
+    skywater_pdk.corners.CornerFlag
+
+    """
+    corner: Tuple[CornerType, CornerType] = dj_pass_cfg()
+    volts: Tuple[float, ...] = dj_pass_cfg()
+    temps: Tuple[int, ...] = dj_pass_cfg()
+    flags: Optional[Tuple[CornerFlag, ...]] = dj_pass_cfg(default=None)
+
+    def __post_init__(self):
+        if self.flags:
+            object.__setattr__(self, 'flags', OptionalTuple(self.flags))
+
+
+VOLTS_REGEX = re.compile('([0-9]p[0-9]+)V')
+TEMP_REGEX = re.compile('(n?)([0-9][0-9]+)C')
+def parse_filename(pathname):
+    """Extract corner information from a filename.
+
+    See Also
+    --------
+    skywater_pdk.base.parse_pathname
+    skywater_pdk.base.parse_filehname
+
+    Examples
+    --------
+
+    >>> parse_filename('tt_1p80V_3p30V_3p30V_25C')
+    (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), [])
+
+    >>> parse_filename('sky130_fd_sc_ms__tt_1p80V_100C.wrap.json')
+    (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), [])
+
+    >>> 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,)), [])
+
+    >>> parse_filename('sky130_fd_sc_ms__wp_1p65V_n40C.wrap.json')
+    (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,)), [])
+
+    >>> 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,)), [])
+
+    >>> 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,)), [])
+
+    >>> 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), [])
+
+    >>> 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:
+        cell, extra, extension = base.parse_filename(pathname)
+    else:
+        cell = None
+        extra = pathname
+        extension = ''
+
+    if extension not in ('', 'lib', 'cell.lib', 'cell.json', 'wrap.lib', 'wrap.json'):
+        raise ValueError('Not possible to extract corners from: {!r}'.format(extension))
+
+    if not extra:
+        extra = cell.name
+        cell = None
+
+    # FIXME: Hack?
+    extra = extra.replace("lpflow_","")
+    extra = extra.replace("udb_","")
+
+    kw = {}
+    kw['flags'] = []
+    kw['volts'] = []
+    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)
+
+        if VOLTS_REGEX.match(b):
+            assert b.endswith('V'), b
+            kw['volts'].append(float(b[:-1].replace('p', '.')))
+        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:
+            kw['flags'].append(CornerFlag.parse(b))
+
+    for k, v in kw.items():
+        kw[k] = tuple(v)
+
+    if not kw['flags']:
+        del kw['flags']
+
+    if 'corner' not in kw:
+        raise TypeError('Invalid corner value: '+extra)
+
+    return Corner(**kw), random
+
+
+
+# 1p60V 5p50V n40C
+
+
+
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()
diff --git a/scripts/python-skywater-pdk/skywater_pdk/liberty.py b/scripts/python-skywater-pdk/skywater_pdk/liberty.py
new file mode 100755
index 0000000..89f561b
--- /dev/null
+++ b/scripts/python-skywater-pdk/skywater_pdk/liberty.py
@@ -0,0 +1,894 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright 2020 SkyWater PDK Authors
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+# SPDX-License-Identifier: Apache-2.0
+
+
+import argparse
+import enum
+import json
+import os
+import pathlib
+import pprint
+import re
+import sys
+
+from collections import defaultdict
+
+from typing import Tuple, List, Dict
+
+from . import sizes
+from .utils import sortable_extracted_numbers
+
+
+debug = False
+
+
+class TimingType(enum.IntFlag):
+    """
+
+    >>> TimingType.parse("ff_100C_1v65")
+    ('ff_100C_1v65', <TimingType.basic: 1>)
+
+    >>> TimingType.parse("ff_100C_1v65_ccsnoise")
+    ('ff_100C_1v65', <TimingType.ccsnoise: 3>)
+
+    >>> TimingType.basic in TimingType.ccsnoise
+    True
+
+    >>> TimingType.parse("ff_100C_1v65_pwrlkg")
+    ('ff_100C_1v65', <TimingType.leakage: 4>)
+
+    >>> (TimingType.basic).describe()
+    ''
+    >>> (TimingType.ccsnoise).describe()
+    '(with ccsnoise)'
+    >>> (TimingType.leakage).describe()
+    '(with power leakage)'
+    >>> (TimingType.leakage | TimingType.ccsnoise).describe()
+    '(with ccsnoise and power leakage)'
+
+    >>> (TimingType.leakage | TimingType.ccsnoise).names()
+    'basic, ccsnoise, leakage'
+
+    >>> TimingType.ccsnoise.names()
+    'basic, ccsnoise'
+    """
+
+    basic    = 1
+
+    # ccsnoise files are basic files with extra 'ccsn_' values in the timing
+    # data.
+    ccsnoise = 2 | basic
+
+    # leakage files are separate from the basic files
+    leakage  = 4
+
+    def names(self):
+        o = []
+        for t in TimingType:
+            if t in self:
+                o.append(t.name)
+        return ", ".join(o)
+
+    def describe(self):
+        o = []
+        if TimingType.ccsnoise in self:
+            o.append("ccsnoise")
+        if TimingType.leakage in self:
+            o.append("power leakage")
+        if not o:
+            return ""
+        return "(with "+" and ".join(o)+")"
+
+    @property
+    def file(self):
+        if self == TimingType.ccsnoise:
+            return "_ccsnoise"
+        elif self == TimingType.leakage:
+            return "_pwrlkg"
+        return ""
+
+    @classmethod
+    def parse(cls, name):
+        ttype = TimingType.basic
+        if name.endswith("_ccsnoise"):
+            name = name[:-len("_ccsnoise")]
+            ttype = TimingType.ccsnoise
+        elif name.endswith("_pwrlkg"):
+            name = name[:-len("_pwrlkg")]
+            ttype = TimingType.leakage
+        return name, ttype
+
+    @property
+    def singular(self):
+        return len(self.types) == 1
+
+    @property
+    def types(self):
+        tt = set(t for t in TimingType if t in self)
+        if TimingType.ccsnoise in tt:
+            tt.remove(TimingType.basic)
+        return list(tt)
+
+
+
+def cell_corner_file(lib, cell_with_size, corner, corner_type: TimingType):
+    """
+
+    >>> cell_corner_file("sky130_fd_sc_hd", "a2111o", "ff_100C_1v65", TimingType.basic)
+    'cells/a2111o/sky130_fd_sc_hd__a2111o__ff_100C_1v65.lib.json'
+    >>> cell_corner_file("sky130_fd_sc_hd", "a2111o_1", "ff_100C_1v65", TimingType.basic)
+    'cells/a2111o/sky130_fd_sc_hd__a2111o_1__ff_100C_1v65.lib.json'
+    >>> cell_corner_file("sky130_fd_sc_hd", "a2111o_1", "ff_100C_1v65", TimingType.ccsnoise)
+    'cells/a2111o/sky130_fd_sc_hd__a2111o_1__ff_100C_1v65_ccsnoise.lib.json'
+
+    """
+    assert corner_type.singular, (lib, cell_with_size, corner, corner_type, corner_type.types())
+
+    sz = sizes.parse_size(cell_with_size)
+    if sz:
+        cell = cell_with_size[:-len(sz.suffix)]
+    else:
+        cell = cell_with_size
+
+    fname = "cells/{cell}/{lib}__{cell_sz}__{corner}{corner_type}.lib.json".format(
+        lib=lib, cell=cell, cell_sz=cell_with_size, corner=corner, corner_type=corner_type.file)
+    return fname
+
+
+def top_corner_file(libname, corner, corner_type: TimingType):
+    """
+
+    >>> top_corner_file("sky130_fd_sc_hd", "ff_100C_1v65", TimingType.ccsnoise)
+    'timing/sky130_fd_sc_hd__ff_100C_1v65_ccsnoise.lib.json'
+    >>> top_corner_file("sky130_fd_sc_hd", "ff_100C_1v65", TimingType.basic)
+    'timing/sky130_fd_sc_hd__ff_100C_1v65.lib.json'
+
+    """
+    assert corner_type.singular, (libname, corner, corner_type, corner_type.types())
+    return "timing/{libname}__{corner}{corner_type}.lib.json".format(
+        libname=libname,
+        corner=corner, corner_type=corner_type.file)
+
+
+def collect(library_dir) -> Tuple[Dict[str, TimingType], List[str]]:
+    """Collect the available timing information in corners.
+
+    Parameters
+    ----------
+    library_dir: str
+        Path to a library.
+
+    Returns
+    -------
+    lib : str
+        Library name
+
+    corners : {str: TimingType}
+        corners in the library.
+
+    cells : list of str
+        cells in the library.
+    """
+
+    if not isinstance(library_dir, pathlib.Path):
+        library_dir = pathlib.Path(library_dir)
+
+    libname0 = None
+
+    corners = {}
+    all_cells = set()
+    for p in library_dir.rglob("*.lib.json"):
+        if not p.is_file():
+            continue
+        if "timing" in str(p):
+            continue
+
+        fname, fext = str(p.name).split('.', 1)
+
+        libname, cellname, corner = fname.split("__")
+        if libname0 is None:
+            libname0 = libname
+        assert libname0 == libname, (libname0, libname)
+
+        corner_name, corner_type = TimingType.parse(corner)
+
+        if corner_name not in corners:
+            corners[corner_name] = [corner_type, set()]
+
+        corners[corner_name][0] |= corner_type
+        corners[corner_name][1].add(cellname)
+        all_cells.add(cellname)
+
+    for c in corners:
+        corners[c] = (corners[c][0], list(sorted(corners[c][1])))
+
+    assert corners, library_dir
+    assert all_cells, library_dir
+    assert libname0, library_dir
+
+    all_cells = list(sorted(all_cells))
+
+    # Sanity check to make sure the corner exists for all cells.
+    for corner, (corner_types, corner_cells) in sorted(corners.items()):
+        missing = set()
+        for cell_with_size in all_cells:
+            if cell_with_size not in corner_cells:
+                missing.add(cell_with_size)
+
+        if not missing:
+            continue
+
+        print("Missing", ", ".join(missing), "from", corner, corner_types)
+
+    return libname0, corners, all_cells
+
+    for corner, (corner_types, corner_cells) in sorted(corners.items()):
+        for corner_type in corner_types.types:
+            fname = cell_corner_file(libname0, cell_with_size, corner, corner_type)
+            fpath = os.path.join(library_dir, fname)
+            if not os.path.exists(fpath) and debug:
+                print("Missing", (fpath, corner, corner_type, corner_types))
+
+    timing_dir = os.path.join(library_dir, "timing")
+    assert os.path.exists(timing_dir), timing_dir
+    for corner, (corner_types, corner_cells) in sorted(corners.items()):
+        for corner_type in corner_types.types:
+            fname = top_corner_file(libname0, corner, corner_type)
+            fpath = os.path.join(library_dir, fname)
+            if not os.path.exists(fpath) and debug:
+                print("Missing", (fpath, corner, corner_type, corner_types))
+
+    return libname0, corners, all_cells
+
+
+def remove_ccsnoise(data):
+    for k, v in list(data.items()):
+        if "ccsn_" in k:
+            del data[k]
+            continue
+
+        if not k.startswith("pin "):
+            continue
+
+        pin_data = data[k]
+
+        if "input_voltage" in pin_data:
+            del pin_data["input_voltage"]
+
+        if "timing" not in pin_data:
+            continue
+        pin_timing = pin_data["timing"]
+
+        for t in pin_timing:
+            ccsn_keys = set()
+            for k in t:
+                if not k.startswith("ccsn_"):
+                    continue
+                ccsn_keys.add(k)
+
+            for k in ccsn_keys:
+                del t[k]
+
+
+def generate(library_dir, lib, corner, ocorner_type, icorner_type, cells):
+    top_fname = top_corner_file(lib, corner, ocorner_type).replace('.lib.json', '.lib')
+    top_fpath = os.path.join(library_dir, top_fname)
+
+    top_fout = open(top_fpath, "w")
+    def top_write(lines):
+        print("\n".join(lines), file=top_fout)
+
+    otype_str = "({} from {})".format(ocorner_type.name, icorner_type.names())
+    print("Starting to write", top_fpath, otype_str, flush=True)
+
+    common_data = {}
+
+    common_data_path = os.path.join(library_dir, "timing", "{}__common.lib.json".format(lib))
+    assert os.path.exists(common_data_path), common_data_path
+    with open(common_data_path) as f:
+        d = json.load(f)
+        assert isinstance(d, dict)
+        for k, v in d.items():
+            assert k not in common_data, (k, common_data[k])
+            common_data[k] = v
+
+    top_data_path = os.path.join(library_dir, top_corner_file(lib, corner, icorner_type))
+    assert os.path.exists(top_data_path), top_data_path
+    with open(top_data_path) as f:
+        d = json.load(f)
+        assert isinstance(d, dict)
+        for k, v in d.items():
+            if k in common_data:
+                print("Overwriting", k, "with", v, "(existing value of", common_data[k], ")")
+            common_data[k] = v
+
+    # Remove the ccsnoise if it exists
+    if ocorner_type != TimingType.ccsnoise:
+        remove_ccsnoise(common_data)
+
+    output = liberty_dict("library", lib+"__"+corner, common_data)
+    assert output[-1] == '}', output
+    top_write(output[:-1])
+
+    for cell_with_size in cells:
+        fname = cell_corner_file(lib, cell_with_size, corner, icorner_type)
+        fpath = os.path.join(library_dir, fname)
+        assert os.path.exists(fpath), fpath
+
+        with open(fpath) as f:
+            cell_data = json.load(f)
+
+        # Remove the ccsnoise if it exists
+        if ocorner_type != TimingType.ccsnoise:
+            remove_ccsnoise(cell_data)
+
+        top_write([''])
+        top_write(liberty_dict("cell", "%s__%s" % (lib, cell_with_size), cell_data, [cell_with_size]))
+
+    top_write([''])
+    top_write(['}'])
+    top_fout.close()
+    print("   Finish writing", top_fpath, flush=True)
+    print("")
+
+
+# * The 'delay_model' should be the 1st attribute in the library
+# * The 'technology' should be the 1st attribute in the library
+
+LIBERTY_ATTRIBUTE_ORDER = re.sub('/\\*[^*]*\\*/', '', """
+library (name_string) {
+    /* Library-Level Simple and Complex Attributes */
+    define (...,...,...) ;
+    technology (name_enum) ;
+    delay_model : "model" ;
+
+    bus_naming_style : "string" ;
+    date : "date" ;
+    comment : "string" ;
+
+    /* Unit definitions */
+    time_unit : "unit" ;
+    voltage_unit : "unit" ;
+    leakage_power_unit : "unit" ;
+    current_unit : "unit" ;
+    pulling_resistance_unit : "unit" ;
+    ..._unit : "unit" ;
+    /* FIXME: Should capacitive_load_unit always be last? */
+    capacitive_load_unit (value, unit) ;
+
+    /* FIXME: Why is define_cell_area here, while other defines are up above? */
+    define_cell_area (area_name, resource_type) ;
+
+    revision : float | string ;
+
+    /* Default Attributes and Values */
+    default_cell_leakage_power : float ;
+    default_fanout_load : float ;
+    default_inout_pin_cap : float ;
+    default_input_pin_cap : float ;
+    default_max_transition : float ;
+    default_output_pin_cap : float ;
+    default_... : ... ;
+
+    /* Scaling Factors Attributes and Values */
+    k_process_cell_fall ... ;
+    k_process_cell_rise ... ;
+    k_process_fall_propagation ... ;
+    k_process_fall_transition ... ;
+    k_process_rise_propagation ... ;
+    k_process_rise_transition ... ;
+    k_temp_cell_fall ... ;
+    k_temp_cell_rise ... ;
+    k_temp_fall_propagation ... ;
+    k_temp_fall_transition ... ;
+    k_temp_rise_propagation ... ;
+    k_temp_rise_transition ... ;
+    k_volt_cell_fall ... ;
+    k_volt_cell_rise ... ;
+    k_volt_fall_propagation ... ;
+    k_volt_fall_transition ... ;
+    k_volt_rise_propagation ... ;
+    k_volt_rise_transition ... ;
+    k_... : ... ;
+
+    /* Library-Level Group Statements */
+    operating_conditions (name_string) {
+        ... operating conditions description ...
+    }
+    wire_load (name_string) {
+        ... wire load description ...
+    }
+    wire_load_selection (name_string) {
+        ... wire load selection criteria...
+    }
+    power_lut_template (namestring)  {
+        ... power lookup table template information...
+    }
+    lu_table_template (name_string) {
+        variable_1 : value_enum ;
+        variable_2 : value_enum ;
+        variable_3 : value_enum ;
+        index_1 ("float, ..., float");
+        index_2 ("float, ..., float");
+        index_3 ("float, ..., float");
+    }
+    normalized_driver_waveform (waveform_template_name) {
+        driver_waveform_name : string; /* Specifies the name of the driver waveform table */
+        index_1 ("float, ... float"); /* Specifies input net transition */
+        index_2 ("float, ... float"); /* Specifies normalized voltage */
+        values ("float, ... float", \ /* Specifies the time in library units */
+            ... , \\
+            "float, ... float");
+    }
+
+    /* Cell definitions */
+    cell (namestring2) {
+        ... cell description ...
+    }
+
+    ...
+
+    /* FIXME: What are these and why are they last */
+    type (namestring) {
+        ... type description ...
+    }
+    input_voltage (name_string) {
+        ... input voltage information ...
+    }
+    output_voltage (name_string) {
+        ... output voltage information ...
+    }
+}
+""")
+
+
+RE_LIBERTY_LIST = re.compile("(.*)_([0-9]+)")
+RE_NUMBERS = re.compile('([0-9]+)')
+
+
+def _lookup_attribute_pos(name):
+    # Pad with spaces so you don't get substring matches.
+    name = ' ' + name
+    if name.endswith('_'):
+        name = name + ' '
+    i = LIBERTY_ATTRIBUTE_ORDER.find(name)
+    if i != -1:
+        return float(i)
+    return None
+
+
+def liberty_attribute_order(attr_name):
+    """
+
+    FIXME: Make these doctests less fragile...
+    >>> liberty_attribute_order("define")
+    (33.0, 0.0)
+
+    >>> liberty_attribute_order('voltage_map')
+    (inf, inf)
+
+    >>> liberty_attribute_order('slew_lower_threshold_pct_fall')
+    (inf, inf)
+
+    >>> liberty_attribute_order('time_unit')
+    (203.0, 0.0)
+    >>> liberty_attribute_order('random_unit')
+    (357.0, 0.0)
+    >>> liberty_attribute_order('capacitive_load_unit')
+    (386.0, 0.0)
+
+    >>> liberty_attribute_order('technology')
+    (60.0, 0.0)
+    >>> liberty_attribute_order('technology("cmos")')
+    (60.0, 0.0)
+
+    >>> liberty_attribute_order('delay_model')
+    (89.0, 0.0)
+
+    >>> liberty_attribute_order("cell")
+    (2282.0, 0.0)
+
+    >>> v1, v2 = "variable_1", "variable_2"
+    >>> i1, i2, i3, i4 = "index_1", "index_2", "index_3", "index_4"
+    >>> print('\\n'.join(sorted([v2, i1, v1, i2, i3, i4], key=liberty_attribute_order)))
+    variable_1
+    variable_2
+    index_1
+    index_2
+    index_3
+    index_4
+
+    >>> liberty_attribute_order("values")
+    (2182.0, 0.0)
+
+    >>> print('\\n'.join(sorted([
+    ...     'default_inout_pin_cap',
+    ...     'k_XXXX',
+    ...     'k_temp_cell_fall',
+    ...     'default_XXXX',
+    ... ], key=liberty_attribute_order)))
+    default_inout_pin_cap
+    default_XXXX
+    k_temp_cell_fall
+    k_XXXX
+
+
+    """
+    assert ':' not in attr_name, attr_name
+
+    m = RE_LIBERTY_LIST.match(attr_name)
+    if m:
+        k, n = m.group(1), m.group(2)
+
+        i = _lookup_attribute_pos(k)
+        if not i:
+            i = float('inf')
+
+        return float(i), float(n)
+
+    lookup_name = attr_name
+    i = _lookup_attribute_pos(lookup_name)
+    if i:
+        return i, 0.0
+
+    if '(' in lookup_name:
+        lookup_name = lookup_name[:lookup_name.index('(')]
+
+    if 'default_' in attr_name:
+        lookup_name = 'default_...'
+    if '_unit' in attr_name:
+        lookup_name = '..._unit'
+    if 'k_' in attr_name:
+        lookup_name = 'k_...'
+
+    i = _lookup_attribute_pos(lookup_name)
+    if i:
+        return i, 0.0
+
+    return float('inf'), float('inf')
+
+
+def is_liberty_list(k):
+    """
+
+    >>> is_liberty_list("variable_1")
+    True
+    >>> is_liberty_list("index_3")
+    True
+    >>> is_liberty_list("values")
+    True
+    """
+    m = RE_LIBERTY_LIST.match(k)
+    if m:
+        k, n = m.group(1), m.group(2)
+
+    return k in ('variable', 'index', 'values')
+
+
+def liberty_float(f):
+    """
+
+    >>> liberty_float(1.9208818e-02)
+    '0.0192088180'
+
+    >>> liberty_float(1.5)
+    '1.5000000000'
+
+    >>> liberty_float(1e20)
+    '1.000000e+20'
+
+    >>> liberty_float(1)
+    '1.0000000000'
+
+    """
+    WIDTH = len(str(0.0083333333))
+
+    s = json.dumps(f)
+    if 'e' in s:
+        a, b = s.split('e')
+        if '.' not in a:
+            a += '.'
+        while len(a)+len(b)+1 < WIDTH:
+            a += '0'
+        s = "%se%s" % (a, b)
+    elif '.' in s:
+        while len(s) < WIDTH:
+            s += '0'
+    else:
+        if len(s) < WIDTH:
+            s += '.'
+        while len(s) < WIDTH:
+            s += '0'
+    return s
+
+
+INDENT="    "
+
+
+def liberty_composite(k, v, i=tuple()):
+    """
+
+    >>> def pl(l):
+    ...     print("\\n".join(l))
+
+    >>> pl(liberty_composite("capacitive_load_unit", [1.0, "pf"], []))
+    capacitive_load_unit(1.0000000000, "pf");
+
+    >>> pl(liberty_composite("voltage_map", [("vpwr", 1.95), ("vss", 0.0)], []))
+    voltage_map("vpwr", 1.9500000000);
+    voltage_map("vss", 0.0000000000);
+
+    >>> pl(liberty_composite("library_features", 'report_delay_calculation', []))
+    library_features("report_delay_calculation");
+
+    """
+    if isinstance(v, tuple):
+        v = list(v)
+    if not isinstance(v, list):
+        v = [v]
+    #assert isinstance(v, list), (k, v)
+
+    if isinstance(v[0], (list, tuple)):
+        o = []
+        for j, l in enumerate(v):
+            o.extend(liberty_composite(k, l, i))
+        return o
+
+    o = []
+    for l in v:
+        if isinstance(l, (float, int)):
+            o.append(liberty_float(l))
+        elif isinstance(l, str):
+            assert '"' not in l, (k, v)
+            o.append('"%s"' % l)
+        else:
+            raise ValueError("%s - %r (%r)" % (k, l, v))
+
+    return ["%s%s(%s);" % (INDENT*len(i), k, ", ".join(o))]
+
+
+def liberty_join(l):
+    """
+
+    >>> l = [5, 1.0, 10]
+    >>> liberty_join(l)(l)
+    '5.0000000000, 1.0000000000, 10.000000000'
+
+    >>> l = [1, 5, 8]
+    >>> liberty_join(l)(l)
+    '1, 5, 8'
+
+    """
+    d = defaultdict(lambda: 0)
+
+    for i in l:
+        d[type(i)] += 1
+
+    def types(l):
+        return [(i, type(i)) for i in l]
+
+    if d[float] > 0:
+        assert (d[float]+d[int]) == len(l), (d, types(l))
+        def join(l):
+            return ", ".join(liberty_float(f) for f in l)
+        return join
+
+    elif d[int] > 0:
+        assert d[int] == len(l), (d, types(l))
+        def join(l):
+            return ", ".join(str(f) for f in l)
+        return join
+
+    raise ValueError("Invalid value: %r" % types(l))
+
+
+def liberty_list(k, v, i=tuple()):
+    o = []
+    if isinstance(v[0], list):
+        o.append('%s%s(' % (INDENT*len(i), k))
+        join = liberty_join(v[0])
+        for l in v:
+            o.append('%s"%s", \\' % (INDENT*(len(i)+1), join(l)))
+
+        o[1] = o[0]+o[1]
+        o.pop(0)
+
+        o[-1] = o[-1][:-3] + ');'
+    else:
+        join = liberty_join(v)
+        o.append('%s%s("%s");' % (INDENT*len(i), k, join(v)))
+
+    return o
+
+
+def liberty_dict(dtype, dvalue, data, indent=tuple()):
+    assert isinstance(data, dict), (dtype, dvalue, data)
+    o = []
+
+    if dvalue:
+        dbits = dvalue.split(",")
+        for j, d in enumerate(dbits):
+            if '"' in d:
+                assert d.startswith('"'), (dvalue, dbits, indent)
+                assert d.endswith('"'), (dvalue, dbits, indent)
+                dbits[j] = d[1:-1]
+        dvalue = ','.join('"%s"' % d.strip() for d in dbits)
+    o.append('%s%s (%s) {' % (INDENT*len(indent), dtype, dvalue))
+
+    # Sort the attributes
+    def attr_sort_key(item):
+        k, v = item
+        if " " in k:
+            ktype, kvalue = k.split(" ", 1)
+            sortable_kv = sortable_extracted_numbers(kvalue)
+        else:
+            ktype = k
+            kvalue = ""
+            sortable_kv = tuple()
+
+        if ktype == "comp_attribute":
+            sortable_kt = liberty_attribute_order(kvalue)
+        else:
+            sortable_kt = liberty_attribute_order(ktype)
+
+        return sortable_kt, ktype, sortable_kv, kvalue, k, v
+
+    di = [attr_sort_key(i) for i in data.items()]
+    di.sort()
+    if debug:
+        for sk, kt, skv, kv, k, v in di:
+            print(str(indent), "%4.0f %4.0f -- " % sk, "%-40s" % kt, '%-40r' % kv, str(v)[:40], '...')
+
+    # Output all the attributes
+    for _, ktype, _, kvalue, k, v in di:
+        indent_n = list(indent)+[k]
+
+        if ktype == 'define':
+            for d in sorted(data['define'], key=lambda d: d['group_name']+'.'+d['attribute_name']):
+                o.append('%sdefine(%s,%s,%s);' % (
+                    INDENT*len(indent_n),
+                    d['attribute_name'],
+                    d['group_name'],
+                    d['attribute_type']),
+                )
+
+        elif ktype == "comp_attribute":
+            o.extend(liberty_composite(kvalue, v, indent_n))
+
+        elif isinstance(v, dict):
+            assert isinstance(v, dict), (dtype, dvalue, k, v)
+            o.extend(liberty_dict(ktype, kvalue, v, indent_n))
+
+        elif isinstance(v, list):
+            assert len(v) > 0, (dtype, dvalue, k, v)
+            if isinstance(v[0], dict):
+                def sk(o):
+                    return o.items()
+
+                for l in sorted(v, key=sk):
+                    o.extend(liberty_dict(ktype, kvalue, l, indent_n))
+
+            elif is_liberty_list(ktype):
+                o.extend(liberty_list(ktype, v, indent_n))
+
+            elif "clk_width" == ktype:
+                for l in sorted(v):
+                    o.append("%s%s : %s;" % (INDENT*len(indent_n), k, l))
+
+            else:
+                raise ValueError("Unknown %s: %r\n%s" % (k, v, indent_n))
+
+        else:
+            if isinstance(v, str):
+                v = '"%s"' % v
+            elif isinstance(v, (float,int)):
+                v = liberty_float(v)
+            o.append("%s%s : %s;" % (INDENT*len(indent_n), k, v))
+
+    o.append("%s}" % (INDENT*len(indent)))
+    return o
+
+
+
+
+def main():
+    parser = argparse.ArgumentParser()
+    parser.add_argument(
+            "library_path",
+            help="Path to the library.",
+            type=pathlib.Path,
+            nargs=1)
+    parser.add_argument(
+            "corner",
+            help="Corner to write output for.",
+            default=None,
+            nargs='*')
+
+    parser.add_argument(
+            "--ccsnoise",
+            help="Include ccsnoise in file output.",
+            action='store_true',
+            default=False)
+    parser.add_argument(
+            "--leakage",
+            help="Include power leakage in file output.",
+            action='store_true',
+            default=False)
+
+    args = parser.parse_args()
+
+    libdir = args.library_path[0]
+
+    retcode = 0
+
+    lib, corners, all_cells = collect(libdir)
+
+    if args.ccsnoise:
+        output_corner_type = TimingType.ccsnoise
+    elif args.leakage:
+        output_corner_type = TimingType.leakage
+    else:
+        output_corner_type = TimingType.basic
+
+    if args.corner == ['all']:
+        args.corner = list(sorted(k for k, (v0, v1) in corners.items() if output_corner_type in v0))
+
+    if args.corner:
+        for acorner in args.corner:
+            if acorner in corners:
+                continue
+            print()
+            print("Unknown corner:", acorner)
+            retcode = 1
+        if retcode != 0:
+            args.corner.clear()
+
+    if not args.corner:
+        print()
+        print("Available corners for", lib+":")
+        for k, v in sorted(corners.items()):
+            print("  -", k, v[0].describe())
+        print()
+        return retcode
+
+    print("Generating", output_corner_type.name, "liberty timing files for", lib, "at", ", ".join(args.corner))
+    print()
+    for corner in args.corner:
+        input_corner_type, corner_cells = corners[corner]
+        if output_corner_type not in input_corner_type:
+            print("Corner", corner, "doesn't support", output_corner_type, "(only {})".format(input_corner_type))
+            return 1
+
+        if output_corner_type == TimingType.basic and TimingType.ccsnoise in input_corner_type:
+            input_corner_type = TimingType.ccsnoise
+        else:
+            input_corner_type = output_corner_type
+
+        generate(
+            libdir, lib,
+            corner, output_corner_type, input_corner_type,
+            corner_cells,
+        )
+    return 0
+
+
+if __name__ == "__main__":
+    import doctest
+    doctest.testmod()
+    sys.exit(main())
diff --git a/scripts/python-skywater-pdk/skywater_pdk/sizes.py b/scripts/python-skywater-pdk/skywater_pdk/sizes.py
index aa3b02b..1988cfd 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/sizes.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/sizes.py
@@ -31,6 +31,9 @@
     >>> parse_size('_1')
     CellSizeNumeric(units=1)
 
+    >>> parse_size('a2111o_1')
+    CellSizeNumeric(units=1)
+
     >>> parse_size('sky130_fd_sc_ms__sdfrtp_1.v')
     CellSizeNumeric(units=1)
 
@@ -47,7 +50,7 @@
     dirname, s = os.path.split(s)
     if '.' in s:
         s = s.split('.', 1)[0]
-    if s.count('_') > 1:
+    if s.count('_') > 0:
         s = '_' + (s.rsplit('_', 1)[-1])
     if not s or s == '_':
         return None
diff --git a/scripts/python-skywater-pdk/skywater_pdk/utils.py b/scripts/python-skywater-pdk/skywater_pdk/utils.py
index 9f7a641..30b3d9d 100644
--- a/scripts/python-skywater-pdk/skywater_pdk/utils.py
+++ b/scripts/python-skywater-pdk/skywater_pdk/utils.py
@@ -21,6 +21,7 @@
 import dataclasses_json
 import functools
 import random
+import re
 import sys
 
 from dataclasses import dataclass
@@ -229,6 +230,64 @@
         return hash(self._name_)
 
 
+def extract_numbers(s):
+    """Create tuple with sequences of numbers converted to ints.
+
+    >>> extract_numbers("pwr_template13x10")
+    ('pwr_template', 13, 'x', 10)
+    >>> extract_numbers("vio_10_10_1")
+    ('vio_', 10, '_', 10, '_', 1)
+    """
+    bits = []
+    for m in re.finditer("([^0-9]*)([0-9]*)", s):
+        if m.group(1):
+            bits.append(m.group(1))
+        if m.group(2):
+            bits.append(int(m.group(2)))
+    return tuple(bits)
+
+
+def sortable_extracted_numbers(s):
+    """Create output which is sortable by numeric values in string.
+
+    >>> sortable_extracted_numbers("pwr_template13x10")
+    ('pwr_template', '0000000013', 'x', '0000000010')
+    >>> sortable_extracted_numbers("vio_10_10_1")
+    ('vio_', '0000000010', '_', '0000000010', '_', '0000000001')
+
+    >>> l = ['a1', 'a2b2', 'a10b10', 'b2', 'a8b50', 'a10b1']
+    >>> l.sort()
+    >>> print('\\n'.join(l))
+    a1
+    a10b1
+    a10b10
+    a2b2
+    a8b50
+    b2
+    >>> l.sort(key=sortable_extracted_numbers)
+    >>> print('\\n'.join(l))
+    a1
+    a2b2
+    a8b50
+    a10b1
+    a10b10
+    b2
+
+    """
+    zero_pad_str = '%010i'
+    bits = extract_numbers(s)
+    o = []
+
+    for b in bits:
+        if not isinstance(b, str):
+            assert isinstance(b, int), (b, bits)
+            assert len(str(b)) < len(zero_pad_str % 0)
+            b = zero_pad_str % b
+        o.append(b)
+    return tuple(o)
+
+
+
 if __name__ == "__main__":
     import doctest
     doctest.testmod()