Source code for bag3_digital.layout.stdcells.flop_diff

from typing import Any, Mapping, Optional, Type

from pybag.enum import RoundMode

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

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

from .latch_diff import LatchDiffCore
from ...schematic.flop_diff import bag3_digital__flop_diff


[docs]class FlopDiffCore(MOSBase): """Differential latch using tristate inverters""" def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) @classmethod
[docs] def get_schematic_class(cls) -> Optional[Type[Module]]: return bag3_digital__flop_diff
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return dict( pinfo='The MOSBasePlaceInfo object.', seg='number of segments of output inverter.', w_p='pmos width.', w_n='nmos width.', ridx_p='pmos row index.', ridx_n='nmos row index.', sig_locs='Signal track location dictionary.', fanout_in='input stage fanout.', fanout_kp='keeper stage fanout.', sep_vert_tracks='True to use separate vertical tracks for in and inb, and out and outb; False by default', vertical_clk='True to keep clocks unconnected on vertical tracks; False by default',
) @classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: return dict( w_p=0, w_n=0, ridx_p=-1, ridx_n=0, sig_locs=None, fanout_in=4, fanout_kp=8, sep_vert_tracks=False, vertical_clk=False,
)
[docs] def draw_layout(self) -> None: pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) sig_locs: Optional[Mapping[str, float]] = self.params['sig_locs'] if sig_locs is None: sig_locs = {} # --- make masters --- # latch0_master = self.new_template(LatchDiffCore, params=self.params.copy(append=dict(sep_vert_in=True), remove=['sep_vert_tracks'])) latch0_ncols = latch0_master.num_cols latch1_master = self.new_template(LatchDiffCore, params=self.params.copy(append=dict(sep_vert_out=True, vertical_in=False), remove=['sep_vert_tracks'])) latch1_ncols = latch1_master.num_cols # --- Placement --- # cur_col = 0 latch0 = self.add_tile(latch0_master, 0, cur_col) cur_col += latch0_ncols + self.min_sep_col latch1 = self.add_tile(latch1_master, 0, cur_col) cur_col += latch1_ncols self.set_mos_size(cur_col) # --- Routing --- # # supplies vss_list, vdd_list = [], [] for inst in (latch0, latch1): vss_list.extend(inst.get_all_port_pins('VSS')) vdd_list.extend(inst.get_all_port_pins('VDD')) self.add_pin('VDD', self.connect_wires(vdd_list)[0]) self.add_pin('VSS', self.connect_wires(vss_list)[0]) # inputs self.reexport(latch0.get_port('in')) self.reexport(latch0.get_port('inb')) # outputs self.reexport(latch1.get_port('out')) self.reexport(latch1.get_port('outb')) # middle nodes self.connect_to_track_wires(latch1.get_pin('in'), latch0.get_pin('out')) self.connect_to_track_wires(latch1.get_pin('inb'), latch0.get_pin('outb')) # clocks on xm_layer vertical_clk: bool = self.params['vertical_clk'] clk_vm = [latch0.get_pin('clkb'), latch1.get_pin('clk')] clkb_vm = [latch0.get_pin('clk'), latch1.get_pin('clkb')] if vertical_clk: self.add_pin('clk', clk_vm, connect=True) self.add_pin('clkb', clkb_vm, connect=True) else: hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 clk_xm_tidx = sig_locs.get('clk_xm', self.grid.coord_to_track(xm_layer, clk_vm[-1].lower, RoundMode.NEAREST)) clkb_xm_tidx = sig_locs.get('clkb_xm', self.grid.coord_to_track(xm_layer, clk_vm[-1].upper, RoundMode.NEAREST)) w_clk_xm = self.tr_manager.get_width(xm_layer, 'clk') clk_xm = self.connect_to_tracks([latch0.get_pin('clkb'), latch1.get_pin('clk')], TrackID(xm_layer, clk_xm_tidx, w_clk_xm)) self.add_pin('clk', clk_xm) clkb_xm = self.connect_to_tracks([latch0.get_pin('clk'), latch1.get_pin('clkb')], TrackID(xm_layer, clkb_xm_tidx, w_clk_xm)) self.add_pin('clkb', clkb_xm) # get schematic parameters self.sch_params = dict( latch=latch0_master.sch_params,
)