Source code for bag3_magnetics.layout.inductor_spiral.ind_spiral

from typing import Mapping, Any

from bag.layout.template import TemplateDB
from bag.layout.util import BBox
from bag.util.immutable import Param

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

from .util import IndSpiralTemplate
from .ind_spiral_core import IndSpiralCore


[docs]class IndSpiral(IndSpiralTemplate): """Spiral inductor with multiple turns across multiple layers, 'R0' orientation""" def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: IndSpiralTemplate.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return dict( n_turns='Number of turns; 1 by default', lay_id='Inductor top layer ID', bot_lay_id='Inductor bottom layer ID', radius='Outermost radius', width='Width of inductor sides', spacing='Spacing between inductor turns', lead_width='Width of inductor leads', lead_spacing='Spacing between inductor leads',
) @classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: return dict( n_turns=1,
)
[docs] def draw_layout(self) -> None: n_turns: int = self.params['n_turns'] lay_id: int = self.params['lay_id'] bot_lay_id: int = self.params['bot_lay_id'] n_layers = lay_id - bot_lay_id + 1 if n_layers & 1: raise ValueError('This generator expects even number of layers so that both ends of the spiral are on ' 'the outside') radius: int = self.params['radius'] width: int = self.params['width'] spacing: int = self.params['spacing'] lead_width: int = self.params['lead_width'] lead_spacing: int = self.params['lead_spacing'] # check feasibility outer_radius = radius + width // 2 _turns = n_turns + 1 assert outer_radius >= _turns * (width + spacing), f'Either increase radius={radius} or decrease ' \ f'width={width} or spacing={spacing} or n_turns={n_turns}' sch_params = dict() for _lay_id in range(lay_id, bot_lay_id - 1, -1): draw_lead = _lay_id == lay_id or _lay_id == bot_lay_id _master: IndSpiralCore = self.new_template(IndSpiralCore, params=dict(n_turns=n_turns, lay_id=_lay_id, radius=radius, width=width, spacing=spacing, lead_width=lead_width, lead_spacing=lead_spacing, interleave=False, draw_lead=draw_lead)) _bbox = _master.actual_bbox flip = (lay_id & 1) != (_lay_id & 1) _top_lp = self.grid.tech_info.get_lay_purp_list(_lay_id)[0] _bot_lp = self.grid.tech_info.get_lay_purp_list(_lay_id - 1)[0] _bot_dir = self.grid.get_direction(_lay_id - 1) _xshift = (lead_width + lead_spacing) // 2 if flip: transform = Transform(dx=_bbox.xh, mode=Orientation.MY) _inst = self.add_instance(_master, inst_name=f'XCORE_{_lay_id}', xform=transform) if _lay_id != bot_lay_id: # draw via outside spiral xm, ym = _master.vertex_out xm -= _xshift via_bbox = BBox(xm - _xshift, ym - width // 2, xm + _xshift, ym + width // 2) self.add_via(via_bbox, _bot_lp, _top_lp, _bot_dir, extend=False) else: _inst = self.add_instance(_master, inst_name=f'XCORE_{_lay_id}') # draw via inside spiral xm, ym = _master.vertex_in xm += _xshift via_bbox = BBox(xm - _xshift, ym - width // 2, xm + _xshift, ym + width // 2) self.add_via(via_bbox, _bot_lp, _top_lp, _bot_dir, extend=False) if draw_lead: # add metal resistor term: BBox = _inst.get_pin('term0') mres_w = term.w mres_l = mres_w // 2 _rbox = BBox(term.xl, term.yl - mres_l, term.xh, term.yl) self.add_res_metal(_lay_id, _rbox) _name = 'plus' if _lay_id == lay_id else 'minus' sch_params[_name] = dict(w=mres_w, l=mres_l, layer=_lay_id) # extend metal beyond metal resistor lower = term.yl - mres_l - mres_w // 4 - mres_w self.add_rect(_top_lp, BBox(term.xl, lower, term.xh, term.yh)) self.add_pin_primitive(_name, _top_lp[0], BBox(term.xl, lower, term.xh, lower + mres_w), hide=True) # set size self._actual_bbox = BBox(0, 0, 2 * outer_radius, 2 * outer_radius) self.set_size_from_bound_box(lay_id, self._actual_bbox, round_up=True) self.sch_params = sch_params