| # 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] |
| via = 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) |
| via_lay = layouter.add_wire(net=nets.vq1, wire=via, bottom_shape=m1pinbb) |
| viavq1pnp1_m2bb = via_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, |
| ) |
| _viavq1m1_lay = layouter.wire_layout( |
| net=net, wire=via, 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) |
| viavq1n1_lay = layouter.place(_viavq1m1_lay, x=x, y=y) |
| viavq1n1_m2bb = viavq1n1_lay.bounds(mask=m2.mask) |
| |
| shape = _geo.Rect.from_rect( |
| rect=viavq1n1_m2bb, right=viavq1pnp1_m2bb.right |
| ) |
| layouter.add_wire(net=net, wire=m2, shape=shape) |
| shape = _geo.Rect.from_rect( |
| rect=viavq1pnp1_m2bb, top=viavq1n1_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) |
| |
| viavq3_lay1 = layouter.add_wire( |
| net=net, wire=via, x=shape2.center.x, y=dy_pnp, |
| bottom_width=shape2.width, |
| ) |
| viavq3_m2bb1 = viavq3_lay1.bounds(mask=m2.mask) |
| layouter.add_wire( |
| net=net, wire=via, 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) |
| viavq3res2_lay = layouter.add_wire( |
| net=net, wire=via, rows=2, x=x, y=dy_pnp, |
| ) |
| viavq3res2_m1bb = viavq3res2_lay.bounds(mask=m1.mask) |
| viavq3res2_m2bb = viavq3res2_lay.bounds(mask=m2.mask) |
| |
| shape = _geo.Rect.from_rect( |
| rect=viavq3res2_m1bb, bottom=mconvq3res2_m1bb.bottom, |
| ) |
| layouter.add_wire(net=net, wire=m1, shape=shape) |
| |
| shape = _geo.Rect.from_rect( |
| rect=viavq3res2_m2bb, left=viavq3_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] |
| via = 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=via, 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=via, 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=via, 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) |