def draw_io_supply_column(template: MOSBase, col: int, sup_info: SupplyColumnInfo, vdd_io_table: Dict[int, List[WireArray]], vdd_core_table: Dict[int, List[WireArray]], vss_table: Dict[int, List[WireArray]], ridx_p: int, ridx_n: int, flip_lr: bool) -> int: ncol = sup_info.ncol sup_col = col + int(flip_lr) * ncol # draw vdd core columns template.add_supply_column(sup_info, sup_col, vdd_core_table, vss_table, ridx_p=ridx_p, ridx_n=ridx_n, flip_lr=flip_lr, extend_vdd=False, extend_vss=False, min_len_mode=MinLenMode.MIDDLE) # draw vdd_io columns for tile in range(1, 3): template.add_supply_column(sup_info, sup_col, vdd_io_table, vss_table, ridx_p=ridx_p, ridx_n=ridx_n, tile_idx=tile, flip_lr=flip_lr, extend_vdd=False) return col + ncol + (template.sub_sep_col // 2)
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) zero = HalfInt(0) self._q_tr_info = (0, zero, zero) self._sr_hm_tr_info = self._q_tr_info self._sr_vm_tr_info = self._q_tr_info
def _connect_lv_por_vm( template: MOSBase, rstl: WireArray, rstr: WireArray, rstc: WireArray, rst_idx_list: List[HalfInt], rstc_idx: int) -> Tuple[WireArray, WireArray, WireArray]: vm_layer = template.conn_layer + 2 vm_w = template.tr_manager.get_width(vm_layer, 'sig') rstl = template.connect_to_tracks( rstl, TrackID(vm_layer, rst_idx_list[0], width=vm_w)) rstc = template.connect_to_tracks( rstc, TrackID(vm_layer, rst_idx_list[rstc_idx], width=vm_w)) rstr = template.connect_to_tracks( rstr, TrackID(vm_layer, rst_idx_list[3], width=vm_w)) return rstl, rstr, rstc
def _make_masters(cls, template: MOSBase, pinfo: MOSBasePlaceInfo, params: Mapping[str, Any] ) -> Tuple[LevelShifterCoreOutBuffer, LevelShifterCoreOutBuffer, LevelShifterCoreOutBuffer, InvCore, SingleToDiffEnable, DiffBufferEnable, InvChainCore, InvChainCore]: se_params: Param = params['se_params'] match_params: Param = params['match_params'] inv_params: Param = params['inv_params'] data_lv_params: Param = params['data_lv_params'] ctrl_lv_params: Param = params['ctrl_lv_params'] por_lv_params: Param = params['por_lv_params'] buf_ctrl_lv_params: Param = params['buf_ctrl_lv_params'] buf_por_lv_params: Param = params['buf_por_lv_params'] ridx_p: int = params['ridx_p'] ridx_n: int = params['ridx_n'] # setup master parameters append = dict(pinfo=pinfo, ridx_n=ridx_n, ridx_p=ridx_p) data_params = data_lv_params.copy(append=dict(dual_output=True, vertical_rst=['rst_outp', 'rst_outn', 'rst_casc'], **append)) ctrl_params = ctrl_lv_params.copy(append=dict(dual_output=True, **append)) inv_params = inv_params.copy(append=append) data_buf_params = dict(vertical_out=False, **append, **se_params) clk_buf_params = dict(vertical_out=False, **append, **match_params) # create masters lv_data_master = template.new_template(LevelShifterCoreOutBuffer, params=data_params) lv_ctrl_master = template.new_template(LevelShifterCoreOutBuffer, params=ctrl_params) inv_master = template.new_template(InvCore, params=inv_params) data_master = template.new_template(SingleToDiffEnable, params=data_buf_params) clk_master = template.new_template(DiffBufferEnable, params=clk_buf_params) buf_ctrl_lv_master = cls._get_buf_lv_master(template, buf_ctrl_lv_params, append) buf_por_lv_master = cls._get_buf_lv_master(template, buf_por_lv_params, append) # NOTE: Set POR level shifter to 4 columns less than normal level shifter. # Since both level shifter are dual output and symmetric, this means that the POR level # shifter is 2 columns shorter than norma level shifter on left and right side, which # will conveniently shift the vm_layer output wires of POR to not collide with # the control level shifters. # Also, since POR level shifter is usually small (because it doesn't have to be big), # this make sure we have enough routing tracks for differential inputs on vm_layer por_ncol = lv_ctrl_master.num_cols - 4 por_params = por_lv_params.copy(append=dict(dual_output=True, has_rst=False, num_col_tot=por_ncol, **append)) lv_por_master = template.new_template(LevelShifterCoreOutBuffer, params=por_params) return (lv_data_master, lv_ctrl_master, lv_por_master, inv_master, data_master, clk_master, buf_ctrl_lv_master, buf_por_lv_master)
def _get_buf_lv_master(cls, template: MOSBase, buf_params: Param, append: Mapping[str, Any] ) -> InvChainCore: buf_params = buf_params.copy(append=dict( dual_output=True, vertical_output=True, **append ), remove=['sig_locs']) buf_master = template.new_template(InvChainCore, params=buf_params) vm_layer = template.conn_layer + 2 out_tidx = buf_master.get_port('out').get_pins()[0].track_id.base_index prev_tidx = template.tr_manager.get_next_track(vm_layer, out_tidx, 'sig', 'sig', up=False) buf_master = buf_master.new_template_with(sig_locs=dict(outb=prev_tidx)) return buf_master
def _record_lv_pins(template: MOSBase, inst: PyLayInstance, vss_tid: TrackID, pin_dict: Dict[str, List[WireArray]], pin_name: str, por_to_out: bool, rst_idx_list: List[HalfInt]) -> None: if inst.has_port('rst_out'): rst_out = inst.get_pin('rst_out') rst_casc = inst.get_pin('rst_casc') rst_outb = inst.get_pin('rst_outb') if rst_out.middle < rst_outb.middle: rstc_idx = 1 if por_to_out else 2 tmp = _connect_lv_por_vm(template, rst_out, rst_outb, rst_casc, rst_idx_list, rstc_idx) rst_out, rst_outb, rst_casc = tmp else: rstc_idx = 2 if por_to_out else 1 tmp = _connect_lv_por_vm(template, rst_outb, rst_out, rst_casc, rst_idx_list, rstc_idx) rst_outb, rst_out, rst_casc = tmp if por_to_out: template.connect_to_tracks(rst_outb, vss_tid) pin_dict['por'].append(rst_out) pin_dict['porb'].append(rst_casc) else: template.connect_to_tracks(rst_out, vss_tid) pin_dict['por'].append(rst_outb) pin_dict['porb'].append(rst_casc) master = cast(LevelShifterCoreOutBuffer, inst.master) key = pin_name + '_out' if master.dual_output: pin_dict[key] = [inst.get_pin('out')] pin_dict[key + 'b'] = [inst.get_pin('outb')] elif master.outr_inverted: pin_dict[key] = [inst.get_pin('outb')] else: pin_dict[key] = [inst.get_pin('out')]
def get_adj_tidx_list(layout: MOSBase, ridx: int, sig_locs: Mapping[str, Union[float, HalfInt]], wtype: MOSWireType, prefix: str, up: bool) -> Tuple[HalfInt, HalfInt]: """Helper method that gives two adjacent signal wires, with sig_locs override.""" hm_layer = layout.conn_layer + 1 out0 = sig_locs.get(prefix + '0', None) if out0 is not None: # user specify output track index for both parities out1 = sig_locs[prefix + '1'] else: out0 = sig_locs.get(prefix, None) if out0 is not None: # user only specify one index. out1 = layout.tr_manager.get_next_track(hm_layer, out0, 'sig', 'sig', up=up) else: # use default track indices widx = 0 if up else -1 out0 = layout.get_track_index(ridx, wtype, wire_name='sig', wire_idx=widx) out1 = layout.tr_manager.get_next_track(hm_layer, out0, 'sig', 'sig', up=up) if out0 == out1: raise ValueError(f'{prefix}0 and {prefix}1 must be on different tracks.') return out0, out1
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._substrate_row_intvl: List[Tuple[int, int]] = []
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._core_ncol: int = 0 self._lvshift_right_ncol: int = 0 self._tap_info: ImmutableList[Tuple[int, bool]] = ImmutableList()
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._tap_columns: ImmutableList[Tuple[int, bool]] = ImmutableList()
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._ridx_p = -1 self._ridx_n = 0
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) zero = HalfInt(0) self._out_tinfo = (1, zero, zero)
def draw_io_shifters(template: MOSBase, col: int, buf_bot_master: MOSBase, buf_top_master: MOSBase, bot_lv_master: LevelShifterCoreOutBuffer, top_lv_master: LevelShifterCoreOutBuffer, bot_vss: TrackID, top_vss: TrackID, bot_name: str, top_name: str, bot_rst_out: bool, top_rst_out: bool, is_tx_din: bool, pin_dict: Dict[str, List[WireArray]], flip_lr: bool = False) -> int: # NOTE: the level shifters are arranged so that the rst/rstb signals of the top/bottom # level shifters can be shorted together. top_ncol = top_lv_master.num_cols bot_ncol = bot_lv_master.num_cols top_buf_ncol = buf_top_master.num_cols bot_buf_ncol = buf_bot_master.num_cols top_center = cast(LevelShifterCoreOutBuffer, top_lv_master).center_col bot_center = cast(LevelShifterCoreOutBuffer, bot_lv_master).center_col delta = max(top_center, bot_center) col_mid = col + delta col_end = col_mid + max(top_ncol - top_center, bot_ncol - bot_center) if flip_lr: col_mid = col_end - delta sign = -1 midr_name = 'midl' midl_name = 'midr' bufl_ncol = bot_buf_ncol bufr_ncol = top_buf_ncol else: sign = 1 midr_name = 'midr' midl_name = 'midl' bufl_ncol = top_buf_ncol bufr_ncol = bot_buf_ncol bot_lv = template.add_tile(bot_lv_master, 1, col_mid - sign * bot_center, flip_lr=flip_lr) top_lv = template.add_tile(top_lv_master, 2, col_mid - sign * top_center, flip_lr=flip_lr) # get buffer location min_sep2 = template.min_sep_col // 2 bufl_col = col_mid - min_sep2 - (bufl_ncol + (bufl_ncol & 1)) bufr_col = col_mid + min_sep2 + (bufr_ncol + (bufr_ncol & 1)) if bot_lv_master.mid_vertical or top_lv_master.mid_vertical: arr_info = template.arr_info tr_manager = template.tr_manager vm_layer = template.conn_layer + 2 if bot_lv_master.mid_vertical: midl_tidx = bot_lv.get_pin(midl_name).track_id.base_index midr_tidx = bot_lv.get_pin(midr_name).track_id.base_index if top_lv_master.mid_vertical: midl_tidx = min( top_lv.get_pin(midl_name).track_id.base_index, midl_tidx) midr_tidx = max( top_lv.get_pin(midr_name).track_id.base_index, midr_tidx) else: midl_tidx = top_lv.get_pin(midl_name).track_id.base_index midr_tidx = top_lv.get_pin(midr_name).track_id.base_index bufl_tidx = tr_manager.get_next_track(vm_layer, midl_tidx, 'sig', 'sig', up=False) bufr_tidx = tr_manager.get_next_track(vm_layer, midr_tidx, 'sig', 'sig', up=True) coll_idx = arr_info.track_to_col(vm_layer, bufl_tidx, mode=RoundMode.LESS_EQ) colr_idx = arr_info.track_to_col(vm_layer, bufr_tidx, mode=RoundMode.GREATER_EQ) bufl_col = min(bufl_col, coll_idx - (bufl_ncol + (bufl_ncol & 1))) bufr_col = max(bufr_col, colr_idx + (bufr_ncol + (bufr_ncol & 1))) if flip_lr: top_buf_col = bufr_col bot_buf_col = bufl_col else: top_buf_col = bufl_col bot_buf_col = bufr_col top_buf = template.add_tile(buf_top_master, 0, top_buf_col, flip_lr=flip_lr) bot_buf = template.add_tile(buf_bot_master, 0, bot_buf_col, flip_lr=not flip_lr) vdd_list = pin_dict['VDD'] vss_list = pin_dict['VSS'] vdd_io_list = pin_dict['VDDIO'] vdd_list.extend(top_buf.port_pins_iter('VDD')) vdd_list.extend(bot_buf.port_pins_iter('VDD')) vdd_io_list.extend(top_lv.port_pins_iter('VDD')) vdd_io_list.extend(bot_lv.port_pins_iter('VDD')) vss_list.extend(top_buf.port_pins_iter('VSS')) vss_list.extend(bot_buf.port_pins_iter('VSS')) vss_list.extend(top_lv.port_pins_iter('VSS')) vss_list.extend(bot_lv.port_pins_iter('VSS')) # NOTE: here we assume that the last stage of the inverter chain is large # enough, so inverter output wires shouldn't run into level shifter middle wires. out_top = top_buf.get_pin('out') outb_top = top_buf.get_pin('outb') out_bot = bot_buf.get_pin('out') outb_bot = bot_buf.get_pin('outb') template.connect_differential_wires(out_top, outb_top, top_lv.get_pin('in'), top_lv.get_pin('inb')) template.connect_differential_wires(out_bot, outb_bot, bot_lv.get_pin('in'), bot_lv.get_pin('inb')) pin_dict[top_name] = [top_buf.get_pin('in')] pin_dict[bot_name] = [bot_buf.get_pin('in')] pin_dict[top_name + '_buf'] = [out_top, outb_top] pin_dict[bot_name + '_buf'] = [out_bot, outb_bot] # connect resets to vm layer # NOTE: here we assume that the inverter chain last stage is small enough, and the # nmos of the level shifters are are enough, so the track immediately adjacent to the # outputs of the invert chain can be used to connect rstb signals together without # running into rst signal's hm layer wires. if flip_lr: rstb_l_tidx = _get_rstb_vm_tidx(template, out_bot, outb_bot, True) rstb_r_tidx = _get_rstb_vm_tidx(template, out_top, outb_top, False) else: rstb_l_tidx = _get_rstb_vm_tidx(template, out_top, outb_top, True) rstb_r_tidx = _get_rstb_vm_tidx(template, out_bot, outb_bot, False) xl_b, xh_b = _get_por_vm_coords(bot_lv) xl_t, xh_t = _get_por_vm_coords(top_lv) bot_rst_l_tidx = _get_rst_vm_tidx(template, xl_b, rstb_l_tidx, True) bot_rst_r_tidx = _get_rst_vm_tidx(template, xh_b, rstb_r_tidx, False) top_rst_l_tidx = _get_rst_vm_tidx(template, xl_t, rstb_l_tidx, True) top_rst_r_tidx = _get_rst_vm_tidx(template, xh_t, rstb_r_tidx, False) if is_tx_din: # NOTE: here, we use the fact that we only have inverter buffer on the right, and the # rst signals on the right are connected to VSS (meaning they don't need to cross into # the other tile). # This means that the rst signals on the left can be shorted with the left-most # vertical track and we won't run into potential vertical wires from # inverter buffers (because they're guaranteed to not be there), and the rst signals on # the right can use their own vertical tracks to short to VSS. rst_idx_list = [ min(bot_rst_l_tidx, top_rst_l_tidx), rstb_l_tidx, rstb_r_tidx, bot_rst_r_tidx ] _record_lv_pins(template, bot_lv, bot_vss, pin_dict, bot_name, bot_rst_out, rst_idx_list) rst_idx_list[3] = top_rst_r_tidx _record_lv_pins(template, top_lv, top_vss, pin_dict, top_name, top_rst_out, rst_idx_list) else: # NOTE: we know the core of top and bottom level shifters are identical, so we use the # same vertical tracks rst_idx_list = [ bot_rst_l_tidx, rstb_l_tidx, rstb_r_tidx, bot_rst_r_tidx ] _record_lv_pins(template, bot_lv, bot_vss, pin_dict, bot_name, bot_rst_out, rst_idx_list) _record_lv_pins(template, top_lv, top_vss, pin_dict, top_name, top_rst_out, rst_idx_list) return col_end + (template.sub_sep_col // 2)
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._en_ncol = 0 self._core: Optional[MOSBase] = None
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._sch_cls: Optional[Type[Module]] = None self._core: Optional[MOSBase] = None
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._center_col: int = -1
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._center_col: int = -1 self._outr_inverted: bool = False self._mid_vertical: bool = False
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._col_margin = 0
def __init__(self, temp_db: TemplateDB, params: Param, **kwargs: Any) -> None: MOSBase.__init__(self, temp_db, params, **kwargs) self._buf_col_list: Sequence[int] = []