Beispiel #1
0
    def merge(self, track_set):
        # type: (TrackSet) -> None
        """Merge the given TrackSet to this one."""
        for hidx, new_intv_set in track_set._tracks.items():
            if hidx not in self._tracks:
                intv_set = IntervalSet()
                self._tracks[hidx] = intv_set
            else:
                intv_set = self._tracks[hidx]

            for intv, val in new_intv_set.items():
                intv_set.add(intv, val, merge=True)
Beispiel #2
0
class LaygoIntvSet(object):
    def __init__(self):
        super(LaygoIntvSet, self).__init__()
        self._intv = IntervalSet()
        self._end_flags = {}

    def add(self, intv, endl, endr):
        ans = self._intv.add(intv)
        if ans:
            start, stop = intv
            if start in self._end_flags:
                del self._end_flags[start]
            else:
                self._end_flags[start] = endl
            if stop in self._end_flags:
                del self._end_flags[stop]
            else:
                self._end_flags[stop] = endr
            return True
        else:
            return False

    def get_complement(self, total_intv):
        compl_intv = self._intv.get_complement(total_intv)
        intv_list = []
        end_list = []
        for intv in compl_intv:
            intv_list.append(intv)
            end_list.append((self._end_flags.get(intv[0], False),
                             self._end_flags.get(intv[1], False)))
        return intv_list, end_list

    def get_end_flags(self, num_col):
        if 0 not in self._end_flags:
            start_flag = False
        else:
            start_flag = self._end_flags[0]

        if num_col not in self._end_flags:
            end_flag = False
        else:
            end_flag = self._end_flags[num_col]
        return start_flag, end_flag

    def get_end(self):
        if not self._intv:
            return 0
        return self._intv.get_end()
Beispiel #3
0
    def add_std_space(self, loc, num_col, update_used_blks=True):
        # type: (Tuple[int, int], int, bool) -> None
        """Add standard cell spaces at the given location.

        Parameters
        ----------
        loc : Tuple[int, int]
            the lower-left corner of the space block.
        num_col : int
            the space block width in number of columns.
        update_used_blks : bool
            True to register space blocks.  This flag is for internal use only.
        """
        if update_used_blks:
            # update self._used_blocks
            while len(self._used_blocks) < loc[1] + 1:
                self._used_blocks.append(IntervalSet())
            success = self._used_blocks[loc[1]].add((loc[0], loc[0] + num_col))
            if not success:
                raise ValueError('Cannot add space at std loc (%d, %d)' %
                                 (loc[0], loc[1]))

        col_pitch = self.std_col_width
        xcur = loc[0] * col_pitch
        if loc[1] % 2 == 0:
            orient = 'R0'
            ycur = loc[1] * self.std_row_height
        else:
            orient = 'MX'
            ycur = (loc[1] + 1) * self.std_row_height

        if self._draw_boundaries:
            dx = self._bound_params['lr_width'] * self.std_col_width
            dy = self._bound_params['tb_height'] * self.std_row_height
        else:
            dx = dy = 0

        for blk_params in self.get_space_blocks():
            lib_name = blk_params['lib_name']
            cell_name = blk_params['cell_name']
            blk_col = blk_params['num_col']
            num_blk, num_col = divmod(num_col, blk_col)
            blk_width = blk_col * col_pitch
            if num_blk > 0:
                self.add_instance_primitive(lib_name,
                                            cell_name, (xcur + dx, ycur + dy),
                                            orient=orient,
                                            nx=num_blk,
                                            spx=blk_width)
                xcur += num_blk * blk_width

        if num_col > 0:
            raise ValueError('has %d columns remaining' % num_col)
Beispiel #4
0
    def add_track(self, hidx, intv, width, value=None):
        # type: (int, Tuple[int, int], int, Any) -> None
        """Add tracks to this data structure.

        Parameters
        ----------
        hidx : int
            the half track index.
        intv : Tuple[int, int]
            the track interval.
        width : int
            the track width.
        value : Any
            value associated with this track.
        """
        if intv[1] - intv[0] >= self._min_len:
            if hidx not in self._tracks:
                intv_set = IntervalSet()
                self._tracks[hidx] = intv_set
            else:
                intv_set = self._tracks[hidx]

            # TODO: add more robust checking?
            intv_set.add(intv, val=[width, value], merge=True)
Beispiel #5
0
    def add_std_instance(self, master, inst_name=None, loc=(0, 0), nx=1, ny=1,
                         spx=0, spy=0, flip_lr=False):
        # type: (StdCellBase, Optional[str], Tuple[int, int], int, int, int, int, bool) -> Instance
        """Add a new standard cell instance.

        Parameters
        ----------
        master : StdCellBase
            the standard cell template master to add.
        inst_name : Optional[str]
            the instance name.
        loc : Tuple[int, int]
            lower-left corner of the instance in number of standard cell columns/rows.
        nx : int
            horizontal array count.
        ny : int
            vertical array count.
        spx : int
            horizontal pitch in number of standard cell columns.
        spy : int
            vertical pitch in number of standard cell rows.  Must be even.
        flip_lr : bool
            True to flip the standard cell over Y axis.

        Returns
        -------
        inst : Instance
            the standard cell instance.
        """
        if spy % 2 != 0:
            raise ValueError('row pitch must be even')

        # update self._used_blocks
        master_std_size = master.std_size
        if master_std_size is None:
            raise ValueError("master.std_size is unset. Try calling master.set_std_size()?")
        inst_ncol, inst_nrow = master_std_size
        cur_nrow = loc[1] + inst_nrow + (ny - 1) * spy
        while len(self._used_blocks) < cur_nrow:
            self._used_blocks.append(IntervalSet())
        for col_off in range(nx):
            xoff = col_off * spx + loc[0]
            for row_off in range(ny):
                yoff = row_off * spy + loc[1]
                for std_row_idx in range(yoff, yoff + inst_nrow):
                    success = self._used_blocks[std_row_idx].add((xoff, xoff + inst_ncol))
                    if not success:
                        raise ValueError('Cannot add instance at std loc (%d, %d)' % (xoff, yoff))

        col_pitch = self.std_col_width
        row_pitch = self.std_row_height
        if loc[1] % 2 == 0:
            orient = 'R0'
            dy = loc[1] * row_pitch
        else:
            orient = 'MX'
            dy = (loc[1] + 1) * row_pitch

        dx = loc[0] * col_pitch
        if flip_lr:
            dx += inst_ncol * col_pitch
            if orient == 'R0':
                orient = 'MY'
            else:
                orient = 'R180'

        spx_new = spx * col_pitch
        spy_new = spy * row_pitch
        if self._draw_boundaries:
            dx += self._bound_params['lr_width'] * self.std_col_width
            dy += self._bound_params['tb_height'] * self.std_row_height

        return self.add_instance(master, inst_name=inst_name, loc=(dx, dy),
                                 orient=orient, nx=nx, ny=ny, spx=spx_new, spy=spy_new)
Beispiel #6
0
    def draw_bias_shields(
            cls,  # type: BiasShield
            template,  # type: TemplateBase
            layer,  # type: int
            bias_config,  # type: Dict[int, Tuple[int, ...]]
            nwire,  # type: int
            offset,  # type: int
            lower,  # type: int
            upper,  # type: int
            width=1,  # type: int
            space_sig=0,  # type: int
            sup_warrs=None,  # type: Optional[Union[WireArray, List[WireArray]]]
            check_blockage=True,  # type: bool
            tb_mode=3,  # type: int
    ):
        if lower >= upper:
            return [], None

        grid = template.grid
        res = grid.resolution

        params = dict(
            layer=layer,
            nwire=nwire,
            bias_config=bias_config,
            top=False,
            width=width,
            space_sig=space_sig,
        )
        bot_master = template.new_template(params=params, temp_cls=BiasShield)
        sh_box = bot_master.bound_box
        params['top'] = True
        top_master = template.new_template(params=params, temp_cls=BiasShield)
        blk_w = sh_box.width_unit
        blk_h = sh_box.height_unit

        route_tids = bot_master.route_tids
        tr_dir = grid.get_direction(layer)
        is_horiz = tr_dir == 'x'
        qdim = blk_w if is_horiz else blk_h
        tr0 = grid.coord_to_track(layer, offset, unit_mode=True) + 0.5
        bot_intvs = IntervalSet()
        top_intvs = IntervalSet()

        nstart, tr_offset = divmod(lower, qdim)
        nstop, tr_off_test = divmod(upper, qdim)
        if tr_offset != tr_off_test:
            raise ValueError('upper - lower not divisible by %d' % qdim)

        # draw shields
        tr0_ref = route_tids[0][0]
        sh0 = tr0_ref + tr0
        shp = route_tids[nwire + 1][0] - tr0_ref
        shields = template.add_wires(layer,
                                     sh0,
                                     lower,
                                     upper,
                                     num=2,
                                     pitch=shp,
                                     unit_mode=True)

        # connect supply wires if necessary
        sup_layer = layer + 1
        if sup_warrs is not None:
            new_sup_warrs = []
            _, wires = template.connect_to_tracks(sup_warrs,
                                                  shields.track_id,
                                                  return_wires=True)
            for warr in wires:
                if warr.layer_id == sup_layer:
                    new_sup_warrs.append(warr)
            sup_warrs = new_sup_warrs
        else:
            sup_warrs = []

        # get blockages
        if check_blockage:
            if is_horiz:
                test_box = BBox(lower,
                                offset,
                                upper,
                                offset + blk_h,
                                res,
                                unit_mode=True)
            else:
                test_box = BBox(offset,
                                lower,
                                offset + blk_w,
                                upper,
                                res,
                                unit_mode=True)
            for lay_id, intv in ((layer - 1, bot_intvs), (layer + 1,
                                                          top_intvs)):
                w_ntr = bias_config[lay_id][1]
                if is_horiz:
                    spx = grid.get_space(lay_id, w_ntr, unit_mode=True)
                    spy = grid.get_line_end_space(lay_id,
                                                  w_ntr,
                                                  unit_mode=True)
                else:
                    spy = grid.get_space(lay_id, w_ntr, unit_mode=True)
                    spx = grid.get_line_end_space(lay_id,
                                                  w_ntr,
                                                  unit_mode=True)
                for box in template.blockage_iter(lay_id,
                                                  test_box,
                                                  spx=spx,
                                                  spy=spy):
                    blkl, blku = box.get_interval(tr_dir, unit_mode=True)
                    blkl = max(blkl, lower)
                    blku = min(blku, upper)
                    if blku > blkl:
                        intv.add((blkl, blku), merge=True, abut=True)

        master_intv_list = []
        if tb_mode & 1 != 0:
            master_intv_list.append((bot_master, bot_intvs))
        if tb_mode & 2 != 0:
            master_intv_list.append((top_master, top_intvs))
        # draw blocks
        for master, intvs in master_intv_list:
            sl, su = master.sup_intv
            ncur = nstart
            for nend, nnext in cls._get_blk_idx_iter(intvs, sl + tr_offset,
                                                     su + tr_offset, qdim,
                                                     nstart, nstop):
                nblk = nend - ncur
                if nblk > 0:
                    if is_horiz:
                        loc = (ncur * qdim + tr_offset, offset)
                        nx = nblk
                        ny = 1
                    else:
                        loc = (offset, ncur * qdim + tr_offset)
                        nx = 1
                        ny = nblk
                    inst = template.add_instance(master,
                                                 loc=loc,
                                                 nx=nx,
                                                 ny=ny,
                                                 spx=qdim,
                                                 spy=qdim,
                                                 unit_mode=True)
                    sup_warrs.extend(
                        inst.port_pins_iter('sup', layer=sup_layer))
                ncur = nnext

        return sup_warrs, shields
Beispiel #7
0
def join_bias_vroutes(template,
                      vm_layer,
                      vdd_dx,
                      vss_dx,
                      xr,
                      num_vdd_tot,
                      num_vss_tot,
                      hm_bias_info_list,
                      bias_config,
                      vdd_pins,
                      vss_pins,
                      xl=0,
                      yt=None,
                      vss_warrs=None,
                      vdd_warrs=None):
    grid = template.grid

    vss_intvs = IntervalSet()
    vdd_intvs = IntervalSet()
    if vss_warrs is not None:
        for w in WireArray.single_warr_iter(vss_warrs):
            vss_intvs.add(w.track_id.get_bounds(grid, unit_mode=True), val=w)
    if vdd_warrs is not None:
        for w in WireArray.single_warr_iter(vdd_warrs):
            vdd_intvs.add(w.track_id.get_bounds(grid, unit_mode=True), val=w)

    vdd_xl, vdd_xr = vdd_dx
    vss_xl, vss_xr = vss_dx
    vdd_xl += xl
    vdd_xr += xl
    vss_xl += xl
    vss_xr += xl
    vss_params = dict(
        nwire=num_vss_tot,
        width=1,
        space_sig=0,
    )
    vdd_params = dict(
        nwire=num_vdd_tot,
        width=1,
        space_sig=0,
    )
    hm_layer = vm_layer + 1
    vss_hm_list = []
    vdd_hm_list = []
    inst_info_list = []
    vss_y_prev = vdd_y_prev = None
    params = dict(
        bot_layer=vm_layer,
        bias_config=bias_config,
    )
    for idx, (code, num, y0) in enumerate(hm_bias_info_list):
        if code == 0:
            params['bot_params'] = vss_params
            if vss_y_prev is not None and y0 > vss_y_prev:
                sup_warrs = list(vss_intvs.overlap_values((vss_y_prev, y0)))
                tmp = BiasShield.draw_bias_shields(template,
                                                   vm_layer,
                                                   bias_config,
                                                   num_vss_tot,
                                                   vss_xl,
                                                   vss_y_prev,
                                                   y0,
                                                   sup_warrs=sup_warrs)
                vss_hm_list.extend(tmp[0])
        else:
            params['bot_params'] = vdd_params
            if vdd_y_prev is not None and y0 > vdd_y_prev:
                sup_warrs = list(vdd_intvs.overlap_values((vdd_y_prev, y0)))
                tmp = BiasShield.draw_bias_shields(template,
                                                   vm_layer,
                                                   bias_config,
                                                   num_vdd_tot,
                                                   vdd_xl,
                                                   vdd_y_prev,
                                                   y0,
                                                   sup_warrs=sup_warrs)
                vdd_hm_list.extend(tmp[0])
            if vss_y_prev is not None and y0 > vss_y_prev:
                sup_warrs = list(vss_intvs.overlap_values((vss_y_prev, y0)))
                tmp = BiasShield.draw_bias_shields(template,
                                                   vm_layer,
                                                   bias_config,
                                                   num_vss_tot,
                                                   vss_xl,
                                                   vss_y_prev,
                                                   y0,
                                                   sup_warrs=sup_warrs)
                vss_hm_list.extend(tmp[0])

        params['top_params'] = dict(
            nwire=num,
            width=1,
            space_sig=0,
        )
        if idx == 0:
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldJoin)
            if code == 1:
                inst_info_list.append((1, master, vdd_xl, y0))
                BiasShield.draw_bias_shields(template, hm_layer, bias_config,
                                             num, y0, vdd_xr, xr)
                vdd_y_prev = y0 + master.array_box.top_unit
            else:
                inst_info_list.append((0, master, vss_xl, y0))
                BiasShield.draw_bias_shields(template, hm_layer, bias_config,
                                             num, y0, vss_xr, xr)
                vss_y_prev = y0 + master.array_box.top_unit
        elif code == 1:
            params['bot_open'] = True
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldJoin)
            inst_info_list.append((1, master, vdd_xl, y0))
            BiasShield.draw_bias_shields(template,
                                         hm_layer,
                                         bias_config,
                                         num,
                                         y0,
                                         vdd_xr,
                                         vss_xl,
                                         tb_mode=1)
            vdd_y_prev = y0 + master.array_box.top_unit
            params['draw_top'] = False
            params['bot_params'] = vss_params
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldCrossing)
            inst_info_list.append((0, master, vss_xl, y0))
            BiasShield.draw_bias_shields(template, hm_layer, bias_config, num,
                                         y0, vss_xr, xr)
            vss_y_prev = y0 + master.array_box.top_unit
        else:
            params['bot_open'] = True
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldJoin)
            inst_info_list.append((0, master, vss_xl, y0))
            BiasShield.draw_bias_shields(template, hm_layer, bias_config, num,
                                         y0, vss_xr, xr)
            vss_y_prev = y0 + master.array_box.top_unit

    if yt is None:
        yt = max(vss_y_prev, vdd_y_prev)
    if vss_y_prev < yt:
        sup_warrs = list(vss_intvs.overlap_values((vss_y_prev, yt)))
        tmp = BiasShield.draw_bias_shields(template,
                                           vm_layer,
                                           bias_config,
                                           num_vss_tot,
                                           vss_xl,
                                           vss_y_prev,
                                           yt,
                                           sup_warrs=sup_warrs)
        vss_hm_list.extend(tmp[0])
    if vdd_y_prev < yt:
        sup_warrs = list(vdd_intvs.overlap_values((vdd_y_prev, yt)))
        tmp = BiasShield.draw_bias_shields(template,
                                           vm_layer,
                                           bias_config,
                                           num_vdd_tot,
                                           vdd_xl,
                                           vdd_y_prev,
                                           yt,
                                           sup_warrs=sup_warrs)
        vdd_hm_list.extend(tmp[0])

    sup_layer = hm_layer + 1
    vss_list = []
    vdd_list = []
    for code, master, x0, y0 in inst_info_list:
        inst = _add_inst_r180(template, master, x0, y0)
        if code == 1:
            vdd_list.extend(inst.port_pins_iter('sup', layer=sup_layer))
        else:
            vss_list.extend(inst.port_pins_iter('sup', layer=sup_layer))

    vdd_list = template.connect_wires(vdd_list, upper=yt, unit_mode=True)
    vss_list = template.connect_wires(vss_list, upper=yt, unit_mode=True)
    template.draw_vias_on_intersections(vdd_hm_list, vdd_list)
    template.draw_vias_on_intersections(vss_hm_list, vss_list)

    # connect pins
    vss_tidx_list = BiasShield.get_route_tids(grid, vm_layer, vss_xl,
                                              bias_config, num_vss_tot)
    vdd_tidx_list = BiasShield.get_route_tids(grid, vm_layer, vdd_xl,
                                              bias_config, num_vdd_tot)
    pin_map = {}
    vss_tr_warrs = []
    vdd_tr_warrs = []
    for pins, tidx_list, result_list in ((vss_pins, vss_tidx_list,
                                          vss_tr_warrs),
                                         (vdd_pins, vdd_tidx_list,
                                          vdd_tr_warrs)):
        next_idx = 0
        for name, warr in pins:
            if name in pin_map:
                cur_idx = pin_map[name]
                add_pin = False
            else:
                cur_idx = pin_map[name] = next_idx
                next_idx += 1
                add_pin = True
            tidx, tr_w = tidx_list[cur_idx + 1]
            tid = TrackID(vm_layer, tidx, width=tr_w)
            warr = template.connect_to_tracks(warr,
                                              tid,
                                              track_upper=yt,
                                              unit_mode=True)
            if add_pin:
                result_list.append((name, warr))

        pin_map.clear()

    return vdd_tr_warrs, vss_tr_warrs, vdd_list, vss_list
Beispiel #8
0
 def __init__(self):
     super(LaygoIntvSet, self).__init__()
     self._intv = IntervalSet()
     self._end_flags = {}