| # 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 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) |
| |
| nmos3v3 = cast(_prm.MOSFET, _prims.nfet_g5v0d10v5) |
| nmos1v8lvt = cast(_prm.MOSFET, _prims.nfet_01v8_lvt) |
| nmos1v8 = cast(_prm.MOSFET, _prims.nfet_01v8) |
| pmos3v3 = cast(_prm.MOSFET, _prims.pfet_g5v0d10v5) |
| pmos1v8lvt = cast(_prm.MOSFET, _prims.pfet_01v8_lvt) |
| pmos1v8 = cast(_prm.MOSFET, _prims.pfet_01v8) |
| pnp = sky130.macrolib.cells.PNP_05v5_W3u40L3u40 |
| res = cast(_prm.Resistor, _prims.poly_res) |
| |
| # Create the bandgap subcells |
| bg3v3_cell = sky130.BandgapCell( |
| lib=lib, name="Bandgap3V3", |
| nmos=nmos3v3, nmos_l=25.0, nmos_w=40.0, |
| pmos=pmos3v3, pmos_l=7.75, pmos_w=40.0, |
| pnp=pnp, pnp_ratio=2, |
| resistor=res, r1_height=13.055, r2_height=329.85, |
| ) |
| lib.cells += bg3v3_cell |
| _bg3v3_bb = bg3v3_cell.layout.bounds() |
| assert _bg3v3_bb is not None |
| _bg3v3vref = bg3v3_cell.circuit.nets.vref |
| _bg3v3vref_m1pinbb = bg3v3_cell.layout.bounds(mask=m1pin.mask, net=_bg3v3vref) |
| |
| bg1v8lvt_cell = sky130.BandgapCell( |
| lib=lib, name="Bandgap1V8lvt", |
| nmos=nmos1v8lvt, nmos_l=1.0, nmos_w=40.0, |
| pmos=pmos1v8lvt, pmos_l=25.0, pmos_w=40.0, |
| pnp=pnp, pnp_ratio=2, |
| resistor=res, r1_height=62.85, r2_height=1091.20, |
| ) |
| lib.cells += bg1v8lvt_cell |
| _bg1v8lvt_bb = bg1v8lvt_cell.layout.bounds() |
| assert _bg1v8lvt_bb is not None |
| _bg1v8lvtvref = bg1v8lvt_cell.circuit.nets.vref |
| _bg1v8lvtvref_m1pinbb = bg1v8lvt_cell.layout.bounds(mask=m1pin.mask, net=_bg1v8lvtvref) |
| |
| bg1v8_cell = sky130.BandgapCell( |
| lib=lib, name="Bandgap1V8", |
| nmos=nmos1v8, nmos_l=25.0, nmos_w=40.0, |
| pmos=pmos1v8, pmos_l=0.5, pmos_w=40.0, |
| pnp=pnp, pnp_ratio=2, |
| resistor=res, r1_height=32.14, r2_height=458.46, |
| ) |
| lib.cells += bg1v8_cell |
| _bg1v8_bb = bg1v8_cell.layout.bounds() |
| assert _bg1v8_bb is not None |
| _bg1v8vref = bg1v8_cell.circuit.nets.vref |
| _bg1v8vref_m1pinbb = bg1v8_cell.layout.bounds(mask=m1pin.mask, net=_bg1v8vref) |
| |
| # Instantiate the bandgap cells |
| bg3v3 = ckt.instantiate(bg3v3_cell, name="bg3v3") |
| bg1v8lvt = ckt.instantiate(bg1v8lvt_cell, name="bg1v8lvt") |
| bg1v8 = ckt.instantiate(bg1v8_cell, name="bg1v8") |
| |
| # Add pins + nets for the io signals of the bandgap |
| vss3v3_pinname = "io_analog[7]" |
| vss3v3_m3pinbb = _frm.toppins[vss3v3_pinname] |
| vss3v3 = ckt.new_net(name=vss3v3_pinname, external=True, childports=bg3v3.ports.vss) |
| layouter.add_wire(net=vss3v3, wire=m3, pin=m3pin, shape=vss3v3_m3pinbb) |
| |
| vdd3v3_pinname = "io_analog[9]" |
| vdd3v3_m3pinbb = _frm.toppins[vdd3v3_pinname] |
| vdd3v3 = ckt.new_net(name=vdd3v3_pinname, external=True, childports=bg3v3.ports.vdd) |
| layouter.add_wire(net=vdd3v3, wire=m3, pin=m3pin, shape=vdd3v3_m3pinbb) |
| |
| vref3v3_pinname = "io_analog[8]" |
| vref3v3_m3pinbb = _frm.toppins[vref3v3_pinname] |
| vref3v3 = ckt.new_net(name=vref3v3_pinname, external=True, childports=bg3v3.ports.vref) |
| layouter.add_wire(net=vref3v3, wire=m3, pin=m3pin, shape=vref3v3_m3pinbb) |
| |
| # vss and vdd are shared between bg1v8lvt and bg1v8 |
| vss1v8_pinname = "io_analog[0]" |
| vss1v8_m3pinbb = _frm.toppins[vss1v8_pinname] |
| vss1v8 = ckt.new_net(name=vss1v8_pinname, external=True, childports=( |
| bg1v8.ports.vss, bg1v8lvt.ports.vss, |
| )) |
| layouter.add_wire(net=vss1v8, wire=m3, pin=m3pin, shape=vss1v8_m3pinbb) |
| |
| vdd1v8_pinname = "io_analog[3]" |
| vdd1v8_m3pinbb = _frm.toppins[vdd1v8_pinname] |
| vdd1v8 = ckt.new_net(name=vdd1v8_pinname, external=True, childports=( |
| bg1v8.ports.vdd, bg1v8lvt.ports.vdd, |
| )) |
| layouter.add_wire(net=vdd1v8, wire=m3, pin=m3pin, shape=vdd1v8_m3pinbb) |
| |
| vref1v8lvt_pinname = "io_analog[2]" |
| vref1v8lvt_m3pinbb = _frm.toppins[vref1v8lvt_pinname] |
| vref1v8lvt = ckt.new_net( |
| name=vref1v8lvt_pinname, external=True, childports=bg1v8lvt.ports.vref, |
| ) |
| layouter.add_wire(net=vref1v8lvt, wire=m3, pin=m3pin, shape=vref1v8lvt_m3pinbb) |
| |
| vref1v8_pinname = "io_analog[1]" |
| vref1v8_m3pinbb = _frm.toppins[vref1v8_pinname] |
| vref1v8 = ckt.new_net( |
| name=vref1v8_pinname, external=True, childports=bg1v8.ports.vref, |
| ) |
| layouter.add_wire(net=vref1v8, wire=m3, pin=m3pin, shape=vref1v8_m3pinbb) |
| |
| # Boundary |
| layout.boundary = _frm.boundary |
| layouter.add_portless(prim=bnd, shape=_frm.boundary) |
| |
| # Place bg3v3, align vref pin with top pin |
| x = vref3v3_m3pinbb.center.x - _bg3v3vref_m1pinbb.center.x |
| y = vref3v3_m3pinbb.bottom - 5.0 - _bg3v3_bb.top |
| bg3v3_lay = layouter.place(bg3v3, x=x, y=y) |
| bg3v3vss_m1pinbb = bg3v3_lay.bounds(mask=m1pin.mask, net=vss3v3, depth=1) |
| bg3v3vss_m1pinbb = _geo.Rect.from_rect( |
| rect=bg3v3vss_m1pinbb, top=(bg3v3vss_m1pinbb.top + 5.0), |
| ) |
| bg3v3vdd_m1pinbb = bg3v3_lay.bounds(mask=m1pin.mask, net=vdd3v3, depth=1) |
| bg3v3vdd_m1pinbb = _geo.Rect.from_rect( |
| rect=bg3v3vdd_m1pinbb, bottom=(bg3v3vdd_m1pinbb.bottom - 5.0), |
| ) |
| bg3v3vref_m1pinbb = bg3v3_lay.bounds(mask=m1pin.mask, net=vref3v3, depth=1) |
| bg3v3vref_m1pinbb = _geo.Rect.from_rect( |
| rect=bg3v3vref_m1pinbb, right=(bg3v3vref_m1pinbb.right + 5.0), |
| ) |
| |
| # Place bg1v8lvt, align vref pin with top pin |
| x = vref1v8lvt_m3pinbb.center.x - _bg1v8lvtvref_m1pinbb.center.x |
| y = vref1v8lvt_m3pinbb.bottom - 10.0 - _bg1v8lvt_bb.top |
| bg1v8lvt_lay = layouter.place(bg1v8lvt, x=x, y=y) |
| bg1v8lvtvss_m1pinbb = bg1v8lvt_lay.bounds(mask=m1pin.mask, net=vss1v8, depth=1) |
| bg1v8lvtvss_m1pinbb = _geo.Rect.from_rect( |
| rect=bg1v8lvtvss_m1pinbb, top=(bg1v8lvtvss_m1pinbb.top + 5.0), |
| ) |
| bg1v8lvtvss_m2pinbb = _geo.Rect.from_rect( |
| rect=bg1v8lvtvss_m1pinbb, bottom=vss1v8_m3pinbb.bottom, |
| ) |
| bg1v8lvtvss_m3pinbb = _geo.Rect.from_rect( |
| rect=bg1v8lvtvss_m2pinbb, top=vss1v8_m3pinbb.top, |
| ) |
| bg1v8lvtvdd_m1pinbb = bg1v8lvt_lay.bounds(mask=m1pin.mask, net=vdd1v8, depth=1) |
| bg1v8lvtvdd_m1pinbb = _geo.Rect.from_rect( |
| rect=bg1v8lvtvdd_m1pinbb, top=(bg1v8lvtvdd_m1pinbb.top + 6.0), |
| ) |
| bg1v8lvtvdd_m2pinbb = _geo.Rect.from_rect( |
| rect=bg1v8lvtvdd_m1pinbb, bottom=(bg1v8lvtvdd_m1pinbb.top - 5.0), |
| ) |
| bg1v8lvtvref_m1pinbb = bg1v8lvt_lay.bounds(mask=m1pin.mask, net=vref1v8lvt, depth=1) |
| bg1v8lvtvref_m1pinbb = _geo.Rect.from_rect( |
| rect=bg1v8lvtvref_m1pinbb, right=(bg1v8lvtvref_m1pinbb.right + 5.0), |
| ) |
| |
| # Place bg1v8 below bg1v8lvt |
| x = vref1v8_m3pinbb.center.x - _bg1v8vref_m1pinbb.center.x |
| y = vref1v8_m3pinbb.bottom - 10.0 - _bg1v8_bb.top |
| bg1v8_lay = layouter.place(bg1v8, x=x, y=y) |
| bg1v8vss_m1pinbb = bg1v8_lay.bounds(mask=m1pin.mask, net=vss1v8, depth=1) |
| bg1v8vss_m1pinbb = _geo.Rect.from_rect( |
| rect=bg1v8vss_m1pinbb, top=(bg1v8vss_m1pinbb.top + 5.0), |
| ) |
| bg1v8vss_m2pinbb = _geo.Rect.from_rect( |
| rect=bg1v8vss_m1pinbb, bottom=vss1v8_m3pinbb.bottom, |
| ) |
| bg1v8vss_m3pinbb = _geo.Rect.from_rect( |
| rect=bg1v8vss_m2pinbb, top=vss1v8_m3pinbb.top, |
| ) |
| bg1v8vdd_m1pinbb = bg1v8_lay.bounds(mask=m1pin.mask, net=vdd1v8, depth=1) |
| bg1v8vdd_m1pinbb = _geo.Rect.from_rect( |
| rect=bg1v8vdd_m1pinbb, top=(bg1v8vdd_m1pinbb.top + 6.0), |
| ) |
| bg1v8vdd_m2pinbb = _geo.Rect.from_rect( |
| rect=bg1v8vdd_m1pinbb, bottom=(bg1v8vdd_m1pinbb.top - 5.0), |
| ) |
| bg1v8vref_m1pinbb = bg1v8_lay.bounds(mask=m1pin.mask, net=vref1v8, depth=1) |
| bg1v8vref_m1pinbb = _geo.Rect.from_rect( |
| rect=bg1v8vref_m1pinbb, right=(bg1v8vref_m1pinbb.right + 5.0), |
| ) |
| |
| # vss3v3 |
| net = vss3v3 |
| |
| layouter.add_wire( |
| net=net, wire=via, bottom_shape=bg3v3vss_m1pinbb, top_shape=bg3v3vss_m1pinbb, |
| ) |
| lay = layouter.add_wire( |
| net=net, wire=via2, bottom_shape=bg3v3vss_m1pinbb, top_shape=bg3v3vss_m1pinbb, |
| ) |
| m3bb = lay.bounds(mask=m3.mask) |
| |
| shape = _geo.Rect.from_rect(rect=m3bb, right=vss3v3_m3pinbb.right) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| shape = _geo.Rect.from_rect(rect=vss3v3_m3pinbb, bottom=m3bb.bottom) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| |
| # vdd3v3 |
| net = vdd3v3 |
| |
| layouter.add_wire( |
| net=net, wire=via, bottom_shape=bg3v3vdd_m1pinbb, top_shape=bg3v3vdd_m1pinbb, |
| ) |
| lay = layouter.add_wire( |
| net=net, wire=via2, bottom_shape=bg3v3vdd_m1pinbb, top_shape=bg3v3vdd_m1pinbb, |
| ) |
| m3bb = lay.bounds(mask=m3.mask) |
| |
| shape = _geo.Rect.from_rect(rect=m3bb, left=vdd3v3_m3pinbb.left) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| shape = _geo.Rect.from_rect(rect=vdd3v3_m3pinbb, bottom=m3bb.bottom) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| |
| # vref3v3 |
| net = vref3v3 |
| |
| layouter.add_wire( |
| net=net, wire=via, bottom_shape=bg3v3vref_m1pinbb, top_shape=bg3v3vref_m1pinbb, |
| ) |
| lay = layouter.add_wire( |
| net=net, wire=via2, bottom_shape=bg3v3vref_m1pinbb, top_shape=bg3v3vref_m1pinbb, |
| ) |
| m3bb = lay.bounds(mask=m3.mask) |
| |
| shape = _geo.Rect.from_rect(rect=m3bb, top=vref3v3_m3pinbb.bottom) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| |
| # vss1v8 |
| net = vss1v8 |
| |
| layouter.add_wire( |
| net=net, wire=via, |
| bottom_shape=bg1v8lvtvss_m1pinbb, top_shape=bg1v8lvtvss_m2pinbb, |
| ) |
| layouter.add_wire( |
| net=net, wire=via, |
| bottom_shape=bg1v8vss_m1pinbb, top_shape=bg1v8vss_m2pinbb, |
| ) |
| |
| layouter.add_wire( |
| net=net, wire=via2, |
| bottom_shape=bg1v8lvtvss_m3pinbb, top_shape=bg1v8lvtvss_m3pinbb, |
| ) |
| layouter.add_wire( |
| net=net, wire=via2, |
| bottom_shape=bg1v8vss_m3pinbb, top_shape=bg1v8vss_m3pinbb, |
| ) |
| |
| shape = _geo.Rect.from_rect(rect=bg1v8lvtvss_m3pinbb, right=vss1v8_m3pinbb.right) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| |
| # vdd1v8 |
| net = vdd1v8 |
| |
| layouter.add_wire( |
| net=net, wire=via, |
| bottom_shape=bg1v8lvtvdd_m1pinbb, top_shape=bg1v8lvtvdd_m2pinbb, |
| ) |
| layouter.add_wire( |
| net=net, wire=via, |
| bottom_shape=bg1v8vdd_m1pinbb, top_shape=bg1v8vdd_m2pinbb, |
| ) |
| via2bb = _geo.Rect.from_rect( |
| rect=bg1v8vdd_m2pinbb, left=vdd1v8_m3pinbb.left, right=vdd1v8_m3pinbb.right, |
| ) |
| layouter.add_wire( |
| net=net, wire=via2, bottom_shape=via2bb, top_shape=via2bb, |
| ) |
| shape = _geo.Rect.from_rect(rect=via2bb, right=bg1v8vdd_m2pinbb.right) |
| layouter.add_wire(net=net, wire=m2, shape=shape) |
| shape = _geo.Rect.from_rect(rect=via2bb, top=vdd1v8_m3pinbb.top) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| |
| # vref1v8lvt |
| net = vref1v8lvt |
| |
| layouter.add_wire( |
| net=net, wire=via, |
| bottom_shape=bg1v8lvtvref_m1pinbb, top_shape=bg1v8lvtvref_m1pinbb, |
| ) |
| lay = layouter.add_wire( |
| net=net, wire=via2, |
| bottom_shape=bg1v8lvtvref_m1pinbb, top_shape=bg1v8lvtvref_m1pinbb, |
| ) |
| m3bb = lay.bounds(mask=m3.mask) |
| |
| shape = _geo.Rect.from_rect(rect=m3bb, top=vref1v8lvt_m3pinbb.bottom) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |
| |
| # vref1v8 |
| net = vref1v8 |
| |
| layouter.add_wire( |
| net=net, wire=via, |
| bottom_shape=bg1v8vref_m1pinbb, top_shape=bg1v8vref_m1pinbb, |
| ) |
| lay = layouter.add_wire( |
| net=net, wire=via2, |
| bottom_shape=bg1v8vref_m1pinbb, top_shape=bg1v8vref_m1pinbb, |
| ) |
| m3bb = lay.bounds(mask=m3.mask) |
| |
| shape = _geo.Rect.from_rect(rect=m3bb, top=vref1v8_m3pinbb.bottom) |
| layouter.add_wire(net=net, wire=m3, shape=shape) |