Ejemplo n.º 1
0
    def get_fill_size(self,
                      top_layer: int,
                      fill_config: FillConfigType,
                      *,
                      include_private: bool = False,
                      half_blk_x: bool = True,
                      half_blk_y: bool = True) -> Tuple[int, int]:
        """Returns unit block size given the top routing layer and power fill configuration.

        Parameters
        ----------
        top_layer : int
            the top layer ID.
        fill_config : Dict[int, Tuple[int, int, int, int]]
            the fill configuration dictionary.
        include_private : bool
            True to include private layers in block size calculation.
        half_blk_x : bool
            True to allow half-block widths.
        half_blk_y : bool
            True to allow half-block heights.

        Returns
        -------
        block_width : int
            the block width in resolution units.
        block_height : int
            the block height in resolution units.
        """
        blk_w, blk_h = self.get_block_size(top_layer,
                                           include_private=include_private,
                                           half_blk_x=half_blk_x,
                                           half_blk_y=half_blk_y)

        dim_list = [[blk_w], [blk_h]]
        for lay, (tr_w, tr_sp, _, _) in fill_config.items():
            if lay <= top_layer:
                cur_pitch = self.get_track_pitch(lay)
                cur_dim = (tr_w + tr_sp) * cur_pitch * 2
                dim_list[1 - self.get_direction(lay).value].append(cur_dim)

        blk_w = lcm(dim_list[0])
        blk_h = lcm(dim_list[1])
        return blk_w, blk_h
Ejemplo n.º 2
0
    def _get_row_specs(self, row_types, row_orientations, row_thresholds,
                       row_kwargs, num_g_tracks, num_gb_tracks, num_ds_tracks):
        lch = self._laygo_info.lch
        lch_unit = int(
            round(lch / self.grid.layout_unit / self.grid.resolution))
        w_sub = self._laygo_info['w_sub']
        w_n = self._laygo_info['w_n']
        w_p = self._laygo_info['w_p']
        min_sub_tracks = self._laygo_info['min_sub_tracks']
        min_n_tracks = self._laygo_info['min_n_tracks']
        min_p_tracks = self._laygo_info['min_p_tracks']
        mos_pitch = self._laygo_info.mos_pitch

        row_specs = []
        for row_type, row_orient, row_thres, kwargs, ng, ngb, nds in \
                zip(row_types, row_orientations, row_thresholds, row_kwargs,
                    num_g_tracks, num_gb_tracks, num_ds_tracks):

            # get information dictionary
            if row_type == 'nch':
                mos_info = self._tech_cls.get_laygo_mos_info(
                    lch_unit, w_n, row_type, row_thres, 'general', **kwargs)
                min_tracks = min_n_tracks
            elif row_type == 'pch':
                mos_info = self._tech_cls.get_laygo_mos_info(
                    lch_unit, w_p, row_type, row_thres, 'general', **kwargs)
                min_tracks = min_p_tracks
            elif row_type == 'ptap':
                mos_info = self._tech_cls.get_laygo_sub_info(
                    lch_unit, w_sub, row_type, row_thres, **kwargs)
                min_tracks = min_sub_tracks
            elif row_type == 'ntap':
                mos_info = self._tech_cls.get_laygo_sub_info(
                    lch_unit, w_sub, row_type, row_thres, **kwargs)
                min_tracks = min_sub_tracks
            else:
                raise ValueError('Unknown row type: %s' % row_type)

            row_pitch = min_row_height = mos_pitch
            for layer, num_tr in min_tracks:
                tr_pitch = self.grid.get_track_pitch(layer, unit_mode=True)
                min_row_height = max(min_row_height, num_tr * tr_pitch)
                row_pitch = lcm([row_pitch, tr_pitch])

            row_specs.append((row_type, row_orient, mos_info, min_row_height,
                              row_pitch, (ng, ngb, nds)))

        return row_specs
Ejemplo n.º 3
0
    def get_mos_base_end_info(self, pinfo: MOSBasePlaceInfo,
                              blk_pitch: int) -> MOSBaseEndInfo:
        blk_pitch = lcm([self.blk_h_pitch, blk_pitch])

        bot_rpinfo = pinfo.get_row_place_info(0)
        top_rpinfo = pinfo.get_row_place_info(-1)

        h_ext_bot = bot_rpinfo.yb_blk - bot_rpinfo.yb
        h_ext_top = top_rpinfo.yt - top_rpinfo.yt_blk

        h_end_min = self.end_h_min
        h_mos_end_bot, h_blk_bot = _get_end_block_info(h_ext_bot, h_end_min,
                                                       blk_pitch)
        h_mos_end_top, h_blk_top = _get_end_block_info(h_ext_top, h_end_min,
                                                       blk_pitch)
        return MOSBaseEndInfo((h_mos_end_bot, h_mos_end_top),
                              (h_blk_bot, h_blk_top))
Ejemplo n.º 4
0
    def get_block_pitch(cls, grid, top_layer, **kwargs):
        integ_htr = kwargs.get('integ_htr', False)

        if top_layer is not None:
            blk_pitch = grid.get_block_size(top_layer, unit_mode=True)[1]
            if integ_htr:
                hm_layer = top_layer
                while grid.get_direction(hm_layer) != 'x':
                    hm_layer -= 1
                blk_pitch = lcm([
                    blk_pitch,
                    grid.get_track_pitch(hm_layer, unit_mode=True)
                ])
        else:
            blk_pitch = 1

        return blk_pitch
Ejemplo n.º 5
0
    def get_block_size(cls,
                       grid,
                       route_layer,
                       bias_config,
                       nwire,
                       width=1,
                       space_sig=0):
        # type: (RoutingGrid, int, Dict[int, Tuple[int, ...]], int, int, int) -> Tuple[int, int]

        bot_layer = route_layer - 1
        top_layer = route_layer + 1
        route_dir = grid.get_direction(route_layer)
        is_horiz = route_dir == 'x'

        # calculate dimension
        bot_pitch2 = grid.get_track_pitch(bot_layer, unit_mode=True) // 2
        route_pitch2 = grid.get_track_pitch(route_layer, unit_mode=True) // 2
        top_pitch2 = grid.get_track_pitch(top_layer, unit_mode=True) // 2
        bot_np2, bot_w, bot_spe2, _ = bias_config[bot_layer]
        route_np2, route_w, route_spe2, _ = bias_config[route_layer]
        top_np2, top_w, top_spe2, _ = bias_config[top_layer]
        bot_unit = bot_np2 * bot_pitch2
        route_unit = route_np2 * route_pitch2
        top_unit = top_np2 * top_pitch2
        dim_par = lcm([bot_unit, top_unit])

        tr_manager = TrackManager(grid, {'sig': {
            route_layer: width
        }}, {('sig', ''): {
                 route_layer: space_sig
             }},
                                  half_space=True)

        tmp = [route_w]
        nwire = -(-nwire // 2) * 2
        route_list = list(chain(tmp, repeat('sig', nwire), tmp))
        _, locs = tr_manager.place_wires(route_layer, route_list)
        num_htr = int(2 * (locs[nwire + 1] - locs[0])) + 2 * route_spe2
        dim_perp = -(-(num_htr * route_pitch2) // route_unit) * route_unit
        if is_horiz:
            return dim_par, dim_perp
        else:
            return dim_perp, dim_par
Ejemplo n.º 6
0
    def get_sub_yloc_info(self, lch_unit, w, **kwargs):
        # type: (int, int, **kwargs) -> Dict[str, Any]
        """Get substrate layout information.

        Layout is quite simple.  We use M0PO to short adjacent S/D together, so dummies can be
        connected using only M2 or below.

        Strategy:

        1. Find bottom M0_PO and bottom OD coordinates from spacing rules.
        #. Find template top coordinate by enforcing symmetry around OD center.
        #. Round up template height to blk_pitch, then recenter OD.
        #. make sure MD/M1 are centered on OD.
        """
        blk_pitch = kwargs['blk_pitch']

        mos_constants = self.get_mos_tech_constants(lch_unit)
        fin_p = mos_constants['mos_pitch']
        od_spy = mos_constants['od_spy']
        mp_cpo_sp_sub = mos_constants['mp_cpo_sp_sub']
        mp_h_sub = mos_constants['mp_h_sub']
        mp_spy_sub = mos_constants['mp_spy_sub']
        mp_md_sp_sub = mos_constants['mp_md_sp_sub']
        cpo_h = mos_constants['cpo_h']
        md_h_min = mos_constants['md_h_min']
        md_od_exty = mos_constants['md_od_exty']
        md_spy = mos_constants['md_spy']

        # compute gate/drain connection parameters
        g_conn_info = self.get_conn_drc_info(lch_unit, 'g')
        g_m1_sple = g_conn_info[1]['sp_le']

        d_conn_info = self.get_conn_drc_info(lch_unit, 'd')
        d_m3_sple = d_conn_info[3]['sp_le']

        od_h = self.get_od_h(lch_unit, w)
        md_h = max(od_h + 2 * md_od_exty, md_h_min)

        # figure out Y coordinate of bottom CPO
        cpo_bot_yt = cpo_h // 2
        # find bottom M0_PO coordinate
        mp_yb = max(mp_spy_sub // 2, cpo_bot_yt + mp_cpo_sp_sub)
        mp_yt = mp_yb + mp_h_sub
        # find first-pass OD coordinate
        od_yb = mp_yt + mp_md_sp_sub + md_h // 2 - od_h // 2
        od_yb = self.snap_od_edge(lch_unit, od_yb, False, True)
        od_yt = od_yb + od_h
        cpo_top_yc = od_yt + od_yb
        # fix substrate height quantization, then recenter OD location
        blk_pitch = lcm([blk_pitch, fin_p])
        blk_h = -(-cpo_top_yc // blk_pitch) * blk_pitch
        cpo_top_yc = blk_h
        od_yb = blk_h // 2 - od_h // 2
        od_yb = self.snap_od_edge(lch_unit, od_yb, False, True)
        od_yt = od_yb + od_h
        od_yc = (od_yb + od_yt) // 2
        # find MD Y coordinates
        md_yb = od_yc - md_h // 2
        md_yt = md_yb + md_h
        blk_yb, blk_yt = 0, cpo_top_yc

        conn_info = self.get_conn_yloc_info(lch_unit, (od_yb, od_yt),
                                            (md_yb, md_yt), True)
        m1_yb, m1_yt = conn_info['d_y_list'][0]
        m3_yb, m3_yt = conn_info['d_y_list'][2]
        return dict(
            blk=(blk_yb, blk_yt),
            po=(blk_yb + cpo_h // 2, blk_yt - cpo_h // 2),
            od=(od_yb, od_yt),
            md=(md_yb, md_yt),
            top_margins=dict(od=(blk_yt - od_yt, od_spy),
                             md=(blk_yt - md_yt, md_spy),
                             m1=(blk_yt - m1_yt, g_m1_sple),
                             m3=(blk_yt - m3_yt, d_m3_sple)),
            bot_margins=dict(
                od=(od_yb - blk_yb, od_spy),
                md=(md_yb - blk_yb, md_spy),
                m1=(m1_yb - blk_yb, g_m1_sple),
                m3=(m3_yb - blk_yb, d_m3_sple),
            ),
            fill_info={},
            g_conn_y=(m3_yb, m3_yt),
            d_conn_y=(m3_yb, m3_yt),
        )
Ejemplo n.º 7
0
    def get_laygo_sub_yloc_info(self, lch_unit, w, **kwargs):
        # type: (int, float, **kwargs) -> Dict[str, Any]
        dnw_mode = kwargs.get('dnw_mode', '')
        blk_pitch = kwargs.get('blk_pitch', 1)

        mos_pitch = self.get_mos_pitch(unit_mode=True)
        md_min_len = self.get_md_min_len(lch_unit)
        mos_constants = self.get_mos_tech_constants(lch_unit)
        od_spy = mos_constants['od_spy']
        imp_od_ency = mos_constants['imp_od_ency']
        po_spy = mos_constants['po_spy']

        d_via_info = mos_constants['laygo_d_via']

        nw_dnw_ovl = mos_constants['nw_dnw_ovl']
        nw_dnw_ext = mos_constants['nw_dnw_ext']
        sub_m1_enc_le = mos_constants['sub_m1_enc_le']

        layout_unit = self.config['layout_unit']
        res = self.res
        od_h = int(round(w / layout_unit / (2 * res))) * 2

        # step 0: figure out implant/OD enclosure
        if dnw_mode:
            imp_od_ency = max(imp_od_ency, (nw_dnw_ovl + nw_dnw_ext - od_h) // 2)

        # step 1: find OD coordinate
        od_yb = imp_od_ency
        od_yt = od_yb + od_h
        blk_yt = od_yt + imp_od_ency
        # fix substrate height quantization, then recenter OD location
        blk_pitch = lcm([blk_pitch, mos_pitch])
        blk_yt = -(-blk_yt // blk_pitch) * blk_pitch
        od_yb = (blk_yt - od_h) // 2
        od_yt = od_yb + od_h
        od_yc = (od_yb + od_yt) // 2

        # step 2: find metal height

        drc_info = self.get_conn_drc_info(lch_unit, 'd', is_laygo=True)

        mx_spy = max((info['sp_le'] for info in drc_info.values()))
        d_v0_h = d_via_info['dim'][0][1]
        d_v0_sp = d_via_info['sp'][0]
        d_v0_od_ency = d_via_info['bot_enc_le'][0]
        d_v0_n = (od_h - 2 * d_v0_od_ency + d_v0_sp) // (d_v0_h + d_v0_sp)
        d_v0_arrh = d_v0_n * (d_v0_h + d_v0_sp) - d_v0_sp
        
        #mx_h = max(md_min_len, d_v0_arrh + 2 * sub_m1_enc_le)
        mx_h = max(md_min_len, d_v0_arrh + 2 * sub_m1_enc_le, od_h)

        d_mx_yb = od_yc - mx_h // 2
        d_mx_yt = d_mx_yb + mx_h

        mx_y = (d_mx_yb, d_mx_yt)
        return dict(
            blk=(0, blk_yt),
            po=(od_yb, od_yb),
            od=(od_yb, od_yt),
            top_margins=dict(
                od=(blk_yt - od_yt, od_spy),
                po=(blk_yt, po_spy),
                #mx=(blk_yt - d_mx_yt, mx_spy),
                m1=(blk_yt - d_mx_yt, mx_spy),
            ),
            bot_margins=dict(
                od=(od_yb, od_spy),
                po=(blk_yt, po_spy),
                #mx=(d_mx_yb, mx_spy),
                m1=(d_mx_yb, mx_spy),
            ),
            fill_info={},
            g_conn_y=mx_y,
            d_conn_y=mx_y,
        )
Ejemplo n.º 8
0
    def get_core_track_info(
            cls,  # type: ResTech
            grid,  # type: RoutingGrid
            min_tracks,  # type: Tuple[int, ...]
            em_specs  # type: Dict[str, Any]
    ):
        # type: (...) -> Tuple[List[int], List[int], Tuple[int, int], Tuple[int, int]]
        """Calculate resistor core size/track information based on given specs.

        This method calculate the track width/spacing on each routing layer from EM specifications,
        then compute minimum width/height and block pitch of resistor blocks from given
        constraints.

        Parameters
        ----------
        grid : RoutingGrid
            the RoutingGrid object.
        min_tracks : List[int]
            minimum number of tracks on each layer.
        em_specs : Dict[str, Any]
            EM specification dictionary.

        Returns
        -------
        track_widths : List[int]
            the track width on each layer that satisfies EM specs.
        track_spaces : List[int]
            the track space on each layer.
        min_size : Tuple[int, int]
            a tuple of minimum width and height of the core in resolution units.
        blk_pitch : Tuple[int, int]
            a tuple of width and height pitch of the core in resolution units.
        """
        track_widths = []
        track_spaces = []
        prev_width = -1
        min_w = min_h = 0
        cur_layer = cls.get_bot_layer()
        for min_num_tr in min_tracks:
            tr_w, tr_sp = grid.get_track_info(cur_layer, unit_mode=True)
            cur_width = grid.get_min_track_width(cur_layer,
                                                 bot_w=prev_width,
                                                 unit_mode=True,
                                                 **em_specs)
            cur_space = grid.get_num_space_tracks(cur_layer, cur_width)
            track_widths.append(cur_width)
            track_spaces.append(cur_space)
            cur_width_lay = cur_width * tr_w + (cur_width - 1) * tr_sp
            cur_space_lay = (cur_space + 1) * tr_sp + cur_space * tr_w
            min_dim = min_num_tr * (cur_width_lay + cur_space_lay)
            if grid.get_direction(cur_layer) == 'x':
                min_h = max(min_h, min_dim)
            else:
                min_w = max(min_w, min_dim)

            cur_layer += 1
            prev_width = cur_width_lay

        cur_layer -= 1
        wblk, hblk = grid.get_block_size(cur_layer, unit_mode=True)
        rwblk, rhblk = cls.get_block_pitch()
        wblk = lcm([wblk, rwblk])
        hblk = lcm([hblk, rhblk])
        min_w = -(-min_w // wblk) * wblk
        min_h = -(-min_h // hblk) * hblk

        return track_widths, track_spaces, (min_w, min_h), (wblk, hblk)
Ejemplo n.º 9
0
    def get_core_track_info(
            self,  # type: ResTech
            grid,  # type: RoutingGrid
            min_tracks,  # type: Tuple[int, ...]
            em_specs,  # type: Dict[str, Any]
            connect_up=False,  # type: bool
    ):
        # type: (...) -> Tuple[List[int], List[Union[int, float]], Tuple[int, int], Tuple[int, int]]
        """Calculate resistor core size/track information based on given specs.

        This method calculate the track width/spacing on each routing layer from EM specifications,
        then compute minimum width/height and block pitch of resistor blocks from given
        constraints.

        Parameters
        ----------
        grid : RoutingGrid
            the RoutingGrid object.
        min_tracks : Tuple[int, ...]
            minimum number of tracks on each layer.
        em_specs : Dict[str, Any]
            EM specification dictionary.
        connect_up : bool
            True if the last used layer needs to be able to connect to the layer above.
            This options will make sure that the width of the last track is wide enough to support
            the inter-layer via.

        Returns
        -------
        track_widths : List[int]
            the track width on each layer that satisfies EM specs.
        track_spaces : List[Union[int, float]]
            the track space on each layer.
        min_size : Tuple[int, int]
            a tuple of minimum width and height of the core in resolution units.
        blk_pitch : Tuple[int, int]
            a tuple of width and height pitch of the core in resolution units.
        """
        track_widths = []
        track_spaces = []
        prev_width = -1
        min_w = min_h = 0
        cur_layer = self.get_bot_layer()
        for idx, min_num_tr in enumerate(min_tracks):
            # make sure that current layer can connect to next layer
            if idx < len(min_tracks) - 1 or connect_up:
                top_tr_w = grid.get_min_track_width(cur_layer + 1,
                                                    unit_mode=True,
                                                    **em_specs)
                top_w = grid.get_track_width(cur_layer + 1,
                                             top_tr_w,
                                             unit_mode=True)
            else:
                top_w = -1

            tr_p = grid.get_track_pitch(cur_layer, unit_mode=True)
            cur_width = grid.get_min_track_width(cur_layer,
                                                 bot_w=prev_width,
                                                 top_w=top_w,
                                                 unit_mode=True,
                                                 **em_specs)
            cur_space = grid.get_num_space_tracks(cur_layer,
                                                  cur_width,
                                                  half_space=True)
            track_widths.append(cur_width)
            track_spaces.append(cur_space)
            cur_ntr = min_num_tr * (cur_width + cur_space)
            if isinstance(cur_space, float):
                cur_ntr += 0.5
            min_dim = int(round(tr_p * cur_ntr))

            if grid.get_direction(cur_layer) == 'x':
                min_h = max(min_h, min_dim)
            else:
                min_w = max(min_w, min_dim)

            prev_width = grid.get_track_width(cur_layer,
                                              cur_width,
                                              unit_mode=True)
            cur_layer += 1

        # get block size
        wblk, hblk = grid.get_block_size(cur_layer - 1,
                                         unit_mode=True,
                                         include_private=True,
                                         half_blk_x=False,
                                         half_blk_y=False)
        wblk_drc, hblk_drc = self.get_block_pitch()
        wblk = lcm([wblk, wblk_drc])
        hblk = lcm([hblk, hblk_drc])
        min_w = -(-min_w // wblk) * wblk
        min_h = -(-min_h // hblk) * hblk

        return track_widths, track_spaces, (min_w, min_h), (wblk, hblk)
Ejemplo n.º 10
0
    def draw_layout(self) -> None:
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid,
                                                 self.params['pinfo'])
        self.draw_base(pinfo)

        se_params: Param = self.params['se_params']
        flop_params: Param = self.params['flop_params']
        inv_params: Param = self.params['inv_params']
        vm_pitch: HalfInt = HalfInt.convert(self.params['vm_pitch'])

        # create masters
        flop_pinfo = self.get_draw_base_sub_pattern(2, 4)
        flop_params = flop_params.copy(
            append=dict(pinfo=flop_pinfo, out_pitch=vm_pitch))
        se_params = se_params.copy(append=dict(pinfo=self.get_tile_pinfo(0),
                                               vertical_out=False,
                                               vertical_in=False))
        inv_params = inv_params.copy(
            append=dict(pinfo=self.get_tile_pinfo(2), ridx_n=0, ridx_p=-1))

        flop_master = self.new_template(FlopStrongArm, params=flop_params)
        se_master = self.new_template(SingleToDiff, params=se_params)
        inv_master = self.new_template(InvCore, params=inv_params)

        # floorplanning
        tr_manager = self.tr_manager
        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        xm_layer = vm_layer + 1
        vm_w = tr_manager.get_width(vm_layer, 'sig')
        vm_w_hs = tr_manager.get_width(vm_layer, 'sig_hs')

        # get flop column quantization
        sd_pitch = self.sd_pitch
        vm_coord_pitch = int(vm_pitch * self.grid.get_track_pitch(vm_layer))
        sep_half = max(-(-self.min_sep_col // 2),
                       -(-vm_coord_pitch // sd_pitch))
        blk_ncol = lcm([sd_pitch, vm_coord_pitch]) // sd_pitch

        sep_ncol = self.min_sep_col
        flop_ncol2 = flop_master.num_cols // 2
        se_col = sep_half
        center_col = sep_half + inv_master.num_cols + sep_ncol + flop_ncol2
        center_col = -(-center_col // blk_ncol) * blk_ncol
        cur_col = center_col - flop_ncol2
        if (cur_col & 1) != (se_col & 1):
            se_col += 1
        se = self.add_tile(se_master, 0, se_col)
        inv = self.add_tile(inv_master, 2, cur_col - sep_ncol, flip_lr=True)
        flop = self.add_tile(flop_master, 2, cur_col)
        cur_col += flop_master.num_cols + self.sub_sep_col // 2

        lay_range = range(self.conn_layer, xm_layer + 1)
        vdd_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range}
        vss_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range}
        sup_info = self.get_supply_column_info(xm_layer)
        for tile_idx in range(self.num_tile_rows):
            self.add_supply_column(sup_info,
                                   cur_col,
                                   vdd_table,
                                   vss_table,
                                   ridx_p=-1,
                                   ridx_n=0,
                                   tile_idx=tile_idx,
                                   flip_lr=False)

        self.set_mos_size()

        # connections
        # supplies
        for lay in range(hm_layer, xm_layer + 1, 2):
            vss = vss_table[lay]
            vdd = vdd_table[lay]
            if lay == hm_layer:
                for inst in [inv, flop, se]:
                    vdd.extend(inst.get_all_port_pins('VDD'))
                    vss.extend(inst.get_all_port_pins('VSS'))
            vdd = self.connect_wires(vdd)
            vss = self.connect_wires(vss)
            self.add_pin(f'VDD_{lay}', vdd, hide=True)
            self.add_pin(f'VSS_{lay}', vss, hide=True)

        inp = flop.get_pin('inp')
        inn = flop.get_pin('inn')
        loc_list = tr_manager.place_wires(vm_layer, ['sig_hs'] * 2,
                                          center_coord=inp.middle)[1]
        inp, inn = self.connect_differential_tracks(inp,
                                                    inn,
                                                    vm_layer,
                                                    loc_list[0],
                                                    loc_list[1],
                                                    width=vm_w_hs)
        self.add_pin('sa_inp', inp)
        self.add_pin('sa_inn', inn)

        in_vm_ref = self.grid.coord_to_track(vm_layer, 0)
        in_vm_tidx = tr_manager.get_next_track(vm_layer,
                                               in_vm_ref,
                                               'sig',
                                               'sig',
                                               up=True)
        vm_phtr = vm_pitch.dbl_value
        in_vm_dhtr = -(-(in_vm_tidx - in_vm_ref).dbl_value //
                       vm_phtr) * vm_phtr
        in_vm_tidx = in_vm_ref + HalfInt(in_vm_dhtr)
        in_warr = self.connect_to_tracks(se.get_all_port_pins('in'),
                                         TrackID(vm_layer,
                                                 in_vm_tidx,
                                                 width=vm_w),
                                         track_lower=0)
        self.add_pin('in', in_warr)

        out = flop.get_pin('outp')
        self.add_pin('out', self.extend_wires(out, upper=self.bound_box.yh))

        self.reexport(flop.get_port('clkl'), net_name='clk', hide=False)
        self.reexport(flop.get_port('rstlb'))
        self.reexport(se.get_port('outp'), net_name='midp')
        self.reexport(se.get_port('outn'), net_name='midn')
        self.reexport(inv.get_port('in'), net_name='dum')

        self.sch_params = dict(
            se_params=se_master.sch_params,
            flop_params=flop_master.sch_params,
            inv_params=inv_master.sch_params,
        )
Ejemplo n.º 11
0
    def make_wire_specs(cls,
                        conn_layer: int,
                        top_layer: int,
                        tr_manager: TrackManager,
                        wire_specs: Mapping[int, Any],
                        min_size: Tuple[int, int] = (1, 1),
                        blk_pitch: Tuple[int, int] = (1, 1),
                        align_default: Alignment = Alignment.LOWER_COMPACT,
                        ptype_default: str = '') -> WireSpecs:
        """Read wire specifications from a dictionary.

        WireSpec dictionary format:

        WireSpec = Dict[int, WireData]
        WireData = Union[WireGraph, {data=WireGraph, align=Alignment, shared=List[str]}]
        WireGraph = Union[WireGroup, List[WireGroup]]
        WireGroup = Union[WireList, {wires=WireList, align=Alignment}]
        WireList = List[Wire]
        Wire = Union[name, (name, placement_type), (name, placement_type, wire_type)]

        keys of WireSpec is delta layer from conn_layer, so key of 1 is the same as conn_layer + 1.

        Parameters
        ----------
        conn_layer : int
            the connection layer ID.
        top_layer : int
            the top layer, used to compute block quantization.
        tr_manager : TrackManager
            the TrackManager instance.
        wire_specs : Mapping[int, Any]
            the wire specification dictionary to parse.
        min_size : Tuple[int, int]
            minimum width/height.
        blk_pitch : Tuple[int, int]
            width/height quantization on top of routing grid quantization.
        align_default : Alignment
            default alignment enum.
        ptype_default : str
            default placement type.

        Returns
        -------
        wire_specs : WireSpecs
            the wire specification dataclass.
        """
        w_min, h_min = min_size
        blk_w_res, blk_h_res = blk_pitch

        grid = tr_manager.grid

        half_blk_x = half_blk_y = True
        graph_list = []
        for delta_layer, wire_data in wire_specs.items():
            cur_layer = conn_layer + delta_layer
            wd = WireData.make_wire_data(wire_data, align_default,
                                         ptype_default)
            cur_graph = WireGraph.make_wire_graph(cur_layer, tr_manager, wd)
            cur_graph.place_compact(cur_layer, tr_manager)
            graph_list.append((cur_layer, cur_graph))
            if grid.is_horizontal(cur_layer):
                half_blk_y = half_blk_y and not cur_graph.has_center
                h_min = max(h_min, cur_graph.upper)
            else:
                half_blk_x = half_blk_x and not cur_graph.has_center
                w_min = max(w_min, cur_graph.upper)

        blk_w, blk_h = grid.get_block_size(top_layer,
                                           half_blk_x=half_blk_x,
                                           half_blk_y=half_blk_y)
        blk_w = lcm([blk_w, blk_w_res])
        blk_h = lcm([blk_h, blk_h_res])

        w_min = -(-w_min // blk_w) * blk_w
        h_min = -(-h_min // blk_h) * blk_h
        return WireSpecs((w_min, h_min), (blk_w, blk_h), graph_list)