First trial with dual port SRAM added.
diff --git a/doitcode/sram.py b/doitcode/sram.py
index afcdc78..24bac9b 100644
--- a/doitcode/sram.py
+++ b/doitcode/sram.py
@@ -105,7 +105,8 @@
 
         stdcells = sky130.stdcelllib.cells
 
-        mem_fab = sky130.Sky130SP6TFactory(lib=self.lib)
+        spmem_fab = sky130.Sky130SP6TFactory(lib=self.lib)
+        dpmem_fab = sky130.Sky130DP8TFactory(lib=self.lib)
 
         nwm = cast(_prm.Well, prims.nwm)
         li = cast(_prm.MetalWire, prims.li)
@@ -142,11 +143,18 @@
         _tie_bb = tie_cell.layout.boundary
         assert _tie_bb is not None
 
-        sram_cell = mem_fab.block(
-            address_groups=(3, 4, 2), word_size=8, we_size=1, cell_name="512x8",
+        word_size = 8
+        we_size = 1
+        address_groups = (3, 4, 2)
+        a_bits = sum(address_groups)
+        spsram_cell = spmem_fab.block(
+            address_groups=(3, 4, 2), word_size=word_size, we_size=we_size,
+            cell_name="512x8",
         )
-        self.a_bits = sram_cell.a_bits
-        self.word_size = sram_cell.word_size
+        dpsram_cell = dpmem_fab.block(
+            address_groups=(3, 4, 2), word_size=word_size, we_size=we_size,
+            cell_name="512x8",
+        )
 
         ckt = self.new_circuit()
         layouter = self.new_circuitlayouter()
@@ -167,18 +175,26 @@
         # Place the SRAM
         #
         # instantiate
-        sram = ckt.instantiate(sram_cell, name="sram")
+        spsram = ckt.instantiate(spsram_cell, name="sram")
+        dpsram = ckt.instantiate(dpsram_cell, name="sram")
 
         # place
-        _sram_lay = layouter.inst_layout(inst=sram)
-        _sram_bb = _sram_lay.boundary
-        assert _sram_bb is not None
+        _spsram_lay = layouter.inst_layout(inst=spsram)
+        _spsram_bb = _spsram_lay.boundary
+        assert _spsram_bb is not None
+        _dpsram_lay = layouter.inst_layout(inst=dpsram)
+        _dpsram_bb = _dpsram_lay.boundary
+        assert _dpsram_bb is not None
 
-        x = sky130.tech.on_grid(_frm.boundary.center.x - _sram_bb.center.x)
-        y = _frm.boundary.top - 100.0 - _sram_bb.top
-        sram_lay = layouter.place(_sram_lay, x=x, y=y)
-        sram_bb = sram_lay.boundary
-        assert sram_bb is not None
+        x = sky130.tech.on_grid(_frm.boundary.center.x - _spsram_bb.center.x)
+        y = _frm.boundary.top - 100.0 - _spsram_bb.top
+        spsram_lay = layouter.place(_spsram_lay, x=x, y=y)
+        spsram_bb = spsram_lay.boundary
+        assert spsram_bb is not None
+        x = spsram_bb.right + 100.0
+        dpsram_lay = layouter.place(_dpsram_lay, x=x, y=y)
+        dpsram_bb = dpsram_lay.boundary
+        assert dpsram_bb is not None
 
 
         # Make three rows of to place standard cells in
@@ -326,13 +342,13 @@
         rot_midrow = _geo.Rotation.R0
         _tie_rotbb = rot_midrow*_tie_bb
 
-        y_midrow = sram_bb.bottom - dbound - _tie_rotbb.top
+        y_midrow = spsram_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
+        x_tie = spsram_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)
@@ -342,7 +358,7 @@
         dvss.childports += inst.ports.vss
         dvdd.childports += inst.ports.vdd
 
-        x_tie = sram_bb.right - _tie_rotbb.right
+        x_tie = spsram_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)
@@ -424,10 +440,10 @@
         #
         # vss
         spec = io_sig2spec["vss"]
-        sram_port = sram.ports[spec.sram_signal]
+        sram_port = spsram.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(
+        bbs = tuple(ms.shape.bounds for ms in spsram_lay.filter_polygons(
             net=net, mask=m2pin.mask, depth=1, split=True,
         ))
         left = max(bb.left for bb in bbs)
@@ -464,10 +480,10 @@
 
         # vdd
         spec = io_sig2spec["vdd"]
-        sram_port = sram.ports[spec.sram_signal]
+        sram_port = spsram.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(
+        bbs = tuple(ms.shape.bounds for ms in spsram_lay.filter_polygons(
             net=net, mask=m2pin.mask, depth=1, split=True,
         ))
         right = min(bb.right for bb in bbs)
@@ -511,9 +527,9 @@
         # 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
+            *(f"a[{a_bit}]" for a_bit in reversed(range(a_bits))), # Reversed for a_col
             "clk", "we[0]",
-            *(f"d[{bit}]" for bit in range(self.word_size)),
+            *(f"d[{bit}]" for bit in range(word_size)),
         ):
             spec = io_sig2spec[sig_name]
             prefix = spec.prefix
@@ -524,7 +540,7 @@
             out_name = f"io_out[{num}]"
             assert spec.io_type == "io_in", "Internal error"
             assert spec.oeb, "Internal error"
-            sram_port = sram.ports[sig_name]
+            sram_port = spsram.ports[sig_name]
 
             # instantiate cells
             buf = ckt.instantiate(buf_cell, name="{prefix}buf")
@@ -550,10 +566,10 @@
             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)
+                sram_m1pinbb = spsram_lay.bounds(mask=m1pin.mask, net=sig_net, depth=1)
 
                 w = 10.0
-                right = sram_bb.left - (2*a_col + 1)*w
+                right = spsram_bb.left - (2*a_col + 1)*w
                 left = right - 1
                 a_col += 1
 
@@ -570,7 +586,7 @@
                 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)
+                sram_m2pinbb = spsram_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
@@ -756,7 +772,7 @@
 
         # connect the output signals
         for sig_name in (
-            *(f"q[{bit}]" for bit in range(self.word_size)),
+            *(f"q[{bit}]" for bit in range(word_size)),
         ):
             spec = io_sig2spec[sig_name]
             prefix = spec.prefix
@@ -766,7 +782,7 @@
             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]
+            sram_port = spsram.ports[spec.sram_signal]
 
             # instantiate cells
             buf = ckt.instantiate(buf_cell, name="{prefix}buf")
@@ -785,7 +801,7 @@
             # 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)
+            sram_m2pinbb = spsram_lay.bounds(mask=m2pin.mask, net=sig_net, depth=1)
 
             is_leftrow = toppin_bb.center.x < sram_m2pinbb.center.x
 
diff --git a/gds/user_analog_project_wrapper.gds.gz b/gds/user_analog_project_wrapper.gds.gz
index e0c643f..e410f8a 100644
--- a/gds/user_analog_project_wrapper.gds.gz
+++ b/gds/user_analog_project_wrapper.gds.gz
Binary files differ