Version with buffered signals
diff --git a/doitcode/frame.py b/doitcode/frame.py
index 9cb8659..8b06584 100644
--- a/doitcode/frame.py
+++ b/doitcode/frame.py
@@ -164,6 +164,8 @@
     "io_in[26]": _geo.Rect(left=-4.00, bottom=19.54, right=2.40, top=20.10),
     "io_in_3v3[26]": _geo.Rect(left=-4.00, bottom=25.45, right=2.40, top=26.01),
     # TODO: vss*, vdd*, ioclamp*, wb(s)_*, la_data*, user_clock2, user_irq
+    "vccd1": _geo.Rect(left=2911.70, bottom=3148.92, right=2924.00, top=3172.92),
+    "vssd1": _geo.Rect(left=2911.70, bottom=957.15, right=2924.00, top=981.15),
     # "vdda2": _geo.Rect(left=-4.00, bottom=1074.44, right=8.30, top=1098.44),
     # "vdda2": _geo.Rect(left=-4.00, bottom=1024.44, right=8.30, top=1048.44),
     # "vssd2": _geo.Rect(left=-4.00, bottom=864.44, right=8.30, top=888.44),
diff --git a/doitcode/sram.py b/doitcode/sram.py
index 9b33ebd..86edfb7 100644
--- a/doitcode/sram.py
+++ b/doitcode/sram.py
@@ -67,21 +67,21 @@
     _io_spec(sram_signal="a[1]", io_type="io_in", io_number=21),
     _io_spec(sram_signal="a[0]", io_type="io_in", io_number=22),
     _io_spec(sram_signal="clk", io_type="io_in", io_number=23),
-    _io_spec(sram_signal="q[7]", io_type="io_in", io_number=13),
-    _io_spec(sram_signal="d[7]", io_type="io_out", io_number=12),
+    _io_spec(sram_signal="q[7]", io_type="io_out", io_number=13),
+    _io_spec(sram_signal="d[7]", io_type="io_in", io_number=12),
     _io_spec(sram_signal="d[6]", io_type="io_in", io_number=11),
     _io_spec(sram_signal="q[6]", io_type="io_out", io_number=10),
-    _io_spec(sram_signal="q[5]", io_type="io_in", io_number=9),
-    _io_spec(sram_signal="d[5]", io_type="io_out", io_number=8),
+    _io_spec(sram_signal="q[5]", io_type="io_out", io_number=9),
+    _io_spec(sram_signal="d[5]", io_type="io_in", io_number=8),
     _io_spec(sram_signal="d[4]", io_type="io_in", io_number=7),
     _io_spec(sram_signal="q[4]", io_type="io_out", io_number=6),
-    _io_spec(sram_signal="q[3]", io_type="io_in", io_number=5),
-    _io_spec(sram_signal="d[3]", io_type="io_out", io_number=4),
+    _io_spec(sram_signal="q[3]", io_type="io_out", io_number=5),
+    _io_spec(sram_signal="d[3]", io_type="io_in", io_number=4),
     _io_spec(sram_signal="d[2]", io_type="io_in", io_number=3),
     _io_spec(sram_signal="q[2]", io_type="io_out", io_number=2),
-    _io_spec(sram_signal="q[1]", io_type="io_in", io_number=1),
+    _io_spec(sram_signal="q[1]", io_type="io_out", io_number=1),
     _io_spec(sram_signal="we[0]", io_type="io_in", io_number=0),
-    _io_spec(sram_signal="d[1]", io_type="io_out", io_number=26),
+    _io_spec(sram_signal="d[1]", io_type="io_in", io_number=26),
     _io_spec(sram_signal="d[0]", io_type="io_in", io_number=25),
     _io_spec(sram_signal="q[0]", io_type="io_out", io_number=24),
     _io_spec(sram_signal="vss", io_type="io_analog", io_number=4),
@@ -97,60 +97,20 @@
 }
 
 
-class ConnectedSRAM(_lbry._OnDemandCell[_lbry.Library]):
+class ConnectedSRAM(_lbry._Cell[_lbry.Library]):
     def __init__(self, *, lib: _lbry.Library):
         super().__init__(lib=lib, name="ConnectedSRAM")
+        tech = lib.tech
+        prims = tech.primitives
 
-    def _create_circuit(self):
         stdcells = sky130.stdcelllib.cells
 
         mem_fab = sky130.Sky130SP6TFactory(lib=self.lib)
 
-        zero_cell = stdcells.zero_x1
-        one_cell = stdcells.one_x1
-        tie_cell = stdcells.tie_diff_w4
-
-        sram_cell = mem_fab.block(words=512, word_size=8, we_size=1)
-        self.a_bits = sram_cell.a_bits
-        self.word_size = sram_cell.word_size
-
-        ckt = self.new_circuit()
-
-        sram = ckt.instantiate(sram_cell, name="sram")
-    
-        for spec in io_specs:
-            prefix = spec.prefix
-
-            sram_port = sram.ports[spec.sram_signal]
-            ckt.new_net(name=spec.toppin_name, external=True, childports=sram_port)
-
-            oeb = spec.oeb
-            if oeb is not None:
-                num = spec.io_number
-                if oeb:
-                    one = ckt.instantiate(one_cell, name=f"{prefix}one")
-                    ckt.new_net(
-                        name=f"io_oeb[{num}]", external=True, childports=one.ports.one,
-                    )
-                else:
-                    zero = ckt.instantiate(zero_cell, name=f"{prefix}zero")
-                    ckt.new_net(
-                        name=f"io_oeb[{num}]", external=True, childports=zero.ports.zero,
-                    )
-
-            if spec.io_type != "io_analog":
-                ckt.instantiate(tie_cell, name=f"{prefix}tie")
-
-    def _create_layout(self):
-        tech = sky130.tech
-        prims = tech.primitives
-
-        ckt = self.circuit
-        nets = ckt.nets
-        insts = ckt.instances
-
+        nwm = cast(_prm.Well, prims.nwm)
         li = cast(_prm.MetalWire, prims.li)
         lipin = cast(_prm.Marker, prims["li.pin"])
+        mcon = cast(_prm.Via, prims.mcon)
         m1 = cast(_prm.MetalWire, prims.m1)
         m1pin = cast(_prm.Marker, prims["m1.pin"])
         via = cast(_prm.Via, prims.via)
@@ -160,10 +120,55 @@
         m3 = cast(_prm.MetalWire, prims.m3)
         m3pin = cast(_prm.Marker, prims["m3.pin"])
 
+        zero_cell = stdcells.zero_x1
+        zero_nets = zero_cell.circuit.nets
+        _zero_zerolipinbb = zero_cell.layout.bounds(
+            mask=lipin.mask, net=zero_nets.zero, depth=1,
+        )
+        _zero_bb = zero_cell.layout.boundary
+        assert _zero_bb is not None
+
+        one_cell = stdcells.one_x1
+        _one_bb = one_cell.layout.boundary
+        assert _one_bb is not None
+
+        buf_cell = stdcells.buf_x2
+        buf_nets = buf_cell.circuit.nets
+        _buf_ilipinbb = buf_cell.layout.bounds(mask=lipin.mask, net=buf_nets.i, depth=1)
+        _buf_bb = buf_cell.layout.boundary
+        assert _buf_bb is not None
+
+        tie_cell = stdcells.tie_diff_w4
+        _tie_bb = tie_cell.layout.boundary
+        assert _tie_bb is not None
+
+        sram_cell = mem_fab.block(words=512, word_size=8, we_size=1)
+        self.a_bits = sram_cell.a_bits
+        self.word_size = sram_cell.word_size
+
+        ckt = self.new_circuit()
         layouter = self.new_circuitlayouter()
         layout = layouter.layout
 
-        _sram_lay = layouter.inst_layout(inst=insts.sram)
+
+        # vss/vdd for the included standard cells
+        #
+        dvss_name = "vssd1"
+        dvss = ckt.new_net(name=dvss_name, external=True)
+        dvss_bb = _frm.toppins[dvss_name]
+
+        dvdd_name = "vccd1"
+        dvdd = ckt.new_net(name=dvdd_name, external=True)
+        dvdd_bb = _frm.toppins[dvdd_name]
+
+
+        # Place the SRAM
+        #
+        # instantiate
+        sram = ckt.instantiate(sram_cell, name="sram")
+
+        # place
+        _sram_lay = layouter.inst_layout(inst=sram)
         _sram_bb = _sram_lay.boundary
         assert _sram_bb is not None
 
@@ -173,9 +178,252 @@
         sram_bb = sram_lay.boundary
         assert sram_bb is not None
 
+
+        # Make three rows of to place standard cells in
+        #
+        dbound = 4.0
+        # left
+        rot_leftrow = _geo.Rotation.R90
+        _tie_rotbb = rot_leftrow*_tie_bb
+
+        x_leftrow = dbound - _tie_rotbb.left
+
+        inst = ckt.instantiate(tie_cell, name="lltie")
+        dvss.childports += inst.ports.vss
+        dvdd.childports += inst.ports.vdd
+
+        y_tie = dbound - _tie_rotbb.bottom
+        lay = layouter.place(inst, x=x_leftrow, y=y_tie, rotation=rot_leftrow)
+        nwmbb1 = lay.bounds(mask=nwm.mask)
+        lipindvssbb1 = lay.bounds(mask=lipin.mask, net=dvss, depth=1)
+        lipindvddbb1 = lay.bounds(mask=lipin.mask, net=dvdd, depth=1)
+
+        inst = ckt.instantiate(tie_cell, name="ultie")
+        dvss.childports += inst.ports.vss
+        dvdd.childports += inst.ports.vdd
+
+        y_tie = _frm.boundary.top - dbound - _tie_rotbb.top
+        lay = layouter.place(inst, x=x_leftrow, y=y_tie, rotation=rot_leftrow)
+        nwmbb2 = lay.bounds(mask=nwm.mask)
+        lipindvssbb2 = lay.bounds(mask=lipin.mask, net=dvss, depth=1)
+        lipindvddbb2 = lay.bounds(mask=lipin.mask, net=dvdd, depth=1)
+
+        shape = _geo.Rect.from_rect(rect=nwmbb1, top=nwmbb2.top)
+        layouter.add_wire(net=dvdd, wire=nwm, shape=shape)
+
+        shape = _geo.Rect.from_rect(rect=lipindvssbb1, top=lipindvssbb2.top)
+        layouter.add_wire(net=dvss, wire=li, shape=shape)
+        w = tech.on_grid(shape.width, mult=2, rounding="floor")
+        h = tech.on_grid(shape.height, mult=2, rounding="floor")
+        o = tech.on_grid(shape.center)
+        lay = layouter.add_wire(
+            net=dvss, wire=mcon, origin=o, bottom_width=w, bottom_height=h,
+        )
+        dvss_leftrowm1bb = lay.bounds(mask=m1.mask)
+
+        shape = _geo.Rect.from_rect(rect=lipindvddbb1, top=lipindvddbb2.top)
+        layouter.add_wire(net=dvdd, wire=li, shape=shape)
+        w = tech.on_grid(shape.width, mult=2, rounding="floor")
+        h = tech.on_grid(shape.height, mult=2, rounding="floor")
+        o = tech.on_grid(shape.center)
+        lay = layouter.add_wire(
+            net=dvdd, wire=mcon, origin=o, bottom_width=w, bottom_height=h,
+        )
+        dvdd_leftrowm1bb = lay.bounds(mask=m1.mask)
+
+        # right
+        rot_rightrow = _geo.Rotation.R90
+        _tie_rotbb = rot_rightrow*_tie_bb
+
+        x_rightrow = _frm.boundary.right - dbound - _tie_rotbb.right
+
+        inst = ckt.instantiate(tie_cell, name="lrtie")
+        dvss.childports += inst.ports.vss
+        dvdd.childports += inst.ports.vdd
+
+        y_tie = dbound - _tie_rotbb.bottom
+        lay = layouter.place(inst, x=x_rightrow, y=y_tie, rotation=rot_rightrow)
+        nwmbb1 = lay.bounds(mask=nwm.mask)
+        lipindvssbb1 = lay.bounds(mask=lipin.mask, net=dvss, depth=1)
+        lipindvddbb1 = lay.bounds(mask=lipin.mask, net=dvdd, depth=1)
+
+        inst = ckt.instantiate(tie_cell, name="urtie")
+        dvss.childports += inst.ports.vss
+        dvdd.childports += inst.ports.vdd
+
+        y_tie = _frm.boundary.top - dbound - _tie_rotbb.top
+        lay = layouter.place(inst, x=x_rightrow, y=y_tie, rotation=rot_rightrow)
+        nwmbb2 = lay.bounds(mask=nwm.mask)
+        lipindvssbb2 = lay.bounds(mask=lipin.mask, net=dvss, depth=1)
+        lipindvddbb2 = lay.bounds(mask=lipin.mask, net=dvdd, depth=1)
+
+        shape = _geo.Rect.from_rect(rect=nwmbb1, top=nwmbb2.top)
+        layouter.add_wire(net=dvdd, wire=nwm, shape=shape)
+
+        shape = _geo.Rect.from_rect(rect=lipindvssbb1, top=lipindvssbb2.top)
+        layouter.add_wire(net=dvss, wire=li, shape=shape)
+        w = tech.on_grid(shape.width, mult=2, rounding="floor")
+        h = tech.on_grid(shape.height, mult=2, rounding="floor")
+        o = tech.on_grid(shape.center)
+        lay = layouter.add_wire(
+            net=dvss, wire=mcon, origin=o, bottom_width=w, bottom_height=h,
+        )
+        dvss_rightrowm1bb = lay.bounds(mask=m1.mask)
+
+        assert dvss_rightrowm1bb.center.x < dvss_bb.center.x, "Internal error"
+        w = dvss_rightrowm1bb.width
+        h = dvss_bb.height
+        x_via = dvss_rightrowm1bb.center.x
+        y_via = dvss_bb.center.y
+        layouter.add_wire(
+            net=dvss, wire=via, x=x_via, y=y_via,
+            bottom_width=w, bottom_height=h, top_width=w, top_height=h,
+        )
+        via2_lay = layouter.add_wire(
+            net=dvss, wire=via2, x=x_via, y=y_via,
+            bottom_width=w, bottom_height=h, top_width=w, top_height=h,
+        )
+        via2_m3bb = via2_lay.bounds(mask=m3.mask)
+
+        shape = _geo.Rect.from_rect(rect=dvss_bb, left=via2_m3bb.left)
+        layouter.add_wire(net=dvss, wire=m3, shape=shape)
+
+        layouter.add_wire(net=dvss, wire=m3, pin=m3pin, shape=dvss_bb)
+
+        shape = _geo.Rect.from_rect(rect=lipindvddbb1, top=lipindvddbb2.top)
+        layouter.add_wire(net=dvdd, wire=li, shape=shape)
+        w = tech.on_grid(shape.width, mult=2, rounding="floor")
+        h = tech.on_grid(shape.height, mult=2, rounding="floor")
+        o = tech.on_grid(shape.center)
+        lay = layouter.add_wire(
+            net=dvdd, wire=mcon, origin=o, bottom_width=w, bottom_height=h,
+        )
+        dvdd_rightrowm1bb = lay.bounds(mask=m1.mask)
+
+        assert dvdd_rightrowm1bb.center.x < dvdd_bb.center.x, "Internal error"
+        w = dvdd_rightrowm1bb.width
+        h = dvdd_bb.height
+        x_via = dvdd_rightrowm1bb.center.x
+        y_via = dvdd_bb.center.y
+        layouter.add_wire(
+            net=dvdd, wire=via, x=x_via, y=y_via,
+            bottom_width=w, bottom_height=h, top_width=w, top_height=h,
+        )
+        via2_lay = layouter.add_wire(
+            net=dvdd, wire=via2, x=x_via, y=y_via,
+            bottom_width=w, bottom_height=h, top_width=w, top_height=h,
+        )
+        via2_m3bb = via2_lay.bounds(mask=m3.mask)
+
+        shape = _geo.Rect.from_rect(rect=dvdd_bb, left=via2_m3bb.left)
+        lay = layouter.add_wire(net=dvdd, wire=m3, shape=shape)
+
+        layouter.add_wire(net=dvdd, wire=m3, pin=m3pin, shape=dvdd_bb)
+
+        # below SRAM
+        rot_midrow = _geo.Rotation.R0
+        _tie_rotbb = rot_midrow*_tie_bb
+
+        y_midrow = sram_bb.bottom - dbound - _tie_rotbb.top
+
+        inst = ckt.instantiate(tie_cell, name="mltie")
+        dvss.childports += inst.ports.vss
+        dvdd.childports += inst.ports.vdd
+
+        x_tie = sram_bb.left - _tie_rotbb.left
+        lay = layouter.place(inst, x=x_tie, y=y_midrow, rotation=rot_midrow)
+        nwmbb1 = lay.bounds(mask=nwm.mask)
+        lipindvssbb1 = lay.bounds(mask=lipin.mask, net=dvss, depth=1)
+        lipindvddbb1 = lay.bounds(mask=lipin.mask, net=dvdd, depth=1)
+
+        inst = ckt.instantiate(tie_cell, name="mrtie")
+        dvss.childports += inst.ports.vss
+        dvdd.childports += inst.ports.vdd
+
+        x_tie = sram_bb.right - _tie_rotbb.right
+        lay = layouter.place(inst, x=x_tie, y=y_midrow, rotation=rot_midrow)
+        nwmbb2 = lay.bounds(mask=nwm.mask)
+        lipindvssbb2 = lay.bounds(mask=lipin.mask, net=dvss, depth=1)
+        lipindvddbb2 = lay.bounds(mask=lipin.mask, net=dvdd, depth=1)
+
+        shape = _geo.Rect.from_rect(rect=nwmbb1, right=nwmbb2.right)
+        layouter.add_wire(net=dvdd, wire=nwm, shape=shape)
+
+        shape = _geo.Rect.from_rect(rect=lipindvssbb1, right=lipindvssbb2.right)
+        layouter.add_wire(net=dvss, wire=li, shape=shape)
+        w = tech.on_grid(shape.width, mult=2, rounding="floor")
+        h = tech.on_grid(shape.height, mult=2, rounding="floor")
+        o = tech.on_grid(shape.center)
+        lay = layouter.add_wire(
+            net=dvss, wire=mcon, origin=o, bottom_width=w, bottom_height=h,
+        )
+        dvss_midrowm1bb = lay.bounds(mask=m1.mask)
+
+        shape = _geo.Rect.from_rect(rect=lipindvddbb1, right=lipindvddbb2.right)
+        layouter.add_wire(net=dvdd, wire=li, shape=shape)
+        w = tech.on_grid(shape.width, mult=2, rounding="floor")
+        h = tech.on_grid(shape.height, mult=2, rounding="floor")
+        o = tech.on_grid(shape.center)
+        lay = layouter.add_wire(
+            net=dvdd, wire=mcon, origin=o, bottom_width=w, bottom_height=h,
+        )
+        dvdd_midrowm1bb = lay.bounds(mask=m1.mask)
+
+        assert dvss_leftrowm1bb.center.x > dvdd_leftrowm1bb.center.x, "Internal error"
+        assert dvss_rightrowm1bb.center.x > dvdd_rightrowm1bb.center.x, "Internal error"
+
+        shape = _geo.Rect.from_rect(
+            rect=dvss_midrowm1bb,
+            left=dvss_leftrowm1bb.left, right=dvdd_rightrowm1bb.left - 1.0,
+        )
+        layouter.add_wire(net=dvss, wire=m1, shape=shape)
+
+        w = shape.height
+        _via_lay = layouter.wire_layout(
+            net=dvss, wire=via, bottom_width=w, bottom_height=w,
+        )
+        _via_m1bb = _via_lay.bounds(mask=m1.mask)
+
+        y_via = shape.center.y
+        x_via = shape.right - _via_m1bb.right
+        lay = layouter.place(_via_lay, x=x_via, y=y_via)
+        m2bb1 = lay.bounds(mask=m2.mask)
+        x_via = dvss_rightrowm1bb.center.x
+        lay = layouter.place(_via_lay, x=x_via, y=y_via)
+        m2bb2 = lay.bounds(mask=m2.mask)
+
+        shape = _geo.Rect.from_rect(rect=m2bb1, right=m2bb2.right)
+        layouter.add_wire(net=dvss, wire=m2, shape=shape)
+
+        shape = _geo.Rect.from_rect(
+            rect=dvdd_midrowm1bb,
+            left=(dvss_leftrowm1bb.right + 1.0), right=dvdd_rightrowm1bb.right,
+        )
+        layouter.add_wire(net=dvdd, wire=m1, shape=shape)
+
+        w = shape.height
+        _via_lay = layouter.wire_layout(
+            net=dvdd, wire=via, bottom_width=w, bottom_height=w,
+        )
+        _via_m1bb = _via_lay.bounds(mask=m1.mask)
+
+        y_via = shape.center.y
+        x_via = shape.left - _via_m1bb.left
+        lay = layouter.place(_via_lay, x=x_via, y=y_via)
+        m2bb1 = lay.bounds(mask=m2.mask)
+        x_via = dvdd_leftrowm1bb.center.x
+        lay = layouter.place(_via_lay, x=x_via, y=y_via)
+        m2bb2 = lay.bounds(mask=m2.mask)
+
+        shape = _geo.Rect.from_rect(rect=m2bb1, left=m2bb2.left)
+        layouter.add_wire(net=dvdd, wire=m2, shape=shape)
+
+        # Connect the SRAM signals
+        #
         # vss
         spec = io_sig2spec["vss"]
-        net = nets[spec.toppin_name]
+        sram_port = sram.ports[spec.sram_signal]
+        net = ckt.new_net(name=spec.toppin_name, external=True, childports=sram_port)
         toppin_bb = _frm.toppins[spec.toppin_name]
         bbs = tuple(ms.shape.bounds for ms in sram_lay.filter_polygons(
             net=net, mask=m2pin.mask, depth=1, split=True,
@@ -209,7 +457,8 @@
 
         # vdd
         spec = io_sig2spec["vdd"]
-        net = nets[spec.toppin_name]
+        sram_port = sram.ports[spec.sram_signal]
+        net = ckt.new_net(name=spec.toppin_name, external=True, childports=sram_port)
         toppin_bb = _frm.toppins[spec.toppin_name]
         bbs = tuple(ms.shape.bounds for ms in sram_lay.filter_polygons(
             net=net, mask=m2pin.mask, depth=1, split=True,
@@ -241,83 +490,400 @@
         layouter.add_wire(net=net, wire=m3, shape=shape)
         layouter.add_wire(net=net, wire=m3, pin=m3pin, shape=toppin_bb)
 
-        # a
-        col = 0
-        w = 10.0
-        for a_bit in reversed(range(self.a_bits)):
-            spec = io_sig2spec[f"a[{a_bit}]"]
+        # connect the input signals
+        a_col = 0
+        for sig_name in (
+            *(f"a[{a_bit}]" for a_bit in reversed(range(self.a_bits))), # Reversed for a_col
+            "clk", "we[0]",
+            *(f"d[{bit}]" for bit in range(self.word_size)),
+        ):
+            spec = io_sig2spec[sig_name]
+            prefix = spec.prefix
+            num = spec.io_number
+
+            pin_name = spec.toppin_name
+            oeb_name = f"io_oeb[{num}]"
+            out_name = f"io_out[{num}]"
             assert spec.io_type == "io_in", "Internal error"
-            net = nets[spec.toppin_name]
+            assert spec.oeb, "Internal error"
+            sram_port = sram.ports[sig_name]
 
-            sram_m1pinbb = sram_lay.bounds(mask=m1pin.mask, net=net, depth=1)
-            toppin_bb = _frm.toppins[spec.toppin_name]
+            # instantiate cells
+            buf = ckt.instantiate(buf_cell, name="{prefix}buf")
+            one = ckt.instantiate(one_cell, name=f"{prefix}one")
+            zero = ckt.instantiate(zero_cell, name=f"{prefix}zero")
+            tie = ckt.instantiate(tie_cell, name=f"{prefix}tie")
 
-            right = sram_bb.left - (2*col + 1)*w
-            left = right - 1
-            col += 1
+            # create nets
+            pin_net = ckt.new_net(name=pin_name, external=True, childports=buf.ports.i)
+            sig_net = ckt.new_net(name=sig_name, external=False, childports=(
+                buf.ports.q, sram_port,
+            ))
+            oeb_net = ckt.new_net(
+                name=oeb_name, external=True, childports=one.ports.one,
+            )
+            out_net = ckt.new_net(
+                name=out_name, external=True, childports=zero.ports.zero,
+            )
 
-            x_via = right - w/2.0
-            y_via = tech.on_grid(sram_m1pinbb.center.y)
-            via_lay = layouter.add_wire(
-                net=net, wire=via, x=x_via, y=y_via,
+            # get bbs; SRAM m2 pin to m3 pin
+            toppin_bb = _frm.toppins[pin_name]
+            oeb_bb = _frm.toppins[oeb_name]
+            out_bb = _frm.toppins[out_name]
+            if sig_name.startswith("a["):
+                # Connect signal up to m2
+                sram_m1pinbb = sram_lay.bounds(mask=m1pin.mask, net=sig_net, depth=1)
+
+                w = 10.0
+                right = sram_bb.left - (2*a_col + 1)*w
+                left = right - 1
+                a_col += 1
+
+                x_via = right - w/2.0
+                y_via = tech.on_grid(sram_m1pinbb.center.y)
+                via_lay = layouter.add_wire(
+                    net=sig_net, wire=via, x=x_via, y=y_via,
+                    bottom_width=w, bottom_enclosure="wide",
+                    top_width=w, top_enclosure="wide",
+                )
+                via_m1bb = via_lay.bounds(mask=m1.mask)
+                sram_m2pinbb = via_lay.bounds(mask=m2.mask)
+
+                shape = _geo.Rect.from_rect(rect=sram_m1pinbb, left=via_m1bb.left)
+                layouter.add_wire(net=sig_net, wire=m1, shape=shape)
+            else:
+                sram_m2pinbb = sram_lay.bounds(mask=m2pin.mask, net=sig_net, depth=1)
+            is_leftrow = toppin_bb.center.x < sram_m2pinbb.center.x
+
+            rot = rot_leftrow if is_leftrow else rot_rightrow
+            x_row = x_leftrow if is_leftrow else x_rightrow
+
+            # place buf
+            _buf_rotilipinbb = rot*_buf_ilipinbb
+            y_buf = toppin_bb.top - _buf_rotilipinbb.bottom
+            buf_lay = layouter.place(buf, x=x_row, y=y_buf, rotation=rot)
+            pinbuf_lipinbb = buf_lay.bounds(mask=lipin.mask, net=pin_net, depth=1)
+            sigbuf_lipinbb = buf_lay.bounds(mask=lipin.mask, net=sig_net, depth=1)
+            buf_bb = buf_lay.boundary
+            assert buf_bb is not None
+
+            # place tie cell
+            _tie_rotbb = rot*_tie_bb
+            if is_leftrow:
+                y_tie = buf_bb.top - _tie_rotbb.bottom
+            else:
+                y_tie = buf_bb.bottom - _tie_rotbb.top
+            layouter.place(tie, x=x_row, y=y_tie, rotation=rot)
+
+            # place zero cell
+            _zero_rotbb = rot*_zero_bb
+            if is_leftrow:
+                y_zero = buf_bb.bottom - _zero_rotbb.top
+            else:
+                y_zero = buf_bb.top - _zero_rotbb.bottom
+            zero_lay = layouter.place(zero, x=x_row, y=y_zero, rotation=rot)
+            zero_bb = zero_lay.boundary
+            assert zero_bb is not None
+            zeroout_lipinbb = zero_lay.bounds(mask=lipin.mask, net=out_net, depth=1)
+
+            # place one cell
+            _one_rotbb = rot*_one_bb
+            if is_leftrow:
+                y_one = zero_bb.bottom - _one_rotbb.top
+            else:
+                y_one = zero_bb.top - _one_rotbb.bottom
+            one_lay = layouter.place(one, x=x_row, y=y_one, rotation=rot)
+            oneoeb_lipinbb = one_lay.bounds(mask=lipin.mask, net=oeb_net, depth=1)
+
+            # connect pin_net
+            w = pinbuf_lipinbb.width
+            x_via = pinbuf_lipinbb.center.x
+            y_via = pinbuf_lipinbb.center.y
+            layouter.add_wire(
+                net=pin_net, wire=mcon, x=x_via, y=y_via,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
-            via_m1bb = via_lay.bounds(mask=m1.mask)
+            layouter.add_wire(
+                net=pin_net, wire=via, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_lay = layouter.add_wire(
+                net=pin_net, wire=via2, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_m3bb = via2_lay.bounds(mask=m3.mask)
+
+            if is_leftrow:
+                shape = _geo.Rect.from_rect(rect=toppin_bb, right=via2_m3bb.right)
+            else:
+                shape = _geo.Rect.from_rect(rect=toppin_bb, left=via2_m3bb.left)
+            layouter.add_wire(net=pin_net, wire=m3, shape=shape)
+            layouter.add_wire(net=pin_net, wire=m3, pin=m3pin, shape=toppin_bb)
+
+            # connect sig_net
+            w = sigbuf_lipinbb.width
+            x_via = sigbuf_lipinbb.center.x
+            y_via = sigbuf_lipinbb.center.y
+            layouter.add_wire(
+                net=sig_net, wire=mcon, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            layouter.add_wire(
+                net=sig_net, wire=via, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_lay = layouter.add_wire(
+                net=sig_net, wire=via2, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_m3bb1 = via2_lay.bounds(mask=m3.mask)
+
+            _via2_lay = layouter.wire_layout(
+                net=sig_net, wire=via2, rows=6, columns=6,
+            )
+            _via2_m2bb = _via2_lay.bounds(mask=m2.mask)
+            if is_leftrow:
+                x_via2 = sram_m2pinbb.right - _via2_m2bb.right
+            else:
+                x_via2 = sram_m2pinbb.left - _via2_m2bb.left
+            y_via2 = via2_m3bb1.center.y
+            via2_lay = layouter.place(_via2_lay, x=x_via2, y=y_via2)
+            via2_m2bb = via2_lay.bounds(mask=m2.mask)
+            via2_m3bb2 = via2_lay.bounds(mask=m3.mask)
+
+            shape = _geo.Rect.from_rect(rect=sram_m2pinbb, bottom=via2_m2bb.bottom)
+            layouter.add_wire(net=sig_net, wire=m2, shape=shape)
+            if is_leftrow:
+                shape = _geo.Rect.from_rect(rect=via2_m3bb1, right=via2_m3bb2.right)
+            else:
+                shape = _geo.Rect.from_rect(rect=via2_m3bb1, left=via2_m3bb2.left)
+            layouter.add_wire(net=sig_net, wire=m3, shape=shape)
+
+            # connect oeb_net
+            w = oneoeb_lipinbb.width
+            x_via = oneoeb_lipinbb.center.x
+            y_via = oneoeb_lipinbb.center.y
+            layouter.add_wire(
+                net=oeb_net, wire=mcon, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via_lay = layouter.add_wire(
+                net=oeb_net, wire=via, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
             via_m2bb = via_lay.bounds(mask=m2.mask)
 
-            shape = _geo.Rect.from_rect(rect=sram_m1pinbb, left=via_m1bb.left)
-            layouter.add_wire(net=net, wire=m1, shape=shape)
-
-            x_via2 = x_via
-            y_via2 = toppin_bb.center.y
+            y_via2 = oeb_bb.center.y
             via2_lay = layouter.add_wire(
-                net=net, wire=via2, x=x_via2, y=y_via2,
+                net=oeb_net, wire=via2, x=x_via, y=y_via2,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
             via2_m2bb = via2_lay.bounds(mask=m2.mask)
             via2_m3bb = via2_lay.bounds(mask=m3.mask)
 
-            shape = _geo.Rect.from_rect(rect=via_m2bb, bottom=via2_m2bb.bottom)
-            layouter.add_wire(net=net, wire=m2, shape=shape)
-            shape = _geo.Rect.from_rect(rect=toppin_bb, right=via2_m3bb.right)
-            layouter.add_wire(net=net, wire=m3, shape=shape)
-            layouter.add_wire(net=net, wire=m3, pin=m3pin, shape=toppin_bb)
+            if is_leftrow:
+                shape = _geo.Rect.from_rect(rect=via_m2bb, bottom=via2_m2bb.bottom)
+            else:
+                shape = _geo.Rect.from_rect(rect=via_m2bb, top=via2_m2bb.top)
+            layouter.add_wire(net=oeb_net, wire=m2, shape=shape)
+            if is_leftrow:
+                shape = _geo.Rect.from_rect(rect=oeb_bb, right=via2_m3bb.right)
+            else:
+                shape = _geo.Rect.from_rect(rect=oeb_bb, left=via2_m3bb.left)
+            layouter.add_wire(net=oeb_net, wire=m3, shape=shape)
 
-        # The rest of the pin on m2
-        for sram_signame in (
-            "clk", "we[0]",
-            *(f"d[{bit}]" for bit in range(self.word_size)),
+            layouter.add_wire(net=oeb_net, wire=m3, pin=m3pin, shape=oeb_bb)
+
+            # connect out_net
+            w = zeroout_lipinbb.width
+            x_via = zeroout_lipinbb.center.x
+            y_via = zeroout_lipinbb.center.y
+            layouter.add_wire(
+                net=out_net, wire=mcon, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            layouter.add_wire(
+                net=out_net, wire=via, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_lay = layouter.add_wire(
+                net=out_net, wire=via2, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_m3bb = via2_lay.bounds(mask=m3.mask)
+
+            if is_leftrow:
+                shape = _geo.Rect.from_rect(rect=via2_m3bb, bottom=out_bb.bottom)
+            else:
+                shape = _geo.Rect.from_rect(rect=via2_m3bb, top=out_bb.top)
+            layouter.add_wire(net=out_net, wire=m3, shape=shape)
+            if is_leftrow:
+                shape = _geo.Rect.from_rect(rect=out_bb, right=via2_m3bb.right)
+            else:
+                shape = _geo.Rect.from_rect(rect=out_bb, left=via2_m3bb.left)
+            layouter.add_wire(net=out_net, wire=m3, shape=shape)
+
+            layouter.add_wire(net=out_net, wire=m3, pin=m3pin, shape=out_bb)
+
+        # connect the output signals
+        for sig_name in (
             *(f"q[{bit}]" for bit in range(self.word_size)),
         ):
-            spec = io_sig2spec[sram_signame]
-            net = nets[spec.toppin_name]
+            spec = io_sig2spec[sig_name]
+            prefix = spec.prefix
+            num = spec.io_number
 
-            sram_m2pinbb = sram_lay.bounds(mask=m2pin.mask, net=net, depth=1)
-            toppin_bb = _frm.toppins[spec.toppin_name]
+            pin_name = spec.toppin_name
+            oeb_name = f"io_oeb[{num}]"
+            assert spec.io_type == "io_out", "Internal error"
+            assert not spec.oeb, "Internal error"
+            sram_port = sram.ports[spec.sram_signal]
+
+            # instantiate cells
+            buf = ckt.instantiate(buf_cell, name="{prefix}buf")
+            zero = ckt.instantiate(zero_cell, name=f"{prefix}zero")
+            tie = ckt.instantiate(tie_cell, name=f"{prefix}tie")
+
+            # create nets
+            pin_net = ckt.new_net(name=pin_name, external=True, childports=buf.ports.q)
+            sig_net = ckt.new_net(name=sig_name, external=False, childports=(
+                buf.ports.i, sram_port,
+            ))
+            oeb_net = ckt.new_net(
+                name=oeb_name, external=True, childports=zero.ports.zero,
+            )
+
+            # get bss
+            toppin_bb = _frm.toppins[pin_name]
+            oeb_bb = _frm.toppins[oeb_name]
+            sram_m2pinbb = sram_lay.bounds(mask=m2pin.mask, net=sig_net, depth=1)
+
+            is_leftrow = toppin_bb.center.x < sram_m2pinbb.center.x
+
+            # place buf
+            rot = rot_midrow
+            y_row = y_midrow
+            _buf_rotilipinbb = rot*_buf_ilipinbb
+            x_buf = sram_m2pinbb.right - _buf_rotilipinbb.left
+            buf_lay = layouter.place(buf, x=x_buf, y=y_row, rotation=rot)
+            pinbuf_lipinbb = buf_lay.bounds(mask=lipin.mask, net=pin_net, depth=1)
+            sigbuf_lipinbb = buf_lay.bounds(mask=lipin.mask, net=sig_net, depth=1)
+            buf_bb = buf_lay.boundary
+            assert buf_bb is not None
+
+            # place zero
+            rot = rot_leftrow if is_leftrow else rot_rightrow
+            x_row = x_leftrow if is_leftrow else x_rightrow
+            _zero_rotzerolipinbb = rot*_zero_zerolipinbb
+            y_zero = oeb_bb.center.y - _zero_rotzerolipinbb.center.y
+            zero_lay = layouter.place(zero, x=x_row, y=y_zero, rotation=rot)
+            zero_zerolipinbb = zero_lay.bounds(mask=lipin.mask, net=oeb_net, depth=1)
+            zero_bb = zero_lay.boundary
+            assert zero_bb is not None
+
+            # place tie
+            _tie_rotbb = rot*_tie_bb
+            y_tie = zero_bb.top - _tie_rotbb.bottom
+            layouter.place(tie, x=x_row, y=y_tie, rotation=rot)
+
+            # connect sig_net
+            h = sigbuf_lipinbb.height
+            x_via = sigbuf_lipinbb.center.x
+            y_via = sigbuf_lipinbb.center.y
+            layouter.add_wire(
+                net=sig_net, wire=mcon, x=x_via, y=y_via,
+                bottom_height=h, bottom_enclosure="tall",
+                top_height=h, top_enclosure="tall",
+            )
+            via_lay = layouter.add_wire(
+                net=sig_net, wire=via, x=x_via, y=y_via,
+                bottom_height=h, bottom_enclosure="tall",
+                top_height=h, top_enclosure="tall",
+            )
+            via_m2bb = via_lay.bounds(mask=m2.mask)
+
+            shape = _geo.Rect.from_rect(rect=sram_m2pinbb, bottom=via_m2bb.bottom)
+            layouter.add_wire(net=sig_net, wire=m2, shape=shape)
+
+            # connect pin_net
+            h = pinbuf_lipinbb.height
+            x_via = pinbuf_lipinbb.center.x
+            y_via = pinbuf_lipinbb.center.y
+
+            layouter.add_wire(
+                net=sig_net, wire=mcon, x=x_via, y=y_via,
+                bottom_height=h, bottom_enclosure="tall",
+                top_height=h, top_enclosure="tall",
+            )
+            via_lay = layouter.add_wire(
+                net=sig_net, wire=via, x=x_via, y=y_via,
+                bottom_height=h, bottom_enclosure="tall",
+                top_height=h, top_enclosure="tall",
+            )
+            via_m2bb = via_lay.bounds(mask=m2.mask)
 
             _via2_lay = layouter.wire_layout(
-                net=net, wire=via2, rows=6, columns=6,
+                net=pin_net, wire=via2, rows=6, columns=6,
             )
             _via2_m2bb = _via2_lay.bounds(mask=m2.mask)
-            if toppin_bb.center.x > sram_m2pinbb.center.x:
-                x_via2 = sram_m2pinbb.left - _via2_m2bb.left
+            if is_leftrow:
+                x_via2 = via_m2bb.right - _via2_m2bb.right
             else:
-                x_via2 = sram_m2pinbb.right - _via2_m2bb.right
+                x_via2 = via_m2bb.left - _via2_m2bb.left
             y_via2 = toppin_bb.center.y
             via2_lay = layouter.place(_via2_lay, x=x_via2, y=y_via2)
             via2_m2bb = via2_lay.bounds(mask=m2.mask)
             via2_m3bb = via2_lay.bounds(mask=m3.mask)
 
-            shape = _geo.Rect.from_rect(rect=sram_m2pinbb, bottom=via2_m2bb.bottom)
-            layouter.add_wire(net=net, wire=m2, shape=shape)
-            if toppin_bb.center.x > sram_m2pinbb.center.x:
-                shape = _geo.Rect.from_rect(rect=toppin_bb, left=via2_m3bb.left)
-            else:
+            shape = _geo.Rect.from_rect(rect=via_m2bb, bottom=via2_m2bb.bottom)
+            layouter.add_wire(net=pin_net, wire=m2, shape=shape)
+            if is_leftrow:
                 shape = _geo.Rect.from_rect(rect=toppin_bb, right=via2_m3bb.right)
-            layouter.add_wire(net=net, wire=m3, shape=shape)
-            layouter.add_wire(net=net, wire=m3, pin=m3pin, shape=toppin_bb)
+            else:
+                shape = _geo.Rect.from_rect(rect=toppin_bb, left=via2_m3bb.left)
+            layouter.add_wire(net=pin_net, wire=m3, shape=shape)
+            layouter.add_wire(net=pin_net, wire=m3, pin=m3pin, shape=toppin_bb)
+
+            # connect oeb_net
+            w = zero_zerolipinbb.width
+            x_via = zero_zerolipinbb.center.x
+            y_via = zero_zerolipinbb.center.y
+            layouter.add_wire(
+                net=oeb_net, wire=mcon, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            layouter.add_wire(
+                net=oeb_net, wire=via, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_lay = layouter.add_wire(
+                net=oeb_net, wire=via2, x=x_via, y=y_via,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+            via2_m3bb = via2_lay.bounds(mask=m3.mask)
+
+            if is_leftrow:
+                shape = _geo.Rect.from_rect(rect=oeb_bb, right=via2_m3bb.right)
+            else:
+                shape = _geo.Rect.from_rect(rect=oeb_bb, left=via2_m3bb.left)
+            layouter.add_wire(net=oeb_net, wire=m3, shape=shape)
+            layouter.add_wire(net=oeb_net, wire=m3, pin=m3pin, shape=oeb_bb)
 
         # boundary
+        #
         layout.boundary = _frm.boundary
diff --git a/gds/user_analog_project_wrapper.gds.gz b/gds/user_analog_project_wrapper.gds.gz
index 0a228d0..9d084bf 100644
--- a/gds/user_analog_project_wrapper.gds.gz
+++ b/gds/user_analog_project_wrapper.gds.gz
Binary files differ