Source code for bag3_magnetics.layout.inductor.ind_diff_wrap

# -*- coding: utf-8 -*-
from typing import Mapping, Any, Optional, Type

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

from pybag.core import Transform
from pybag.enum import Orientation, PathStyle

from .util import IndTemplate
from .ind_core import IndCore
from .ind_ring import IndRing
from ...schematic.ind_diff_wrap import bag3_magnetics__ind_diff_wrap


[docs]class IndDiffWrap(IndTemplate): """A wrapper for differential non-interleaved inductors.""" def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: IndTemplate.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return bag3_magnetics__ind_diff_wrap
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return dict( lay_id='Inductor top layer ID', bot_lay_id='Inductor bot layer ID; same as top layer by default', n_turns='Number of turns; 1 by default', width='Metal width for inductor turns', spacing='Metal spacing between inductor turns', radius_x='radius along X-axis in R0 orientation of single inductor, will be rotated by 90 degrees', radius_y='radius along Y-axis in R0 orientation of single inductor, will be rotated by 90 degrees', term_sp='Spacing between inductor terminals', common_term='True to have one common terminal for differential inductors; False by default', w_ring='True to have guard ring, False by default', ring_specs='Specs for guard ring, Optional',
) @classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: return dict( bot_lay_id=-1, n_turns=1, common_term=False, w_ring=False, ring_specs=None,
)
[docs] def draw_layout(self) -> None: lay_id: int = self.params['lay_id'] bot_lay_id: int = self.params['bot_lay_id'] if bot_lay_id < 1: bot_lay_id = lay_id if bot_lay_id < lay_id: n_turns = 2 else: n_turns: int = self.params['n_turns'] width: int = self.params['width'] spacing: int = self.params['spacing'] radius_x: int = self.params['radius_x'] radius_y: int = self.params['radius_y'] term_sp: int = self.params['term_sp'] common_term: bool = self.params['common_term'] w_ring: bool = self.params['w_ring'] ring_specs: Optional[Mapping[str, Any]] = self.params['ring_specs'] # make inductor core core_params = dict( lay_id=lay_id, bot_lay_id=bot_lay_id, n_turns=n_turns, width=width, spacing=spacing, radius_x=radius_x, radius_y=radius_y, term_sp=-1, ind_shape='Rectangle', ) core_master: IndCore = self.new_template(IndCore, params=core_params) # make inductor guard ring if w_ring: ring_width: int = ring_specs['width'] ring_spacing: int = ring_specs['spacing'] ring_gap_spacing: int = ring_specs.get('gap_spacing', ring_spacing) gap = term_sp + 2 * width + 2 * ring_gap_spacing + ring_width if common_term: gap_top = width + 2 * ring_gap_spacing + ring_width ring_sup_top = 'P2_R' else: gap_top = gap ring_sup_top = 'P24_R' ring_params = dict( lay_id=lay_id, bot_lay_id=bot_lay_id, width=ring_width, gap=gap, gap_top=gap_top, radius_x=term_sp // 2 + 2 * radius_y + width + ring_spacing + ring_width // 2, radius_y=radius_x + width // 2 + ring_spacing + ring_width // 2, ring_sup='P13_R', ring_sup_top=ring_sup_top, ring_pin_w=term_sp + 2 * width, ) dx = dy = ring_width + ring_spacing ring_master: IndRing = self.new_template(IndRing, params=ring_params) ring_inst = self.add_instance(ring_master, inst_name='XRING') for pin in ['P13_R', ring_sup_top]: self.reexport(ring_inst.get_port(pin)) self._actual_bbox = ring_master.actual_bbox else: raise NotImplementedError # place 2 inductors self.add_instance(core_master, inst_name='XCORE_L', xform=Transform(dx=dx + 2 * radius_y + width, dy=dy, mode=Orientation.R90)) self.add_instance(core_master, inst_name='XCORE_R', xform=Transform(dx=dx + 2 * radius_y + width + term_sp, dy=dy, mode=Orientation.MXR90)) # draw leads and add pins width2 = width // 2 res1_l = width // 4 res2_l = width // 2 res3_l = width // 4 * 3 res4_l = width lp = self.grid.tech_info.get_lay_purp_list(lay_id)[0] bot_term_coords = [(dx + 2 * radius_y + width2, dy + width2), (dx + 2 * radius_y + width + term_sp + width2, dy + width2)] term1, term3 = self._draw_leads(lay_id, width, bot_term_coords, res1_l, res3_l) self.add_pin_primitive('P1', lp[0], term1) self.add_pin_primitive('P3', lp[0], term3) top_term_coords = [(dx + 2 * radius_y + width2, dy + 2 * radius_x + width2), (dx + 2 * radius_y + width + term_sp + width2, dy + 2 * radius_x + width2)] if common_term: self._draw_bridge(top_term_coords[0], top_term_coords[-1], lay_id, lay_id, lay_id, width, PathStyle.extend) top_term_coord = (dx + 2 * radius_y + width + term_sp // 2, dy + 2 * radius_x + width2) term2 = self._draw_lead(lay_id, width, top_term_coord, res2_l, self._actual_bbox.yh, True) else: term2, term4 = self._draw_leads(lay_id, width, top_term_coords, res2_l, res4_l, self._actual_bbox.yh, True) self.add_pin_primitive('P4', lp[0], term4) self.add_pin_primitive('P2', lp[0], term2) # add inductor ID layer id_lp = self.grid.tech_info.tech_params['inductor'].get('id_lp', []) for _lp in id_lp: self.add_rect(_lp, self._actual_bbox) # set size self.set_size_from_bound_box(lay_id, self._actual_bbox, round_up=True) # get schematic parameters self.sch_params = dict( res1_l=res1_l, res2_l=res2_l, res3_l=res3_l, res4_l=res4_l, res_w=width, res_layer=lay_id, common_term=common_term, w_ring=w_ring,
)