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