Source code for bag3_digital.layout.serdes.serNto1_fast

from typing import Any, Optional, Mapping, Type, Sequence, Union, Tuple
from itertools import chain

from pybag.enum import MinLenMode, RoundMode, PinMode

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

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

from ..stdcells.gates import InvCore, InvTristateCore, InvChainCore
from ..stdcells.memory import FlopCore
from ...schematic.serNto1_fast import bag3_digital__serNto1_fast


[docs]class SerNto1Fast(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__serNto1_fast
@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', export_nets='True to export intermediate nets', tap_sep_flop='Horizontal separation between column taps in number of flops. Default is ratio // 2.', is_rst_async='True if asynchronous rst input; False if synchronous rstb input. True by default',
) @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, is_rst_async=True
)
[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'] if tap_sep_flop <= 0: tap_sep_flop = ratio >> 1 is_rst_async: bool = self.params['is_rst_async'] # --- Make masters --- # # flops ff_params = dict(pinfo=pinfo, seg=seg_dict['ff']) ff_master = self.new_template(FlopCore, params=ff_params) ff_ncols = ff_master.num_cols ff_rst_params = dict(pinfo=pinfo, seg=seg_dict['ff'], resetable=True, rst_type='RESET') ff_rst_master = self.new_template(FlopCore, params=ff_rst_params) ff_rst_ncols = ff_rst_master.num_cols ff_set_params = dict(pinfo=pinfo, seg=seg_dict['ff'], resetable=True, rst_type='SET') ff_set_master = self.new_template(FlopCore, params=ff_set_params) # sig_locs for inverters in clk_div inverter chain pd1_tidx = self.get_track_index(ridx_p, MOSWireType.DS, 'sig', 1) pd0_tidx = self.get_track_index(ridx_p, MOSWireType.DS, 'sig', 0) pg1_tidx = self.get_track_index(ridx_p, MOSWireType.G, 'sig', -2) pg0_tidx = self.get_track_index(ridx_p, MOSWireType.G, 'sig', -3) ng_tidx = self.get_track_index(ridx_n, MOSWireType.G, 'sig', 1) nd1_tidx = self.get_track_index(ridx_n, MOSWireType.DS, 'sig', -1) nd0_tidx = self.get_track_index(ridx_n, MOSWireType.DS, 'sig', -2) seg_clk: int = seg_dict['inv_clk'] assert seg_clk & 1 == 0, f'seg_dict["inv_clk"]={seg_clk} has to be even.' inv_0_params = dict(pinfo=pinfo, seg=seg_clk, vertical_out=False, sig_locs={'in': ng_tidx, 'pout': pd0_tidx, 'nout': nd1_tidx}) inv_0_master = self.new_template(InvCore, params=inv_0_params) inv_1_params = dict(pinfo=pinfo, seg=seg_clk, vertical_out=False, sig_locs={'in': pg1_tidx, 'pout': pd1_tidx, 'nout': nd0_tidx}) inv_1_master = self.new_template(InvCore, params=inv_1_params) inv_clk_ncols = inv_0_master.num_cols # inverter for fast clk and clkb seg_clk_fast = 2 * seg_clk inv_clk_params = dict(pinfo=pinfo, seg=seg_clk_fast, vertical_out=False, sig_locs={'in': pg1_tidx}) inv_clk_master = self.new_template(InvCore, params=inv_clk_params) # inverter chain for p0 inv_en_params = dict(pinfo=pinfo, seg_list=seg_dict['inv_en'], dual_output=True, sig_locs={'nin0': pg0_tidx, 'nin1': ng_tidx}) inv_en_master = self.new_template(InvChainCore, params=inv_en_params) inv_en_ncols = inv_en_master.num_cols # inverter chain for rst inv_r_params = dict(pinfo=pinfo, seg_list=seg_dict['inv_rst'], dual_output=True, sig_locs={'nin0': pg0_tidx, 'nin1': ng_tidx}) inv_r_master = self.new_template(InvChainCore, params=inv_r_params) inv_r_ncols = inv_r_master.num_cols # tristate inverters tinv_params = dict(pinfo=pinfo, seg=seg_dict['tinv'], vertical_out=False, sig_locs={'nin': pg0_tidx, 'pout': pd1_tidx, 'nout': nd0_tidx}) tinv_master = self.new_template(InvTristateCore, params=tinv_params) tinv_ncols = tinv_master.num_cols # data inverters seg_data: int = seg_dict['inv_data'] assert seg_data & 1 == 0, f'seg_dict["inv_data"]={seg_data} has to be even.' inv_d_params = dict(pinfo=pinfo, seg=seg_data // 2, vertical_out=False, sig_locs={'in': ng_tidx, 'pout': pd0_tidx, 'nout': nd1_tidx}) inv_d_master = self.new_template(InvCore, params=inv_d_params) inv_d_sch = dict(**inv_d_master.sch_params) inv_d_sch['seg_p'] = inv_d_sch['seg_n'] = seg_data inv_d_ncols = inv_d_master.num_cols hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 ym_layer = xm_layer + 1 xxm_layer = ym_layer + 1 # --- Placement --- # blk_sp = self.min_sep_col sub_sep = self.sub_sep_col seg_tap = 4 tap_ncols = self.get_tap_ncol(seg_tap) num_tiles = 3 # left tap vdd_list = [[] for _ in range(num_tiles)] vss_list = [[] for _ in range(num_tiles)] for idx in range(num_tiles): self.add_tap(0, vdd_list[idx], vss_list[idx], tile_idx=idx, seg=seg_tap) sup_coords = [self.grid.track_to_coord(self.conn_layer, tap_ncols >> 1)] cur_col = tap_ncols + sub_sep - blk_sp # flops ff_f_list, ff_s_list, ff_rst_list = [], [], [] clk_list0, clkb_list0 = [], [] clk_list1, clkb_list1 = [], [] clk_div_list, clk_divb_list = [], [] tinv_f_list, tinv_s_list = [], [] en_list, enb_list = [], [] inv_r = None inv_en = None p0_list = [] _d = None dout_vm = None w_sig_vm = self.tr_manager.get_width(vm_layer, 'sig') rst_hm_list, rst_vm_list = [], [] in_list = [] for idx in range(ratio + 1): if idx > 0 and idx % tap_sep_flop == 0: # mid tap cur_col += sub_sep for tidx in range(num_tiles): self.add_tap(cur_col, vdd_list[tidx], vss_list[tidx], tile_idx=tidx, seg=seg_tap) sup_coords.append(self.grid.track_to_coord(self.conn_layer, cur_col + (tap_ncols >> 1))) cur_col += tap_ncols + sub_sep else: cur_col += blk_sp # tile 0: p0 counter cur_col0 = cur_col if idx == ratio: inv_en = self.add_tile(inv_en_master, 0, cur_col0) cur_col0 += inv_en_ncols # inv_en input p0_list.append(self.connect_to_track_wires(inv_en.get_pin('nin'), ff_rst_list[-1].get_pin('out'))) self.add_pin('p<0>', p0_list[-1], hide=not export_nets) # inv_en out and outb en_list.append(inv_en.get_pin('out')) enb_list.append(inv_en.get_pin('outb')) cur_col0 += blk_sp + inv_r_ncols inv_r = self.add_tile(inv_r_master, 0, cur_col0, flip_lr=True) # rstb_sync ff_set = ff_rst_list[-1] self.connect_to_track_wires(ff_set.get_pin('psetb'), inv_r.get_pin('out')) rst_vm_list.append(inv_r.get_pin('outb')) else: ff_rst = self.add_tile(ff_rst_master if idx < ratio - 1 else ff_set_master, 0, cur_col0) ff_rst_list.append(ff_rst) cur_col0 += ff_rst_ncols # ff_rst is on clkb clk_vm = ff_rst.get_pin('clk') clkb_list0.append(clk_vm) clk_list0.append(ff_rst.get_pin('clkb')) # ff_rst input if idx == 0: in_vm_tid = self.tr_manager.get_next_track_obj(clk_vm, 'sig', 'sig', count_rel_tracks=-1) p0_list.append(self.connect_to_tracks(ff_rst.get_pin('pin'), in_vm_tid, min_len_mode=MinLenMode.MIDDLE)) else: _p = self.connect_to_track_wires(ff_rst.get_pin('pin'), ff_rst_list[-2].get_pin('out')) self.add_pin(f'p<{idx}>', _p, hide=not export_nets) # ff_rst rst if idx < ratio - 1: rst_hm = ff_rst.get_pin('prst') rst_hm_list.append(rst_hm) rst_vm_tid = self.tr_manager.get_next_track_obj(ff_rst.get_pin('out'), 'sig', 'sig', 1) rst_vm_list.append(self.connect_to_tracks(rst_hm, rst_vm_tid, min_len_mode=MinLenMode.LOWER)) # tile 1: fast flops and tinv and data inverter tinv_out_list, inv_out_list = [], [] en_hm_list, enb_hm_list = [], [] cur_col1 = cur_col if idx > 0: ff_f = self.add_tile(ff_master, 1, cur_col1) ff_f_list.append(ff_f) cur_col1 += ff_ncols clk_list1.append(ff_f.get_pin('clk')) clkb_list1.append(ff_f.get_pin('clkb')) # ff_f input self.connect_to_track_wires(ff_f.get_pin('nin'), _d) if idx < ratio: cur_col1 += blk_sp tinv_f = self.add_tile(tinv_master, 1, cur_col1) cur_col1 += tinv_ncols + blk_sp inv_f = self.add_tile(inv_d_master, 1, cur_col1) cur_col1 += inv_d_ncols tinv_f_list.extend([tinv_f, inv_f]) # ff_f output to tinv_f input self.connect_to_track_wires(tinv_f.get_pin('nin'), ff_f.get_pin('out')) # tinv_f output, inv_f input and output tinv_out_list.extend([tinv_f.get_pin('pout'), tinv_f.get_pin('nout'), inv_f.get_pin('nin')]) inv_out_list.extend([inv_f.get_pin('pout'), inv_f.get_pin('nout')]) # tinv_f enable en_hm_list.append(tinv_f.get_pin('enb')) enb_hm_list.append(tinv_f.get_pin('en')) else: dout_vm = ff_f.get_pin('out') # tile 2: slow flops and tinv and data inverter cur_col2 = cur_col if idx < ratio: ff_s = self.add_tile(ff_master, 2, cur_col2) ff_s_list.append(ff_s) cur_col2 += ff_ncols clk_div_vm = ff_s.get_pin('clk') clk_div_list.append(clk_div_vm) clk_divb_list.append(ff_s.get_pin('clkb')) # ff_s input in_vm_tid = self.tr_manager.get_next_track_obj(clk_div_vm, 'sig', 'sig', count_rel_tracks=-1) in_vm = self.connect_to_tracks(ff_s.get_pin('pin'), in_vm_tid, min_len_mode=MinLenMode.MIDDLE) in_list.append(in_vm) if idx > 0: cur_col2 += blk_sp tinv_s = self.add_tile(tinv_master, 2, cur_col2) cur_col2 += tinv_ncols + blk_sp inv_s = self.add_tile(inv_d_master, 2, cur_col2) cur_col2 += inv_d_ncols tinv_s_list.extend([tinv_s, inv_s]) _tidx = self.grid.coord_to_track(vm_layer, cur_col2 * self.sd_pitch, RoundMode.NEAREST) _, _vm_locs = self.tr_manager.place_wires(vm_layer, ['sig'] * 5, _tidx, -1) # ff_s output to tinv_s input self.connect_to_track_wires(tinv_s.get_pin('nin'), ff_s.get_pin('out')) # tinv_s output, inv_s input and output tinv_out_list.extend([tinv_s.get_pin('pout'), tinv_s.get_pin('nout'), inv_s.get_pin('nin')]) self.connect_to_tracks(tinv_out_list, TrackID(vm_layer, _vm_locs[-3], w_sig_vm)) inv_out_list.extend([inv_s.get_pin('pout'), inv_s.get_pin('nout')]) _d = self.connect_to_tracks(inv_out_list, TrackID(vm_layer, _vm_locs[-1], w_sig_vm)) # tinv_s enable en_hm_list.append(tinv_s.get_pin('en')) enb_hm_list.append(tinv_s.get_pin('enb')) enb_list.append(self.connect_to_tracks(enb_hm_list, TrackID(vm_layer, _vm_locs[0], w_sig_vm))) en_list.append(self.connect_to_tracks(en_hm_list, TrackID(vm_layer, _vm_locs[1], w_sig_vm))) else: _d = ff_s.get_pin('out') self.add_pin(f'd<{ratio - 1 - idx}>', _d, hide=not export_nets) cur_col = max(cur_col0, cur_col1, cur_col2) inst0_list = [inv_r, inv_en] inst1_list = [] # flops for reset synchronizer if is_rst_async: cur_col += blk_sp rst_ff0 = self.add_tile(ff_rst_master, 0, cur_col + ff_rst_ncols, flip_lr=True) inst0_list.append(rst_ff0) clkb_list0.append(rst_ff0.get_pin('clk')) clk_list0.append(rst_ff0.get_pin('clkb')) self.connect_to_track_wires(inv_r.get_pin('in'), rst_ff0.get_pin('out')) # extra blk_sp so that rst_ff1 output on vm_layer can go down to rst_ff0 input cur_col += ff_rst_ncols + blk_sp rst_ff1 = self.add_tile(ff_rst_master, 1, cur_col - ff_rst_ncols) inst1_list.append(rst_ff1) rst_ff1_clkb = rst_ff1.get_pin('clk') clkb_list1.append(rst_ff1_clkb) clk_list1.append(rst_ff1.get_pin('clkb')) _in_vm_tid = self.tr_manager.get_next_track_obj(rst_ff1_clkb, 'sig', 'sig', -1) self.connect_to_tracks([rst_ff1.get_pin('nin'), rst_ff1.get_pin('VDD')], _in_vm_tid) rst_ff1_out = rst_ff1.get_pin('out') self.connect_to_track_wires(rst_ff0.get_pin('nin'), rst_ff1_out) rstb_in_vm = None rst_sync_sch_params = dict(ff=ff_rst_master.sch_params, buf=inv_r_master.sch_params) _p0_ym_idx = -3 else: rst_ff1_out = None rst_ff0 = rst_ff1 = None _tid = self.tr_manager.get_next_track_obj(inv_r.get_pin('outb'), 'sig', 'sig', 1) rstb_in_vm = self.connect_to_tracks(inv_r.get_pin('in'), _tid) rst_sync_sch_params = inv_r_master.sch_params _p0_ym_idx = -2 # clock inverters chains cur_col += blk_sp _lower_idx = self.grid.coord_to_track(vm_layer, cur_col * self.sd_pitch, RoundMode.GREATER) cur_col += inv_clk_ncols invs_1 = self.add_tile(inv_1_master, 2, cur_col, flip_lr=True) cur_col += inv_clk_ncols _upper_idx = self.grid.coord_to_track(vm_layer, cur_col * self.sd_pitch, RoundMode.LESS) invs_0 = self.add_tile(inv_0_master, 2, cur_col, flip_lr=True) invf_0 = self.add_tile(inv_clk_master, 0, cur_col, flip_lr=True) invf_1 = self.add_tile(inv_clk_master, 1, cur_col, flip_lr=True) inst0_list.append(invf_0) inst1_list.append(invf_1) # try to fit as many vm_layer tracks as possible clk_vm_locs = [] vm_clk_num = 1 for vm_clk_num in range(4, 0, -1): try: _num = (vm_clk_num * 2 - 1) * 2 + 3 clk_vm_locs = self.tr_manager.spread_wires(vm_layer, ['clk'] * _num, _lower_idx, _upper_idx, ('clk', 'clk')) break except ValueError: continue assert vm_clk_num > 0, 'Redo routing' # right tap cur_col += sub_sep for idx in range(num_tiles): self.add_tap(cur_col, vdd_list[idx], vss_list[idx], tile_idx=idx, seg=seg_tap) sup_coords.append(self.grid.track_to_coord(self.conn_layer, cur_col + (tap_ncols >> 1))) self.set_mos_size() xh = self.bound_box.xh yh = self.bound_box.yh # --- Routing --- # # supplies vss_hm_list = [[] for _ in range(num_tiles)] vdd_hm_list = [[] for _ in range(num_tiles)] for inst in chain(ff_rst_list, inst0_list): vss_hm_list[0].append(inst.get_pin('VSS')) vdd_hm_list[0].append(inst.get_pin('VDD')) for inst in chain(ff_f_list, tinv_f_list, inst1_list): vss_hm_list[1].append(inst.get_pin('VSS')) vdd_hm_list[1].append(inst.get_pin('VDD')) for inst in chain(ff_s_list, tinv_s_list, [invs_1, invs_0]): vss_hm_list[2].append(inst.get_pin('VSS')) vdd_hm_list[2].append(inst.get_pin('VDD')) vss_hm, vdd_hm = [], [] for idx in range(num_tiles): vss_hm.append(self.connect_to_track_wires(vss_list[idx], self.connect_wires(vss_hm_list[idx])[0])) vdd_hm.append(self.connect_to_track_wires(vdd_list[idx], self.connect_wires(vdd_hm_list[idx])[0])) vss_hm = self.connect_wires(vss_hm, lower=0, upper=xh)[0] vdd_hm = self.connect_wires(vdd_hm, lower=0, upper=xh)[0] vdd_dict, vss_dict = self.connect_supplies(vdd_hm, vss_hm, sup_coords, xh, yh) self.add_pin('VDD_ym', vdd_dict[ym_layer], hide=True) self.add_pin('VSS_ym', vss_dict[ym_layer], hide=True) # find xm_layer and xxm_layer tracks using supply tracks as reference xm_locs0 = self.tr_manager.spread_wires(xm_layer, ['sup', 'clk', 'clk', 'clk', 'clk', 'sup'], lower=vss_dict[xm_layer][0].track_id.base_index, upper=vdd_dict[xm_layer][0].track_id.base_index, sp_type=('clk', 'clk')) xm_locs1 = self.tr_manager.spread_wires(xm_layer, ['sup', 'clk', 'clk', 'clk', 'clk', 'sup'], lower=vdd_dict[xm_layer][0].track_id.base_index, upper=vss_dict[xm_layer][1].track_id.base_index, sp_type=('clk', 'clk')) xm_locs2 = self.tr_manager.spread_wires(xm_layer, ['sup', 'clk', 'clk', 'clk', 'clk', 'sup'], lower=vss_dict[xm_layer][1].track_id.base_index, upper=vdd_dict[xm_layer][1].track_id.base_index, sp_type=('clk', 'clk')) xxm_locs0 = self.tr_manager.spread_wires(xxm_layer, ['sup', 'clk', 'sig', 'sig', 'clk', 'sup'], lower=vss_dict[xxm_layer][0].track_id.base_index, upper=vdd_dict[xxm_layer][0].track_id.base_index, sp_type=('clk', 'clk')) xxm_locs1 = self.tr_manager.spread_wires(xxm_layer, ['sup', 'clk', 'sig', 'sig', 'clk', 'sup'], lower=vdd_dict[xxm_layer][0].track_id.base_index, upper=vss_dict[xxm_layer][1].track_id.base_index, sp_type=('sig', 'sig')) # --- Clocks # w_clk_vm = self.tr_manager.get_width(vm_layer, 'clk') vm_clk_pitch = clk_vm_locs[1] - clk_vm_locs[0] w_clk_xm = self.tr_manager.get_width(xm_layer, 'clk') # clk -> clkb_buf in row 1 clkb_vm = self.connect_to_tracks([invf_1.get_pin('pout'), invf_1.get_pin('nout')], TrackID(vm_layer, clk_vm_locs[2 * vm_clk_num], w_clk_vm, num=vm_clk_num, pitch=2 * vm_clk_pitch)) clkb_list0.append(clkb_vm) clkb_xm0 = self.connect_to_tracks(clkb_list0, TrackID(xm_layer, xm_locs0[-2], w_clk_xm)) clkb_dict0 = self.connect_up(clkb_list0, clkb_xm0, xxm_locs0[-2], 'clk', MinLenMode.LOWER) clkb_list1.append(clkb_vm) clkb_xm1 = self.connect_to_tracks(clkb_list1, TrackID(xm_layer, xm_locs1[-2], w_clk_xm)) clkb_dict1 = self.connect_up(clkb_list1, clkb_xm1, xxm_locs1[-2], 'clk', MinLenMode.LOWER) self.add_pin('clkb_buf', [clkb_dict0[xxm_layer], clkb_dict1[xxm_layer], clkb_xm0, clkb_xm1], mode=PinMode.LOWER) # clkb -> clk_buf in row 0 clk_vm = self.connect_to_tracks([invf_0.get_pin('pout'), invf_0.get_pin('nout')], TrackID(vm_layer, clk_vm_locs[0], w_clk_vm, num=vm_clk_num, pitch=2 * vm_clk_pitch)) clk_list0.append(clk_vm) clk_xm0 = self.connect_to_tracks(clk_list0, TrackID(xm_layer, xm_locs0[1], w_clk_xm)) clk_dict0 = self.connect_up(clk_list0, clk_xm0, xxm_locs0[1], 'clk', MinLenMode.UPPER) clk_list1.append(clk_vm) clk_xm1 = self.connect_to_tracks(clk_list1, TrackID(xm_layer, xm_locs1[1], w_clk_xm)) clk_dict1 = self.connect_up(clk_list1, clk_xm1, xxm_locs1[1], 'clk', MinLenMode.UPPER) self.add_pin('clk_buf', [clk_dict0[xxm_layer], clk_dict1[xxm_layer], clk_xm0, clk_xm1], mode=PinMode.LOWER) # hidden pins on clk ym_layer for top level routing for idx in range(ratio): self.add_pin(f'left_ym<{ratio - 1 - idx}>', clk_dict0[ym_layer][idx], hide=True) # clk in row 1 clk_in_vm = self.connect_to_tracks(invf_1.get_pin('nin'), TrackID(vm_layer, clk_vm_locs[-1], w_clk_vm), min_len_mode=MinLenMode.MIDDLE) clk_in_xm = self.connect_to_tracks(clk_in_vm, TrackID(xm_layer, xm_locs1[2], w_clk_xm), min_len_mode=MinLenMode.UPPER) self.add_pin('clk', clk_in_xm) # clkb in row 0 clkb_in_vm = self.connect_to_tracks(invf_0.get_pin('nin'), TrackID(vm_layer, clk_vm_locs[-1], w_clk_vm), min_len_mode=MinLenMode.MIDDLE) clkb_in_xm = self.connect_to_tracks(clkb_in_vm, TrackID(xm_layer, xm_locs0[-3], w_clk_xm), min_len_mode=MinLenMode.UPPER) self.add_pin('clkb', clkb_in_xm) # clk_divb_buf clk_divb_vm = self.connect_to_tracks([invs_0.get_pin('pout'), invs_0.get_pin('nout'), invs_1.get_pin('nin')], TrackID(vm_layer, clk_vm_locs[2 * vm_clk_num], w_clk_vm, num=vm_clk_num, pitch=2 * vm_clk_pitch)) clk_divb_list.append(clk_divb_vm) clk_divb_xm = self.connect_to_tracks(clk_divb_list, TrackID(xm_layer, xm_locs2[1], w_clk_xm)) self.add_pin('clk_divb_buf', clk_divb_xm, hide=not export_nets, mode=PinMode.LOWER) # clk_div_buf clk_div_vm = self.connect_to_tracks([invs_1.get_pin('pout'), invs_1.get_pin('nout')], TrackID(vm_layer, clk_vm_locs[0], w_clk_vm, num=vm_clk_num, pitch=2 * vm_clk_pitch)) clk_div_list.append(clk_div_vm) clk_div_xm = self.connect_to_tracks(clk_div_list, TrackID(xm_layer, xm_locs2[-2], w_clk_xm)) self.add_pin('clk_div_buf', clk_div_xm, mode=PinMode.LOWER) # clk_div clk_div_vm = self.connect_to_tracks(invs_0.get_pin('nin'), TrackID(vm_layer, clk_vm_locs[-1], w_clk_vm), min_len_mode=MinLenMode.MIDDLE) clk_div_xm = self.connect_to_tracks(clk_div_vm, TrackID(xm_layer, xm_locs2[-3], w_clk_xm), min_len_mode=MinLenMode.UPPER) self.add_pin('clk_div', [clk_div_vm, clk_div_xm]) # connect p<0> to complete shift register p0_xm = self.connect_to_tracks(p0_list, TrackID(xm_layer, xm_locs0[2], w_clk_xm)) self.connect_up(p0_list, p0_xm, xxm_locs0[2], 'sig', MinLenMode.UPPER) # p0_buf and p0b_buf en_xm0 = self.connect_to_tracks(en_list[-1], TrackID(xm_layer, xm_locs0[2], w_clk_xm), min_len_mode=MinLenMode.UPPER) en_xm1 = self.connect_to_tracks(en_list[:-1], TrackID(xm_layer, xm_locs1[2], w_clk_xm)) en_dict = self.connect_up(en_list[:-1], en_xm1, xxm_locs1[2], 'sig', MinLenMode.UPPER) en_ym_tid = self.tr_manager.get_next_track_obj(clkb_dict1[ym_layer][_p0_ym_idx], 'sig', 'clk', 1) self.connect_to_tracks([en_xm0, en_xm1, en_dict[xxm_layer]], en_ym_tid) self.add_pin('p0_buf', en_dict[xxm_layer], hide=not export_nets, mode=PinMode.LOWER) enb_xm0 = self.connect_to_tracks(enb_list[-1], TrackID(xm_layer, xm_locs0[2], w_clk_xm), min_len_mode=MinLenMode.LOWER) enb_xm1 = self.connect_to_tracks(enb_list[:-1], TrackID(xm_layer, xm_locs1[-3], w_clk_xm)) enb_dict = self.connect_up(enb_list[:-1], enb_xm1, xxm_locs1[-3], 'sig', MinLenMode.LOWER) enb_ym_tid = self.tr_manager.get_next_track_obj(clk_dict1[ym_layer][_p0_ym_idx], 'sig', 'clk', -1) self.connect_to_tracks([enb_xm0, enb_xm1, enb_dict[xxm_layer]], enb_ym_tid) # hidden pins on p0b_buf ym_layer for top level routing for idx in range(ratio - 1): self.add_pin(f'right_ym<{ratio - 2 - idx}>', enb_dict[ym_layer][idx], hide=True) self.add_pin(f'right_ym<{ratio - 1}>', clkb_dict0[ym_layer][1], hide=True) # reset self.connect_wires(rst_hm_list) rst_sync_xm = self.connect_to_tracks(rst_vm_list, TrackID(xm_layer, xm_locs0[-3], w_clk_xm)) self.add_pin('rst_sync', rst_sync_xm, hide=not export_nets, mode=PinMode.LOWER) if is_rst_async: w_sig_ym = self.tr_manager.get_width(ym_layer, 'sig') rst_vm_tid = self.tr_manager.get_next_track_obj(rst_ff1_out, 'sig', 'sig', 1) rst_vm = self.connect_to_tracks([rst_ff0.get_pin('prst'), rst_ff1.get_pin('prst')], rst_vm_tid) rst_xm = self.connect_to_tracks(rst_vm, TrackID(xm_layer, xm_locs1[2], w_clk_xm), min_len_mode=MinLenMode.MIDDLE) rst_ym_tidx = self.grid.coord_to_track(ym_layer, rst_xm.middle, RoundMode.NEAREST) rst_ym = self.connect_to_tracks(rst_xm, TrackID(ym_layer, rst_ym_tidx, w_sig_ym), min_len_mode=MinLenMode.MIDDLE) self.add_pin('rst', rst_ym) else: rstb_in = self.connect_to_tracks(rstb_in_vm, TrackID(xm_layer, xm_locs0[2], w_clk_xm), min_len_mode=MinLenMode.UPPER) self.add_pin('rstb_sync_in', rstb_in) # output dout = self.connect_to_tracks(dout_vm, TrackID(xm_layer, xm_locs1[-3], w_clk_xm), min_len_mode=MinLenMode.UPPER) self.add_pin('dout', dout) # inputs on xm_layer in_xm_tid = TrackID(xm_layer, xm_locs2[2], w_clk_xm) for idx, in_vm in enumerate(in_list): in_xm = self.connect_to_tracks(in_vm, in_xm_tid, min_len_mode=MinLenMode.MIDDLE) self.add_pin(f'din<{ratio - 1 - idx}>', in_xm) # get schematic parameters self.sch_params = dict( ff_rst=ff_rst_master.sch_params, ff_set=ff_set_master.sch_params, rst_sync=rst_sync_sch_params, inv_d=inv_d_sch, inv_en=inv_en_master.sch_params, ff=ff_master.sch_params, tinv=tinv_master.sch_params, inv_clk=inv_clk_master.sch_params, inv_clk_div=dict(inv_params=[inv_0_master.sch_params, inv_1_master.sch_params], dual_output=True), ratio=ratio, export_nets=export_nets, is_rst_async=is_rst_async,
)
[docs] def connect_supplies(self, vdd_hm: WireArray, vss_hm: WireArray, sup_coords: Sequence[int], xh: int, yh: int ) -> Tuple[Mapping[int, Union[WireArray, Sequence[WireArray]]], Mapping[int, Union[WireArray, Sequence[WireArray]]]]: hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 ym_layer = xm_layer + 1 xxm_layer = ym_layer + 1 vdd_dict = {hm_layer: vdd_hm} vss_dict = {hm_layer: vss_hm} self.add_pin('VDD', vdd_hm) self.add_pin('VSS', vss_hm) for _vm, _hm in [(vm_layer, xm_layer), (ym_layer, xxm_layer)]: # connect to vertical layer w_vm_sup = self.tr_manager.get_width(_vm, 'sup') vss_vm_list, vdd_vm_list = [], [] for _coord in sup_coords: _, _locs = self.tr_manager.place_wires(_vm, ['sup', 'sup'], center_coord=_coord) vss_tid = TrackID(_vm, _locs[0], w_vm_sup) vss_vm_list.append(self.connect_to_tracks(vss_hm, vss_tid, track_lower=0, track_upper=yh)) vdd_tid = TrackID(_vm, _locs[-1], w_vm_sup) vdd_vm_list.append(self.connect_to_tracks(vdd_hm, vdd_tid, track_lower=0, track_upper=yh)) vdd_dict[_vm] = vdd_vm_list vss_dict[_vm] = vss_vm_list # connect to horizontal layer w_hm_sup = self.tr_manager.get_width(_hm, 'sup') vss0_hm_idx = self.grid.coord_to_track(_hm, vss_hm[0].bound_box.ym, RoundMode.NEAREST) vss1_hm_idx = self.grid.coord_to_track(_hm, vss_hm[1].bound_box.ym, RoundMode.NEAREST) vdd0_hm_idx = self.grid.coord_to_track(_hm, vdd_hm[0].bound_box.ym, RoundMode.NEAREST) vdd1_hm_idx = self.grid.coord_to_track(_hm, vdd_hm[1].bound_box.ym, RoundMode.NEAREST) vss_hm = self.connect_to_tracks(vss_vm_list, TrackID(_hm, vss0_hm_idx, w_hm_sup, 2, vss1_hm_idx - vss0_hm_idx), track_lower=0, track_upper=xh) vdd_hm = self.connect_to_tracks(vdd_vm_list, TrackID(_hm, vdd0_hm_idx, w_hm_sup, 2, vdd1_hm_idx - vdd0_hm_idx), track_lower=0, track_upper=xh) vdd_dict[_hm] = vdd_hm vss_dict[_hm] = vss_hm self.add_pin('VDD', vdd_hm) self.add_pin('VSS', vss_hm) return vdd_dict, vss_dict
[docs] def connect_up(self, warr_vm_list: Sequence[WireArray], warr_xm: WireArray, xxm_tidx: HalfInt, sig_type: str, mlm_mode: MinLenMode) -> Mapping[int, Union[WireArray, Sequence[WireArray]]]: hm_layer = self.conn_layer + 1 vm_layer = hm_layer + 1 xm_layer = vm_layer + 1 ym_layer = xm_layer + 1 xxm_layer = ym_layer + 1 # connect to ym_layer w_ym = self.tr_manager.get_width(ym_layer, sig_type) warr_ym_list = [] for _warr_vm in warr_vm_list: _tidx = self.grid.coord_to_track(ym_layer, _warr_vm.bound_box.xm, RoundMode.NEAREST) warr_ym_list.append(self.connect_to_tracks(warr_xm, TrackID(ym_layer, _tidx, w_ym), min_len_mode=mlm_mode)) # connect to xxm_layer w_xxm = self.tr_manager.get_width(xxm_layer, sig_type) warr_xxm = self.connect_to_tracks(warr_ym_list, TrackID(xxm_layer, xxm_tidx, w_xxm)) return {ym_layer: warr_ym_list, xxm_layer: warr_xxm}