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