Source code for bag3_digital.layout.sampler.flop_strongarm

# SPDX-License-Identifier: Apache-2.0
# Copyright 2019 Blue Cheetah Analog Design Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""This module contains a strong arm based flop"""

from typing import Any, Dict, Type, Optional

from bag.util.math import HalfInt
from bag.util.immutable import Param
from bag.design.module import Module
from bag.layout.template import TemplateBase, TemplateDB

from xbase.layout.mos.base import MOSBasePlaceInfo, MOSBase

from ...schematic.flop_strongarm import bag3_digital__flop_strongarm
from .sr_latch import SRLatchSymmetric
from .strongarm import SAFrontend
from .strongarm_dig import SAFrontendDigital


[docs]class FlopStrongArm(MOSBase): def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: TemplateBase.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return bag3_digital__flop_strongarm
@classmethod
[docs] def get_params_info(cls) -> Dict[str, str]: return dict( pinfo='The placement information object.', sa_params='StrongArm parameters.', sr_params='SR latch parameters.', has_rstlb='True to enable rstlb functionality.', swap_outbuf='True to swap output buffers, so outp is on opposite side of inp.', out_pitch='output wire pitch from center.', export_mid='True to export intermediate nodes; False by default.',
) @classmethod
[docs] def get_default_param_values(cls) -> Dict[str, Any]: return dict( has_rstlb=False, swap_outbuf=False, out_pitch=0.5, export_mid=False,
)
[docs] def draw_layout(self) -> None: pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) sa_params: Param = self.params['sa_params'] sr_params: Param = self.params['sr_params'] has_rstlb: bool = self.params['has_rstlb'] swap_outbuf: bool = self.params['swap_outbuf'] out_pitch: HalfInt = HalfInt.convert(self.params['out_pitch']) export_mid: bool = self.params['export_mid'] # create masters sr_pinfo = self.get_tile_pinfo(1) sr_params = sr_params.copy(append=dict(pinfo=sr_pinfo, has_rstb=has_rstlb, has_inbuf=True, swap_outbuf=swap_outbuf, out_pitch=out_pitch)) sr_master: SRLatchSymmetric = self.new_template(SRLatchSymmetric, params=sr_params) even_center = sr_master.num_cols % 4 == 0 sa_pinfo = self.get_tile_pinfo(0) dig_style = (sa_pinfo == sr_pinfo) if dig_style: # digital style sa_params = sa_params.copy(append=dict(pinfo=sa_pinfo, has_rstb=has_rstlb, even_center=even_center)) sa_master: MOSBase = self.new_template(SAFrontendDigital, params=sa_params) else: # analog style sa_params = sa_params.copy(append=dict(pinfo=sa_pinfo, has_rstb=has_rstlb, even_center=even_center, vertical_out=False, vertical_rstb=False, export_mid=export_mid)) sa_master: MOSBase = self.new_template(SAFrontend, params=sa_params) # placement sa_ncol = sa_master.num_cols sr_ncol = sr_master.num_cols ncol = max(sa_ncol, sr_ncol) sa = self.add_tile(sa_master, 0, (ncol - sa_ncol) // 2) # NOTE: flip SR latch so outputs and inputs lines up nicely sr = self.add_tile(sr_master, 1, (ncol - sr_ncol) // 2 + sr_ncol, flip_lr=True) self.set_mos_size() # supplies self.add_pin('VSS', [sr.get_pin('VSS'), sa.get_pin('VSS')], connect=True) vdd = self.connect_wires([sr.get_pin('VDD'), sa.get_pin('VDD')])[0] self.add_pin('VDD', vdd) # connect outputs rb = sr.get_pin('rb') sb = sr.get_pin('sb') outp = sa.get_all_port_pins('outp') outn = sa.get_all_port_pins('outn') midp = self.connect_to_track_wires(outp, rb) midn = self.connect_to_track_wires(outn, sb) self.add_pin('midp', midp, hide=not export_mid) self.add_pin('midn', midn, hide=not export_mid) for _pin in ['tail', 'midp', 'midn']: self.reexport(sa.get_port(_pin), net_name=f'fe_{_pin}') # connect reset signals if has_rstlb: rstlb = sr.get_pin('rstlb') rsthb = sr.get_pin('rsthb') if dig_style: sa_rstb = sa.get_pin('rstb') rstlbl = self.connect_to_track_wires(sa_rstb, rstlb) rsthb = self.connect_to_tracks(vdd, rsthb.track_id, track_lower=rstlbl.lower, track_upper=rsthb.upper) self.add_pin('rstlb', sa_rstb) self.add_pin('rsthb', rsthb, hide=True) else: sa_rstbl = [sa.get_pin('prstbl'), sa.get_pin('nrstb')] sa_rstbr = [sa.get_pin('prstbr'), sa_rstbl[1]] rstlbl = self.connect_to_track_wires(sa_rstbl, rstlb) rstlbr = self.connect_to_tracks(sa_rstbr, rsthb.track_id) self.connect_to_tracks(rsthb, vdd.track_id) self.add_pin('rstlb', sa_rstbl[1]) self.add_pin('rstlb_vm_r', rstlbr, hide=True) self.add_pin('rstlb_vm_l', rstlbl, hide=True) # reexport pins for name in ['inp', 'inn', 'clk', 'clkl', 'clkr']: self.reexport(sa.get_port(name)) self.reexport(sr.get_port('q'), net_name='outp') self.reexport(sr.get_port('qb'), net_name='outn') self.sch_params = dict( sa_params=sa_master.sch_params.copy(remove=['has_rstb']), sr_params=sr_master.sch_params.copy(remove=['has_rstb']), has_rstlb=has_rstlb, export_mid=export_mid,
)