Exemplo n.º 1
0
 def __init__(self, row_specs: MOSRowSpecs, row_info: MOSRowInfo,
              bot_conn_y_table: Mapping[MOSWireType, Tuple[int, int]],
              top_conn_y_table: Mapping[MOSWireType, Tuple[int, int]],
              bot_ext_info: RowExtInfo, top_ext_info: RowExtInfo):
     # work around: this is how you set attributes for frozen data classes
     object.__setattr__(self, 'row_specs', row_specs)
     object.__setattr__(self, 'row_info', row_info)
     object.__setattr__(self, 'bot_conn_y_table', ImmutableSortedDict(bot_conn_y_table))
     object.__setattr__(self, 'top_conn_y_table', ImmutableSortedDict(top_conn_y_table))
     object.__setattr__(self, 'bot_ext_info', bot_ext_info)
     object.__setattr__(self, 'top_ext_info', top_ext_info)
Exemplo n.º 2
0
 def _update_dut_params(pinfo: Mapping[str, Any], nbits: int, seg_unit: int,
                        seg_buf: int, seg_nand: int, seg_inv: int,
                        num_cores: int, dc_params: Mapping[str,
                                                           Any]) -> Param:
     return ImmutableSortedDict(
         dict(
             pinfo=pinfo,
             pi_params=dict(
                 unit_params={
                     'seg': seg_unit,
                     'stack_p': 1,
                     'stack_n': 1
                 },
                 inv_params={
                     'seg': seg_buf,
                     'stack_p': 1,
                     'stack_n': 1
                 },
                 abut_tristates=True,
             ),
             dc_params=dc_params,
             inv_params=dict(seg=seg_inv),
             nand_params=dict(seg=seg_nand),
             num_core=num_cores,
             nbits=nbits,
             export_dc_out=True,
             export_dc_in=True,
             draw_sub=True,
             # export_outb=True,
         ))
Exemplo n.º 3
0
    def __init__(self, temp_db: TemplateDB, params: Param,
                 **kwargs: Any) -> None:
        TemplateBase.__init__(self, temp_db, params, **kwargs)

        self.prim_top_layer = self.grid.bot_layer
        self._corner: Optional[Tuple[int, int]] = None
        self._edgel = self._edgeb = ImmutableSortedDict()
Exemplo n.º 4
0
    def get_blk_info(self, conn_layer: int, w: int, h: int, nx: int, ny: int,
                     **kwargs: Any) -> Optional[ArrayLayInfo]:
        res_type: str = kwargs.get('res_type', 'standard')

        if res_type != 'metal':
            raise ValueError(f'unsupported resistor type: {res_type}')

        x_pitch: int = self.res_config['x_pitch']
        conn_w: int = self.res_config['conn_w']

        sp_le = self.tech_info.get_min_line_end_space('M1CA',
                                                      conn_w,
                                                      purpose='drawing',
                                                      even=True)

        builder = LayoutInfoBuilder()
        x0 = x_pitch // 2
        yl = sp_le
        yh = h - sp_le
        x1 = w - x_pitch // 2
        boxl = BBox(x0 - conn_w // 2, yl, x0 + conn_w // 2, yh)
        builder.add_rect_arr(('M1CA', 'drawing'), boxl, nx=2, spx=x1 - x0)
        xm = w // 2
        boxm = BBox(xm - conn_w // 2, yl, xm + conn_w // 2, yh)
        builder.add_rect_arr(('M1CA', 'drawing'), boxm)
        boxr = BBox(boxm.xl, yl + conn_w, boxm.xh, yh - conn_w)
        builder.add_rect_arr(('m1res', 'drawing'), boxr)
        builder.add_rect_arr(('M1CA', 'drawing'),
                             BBox(boxl.xl, yl, boxm.xh, yl + conn_w))
        boxr = boxl.get_move_by(dx=x1 - x0)
        builder.add_rect_arr(('M1CA', 'drawing'),
                             BBox(boxm.xl, yh - conn_w, boxr.xh, yh))

        tidu = HalfInt(2 * ((w // x_pitch) - 1))
        return ArrayLayInfo(
            builder.get_info(BBox(0, 0, w, h)),
            ImmutableSortedDict({
                'u':
                WireArrayInfo(1, tidu, yl, yh, 1, 1, 0),
                'l':
                WireArrayInfo(1, HalfInt(0), yl, yh, 1, 1, 0)
            }), ImmutableSortedDict(), ImmutableSortedDict())
Exemplo n.º 5
0
 def copy_with(self,
               row_type: Optional[MOSType] = None,
               threshold: Optional[str] = None,
               **kwargs) -> RowExtInfo:
     if row_type is None:
         row_type = self.row_type
     if threshold is None:
         threshold = self.threshold
     info_dict = self.info.to_dict()
     info_dict.update(kwargs)
     return RowExtInfo(row_type, threshold, ImmutableSortedDict(info_dict))
Exemplo n.º 6
0
    def _get_w_th_dict(
        self, ridx_n: int, ridx_p: int
    ) -> Tuple[ImmutableSortedDict[str, int], ImmutableSortedDict[str, str]]:
        w_dict: Mapping[str, int] = self.params['w_dict']

        w_ans = {}
        th_ans = {}
        for name, row_idx in [('tail', ridx_n), ('in', ridx_n + 1),
                              ('pfb', ridx_p)]:
            rinfo = self.get_row_info(row_idx, 0)
            w = w_dict.get(name, 0)
            if w == 0:
                w = rinfo.width
            w_ans[name] = w
            th_ans[name] = rinfo.threshold

        w_ans['br'] = w_ans['nfb'] = w_ans['in']
        w_ans['swm'] = w_ans['swo'] = w_ans['pfb']
        th_ans['br'] = th_ans['nfb'] = th_ans['in']
        th_ans['swm'] = th_ans['swo'] = th_ans['pfb']
        return ImmutableSortedDict(w_ans), ImmutableSortedDict(th_ans)
Exemplo n.º 7
0
    def _get_w_th_dict(self, ridx_n: int, ridx_p: int, has_rstb: bool
                       ) -> Tuple[ImmutableSortedDict[str, int], ImmutableSortedDict[str, str]]:
        w_dict: Mapping[str, int] = self.params['w_dict']

        w_ans = {}
        th_ans = {}
        for row_idx, name_list in [(ridx_n, ['nfb', 'nr']),
                                   (ridx_p, ['pfb', 'ps'])]:
            rinfo = self.get_row_info(row_idx, 0)
            for name in name_list:
                w = w_dict.get(name, 0)
                if w == 0:
                    w = rinfo.width
                w_ans[name] = w
                th_ans[name] = rinfo.threshold

        if has_rstb:
            w_ans['pr'] = w_ans['ps']
            th_ans['pr'] = th_ans['ps']

        return ImmutableSortedDict(w_ans), ImmutableSortedDict(th_ans)
Exemplo n.º 8
0
 def __init__(self,
              data: Dict[Tuple[str, int], Tuple[HalfInt, int]],
              ranges: Optional[Dict[str, List[int]]] = None) -> None:
     self._data: ImmutableSortedDict[Tuple[str, int],
                                     Tuple[HalfInt,
                                           int]] = ImmutableSortedDict(data)
     if ranges is None:
         self._ranges = {}
         for name, idx in data.keys():
             cur_range = self._ranges.get(name, None)
             if cur_range is None:
                 self._ranges[name] = [idx, idx]
             else:
                 cur_range[0] = min(cur_range[0], idx)
                 cur_range[1] = max(cur_range[1], idx)
     else:
         self._ranges = ranges
Exemplo n.º 9
0
    def get_mos_corner_info(self, blk_w: int, blk_h: int, einfo: MOSEdgeInfo) -> CornerLayInfo:
        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_rect = BBox(0, 0, blk_w, blk_h)

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

        edgel = edgeb = ImmutableSortedDict(dict(dev_type=DeviceType.MOS, well_margin=sd_pitch))
        return CornerLayInfo(builder.get_info(blk_rect), (0, 0), edgel, edgeb)
Exemplo n.º 10
0
    def __init__(self,
                 mos_type: MOSType,
                 width: int,
                 threshold: str,
                 bot_wires: WireData,
                 top_wires: WireData,
                 options: Optional[Mapping[str, Any]] = None,
                 flip: bool = False,
                 sub_width: int = 0) -> None:
        if sub_width == 0 or mos_type.is_substrate:
            sub_width = width

        # work around: this is how you set attributes for frozen data classes
        object.__setattr__(self, 'mos_type', mos_type)
        object.__setattr__(self, 'width', width)
        object.__setattr__(self, 'threshold', threshold)
        object.__setattr__(self, 'bot_wires', bot_wires)
        object.__setattr__(self, 'top_wires', top_wires)
        object.__setattr__(self, 'options', ImmutableSortedDict(options))
        object.__setattr__(self, 'flip', flip)
        object.__setattr__(self, 'sub_width', sub_width)
Exemplo n.º 11
0
    def from_dict(cls, table: Mapping[str, Any]) -> MOSRowInfo:
        row_type = MOSType[table['row_type']]
        top_ext_info = RowExtInfo.from_dict(table['top_ext_info'])
        bot_ext_info = RowExtInfo.from_dict(table['bot_ext_info'])

        return MOSRowInfo(table['lch'],
                          table['width'],
                          table['sub_width'],
                          row_type,
                          table['threshold'],
                          table['height'],
                          table['flip'],
                          top_ext_info,
                          bot_ext_info,
                          ImmutableSortedDict(table['info']),
                          table['g_conn_y'],
                          table['g_m_conn_y'],
                          table['ds_conn_y'],
                          table['ds_m_conn_y'],
                          table['ds_g_conn_y'],
                          table['sub_conn_y'],
                          guard_ring=table.get('guard_ring', False))
Exemplo n.º 12
0
 def get_end_info(self, w: int, h: int, info: ImmutableSortedDict[str, Any],
                  **kwargs: Any) -> ArrayEndInfo:
     builder = LayoutInfoBuilder()
     return ArrayEndInfo(builder.get_info(BBox(0, 0, w, h)),
                         ImmutableSortedDict())
Exemplo n.º 13
0
 def get_info(self, bnd_box: BBox) -> LayoutInfo:
     return LayoutInfo(ImmutableSortedDict(self._lp_dict),
                       ImmutableList(self._warr_list),
                       ImmutableList(self._via_list), bnd_box)
Exemplo n.º 14
0
    def draw_layout(self) -> None:
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid,
                                                 self.params['pinfo'])
        self.draw_base(pinfo)

        seg_dict: ImmutableSortedDict[str, int] = self.params['seg_dict']
        ridx_n: int = self.params['ridx_n']
        ridx_p: int = self.params['ridx_p']
        vertical_sel: bool = self.params['vertical_sel']

        w_dict = self._get_w_dict(ridx_n, ridx_p)

        seg_tri = seg_dict['tri']
        seg_buf = seg_dict['buf']
        w_pbuf = w_dict['pbuf']
        w_nbuf = w_dict['nbuf']
        w_ptri = w_dict['ptri']
        w_ntri = w_dict['ntri']

        if (seg_tri & 1) or (seg_buf % 4 != 0):
            raise ValueError(
                'segments of transistors must be even, buf must be multiple of 4.'
            )
        seg_buf_half = seg_buf // 2

        # placement
        vm_layer = self.conn_layer + 2
        grid = self.grid
        tr_manager = self.tr_manager
        vm_w = tr_manager.get_width(vm_layer, 'sig')

        vss_tid = self.get_track_id(ridx_n, False, wire_name='sup')
        vdd_tid = self.get_track_id(ridx_p, True, wire_name='sup')
        nd_tid = self.get_track_id(ridx_n,
                                   MOSWireType.DS,
                                   wire_name='sig',
                                   wire_idx=-1)
        pd_tid = self.get_track_id(ridx_p,
                                   MOSWireType.DS,
                                   wire_name='sig',
                                   wire_idx=0)
        ng2_tid = self.get_track_id(ridx_n,
                                    MOSWireType.G,
                                    wire_name='sig',
                                    wire_idx=2)
        pg0_tid = self.get_track_id(ridx_p,
                                    MOSWireType.G,
                                    wire_name='sig',
                                    wire_idx=-2)
        pg1_tid = self.get_track_id(ridx_p,
                                    MOSWireType.G,
                                    wire_name='sig',
                                    wire_idx=-1)
        in_tid = ng2_tid
        pmid_tid = pg0_tid
        psel_tid = pg1_tid

        tri_ncol = 2 * seg_tri
        min_sep = self.min_sep_col
        min_sep += (min_sep & 1)
        ntri = self.add_mos(ridx_n,
                            0,
                            seg_tri,
                            w=w_ntri,
                            stack=2,
                            g_on_s=True,
                            sep_g=True)
        ptri = self.add_mos(ridx_p,
                            0,
                            seg_tri,
                            w=w_ptri,
                            stack=2,
                            g_on_s=True,
                            sep_g=True)
        cur_col = tri_ncol + min_sep
        nbuf = self.add_mos(ridx_n, cur_col, seg_buf_half, w=w_nbuf)
        pbuf = self.add_mos(ridx_p, cur_col, seg_buf_half, w=w_pbuf)
        self.set_mos_size()

        # routing
        # supplies
        vdd = self.connect_to_tracks([ptri.s, pbuf.s], vdd_tid)
        vss = self.connect_to_tracks([ntri.s, nbuf.s], vss_tid)
        self.add_pin('VDD', vdd)
        self.add_pin('VSS', vss)

        # select signals
        in_warr = self.connect_to_tracks([ntri.g[0::2], ptri.g[0::2]], in_tid)
        nsel = ntri.g[1::2]
        psel = self.connect_to_tracks(ptri.g[1::2],
                                      psel_tid,
                                      min_len_mode=MinLenMode.MIDDLE)
        vm_tidx = grid.coord_to_track(vm_layer,
                                      psel.middle,
                                      mode=RoundMode.GREATER_EQ)
        if vertical_sel:
            psel_vm = self.connect_to_tracks(psel,
                                             TrackID(vm_layer,
                                                     vm_tidx,
                                                     width=vm_w),
                                             min_len_mode=MinLenMode.LOWER)
            self.add_pin('psel_vm', psel_vm)
        self.add_pin('in', in_warr)
        self.add_pin('nsel', nsel)
        self.add_pin('psel', psel)

        # mid
        pmid = self.connect_to_tracks(ptri.d,
                                      pd_tid,
                                      min_len_mode=MinLenMode.UPPER)
        nmid = self.connect_to_tracks(ntri.d,
                                      nd_tid,
                                      min_len_mode=MinLenMode.UPPER)
        vm_tidx = tr_manager.get_next_track(vm_layer,
                                            vm_tidx,
                                            'sig',
                                            'sig',
                                            up=True)
        mid = self.connect_to_tracks([pmid, nmid],
                                     TrackID(vm_layer, vm_tidx, width=vm_w))
        mid = self.connect_to_tracks([mid, nbuf.g, pbuf.g], pmid_tid)
        self.add_pin('mid', mid)

        # output
        pout = self.connect_to_tracks(pbuf.d,
                                      pd_tid,
                                      min_len_mode=MinLenMode.UPPER)
        nout = self.connect_to_tracks(nbuf.d,
                                      nd_tid,
                                      min_len_mode=MinLenMode.UPPER)
        vm_tidx = grid.coord_to_track(vm_layer, self.bound_box.xh)
        out = self.connect_to_tracks([pout, nout],
                                     TrackID(vm_layer, vm_tidx, width=vm_w))
        self.add_pin('out', out)

        lch = self.arr_info.lch
        th_p = self.get_row_info(ridx_p, 0).threshold
        th_n = self.get_row_info(ridx_n, 0).threshold
        self.sch_params = dict(
            inv_params=ImmutableSortedDict(
                dict(
                    lch=lch,
                    seg_p=seg_buf,
                    seg_n=seg_buf,
                    w_p=w_pbuf,
                    w_n=w_nbuf,
                    th_p=th_p,
                    th_n=th_n,
                )),
            tri_params=ImmutableSortedDict(
                dict(
                    lch=lch,
                    seg=seg_tri,
                    w_p=w_ptri,
                    w_n=w_ntri,
                    th_p=th_p,
                    th_n=th_n,
                )),
        )
    def draw_layout(self):
        place_info = MOSBasePlaceInfo.make_place_info(self.grid,
                                                      self.params['pinfo'])
        self.draw_base(place_info)

        seg_dict: ImmutableSortedDict[str, int] = self.params['seg_dict']
        ridx_n: int = self.params['ridx_n']
        ridx_p: int = self.params['ridx_p']
        has_rstb: bool = self.params['has_rstb']
        has_outbuf: bool = self.params['has_outbuf']
        has_inbuf: bool = self.params['has_inbuf']
        out_pitch: HalfInt = HalfInt.convert(self.params['out_pitch'])

        w_dict, th_dict = self._get_w_th_dict(ridx_n, ridx_p, has_rstb)

        seg_fb = seg_dict['fb']
        seg_ps = seg_dict['ps']
        seg_nr = seg_dict['nr']
        seg_obuf = seg_dict['obuf'] if has_outbuf else 0
        seg_ibuf = seg_dict['ibuf'] if has_inbuf else 0

        w_pfb = w_dict['pfb']
        w_nfb = w_dict['nfb']
        w_ps = w_dict['ps']
        w_nr = w_dict['nr']
        w_rst = w_dict.get('pr', 0)
        w_nbuf = w_nr
        w_pbuf = w_ps

        sch_seg_dict = dict(nfb=seg_fb, pfb=seg_fb, ps=seg_ps, nr=seg_nr)
        if has_rstb:
            sch_seg_dict['pr'] = seg_rst = seg_dict['rst']
        else:
            seg_rst = 0

        if seg_ps & 1 or seg_nr & 1 or seg_rst & 1 or seg_obuf & 1:
            raise ValueError(
                'ps, nr, rst, and buf must have even number of segments')

        # placement
        min_sep = self.min_sep_col
        # use even step size to maintain supply conn_layer wires parity.
        min_sep += (min_sep & 1)

        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        grid = self.grid
        arr_info = self.arr_info
        tr_manager = self.tr_manager
        hm_w = tr_manager.get_width(hm_layer, 'sig')
        vm_w = tr_manager.get_width(vm_layer, 'sig')
        hm_sep_col = self.get_hm_sp_le_sep_col(ntr=hm_w)
        mid_sep = max(hm_sep_col - 2, 0)
        mid_sep = (mid_sep + 1) // 2

        if has_inbuf:
            m_nibuf = self.add_mos(ridx_n, mid_sep, seg_ibuf, w=w_nbuf)
            m_pibuf = self.add_mos(ridx_p, mid_sep, seg_ibuf, w=w_pbuf)
            cur_col = mid_sep + seg_ibuf
            psrb_list = [m_nibuf.g, m_pibuf.g]
        else:
            m_nibuf = m_pibuf = None
            cur_col = mid_sep
            psrb_list = []

        nr_col = cur_col
        m_nr = self.add_mos(ridx_n, cur_col, seg_nr, w=w_nr)
        m_ps = self.add_mos(ridx_p, cur_col, seg_ps, w=w_ps)
        psrb_list.append(m_ps.g)
        pcol = cur_col + seg_ps
        if has_rstb:
            m_rst = self.add_mos(ridx_p, pcol, seg_rst, w=w_rst)
            pcol += seg_rst
        else:
            m_rst = None

        cur_col = max(cur_col + seg_nr, pcol)
        if has_outbuf:
            m_pinv = self.add_mos(ridx_p, cur_col, seg_obuf, w=w_pbuf)
            m_ninv = self.add_mos(ridx_n, cur_col, seg_obuf, w=w_nbuf)
            cur_col += seg_obuf
        else:
            m_pinv = m_ninv = None

        cur_col += min_sep
        fb_col = cur_col
        m_pfb = self.add_mos(ridx_p,
                             cur_col,
                             seg_fb,
                             w=w_pfb,
                             g_on_s=True,
                             stack=2,
                             sep_g=True)
        m_nfb = self.add_mos(ridx_n,
                             cur_col,
                             seg_fb,
                             w=w_nfb,
                             g_on_s=True,
                             stack=2,
                             sep_g=True)
        self.set_mos_size()

        # track planning
        vss_tid = self.get_track_id(ridx_n, MOSWireType.DS, wire_name='sup')
        nbuf_tid = self.get_track_id(ridx_n,
                                     MOSWireType.DS,
                                     wire_name='sig',
                                     wire_idx=-2)
        nq_tid = self.get_track_id(ridx_n,
                                   MOSWireType.DS,
                                   wire_name='sig',
                                   wire_idx=-1)
        psr_tid = self.get_track_id(ridx_p,
                                    MOSWireType.G,
                                    wire_name='sig',
                                    wire_idx=-1)
        pq_tid = self.get_track_id(ridx_p,
                                   MOSWireType.DS,
                                   wire_name='sig',
                                   wire_idx=0)
        pbuf_tid = self.get_track_id(ridx_p,
                                     MOSWireType.DS,
                                     wire_name='sig',
                                     wire_idx=1)
        vdd_tid = self.get_track_id(ridx_p, MOSWireType.DS, wire_name='sup')

        # try to spread out gate wires to lower parasitics on differential Q wires
        ng_lower = self.get_track_index(ridx_n,
                                        MOSWireType.G,
                                        wire_name='sig',
                                        wire_idx=0)
        ng_upper = self.get_track_index(ridx_n,
                                        MOSWireType.G,
                                        wire_name='sig',
                                        wire_idx=-1)
        g_idx_list = tr_manager.spread_wires(
            hm_layer, ['sig', 'sig_hs', 'sig_hs', 'sig'],
            ng_lower,
            ng_upper, ('sig_hs', 'sig_hs'),
            alignment=0)
        self._q_tr_info = (hm_w, g_idx_list[2], g_idx_list[1])
        self._sr_hm_tr_info = (hm_w, g_idx_list[3], g_idx_list[0])

        if has_rstb:
            rst_tid = self.get_track_id(ridx_p,
                                        MOSWireType.G,
                                        wire_name='sig',
                                        wire_idx=-2)
            pq_conn_list = [m_ps.d, m_rst.d, m_pfb.s]
            vdd_list = [m_ps.s, m_rst.s, m_pfb.d]
            vss_list = [m_nr.s, m_nfb.d]

            rstb = self.connect_to_tracks(m_rst.g,
                                          rst_tid,
                                          min_len_mode=MinLenMode.MIDDLE)
            rst_vm_tidx = grid.coord_to_track(vm_layer,
                                              rstb.middle,
                                              mode=RoundMode.GREATER_EQ)
            rstb_vm = self.connect_to_tracks(
                rstb, TrackID(vm_layer, rst_vm_tidx, width=vm_w))
            self.add_pin('rstb', rstb_vm)
        else:
            pq_conn_list = [m_ps.d, m_pfb.s]
            vdd_list = [m_ps.s, m_pfb.d]
            vss_list = [m_nr.s, m_nfb.d]

        self.add_pin('nsr', m_nr.g)
        self.add_pin('nsrb', m_nfb.g[0::2])
        nq = self.connect_to_tracks([m_nr.d, m_nfb.s], nq_tid)
        pq = self.connect_to_tracks(pq_conn_list, pq_tid)
        psrb = self.connect_to_tracks(psrb_list,
                                      psr_tid,
                                      min_len_mode=MinLenMode.UPPER)
        psr = self.connect_to_tracks(m_pfb.g[0::2],
                                     psr_tid,
                                     min_len_mode=MinLenMode.LOWER)
        qb = self.connect_wires([m_nfb.g[1::2], m_pfb.g[1::2]])
        self.add_pin('qb', qb)

        if has_inbuf:
            vdd_list.append(m_pibuf.s)
            vss_list.append(m_nibuf.s)

            nbuf = self.connect_to_tracks(m_nibuf.d,
                                          nbuf_tid,
                                          min_len_mode=MinLenMode.UPPER)
            pbuf = self.connect_to_tracks(m_pibuf.d,
                                          pbuf_tid,
                                          min_len_mode=MinLenMode.UPPER)
            vm_tidx = grid.coord_to_track(vm_layer,
                                          nbuf.middle,
                                          mode=RoundMode.LESS_EQ)
            buf = self.connect_to_tracks([nbuf, pbuf],
                                         TrackID(vm_layer, vm_tidx,
                                                 width=vm_w))
            self.add_pin('sr_buf', buf)

        out_p_htr = out_pitch.dbl_value
        vm_ref = grid.coord_to_track(vm_layer, 0)
        srb_vm_tidx = arr_info.col_to_track(vm_layer,
                                            nr_col + 1,
                                            mode=RoundMode.GREATER_EQ)
        if has_outbuf:
            vdd_list.append(m_pinv.s)
            vss_list.append(m_ninv.s)

            nbuf = self.connect_to_tracks(m_ninv.d,
                                          nbuf_tid,
                                          min_len_mode=MinLenMode.MIDDLE)
            pbuf = self.connect_to_tracks(m_pinv.d,
                                          pbuf_tid,
                                          min_len_mode=MinLenMode.MIDDLE)
            vm_delta = grid.coord_to_track(
                vm_layer, nbuf.middle, mode=RoundMode.LESS_EQ) - vm_ref
            vm_htr = -(-vm_delta.dbl_value // out_p_htr) * out_p_htr
            vm_tidx = vm_ref + HalfInt(vm_htr)
            buf = self.connect_to_tracks([nbuf, pbuf],
                                         TrackID(vm_layer, vm_tidx,
                                                 width=vm_w))
            self.add_pin('buf_out', buf)
            buf_in = self.connect_wires([m_ninv.g, m_pinv.g])
            self.add_pin('buf_in', buf_in)

            q_vm_tidx = tr_manager.get_next_track(vm_layer, srb_vm_tidx, 'sig',
                                                  'sig')
        else:
            vm_delta = tr_manager.get_next_track(vm_layer, srb_vm_tidx, 'sig',
                                                 'sig') - vm_ref
            vm_htr = -(-vm_delta.dbl_value // out_p_htr) * out_p_htr
            q_vm_tidx = vm_ref + HalfInt(vm_htr)

        sr_vm_tidx = arr_info.col_to_track(vm_layer,
                                           fb_col,
                                           mode=RoundMode.LESS_EQ)
        self._sr_vm_tr_info = (vm_w, sr_vm_tidx, srb_vm_tidx)

        q_vm = self.connect_to_tracks([nq, pq],
                                      TrackID(vm_layer, q_vm_tidx, width=vm_w))
        self.add_pin('q_vm', q_vm)
        self.add_pin('psr', psr)
        self.add_pin('psrb', psrb)

        self.add_pin('VDD', self.connect_to_tracks(vdd_list, vdd_tid))
        self.add_pin('VSS', self.connect_to_tracks(vss_list, vss_tid))

        lch = arr_info.lch
        buf_params = ImmutableSortedDict(
            dict(
                lch=lch,
                w_p=w_pbuf,
                w_n=w_nbuf,
                th_p=th_dict['ps'],
                th_n=th_dict['nr'],
                seg=seg_obuf,
            ))
        obuf_params = buf_params if has_outbuf else None
        ibuf_params = buf_params.copy(append=dict(
            seg=seg_ibuf)) if has_inbuf else None
        self.sch_params = dict(
            core_params=ImmutableSortedDict(
                dict(
                    lch=lch,
                    seg_dict=ImmutableSortedDict(sch_seg_dict),
                    w_dict=w_dict,
                    th_dict=th_dict,
                )),
            outbuf_params=obuf_params,
            inbuf_params=ibuf_params,
            has_rstb=has_rstb,
        )
Exemplo n.º 16
0
 def __init__(self, **kwargs: Any) -> None:
     object.__setattr__(self, 'info', ImmutableSortedDict(kwargs))
Exemplo n.º 17
0
    def get_mos_row_info(self, conn_layer: int, specs: MOSRowSpecs, bot_mos_type: MOSType,
                         top_mos_type: MOSType, global_options: Param) -> MOSRowInfo:
        guard_ring: bool = specs.options.get('guard_ring', False)

        assert conn_layer == 1, 'currently only work for conn_layer = 1'

        fin_p = self.mos_config['fin_p']

        mp_cpo_spy: int = self.mos_config['mp_cpo_spy']
        mp_h: int = self.mos_config['mp_h']
        mp_spy: int = self.mos_config['mp_spy']
        cpo_od_spy: int = self.mos_config['cpo_od_spy']
        cpo_h: int = self.mos_config['cpo_h']
        md_spy: int = self.mos_config['md_spy']
        md_h_min: int = self.mos_config['md_h_min']
        md_od_exty: int = self.mos_config['md_od_exty']
        od_spy: int = self.mos_config['od_spy']

        mos_type = specs.mos_type
        w = specs.width
        w_sub = specs.sub_width

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

        g_conn_info = self.get_conn_info(conn_layer, True)
        g_m1_dyt = g_conn_info.via_w // 2 + g_conn_info.via_top_enc
        g_m1_sp_le = g_conn_info.sp_le

        d_conn_info = self.get_conn_info(conn_layer, False)
        d_m1_h = max(md_h, d_conn_info.len_min)

        # place bottom CPO, compute gate/OD locations
        blk_yb = 0
        cpo_bot_yb = blk_yb - cpo_h // 2
        cpo_bot_yt = cpo_bot_yb + cpo_h
        # get gate via/M1 location
        mp_yb = max(mp_spy // 2, cpo_bot_yt + mp_cpo_spy)
        mp_yt = mp_yb + mp_h
        mp_yc = (mp_yt + mp_yb) // 2
        g_m1_yt = mp_yc + g_m1_dyt
        # get OD location, round to fin grid.
        od_yb = g_m1_yt + g_m1_sp_le + (d_m1_h - od_h) // 2
        od_yb = self.snap_od_edge(od_yb, False, True)
        od_yt = od_yb + od_h
        od_yc = (od_yb + od_yt) // 2
        md_yb = od_yc - md_h // 2
        md_yt = md_yb + md_h
        # compute top CPO location.
        blk_yt = od_yt + cpo_od_spy + cpo_h // 2
        blk_yt = -(-blk_yt // fin_p) * fin_p

        conn_info = self.get_conn_yloc_info(conn_layer, md_yb, md_yt, mos_type.is_substrate)
        m1_yt = conn_info.ds[1]
        m1_yb = conn_info.g[0]
        m1_spy = d_conn_info.sp_le
        top_einfo = RowExtInfo(
            mos_type, specs.threshold,
            ImmutableSortedDict(dict(
                margins=dict(
                    od=(blk_yt - od_yt, od_spy),
                    md=(blk_yt - md_yt, md_spy),
                    m1=(blk_yt - m1_yt, m1_spy),
                ))),
        )
        bot_einfo = RowExtInfo(
            specs.mos_type, specs.threshold,
            ImmutableSortedDict(dict(
                margins=dict(
                    od=(od_yb, od_spy),
                    md=(md_yb, md_spy),
                    m1=(m1_yb, m1_spy),
                ))),
        )
        info = dict(
            od_yb=od_yb,
            md_y=(md_yb, md_yt),
            po_y=(cpo_h // 2, blk_yt - cpo_h // 2),
            mp_y=conn_info.mp,
        )
        return MOSRowInfo(self.lch, w, w_sub, mos_type, specs.threshold, blk_yt, specs.flip,
                          top_einfo, bot_einfo, ImmutableSortedDict(info), conn_info.g,
                          conn_info.g_m, conn_info.ds, conn_info.ds_m, conn_info.ds_g,
                          conn_info.sub, guard_ring=guard_ring and mos_type.is_substrate)
Exemplo n.º 18
0
 def from_dict(cls, table: Mapping[str, Any]) -> RowExtInfo:
     return RowExtInfo(MOSType[table['row_type']], table['threshold'],
                       ImmutableSortedDict(table['info']))
Exemplo n.º 19
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())
Exemplo n.º 20
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())
Exemplo n.º 21
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]))