Source code for bag3_analog.layout.res.diff_res

# SPDX-License-Identifier: BSD-3-Clause AND Apache-2.0
# Copyright 2018 Regents of the University of California
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# * Redistributions of source code must retain the above copyright notice, this
#   list of conditions and the following disclaimer.
#
# * Redistributions in binary form must reproduce the above copyright notice,
#   this list of conditions and the following disclaimer in the documentation
#   and/or other materials provided with the distribution.
#
# * Neither the name of the copyright holder nor the names of its
#   contributors may be used to endorse or promote products derived from
#   this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

"""This module defines differential resistor loads."""
# TODO: support separate biases
# TODO: support common bias that is not the substrate

from typing import Mapping, Any, Optional, Type, cast

from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateDB

from pybag.enum import MinLenMode

from xbase.layout.res.base import ResBasePlaceInfo, ResArrayBase

from ...schematic.diff_res import bag3_analog__diff_res


[docs]class DiffRes(ResArrayBase): def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: ResArrayBase.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return bag3_analog__diff_res
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return dict( pinfo='The ResBasePlaceInfo object.', nx_dum='Number of dummies on each side, X direction', ny_dum='Number of dummies on each side, Y direction', diff='True to have differential resistor, false to have single resistor, True by default.', port_layer='Layer for rout and rout_b, top_layer by default', bias_node='Common bias terminal of differential resistors, VDD by default', double='True to have 2 pairs of differential resistors, False by default.',
) @classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: return dict(nx_dum=0, ny_dum=0, diff=True, port_layer=-1, bias_node='VDD', double=False)
[docs] def draw_layout(self) -> None: pinfo = cast(ResBasePlaceInfo, ResBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])) self.draw_base(pinfo) # Get hm_layer and vm_layer WireArrays warrs, bulk_warrs = self.connect_hm_vm() # Connect all dummies self.connect_dummies(warrs, bulk_warrs) # Connect to bulk self.connect_bulk_xm(bulk_warrs) unit_params = dict( w=pinfo.w_res, l=pinfo.l_res, intent=pinfo.res_type, ) nx, ny = pinfo.nx, pinfo.ny nx_dum: int = self.params['nx_dum'] ny_dum: int = self.params['ny_dum'] npar_tot = nx - 2 * nx_dum nser = ny - 2 * ny_dum diff: bool = self.params['diff'] double: bool = self.params['double'] if diff: if double: if npar_tot % 4 != 0: raise ValueError(f'npar_tot={npar_tot} has to be divisble by 4 when diff=double=True.') npar = npar_tot // 4 else: if npar_tot % 2: raise ValueError(f'npar_tot={npar_tot} has to be even when diff={diff}.') npar = npar_tot // 2 else: if double: raise ValueError('double has to be False when diff=False.') npar = npar_tot num_dum = nx * ny - npar_tot * nser # --- Routing of unit resistors --- # hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 ym_layer = xm_layer + 1 xxm_layer = ym_layer + 1 port_layer: int = self.params['port_layer'] if port_layer == -1: port_layer = pinfo.top_layer # make 2 resistors out of all the resistor units if diff: if double: rp_bot, rp_top = self.connect_units(warrs, nx_dum, nx_dum + npar, ny_dum, ny - ny_dum) rm_bot, rm_top = self.connect_units(warrs, nx_dum + npar, nx // 2, ny_dum, ny - ny_dum) rp_bot2, rp_top2 = self.connect_units(warrs, nx // 2, nx - nx_dum - npar, ny_dum, ny - ny_dum) rm_bot2, rm_top2 = self.connect_units(warrs, nx - nx_dum - npar, nx - nx_dum, ny_dum, ny - ny_dum) r_bias = self.connect_wires([rp_top, rm_top, rp_top2, rm_top2])[0] else: rp_bot, rp_top = self.connect_units(warrs, nx_dum, nx // 2, ny_dum, ny - ny_dum) rm_bot, rm_top = self.connect_units(warrs, nx // 2, nx - nx_dum, ny_dum, ny - ny_dum) rp_bot2, rm_bot2 = None, None r_bias = self.connect_wires([rp_top, rm_top])[0] align_p = -1 else: rp_bot, rp_top = self.connect_units(warrs, nx_dum, nx - nx_dum, ny_dum, ny - ny_dum) rm_bot = None rp_bot2, rm_bot2 = None, None r_bias = rp_top align_p = 0 # Supply connections on xxm_layer sub_type = cast(ResBasePlaceInfo, self.place_info).res_config['sub_type_default'] # sup_xxm0 = self.connect_via_stack(self.tr_manager, bulk_warrs[vm_layer][0], xxm_layer, 'sup') # sup_xxm1 = self.connect_via_stack(self.tr_manager, bulk_warrs[vm_layer][1], xxm_layer, 'sup') sup_name = 'VDD' if sub_type == 'ntap' else 'VSS' # self.add_pin(sup_name, [bulk_warrs[xm_layer][0], bulk_warrs[xm_layer][1]]) # connect bot vm_layers to xxm_layer mlm_dict_p = {xm_layer: MinLenMode.LOWER, xxm_layer: MinLenMode.LOWER} rp = self.connect_via_stack(self.tr_manager, rp_bot, port_layer, 'sig', align_p, 0, mlm_dict_p) rout_pin = 'rout<0>' if double else 'rout' self.add_pin(rout_pin, rp) if diff: mlm_dict_m = {xm_layer: MinLenMode.UPPER, xxm_layer: MinLenMode.UPPER} if double: port_tid = self.tr_manager.get_next_track_obj(rp, 'sig', 'sig', 1) rm = self.connect_via_stack(self.tr_manager, rm_bot, port_layer - 1, 'sig', 1, 0, mlm_dict_m) rm = self.connect_to_tracks(rm, port_tid) rp2 = self.connect_via_stack(self.tr_manager, rp_bot2, port_layer - 1, 'sig', align_p, 0, mlm_dict_p) rp2 = self.connect_to_tracks(rp2, port_tid) self.add_pin('rout<1>', rp2) rm2 = self.connect_via_stack(self.tr_manager, rm_bot2, port_layer, 'sig', 1, 0, mlm_dict_m) self.add_pin('rout_b<1>', rm2) else: rm = self.connect_via_stack(self.tr_manager, rm_bot, port_layer, 'sig', 1, 0, mlm_dict_m) routb_pin = 'rout_b<0>' if double else 'rout_b' self.add_pin(routb_pin, rm) # connect top vm_layers to bias_node bias_node: str = self.params['bias_node'] if bias_node == sup_name: self.connect_to_track_wires(r_bias, bulk_warrs[hm_layer][-2]) else: mlm_dict_m = {xm_layer: MinLenMode.UPPER, xxm_layer: MinLenMode.UPPER} rm = self.connect_via_stack(self.tr_manager, r_bias, port_layer, 'sig', 0, 0, mlm_dict_m) self.add_pin(bias_node, rm) self.sch_params = dict( load_params=dict( unit_params=unit_params, nser=nser, npar=npar, ), dum_params=dict( unit_params=unit_params, nser=1, npar=num_dum, ), sub_type=sub_type, diff=diff, bias_node=bias_node, double=double,
)
[docs]class DiffResVert(ResArrayBase): def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: ResArrayBase.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return bag3_analog__diff_res
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return dict( pinfo='The ResBasePlaceInfo object.', nx_dum='Number of dummies on each side, X direction', ny_dum='Number of dummies on each side, Y direction',
) @classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: return dict(nx_dum=0, ny_dum=0)
[docs] def draw_layout(self) -> None: pinfo = cast(ResBasePlaceInfo, ResBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])) self.draw_base(pinfo) # Get hm_layer and vm_layer WireArrays warrs, bulk_warrs = self.connect_hm_vm() # Connect all dummies self.connect_dummies(warrs, bulk_warrs) unit_params = dict( w=pinfo.w_res, l=pinfo.l_res, intent=pinfo.res_type, ) nx, ny = pinfo.nx, pinfo.ny nx_dum: int = self.params['nx_dum'] ny_dum: int = self.params['ny_dum'] npar = nx - 2 * nx_dum nser_tot = ny - 2 * ny_dum assert nser_tot & 1 == 0, f'ny - 2 * ny_dum = {nser_tot} should be even.' num_dum = nx * ny - npar * nser_tot # --- Routing of unit resistors --- # hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 ym_layer = xm_layer + 1 # make 2 resistors out of all the resistor units rp_bot, rp_top = self.connect_units(warrs, nx_dum, nx - nx_dum, ny // 2, ny - ny_dum) rm_bot, rm_top = self.connect_units(warrs, nx_dum, nx - nx_dum, ny_dum, ny // 2) # Supply connections on xm_layer sub_type = cast(ResBasePlaceInfo, self.place_info).res_config['sub_type_default'] sup_top0 = self.connect_via_stack(self.tr_manager, bulk_warrs[vm_layer][0], xm_layer, 'sup') sup_top1 = self.connect_via_stack(self.tr_manager, bulk_warrs[vm_layer][1], xm_layer, 'sup') sup_name = 'VDD' if sub_type == 'ntap' else 'VSS' self.add_pin(sup_name, [sup_top0, sup_top1]) # connect rout vm_layers to ym_layer r_p = self.connect_via_stack(self.tr_manager, rp_bot, ym_layer, 'sig') rb_p = self.connect_via_stack(self.tr_manager, rp_top, ym_layer, 'sig') sup_ym1 = self.connect_to_track_wires(sup_top1, rb_p) self.add_pin('rout', r_p) # connect rout_b vm_layers to ym_layer r_m = self.connect_via_stack(self.tr_manager, rm_top, ym_layer, 'sig') rb_m = self.connect_via_stack(self.tr_manager, rm_bot, ym_layer, 'sig') sup_ym0 = self.connect_to_track_wires(sup_top0, rb_m) self.add_pin('rout_b', r_m) self.add_pin(sup_name, [sup_ym0, sup_ym1]) self.sch_params = dict( load_params=dict( unit_params=unit_params, nser=nser_tot // 2, npar=npar, ), dum_params=dict( unit_params=unit_params, nser=1, npar=num_dum, ), sub_type=sub_type,
)