add dummy (fake) PLL to experiments10_verilog for testing
authorLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 5 Jun 2021 10:15:23 +0000 (10:15 +0000)
committerLuke Kenneth Casson Leighton <lkcl@lkcl.net>
Sat, 5 Jun 2021 10:15:34 +0000 (10:15 +0000)
experiments10_verilog/coriolis2/settings.py
experiments10_verilog/dummypll.py [new file with mode: 0644]
experiments10_verilog/non_generated/pll.v [new file with mode: 0644]
experiments10_verilog/pll.py [new file with mode: 0644]

index e4e3362cd24142fed2499339a92f84548000a38a..22e72f516db1a50f498b436d69413dd8c2dc7f67 100644 (file)
@@ -10,6 +10,14 @@ import os
 import socket
 import helpers
 
+import Cfg
+from   Hurricane import DataBase, Cell, Instance, Net
+from   CRL     import AllianceFramework, RoutingLayerGauge
+import CRL
+import Viewer
+from   helpers.overlay import CfgCache
+import symbolic.cmos45  # do not remove
+
 NdaDirectory = None
 if os.environ.has_key('NDA_TOP'):
     NdaDirectory = os.environ['NDA_TOP']
@@ -23,10 +31,6 @@ if not NdaDirectory:
         NdaDirectory = '/users/soft/techno/techno'
 helpers.setNdaTopDir( NdaDirectory )
 
-import CRL
-import Cfg
-from   helpers import overlay, l, u, n
-
 # select one or other of these
 if False:
     from   NDA.node45.freepdk45_c4m import techno, FlexLib, LibreSOCIO
@@ -35,12 +39,53 @@ if False:
     LibreSOCIO.setup()
 else:
     import symbolic.cmos45
+    import pll # fake pll
+    pll.setup()
 
 
 if os.environ.has_key('CELLS_TOP'):
     cellsTop = os.environ['CELLS_TOP']
 else:
     cellsTop = '../../../alliance-check-toolkit/cells'
+
+db = DataBase.getDB()
+af = AllianceFramework.get()
+
+
+def createPLLBlackbox ():
+    global db, af
+    print( '  o  Creating PLL blackboxes for "ls180" design.' )
+    rootlib  = db.getRootLibrary()
+    lib      = rootlib.getLibrary( 'pll' )
+    pllName = 'pll'
+    pll     = lib.getCell( pllName )
+    if not pll:
+        raise ErrorMessage( 1, 'settings.createPLLBlackBox(): '
+                                'PLL Cell "{}" not found.' \
+                               .format(pllName) )
+    pll.setAbstractedSupply( True )
+    blackboxName = 'real_pll'
+    cell     = Cell.create( lib, blackboxName )
+    instance = Instance.create( cell, 'real_pll', pll )
+    state    = af.getCatalog().getState( blackboxName, True )
+    state.setCell( cell )
+    state.setLogical( True )
+    state.setInMemory( True )
+    print( '     - {}.'.format(cell) )
+    for masterNet in pll.getNets():
+        if not masterNet.isExternal():
+            continue
+        net = Net.create( cell, masterNet.getName() )
+        net.setDirection( masterNet.getDirection() )
+        net.setType( masterNet.getType() )
+        net.setExternal( True )
+        net.setGlobal( masterNet.isGlobal() )
+        if masterNet.isSupply():
+            continue
+        plug = instance.getPlug( masterNet )
+        plug.setNet( net )
+
+
 with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
     cfg.misc.catchCore = False
     cfg.misc.info = False
@@ -70,5 +115,11 @@ with overlay.CfgCache(priority=Cfg.Parameter.Priority.UserFile) as cfg:
                            mode=CRL.Environment.Prepend )
     env.addSYSTEM_LIBRARY( library=cellsTop+'/nsxlib',
                            mode=CRL.Environment.Prepend )
+
+# runs the "fake" pll blackbox create
+with overlay.UpdateSession():
+    createPLLBlackbox()
+
 print( '  o  Successfully run "<>/coriolis2/settings.py".' )
 print( '     - CELLS_TOP = "{}"'.format(cellsTop) )
+
diff --git a/experiments10_verilog/dummypll.py b/experiments10_verilog/dummypll.py
new file mode 100644 (file)
index 0000000..1fcc4f3
--- /dev/null
@@ -0,0 +1,60 @@
+"""a Dummy PLL module to be replaced by a real one
+"""
+
+from nmigen import (Module, Signal, Elaboratable, Const, Cat, Instance)
+from nmigen.cli import rtlil
+
+class DummyPLL(Elaboratable):
+    def __init__(self, instance):
+        self.instance = instance
+        self.clk_24_i = Signal(reset_less=True) # external incoming
+        self.clk_sel_i = Signal(2, reset_less=True) # PLL selection
+        self.clk_pll_o = Signal(reset_less=True)  # output clock
+        self.pll_test_o = Signal(reset_less=True)  # test out
+        self.pll_vco_o = Signal(reset_less=True) # analog
+
+    def elaborate(self, platform):
+        m = Module()
+
+        if self.instance:
+            clk_24_i = Signal(reset_less=True) # external incoming
+            clk_sel_i = Signal(2, reset_less=True) # PLL selection
+            clk_pll_o = Signal(reset_less=True)  # output clock
+            pll_test_o = Signal(reset_less=True)  # test out
+            pll_vco_o = Signal(reset_less=True) # analog
+            pll = Instance("pll", i_ref_v=clk_24_i,
+                                  i_a0=clk_sel_i[0],
+                                  i_a1=clk_sel_i[1],
+                                  o_out_v=clk_pll_o,
+                                  o_div_out_test=pll_test_o,
+                                  o_vco_test_ana=pll_vco_o,
+                           )
+            m.submodules['real_pll'] = pll
+            #pll.attrs['blackbox'] = 1
+            m.d.comb += clk_24_i.eq(self.clk_24_i)
+            m.d.comb += clk_sel_i.eq(self.clk_sel_i)
+            m.d.comb += self.clk_pll_o.eq(clk_pll_o)
+            m.d.comb += self.pll_test_o.eq(pll_test_o)
+            m.d.comb += self.pll_vco_o.eq(pll_vco_o)
+
+        else:
+            m.d.comb += self.clk_pll_o.eq(self.clk_24_i) # just pass through
+            # just get something, stops yosys destroying (optimising) these out
+            with m.If(self.clk_sel_i == 0):
+                m.d.comb += self.pll_test_o.eq(self.clk_24_i)
+                m.d.comb += self.pll_vco_o.eq(~self.clk_24_i)
+
+        return m
+
+    def ports(self):
+        return [self.clk_24_i, self.clk_sel_i, self.clk_pll_o,
+                self.pll_test_o, self.pll_vco_o]
+
+
+if __name__ == '__main__':
+    dut = DummyPLL()
+
+    vl = rtlil.convert(dut, ports=dut.ports())
+    with open("test_dummy_pll.il", "w") as f:
+        f.write(vl)
+
diff --git a/experiments10_verilog/non_generated/pll.v b/experiments10_verilog/non_generated/pll.v
new file mode 100644 (file)
index 0000000..73212b5
--- /dev/null
@@ -0,0 +1,10 @@
+(* blackbox = 1 *)
+module pll(ref_v, div_out_test, a0, a1, vco_test_ana, out_v);
+  input a0;
+  input a1;
+  output div_out_test;
+  output out_v;
+  input ref_v;
+  output vco_test_ana;
+endmodule
+
diff --git a/experiments10_verilog/pll.py b/experiments10_verilog/pll.py
new file mode 100644 (file)
index 0000000..56163ae
--- /dev/null
@@ -0,0 +1,450 @@
+# Autogenerated file. Changes will be overwritten.
+
+import CRL, Hurricane, Viewer, Cfg
+from Hurricane import (
+    Technology, DataBase, DbU, Library,
+    Layer, BasicLayer,
+    Cell, Net, Vertical, Rectilinear, Box, Point,
+    Instance, Transformation,
+    NetExternalComponents,
+)
+from common.colors import toRGB
+from common.patterns import toHexa
+from helpers import u, l
+from helpers.technology import setEnclosures
+from helpers.overlay import CfgCache, UpdateSession
+
+__all__ = ["setup"]
+
+def createRL(tech, net, layer, coords):
+    return
+    coords = [Point(u(x), u(y)) for x,y in coords]
+    Rectilinear.create(net, tech.getLayer(layer), coords)
+
+def _routing():
+    return # all commented-out for now
+    af = CRL.AllianceFramework.get()
+    db = DataBase.getDB()
+    tech = db.getTechnology()
+
+    rg = CRL.RoutingGauge.create('pll')
+    rg.setSymbolic(False)
+    metal = tech.getLayer('metal1')
+    via = tech.getLayer('metal1_via1_metal2')
+    setEnclosures(via, metal, (u(0.0), u(0.035)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Horizontal, CRL.RoutingLayerGauge.PinOnly, 0, 0.0,
+        u(0.0), u(0.21), u(0.065), u(0.065), u(0.065), u(0.065),
+    ))
+    metal = tech.getLayer('metal2')
+    via = tech.getLayer('metal1_via1_metal2')
+    setEnclosures(via, metal, (u(0.0), u(0.035)))
+    via = tech.getLayer('metal2_via2_metal3')
+    setEnclosures(via, metal, (u(0.0), u(0.035)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Horizontal, CRL.RoutingLayerGauge.Default, 1, 0.0,
+        u(0.0), u(0.21), u(0.14), u(0.07), u(0.07), u(0.07),
+    ))
+    metal = tech.getLayer('metal3')
+    via = tech.getLayer('metal2_via2_metal3')
+    setEnclosures(via, metal, (u(0.035), u(0.0)))
+    via = tech.getLayer('metal3_via3_metal4')
+    setEnclosures(via, metal, (u(0.035), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Vertical, CRL.RoutingLayerGauge.Default, 2, 0.0,
+        u(0.0), u(0.21), u(0.14), u(0.07), u(0.07), u(0.07),
+    ))
+    metal = tech.getLayer('metal4')
+    via = tech.getLayer('metal3_via3_metal4')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    via = tech.getLayer('metal4_via4_metal5')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Horizontal, CRL.RoutingLayerGauge.Default, 3, 0.0,
+        u(0.0), u(0.28), u(0.14), u(0.14), u(0.14), u(0.14),
+    ))
+    metal = tech.getLayer('metal5')
+    via = tech.getLayer('metal4_via4_metal5')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    via = tech.getLayer('metal5_via5_metal6')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Vertical, CRL.RoutingLayerGauge.Default, 4, 0.0,
+        u(0.0), u(0.28), u(0.14), u(0.14), u(0.14), u(0.14),
+    ))
+    metal = tech.getLayer('metal6')
+    via = tech.getLayer('metal5_via5_metal6')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    via = tech.getLayer('metal6_via6_metal7')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Horizontal, CRL.RoutingLayerGauge.Default, 5, 0.0,
+        u(0.0), u(0.28), u(0.14), u(0.14), u(0.14), u(0.14),
+    ))
+    metal = tech.getLayer('metal7')
+    via = tech.getLayer('metal6_via6_metal7')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    via = tech.getLayer('metal7_via7_metal8')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Vertical, CRL.RoutingLayerGauge.Default, 6, 0.0,
+        u(0.0), u(0.8), u(0.4), u(0.4), u(0.4), u(0.4),
+    ))
+    metal = tech.getLayer('metal8')
+    via = tech.getLayer('metal7_via7_metal8')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    via = tech.getLayer('metal8_via8_metal9')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Horizontal, CRL.RoutingLayerGauge.Default, 7, 0.0,
+        u(0.0), u(0.8), u(0.4), u(0.4), u(0.4), u(0.4),
+    ))
+    metal = tech.getLayer('metal9')
+    via = tech.getLayer('metal8_via8_metal9')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    via = tech.getLayer('metal9_via9_metal10')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Vertical, CRL.RoutingLayerGauge.Default, 8, 0.0,
+        u(0.0), u(1.6), u(0.8), u(0.8), u(0.8), u(0.8),
+    ))
+    metal = tech.getLayer('metal10')
+    via = tech.getLayer('metal9_via9_metal10')
+    setEnclosures(via, metal, (u(0.0), u(0.0)))
+    rg.addLayerGauge(CRL.RoutingLayerGauge.create(
+        metal, CRL.RoutingLayerGauge.Horizontal, CRL.RoutingLayerGauge.Default, 9, 0.0,
+        u(0.0), u(1.6), u(0.8), u(0.8), u(0.8), u(0.8),
+    ))
+    af.addRoutingGauge(rg)
+    af.setRoutingGauge('LibreSOCMem')
+
+    cg = CRL.CellGauge.create(
+        'LibreSOCMem', 'metal2',
+        u(0.4), u(4.0), u(0.4),
+    )
+    af.addCellGauge(cg)
+    af.setCellGauge('LibreSOCMem')
+
+    # Place & Route setup
+    with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
+        cfg.lefImport.minTerminalWidth = 0.0
+        cfg.crlcore.groundName = 'vss'
+        cfg.crlcore.powerName = 'vdd'
+        cfg.etesian.aspectRatio = 1.00
+        cfg.etesian.aspectRatio = [10, 1000]
+        cfg.etesian.spaceMargin = 0.10
+        cfg.etesian.uniformDensity = False
+        cfg.etesian.routingDriven = False
+        cfg.etesian.feedNames = 'tie_x0,fill_x0'
+        cfg.etesian.cell.zero = 'zero_x0'
+        cfg.etesian.cell.one = 'one_x0'
+        cfg.etesian.bloat = 'disabled'
+        cfg.etesian.effort = 2
+        cfg.etesian.effort = (
+            ('Fast', 1),
+            ('Standard', 2),
+            ('High', 3 ),
+            ('Extreme', 4 ),
+        )
+        cfg.etesian.graphics = 2
+        cfg.etesian.graphics = (
+            ('Show every step', 1),
+            ('Show lower bound', 2),
+            ('Show result only', 3),
+        )
+        cfg.anabatic.routingGauge = 'LibreSOCMem'
+        cfg.anabatic.globalLengthThreshold = 1450
+        cfg.anabatic.saturateRatio = 90
+        cfg.anabatic.saturateRp = 10
+        cfg.anabatic.topRoutingLayer = 'metal10'
+        cfg.anabatic.edgeLength = 48
+        cfg.anabatic.edgeWidth = 8
+        cfg.anabatic.edgeCostH = 9.0
+        cfg.anabatic.edgeCostK = -10.0
+        cfg.anabatic.edgeHInc = 1.0
+        cfg.anabatic.edgeHScaling = 1.0
+        cfg.anabatic.globalIterations = 10
+        cfg.anabatic.globalIterations = [ 1, 100 ]
+        cfg.anabatic.gcell.displayMode = 1
+        cfg.anabatic.gcell.displayMode = (("Boundary", 1), ("Density", 2))
+        cfg.katana.hTracksReservedLocal = 4
+        cfg.katana.hTracksReservedLocal = [0, 20]
+        cfg.katana.vTracksReservedLocal = 3
+        cfg.katana.vTracksReservedLocal = [0, 20]
+        cfg.katana.termSatReservedLocal = 8
+        cfg.katana.termSatThreshold = 9
+        cfg.katana.eventsLimit = 4000002
+        cfg.katana.ripupCost = 3
+        cfg.katana.ripupCost = [0, None]
+        cfg.katana.strapRipupLimit = 16
+        cfg.katana.strapRipupLimit = [1, None]
+        cfg.katana.localRipupLimit = 9
+        cfg.katana.localRipupLimit = [1, None]
+        cfg.katana.globalRipupLimit = 5
+        cfg.katana.globalRipupLimit = [1, None]
+        cfg.katana.longGlobalRipupLimit = 5
+        cfg.chip.padCoreSide = 'South'
+
+    # Plugins setup
+    with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
+        cfg.chip.block.rails.count = 5
+        cfg.chip.block.rails.hWidth = u(2.68)
+        cfg.chip.block.rails.vWidth = u(2.68)
+        cfg.chip.block.rails.hSpacing = u(0.7)
+        cfg.chip.block.rails.vSpacing = u(0.7)
+        cfg.clockTree.minimumSide = l(600)
+        cfg.clockTree.buffer = 'buf_x2'
+        cfg.clockTree.placerEngine = 'Etesian'
+        cfg.block.spareSide = 10
+        cfg.spares.buffer = 'buf_x8'
+        cfg.spares.maxSinks = 31
+
+
+def _load():
+    af = CRL.AllianceFramework.get()
+    db = DataBase.getDB()
+    tech = db.getTechnology()
+    rootlib = db.getRootLibrary()
+
+    lib = Library.create(rootlib, 'pll')
+
+    space = 0.1
+
+    cell = Cell.create(lib, 'pll')
+    with UpdateSession():
+        cell.setAbutmentBox(Box(
+            #u(0.0), u(0.0), u(13.5), u(2.025),
+            u(0.0), u(0.0), u(space*100), u(space*25),
+        ))
+        nets = {
+            #'*': Net.create(cell, '*'),
+            'ref_v': Net.create(cell, 'ref_v'),
+            'div_out_test': Net.create(cell, 'div_out_test'),
+            'a0': Net.create(cell, 'a0'),
+            'a1': Net.create(cell, 'a1'),
+            'vco_test_ana': Net.create(cell, 'vco_test_ana'),
+            'out_v': Net.create(cell, 'out_v'),
+        }
+
+        # set net directions
+        nets['ref_v'].setDirection( Net.Direction.IN )
+        nets['a0'].setDirection( Net.Direction.IN )
+        nets['a1'].setDirection( Net.Direction.IN )
+        nets['div_out_test'].setDirection( Net.Direction.OUT )
+        nets['vco_test_ana'].setDirection( Net.Direction.OUT )
+        nets['out_v'].setDirection( Net.Direction.OUT )
+
+        # create series of stepped pins
+        x = space*20
+        wid = space
+        step = wid*5
+        for cname in ['ref_v', 'div_out_test', 'a0', 'a1', 'vco_test_ana',
+                      'out_v']:
+            net = nets[cname]
+            pin = Vertical.create(
+                net, tech.getLayer('metal1'),
+                u(x), u(wid), u(0), u(space*15),
+            )
+            x += step
+            net.setExternal(True)
+            NetExternalComponents.setExternal(pin)
+
+        if False:
+            net = nets['*']
+            createRL(
+                tech, net, 'active',
+                ((1.105,1.0),(1.4375,1.0),(1.4375,0.24),(0.9625,0.24),(0.9625,1.0),(1.105,1.0)),
+            )
+            net = nets['*']
+            createRL(
+                tech, net, 'nimplant',
+                ((1.105,0.235),(0.895,0.235),(0.895,0.17),(0.705,0.17),(0.705,0.235),(0.55,0.235),(0.55,0.615),(0.495,0.615),(0.495,0.55),(0.305,0.55),(0.305,0.615),(0.1575,0.615),(0.1575,1.385),(0.305,1.385),(0.305,1.45),(0.495,1.45),(0.495,1.385),(0.65,1.385),(0.65,1.005),(0.705,1.005),(0.705,1.07),(0.895,1.07),(0.895,1.005),(1.105,1.005),(1.105,1.07),(1.295,1.07),(1.295,1.005),(1.4425,1.005),(1.4425,0.235),(1.295,0.235),(1.295,0.17),(1.105,0.17),(1.105,0.235)),
+            )
+            createRL(
+                tech, net, 'nimplant',
+                ((0.515,3.595),(0.515,3.765),(0.685,3.765),(0.685,3.595),(0.515,3.595)),
+            )
+            createRL(
+                tech, net, 'vthg',
+                ((1.105,0.17),(1.105,1.07),(1.295,1.07),(1.295,0.17),(1.105,0.17)),
+            )
+            createRL(
+                tech, net, 'vthg',
+                ((1.105,2.13),(1.105,3.87),(1.295,3.87),(1.295,2.13),(1.105,2.13)),
+            )
+            createRL(
+                tech, net, 'vthg',
+                ((0.305,0.55),(0.305,1.45),(0.495,1.45),(0.495,0.55),(0.305,0.55)),
+            )
+            createRL(
+                tech, net, 'vthg',
+                ((0.305,2.53),(0.305,3.47),(0.495,3.47),(0.495,2.53),(0.305,2.53)),
+            )
+            createRL(
+                tech, net, 'vthg',
+                ((0.705,0.17),(0.705,1.07),(0.895,1.07),(0.895,0.17),(0.705,0.17)),
+            )
+            createRL(
+                tech, net, 'vthg',
+                ((0.705,2.53),(0.705,3.47),(0.895,3.47),(0.895,2.53),(0.705,2.53)),
+            )
+            createRL(
+                tech, net, 'pimplant',
+                ((1.105,2.195),(0.9575,2.195),(0.9575,2.595),(0.895,2.595),(0.895,2.53),(0.705,2.53),(0.705,2.595),(0.7,2.595),(0.495,2.595),(0.495,2.53),(0.305,2.53),(0.305,2.595),(0.15,2.595),(0.15,3.6825),(0.25,3.6825),(0.25,3.405),(0.305,3.405),(0.305,3.47),(0.495,3.47),(0.495,3.405),(0.5,3.405),(0.705,3.405),(0.705,3.47),(0.895,3.47),(0.895,3.405),(0.95,3.405),(0.95,3.7875),(0.9575,3.7875),(0.9575,3.805),(1.105,3.805),(1.105,3.87),(1.295,3.87),(1.295,3.805),(1.4425,3.805),(1.4425,2.195),(1.295,2.195),(1.295,2.13),(1.105,2.13),(1.105,2.195)),
+            )
+            createRL(
+                tech, net, 'pimplant',
+                ((0.115,0.195),(0.115,0.365),(0.285,0.365),(0.285,0.195),(0.115,0.195)),
+            )
+        if False:
+            net = nets['vss']
+            createRL(
+                tech, net, 'pwell',
+                ((-0.12,-0.32),(-0.12,1.92),(1.72,1.92),(1.72,-0.32),(-0.12,-0.32)),
+            )
+            createRL(
+                tech, net, 'metal1',
+                ((0.0,0.0),(0.0,0.48),(1.6,0.48),(1.6,0.0),(0.0,0.0)),
+            )
+            if False:
+                Vertical.create(
+                    net, tech.getLayer('metal1.pin'),
+                    u(0.8), u(1.6), u(0.0), u(0.48),
+                )
+            pin = Vertical.create(
+                net, tech.getLayer('metal1'),
+                u(0.8), u(1.6), u(0.0), u(0.48),
+            )
+            net.setExternal(True)
+            NetExternalComponents.setExternal(pin)
+            createRL(
+                tech, net, 'active',
+                ((0.12,0.2),(0.12,0.36),(0.28,0.36),(0.28,0.2),(0.12,0.2)),
+            )
+            createRL(
+                tech, net, 'active',
+                ((0.9625,0.3075),(1.0375,0.3075),(1.0375,0.3825),(0.9625,0.3825),(0.9625,0.3075)),
+            )
+            createRL(
+                tech, net, 'contact',
+                ((0.1675,0.2475),(0.2325,0.2475),(0.2325,0.3125),(0.1675,0.3125),(0.1675,0.2475)),
+            )
+            createRL(
+                tech, net, 'contact',
+                ((0.9675,0.3125),(1.0325,0.3125),(1.0325,0.3775),(0.9675,0.3775),(0.9675,0.3125)),
+            )
+        if False:
+            net = nets['*']
+            createRL(
+                tech, net, 'active',
+                ((1.105,3.8),(1.4375,3.8),(1.4375,2.2),(0.9625,2.2),(0.9625,3.8),(1.105,3.8)),
+            )
+        if False:
+            net = nets['vdd']
+            createRL(
+                tech, net, 'nwell',
+                ((-0.12,1.92),(-0.12,4.32),(1.72,4.32),(1.72,1.92),(-0.12,1.92)),
+            )
+            createRL(
+                tech, net, 'metal1',
+                ((0.0,3.52),(0.0,4.0),(1.6,4.0),(1.6,3.52),(0.0,3.52)),
+            )
+            if False:
+                Vertical.create(
+                    net, tech.getLayer('metal1.pin'),
+                    u(0.8), u(1.6), u(3.52), u(4.0),
+                )
+            pin = Vertical.create(
+                net, tech.getLayer('metal1'),
+                u(0.8), u(1.6), u(3.52), u(4.0),
+            )
+            net.setExternal(True)
+            NetExternalComponents.setExternal(pin)
+            createRL(
+                tech, net, 'active',
+                ((0.52,3.6),(0.52,3.76),(0.68,3.76),(0.68,3.6),(0.52,3.6)),
+            )
+            createRL(
+                tech, net, 'active',
+                ((0.9625,3.5675),(1.0375,3.5675),(1.0375,3.7825),(0.9625,3.7825),(0.9625,3.5675)),
+            )
+            createRL(
+                tech, net, 'active',
+                ((0.1625,3.6025),(0.2375,3.6025),(0.2375,3.6775),(0.1625,3.6775),(0.1625,3.6025)),
+            )
+            createRL(
+                tech, net, 'contact',
+                ((0.5675,3.6475),(0.6325,3.6475),(0.6325,3.7125),(0.5675,3.7125),(0.5675,3.6475)),
+            )
+            createRL(
+                tech, net, 'contact',
+                ((0.9675,3.5725),(1.0325,3.5725),(1.0325,3.6375),(0.9675,3.6375),(0.9675,3.5725)),
+            )
+            createRL(
+                tech, net, 'contact',
+                ((0.9675,3.7125),(1.0325,3.7125),(1.0325,3.7775),(0.9675,3.7775),(0.9675,3.7125)),
+            )
+            createRL(
+                tech, net, 'contact',
+                ((0.1675,3.6075),(0.2325,3.6075),(0.2325,3.6725),(0.1675,3.6725),(0.1675,3.6075)),
+            )
+        if False:
+            net = nets['*']
+            createRL(
+                tech, net, 'active',
+                ((0.305,1.38),(0.495,1.38),(0.495,0.62),(0.1625,0.62),(0.1625,1.38),(0.305,1.38)),
+            )
+            net = nets['*']
+            createRL(
+                tech, net, 'active',
+                ((0.425,2.6),(0.155,2.6),(0.155,3.6775),(0.245,3.6775),(0.245,3.4),(0.705,3.4),(0.705,2.6),(0.425,2.6)),
+            )
+            net = nets['*']
+            createRL(
+                tech, net, 'active',
+                ((0.705,1.0),(1.0375,1.0),(1.0375,0.24),(0.555,0.24),(0.555,1.0),(0.705,1.0)),
+            )
+            createRL(
+                tech, net, 'poly',
+                ((0.775,2.545),(0.775,3.455),(0.825,3.455),(0.825,2.0375),(0.9975,2.0375),(0.9975,1.9625),(0.775,1.9625),(0.775,2.545)),
+            )
+            createRL(
+                tech, net, 'metal1',
+                ((0.9675,1.2675),(0.9675,1.9325),(0.9275,1.9325),(0.9275,2.0675),(0.9675,2.0675),(0.9675,3.455),(1.0325,3.455),(1.0325,0.545),(0.9675,0.545),(0.9675,1.1325),(0.9275,1.1325),(0.9275,1.2675),(0.9675,1.2675)),
+            )
+        if False:
+            Vertical.create(
+                net, tech.getLayer('metal1.pin'),
+                u(1.0), u(0.065), u(0), u(3.455),
+            )
+        pin = Vertical.create(
+            net, tech.getLayer('metal1'),
+            u(1.0), u(0.065), u(0), u(3.455),
+        )
+        net.setExternal(True)
+        NetExternalComponents.setExternal(pin)
+        createRL(
+            tech, net, 'contact',
+            ((0.9275,1.1675),(0.9925,1.1675),(0.9925,1.2325),(0.9275,1.2325),(0.9275,1.1675)),
+        )
+        createRL(
+            tech, net, 'contact',
+            ((0.9275,1.9675),(0.9925,1.9675),(0.9925,2.0325),(0.9275,2.0325),(0.9275,1.9675)),
+        )
+        if False:
+            net = nets['*']
+            createRL(
+                tech, net, 'active',
+                ((0.775,2.6),(0.705,2.6),(0.705,3.4),(0.955,3.4),(0.955,3.7825),(1.045,3.7825),(1.045,2.6),(0.775,2.6)),
+            )
+
+
+    af.wrapLibrary(lib, 0)
+
+    return lib
+
+def setup():
+    lib = _load()
+    _routing()
+
+    return lib