示例#1
0
    def _get_mos_ext_info_helper(self, num_cols: int, blk_h: int, row_type: MOSType, threshold: str
                                 ) -> ExtEndLayInfo:
        sd_pitch = self.sd_pitch

        cpo_h = self.mos_config['cpo_h']

        mos_lay_table = self.tech_info.config['mos_lay_table']
        cpo_lp = mos_lay_table['CPO']
        po_lp = mos_lay_table['PO_DUMMY']

        blk_w = num_cols * sd_pitch
        cpo_h2 = cpo_h // 2
        blk_rect = BBox(0, 0, blk_w, blk_h)

        builder = LayoutInfoBuilder()
        builder.add_rect_arr(cpo_lp, BBox(0, -cpo_h2, blk_w, cpo_h2))
        builder.add_rect_arr(cpo_lp, BBox(0, blk_h - cpo_h2, blk_w, blk_h + cpo_h2))

        self._add_fb(builder, blk_rect)
        self._add_po_array(builder, po_lp, (0, blk_h), 0, num_cols)

        for lay_purp in self._thres_imp_well_layers_iter(row_type, row_type, threshold):
            builder.add_rect_arr(lay_purp, blk_rect)

        edge_info = MOSEdgeInfo(blk_h=blk_h, row_type=row_type, mos_type=row_type,
                                threshold=threshold)
        return ExtEndLayInfo(builder.get_info(blk_rect), edge_info)
示例#2
0
    def get_mos_end_info(self, blk_h: int, num_cols: int, einfo: RowExtInfo) -> ExtEndLayInfo:
        sd_pitch = self.sd_pitch

        cpo_h = self.mos_config['cpo_h']

        mos_lay_table = self.tech_info.config['mos_lay_table']
        cpo_lp = mos_lay_table['CPO']

        cpo_h2 = cpo_h // 2
        blk_w = num_cols * sd_pitch

        blk_rect = BBox(0, 0, blk_w, blk_h)

        builder = LayoutInfoBuilder()
        builder.add_rect_arr(cpo_lp, BBox(0, blk_h - cpo_h2, blk_w, blk_h + cpo_h2))

        edge_info = MOSEdgeInfo()
        return ExtEndLayInfo(builder.get_info(blk_rect), edge_info)
示例#3
0
    def get_mos_row_edge_info(self, blk_w: int, rinfo: MOSRowInfo,
                              einfo: MOSEdgeInfo) -> LayoutInfo:
        lch = self.lch
        sd_pitch = self.sd_pitch
        od_po_extx = self.od_po_extx
        od_extx = od_po_extx - (sd_pitch - lch) // 2

        mos_config = self.mos_config
        imp_od_encx: int = mos_config['imp_od_encx']

        mos_lay_table = self.tech_info.config['mos_lay_table']

        row_type = rinfo.row_type
        blk_h = rinfo.height

        mos_type = einfo['mos_type']
        has_od = einfo.get('has_od', False)

        blk_rect = BBox(0, 0, blk_w, blk_h)
        imp_rect = BBox(blk_w - imp_od_encx - od_extx, 0, blk_w, blk_h)
        po_xl = blk_w - sd_pitch // 2 - lch // 2
        builder = LayoutInfoBuilder()
        if has_od:
            po_lp = mos_lay_table['PO_PODE']
        else:
            po_lp = mos_lay_table['PO_DUMMY']

        builder.add_rect_arr(po_lp, BBox(po_xl, 0, po_xl + lch, rinfo.height))

        self._add_fb(builder, imp_rect)
        if mos_type.is_substrate and mos_type is not row_type.sub_type:
            row_type = mos_type
        for lay_purp in self._thres_imp_well_layers_iter(
                row_type, mos_type, rinfo.threshold):
            builder.add_rect_arr(lay_purp, imp_rect)

        return builder.get_info(blk_rect)
示例#4
0
    def get_mos_space_info(self, row_info: MOSRowInfo, num_cols: int, left_info: MOSEdgeInfo,
                           right_info: MOSEdgeInfo) -> MOSLayInfo:
        lch = self.lch
        sd_pitch = self.sd_pitch
        od_po_extx = self.od_po_extx

        if num_cols < self.min_sep_col and left_info and right_info:
            # cannot draw less than min_sep_col between two devices
            raise ODImplantEnclosureError(f'Cannot draw MOSSpace in {num_cols} columns.')

        imp_od_encx: int = self.mos_config['imp_od_encx']

        mos_lay_table = self.tech_info.config['mos_lay_table']
        po_lp = mos_lay_table['PO_DUMMY']
        pode_lp = mos_lay_table['PO_PODE']

        blk_xr = num_cols * sd_pitch
        blk_yt = row_info.height
        bbox = BBox(0, 0, blk_xr, blk_yt)

        row_type = row_info.row_type
        threshold = row_info.threshold

        builder = LayoutInfoBuilder()

        po_y = (0, blk_yt)
        od_extx = od_po_extx - (sd_pitch - lch) // 2
        if left_info.get('has_od', False):
            self._add_po_array(builder, pode_lp, po_y, 0, 1)
            po_start = 1
            imp_xmin = od_extx + imp_od_encx
        else:
            po_start = 0
            imp_xmin = 0

        if right_info.get('has_od', False):
            self._add_po_array(builder, pode_lp, po_y, num_cols - 1, num_cols)
            po_stop = num_cols - 1
            imp_xmax = blk_xr - od_extx - imp_od_encx
        else:
            po_stop = num_cols
            imp_xmax = blk_xr

        self._add_po_array(builder, po_lp, (0, blk_yt), po_start, po_stop)
        self._add_fb(builder, bbox)

        if left_info:
            typel = left_info['mos_type']
            if right_info:
                typer = right_info['mos_type']
            else:
                typer = typel
        else:
            if right_info:
                typer = right_info['mos_type']
            else:
                typer = row_type
            typel = typer

        guard_ring = ((typel.is_substrate and typel is not row_type.sub_type) or
                      (typer.is_substrate and typer is not row_type.sub_type))
        if typel == typer:
            if guard_ring:
                raise ValueError('Cannot have empty spaces between guard ring edges.')

            blk_rect = BBox(0, 0, blk_xr, blk_yt)
            for lay_purp in self._thres_imp_well_layers_iter(row_type, typel, threshold):
                builder.add_rect_arr(lay_purp, blk_rect)
            be = BlkExtInfo(row_type, threshold, False, ImmutableList([(num_cols, typel)]),
                            ImmutableSortedDict())
            edgel = edger = MOSEdgeInfo(mos_type=typel, has_od=False, is_sub=False)
        else:
            # must be in transistor row, and has one substrate
            if typel.is_substrate and ((not typer.is_substrate) or typel is not row_type.sub_type):
                xmid = od_extx + imp_od_encx
            else:
                xmid = blk_xr - od_extx - imp_od_encx

            if xmid < imp_xmin or xmid > imp_xmax:
                raise ODImplantEnclosureError('Insufficient space to satisfy implant-OD '
                                              'horizontal enclosure.')

            rectl = BBox(0, 0, xmid, blk_yt)
            rectr = BBox(xmid, 0, blk_xr, blk_yt)
            for lay_purp in self._thres_imp_well_layers_iter(row_type, typel, threshold):
                builder.add_rect_arr(lay_purp, rectl)
            for lay_purp in self._thres_imp_well_layers_iter(row_type, typer, threshold):
                builder.add_rect_arr(lay_purp, rectr)

            fgl = xmid // sd_pitch
            be = BlkExtInfo(row_type, threshold, guard_ring,
                            ImmutableList([(fgl, typel), (num_cols - fgl, typer)]),
                            ImmutableSortedDict())
            edgel = MOSEdgeInfo(mos_type=typel, has_od=False, is_sub=False)
            edger = MOSEdgeInfo(mos_type=typer, has_od=False, is_sub=False)

        wire_info = (0, 0, 0)
        return MOSLayInfo(builder.get_info(bbox), edgel, edger, be, be,
                          g_info=wire_info, d_info=wire_info, s_info=wire_info,
                          shorted_ports=ImmutableList())
示例#5
0
    def get_mos_tap_info(self, row_info: MOSRowInfo, conn_layer: int, seg: int,
                         options: Param) -> MOSLayInfo:
        row_type = row_info.row_type

        guard_ring: bool = options.get('guard_ring', row_info.guard_ring)
        if guard_ring:
            sub_type: MOSType = options.get('sub_type', row_type.sub_type)
        else:
            sub_type: MOSType = row_type.sub_type

        lch = self.lch
        sd_pitch = self.sd_pitch

        mp_h: int = self.mos_config['mp_h']
        mp_po_extx: int = self.mos_config['mp_po_extx']
        md_w: int = self.mos_config['md_w']

        mos_lay_table = self.tech_info.config['mos_lay_table']
        mp_lp = mos_lay_table['MP']

        g_info = self.get_conn_info(1, True)
        d_info = self.get_conn_info(1, False)

        threshold = row_info.threshold
        ds_yt = row_info.ds_conn_y[1]
        mp_yb, mp_yt = row_info['mp_y']
        md_yb, md_yt = row_info['md_y']
        md_yc = (md_yt + md_yb) // 2
        ds_yb = md_yc - (ds_yt - md_yc)

        fg = seg
        num_wire = seg + 1
        num_po = num_wire + 1

        builder = LayoutInfoBuilder()
        bbox = self._get_mos_active_rect_list(builder, row_info, fg, row_info.sub_width, sub_type)

        # Connect gate to MP
        mp_yc = (mp_yb + mp_yt) // 2
        mp_delta = (sd_pitch + lch) // 2 + mp_po_extx
        if num_po & 1:
            num_vg = num_po // 2
            if num_vg & 1:
                # we have 3 PO left over in the middle
                num_vg2 = (num_vg - 1) // 2
                num_vgm = 2
            else:
                # we have 5 PO left over in the middle
                num_vg2 = (num_vg - 2) // 2
                num_vgm = 4
            # draw middle vg
            vgm_x = bbox.xm - ((num_vgm - 1) * sd_pitch) // 2
            mp_xl = vgm_x - mp_delta
            mp_xr = vgm_x + (num_vgm - 1) * sd_pitch + mp_delta
            builder.add_rect_arr(mp_lp, BBox(mp_xl, mp_yb, mp_xr, mp_yt))
            builder.add_via(g_info.get_via_info('M1_LiPo', vgm_x, mp_yc, mp_h,
                                                nx=num_vgm, spx=sd_pitch))
            # draw left/right vg
            if num_vg2 > 0:
                vg_pitch = 2 * sd_pitch

                def _add_vg_half(vg_x: int) -> None:
                    xl = vg_x - mp_delta
                    xr = vg_x + mp_delta
                    builder.add_rect_arr(mp_lp, BBox(xl, mp_yb, xr, mp_yt),
                                         nx=num_vg2, spx=vg_pitch)
                    builder.add_via(g_info.get_via_info('M1_LiPo', vg_x, mp_yc, mp_h,
                                                        nx=num_vg2, spx=vg_pitch))

                _add_vg_half(0)
                _add_vg_half((num_wire - 1) * sd_pitch - (num_vg2 - 1) * vg_pitch)
        else:
            # even number of PO, can connect pair-wise
            num_vg = num_po // 2
            vg_pitch = 2 * sd_pitch
            builder.add_rect_arr(mp_lp, BBox(-mp_delta, mp_yb, mp_delta, mp_yt),
                                 nx=num_vg, spx=vg_pitch)
            builder.add_via(g_info.get_via_info('M1_LiPo', 0, mp_yc, mp_h,
                                                nx=num_vg, spx=vg_pitch))

        # connect drain/source to M1
        m1_yc = (md_yb + md_yt) // 2
        via_pitch = d_info.via_h + d_info.via_sp

        vnum_bot = (md_yt - md_yb - d_info.via_bot_enc * 2 + d_info.via_sp) // via_pitch
        vnum_top = (ds_yt - ds_yb - d_info.via_top_enc * 2 + d_info.via_sp) // via_pitch
        vnum = min(vnum_top, vnum_bot)
        builder.add_via(d_info.get_via_info('M1_LiAct', 0, m1_yc, md_w, ortho=False,
                                            num=vnum, nx=num_wire, spx=sd_pitch))

        edge_info = MOSEdgeInfo(mos_type=sub_type, has_od=True, is_sub=True)
        be = BlkExtInfo(row_type, threshold, guard_ring, ImmutableList([(fg, sub_type)]),
                        ImmutableSortedDict())
        wire_info = (0, num_wire, sd_pitch)
        return MOSLayInfo(builder.get_info(bbox), edge_info, edge_info, be, be,
                          g_info=wire_info, d_info=wire_info, s_info=wire_info,
                          shorted_ports=ImmutableList())
示例#6
0
    def get_mos_conn_info(self, row_info: MOSRowInfo, conn_layer: int, seg: int, w: int, stack: int,
                          g_on_s: bool, options: Param) -> MOSLayInfo:
        assert conn_layer == 1, 'currently only work for conn_layer = 1'

        lch = self.lch
        sd_pitch = self.sd_pitch

        mp_h: int = self.mos_config['mp_h']
        mp_po_extx: int = self.mos_config['mp_po_extx']
        md_w: int = self.mos_config['md_w']

        mos_lay_table = self.tech_info.config['mos_lay_table']
        mp_lp = mos_lay_table['MP']

        g_info = self.get_conn_info(1, True)
        d_info = self.get_conn_info(1, False)

        export_mid = options.get('export_mid', False)
        export_mid = export_mid and stack == 2

        row_type = row_info.row_type
        ds_yb, ds_yt = row_info.ds_conn_y
        threshold = row_info.threshold
        mp_yb, mp_yt = row_info['mp_y']
        md_yb, md_yt = row_info['md_y']

        fg = seg * stack
        wire_pitch = stack * sd_pitch
        conn_pitch = 2 * wire_pitch
        num_s = seg // 2 + 1
        num_d = (seg + 1) // 2
        s_xc = 0
        d_xc = wire_pitch
        if g_on_s:
            num_g = fg // 2 + 1
            g_xc = 0
        else:
            num_g = (fg + 1) // 2
            g_xc = sd_pitch
        g_pitch = 2 * sd_pitch

        builder = LayoutInfoBuilder()
        bbox = self._get_mos_active_rect_list(builder, row_info, fg, w, row_info.row_type)

        # Connect gate to MP
        mp_po_dx = (sd_pitch + lch) // 2 + mp_po_extx
        builder.add_rect_arr(mp_lp, BBox(g_xc - mp_po_dx, mp_yb, g_xc + mp_po_dx, mp_yt),
                             nx=num_g, spx=g_pitch)

        # connect gate to M1.
        mp_yc = (mp_yb + mp_yt) // 2
        builder.add_via(g_info.get_via_info('M1_LiPo', g_xc, mp_yc, mp_h,
                                            nx=num_g, spx=g_pitch))

        # connect drain/source to M1
        m1_yc = (md_yb + md_yt) // 2
        via_pitch = d_info.via_h + d_info.via_sp
        vnum1 = (md_yt - md_yb - d_info.via_bot_enc * 2 + d_info.via_sp) // via_pitch
        vnum2 = (ds_yt - ds_yb - d_info.via_top_enc * 2 + d_info.via_sp) // via_pitch
        vnum = min(vnum1, vnum2)
        builder.add_via(d_info.get_via_info('M1_LiAct', d_xc, m1_yc, md_w, ortho=False,
                                            num=vnum, nx=num_d, spx=conn_pitch))
        builder.add_via(d_info.get_via_info('M1_LiAct', s_xc, m1_yc, md_w, ortho=False,
                                            num=vnum, nx=num_s, spx=conn_pitch))
        if export_mid:
            m_xc = sd_pitch
            num_m = fg + 1 - num_s - num_d
            m_info = (m_xc, num_m, wire_pitch)
            builder.add_via(d_info.get_via_info('M1_LiAct', m_xc, m1_yc, md_w, ortho=False,
                                                num=vnum, nx=num_m, spx=wire_pitch))
        else:
            m_info = None

        edge_info = MOSEdgeInfo(mos_type=row_type, has_od=True, is_sub=False)
        be = BlkExtInfo(row_type, threshold, False, ImmutableList([(fg, row_type)]),
                        ImmutableSortedDict())
        return MOSLayInfo(builder.get_info(bbox), edge_info, edge_info, be, be,
                          g_info=(g_xc, num_g, g_pitch), d_info=(d_xc, num_d, conn_pitch),
                          s_info=(s_xc, num_s, conn_pitch), m_info=m_info,
                          shorted_ports=ImmutableList([MOSPortType.G]))