コード例 #1
0
    def draw_layout(self):
        # type: () -> None

        top_layer = self.params['top_layer']
        bound_box = self.params['bound_box']
        w = self.params['w']
        fg_side = self.params['fg_side']
        threshold = self.params['threshold']
        show_pins = self.params['show_pins']
        dnw_mode = self.params['dnw_mode']

        # test top_layer
        hm_layer = self._tech_cls.get_mos_conn_layer() + 1
        if top_layer <= hm_layer:
            raise ValueError('top layer for DeepNWellRing must be >= %d' %
                             (hm_layer + 1))

        # make masters
        dnw_params = dict(
            top_layer=top_layer,
            bound_box=bound_box,
            sub_type='ntap',
            w=w,
            fg_side=fg_side,
            threshold=threshold,
            show_pins=False,
            dnw_mode='compact',
        )
        dnw_master = self.new_template(params=dnw_params,
                                       temp_cls=SubstrateRing)
        dnw_blk_loc = dnw_master.blk_loc_unit

        sub_params = dict(
            top_layer=top_layer,
            bound_box=dnw_master.bound_box,
            sub_type='ptap',
            w=w,
            fg_side=fg_side,
            threshold=threshold,
            show_pins=False,
        )
        sub_master = self.new_template(params=sub_params,
                                       temp_cls=SubstrateRing)
        sub_blk_loc = sub_master.blk_loc_unit

        # put masters at (0, 0)
        sub_inst = self.add_instance(sub_master, 'XSUB')
        dnw_inst = self.add_instance(dnw_master,
                                     'XDNW',
                                     loc=sub_blk_loc,
                                     unit_mode=True)

        # check how much to move substrate rings by to achive the DNW margin.
        x_pitch, y_pitch = self.grid.get_block_size(top_layer, unit_mode=True)
        dnw_margin = self.grid.tech_info.get_dnw_margin_unit(dnw_mode)
        dnw_box = BBox.get_invalid_bbox()
        for dnw_lay in self.grid.tech_info.get_dnw_layers():
            dnw_box = dnw_box.merge(dnw_inst.get_rect_bbox(dnw_lay))

        dx = -(-max(0, dnw_margin - dnw_box.left_unit) // x_pitch) * x_pitch
        dy = -(-max(0, dnw_margin - dnw_box.bottom_unit) // x_pitch) * x_pitch
        self.move_all_by(dx=dx, dy=dy, unit_mode=True)

        # set size
        res = self.grid.resolution
        sub_w = sub_master.bound_box.width_unit
        sub_h = sub_master.bound_box.height_unit
        bnd_box = BBox(0,
                       0,
                       sub_w + 2 * dx,
                       sub_h + 2 * dy,
                       res,
                       unit_mode=True)
        self.set_size_from_bound_box(top_layer, bnd_box)
        self.array_box = bnd_box

        # record block location
        dnw_loc = dnw_inst.location_unit
        self._blk_loc = dnw_loc[0] + dnw_blk_loc[0], dnw_loc[1] + dnw_blk_loc[1]

        # export supplies
        self.reexport(sub_inst.get_port('VSS'), show=show_pins)
        self.reexport(dnw_inst.get_port('VDD'), show=show_pins)
コード例 #2
0
    def draw_layout(self):
        # type: () -> None
        nin0 = self.params['nin0']
        nin1 = self.params['nin1']
        res_params = self.params['res_params']
        mux_params = self.params['mux_params']
        fill_config = self.params['fill_config']
        nout = self.params['nout']
        top_layer = self.params['top_layer']
        fill_orient_mode = self.params['fill_orient_mode']
        show_pins = self.params['show_pins']

        if nout <= 0:
            raise ValueError('nout must be positive.')

        res = self.grid.resolution
        num_mux_left = nout // 2
        num_mux_right = nout - num_mux_left
        num_col = 2**nin0
        num_row = 2**nin1
        nbits_tot = nin0 + nin1

        # make masters
        r_params = res_params.copy()
        r_params['nx'] = num_col
        r_params['ny'] = num_row
        r_params['show_pins'] = False
        res_master = self.new_template(params=r_params, temp_cls=ResLadderTop)
        sup_layer = res_master.top_layer + 1
        if top_layer is None:
            top_layer = res_master.top_layer + 1
        elif top_layer < sup_layer:
            raise ValueError('top_layer must be >= %d' % sup_layer)

        m_params = mux_params.copy()
        m_params['col_nbits'] = nin0
        m_params['row_nbits'] = nin1
        m_params['top_layer'] = res_master.top_layer
        m_params['show_pins'] = False
        if num_mux_left > 0:
            m_params['num_mux'] = num_mux_left
            lmux_master = self.new_template(params=m_params,
                                            temp_cls=RLadderMuxArray)
        else:
            lmux_master = None

        m_params['num_mux'] = num_mux_right
        rmux_master = self.new_template(params=m_params,
                                        temp_cls=RLadderMuxArray)

        # figure out Y coordinates
        mux_warr = rmux_master.get_port('in<1>').get_pins()[0]
        pin_layer = mux_warr.layer_id
        tr_pitch = self.grid.get_track_pitch(pin_layer, unit_mode=True)
        mux_tr = mux_warr.track_id.base_index
        res_tr = res_master.get_port(
            'out<1>').get_pins()[0].track_id.base_index
        res_yo = int(round(max(mux_tr - res_tr, 0))) * tr_pitch
        mux_yo = int(round(max(res_tr - mux_tr, 0))) * tr_pitch

        # place left mux
        sup_table = {'VDD': [], 'VSS': []}
        if lmux_master is not None:
            blk_w, blk_h = self.grid.get_size_dimension(lmux_master.size,
                                                        unit_mode=True)
            lmux_inst = self.add_instance(lmux_master,
                                          loc=(blk_w, mux_yo),
                                          orient='MY',
                                          unit_mode=True)

            # gather supply and re-export inputs
            for port_name, port_list in sup_table.items():
                port_list.extend(lmux_inst.port_pins_iter(port_name))
            for mux_idx in range(num_mux_left):
                self.reexport(lmux_inst.get_port('out<%d>' % mux_idx),
                              show=show_pins)
                for bit_idx in range(nbits_tot):
                    self.reexport(lmux_inst.get_port(
                        'code<%d>' % (bit_idx + mux_idx * nbits_tot)),
                                  show=show_pins)

            vref_left = int(
                round(lmux_inst.get_port('in<1>').get_pins()[0].lower / res))
            xo = blk_w
            self.array_box = lmux_inst.array_box
        else:
            xo = 0
            vref_left = -1
            self.array_box = BBox.get_invalid_bbox()

        # place resistor ladder
        res_inst = self.add_instance(res_master,
                                     loc=(xo, res_yo),
                                     unit_mode=True)
        for port_name, port_list in sup_table.items():
            port_list.extend(res_inst.port_pins_iter(port_name))
        if vref_left < 0:
            vref_left = int(
                round(res_inst.get_port('out<1>').get_pins()[0].lower / res))

        res_w, res_h = self.grid.get_size_dimension(res_master.size,
                                                    unit_mode=True)
        xo += res_w
        # place right mux
        rmux_inst = self.add_instance(rmux_master,
                                      loc=(xo, mux_yo),
                                      unit_mode=True)
        rmux_w, rmux_h = self.grid.get_size_dimension(rmux_master.size,
                                                      unit_mode=True)
        xo += rmux_w
        out_off = num_mux_left
        in_off = num_mux_left * nbits_tot
        for port_name, port_list in sup_table.items():
            port_list.extend(rmux_inst.port_pins_iter(port_name))
        for mux_idx in range(num_mux_right):
            old_name = 'out<%d>' % mux_idx
            new_name = 'out' if nout == 1 else 'out<%d>' % (mux_idx + out_off)
            self.reexport(rmux_inst.get_port(old_name),
                          net_name=new_name,
                          show=show_pins)
            for bit_idx in range(nbits_tot):
                old_name = 'code<%d>' % (bit_idx + mux_idx * nbits_tot)
                new_name = 'code<%d>' % (bit_idx + mux_idx * nbits_tot +
                                         in_off)
                self.reexport(rmux_inst.get_port(old_name),
                              net_name=new_name,
                              show=show_pins)
        vref_right = int(
            round(rmux_inst.get_port('in<1>').get_pins()[0].upper / res))

        for vref_idx in range(2**nbits_tot):
            vref_warr = rmux_inst.get_port('in<%d>' % vref_idx).get_pins()[0]
            vref_tr = vref_warr.track_id.base_index
            vref_layer = vref_warr.track_id.layer_id
            self.add_wires(vref_layer,
                           vref_tr,
                           vref_left,
                           vref_right,
                           unit_mode=True)

        # set size
        yo = max(mux_yo + rmux_h, res_yo + res_h)
        blk_w, blk_h = self.grid.get_fill_size(top_layer,
                                               fill_config,
                                               unit_mode=True)
        nfill_x = -(-xo // blk_w)  # type: int
        nfill_y = -(-yo // blk_h)
        bnd_box = BBox(0,
                       0,
                       nfill_x * blk_w,
                       nfill_y * blk_h,
                       res,
                       unit_mode=True)
        self.set_size_from_bound_box(top_layer, bnd_box)
        self.array_box = bnd_box
        self.add_cell_boundary(bnd_box)

        # connect supplies
        vdd_list = sup_table['VDD']
        vss_list = sup_table['VSS']
        flip_fill = (fill_orient_mode & 2 != 0)
        fill_width, fill_space, space, space_le = fill_config[sup_layer]
        vdd_list, vss_list = self.do_power_fill(sup_layer,
                                                space,
                                                space_le,
                                                vdd_warrs=vdd_list,
                                                vss_warrs=vss_list,
                                                fill_width=fill_width,
                                                fill_space=fill_space,
                                                flip=flip_fill,
                                                unit_mode=True)
        # add fill cells
        if top_layer > sup_layer:
            fill_params = dict(
                fill_config=fill_config,
                bot_layer=sup_layer,
                top_layer=top_layer,
                show_pins=False,
            )
            orient = PowerFill.get_fill_orient(fill_orient_mode)
            x0 = 0 if (fill_orient_mode & 1 == 0) else 1
            y0 = 0 if (fill_orient_mode & 2 == 0) else 1
            loc = (x0 * blk_w, y0 * blk_h)
            fill_master = self.new_template(params=fill_params,
                                            temp_cls=PowerFill)
            fill_inst = self.add_instance(fill_master,
                                          'XFILL',
                                          loc=loc,
                                          orient=orient,
                                          nx=nfill_x,
                                          ny=nfill_y,
                                          spx=blk_w,
                                          spy=blk_h,
                                          unit_mode=True)
            vdd_list = fill_inst.get_all_port_pins('VDD')
            vss_list = fill_inst.get_all_port_pins('VSS')

        self.add_pin('VDD', self.connect_wires(vdd_list), show=show_pins)
        self.add_pin('VSS', self.connect_wires(vss_list), show=show_pins)

        res_sch_params = res_master.sch_params.copy()
        mux_sch_params = rmux_master.mux_params.copy()
        del res_sch_params['nout']
        del mux_sch_params['nin0']
        del mux_sch_params['nin1']
        self._sch_params = dict(
            nin0=nin0,
            nin1=nin1,
            nout=nout,
            res_params=res_sch_params,
            mux_params=mux_sch_params,
        )
コード例 #3
0
    def draw_layout(self):
        # type: () -> None

        top_layer = self.params['top_layer']
        lch = self.params['lch']
        w = self.params['w']
        sub_type = self.params['sub_type']
        threshold = self.params['threshold']
        port_width = self.params['port_width']
        well_width = self.params['well_width']
        end_mode = self.params['end_mode']
        is_passive = self.params['is_passive']
        max_nxblk = self.params['max_nxblk']
        port_tid = self.params['port_tid']
        show_pins = self.params['show_pins']

        half_blk_y = self.params['half_blk_y']
        half_blk_x = self.params['half_blk_x']

        res = self.grid.resolution
        well_width = int(round(well_width / res))
        right_end = (end_mode & 8) != 0
        left_end = (end_mode & 4) != 0
        top_end = (end_mode & 2) != 0
        bot_end = (end_mode & 1) != 0

        # get layout info, also set RoutingGrid to substrate grid.
        layout_info = AnalogBaseInfo(self.grid,
                                     lch,
                                     0,
                                     top_layer=top_layer,
                                     end_mode=end_mode,
                                     half_blk_y=half_blk_y,
                                     half_blk_x=half_blk_x)
        # compute template width in number of sd pitches
        # find maximum number of fingers we can draw
        bin_iter = BinaryIterator(1, None)
        while bin_iter.has_next():
            cur_fg = bin_iter.get_next()
            cur_pinfo = layout_info.get_placement_info(cur_fg)
            cur_core_width = cur_pinfo.core_width
            if cur_core_width == well_width:
                bin_iter.save_info(cur_pinfo)
                break
            elif cur_core_width < well_width:
                bin_iter.save_info(cur_pinfo)
                bin_iter.up()
            else:
                bin_iter.down()

        sub_fg_tot = bin_iter.get_last_save()
        if sub_fg_tot is None:
            raise ValueError('Cannot draw substrate that fit in width: %d' %
                             well_width)

        # check width parity requirement
        if max_nxblk > 0:
            blkw = self.grid.get_block_size(top_layer, unit_mode=True)[0]
            place_info = bin_iter.get_last_save_info()
            cur_nxblk = place_info.tot_width // blkw
            while sub_fg_tot > 0 and (cur_nxblk > max_nxblk or
                                      (max_nxblk - cur_nxblk) % 2 != 0):
                sub_fg_tot -= 1
                place_info = layout_info.get_placement_info(sub_fg_tot)
                cur_nxblk = place_info.tot_width // blkw
            if sub_fg_tot <= 0:
                raise ValueError('Cannot draw substrate with width = %d, '
                                 'max_nxblk = %d' % (well_width, max_nxblk))

        layout_info.set_fg_tot(sub_fg_tot)
        self.grid = layout_info.grid

        place_info = layout_info.get_placement_info(sub_fg_tot)
        edgel_x0 = place_info.edge_margins[0]
        tot_width = place_info.tot_width

        # create masters
        master_list = [
            self.new_template(params=dict(
                lch=lch,
                fg=sub_fg_tot,
                sub_type=sub_type,
                threshold=threshold,
                is_end=bot_end,
                top_layer=top_layer,
            ),
                              temp_cls=AnalogEndRow),
            self.new_template(params=dict(
                lch=lch,
                w=w,
                sub_type=sub_type,
                threshold=threshold,
                fg=sub_fg_tot,
                top_layer=top_layer,
                options=dict(is_passive=is_passive),
            ),
                              temp_cls=AnalogSubstrate),
            self.new_template(params=dict(
                lch=lch,
                fg=sub_fg_tot,
                sub_type=sub_type,
                threshold=threshold,
                is_end=top_end,
                top_layer=top_layer,
            ),
                              temp_cls=AnalogEndRow),
        ]

        ycur = 0
        array_box = BBox.get_invalid_bbox()
        sub_conn, inst = None, None
        for master, orient in zip(master_list, ['R0', 'R0', 'MX']):
            if orient == 'MX':
                ycur += master.array_box.top_unit

            name_id = master.get_layout_basename()
            edge_layout_info = master.get_edge_layout_info()
            xcur = edgel_x0
            if left_end:
                edge_info = master.get_left_edge_info()
                edge_params = dict(
                    is_end=True,
                    guard_ring_nf=0,
                    name_id=name_id,
                    layout_info=edge_layout_info,
                    adj_blk_info=edge_info,
                )
                edge_master = self.new_template(params=edge_params,
                                                temp_cls=AnalogEdge)
                if not edge_master.is_empty:
                    edge_inst = self.add_instance(edge_master,
                                                  loc=(edgel_x0, ycur),
                                                  orient=orient,
                                                  unit_mode=True)
                    array_box = array_box.merge(edge_inst.array_box)
                    xcur = edge_inst.array_box.right_unit

            inst = self.add_instance(master,
                                     loc=(xcur, ycur),
                                     orient=orient,
                                     unit_mode=True)
            array_box = array_box.merge(inst.array_box)
            if isinstance(master, AnalogSubstrate):
                conn_params = dict(
                    layout_info=edge_layout_info,
                    layout_name=name_id + '_subconn',
                    is_laygo=False,
                )
                conn_master = self.new_template(params=conn_params,
                                                temp_cls=AnalogSubstrateConn)
                sub_conn = self.add_instance(conn_master,
                                             loc=(xcur, ycur),
                                             orient=orient,
                                             unit_mode=True)
            xcur = inst.array_box.right_unit

            if right_end:
                edge_info = master.get_right_edge_info()
                edge_params = dict(
                    is_end=True,
                    guard_ring_nf=0,
                    name_id=name_id,
                    layout_info=edge_layout_info,
                    adj_blk_info=edge_info,
                )
                edge_master = self.new_template(params=edge_params,
                                                temp_cls=AnalogEdge)
                if not edge_master.is_empty:
                    xcur += edge_master.array_box.right_unit
                    eor = 'MY' if orient == 'R0' else 'R180'
                    edge_inst = self.add_instance(edge_master,
                                                  loc=(xcur, ycur),
                                                  orient=eor,
                                                  unit_mode=True)
                    array_box = array_box.merge(edge_inst.array_box)

            if orient == 'R0':
                ycur += master.array_box.top_unit

        # calculate substrate Y coordinates
        imp_yb, thres_yb = master_list[0].sub_ysep
        imp_yt, thres_yt = master_list[2].sub_ysep
        self._sub_bndy = (imp_yb, ycur - imp_yt), (thres_yb, ycur - thres_yt)

        # get left/right substrate coordinates
        tot_imp_box = BBox.get_invalid_bbox()
        for lay in self.grid.tech_info.get_implant_layers('ptap'):
            tot_imp_box = tot_imp_box.merge(self.get_rect_bbox(lay))
        for lay in self.grid.tech_info.get_implant_layers('ntap'):
            tot_imp_box = tot_imp_box.merge(self.get_rect_bbox(lay))

        if not tot_imp_box.is_physical():
            self._sub_bndx = None, None
        else:
            self._sub_bndx = tot_imp_box.left_unit, tot_imp_box.right_unit

        # set array box and size
        self.array_box = array_box
        bound_box = BBox(0,
                         0,
                         tot_width,
                         inst.bound_box.top_unit,
                         res,
                         unit_mode=True)
        if self.grid.size_defined(top_layer):
            self.set_size_from_bound_box(top_layer, bound_box)
        else:
            self.prim_bound_box = bound_box
            self.prim_top_layer = top_layer

        hm_layer = layout_info.mconn_port_layer + 1
        if port_tid is None:
            # find center track index
            hm_mid = self.grid.coord_to_nearest_track(hm_layer,
                                                      self.array_box.yc_unit,
                                                      mode=0,
                                                      half_track=True,
                                                      unit_mode=True)
            # connect to horizontal metal layer.
            hm_pitch = self.grid.get_track_pitch(hm_layer, unit_mode=True)
            ntr = self.array_box.height_unit // hm_pitch  # type: int
            if port_width is None:
                port_width = self.grid.get_max_track_width(
                    hm_layer, 1, ntr, half_end_space=False)
            port_tid = TrackID(hm_layer, hm_mid, width=port_width)
        else:
            port_tid = TrackID(hm_layer, port_tid[0], width=port_tid[1])

        port_name = 'VDD' if sub_type == 'ntap' else 'VSS'
        sub_wires = self.connect_to_tracks(
            sub_conn.get_port(port_name).get_pins(hm_layer - 1), port_tid)
        self.add_pin(port_name, sub_wires, show=show_pins)

        self._fg_tot = sub_fg_tot
コード例 #4
0
ファイル: fill.py プロジェクト: xyabc/BAG_framework
 def get_track_bbox(self, layer_id):
     # type: (int) -> BBox
     if layer_id not in self._idx_table:
         return BBox.get_invalid_bbox()
     return self._idx_table[layer_id].bound_box
コード例 #5
0
    def _draw_layout_helper(
            self,  # type: ResLadderDAC
            l,  # type: float
            w,  # type: float
            sub_lch,  # type: float
            sub_w,  # type: Union[float, int]
            sub_type,  # type: str
            threshold,  # type: str
            ndum,  # type: int
            res_type,  # type: str
            num_out,  # type: int
            col_nbits,  # type: int
            row_nbits,  # type: int
            config_file,  # type: str
            **kwargs):
        # type: (...) -> None
        if num_out <= 0:
            raise ValueError('num_out must be positive.')

        res = self.grid.resolution
        num_mux_left = num_out // 2
        num_mux_right = num_out - num_mux_left
        num_col = 2**col_nbits
        num_row = 2**row_nbits
        nbits_tot = col_nbits + row_nbits

        # make masters
        mux_params = dict(col_nbits=col_nbits,
                          row_nbits=row_nbits,
                          config_file=config_file)
        if num_mux_left > 0:
            mux_params['num_mux'] = num_mux_left
            lmux_master = self.new_template(params=mux_params,
                                            temp_cls=RLadderMuxArray)
        else:
            lmux_master = None

        mux_params['num_mux'] = num_mux_right
        rmux_master = self.new_template(params=mux_params,
                                        temp_cls=RLadderMuxArray)

        res_params = dict(l=l,
                          w=w,
                          sub_lch=sub_lch,
                          sub_w=sub_w,
                          sub_type=sub_type,
                          threshold=threshold,
                          nx=num_col,
                          ny=num_row,
                          ndum=ndum,
                          res_type=res_type)
        res_master = self.new_template(params=res_params, temp_cls=ResLadder)

        # figure out Y coordinates
        mux_warr = rmux_master.get_port('in<1>').get_pins()[0]
        pin_layer = mux_warr.layer_id
        tr_pitch = self.grid.get_track_pitch(pin_layer, unit_mode=True)
        mux_tr = mux_warr.track_id.base_index
        res_tr = res_master.get_port(
            'out<1>').get_pins()[0].track_id.base_index
        res_yo = int(round(max(mux_tr - res_tr, 0))) * tr_pitch
        mux_yo = int(round(max(res_tr - mux_tr, 0))) * tr_pitch

        # place left mux
        sup_table = {'VDD': [], 'VSS': []}
        if lmux_master is not None:
            blk_w, blk_h = self.grid.get_size_dimension(lmux_master.size,
                                                        unit_mode=True)
            lmux_inst = self.add_instance(lmux_master,
                                          loc=(blk_w, mux_yo),
                                          orient='MY',
                                          unit_mode=True)

            # gather supply and re-export inputs
            for port_name, port_list in sup_table.items():
                port_list.extend(lmux_inst.get_all_port_pins(port_name))
            for mux_idx in range(num_mux_left):
                self.reexport(lmux_inst.get_port('out<%d>' % mux_idx),
                              show=True)
                for bit_idx in range(nbits_tot):
                    self.reexport(lmux_inst.get_port(
                        'code<%d>' % (bit_idx + mux_idx * nbits_tot)),
                                  show=True)

            vref_left = int(
                round(lmux_inst.get_port('in<1>').get_pins()[0].lower / res))
            xo = blk_w
            self.array_box = lmux_inst.array_box
        else:
            xo = 0
            vref_left = -1
            self.array_box = BBox.get_invalid_bbox()

        # place resistor ladder
        res_inst = self.add_instance(res_master,
                                     loc=(xo, res_yo),
                                     unit_mode=True)
        for port_name, port_list in sup_table.items():
            port_list.extend(res_inst.get_all_port_pins(port_name))
        if vref_left < 0:
            vref_left = int(
                round(res_inst.get_port('out<1>').get_pins()[0].lower / res))

        res_w, res_h = self.grid.get_size_dimension(res_master.size,
                                                    unit_mode=True)
        xo += res_w
        # place right mux
        rmux_inst = self.add_instance(rmux_master,
                                      loc=(xo, mux_yo),
                                      unit_mode=True)
        rmux_w, rmux_h = self.grid.get_size_dimension(rmux_master.size,
                                                      unit_mode=True)
        xo += rmux_w
        out_off = num_mux_left
        in_off = num_mux_left * nbits_tot
        for port_name, port_list in sup_table.items():
            port_list.extend(rmux_inst.get_all_port_pins(port_name))
        for mux_idx in range(num_mux_right):
            old_name = 'out<%d>' % mux_idx
            new_name = 'out' if num_out == 1 else 'out<%d>' % (mux_idx +
                                                               out_off)
            self.reexport(rmux_inst.get_port(old_name),
                          net_name=new_name,
                          show=True)
            for bit_idx in range(nbits_tot):
                old_name = 'code<%d>' % (bit_idx + mux_idx * nbits_tot)
                new_name = 'code<%d>' % (bit_idx + mux_idx * nbits_tot +
                                         in_off)
                self.reexport(rmux_inst.get_port(old_name),
                              net_name=new_name,
                              show=True)
        vref_right = int(
            round(rmux_inst.get_port('in<1>').get_pins()[0].upper / res))

        for vref_idx in range(2**nbits_tot):
            vref_warr = rmux_inst.get_port('in<%d>' % vref_idx).get_pins()[0]
            vref_tr = vref_warr.track_id.base_index
            vref_layer = vref_warr.track_id.layer_id
            self.add_wires(vref_layer,
                           vref_tr,
                           vref_left,
                           vref_right,
                           unit_mode=True)

        # set size
        yo = max(mux_yo + rmux_h, res_yo + res_h)
        top_layer = sup_table['VDD'][0].layer_id + 1
        self.size = self.grid.get_size_tuple(top_layer,
                                             xo,
                                             yo,
                                             round_up=True,
                                             unit_mode=True)
        self.array_box = self.bound_box

        # do power fill
        sup_width = 2
        vdd_list, vss_list = self.do_power_fill(top_layer,
                                                sup_table['VDD'],
                                                sup_table['VSS'],
                                                sup_width=sup_width,
                                                fill_margin=0.5,
                                                edge_margin=0.2)
        self.add_pin('VDD', vdd_list)
        self.add_pin('VSS', vss_list)
コード例 #6
0
    def draw_res_boundary(self, template, boundary_type, layout_info,
                          end_mode):
        # type: (TemplateBase, str, Dict[str, Any], bool) -> None

        mos_layer_table = self.config['mos_layer_table']
        res_layer_table = self.config['res_layer_table']
        metal_exclude_table = self.config['metal_exclude_table']
        layer_table = self.config['layer_name']
        res_info = self.res_config['info']
        imp_ency = self.res_config['imp_enc'][1]
        rpo_extx = self.res_config['rpo_extx']

        grid = template.grid
        res = grid.resolution

        w = layout_info['w']
        l = layout_info['l']
        res_type = layout_info['res_type']
        sub_type = layout_info['sub_type']
        threshold = layout_info['threshold']
        w_core = layout_info['w_core']
        h_core = layout_info['h_core']
        w_edge = layout_info['w_edge']
        h_edge = layout_info['h_edge']

        res_info = res_info[res_type]
        need_rpo = res_info['need_rpo']
        od_in_res = res_info['od_in_res']

        wres, lres, wres_lr, lres_tb = self.get_res_dimension(l, w)
        implant_layers = self.get_res_imp_layers(res_type, sub_type, threshold)
        bnd_spx = (w_core - wres) // 2
        bnd_spy = (h_core - lres) // 2

        core_info = layout_info['core_info']
        edge_lr_info = layout_info['edge_lr_info']
        edge_tb_info = layout_info['edge_tb_info']

        well_xl = edge_lr_info['well_xl']
        well_yb = edge_tb_info['well_yb']

        core_lr_od_xloc = core_info['lr_od_xloc']
        core_top_od_yloc = core_info['top_od_yloc']
        core_bot_od_yloc = core_info['bot_od_yloc']

        #  get bounding box/implant coordinates, draw RPDMY/RPO, and draw dummies.
        po_xl = po_xr = po_yb = po_yt = None
        if boundary_type == 'lr':
            # set implant Y coordinates to 0
            well_yb = 0
            # get bounding box and PO coordinates
            bnd_box = BBox(0, 0, w_edge, h_core, res, unit_mode=True)
            if wres_lr > 0:
                po_xr = w_edge - bnd_spx
                po_xl = po_xr - wres_lr
                po_yb, po_yt = bnd_spy, bnd_spy + lres
                # draw bottom/top edge dummies
                po_x_list = [(po_xl, po_xr)]
                self._draw_dummies(template, po_x_list, core_bot_od_yloc)
                self._draw_dummies(template, po_x_list, core_top_od_yloc)
            if need_rpo:
                # draw RPO in left/right edge block
                rpo_yb = h_core // 2 - l // 2
                rpo_yt = rpo_yb + l
                rpo_name = res_layer_table['RPO']
                rpo_xl = w_edge + bnd_spx - rpo_extx
                rpo_box = BBox(rpo_xl,
                               rpo_yb,
                               w_edge,
                               rpo_yt,
                               res,
                               unit_mode=True)
                if rpo_box.is_physical():
                    template.add_rect(rpo_name, rpo_box)
            m1_x_list = edge_lr_info['m1_edge_x']
            m1_y_list = core_info['m1_core_y']
        elif boundary_type == 'tb':
            # set implant X coordinates to 0
            well_xl = 0
            # get bounding box and PO coordinates
            bnd_box = BBox(0, 0, w_core, h_edge, res, unit_mode=True)
            if lres_tb > 0:
                po_yt = h_edge - bnd_spy
                po_yb = po_yt - lres_tb
                po_xl, po_xr = bnd_spx, bnd_spx + wres
                # draw bottom edge dummies
                po_y_list = [(po_yb, po_yt)]
                self._draw_dummies(template, core_lr_od_xloc, po_y_list)
                self._draw_dummies(template,
                                   core_lr_od_xloc,
                                   po_y_list,
                                   dx=w_core)
            m1_x_list = core_info['m1_core_x']
            m1_y_list = edge_tb_info['m1_edge_y']
        else:
            # get bounding box and PO coordinates
            bnd_box = BBox(0, 0, w_edge, h_edge, res, unit_mode=True)
            if wres_lr > 0 and lres_tb > 0:
                po_xr = w_edge - bnd_spx
                po_xl = po_xr - wres_lr
                po_yt = h_edge - bnd_spy
                po_yb = po_yt - lres_tb
            m1_x_list = edge_lr_info['m1_edge_x']
            m1_y_list = edge_tb_info['m1_edge_y']

        # draw DPO
        if wres_lr > 0 and lres_tb > 0:
            dpo_name = mos_layer_table['PO_dummy']
            template.add_rect(
                dpo_name, BBox(po_xl, po_yb, po_xr, po_yt, res,
                               unit_mode=True))

        # draw implant layers
        if not od_in_res:
            if boundary_type == 'lr':
                po_yb, po_yt = bnd_spy, bnd_spy + lres
                imp_box = BBox(well_xl,
                               po_yb - imp_ency,
                               bnd_box.right_unit,
                               po_yt + imp_ency,
                               res,
                               unit_mode=True)
            else:
                imp_box = BBox.get_invalid_bbox()
        else:
            imp_box = BBox(well_xl,
                           well_yb,
                           bnd_box.right_unit,
                           bnd_box.top_unit,
                           res,
                           unit_mode=True)

        if imp_box.is_physical():
            for lay in implant_layers:
                template.add_rect(lay, imp_box)

        # set bounding box
        template.prim_bound_box = bnd_box
        template.array_box = bnd_box

        # draw M1 exclusion layer
        m1_exc_layer = metal_exclude_table[1]
        template.add_rect(m1_exc_layer, bnd_box)

        # draw M1 fill
        m1_lay = layer_table[1]
        for xl, xr in m1_x_list:
            for yb, yt in m1_y_list:
                template.add_rect(m1_lay,
                                  BBox(xl, yb, xr, yt, res, unit_mode=True))
コード例 #7
0
    def draw_layout(self):
        # type: () -> None
        nin0 = self.params['nin0']
        nin1 = self.params['nin1']
        name_list2 = self.params['name_list2']
        nout_list2 = self.params['nout_list2']
        num_vdd_list = self.params['num_vdd_list']
        fill_config = self.params['fill_config']
        bias_config = self.params['bias_config']
        fill_orient_mode = self.params['fill_orient_mode']
        show_pins = self.params['show_pins']

        # get number of VDD/VSS bias wires
        num_vdd_tot = num_tot = 0
        for num_vdd, nout_list in zip(num_vdd_list, nout_list2):
            num_vdd_tot += num_vdd
            num_tot += sum(nout_list)
        num_vss_tot = num_tot - num_vdd_tot

        ycur = 0
        inst_list = []
        nout_arr_list = []
        fill_info_list = []
        hm_bias_info_list = []
        params = self.params.copy()
        params['show_pins'] = False
        tot_box = BBox.get_invalid_bbox()
        top_layer = res_params = mux_params = blk_w = blk_h = None
        vm_layer = route_w = vdd_x = vss_x = None
        for row_idx, (num_vdd,
                      nout_list) in enumerate(zip(num_vdd_list, nout_list2)):
            if row_idx % 2 == 0:
                orient = 'R0'
                cur_fo_mode = fill_orient_mode
            else:
                orient = 'MX'
                cur_fo_mode = fill_orient_mode ^ 2
            params['nout_list'] = nout_list
            params['num_vdd'] = num_vdd
            params['fill_orient_mode'] = cur_fo_mode
            master = self.new_template(params=params, temp_cls=RDACRow)
            nout_arr_list.extend(master.sch_params['nout_arr_list'])
            if top_layer is None:
                top_layer = master.top_layer
                vm_layer = master.bias_layer - 1
                res_params = master.sch_params['res_params']
                mux_params = master.sch_params['mux_params']
                blk_w, blk_h = self.grid.get_fill_size(top_layer,
                                                       fill_config,
                                                       unit_mode=True)
                tmp = compute_vroute_width(self, vm_layer, blk_w, num_vdd_tot,
                                           num_vss_tot, bias_config)
                route_w, vdd_x, vss_x = tmp

            ny = master.bound_box.height_unit // blk_h
            cur_bias_info = master.bias_info
            if row_idx % 2 == 1:
                ycur += master.bound_box.height_unit
                if cur_bias_info[0] is not None:
                    num_vss, p0, dim = cur_bias_info[0]
                    hm_bias_info_list.append((0, num_vss, ycur - p0[1] - dim))
                if cur_bias_info[1] is not None:
                    num_vdd, p0, dim = cur_bias_info[1]
                    hm_bias_info_list.append((1, num_vdd, ycur - p0[1] - dim))
            else:
                if cur_bias_info[1] is not None:
                    num_vdd, p0, dim = cur_bias_info[1]
                    hm_bias_info_list.append((1, num_vdd, p0[1] + ycur))
                if cur_bias_info[0] is not None:
                    num_vss, p0, dim = cur_bias_info[0]
                    hm_bias_info_list.append((0, num_vss, p0[1] + ycur))

            inst = self.add_instance(master,
                                     'X%d' % row_idx,
                                     loc=(route_w, ycur),
                                     orient=orient,
                                     unit_mode=True)

            inst_box = inst.bound_box
            fill_info_list.append((inst_box.right_unit, ycur, ny, cur_fo_mode))
            tot_box = tot_box.merge(inst_box)
            ycur = tot_box.top_unit
            inst_list.append(inst)

        self.array_box = tot_box = tot_box.extend(x=0, unit_mode=True)
        self.set_size_from_bound_box(top_layer, tot_box)
        self.add_cell_boundary(tot_box)
        xr_tot = tot_box.right_unit

        nin = nin0 + nin1
        io_name_list = []
        vdd_pins = []
        vss_pins = []
        vdd_names = []
        vss_names = []
        params = dict(fill_config=fill_config,
                      bot_layer=top_layer - 1,
                      show_pins=False)
        fill_master = self.new_template(params=params, temp_cls=PowerFill)
        for inst, (xr, yf, ny, fo_mode), name_list, num_vdd in zip(
                inst_list, fill_info_list, name_list2, num_vdd_list):
            # add fill if needed
            dx = xr_tot - xr
            if dx > 0:
                nx = dx // blk_w
                orient = PowerFill.get_fill_orient(fill_orient_mode)
                x0 = 0 if (fill_orient_mode & 1 == 0) else 1
                y0 = 0 if (fill_orient_mode & 2 == 0) else 1
                floc = (xr + x0 * blk_w, yf + y0 * blk_h)
                self.add_instance(fill_master,
                                  loc=floc,
                                  orient=orient,
                                  nx=nx,
                                  ny=ny,
                                  spx=blk_w,
                                  spy=blk_h,
                                  unit_mode=True)

            in_cnt = out_cnt = 0
            for name in name_list:
                opin_name = 'v_%s' % name
                out_pin = inst.get_pin('out<%d>' % out_cnt)
                io_name_list.append(name)
                if out_cnt < num_vdd:
                    vdd_pins.append((opin_name, out_pin))
                    vdd_names.append(opin_name)
                else:
                    vss_pins.append((opin_name, out_pin))
                    vss_names.append(opin_name)
                for in_idx in range(nin):
                    in_pin = inst.get_pin('code<%d>' % in_cnt)
                    in_pin = self.extend_wires(in_pin,
                                               upper=xr_tot,
                                               unit_mode=True)
                    self.add_pin('bias_%s<%d>' % (name, in_idx),
                                 in_pin,
                                 show=show_pins,
                                 edge_mode=1)
                    in_cnt += 1
                out_cnt += 1

        # draw routes
        tmp = join_bias_vroutes(self,
                                vm_layer,
                                vdd_x,
                                vss_x,
                                route_w,
                                num_vdd_tot,
                                num_vss_tot,
                                hm_bias_info_list,
                                bias_config,
                                vdd_pins,
                                vss_pins,
                                yt=self.bound_box.top_unit)
        vdd_pins, vss_pins, vdd_list, vss_list = tmp
        for name, warr in chain(vdd_pins, vss_pins):
            self.add_pin(name, warr, show=show_pins, edge_mode=1)

        # draw fill over routes
        nx = route_w // blk_w
        ny = tot_box.top_unit // blk_h

        orient = PowerFill.get_fill_orient(fill_orient_mode)
        dx = 0 if (fill_orient_mode & 1 == 0) else 1
        dy = 0 if (fill_orient_mode & 2 == 0) else 1
        loc = (dx * blk_w, dy * blk_h)
        inst = self.add_instance(fill_master,
                                 loc=loc,
                                 orient=orient,
                                 nx=nx,
                                 ny=ny,
                                 spx=blk_w,
                                 spy=blk_h,
                                 unit_mode=True)
        if vdd_list:
            self.draw_vias_on_intersections(vdd_list,
                                            inst.get_all_port_pins('VDD_b'))
        if vss_list:
            self.draw_vias_on_intersections(vss_list,
                                            inst.get_all_port_pins('VSS_b'))

        self.reexport(inst.get_port('VDD'), show=show_pins)
        self.reexport(inst.get_port('VSS'), show=show_pins)

        self._sch_params = dict(
            nin0=nin0,
            nin1=nin1,
            nout_arr_list=nout_arr_list,
            res_params=res_params,
            mux_params=mux_params,
            io_name_list=io_name_list,
        )
        self._bias_info = ((vdd_x[0], vdd_names), (vss_x[0], vss_names))