blob: 3176dfc4073cb6e84f27f83150d1b9fb8f795d22 [file] [log] [blame]
# 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)