Fix DRC errors and connect ESD clamp to SRAM vdd/vss
diff --git a/doitcode/frame.py b/doitcode/frame.py
index 8b06584..9bf5d39 100644
--- a/doitcode/frame.py
+++ b/doitcode/frame.py
@@ -83,8 +83,14 @@
     "io_analog[2]": _geo.Rect(left=2326.97, bottom=3511.50, right=2351.97, top=3524.00),
     "io_analog[3]": _geo.Rect(left=2066.97, bottom=3511.50, right=2091.97, top=3524.00),
     "io_analog[4]": _geo.Rect(left=1594.97, bottom=3511.50, right=1619.97, top=3524.00),
+    "io_clamp_low[0]": _geo.Rect(left=1621.47, bottom=3511.50, right=1632.47, top=3524.00),
+    "io_clamp_high[0]": _geo.Rect(left=1633.97, bottom=3511.50, right=1644.97, top=3524.00),
     "io_analog[5]": _geo.Rect(left=1086.47, bottom=3511.50, right=1111.47, top=3524.00),
+    "io_clamp_low[1]": _geo.Rect(left=1112.97, bottom=3511.50, right=1123.97, top=3524.00),
+    "io_clamp_high[1]": _geo.Rect(left=1125.47, bottom=3511.50, right=1136.47, top=3524.00),
     "io_analog[6]": _geo.Rect(left=827.97, bottom=3511.50, right=852.97, top=3524.00),
+    "io_clamp_low[2]": _geo.Rect(left=854.47, bottom=3511.50, right=865.47, top=3524.00),
+    "io_clamp_high[2]": _geo.Rect(left=866.97, bottom=3511.50, right=877.97, top=3524.00),
     "io_analog[7]": _geo.Rect(left=600.97, bottom=3511.50, right=625.97, top=3524.00),
     "io_analog[8]": _geo.Rect(left=340.97, bottom=3511.50, right=365.97, top=3524.00),
     "io_analog[9]": _geo.Rect(left=80.97, bottom=3511.50, right=105.97, top=3524.00),
diff --git a/doitcode/sram.py b/doitcode/sram.py
index 86edfb7..b0ddb51 100644
--- a/doitcode/sram.py
+++ b/doitcode/sram.py
@@ -84,8 +84,8 @@
     _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),
-    _io_spec(sram_signal="vdd", io_type="io_analog", io_number=5),
+    _io_spec(sram_signal="vdd", io_type="io_analog", io_number=4),
+    _io_spec(sram_signal="vss", io_type="io_analog", io_number=5),
 )
 io_sig2spec = {
     spec.sram_signal: spec
@@ -271,10 +271,10 @@
         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
+        w = tech.on_grid(dvss_rightrowm1bb.width, mult=2, rounding="floor")
+        h = tech.on_grid(dvss_bb.height, mult=2, rounding="floor")
+        x_via = tech.on_grid(dvss_rightrowm1bb.center.x)
+        y_via = tech.on_grid(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,
@@ -301,10 +301,10 @@
         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
+        w = tech.on_grid(dvdd_rightrowm1bb.width, mult=2, rounding="floor")
+        h = tech.on_grid(dvdd_bb.height, mult=2, rounding="floor")
+        x_via = tech.on_grid(dvdd_rightrowm1bb.center.x)
+        y_via = tech.on_grid(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,
@@ -428,41 +428,6 @@
         bbs = tuple(ms.shape.bounds for ms in sram_lay.filter_polygons(
             net=net, mask=m2pin.mask, depth=1, split=True,
         ))
-        right = min(bb.right for bb in bbs)
-        top = max(bb.top for bb in bbs)
-        bottom = min(bb.bottom for bb in bbs)
-        w = 10.0
-        x_via2 = right - w/2.0
-        left = right - w
-
-        for bb in bbs:
-            y_via2 = bb.center.y
-            layouter.add_wire(
-                net=net, wire=via2, x=x_via2, y=y_via2,
-                bottom_width=w, bottom_enclosure="wide",
-                top_width=w, top_enclosure="wide",
-            )
-
-        shape = _geo.Rect(
-            left=left, bottom=bottom, right=right, top=(top + 20.0),
-        )
-        layouter.add_wire(net=net, wire=m3, shape=shape)
-        shape = _geo.Rect(
-            left=left, bottom=(top + 10.0), right=toppin_bb.right, top=(top+20.0),
-        )
-        layouter.add_wire(net=net, wire=m3, shape=shape)
-        shape = _geo.Rect.from_rect(rect=toppin_bb, bottom=(top + 10.0))
-        layouter.add_wire(net=net, wire=m3, shape=shape)
-        layouter.add_wire(net=net, wire=m3, pin=m3pin, shape=toppin_bb)
-
-        # vdd
-        spec = io_sig2spec["vdd"]
-        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,
-        ))
         left = max(bb.left for bb in bbs)
         top = max(bb.top for bb in bbs)
         bottom = min(bb.bottom for bb in bbs)
@@ -490,6 +455,57 @@
         layouter.add_wire(net=net, wire=m3, shape=shape)
         layouter.add_wire(net=net, wire=m3, pin=m3pin, shape=toppin_bb)
 
+        # io_clamp_low
+        clamp_bb = _frm.toppins["io_clamp_low[1]"]
+        shape = _geo.Rect.from_rect(rect=clamp_bb, bottom=(top + 10))
+        layouter.add_wire(net=net, wire=m3, shape=shape)
+
+        # vdd
+        spec = io_sig2spec["vdd"]
+        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,
+        ))
+        right = min(bb.right for bb in bbs)
+        top = max(bb.top for bb in bbs)
+        bottom = min(bb.bottom for bb in bbs)
+        w = 10.0
+        x_via2 = right - w/2.0
+        left = right - w
+
+        for bb in bbs:
+            y_via2 = bb.center.y
+            layouter.add_wire(
+                net=net, wire=via2, x=x_via2, y=y_via2,
+                bottom_width=w, bottom_enclosure="wide",
+                top_width=w, top_enclosure="wide",
+            )
+
+        shape = _geo.Rect(
+            left=left, bottom=bottom, right=right, top=(top + 20.0),
+        )
+        layouter.add_wire(net=net, wire=m3, shape=shape)
+        shape = _geo.Rect(
+            left=left, bottom=(top + 10.0), right=toppin_bb.right, top=(top + 20.0),
+        )
+        layouter.add_wire(net=net, wire=m3, shape=shape)
+        shape = _geo.Rect.from_rect(rect=toppin_bb, bottom=(top + 10.0))
+        layouter.add_wire(net=net, wire=m3, shape=shape)
+        layouter.add_wire(net=net, wire=m3, pin=m3pin, shape=toppin_bb)
+
+        # io_clamp_high
+        clamp_bb = _frm.toppins["io_clamp_high[1]"]
+        w = clamp_bb.width
+        shape = _geo.Rect.from_rect(rect=clamp_bb, bottom=(clamp_bb.bottom - 2*w))
+        layouter.add_wire(net=net, wire=m3, shape=shape)
+        shape = _geo.Rect(
+            left=clamp_bb.left, bottom=(clamp_bb.bottom - 2*w),
+            right=toppin_bb.right, top=(clamp_bb.bottom - w)
+        )
+        layouter.add_wire(net=net, wire=m3, shape=shape)
+
         # connect the input signals
         a_col = 0
         for sig_name in (
@@ -560,7 +576,10 @@
 
             # place buf
             _buf_rotilipinbb = rot*_buf_ilipinbb
-            y_buf = toppin_bb.top - _buf_rotilipinbb.bottom
+            y_buf = tech.on_grid(
+                toppin_bb.top - _buf_rotilipinbb.bottom,
+                mult=2,
+            )
             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)
@@ -596,21 +615,20 @@
             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
+            w = tech.on_grid(pinbuf_lipinbb.width, mult=2, rounding="floor")
+            o_via = tech.on_grid(pinbuf_lipinbb.center)
             layouter.add_wire(
-                net=pin_net, wire=mcon, x=x_via, y=y_via,
+                net=pin_net, wire=mcon, origin=o_via,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
             layouter.add_wire(
-                net=pin_net, wire=via, x=x_via, y=y_via,
+                net=pin_net, wire=via, origin=o_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,
+                net=pin_net, wire=via2, origin=o_via,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
@@ -624,28 +642,27 @@
             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
+            w = tech.on_grid(sigbuf_lipinbb.width, mult=2, rounding="floor")
+            o_via = tech.on_grid(sigbuf_lipinbb.center)
             layouter.add_wire(
-                net=sig_net, wire=mcon, x=x_via, y=y_via,
+                net=sig_net, wire=mcon, origin=o_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,
+                net=sig_net, wire=via, origin=o_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,
+                net=sig_net, wire=via2, origin=o_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,
+                net=sig_net, wire=via2, rows=6, columns=3,
             )
             _via2_m2bb = _via2_lay.bounds(mask=m2.mask)
             if is_leftrow:
@@ -666,24 +683,23 @@
             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
+            w = tech.on_grid(oneoeb_lipinbb.width, mult=2, rounding="floor")
+            o_via = tech.on_grid(oneoeb_lipinbb.center)
             layouter.add_wire(
-                net=oeb_net, wire=mcon, x=x_via, y=y_via,
+                net=oeb_net, wire=mcon, origin=o_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,
+                net=oeb_net, wire=via, origin=o_via,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
             via_m2bb = via_lay.bounds(mask=m2.mask)
 
-            y_via2 = oeb_bb.center.y
+            o_via2 = _geo.Point.from_point(point=o_via, y=oeb_bb.center.y)
             via2_lay = layouter.add_wire(
-                net=oeb_net, wire=via2, x=x_via, y=y_via2,
+                net=oeb_net, wire=via2, origin=o_via2,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
@@ -704,21 +720,20 @@
             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
+            w = tech.on_grid(zeroout_lipinbb.width, mult=2, rounding="floor")
+            o_via = tech.on_grid(zeroout_lipinbb.center)
             layouter.add_wire(
-                net=out_net, wire=mcon, x=x_via, y=y_via,
+                net=out_net, wire=mcon, origin=o_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,
+                net=out_net, wire=via, origin=o_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,
+                net=out_net, wire=via2, origin=o_via,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
@@ -776,7 +791,10 @@
             rot = rot_midrow
             y_row = y_midrow
             _buf_rotilipinbb = rot*_buf_ilipinbb
-            x_buf = sram_m2pinbb.right - _buf_rotilipinbb.left
+            x_buf = tech.on_grid(
+                sram_m2pinbb.right - _buf_rotilipinbb.left,
+                mult=2, rounding="ceiling",
+            )
             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)
@@ -799,16 +817,15 @@
             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
+            h = tech.on_grid(sigbuf_lipinbb.height, mult=2, rounding="floor")
+            o_via = tech.on_grid(sigbuf_lipinbb.center)
             layouter.add_wire(
-                net=sig_net, wire=mcon, x=x_via, y=y_via,
+                net=sig_net, wire=mcon, origin=o_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,
+                net=sig_net, wire=via, origin=o_via,
                 bottom_height=h, bottom_enclosure="tall",
                 top_height=h, top_enclosure="tall",
             )
@@ -818,24 +835,23 @@
             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
+            h = tech.on_grid(pinbuf_lipinbb.height, mult=2, rounding="floor")
+            o_via = tech.on_grid(pinbuf_lipinbb.center)
 
             layouter.add_wire(
-                net=sig_net, wire=mcon, x=x_via, y=y_via,
+                net=sig_net, wire=mcon, origin=o_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,
+                net=sig_net, wire=via, origin=o_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=pin_net, wire=via2, rows=6, columns=6,
+                net=pin_net, wire=via2, rows=6, columns=3,
             )
             _via2_m2bb = _via2_lay.bounds(mask=m2.mask)
             if is_leftrow:
@@ -857,21 +873,20 @@
             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
+            w = tech.on_grid(zero_zerolipinbb.width, mult=2, rounding="floor")
+            o_via = tech.on_grid(zero_zerolipinbb.center)
             layouter.add_wire(
-                net=oeb_net, wire=mcon, x=x_via, y=y_via,
+                net=oeb_net, wire=mcon, origin=o_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,
+                net=oeb_net, wire=via, origin=o_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,
+                net=oeb_net, wire=via2, origin=o_via,
                 bottom_width=w, bottom_enclosure="wide",
                 top_width=w, top_enclosure="wide",
             )
diff --git a/gds/user_analog_project_wrapper.gds.gz b/gds/user_analog_project_wrapper.gds.gz
index 9d084bf..e6b360b 100644
--- a/gds/user_analog_project_wrapper.gds.gz
+++ b/gds/user_analog_project_wrapper.gds.gz
Binary files differ