Source code for bag3_digital.layout.serdes.ser2Nto1

from typing import Any, Optional, Mapping, Type

from pybag.enum import MinLenMode, PinMode, 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 xbase.layout.enum import MOSWireType

from ..stdcells.gates import InvTristateCore, InvCore
from .serNto1 import SerNto1
from ...schematic.ser2Nto1 import bag3_digital__ser2Nto1


[docs]class Ser2Nto1(MOSBase): 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__ser2Nto1
@classmethod
[docs] def get_params_info(cls) -> Mapping[str, str]: return dict( pinfo='The MOSBasePlaceInfo object.', ridx_p='pch row index', ridx_n='nch row index', seg_dict='Dictionary of segments', ratio='Number of serialized inputs for each serNto1', export_nets='True to export intermediate nets', tap_sep_flop='Horizontal separation between column taps in number of flops. Default is ratio // 2.'
) @classmethod
[docs] def get_default_param_values(cls) -> Mapping[str, Any]: return dict( ridx_p=-1, ridx_n=0, export_nets=False, tap_sep_flop=-1,
)
[docs] def draw_layout(self) -> None: pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo']) self.draw_base(pinfo) ridx_p: int = self.params['ridx_p'] ridx_n: int = self.params['ridx_n'] seg_dict: Mapping[str, int] = self.params['seg_dict'] ratio: int = self.params['ratio'] export_nets: bool = self.params['export_nets'] tap_sep_flop: int = self.params['tap_sep_flop'] # make masters ser_params = dict(pinfo=pinfo, seg_dict=seg_dict['ser'], ridx_p=ridx_p, ridx_n=ridx_n, ratio=ratio, tap_sep_flop=tap_sep_flop) ser_master = self.new_template(SerNto1, params=ser_params) ser_ncols = ser_master.num_cols ser_ntiles = ser_master.num_tile_rows tinv_params = dict(pinfo=pinfo, seg=seg_dict['tinv'], vertical_out=False) tinv_master = self.new_template(InvTristateCore, params=tinv_params) tinv_ncols = tinv_master.num_cols seg_inv = seg_dict.get('inv', 0) if seg_inv > 0: assert seg_inv & 1 == 0, f'seg_dict["inv"] = {seg_inv} must be even' pg_tidx = self.get_track_index(ridx_p, MOSWireType.G, 'sig', -2) inv_params = dict(pinfo=pinfo, seg=seg_inv // 2, vertical_out=False, sig_locs={'nin': pg_tidx}) inv_master = self.new_template(InvCore, params=inv_params) inv_sch_params = dict(**inv_master.sch_params) inv_sch_params['seg_p'] = inv_sch_params['seg_n'] = seg_inv else: inv_master = None inv_sch_params = None hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 w_clk_vm = self.tr_manager.get_width(vm_layer, 'clk') # --- Placement --- # cur_col = 0 ser0 = self.add_tile(ser_master, 0, cur_col) ser1 = self.add_tile(ser_master, 2 * ser_ntiles - 1, cur_col) cur_col += ser_ncols + self.sub_sep_col tinv0 = self.add_tile(tinv_master, ser_ntiles - 1, cur_col) tinv1 = self.add_tile(tinv_master, ser_ntiles, cur_col) _, vm_locs = self.tr_manager.place_wires(vm_layer, ['clk', 'clk', 'clk', 'clk'], center_coord=(cur_col + tinv_ncols // 2) * self.sd_pitch) inst_list = [ser0, ser1, tinv0, tinv1] dout_hm_list = [tinv0.get_pin('pout'), tinv0.get_pin('nout'), tinv1.get_pin('pout'), tinv1.get_pin('nout')] if seg_inv > 0: cur_col += tinv_ncols + self.min_sep_col inv0 = self.add_tile(inv_master, ser_ntiles - 1, cur_col) inv1 = self.add_tile(inv_master, ser_ntiles, cur_col) inst_list.extend([inv0, inv1]) # doutb inv0_pout = inv0.get_pin('pout') doutb_vm_tidx = self.grid.coord_to_track(vm_layer, inv0_pout.upper, RoundMode.NEAREST) doutb_vm = self.connect_to_tracks([inv0_pout, inv0.get_pin('nout'), inv1.get_pin('pout'), inv1.get_pin('nout')], TrackID(vm_layer, doutb_vm_tidx, w_clk_vm)) self.add_pin('doutb', doutb_vm) dout_hm_list.extend([inv0.get_pin('nin'), inv1.get_pin('nin')]) self.set_mos_size() # --- Routing --- # # supplies vdd_hm_list, vss_hm_list = [], [] lower = 0 upper = self.bound_box.xh for inst in inst_list: vdd_hm_list.append(inst.get_pin('VDD', layer=hm_layer)) vss_hm_list.append(inst.get_pin('VSS', layer=hm_layer)) lower = min(lower, vdd_hm_list[-1].lower, vss_hm_list[-1].lower) upper = max(upper, vdd_hm_list[-1].upper, vss_hm_list[-1].upper) vdd_hm = self.connect_wires(vdd_hm_list, lower=lower, upper=upper)[0] vss_hm = self.connect_wires(vss_hm_list, lower=lower, upper=upper)[0] vdd_xm = self.connect_wires([ser0.get_pin('VDD', layer=xm_layer), ser1.get_pin('VDD', layer=xm_layer)], lower=lower, upper=upper)[0] vss_xm = self.connect_wires([ser0.get_pin('VSS', layer=xm_layer), ser1.get_pin('VSS', layer=xm_layer)], lower=lower, upper=upper)[0] self.add_pin('VDD', [vdd_hm, vdd_xm]) self.add_pin('VSS', [vss_hm, vss_xm]) vdd_vm = ser0.get_all_port_pins('VDD_vm') + ser1.get_all_port_pins('VDD_vm') vss_vm = ser0.get_all_port_pins('VSS_vm') + ser1.get_all_port_pins('VSS_vm') self.add_pin('VDD_vm', vdd_vm, hide=True) self.add_pin('VSS_vm', vss_vm, hide=True) # doutb<0> and doutb<1> in_vm_tid = TrackID(vm_layer, vm_locs[0], w_clk_vm) doutb0_vm = self.connect_to_tracks(tinv0.get_pin('nin'), in_vm_tid, min_len_mode=MinLenMode.MIDDLE) doutb0_xm = self.connect_to_track_wires(doutb0_vm, ser0.get_pin('doutb')) self.add_pin('ser_outb<0>', doutb0_xm, hide=not export_nets, mode=PinMode.UPPER) doutb1_vm = self.connect_to_tracks(tinv1.get_pin('nin'), in_vm_tid, min_len_mode=MinLenMode.MIDDLE) doutb1_xm = self.connect_to_track_wires(doutb1_vm, ser1.get_pin('doutb')) self.add_pin('ser_outb<1>', doutb1_xm, hide=not export_nets, mode=PinMode.UPPER) # dout dout_vm = self.connect_to_tracks(dout_hm_list, TrackID(vm_layer, vm_locs[-1], w_clk_vm)) self.add_pin('dout', dout_vm) # clk and clkb clk_vm = self.connect_to_tracks([tinv0.get_pin('enb'), tinv1.get_pin('en')], TrackID(vm_layer, vm_locs[1], w_clk_vm)) clk_xm = self.connect_to_track_wires(clk_vm, ser0.get_pin('clk')) self.add_pin('clk', clk_xm, mode=PinMode.UPPER) clkb_vm = self.connect_to_tracks([tinv0.get_pin('en'), tinv1.get_pin('enb')], TrackID(vm_layer, vm_locs[-2], w_clk_vm)) clkb_xm = self.connect_to_track_wires(clkb_vm, ser1.get_pin('clk')) self.add_pin('clkb', clkb_xm, mode=PinMode.UPPER) # clk_div self.connect_wires([ser0.get_pin('clk_div', layer=vm_layer), ser1.get_pin('clk_div', layer=vm_layer)]) clk_div_xm = self.connect_wires([ser0.get_pin('clk_div', layer=xm_layer), ser1.get_pin('clk_div', layer=xm_layer)])[0] self.add_pin('clk_div', clk_div_xm, mode=PinMode.LOWER) # rst rst = self.connect_wires([ser0.get_pin('rst'), ser1.get_pin('rst')])[0] self.add_pin('rst', rst, mode=PinMode.LOWER) # inputs for idx in range(ratio): self.reexport(ser0.get_port(f'din<{idx}>'), net_name=f'din<{2 * idx}>') self.reexport(ser1.get_port(f'din<{idx}>'), net_name=f'din<{2 * idx + 1}>') # get schematic parameters self.sch_params = dict( ser=ser_master.sch_params, tinv=tinv_master.sch_params, inv=inv_sch_params, export_nets=export_nets,
)