Example #1
0
    def get_laygo_space_info(self, row_info, num_blk, left_blk_info, right_blk_info):
        # type: (Dict[str, Any], int, Any, Any) -> Dict[str, Any]

        od_y = row_info['od_y']
        po_y = row_info['po_y']
        # md_y = row_info['md_y']
        arr_y = row_info['arr_y']
        lch_unit = row_info['lch_unit']
        row_type = row_info['row_type']
        sub_type = row_info['sub_type']
        row_ext_top = row_info['ext_top_info']
        row_ext_bot = row_info['ext_bot_info']
        lay_info_list = row_info['lay_info_list']
        fill_info_list = row_info['fill_info_list']
        imp_params = row_info['imp_params']

        is_sub = (row_type == sub_type)

        mos_constants = self.get_mos_tech_constants(lch_unit)
        sd_pitch = mos_constants['sd_pitch']
        od_fill_w_max = None
        
        ####TODO####
        #This probably needs to come from get_mos_tech_constants, 
        #but its not super sensitive because of the // done in od_spx_fg
        #this works for now
        od_spx = lch_unit
        ##########
        
        od_spx_fg = -(-(od_spx - sd_pitch + lch_unit) // sd_pitch) + 2
        
        # get OD fill X interval
        area = num_blk - 2 * od_spx_fg
        if area > 0:
            if od_fill_w_max is None:
                #od_x_list = [(od_spx_fg, num_blk - od_spx_fg)]
                od_x = (od_spx_fg, num_blk - od_spx_fg)
            else:
                raise Exception('Greg is not rewriteing planar to accomodate od_list')
                od_fg_max = (od_fill_w_max - lch_unit) // sd_pitch - 1
                od_x_list = fill_symmetric_max_density(area, area, 2, od_fg_max, od_spx_fg,
                                                       offset=od_spx_fg, fill_on_edge=True,
                                                       cyclic=False)[0]
            draw_od = True
        else:
            #This is just a reasonable dummy value since draw_od is false
            od_x = (1,2)            
            draw_od = False

        row_info_list = [RowInfo(od_x=od_x, od_y=od_y, od_type=('dum', sub_type),
                                po_y=po_y), ]

        # update extension information
        cur_edge_info = EdgeInfo(od_type=None, draw_layers={}, y_intv=dict(od=od_y))
        # figure out poly types per finger
        po_types = []
        od_intv_idx = 0
        for cur_idx in range(num_blk):
            if cur_idx == 0 or cur_idx == num_blk - 1:
                od_type = left_blk_info[0].od_type if cur_idx == 0 else right_blk_info[0].od_type
                if od_type == 'mos':
                    po_types.append('PO_edge')
                elif od_type == 'sub':
                    po_types.append('PO_edge_sub')
                elif od_type == 'dum':
                    po_types.append('PO_edge_dummy')
                else:
                    po_types.append('PO_dummy')
            elif cur_idx < od_spx_fg or cur_idx >= num_blk - od_spx_fg:
                po_types.append('PO_dummy')

            #elif od_intv_idx < len(od_x_list):
            elif od_intv_idx < 1:
                #cur_od_intv = od_x_list[od_intv_idx]
                cur_od_intv = od_x
                if cur_od_intv[1] == cur_idx:
                    po_types.append('PO_edge_dummy')
                    od_intv_idx += 1
                elif cur_od_intv[0] <= cur_idx < cur_od_intv[1]:
                    po_types.append('PO_gate_dummy')
                elif cur_idx == cur_od_intv[0] - 1:
                    po_types.append('PO_edge_dummy')
                else:
                    if cur_idx > cur_od_intv[1]:
                        od_intv_idx += 1
                    po_types.append('PO_dummy')
            else:
                po_types.append('PO_dummy')

        # noinspection PyProtectedMember
        ext_top_info = row_ext_top._replace(po_types=po_types, edgel_info=cur_edge_info,
                                            edger_info=cur_edge_info)
        # noinspection PyProtectedMember
        ext_bot_info = row_ext_bot._replace(po_types=po_types, edgel_info=cur_edge_info,
                                            edger_info=cur_edge_info)

        lr_edge_info = (cur_edge_info, [])
        layout_info = dict(
            is_sub_row=is_sub,
            blk_type='sub' if is_sub else 'mos',
            lch_unit=lch_unit,
            sd_pitch=sd_pitch,
            fg=num_blk,
            arr_y=arr_y,
            draw_od=draw_od,
            row_info_list=row_info_list,
            lay_info_list=lay_info_list,
            sub_type=sub_type,
            imp_params=imp_params,
            is_sub_ring=False,
            dnw_mode='',

        )

        # step 8: return results
        return dict(
            layout_info=layout_info,
            ext_top_info=ext_top_info,
            ext_bot_info=ext_bot_info,
            left_edge_info=lr_edge_info,
            right_edge_info=lr_edge_info,
        )
Example #2
0
    def get_tb_edge_info(
            self,  # type: ResTechFinfetBase
            grid,  # type: RoutingGrid
            core_info,  # type: Dict[str, Any]
            hedge,  # type: int
            l,  # type: int
            w,  # type: int
            res_type,  # type: str
            sub_type,  # type: str
            threshold,  # type: str
            track_widths,  # type: List[int]
            track_spaces,  # type: List[Union[float, int]]
            options,  # type: Dict[str, Any]
    ):
        # type: (...) -> Optional[Dict[str, Any]]
        """Returns a dictionary of TB edge layout information.

        This method checks:
        1. spacing rules.
        2. PO density rules

        if all these pass, return TB edge layout information dictionary.
        """
        well_end_mode = options.get('well_end_mode', 3)

        nfin_min, nfin_max = self.res_config['od_fill_h']
        po_od_exty = self.res_config['po_od_exty']
        edge_margin = self.res_config['edge_margin']
        po_res_spy = self.res_config['po_res_spy']
        res_max_density = self.res_config['res_max_density']
        od_min_density = self.res_config['od_min_density']
        po_spy = self.res_config['po_spy']
        finfet_od_exty = self.res_config['finfet_od_exty']
        imp_po_ency = self.res_config['imp_po_ency']
        rtop_od_ency = self.res_config['rtop_od_ency']

        fin_h = self.mos_tech.mos_config['fin_h']
        fin_p = self.mos_tech.mos_config['mos_pitch']

        fin_p2 = fin_p // 2
        fin_h2 = fin_h // 2

        wcore = core_info['width']
        hcore = core_info['height']
        core_lr_dum_w = core_info['lr_dum_w']
        core_tb_dum_w = core_info['tb_dum_w']
        core_lr_od_loc = core_info['lr_od_loc'][0]
        core_fill_info = core_info['fill_info']
        if well_end_mode & 1 == 0:
            edge_margin = self.res_config.get('edge_margin_nowell',
                                              edge_margin)

        wres, lres, wres_lr, lres_tb = self.get_res_dimension(l, w)

        # compute dummy OD Y separation in number of fins
        od_sp = po_spy + po_od_exty * 2
        # when two ODs are N fin pitches apart, the actual OD spacing is N * fin_pitch - fin_h
        od_sp = -(-(od_sp + fin_h) // fin_p)

        # check RH_TN density rule
        max_res_area = int(wcore * hedge * res_max_density)
        if wres * lres_tb > max_res_area:
            return None

        # check spacing rule, which just means we can draw dummy transistors below RH
        # get space between resistor and core boundary
        spy = (hcore - lres) // 2
        # find bottom edge OD locations
        # compute OD Y coordinate for bottom edge of TBEdge block
        bot_dummy_bnd = edge_margin + imp_po_ency + po_od_exty
        bot_pitch_index = -(-(bot_dummy_bnd - fin_p2 + fin_h2) // fin_p)
        top_dummy_bnd = hedge - spy - lres_tb - po_res_spy - po_od_exty
        top_pitch_index = (top_dummy_bnd - fin_p2 - fin_h2) // fin_p
        tot_space = top_pitch_index - bot_pitch_index + 1
        edge_bot_od_loc = fill_symmetric_max_density(tot_space,
                                                     tot_space,
                                                     nfin_min,
                                                     nfin_max,
                                                     od_sp,
                                                     fill_on_edge=True,
                                                     cyclic=False)[0]
        # compute fin 0 offset and convert fin location to Y coordinates
        fin_offset = bot_pitch_index * fin_p + fin_p2
        edge_bot_od_loc = self._compute_od_y_loc(edge_bot_od_loc, fin_p, fin_h,
                                                 fin_offset)
        if not edge_bot_od_loc:
            # we cannot draw any bottom OD
            return None
        edge_tb_dum_yb = edge_bot_od_loc[0][0]

        # compute OD Y coordinate for left/right edge of TBEdge block.
        # find the fin pitch index of the lower bound of empty space.
        bot_pitch_index = top_pitch_index + od_sp
        # find the fin pitch index of the upper bound of empty space.
        adj_top_od_yb = hedge + core_lr_od_loc[0][0]
        top_pitch_index = (adj_top_od_yb - fin_p2 + fin_h2) // fin_p - od_sp
        # compute total space and fill
        tot_space = top_pitch_index - bot_pitch_index + 1
        edge_lr_od_loc = fill_symmetric_max_density(tot_space,
                                                    tot_space,
                                                    nfin_min,
                                                    nfin_max,
                                                    od_sp,
                                                    fill_on_edge=True,
                                                    cyclic=False)[0]
        # compute fin 0 offset and convert fin location to Y coordinates
        fin_offset = bot_pitch_index * fin_p + fin_p2
        edge_lr_od_loc = self._compute_od_y_loc(edge_lr_od_loc, fin_p, fin_h,
                                                fin_offset)
        edge_lr_po_bnd = (edge_bot_od_loc[-1][-1] + po_od_exty + po_spy,
                          adj_top_od_yb - po_od_exty - po_spy)

        # compute total OD area
        od_area = 0
        for od_w, yloc_list in ((core_lr_dum_w + core_tb_dum_w,
                                 edge_bot_od_loc), (core_lr_dum_w,
                                                    edge_lr_od_loc)):
            for yb, yt in yloc_list:
                od_area += od_w * (yt - yb)
        # check OD density rule
        min_od_area = int(math.ceil(wcore * hedge * od_min_density))
        if od_area < min_od_area:
            return None

        # if we get here, then all density rules are met
        # compute fill Y coordinate in edge block
        fill_edge_y_list = []
        for _, _, w, h, core_x, core_y, density, sp_min, sp_max, sp_bnd in core_fill_info:
            sp_yb = sp_bnd + h
            sp_yt = hedge + core_y[0][0]

            area = sp_yt - sp_yb
            tarea = int(math.ceil(area * density**0.5))
            c_info = fill_symmetric_min_density_info(area,
                                                     tarea,
                                                     h,
                                                     h,
                                                     sp_min,
                                                     sp_max=sp_max,
                                                     fill_on_edge=False)
            edge_y = fill_symmetric_interval(*c_info[0][2],
                                             offset=sp_yb,
                                             invert=c_info[1])[0]
            edge_y.insert(0, (sp_bnd, sp_yb))
            fill_edge_y_list.append(edge_y)

        # return layout information
        return dict(
            lr_od_loc=(edge_lr_od_loc, edge_lr_po_bnd),
            bot_od_loc=(edge_bot_od_loc, None),
            fb_yb=edge_tb_dum_yb - finfet_od_exty,
            rtop_yb=edge_tb_dum_yb - rtop_od_ency,
            imp_yb=edge_tb_dum_yb - po_od_exty - imp_po_ency,
            fill_edge_y_list=fill_edge_y_list,
        )
Example #3
0
    def get_core_info(
            self,
            grid,  # type: RoutingGrid
            width,  # type: int
            height,  # type: int
            l,  # type: int
            w,  # type: int
            res_type,  # type: str
            sub_type,  # type: str
            threshold,  # type: str
            track_widths,  # type: List[int]
            track_spaces,  # type: List[Union[float, int]]
            options,  # type: Dict[str, Any]
    ):
        # type: (...) -> Optional[Dict[str, Any]]
        """Compute core layout information dictionary.

        This method checks max PO and min OD density rules.
        """
        layer_table = self.config['layer_name']
        od_wmin = self.res_config['od_dim_min'][0]
        od_wmax = self.res_config['od_dim_max'][0]
        od_sp = self.res_config['od_sp']
        od_min_density = self.res_config['od_min_density']
        po_od_sp = self.res_config['po_od_sp']
        po_max_density = self.res_config['po_max_density']
        co_w = self.res_config['co_w']
        rpo_co_sp = self.res_config['rpo_co_sp']
        m1_sp_max = self.res_config['m1_sp_max']
        imp_od_sp = self.res_config['imp_od_sp']
        imp_ency = self.res_config['imp_enc'][1]
        res_info = self.res_config['info'][res_type]
        od_in_res = res_info['od_in_res']

        wres, lres, wres_lr, lres_tb = self.get_res_dimension(l, w)

        # check PO density
        max_res_area = int(width * height * po_max_density)
        if wres * lres > max_res_area:
            return None

        # compute OD fill X coordinates on the left/right edge
        if od_in_res:
            bnd_spx = (width - wres) // 2
            area = 2 * (bnd_spx - po_od_sp)
            lr_od_xloc = fill_symmetric_max_density(area,
                                                    area,
                                                    od_wmin,
                                                    od_wmax,
                                                    od_sp,
                                                    offset=-bnd_spx + po_od_sp,
                                                    sp_max=None,
                                                    fill_on_edge=True,
                                                    cyclic=False)[0]
            lr_od_h = lres
        else:
            lr_od_xloc = []
            lr_od_h = 0
        # compute OD fill Y coordinates on the top/bottom edge
        bnd_spy = (height - lres) // 2
        if od_in_res:
            area = 2 * (bnd_spy - po_od_sp)
            tb_od_offset = -bnd_spy + po_od_sp
            tb_od_w = wres
        else:
            area = 2 * (bnd_spy - (imp_od_sp + imp_ency))
            tb_od_offset = -bnd_spy + imp_od_sp + imp_ency
            tb_od_w = width - od_sp
        dod_dx = (width - tb_od_w) // 2
        tb_od_xloc = [(dod_dx, width - dod_dx)]
        tb_od_yloc = fill_symmetric_max_density(area,
                                                area,
                                                od_wmin,
                                                od_wmax,
                                                od_sp,
                                                offset=tb_od_offset,
                                                sp_max=None,
                                                fill_on_edge=True,
                                                cyclic=False)[0]

        # check OD density
        min_od_area = int(math.ceil(width * height * od_min_density))
        # compute OD area
        od_area = 0
        for od_w, od_intv_list in ((lr_od_h, lr_od_xloc), (tb_od_w,
                                                           tb_od_yloc)):
            for lower, upper in od_intv_list:
                od_area += od_w * (upper - lower)
        if od_area < min_od_area:
            return None

        # if we get here, then all density rules are met
        # split into top and bottom dummy locations
        num_dummy_half = -(-len(tb_od_yloc) // 2)
        bot_od_yloc = tb_od_yloc[-num_dummy_half:]
        top_od_yloc = [(a + height, b + height)
                       for a, b in tb_od_yloc[:num_dummy_half]]

        # fill layout info with dummy information
        layout_info = dict(
            width=width,
            height=height,
            lr_od_xloc=lr_od_xloc,
            bot_od_yloc=bot_od_yloc,
            top_od_yloc=top_od_yloc,
            tb_od_xloc=tb_od_xloc,
        )

        # compute port information
        # first, compute M2 routing track location
        xc = width // 2
        rpdmy_yb = height // 2 - l // 2
        rpdmy_yt = rpdmy_yb + l
        bot_yc = rpdmy_yb - rpo_co_sp - co_w // 2
        top_yc = rpdmy_yt + rpo_co_sp + co_w // 2
        bot_layer = self.get_bot_layer()
        bot_pitch = grid.get_track_pitch(bot_layer, unit_mode=True)
        bot_num_tr = height // bot_pitch if height % bot_pitch == 0 else height / bot_pitch
        # first, find M2 tracks such that the top track of this block and the bottom track of
        # the top adjacent block is track_spaces[0] tracks apart.  the actual tracks cannot exceed these.
        m2_w, m2_sp = track_widths[0], track_spaces[0]
        if isinstance(m2_sp, int):
            bot_tr_min = (m2_w + m2_sp + 1) / 2 - 1
        else:
            # for half-integer spacing, we need to round up edge space so that tracks remain centered
            # in the block
            bot_tr_min = (m2_w + m2_sp + 1.5) / 2 - 1
        top_tr_max = bot_num_tr - 1 - bot_tr_min

        # find M2 tracks closest to ports
        top_tr = min(
            top_tr_max,
            grid.coord_to_nearest_track(bot_layer,
                                        top_yc,
                                        half_track=True,
                                        mode=1,
                                        unit_mode=True))
        bot_tr = max(
            bot_tr_min,
            grid.coord_to_nearest_track(bot_layer,
                                        bot_yc,
                                        half_track=True,
                                        mode=-1,
                                        unit_mode=True))

        # get CO/VIA1 parameters, and metal 1 bounding box
        m1_name = layer_table[1]
        m2_name = layer_table[2]
        m2_h = grid.get_track_width(bot_layer, m2_w, unit_mode=True)
        m2_type = self.tech_info.get_layer_type(m2_name)
        m2_len_min = self.tech_info.get_min_length_unit(m2_type, m2_h)
        res = grid.resolution
        port_info = []
        for port_name, yc, m2_tr in (('bot', bot_yc, bot_tr), ('top', top_yc,
                                                               top_tr)):
            via0_params, m1_box = self.get_via0_info(xc, yc, wres, res)
            # get via1 parameters
            m2_yc = grid.track_to_coord(bot_layer, m2_tr, unit_mode=True)
            v1_box = BBox(m1_box.left_unit,
                          m2_yc - m2_h // 2,
                          m1_box.right_unit,
                          m2_yc + m2_h // 2,
                          res,
                          unit_mode=True)
            via1_info = grid.tech_info.get_via_info(v1_box, m1_name, m2_name,
                                                    'y')
            m1_box = m1_box.merge(via1_info['bot_box'])
            m2_box = via1_info['top_box']
            m2_box = m2_box.expand(dx=max(
                0, (m2_len_min - m2_box.width_unit) // 2),
                                   unit_mode=True)
            via1_params = via1_info['params']
            via1_params['via_type'] = via1_params.pop('id')
            port_info.append(
                (port_name, via0_params, via1_params, m1_box, m2_box))

        # compute fill information
        # compute fill Y coordinate in core block
        # compute fill Y coordinates between ports inside the cell
        m1_w = port_info[0][3].width_unit
        m1_h = port_info[0][3].height_unit
        m1_bot = port_info[0][3]
        m1_top = port_info[1][3]
        m1_bot_yb, m1_bot_yt = m1_bot.bottom_unit, m1_bot.top_unit
        m1_top_yb, m1_top_yt = m1_top.bottom_unit, m1_top.top_unit
        m1_core_mid_y = fill_symmetric_const_space(m1_top_yb - m1_bot_yt,
                                                   m1_sp_max,
                                                   m1_h,
                                                   m1_h,
                                                   offset=m1_bot_yt)
        # compute fill Y coordinates between ports outside the cell
        m1_core_top_y = fill_symmetric_const_space(m1_bot_yb + height -
                                                   m1_top_yt,
                                                   m1_sp_max,
                                                   m1_h,
                                                   m1_h,
                                                   offset=m1_top_yt)
        # combine fill Y coordinates together in one list
        fill_len2 = -(-len(m1_core_top_y) // 2)
        m1_core_y = [(a - height, b - height)
                     for (a, b) in m1_core_top_y[-fill_len2:]]
        m1_core_y.append((m1_bot_yb, m1_bot_yt))
        m1_core_y.extend(m1_core_mid_y)
        m1_core_y.append((m1_top_yb, m1_top_yt))
        m1_core_y.extend(m1_core_top_y[:fill_len2])

        # compute fill X coordinate in core block
        m1_xl, m1_xr = m1_bot.left_unit, m1_bot.right_unit
        sp_xl = -width + m1_xr
        sp_xr = m1_xl
        m1_core_x = fill_symmetric_const_space(sp_xr - sp_xl,
                                               m1_sp_max,
                                               m1_w,
                                               m1_w,
                                               offset=sp_xl)
        m1_core_x.append((m1_xl, m1_xr))
        m1_core_x.extend(((a + width, b + width) for (a, b) in m1_core_x[:-1]))

        layout_info['port_info'] = port_info
        layout_info['m1_core_x'] = m1_core_x
        layout_info['m1_core_y'] = m1_core_y
        layout_info['m1_w'] = m1_w
        layout_info['m1_h'] = m1_h

        return layout_info
Example #4
0
    def get_core_info(
            self,  # type: ResTechFinfetBase
            grid,  # type: RoutingGrid
            width,  # type: int
            height,  # type: int
            l,  # type: int
            w,  # type: int
            res_type,  # type: str
            sub_type,  # type: str
            threshold,  # type: str
            track_widths,  # type: List[int]
            track_spaces,  # type: List[Union[float, int]]
            options,  # type: Dict[str, Any]
    ):
        # type: (...) -> Optional[Dict[str, Any]]
        """Compute core layout information dictionary.

        This method checks max PO and min OD density rules.
        """
        res = grid.resolution

        nfin_min, nfin_max = self.res_config['od_fill_h']
        po_od_exty = self.res_config['po_od_exty']
        po_spx = self.res_config['po_spx']
        po_spy = self.res_config['po_spy']
        po_res_spx = self.res_config['po_res_spx']
        po_res_spy = self.res_config['po_res_spy']
        po_lch = self.res_config['po_lch']
        po_pitch = self.res_config['po_pitch']
        mp_h = self.res_config['mp_h']
        res_max_density = self.res_config['res_max_density']
        od_min_density = self.res_config['od_min_density']

        fin_h = self.mos_tech.mos_config['fin_h']
        fin_p = self.mos_tech.mos_config['mos_pitch']

        fin_p2 = fin_p // 2
        fin_h2 = fin_h // 2

        wres, lres, wres_lr, lres_tb = self.get_res_dimension(l, w)

        # check resistor density
        max_res_area = int(width * height * res_max_density)
        if wres * lres > max_res_area:
            return None

        # Compute dummy Y coordinates
        # compute dummy OD Y separation in number of fins
        od_sp = po_spy + po_od_exty * 2
        # when two ODs are N fin pitches apart, the actual OD spacing is N * fin_pitch - fin_h
        od_sp = -(-(od_sp + fin_h) // fin_p)
        # compute OD Y coordinates for left/right edge.
        h_core_nfin = height // fin_p
        core_lr_od_loc = fill_symmetric_max_density(h_core_nfin,
                                                    h_core_nfin,
                                                    nfin_min,
                                                    nfin_max,
                                                    od_sp,
                                                    fill_on_edge=False,
                                                    cyclic=True)[0]
        # compute OD Y coordinates for top/bottom edge.
        # compute fin offset for top edge dummies
        bnd_spy = (height - lres) // 2
        top_dummy_bnd = bnd_spy + lres + po_res_spy + po_od_exty
        # find the fin pitch index of the lower bound of the empty space.
        pitch_index = -(-(top_dummy_bnd - fin_p2 + fin_h2) // fin_p)
        tot_space = 2 * (h_core_nfin - pitch_index)
        core_tb_od_loc = fill_symmetric_max_density(tot_space,
                                                    tot_space,
                                                    nfin_min,
                                                    nfin_max,
                                                    od_sp,
                                                    fill_on_edge=True,
                                                    cyclic=False)[0]

        # compute dummy number of fingers for left/right edge
        bnd_spx = (width - wres) // 2
        avail_sp = bnd_spx * 2 - po_res_spx * 2
        core_lr_fg = (avail_sp - po_lch) // po_pitch + 1
        # compute dummy number of fingers for top/bottom edge
        core_lr_dum_w = po_lch + (core_lr_fg - 1) * po_pitch
        avail_sp = width - core_lr_dum_w - 2 * po_spx
        core_tb_fg = (avail_sp - po_lch) // po_pitch + 1
        core_tb_dum_w = po_lch + (core_tb_fg - 1) * po_pitch

        # check OD density
        min_od_area = int(math.ceil(width * height * od_min_density))
        # compute OD area
        od_area = 0
        for od_w, od_fin_list in ((core_lr_dum_w, core_lr_od_loc),
                                  (core_tb_dum_w, core_tb_od_loc)):
            for fin_start, fin_stop in od_fin_list:
                od_area += od_w * ((fin_stop - fin_start - 1) * fin_p + fin_h)
        if od_area < min_od_area:
            return None

        # if we get here, then all density rules are met
        # convert dummy fin location to Y coordinates
        core_lr_od_loc = self._compute_od_y_loc(core_lr_od_loc, fin_p, fin_h,
                                                fin_p2)
        # split the top/bottom dummies into halves
        num_dummy_half = -(-len(core_tb_od_loc) // 2)
        # top dummy locations
        top_offset = pitch_index * fin_p + fin_p2
        core_top_od_loc = self._compute_od_y_loc(
            core_tb_od_loc[:num_dummy_half], fin_p, fin_h, top_offset)
        core_top_po_bnd = (height - bnd_spy + po_res_spy,
                           height + bnd_spy - po_res_spy)
        # bottom dummy locations
        core_bot_od_loc = self._compute_od_y_loc(
            core_tb_od_loc[-num_dummy_half:], fin_p, fin_h,
            top_offset - height)
        core_bot_po_bnd = (-bnd_spy + po_res_spy, bnd_spy - po_res_spy)

        # fill layout info with dummy information
        layout_info = dict(
            width=width,
            height=height,
            lr_dum_w=core_lr_dum_w,
            tb_dum_w=core_tb_dum_w,
            lr_od_loc=(core_lr_od_loc, None),
            top_od_loc=(core_top_od_loc, core_top_po_bnd),
            bot_od_loc=(core_bot_od_loc, core_bot_po_bnd),
            lr_fg=core_lr_fg,
            tb_fg=core_tb_fg,
        )

        # compute port information
        # first, compute port track location
        xc = width // 2
        rpdmy_yb = height // 2 - l // 2
        rpdmy_yt = rpdmy_yb + l
        bot_yc = rpdmy_yb - mp_h // 2
        top_yc = rpdmy_yt + mp_h // 2
        bot_layer = self.get_bot_layer()
        bot_pitch = grid.get_track_pitch(bot_layer, unit_mode=True)
        bot_num_tr = height // bot_pitch
        # first, find port tracks such that the top track of this block and the bottom track of
        # the top adjacent block is track_spaces[0] tracks apart.
        # the actual tracks cannot exceed these.
        top_tr_max = bot_num_tr - (track_widths[0] + track_spaces[0] + 1) / 2
        bot_tr_min = (track_widths[0] + track_spaces[0] + 1) / 2 - 1
        # find port tracks closest to ports
        top_tr = min(
            top_tr_max,
            grid.coord_to_nearest_track(bot_layer,
                                        top_yc,
                                        half_track=True,
                                        mode=1,
                                        unit_mode=True))
        bot_tr = max(
            bot_tr_min,
            grid.coord_to_nearest_track(bot_layer,
                                        bot_yc,
                                        half_track=True,
                                        mode=-1,
                                        unit_mode=True))

        # get port information
        port_info = []
        for port_name, yc, m2_tr in (('bot', bot_yc, bot_tr), ('top', top_yc,
                                                               top_tr)):
            port_yb, port_yt = grid.get_wire_bounds(bot_layer,
                                                    m2_tr,
                                                    track_widths[0],
                                                    unit_mode=True)
            rect_list, via_list = self.get_port_info(xc, yc, wres, port_yb,
                                                     port_yt, res)
            port_info.append((port_name, rect_list, via_list))

        # compute fill information
        # compute fill Y coordinate in core block
        bot_rect_list = port_info[0][1]
        top_rect_list = port_info[1][1]
        fill_info = []
        for bot_rect_info, top_rect_info in zip(bot_rect_list, top_rect_list):
            if bot_rect_info['do_fill']:
                layer = bot_rect_info['layer']
                exc_layer = bot_rect_info['exc_layer']
                density = bot_rect_info['density']
                sp_min = bot_rect_info['sp_min']
                sp_max = bot_rect_info['sp_max']
                sp_bnd = bot_rect_info['sp_bnd']
                bot_box = bot_rect_info['bbox']
                top_box = top_rect_info['bbox']
                density_1d = density**0.5
                w, h = bot_box.width_unit, bot_box.height_unit
                bot_yb, bot_yt = bot_box.bottom_unit, bot_box.top_unit
                top_yb, top_yt = top_box.bottom_unit, top_box.top_unit
                # compute fill Y coordinates between ports inside the cell
                area = top_yb - bot_yt
                tarea = int(math.ceil(area * density_1d))
                mid_info = fill_symmetric_min_density_info(area,
                                                           tarea,
                                                           h,
                                                           h,
                                                           sp_min,
                                                           sp_max=sp_max,
                                                           fill_on_edge=False)
                core_mid_y = fill_symmetric_interval(*mid_info[0][2],
                                                     offset=bot_yt,
                                                     invert=mid_info[1])[0]
                # compute fill Y coordinates between ports outside the cell
                area = bot_yb + height - top_yt
                tarea = int(math.ceil(area * density_1d))
                top_info = fill_symmetric_min_density_info(area,
                                                           tarea,
                                                           h,
                                                           h,
                                                           sp_min,
                                                           sp_max=sp_max,
                                                           fill_on_edge=False)
                core_top_y = fill_symmetric_interval(*top_info[0][2],
                                                     offset=top_yt,
                                                     invert=top_info[1])[0]

                # combine fill Y coordinates together in one list
                fill_len2 = -(-len(core_top_y) // 2)
                core_y = [(a - height, b - height)
                          for (a, b) in core_top_y[-fill_len2:]]
                core_y.append((bot_yb, bot_yt))
                core_y.extend(core_mid_y)
                core_y.append((top_yb, top_yt))
                core_y.extend(core_top_y[:fill_len2])
                # compute fill X coordinate in core block
                xl, xr = bot_box.left_unit, bot_box.right_unit
                sp_xl = -width + xr
                sp_xr = xl

                area = sp_xr - sp_xl
                tarea = int(math.ceil(area * density_1d))
                x_info = fill_symmetric_min_density_info(area,
                                                         tarea,
                                                         w,
                                                         w,
                                                         sp_min,
                                                         sp_max=sp_max,
                                                         fill_on_edge=False)
                core_x = fill_symmetric_interval(*x_info[0][2],
                                                 offset=sp_xl,
                                                 invert=x_info[1])[0]

                core_x.append((xl, xr))
                core_x.extend(
                    ((a + width, b + width) for (a, b) in core_x[:-1]))

                fill_info.append((layer, exc_layer, w, h, core_x, core_y,
                                  density, sp_min, sp_max, sp_bnd))

        layout_info['port_info'] = port_info
        layout_info['fill_info'] = fill_info
        return layout_info
Example #5
0
    def get_laygo_space_info(self, row_info, num_blk, left_blk_info, right_blk_info):
        # type: (Dict[str, Any], int, Any, Any) -> Dict[str, Any]

        od_y = row_info['od_y']
        po_y = row_info['po_y']
        md_y = row_info['md_y']
        arr_y = row_info['arr_y']
        lch_unit = row_info['lch_unit']
        row_type = row_info['row_type']
        sub_type = row_info['sub_type']
        row_ext_top = row_info['ext_top_info']
        row_ext_bot = row_info['ext_bot_info']
        lay_info_list = row_info['lay_info_list']
        fill_info_list = row_info['fill_info_list']
        imp_params = row_info['imp_params']

        is_sub = (row_type == sub_type)

        mos_constants = self.get_mos_tech_constants(lch_unit)
        sd_pitch = mos_constants['sd_pitch']
        od_spx = mos_constants['od_spx']
        od_fill_w_max = mos_constants['od_fill_w_max']

        od_spx_fg = -(-(od_spx - sd_pitch + lch_unit) // sd_pitch) + 2

        # get OD fill X interval
        area = num_blk - 2 * od_spx_fg
        if area > 0:
            if od_fill_w_max is None:
                od_x_list = [(od_spx_fg, num_blk - od_spx_fg)]
            else:
                od_fg_max = (od_fill_w_max - lch_unit) // sd_pitch - 1
                od_x_list = fill_symmetric_max_density(area, area, 2, od_fg_max, od_spx_fg,
                                                       offset=od_spx_fg, fill_on_edge=True,
                                                       cyclic=False)[0]
        else:
            od_x_list = []
        # get row OD list
        row_info_list = [RowInfo(od_x_list=od_x_list, od_y=od_y, od_type=('dum', sub_type),
                                 row_y=arr_y, po_y=po_y, md_y=md_y), ]

        # update extension information
        cur_edge_info = EdgeInfo(od_type=None, draw_layers={}, y_intv=dict(od=od_y, md=md_y))
        # figure out poly types per finger
        po_types = []
        od_intv_idx = 0
        for cur_idx in range(num_blk):
            if cur_idx == 0 or cur_idx == num_blk - 1:
                od_type = left_blk_info[0].od_type if cur_idx == 0 else right_blk_info[0].od_type
                if od_type == 'mos':
                    po_types.append('PO_edge')
                elif od_type == 'sub':
                    po_types.append('PO_edge_sub')
                elif od_type == 'dum':
                    po_types.append('PO_edge_dummy')
                else:
                    po_types.append('PO_dummy')
            elif cur_idx < od_spx_fg - 1 or cur_idx >= num_blk - od_spx_fg + 1:
                po_types.append('PO_dummy')
            elif od_intv_idx < len(od_x_list):
                cur_od_intv = od_x_list[od_intv_idx]
                if cur_od_intv[1] == cur_idx:
                    po_types.append('PO_edge_dummy')
                    od_intv_idx += 1
                elif cur_od_intv[0] <= cur_idx < cur_od_intv[1]:
                    po_types.append('PO_gate_dummy')
                elif cur_idx == cur_od_intv[0] - 1:
                    po_types.append('PO_edge_dummy')
                else:
                    if cur_idx > cur_od_intv[1]:
                        od_intv_idx += 1
                    po_types.append('PO_dummy')
            else:
                po_types.append('PO_dummy')

        # noinspection PyProtectedMember
        ext_top_info = row_ext_top._replace(po_types=po_types, edgel_info=cur_edge_info,
                                            edger_info=cur_edge_info)
        # noinspection PyProtectedMember
        ext_bot_info = row_ext_bot._replace(po_types=po_types, edgel_info=cur_edge_info,
                                            edger_info=cur_edge_info)

        lr_edge_info = (cur_edge_info, [])
        layout_info = dict(
            is_sub_row=is_sub,
            blk_type='sub' if is_sub else 'mos',
            lch_unit=lch_unit,
            fg=num_blk,
            arr_y=arr_y,
            draw_od=True,
            row_info_list=row_info_list,
            lay_info_list=lay_info_list,
            fill_info_list=fill_info_list,
            # edge parameters
            sub_type=sub_type,
            imp_params=imp_params,
            is_sub_ring=False,
            dnw_mode='',
            # adjacent block information list
            adj_row_list=[],
            left_blk_info=left_blk_info[0],
            right_blk_info=right_blk_info[0],
        )

        # step 8: return results
        return dict(
            layout_info=layout_info,
            ext_top_info=ext_top_info,
            ext_bot_info=ext_bot_info,
            left_edge_info=lr_edge_info,
            right_edge_info=lr_edge_info,
        )