Source code for xbase.layout.esd_static.esd

from typing import Optional, Type, Any, Mapping

from bag.layout.template import TemplateBase, TemplateDB
from bag.layout.routing.base import WDictType, SpDictType, TrackManager, TrackID
from bag.design.module import Module
from bag.util.immutable import Param

from pybag.core import BBox, Transform
from pybag.enum import Orientation, RoundMode, MinLenMode

from . import ESDStatic
from ...schematic.esd import xbase__esd


[docs]class ESD(TemplateBase): """This class instantiates esd_vdd and esd_vss to make one complete unit ESD.""" def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: TemplateBase.__init__(self, temp_db, params, **kwargs) tr_widths: WDictType = self.params['tr_widths'] tr_spaces: SpDictType = self.params['tr_spaces'] self._tr_manager = TrackManager(self.grid, tr_widths, tr_spaces) self._conn_layer = -1 @property
[docs] def conn_layer(self) -> int: return self._conn_layer
@property
[docs] def tr_manager(self) -> TrackManager: return self._tr_manager
@classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return xbase__esd
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return dict( esd_p='library name and cell name for esd_p.', esd_n='library name and cell name for esd_n.', tr_widths='Track widths dictionary', tr_spaces='Track spaces dictionary',
)
[docs] def draw_layout(self) -> None: esd_p: Mapping[str, Any] = self.params['esd_p'] esd_n: Mapping[str, Any] = self.params['esd_n'] tr_widths: WDictType = self.params['tr_widths'] tr_spaces: SpDictType = self.params['tr_spaces'] tr_manager = self._tr_manager # make masters esd_p_master: ESDStatic = self.new_template(ESDStatic, params=dict(tr_widths=tr_widths, tr_spaces=tr_spaces, **esd_p)) esd_p_bbox = esd_p_master.bound_box esd_n_master: ESDStatic = self.new_template(ESDStatic, params=dict(tr_widths=tr_widths, tr_spaces=tr_spaces, **esd_n)) esd_n_bbox = esd_n_master.bound_box # Assume one unit ESD will have one esd_p and one esd_n. Generator can be extended to have programmable # number of esd_p and esd_n. tot_w = max(esd_p_bbox.w, esd_n_bbox.w) tot_h = esd_p_bbox.h + esd_n_bbox.h conn_layer = esd_p_master.conn_layer assert conn_layer == esd_n_master.conn_layer self._conn_layer = top_layer = esd_p_master.top_layer assert top_layer == esd_n_master.top_layer # add instances off_n = (tot_w - esd_n_bbox.w) // 2 inst_n = self.add_instance(esd_n_master, inst_name='XN', xform=Transform(dx=off_n)) off_p = (tot_w - esd_p_bbox.w) // 2 inst_p = self.add_instance(esd_p_master, inst_name='XP', xform=Transform(dx=off_p, dy=tot_h, mode=Orientation.MX)) self.set_size_from_bound_box(top_layer, BBox(0, 0, tot_w, tot_h), round_up=True) # --- Routing --- # vdd_n = inst_n.get_pin('VDD') vss_n = inst_n.get_pin('plus') term_n = inst_n.get_pin('minus') vdd_p = inst_p.get_pin('minus') vss_p = inst_p.get_pin('VSS') term_p = inst_p.get_pin('plus') top_ports = {} for port_p, port_n, name in [(vdd_p, vdd_n, 'VDD'), (vss_p, vss_n, 'VSS'), (term_p, term_n, 'term')]: assert port_p.track_id.base_index == port_n.track_id.base_index top_ports[name] = self.connect_wires([port_p, port_n])[0] if top_layer > conn_layer: for _layer in range(conn_layer + 1, top_layer + 1): _lower = min([warr.lower for warr in top_ports.values()]) _upper = max([warr.upper for warr in top_ports.values()]) _l_idx = self.grid.coord_to_track(_layer, _lower, RoundMode.GREATER_EQ) _r_idx = self.grid.coord_to_track(_layer, _upper, RoundMode.LESS_EQ) _num = tr_manager.get_num_wires_between(_layer, 'sup', _l_idx, 'sup', _r_idx, 'sup') + 2 if _num < 3: raise ValueError(f'Redo routing on layer={_layer}') _n = _num // 3 _idx_list = tr_manager.spread_wires(_layer, ['sup', 'sup', 'sup'] * _n, _l_idx, _r_idx, ('sup', 'sup')) _p = (_idx_list[1] - _idx_list[0]) * 3 w_sup = tr_manager.get_width(_layer, 'sup') vss_tid = TrackID(_layer, _idx_list[0], w_sup, _n, _p) top_ports['VSS'] = self.connect_to_tracks(top_ports['VSS'], vss_tid, min_len_mode=MinLenMode.MIDDLE) term_tid = TrackID(_layer, _idx_list[1], w_sup, _n, _p) top_ports['term'] = self.connect_to_tracks(top_ports['term'], term_tid, min_len_mode=MinLenMode.MIDDLE) vdd_tid = TrackID(_layer, _idx_list[2], w_sup, _n, _p) top_ports['VDD'] = self.connect_to_tracks(top_ports['VDD'], vdd_tid, min_len_mode=MinLenMode.MIDDLE) for pin in ('VDD', 'VSS', 'term'): self.add_pin(pin, top_ports[pin]) # set schematic parameters self.sch_params = dict( esd_p=esd_p_master.sch_params, esd_n=esd_n_master.sch_params,
)