Add 3.3V bandgap.
diff --git a/doitcode/bandgap.py b/doitcode/bandgap.py
new file mode 100644
index 0000000..3176dfc
--- /dev/null
+++ b/doitcode/bandgap.py
@@ -0,0 +1,747 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+import sys
+from termios import TIOCPKT_FLUSHREAD
+from typing import List, Tuple, cast
+
+from pdkmaster.technology import geometry as _geo, primitive as _prm
+from pdkmaster.design import circuit as _ckt, layout as _lay, library as _lbry
+
+from c4m.pdk import sky130
+_prims = sky130.tech.primitives
+
+from . import frame as _frm
+
+
+__all__ = ["ConnectedBandGap"]
+
+
+class _BandGap3V3(_lbry._OnDemandCell[_lbry.Library]):
+ def __init__(self, *, lib: _lbry.Library):
+ super().__init__(lib=lib, name="BandGap3V3")
+
+ def _create_circuit(self):
+ ckt = self.new_circuit()
+
+ ln = 2.0
+ wn = 3.7
+ lp = 2.0
+ wp = 18
+
+ res1_h = 11.5
+ res2_h = 20.0
+ self.res2_n = res2_n = 7
+
+ self.pnp_ratio = pnp_ratio = 4
+
+ nmos = cast(_prm.MOSFET, _prims.nfet_g5v0d10v5)
+ pmos = cast(_prm.MOSFET, _prims.pfet_g5v0d10v5)
+ res = cast(_prm.Resistor, _prims.poly_res)
+
+ p1 = ckt.instantiate(pmos, name="p1", l=lp, w=wp)
+ p2 = ckt.instantiate(pmos, name="p2", l=lp, w=wp)
+ p3 = ckt.instantiate(pmos, name="p3", l=lp, w=wp)
+ ps = (p1, p2, p3)
+
+ n1 = ckt.instantiate(nmos, name="n1", l=ln, w=wn)
+ n2 = ckt.instantiate(nmos, name="n2", l=ln, w=wn)
+ ns = (n1, n2)
+
+ res1 = ckt.instantiate(res, name="res1", height=res1_h)
+ res2s = tuple(
+ ckt.instantiate(res, name=f"res2[{n}]", height=res2_h)
+ for n in range(res2_n)
+ )
+
+ pnp_cell = sky130.macrolib.cells["PNP_05v5_W3u40L3u40"]
+ pnp1 = ckt.instantiate(pnp_cell, name="pnp1")
+ pnp2s = tuple(
+ ckt.instantiate(pnp_cell, name=f"pnp2[{n}]")
+ for n in range(pnp_ratio)
+ )
+ pnp3s = tuple(
+ ckt.instantiate(pnp_cell, name=f"pnp3[{n}]")
+ for n in range(pnp_ratio)
+ )
+ pnps = (pnp1, *pnp2s, *pnp3s)
+
+ ckt.new_net(name="vss", external=True, childports=(
+ *(n.ports.bulk for n in ns),
+ *(pnp.ports.base for pnp in pnps),
+ *(pnp.ports.collector for pnp in pnps),
+ ))
+ ckt.new_net(name="vdd", external=True, childports=(
+ *(p.ports.sourcedrain1 for p in ps),
+ *(p.ports.bulk for p in ps),
+ ))
+ ckt.new_net(name="vref", external=True, childports=(
+ p3.ports.sourcedrain2, res2s[-1].ports.port2,
+ ))
+
+ ckt.new_net(name="p_gate", external=False, childports=(
+ *(p.ports.gate for p in ps),
+ p2.ports.sourcedrain2, n2.ports.sourcedrain2,
+ ))
+ ckt.new_net(name="n_gate", external=False, childports=(
+ *(n.ports.gate for n in ns),
+ n1.ports.sourcedrain2, p1.ports.sourcedrain2,
+ ))
+ ckt.new_net(name="vq1", external=False, childports=(
+ pnp1.ports.emitter, n1.ports.sourcedrain1,
+ ))
+ ckt.new_net(name="vq2", external=False, childports=(
+ *(pnp2.ports.emitter for pnp2 in pnp2s), res1.ports.port1,
+ ))
+ ckt.new_net(name="vq2r1", external=False, childports=(
+ res1.ports.port2, n2.ports.sourcedrain1,
+ ))
+ ckt.new_net(name="vq3", external=False, childports=(
+ *(pnp3.ports.emitter for pnp3 in pnp3s), res2s[0].ports.port1,
+ ))
+
+ for n in range(res2_n - 1):
+ res2_1 = res2s[n]
+ res2_2 = res2s[n + 1]
+ ckt.new_net(name=f"res2_{n}", external=False, childports=(
+ res2_1.ports.port2, res2_2.ports.port1,
+ ))
+
+ def _create_layout(self):
+ tech = self.tech
+
+ # We don't try to optimize area for this circuit yet.
+ ckt = self.circuit
+ nets = ckt.nets
+ insts = ckt.instances
+
+ nwm = cast(_prm.Well, _prims.nwm)
+ difftap = cast(_prm.WaferWire, _prims.difftap)
+ nsdm = cast(_prm.Implant, _prims.nsdm)
+ psdm = cast(_prm.Implant, _prims.psdm)
+ hvi = cast(_prm.Insulator, _prims.hvi)
+ poly = cast(_prm.GateWire, _prims.poly)
+ licon = cast(_prm.Via, _prims.licon)
+ li = cast(_prm.MetalWire, _prims.li)
+ assert li.pin is not None
+ lipin = li.pin[0]
+ mcon = cast(_prm.Via, _prims.mcon)
+ m1 = cast(_prm.MetalWire, _prims.m1)
+ assert m1.pin is not None
+ m1pin = m1.pin[0]
+ via1 = cast(_prm.Via, _prims.via)
+ m2 = cast(_prm.MetalWire, _prims.m2)
+ assert m2.pin is not None
+ bnd = cast(_prm.Auxiliary, _prims.prBoundary)
+
+ layouter = self.new_circuitlayouter()
+ layout = layouter.layout
+
+ # place res1
+ _res1 = layouter.inst_layout(inst=insts.res1, rotation=_geo.Rotation.MX)
+ _bb = _res1.bounds()
+ x = -1.0 - _bb.right
+ y = 20.0 - _bb.top
+ res1_lay = layouter.place(insts.res1, x=x, y=y)
+ res1vq2_libb = res1_lay.bounds(net=nets.vq2, mask=li.mask)
+ res1vq2r1_libb = res1_lay.bounds(net=nets.vq2r1, mask=li.mask)
+
+ # place bipolars
+ pnp1 = cast(_ckt._CellInstance, insts.pnp1)
+ pnp2s = tuple(
+ cast(_ckt._CellInstance, insts[f"pnp2[{n}]"])
+ for n in range(self.pnp_ratio)
+ )
+ pnp3s = tuple(
+ cast(_ckt._CellInstance, insts[f"pnp3[{n}]"])
+ for n in range(self.pnp_ratio)
+ )
+
+ _pnp1_bb = pnp1.cell.layout.boundary
+ assert _pnp1_bb is not None
+
+ x0_pnp = -_pnp1_bb.left
+ y0_pnp = -_pnp1_bb.bottom
+ dx_pnp = _pnp1_bb.width
+ dy_pnp = _pnp1_bb.height
+
+ assert self.pnp_ratio == 4, "Internal error"
+ inst_matrix = (
+ (pnp2s[0], pnp2s[1], pnp3s[0]),
+ (pnp3s[1], pnp1, pnp3s[2]),
+ (pnp3s[3], pnp2s[2], pnp2s[3]),
+ )
+ lay_matrix: List[Tuple[_lay._Layout, _lay._Layout, _lay._Layout]] = []
+ for row in range(3):
+ row_lays: List[_lay._Layout] = []
+ y = y0_pnp + row*dy_pnp
+ for col in range(3):
+ x = x0_pnp + col*dx_pnp
+ inst = inst_matrix[row][col]
+ row_lays.append(layouter.place(inst, x=x, y=y))
+ lay_matrix.append(tuple(row_lays))
+
+ # vss connection to the bipolars
+ right = 0.0
+ top = 0.0
+ for ms in lay_matrix[0][0].filter_polygons(
+ net=nets.vss, mask=lipin.mask, split=True
+ ):
+ shape = ms.shape
+ right = max(right, shape.bounds.left)
+ top = max(top, shape.bounds.bottom)
+
+ shape = _geo.Rect(left=0.0, bottom=0.0, right=3*dx_pnp, top=top)
+ layouter.add_wire(net=nets.vss, wire=li, pin=lipin, shape=shape)
+ shape = _geo.Rect(
+ left=0.0, bottom=(dy_pnp - top), right=3*dx_pnp, top=(dy_pnp + top),
+ )
+ layouter.add_wire(net=nets.vss, wire=li, shape=shape)
+ shape = _geo.Rect(
+ left=0.0, bottom=(2*dy_pnp - top), right=3*dx_pnp, top=(2*dy_pnp + top),
+ )
+ layouter.add_wire(net=nets.vss, wire=li, shape=shape)
+ shape = _geo.Rect(
+ left=0.0, bottom=(3*dy_pnp - top), right=3*dx_pnp, top=3*dy_pnp,
+ )
+ layouter.add_wire(net=nets.vss, wire=li, shape=shape)
+
+ shape = _geo.Rect(left=0.0, bottom=0.0, right=right, top=3*dy_pnp)
+ layouter.add_wire(net=nets.vss, wire=li, shape=shape)
+ shape = _geo.Rect(
+ left=(dx_pnp - right), bottom=0.0, right=(dx_pnp + right), top=3*dy_pnp,
+ )
+ layouter.add_wire(net=nets.vss, wire=li, shape=shape)
+ shape = _geo.Rect(
+ left=(2*dx_pnp - right), bottom=0.0, right=(2*dx_pnp + right), top=3*dy_pnp,
+ )
+ layouter.add_wire(net=nets.vss, wire=li, shape=shape)
+ shape = _geo.Rect(
+ left=(3*dx_pnp - right), bottom=0.0, right=3*dx_pnp, top=3*dy_pnp,
+ )
+ layouter.add_wire(net=nets.vss, wire=li, shape=shape)
+
+ # Place res2s
+ polyport2bb = liport2bb = None
+ x = 3*dx_pnp + 1.0
+ vq3res2_libb = None
+ vrefres2_libb = None
+ for n in range(self.res2_n):
+ if (n%2) == 0:
+ _res_lay = layouter.inst_layout(inst=insts[f"res2[{n}]"])
+ else:
+ _res_lay = layouter.inst_layout(
+ inst=insts[f"res2[{n}]"], rotation=_geo.Rotation.MX,
+ )
+ _res_polybb = _res_lay.bounds(mask=poly.mask)
+
+ x_res = x - _res_polybb.left
+ y_res = -_res_polybb.bottom
+ res_lay = layouter.place(_res_lay, x=x_res, y=y_res)
+ res_polybb = res_lay.bounds(mask=poly.mask)
+ res_libb = res_lay.bounds(mask=li.mask)
+
+ if polyport2bb is not None:
+ assert n > 0
+ assert liport2bb is not None
+
+ net = nets[f"res2_{n - 1}"]
+ shape = _geo.Rect.from_rect(rect=polyport2bb, right=res_polybb.right)
+ layouter.add_wire(net=net, wire=poly, shape=shape)
+
+ shape = _geo.Rect.from_rect(rect=liport2bb, right=res_libb.right)
+ layouter.add_wire(net=net, wire=li, shape=shape)
+
+ if n == 0:
+ vq3res2_libb = res_lay.bounds(mask=li.mask, net=nets.vq3)
+
+ if n < (self.res2_n - 1):
+ net = nets[f"res2_{n}"]
+ polyport2bb = res_lay.bounds(mask=poly.mask, net=net)
+ liport2bb = res_lay.bounds(mask=li.mask, net=net)
+ else:
+ vrefres2_libb = res_lay.bounds(mask=li.mask, net=nets.vref)
+
+ x = res_polybb.right + poly.min_space
+ assert vq3res2_libb is not None
+ assert vrefres2_libb is not None
+
+ # Place mosfets
+ _n1_lay = layouter.inst_layout(inst=insts.n1)
+ _n1_bb = _n1_lay.bounds()
+ _p1_lay = layouter.inst_layout(inst=insts.p1)
+ _p1_bb = _p1_lay.bounds()
+
+ x = 1.5 - min(_n1_bb.left, _p1_bb.left)
+ dx_mos = _n1_bb.width + 0.5
+ y_n = 3*dy_pnp + 0.5 - _n1_bb.bottom
+ y_p = y_n + _n1_bb.top + 0.8 - _p1_bb.bottom
+
+ n1_lay = layouter.place(_n1_lay, x=x, y=y_n)
+ n1_actbb = n1_lay.bounds(mask=difftap.mask)
+ n1_nsdmbb = n1_lay.bounds(mask=nsdm.mask)
+ n1_hvibb = n1_lay.bounds(mask=hvi.mask)
+ n1_polybb = n1_lay.bounds(mask=poly.mask)
+ p1_lay = layouter.place(_p1_lay, x=x, y=y_p)
+ p1_actbb = p1_lay.bounds(mask=difftap.mask)
+ p1_psdmbb = p1_lay.bounds(mask=psdm.mask)
+ p1_hvibb = p1_lay.bounds(mask=hvi.mask)
+ p1_polybb = p1_lay.bounds(mask=poly.mask)
+
+ x += dx_mos
+ n2_lay = layouter.place(insts.n2, x=x, y=y_n)
+ n2_actbb = n2_lay.bounds(mask=difftap.mask)
+ n2_nsdmbb = n2_lay.bounds(mask=nsdm.mask)
+ n2_polybb = n2_lay.bounds(mask=poly.mask)
+ p2_lay = layouter.place(insts.p2, x=x, y=y_p)
+ p2_actbb = p2_lay.bounds(mask=difftap.mask)
+ p2_polybb = p2_lay.bounds(mask=poly.mask)
+ x += dx_mos
+ p3_lay = layouter.place(insts.p3, x=x, y=y_p)
+ p3_nwbb = p3_lay.bounds(mask=nwm.mask)
+ p3_actbb = p3_lay.bounds(mask=difftap.mask)
+ p3_psdmbb = p3_lay.bounds(mask=psdm.mask)
+ p3_polybb = p3_lay.bounds(mask=poly.mask)
+
+ # n_gate
+ net = nets.n_gate
+
+ _chngaten_lay = layouter.wire_layout(
+ net=net, wire=licon, bottom=difftap, bottom_implant=nsdm,
+ bottom_height=n1_actbb.height, bottom_enclosure="wide",
+ )
+ _chngaten_actbb = _chngaten_lay.bounds(mask=difftap.mask)
+ x = n1_polybb.right - _chngaten_actbb.left
+ y = n1_actbb.bottom - _chngaten_actbb.bottom
+ chngaten_lay = layouter.place(_chngaten_lay, x=x, y=y)
+ chngaten_libb = chngaten_lay.bounds(mask=li.mask)
+
+ _chngatep_lay = layouter.wire_layout(
+ net=net, well_net=nets.vdd, wire=licon,
+ bottom=difftap, bottom_implant=psdm, bottom_well=nwm,
+ bottom_height=p1_actbb.height, bottom_enclosure="wide",
+ )
+ _chngatep_actbb = _chngatep_lay.bounds(mask=difftap.mask)
+ x = p1_polybb.right - _chngatep_actbb.left
+ y = p1_actbb.bottom - _chngatep_actbb.bottom
+ chngatep_lay = layouter.place(_chngatep_lay, x=x, y=y)
+ chngatep_libb = chngatep_lay.bounds(mask=li.mask)
+
+ _chngatepad_lay = layouter.wire_layout(
+ net=net, wire=licon, bottom=poly, bottom_enclosure="tall",
+ )
+ _chngatepad_polybb = _chngatepad_lay.bounds(mask=poly.mask)
+ # x = x # Keep the x value
+ y = n1_polybb.top - _chngatepad_polybb.bottom
+ chngatepad_lay = layouter.place(_chngatepad_lay, x=x, y=y)
+ chngatepad_polybb = chngatepad_lay.bounds(mask=poly.mask)
+
+ shape = _geo.Rect.from_rect(
+ rect=chngaten_libb, top=chngatep_libb.top)
+ layouter.add_wire(net=net, wire=li, shape=shape)
+
+ ngatepad_bb = _geo.Rect.from_rect(
+ rect=chngatepad_polybb, left=n1_polybb.left, right=n2_polybb.right,
+ )
+ layouter.add_wire(net=net, wire=poly, shape=ngatepad_bb)
+
+ # p_gate
+ net = nets.p_gate
+
+ _chpgaten_lay = layouter.wire_layout(
+ net=net, wire=licon, bottom=difftap, bottom_implant=nsdm,
+ bottom_height=n2_actbb.height, bottom_enclosure="wide",
+ )
+ _chpgaten_actbb = _chpgaten_lay.bounds(mask=difftap.mask)
+ x = n2_polybb.right - _chpgaten_actbb.left
+ y = n2_actbb.bottom - _chpgaten_actbb.bottom
+ chpgaten_lay = layouter.place(_chpgaten_lay, x=x, y=y)
+ chpgaten_libb = chpgaten_lay.bounds(mask=li.mask)
+
+ _chpgatep_lay = layouter.wire_layout(
+ net=net, well_net=nets.vdd, wire=licon,
+ bottom=difftap, bottom_implant=psdm, bottom_well=nwm,
+ bottom_height=p1_actbb.height, bottom_enclosure="wide",
+ )
+ _chpgatep_actbb = _chpgatep_lay.bounds(mask=difftap.mask)
+ x = p2_polybb.right - _chpgatep_actbb.left
+ y = p2_actbb.bottom - _chpgatep_actbb.bottom
+ chpgatep_lay = layouter.place(_chpgatep_lay, x=x, y=y)
+ chpgatep_libb = chpgatep_lay.bounds(mask=li.mask)
+
+ _chpgatepad_lay = layouter.wire_layout(
+ net=net, wire=licon, bottom=poly, bottom_enclosure="tall",
+ )
+ _chpgatepad_polybb = _chpgatepad_lay.bounds(mask=poly.mask)
+ # x = x # Keep the x value
+ y = p2_polybb.bottom - _chngatepad_polybb.top
+ chpgatepad_lay = layouter.place(_chpgatepad_lay, x=x, y=y)
+ chpgatepad_polybb = chpgatepad_lay.bounds(mask=poly.mask)
+
+ shape = _geo.Rect.from_rect(
+ rect=chpgaten_libb, top=chpgatep_libb.top)
+ layouter.add_wire(net=net, wire=li, shape=shape)
+
+ pgatepad_bb = _geo.Rect.from_rect(
+ rect=chpgatepad_polybb, left=p1_polybb.left, right=p3_polybb.right,
+ )
+ layouter.add_wire(net=net, wire=poly, shape=pgatepad_bb)
+
+ # vq1
+ net = nets.vq1
+
+ lay = lay_matrix[1][1] # pnp1
+ m1pinbb = lay.bounds(mask=m1pin.mask, net=nets.vq1)
+ via1_lay = layouter.add_wire(net=nets.vq1, wire=via1, bottom_shape=m1pinbb)
+ via1vq1pnp1_m2bb = via1_lay.bounds(mask=m2.mask)
+
+ _chvq1n1_lay = layouter.wire_layout(
+ net=net, wire=licon, bottom=difftap, bottom_implant=nsdm,
+ bottom_height=n1_actbb.height, bottom_enclosure="wide",
+ )
+ _chvq1n1_actbb = _chvq1n1_lay.bounds(mask=difftap.mask)
+ _mconvq1m1_lay = layouter.wire_layout(
+ net=net, wire=mcon, bottom_height=n1_actbb.height,
+ top_height=n1_actbb.height,
+ )
+ _via1vq1m1_lay = layouter.wire_layout(
+ net=net, wire=via1, bottom_height=n1_actbb.height,
+ top_height=n1_actbb.height,
+ )
+
+ x = n1_polybb.left - _chvq1n1_actbb.right
+ y = n1_actbb.bottom - _chvq1n1_actbb.bottom
+ layouter.place(_chvq1n1_lay, x=x, y=y)
+ layouter.place(_mconvq1m1_lay, x=x, y=y)
+ via1vq1n1_lay = layouter.place(_via1vq1m1_lay, x=x, y=y)
+ via1vq1n1_m2bb = via1vq1n1_lay.bounds(mask=m2.mask)
+
+ shape = _geo.Rect.from_rect(
+ rect=via1vq1n1_m2bb, right=via1vq1pnp1_m2bb.right
+ )
+ layouter.add_wire(net=net, wire=m2, shape=shape)
+ shape = _geo.Rect.from_rect(
+ rect=via1vq1pnp1_m2bb, top=via1vq1n1_m2bb.top
+ )
+ layouter.add_wire(net=net, wire=m2, shape=shape)
+
+ # vq2
+ net = nets.vq2
+ lay0 = lay_matrix[0][0]
+ lay0_m1pinbb = lay0.bounds(mask=m1pin.mask, net=net)
+ lay1 = lay_matrix[0][1]
+ lay1_m1pinbb = lay1.bounds(mask=m1pin.mask, net=net)
+ lay2 = lay_matrix[2][1]
+ lay2_m1pinbb = lay2.bounds(mask=m1pin.mask, net=net)
+ lay3 = lay_matrix[2][2]
+ lay3_m1pinbb = lay3.bounds(mask=m1pin.mask, net=net)
+
+ shape1 = _geo.Rect.from_rect(rect=lay0_m1pinbb, right=lay1_m1pinbb.right)
+ layouter.add_wire(net=net, wire=m1, shape=shape1)
+ shape2 = _geo.Rect.from_rect(rect=lay2_m1pinbb, right=lay3_m1pinbb.right)
+ layouter.add_wire(net=net, wire=m1, shape=shape2)
+
+ o = res1vq2_libb.center
+ mconvq2res1_lay = layouter.add_wire(net=net, wire=mcon, columns=2, origin=o)
+ mconvq2res1_m1bb = mconvq2res1_lay.bounds(mask=m1.mask)
+
+ w = mconvq2res1_m1bb.width
+ left = mconvq2res1_m1bb.left
+ right = 2*dx_pnp + 0.5*w
+ top = shape1.top
+ bottom = top - w
+ shape = _geo.Rect(left=left, bottom=bottom, right=right, top=top)
+ layouter.add_wire(net=net, wire=m1, shape=shape)
+
+ # right = right; keep same right
+ left = right - w
+ # bottom = bottom; keep same bottom
+ top = shape2.top
+ shape = _geo.Rect(left=left, bottom=bottom, right=right, top=top)
+ layouter.add_wire(net=net, wire=m1, shape=shape)
+
+ shape = _geo.Rect.from_rect(rect=mconvq2res1_m1bb, bottom=bottom)
+ layouter.add_wire(net=net, wire=m1, shape=shape)
+
+ # vq2r1
+ _mconvq2r1res1_lay = layouter.wire_layout(net=net, wire=mcon, rows=2)
+ _mconvq2r1res1_libb = _mconvq2r1res1_lay.bounds(mask=li.mask)
+
+ x = res1vq2r1_libb.center.x
+ y = res1vq2r1_libb.bottom - _mconvq2r1res1_libb.bottom
+ mconvq2r1res1_lay = layouter.place(_mconvq2r1res1_lay, x=x, y=y)
+ mconvq2r1res1_m1bb = mconvq2r1res1_lay.bounds(mask=m1.mask)
+
+ _chvq2r1n2_lay = layouter.wire_layout(
+ net=net, wire=licon, bottom=difftap, bottom_implant=nsdm,
+ bottom_height=n2_actbb.height, bottom_enclosure="wide",
+ top_height=n2_actbb.height,
+ )
+ _chvq2r1n2_actbb = _chvq2r1n2_lay.bounds(mask=difftap.mask)
+ _mconvq2r1n2_lay = layouter.wire_layout(
+ net=net, wire=mcon,
+ bottom_height=n2_actbb.height, top_height=n2_actbb.height,
+ )
+
+ x = n2_polybb.left - _chvq2r1n2_actbb.right
+ y = n2_actbb.bottom - _chvq2r1n2_actbb.bottom
+ layouter.place(_chvq2r1n2_lay, x=x, y=y)
+ mconvq2r1n2_lay = layouter.place(_mconvq2r1n2_lay, x=x, y=y)
+ mconvq2r1n2_m1bb = mconvq2r1n2_lay.bounds(mask=m1.mask)
+
+ shape = _geo.Rect.from_rect(rect=mconvq2r1res1_m1bb, right=mconvq2r1n2_m1bb.right)
+ layouter.add_wire(net=net, wire=m1, shape=shape)
+ shape = _geo.Rect.from_rect(rect=mconvq2r1n2_m1bb, bottom=mconvq2r1res1_m1bb.bottom)
+ layouter.add_wire(net=net, wire=m1, shape=shape)
+
+ # vq3
+ net = nets.vq3
+
+ lay0 = lay_matrix[0][2]
+ lay0_m1pinbb = lay0.bounds(mask=m1pin.mask, net=net)
+ lay1 = lay_matrix[1][2]
+ lay1_m1pinbb = lay1.bounds(mask=m1pin.mask, net=net)
+ lay2 = lay_matrix[1][0]
+ lay2_m1pinbb = lay2.bounds(mask=m1pin.mask, net=net)
+ lay3 = lay_matrix[2][0]
+ lay3_m1pinbb = lay3.bounds(mask=m1pin.mask, net=net)
+
+ shape1 = _geo.Rect.from_rect(rect=lay0_m1pinbb, top=lay1_m1pinbb.top)
+ layouter.add_wire(net=net, wire=m1, shape=shape1)
+ shape2 = _geo.Rect.from_rect(rect=lay3_m1pinbb, bottom=dy_pnp)
+ layouter.add_wire(net=net, wire=m1, shape=shape2)
+
+ via1vq3_lay1 = layouter.add_wire(
+ net=net, wire=via1, x=shape2.center.x, y=dy_pnp,
+ bottom_width=shape2.width,
+ )
+ via1vq3_m2bb1 = via1vq3_lay1.bounds(mask=m2.mask)
+ layouter.add_wire(
+ net=net, wire=via1, x=shape1.center.x, y=dy_pnp,
+ bottom_width=shape1.width,
+ )
+
+ _mconvq3res2_lay = layouter.wire_layout(net=net, wire=mcon, rows=2)
+ _mconvq3res2_libb = _mconvq3res2_lay.bounds(mask=li.mask)
+ x = vq3res2_libb.center.x
+ y = vq3res2_libb.bottom - _mconvq3res2_libb.bottom
+ mconvq3res2_lay = layouter.place(_mconvq3res2_lay, x=x, y=y)
+ mconvq3res2_m1bb = mconvq3res2_lay.bounds(mask=m1.mask)
+ via1vq3res2_lay = layouter.add_wire(
+ net=net, wire=via1, rows=2, x=x, y=dy_pnp,
+ )
+ via1vq3res2_m1bb = via1vq3res2_lay.bounds(mask=m1.mask)
+ via1vq3res2_m2bb = via1vq3res2_lay.bounds(mask=m2.mask)
+
+ shape = _geo.Rect.from_rect(
+ rect=via1vq3res2_m1bb, bottom=mconvq3res2_m1bb.bottom,
+ )
+ layouter.add_wire(net=net, wire=m1, shape=shape)
+
+ shape = _geo.Rect.from_rect(
+ rect=via1vq3res2_m2bb, left=via1vq3_m2bb1.left,
+ )
+ layouter.add_wire(net=net, wire=m2, shape=shape)
+
+ # vref
+ net = nets.vref
+
+ _chvrefp_lay = layouter.wire_layout(
+ net=net, well_net=nets.vdd, wire=licon,
+ bottom=difftap, bottom_implant=psdm, bottom_well=nwm,
+ bottom_height=p1_actbb.height, bottom_enclosure="wide",
+ )
+ _chvrefp_actbb = _chvrefp_lay.bounds(mask=difftap.mask)
+ x = p3_polybb.right - _chvrefp_actbb.left
+ y = p3_actbb.bottom - _chvrefp_actbb.bottom
+ chvrefp_lay = layouter.place(_chvrefp_lay, x=x, y=y)
+ chvrefp_libb = chvrefp_lay.bounds(mask=li.mask)
+
+ shape = _geo.Rect.from_rect(rect=vrefres2_libb, top=chvrefp_libb.top)
+ layouter.add_wire(net=net, wire=li, shape=shape)
+ shape = _geo.Rect.from_rect(rect=chvrefp_libb, right=vrefres2_libb.right)
+ layouter.add_wire(net=net, wire=li, pin=lipin, shape=shape)
+
+ # vdd
+ net = nets.vdd
+
+ _chvdd_lay = layouter.wire_layout(
+ net=net, well_net=net, wire=licon,
+ bottom=difftap, bottom_implant=psdm, bottom_well=nwm,
+ bottom_height=p1_actbb.height, bottom_enclosure="wide",
+ )
+ _chvdd_actbb = _chvdd_lay.bounds(mask=difftap.mask)
+ _mconvdd_lay = layouter.wire_layout(
+ net=net, wire=mcon, bottom_height=p1_actbb.height,
+ )
+
+ x = p1_polybb.left - _chvdd_actbb.right
+ y = p1_actbb.bottom - _chvdd_actbb.bottom
+ lay = layouter.place(_chvdd_lay, x=x, y=y)
+ actbb = lay.bounds(mask=difftap.mask)
+ libb = lay.bounds(mask=li.mask)
+ lay = layouter.place(_mconvdd_lay, x=x, y=y)
+ mconp1_m1bb = lay.bounds(mask=m1.mask)
+ x = p2_polybb.left - _chvdd_actbb.right
+ layouter.place(_chvdd_lay, x=x, y=y)
+ layouter.place(_mconvdd_lay, x=x, y=y)
+ x = p3_polybb.left - _chvdd_actbb.right
+ layouter.place(_chvdd_lay, x=x, y=y)
+ lay = layouter.place(_mconvdd_lay, x=x, y=y)
+ mconp3_m1bb = lay.bounds(mask=m1.mask)
+
+ _chvddnw_lay = layouter.wire_layout(
+ net=net, well_net=net, wire=licon, columns=2,
+ bottom=difftap, bottom_implant=nsdm, bottom_well=nwm,
+ bottom_height=p1_actbb.height, bottom_enclosure="wide",
+ )
+ _chvddnw_actbb = _chvddnw_lay.bounds(mask=difftap.mask)
+
+ x = actbb.left - 0.5 - _chvddnw_actbb.right
+ chvddnw_lay = layouter.place(_chvddnw_lay, x=x, y=y)
+ chvddnw_nwbb = chvddnw_lay.bounds(mask=nwm.mask)
+ chvddnw_libb = chvddnw_lay.bounds(mask=li.mask)
+
+ shape = _geo.Rect.from_rect(rect=libb, left=chvddnw_libb.left)
+ layouter.add_wire(net=net, wire=li, shape=shape)
+
+ shape = _geo.Rect.from_rect(rect=mconp1_m1bb, right=mconp3_m1bb.right)
+ layouter.add_wire(net=net, wire=m1, pin=m1pin, shape=shape)
+
+ # nsdm; cover poly contact hole
+ shape = _geo.Rect.from_rect(
+ rect=n1_nsdmbb, right=n2_nsdmbb.right, top=ngatepad_bb.top,
+ )
+ layouter.add_portless(prim=nsdm, shape=shape)
+
+ # psdm; cover poly contact hole
+ shape = _geo.Rect.from_rect(
+ rect=p1_psdmbb, right=p3_psdmbb.right, bottom=pgatepad_bb.bottom,
+ )
+ layouter.add_portless(prim=psdm, shape=shape)
+
+ # nwell
+ shape = _geo.Rect.from_rect(rect=p3_nwbb, left=chvddnw_nwbb.left)
+ layouter.add_wire(net=nets.vdd, wire=nwm, shape=shape)
+
+ # hvi
+ shape = _geo.Rect(
+ left=0.0, bottom=n1_hvibb.bottom, right=3*dx_pnp, top=p1_hvibb.top,
+ )
+ layouter.add_portless(prim=hvi, shape=shape)
+
+ # Boundary
+ shape = _geo.Rect.from_rect(rect=layout.bounds(), bias=0.2)
+ layout.boundary = shape
+ layouter.add_portless(prim=bnd, shape=shape)
+
+
+class ConnectedBandGap(_lbry._Cell[_lbry.Library]):
+ def __init__(self, *, lib: _lbry.Library):
+ super().__init__(lib=lib, name="ConnectedBandGap")
+
+ ckt = self.new_circuit()
+ layouter = self.new_circuitlayouter()
+ layout = layouter.layout
+
+ li = cast(_prm.MetalWire, _prims.li)
+ assert li.pin is not None
+ lipin = li.pin[0]
+ mcon = cast(_prm.Via, _prims.mcon)
+ m1 = cast(_prm.MetalWire, _prims.m1)
+ assert m1.pin is not None
+ m1pin = m1.pin[0]
+ via1 = cast(_prm.Via, _prims.via)
+ m2 = cast(_prm.MetalWire, _prims.m2)
+ via2 = cast(_prm.Via, _prims.via2)
+ m3 = cast(_prm.MetalWire, _prims.m3)
+ assert m3.pin is not None
+ m3pin = m3.pin[0]
+ bnd = cast(_prm.Auxiliary, _prims.prBoundary)
+
+ bg_cell = _BandGap3V3(lib=lib)
+ lib.cells += bg_cell
+ _bg_bb = bg_cell.layout.boundary
+ assert _bg_bb is not None
+ _bgvref = bg_cell.circuit.nets.vref
+ _bgvref_lipinbb = bg_cell.layout.bounds(mask=lipin.mask, net=_bgvref)
+
+ bg = ckt.instantiate(bg_cell, name="bg")
+
+ # Add pins + nets for the io signals of the bandgap
+ vss_pinname = "io_analog[7]"
+ vss_m3pinbb = _frm.toppins[vss_pinname]
+ vss = ckt.new_net(name=vss_pinname, external=True, childports=bg.ports.vss)
+ layouter.add_wire(net=vss, wire=m3, pin=m3pin, shape=vss_m3pinbb)
+
+ vdd_pinname = "io_analog[9]"
+ vdd_m3pinbb = _frm.toppins[vdd_pinname]
+ vdd = ckt.new_net(name=vdd_pinname, external=True, childports=bg.ports.vdd)
+ layouter.add_wire(net=vdd, wire=m3, pin=m3pin, shape=vdd_m3pinbb)
+
+ vref_pinname = "io_analog[8]"
+ vref_m3pinbb = _frm.toppins[vref_pinname]
+ vref = ckt.new_net(name=vref_pinname, external=True, childports=bg.ports.vref)
+ layouter.add_wire(net=vref, wire=m3, pin=m3pin, shape=vref_m3pinbb)
+
+ # Place bandgap, align vref pin with top pin
+ x = vref_m3pinbb.center.x - _bgvref_lipinbb.center.x
+ y = vref_m3pinbb.bottom - 5.0 - _bg_bb.top
+ bg_lay = layouter.place(bg, x=x, y=y)
+ bgvss_lipinbb = bg_lay.bounds(mask=lipin.mask, net=vss, depth=1)
+ bgvdd_m1pinbb = bg_lay.bounds(mask=m1pin.mask, net=vdd, depth=1)
+ bgvref_lipinbb = bg_lay.bounds(mask=lipin.mask, net=vref, depth=1)
+
+ # Boundary
+ layout.boundary = _frm.boundary
+ layouter.add_portless(prim=bnd, shape=_frm.boundary)
+
+ # vss
+ net = vss
+
+ layouter.add_wire(
+ net=net, wire=mcon, bottom_shape=bgvss_lipinbb, top_shape=bgvss_lipinbb,
+ )
+ layouter.add_wire(
+ net=net, wire=via1, bottom_shape=bgvss_lipinbb, top_shape=bgvss_lipinbb,
+ )
+ lay = layouter.add_wire(
+ net=net, wire=via2, bottom_shape=bgvss_lipinbb, top_shape=bgvss_lipinbb,
+ )
+ m3bb = lay.bounds(mask=m3.mask)
+
+ shape = _geo.Rect.from_rect(rect=m3bb, right=vss_m3pinbb.right)
+ layouter.add_wire(net=net, wire=m3, shape=shape)
+ shape = _geo.Rect.from_rect(rect=vss_m3pinbb, bottom=m3bb.bottom)
+ layouter.add_wire(net=net, wire=m3, shape=shape)
+
+ # vss
+ net = vdd
+
+ layouter.add_wire(
+ net=net, wire=via1, bottom_shape=bgvdd_m1pinbb, top_shape=bgvdd_m1pinbb,
+ )
+ lay = layouter.add_wire(
+ net=net, wire=via2, bottom_shape=bgvdd_m1pinbb, top_shape=bgvdd_m1pinbb,
+ )
+ m3bb = lay.bounds(mask=m3.mask)
+
+ shape = _geo.Rect.from_rect(rect=m3bb, left=vdd_m3pinbb.left)
+ layouter.add_wire(net=net, wire=m3, shape=shape)
+ shape = _geo.Rect.from_rect(rect=vdd_m3pinbb, bottom=m3bb.bottom)
+ layouter.add_wire(net=net, wire=m3, shape=shape)
+
+ # vref
+ net = vref
+
+ layouter.add_wire(
+ net=net, wire=mcon, bottom_shape=bgvref_lipinbb, top_shape=bgvref_lipinbb,
+ )
+ layouter.add_wire(
+ net=net, wire=via1, bottom_shape=bgvref_lipinbb, top_shape=bgvref_lipinbb,
+ )
+ lay = layouter.add_wire(
+ net=net, wire=via2, bottom_shape=bgvref_lipinbb, top_shape=bgvref_lipinbb,
+ )
+ m3bb = lay.bounds(mask=m3.mask)
+
+ shape = _geo.Rect.from_rect(rect=m3bb, top=vref_m3pinbb.bottom)
+ layouter.add_wire(net=net, wire=m3, shape=shape)
diff --git a/doitcode/generate.py b/doitcode/generate.py
index 4c677a4..8297498 100644
--- a/doitcode/generate.py
+++ b/doitcode/generate.py
@@ -14,7 +14,7 @@
from c4m.pdk import sky130
-from . import frame as _frm, sram as _ram
+from . import frame as _frm, sram as _ram, bandgap as _bg
__all__ = ["gen_gds"]
@@ -65,11 +65,18 @@
ckt = top.new_circuit()
layouter = top.new_circuitlayouter()
+ # Add the BandGap
+ bandgap_cell = _bg.ConnectedBandGap(lib=lib)
+ bandgap_inst = ckt.instantiate(bandgap_cell, name="bandgaptop")
+ layouter.place(bandgap_inst, x=0.0, y=0.0)
+
# Add the SRAM
sram_cell = _ram.ConnectedSRAM(lib=lib)
sram_inst = ckt.instantiate(sram_cell, name="sramtop")
layouter.place(sram_inst, origin=_geo.origin)
+ lib.cells += (bandgap_cell, sram_cell)
+
# Add circuit and
layouter.layout.boundary = _frm.boundary
diff --git a/gds/user_analog_project_wrapper.gds.gz b/gds/user_analog_project_wrapper.gds.gz
index 1bfbf8c..ca5b026 100644
--- a/gds/user_analog_project_wrapper.gds.gz
+++ b/gds/user_analog_project_wrapper.gds.gz
Binary files differ
diff --git a/netgen/user_analog_project_wrapper.spice b/netgen/user_analog_project_wrapper.spice
index 6b4e7ab..6776910 100644
--- a/netgen/user_analog_project_wrapper.spice
+++ b/netgen/user_analog_project_wrapper.spice
@@ -4,6 +4,10 @@
.ends
+.subckt ConnectedBandGap
+
+.ends
+
.subckt user_analog_project_wrapper_empty gpio_analog[0] gpio_analog[10] gpio_analog[11]
+ gpio_analog[12] gpio_analog[13] gpio_analog[14] gpio_analog[15] gpio_analog[16]
+ gpio_analog[17] gpio_analog[1] gpio_analog[2] gpio_analog[3] gpio_analog[4] gpio_analog[5]
@@ -227,6 +231,8 @@
+ io_analog[4] io_analog[5]
+ ConnectedSRAM
+Xbg io_analog[7] io_analog[9] io_analog[8] ConnectedBandGap
+
Xempty gpio_analog[0] gpio_analog[10] gpio_analog[11]
+ gpio_analog[12] gpio_analog[13] gpio_analog[14] gpio_analog[15] gpio_analog[16]
+ gpio_analog[17] gpio_analog[1] gpio_analog[2] gpio_analog[3] gpio_analog[4] gpio_analog[5]
diff --git a/verilog/rtl/blocks.v b/verilog/rtl/blocks.v
index c4db2d6..f8a982d 100644
--- a/verilog/rtl/blocks.v
+++ b/verilog/rtl/blocks.v
@@ -8,6 +8,14 @@
endmodule
+module ConnectedBandGap (
+ inout vss,
+ inout vdd,
+ out vref
+);
+
+endmodule
+
module user_analog_project_wrapper_empty (
inout vdda1,
diff --git a/verilog/rtl/user_analog_project_wrapper.v b/verilog/rtl/user_analog_project_wrapper.v
index 95fc0c5..8798597 100644
--- a/verilog/rtl/user_analog_project_wrapper.v
+++ b/verilog/rtl/user_analog_project_wrapper.v
@@ -91,4 +91,9 @@
.vdd(io_analog[5])
)
+ConnectedBandGap bg (
+ .vss(io_analog[7]),
+ .vdd(io_analog[9])
+)
+
endmodule // user_analog_project_wrapper