Source code for bag3_digital.layout.stdcells.inv_chain_gr

from typing import Any, Dict, Optional, Mapping, Type, List

from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB
from bag.layout.routing.base import WireArray
from bag.layout.enum import DrawTaps

from xbase.layout.mos.base import MOSBasePlaceInfo, MOSBase
from xbase.layout.mos.guardring import GuardRing
from xbase.layout.enum import MOSWireType

from ...schematic.inv_chain import bag3_digital__inv_chain
from .gates import InvChainCore


[docs]class InvChainCoreWithTaps(MOSBase): def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: ans = InvChainCore.get_params_info() ans.update( draw_taps='LEFT or RIGHT or BOTH or NONE', ) return ans
@classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: ans = InvChainCore.get_default_param_values() ans.update( draw_taps='NONE', ) return ans
@classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return bag3_digital__inv_chain
[docs] def draw_layout(self) -> None: pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) draw_taps: DrawTaps = DrawTaps[self.params['draw_taps']] # create masters inv_params = self.params.copy(remove=['draw_taps'], append=dict(is_guarded=True)) master = self.new_template(InvChainCore, params=inv_params) inv_ncol = master.num_cols hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 sep = max(self.min_sep_col, self.get_hm_sp_le_sep_col()) # taps sub_sep = self.sub_sep_col sup_info = self.get_supply_column_info(xm_layer) num_taps = 0 tap_offset = 0 tap_left = tap_right = False if draw_taps in DrawTaps.RIGHT | DrawTaps.BOTH: num_taps += 1 tap_right = True if draw_taps in DrawTaps.LEFT | DrawTaps.BOTH: num_taps += 1 tap_offset += sup_info.ncol + sub_sep // 2 tap_left = True # set total number of columns seg_tot = inv_ncol + (sup_info.ncol + sub_sep // 2) * num_taps self.set_mos_size(seg_tot) # --- Placement --- # cur_col = tap_offset inst = self.add_tile(master, 0, cur_col) cur_col += inv_ncol + sep # add taps lay_range = range(self.conn_layer, xm_layer + 1) vdd_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range} vss_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range} if tap_left: self.add_supply_column(sup_info, 0, vdd_table, vss_table) if tap_right: self.add_supply_column(sup_info, seg_tot, vdd_table, vss_table, flip_lr=True) # --- Routing --- # # 1. supplies self.connect_to_track_wires(inst.get_all_port_pins('VDD'), vdd_table[vm_layer]) self.connect_to_track_wires(inst.get_all_port_pins('VDD'), vdd_table[self.conn_layer]) self.connect_to_track_wires(inst.get_all_port_pins('VSS'), vss_table[vm_layer]) self.connect_to_track_wires(inst.get_all_port_pins('VSS'), vss_table[self.conn_layer]) vdd_xm = self.connect_wires(vdd_table[xm_layer]) vss_xm = self.connect_wires(vss_table[xm_layer]) self.add_pin('VDD', vdd_xm) self.add_pin('VSS', vss_xm) self.add_pin('VDD_vm', vdd_table[vm_layer], label='VDD') self.add_pin('VSS_vm', vss_table[vm_layer], label='VSS') self.reexport(inst.get_port('in')) self.reexport(inst.get_port('out')) # set properties self.sch_params = master.sch_params
[docs]class InvChainCoreWithTapRows(MOSBase): def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return InvChainCore.get_params_info()
@classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: return InvChainCore.get_default_param_values()
@classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return bag3_digital__inv_chain
[docs] def draw_layout(self) -> None: pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) # create masters tile_ptap = 0 tile_logic = 1 tile_ntap = 2 logic_pinfo = self.get_tile_pinfo(tile_idx=tile_logic) inv_params = self.params.copy(append=dict(vertical_sup=True), remove=['pinfo']) master = self.new_template(InvChainCore, params=dict(pinfo=logic_pinfo, **inv_params)) inv_ncol = master.num_cols # --- Placement --- # inst = self.add_tile(master, tile_logic, 0) self.add_substrate_contact(0, 0, tile_idx=tile_ptap, seg=inv_ncol) self.add_substrate_contact(0, 0, tile_idx=tile_ntap, seg=inv_ncol) self.set_mos_size() # --- Routing --- # # 1. supplies ptap_tid = self.get_track_id(0, MOSWireType.DS, 'sup', tile_idx=tile_ptap) vss_hm = self.connect_to_tracks(inst.get_all_port_pins('VSS'), ptap_tid) self.add_pin('VSS', vss_hm) ntap_tid = self.get_track_id(0, MOSWireType.DS, 'sup', tile_idx=tile_ntap) vdd_hm = self.connect_to_tracks(inst.get_all_port_pins('VDD'), ntap_tid) self.add_pin('VDD', vdd_hm) for pin in ['in', 'out', 'outb']: self.reexport(inst.get_port(pin)) # set properties self.sch_params = master.sch_params
[docs]class InvChainCoreGuardRing(GuardRing): def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: GuardRing.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return InvChainCoreWithTaps.get_schematic_class()
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: ans = dict( **InvChainCoreWithTaps.get_params_info(), pmos_gr='pmos guard ring tile name.', nmos_gr='nmos guard ring tile name.', edge_ncol='Number of columns on guard ring edge. Use 0 for default.', ) return ans
@classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: ans = dict( **InvChainCoreWithTaps.get_default_param_values(), pmos_gr='pgr', nmos_gr='ngr', edge_ncol=0, ) return ans
[docs] def get_layout_basename(self) -> str: return self.__class__.__name__
[docs] def draw_layout(self) -> None: params = self.params pmos_gr: str = params['pmos_gr'] nmos_gr: str = params['nmos_gr'] edge_ncol: int = params['edge_ncol'] core_params = params.copy(remove=['pmos_gr', 'nmos_gr', 'edge_ncol']) master = self.new_template(InvChainCoreWithTaps, params=core_params) sub_sep = master.sub_sep_col gr_sub_sep = master.gr_sub_sep_col sep_ncol_left = sep_ncol_right = sub_sep draw_taps: DrawTaps = DrawTaps[params['draw_taps']] if draw_taps in DrawTaps.RIGHT | DrawTaps.BOTH: sep_ncol_right = gr_sub_sep - sub_sep // 2 if draw_taps in DrawTaps.LEFT | DrawTaps.BOTH: sep_ncol_left = gr_sub_sep - sub_sep // 2 sep_ncol = (sep_ncol_left, sep_ncol_right) inst, sup_list = self.draw_guard_ring(master, pmos_gr, nmos_gr, sep_ncol, edge_ncol) vdd_hm_list, vss_hm_list = [], [] for (vss_list, vdd_list) in sup_list: vss_hm_list.extend(vss_list) vdd_hm_list.extend(vdd_list) self.connect_to_track_wires(vss_hm_list, inst.get_all_port_pins('VSS_vm')) self.connect_to_track_wires(vdd_hm_list, inst.get_all_port_pins('VDD_vm'))