def design(self, nand_params: Param, nor_params: Param, pupd_params: Param,
               export_pins: bool) -> None:
        self.instances['XNAND'].design(**nand_params)
        self.instances['XNOR'].design(**nor_params)
        self.instances['Xpupd'].design(**pupd_params.copy(append=dict(
            strong=True)))

        if export_pins:
            self.add_pin('nand_pu', TermType.output)
            self.add_pin('nor_pd', TermType.output)
    def design(self, sa_params: Param, sr_params: Param, has_rstlb: bool) -> None:
        inbuf_test = sr_params.get('inbuf_params', None)
        if inbuf_test is None:
            raise ValueError('SR latch must have input buffers.')

        self.instances['XSA'].design(has_rstb=has_rstlb, **sa_params)
        self.instances['XSR'].design(has_rstb=has_rstlb, **sr_params)

        if not has_rstlb:
            self.remove_pin('rstlb')
예제 #3
0
    def _get_buf_lv_master(self, buf_params: Param, append: Mapping[str, Any]) -> InvChainCore:
        buf_params = buf_params.copy(append=dict(
            dual_output=True,
            vertical_output=True,
            **append
        ), remove=['sig_locs'])
        buf_master = self.new_template(InvChainCore, params=buf_params)

        vm_layer = self.conn_layer + 2
        out_tidx = buf_master.get_port('out').get_pins()[0].track_id.base_index
        prev_tidx = self.tr_manager.get_next_track(vm_layer, out_tidx, 'sig', 'sig', up=False)
        buf_master = buf_master.new_template_with(sig_locs=dict(outb=prev_tidx))
        return buf_master
예제 #4
0
    def get_fill_info(self, mos_type: str, threshold: str, w: int, h: int,
                      el: Param, eb: Param, er: Param,
                      et: Param) -> LayoutInfo:
        fin_p: int = self._fill_config['mos_pitch']
        fin_h: int = self._fill_config['fin_h']
        lch: int = self._fill_config['lch']
        po_od_exty: int = self._fill_config['po_od_exty']
        po_spy: int = self._fill_config['po_spy']
        sd_pitch: int = self._fill_config['sd_pitch']
        od_spx: int = self._fill_config['od_spx']
        od_density_min: float = self._fill_config['od_density_min']
        imp_od_encx: int = self._fill_config['imp_od_encx']
        imp_po_ency: int = self._fill_config['imp_po_ency']
        fin_p2 = fin_p // 2
        fin_h2 = fin_h // 2
        od_edge_margin = max(imp_od_encx, od_spx // 2)
        po_edge_margin = max(imp_po_ency, po_spy // 2)

        mos_layer_table = self.tech_info.config['mos_lay_table']
        po_lp = mos_layer_table['PO_DUMMY']
        od_lp = mos_layer_table['OD_DUMMY']
        fb_lp = mos_layer_table['FB']

        builder = LayoutInfoBuilder()

        # compute fill X intervals
        bnd_xl = el.get('delta', 0)
        bnd_xr = w - er.get('delta', 0)
        bnd_yb = eb.get('delta', 0)
        bnd_yt = h - et.get('delta', 0)
        bbox = BBox(bnd_xl, bnd_yb, bnd_xr, bnd_yt)
        fill_xl = bnd_xl + od_edge_margin
        fill_xh = bnd_xr - od_edge_margin
        fill_yl = bnd_yb + po_edge_margin
        fill_yh = bnd_yt - po_edge_margin

        # compute fill X/Y intervals
        od_x_list, od_x_density = self._get_od_x_list(w, fill_xl, fill_xh,
                                                      sd_pitch, lch, od_spx)
        if not od_x_list:
            return builder.get_info(bbox)

        od_y_density = od_density_min / od_x_density
        od_y_list = self._get_od_y_list(h, fill_yl, fill_yh, fin_p, fin_h,
                                        od_y_density)

        if not od_y_list:
            return builder.get_info(bbox)

        # draw fills
        ny = len(od_y_list)
        for idx, (od_yb, od_yt) in enumerate(od_y_list):
            po_yb = fill_yl if idx == 0 else od_yb - po_od_exty
            po_yt = fill_yh if idx == ny - 1 else od_yt + po_od_exty
            for od_xl, od_xr in od_x_list:
                builder.add_rect_arr(od_lp, BBox(od_xl, od_yb, od_xr, od_yt))
                nx = 1 + (od_xr - od_xl - lch) // sd_pitch
                builder.add_rect_arr(po_lp,
                                     BBox(od_xl, po_yb, od_xl + lch, po_yt),
                                     nx=nx,
                                     spx=sd_pitch)

        # draw other layers
        fin_yb = (
            (bnd_yb - fin_p2 + fin_h2) // fin_p) * fin_p + fin_p2 - fin_h2
        fin_yt = -(-(bnd_yt - fin_p2 - fin_h2) //
                   fin_p) * fin_p + fin_p2 + fin_h2
        for imp_lp in self._thres_imp_well_layers_iter(mos_type, threshold):
            builder.add_rect_arr(imp_lp, BBox(bnd_xl, bnd_yb, bnd_xr, bnd_yt))
        builder.add_rect_arr(fb_lp, BBox(bnd_xl, fin_yb, bnd_xr, fin_yt))

        return builder.get_info(bbox)
예제 #5
0
    def design(self, dlycell_params: Param, num_insts: int, num_dum: int,
               flop: bool, flop_char: bool, output_sr_pins: bool) -> None:
        """To be overridden by subclasses to design this module.

        This method should fill in values for all parameters in
        self.parameters.  To design instances of this module, you can
        call their design() method or any other ways you coded.

        To modify schematic structure, call:

        rename_pin()
        delete_instance()
        replace_instance_master()
        reconnect_instance_terminal()
        restore_instance()
        array_instance()
        """
        if not flop:
            self.replace_instance_master('XCELL',
                                         'aib_ams',
                                         'aib_dlycell_no_flop',
                                         keep_connections=True)
            self.replace_instance_master('XDUM',
                                         'aib_ams',
                                         'aib_dlycell_no_flop',
                                         keep_connections=True)
            for name in ['RSTb', 'CLKIN', 'iSI', 'SOOUT', 'iSE']:
                self.remove_pin(name)

        self.instances['XCELL'].design(**dlycell_params)

        if num_insts > 2:

            if output_sr_pins:
                conn_list = [('in_p', f'a<{num_insts - 2}:0>,dlyin'),
                             ('bk', f'bk<{num_insts - 1}:0>'),
                             ('ci_p', f'b<{num_insts - 1}:0>'),
                             ('out_p', f'b<{num_insts-2}:0>,dlyout'),
                             ('co_p', f'a<{num_insts - 1}:0>'),
                             ('si', f'so<{num_insts-2}:0>,iSI'),
                             ('so', f'SOOUT,so<{num_insts-2}:0>'),
                             ('srqb', f'srqb<{num_insts - 1}:0>'),
                             ('srq', f'srq<{num_insts - 1}:0>')]
            else:
                conn_list = [
                    ('in_p', f'a<{num_insts - 2}:0>,dlyin'),
                    ('bk', f'bk<{num_insts - 1}:0>'),
                    ('ci_p', f'b{num_insts - 1},b<{num_insts - 2}:0>'),
                    ('out_p', f'b<{num_insts - 2}:0>,dlyout'),
                    ('co_p', f'a{num_insts - 1},a<{num_insts - 2}:0>'),
                    ('si', f'so<{num_insts - 2}:0>,iSI'),
                    ('so', f'SOOUT,so<{num_insts - 2}:0>'),
                ]

            if flop_char:
                conn_list.append(('bk1', f'flop_q<{num_insts - 1}:0>'))
                self.add_pin(f'flop_q<{num_insts - 1}:0>', TermType.output)
            self.rename_instance('XCELL', f'XCELL<{num_insts - 1}:0>',
                                 conn_list)
        elif num_insts == 2:
            conn_list = [
                ('in_p', f'a,dlyin'),
                ('bk', f'bk<{num_insts - 1}:0>'),
                ('ci_p', f'b{num_insts - 1},b'),
                ('out_p', 'b,dlyout'),
                ('co_p', f'a{num_insts - 1},a'),
                ('si', f'so,iSI'),
                ('so', f'SOOUT,so'),
            ]

            if output_sr_pins:
                conn_list += [('srqb', f'srqb<1:0>'), ('srq', f'srq<1:0>')]

            if flop_char:
                conn_list.append(('bk1', f'flop_q<{num_insts - 1}:0>'))
                self.add_pin(f'flop_q<{num_insts - 1}:0>', TermType.output)
            self.rename_instance('XCELL', f'XCELL<{num_insts - 1}:0>',
                                 conn_list)
        elif num_insts == 1:
            if flop_char:
                self.reconnect_instance_terminal('XCELL', 'bk1', 'flop_q<0>')
                self.add_pin('flop_q<0>', TermType.output)
            if output_sr_pins:
                self.reconnect_instance_terminal('XCELL', 'srq', 'srq')
                self.reconnect_instance_terminal('XCELL', 'srqb', 'srqb')

        else:
            raise ValueError(
                f'num_insts={num_insts} should be greater than 0.')

        if num_dum > 0:
            dc_core_params = dlycell_params['dc_core_params'].copy(
                remove=['output_sr_pins'])
            dum_params = dlycell_params.copy(
                remove=['flop_char', 'output_sr_pins'],
                append={
                    'is_dum': True,
                    'dc_core_params': dc_core_params
                })
            self.instances['XDUM'].design(**dum_params)
            if num_dum > 1:
                suffix = f'<{num_dum - 1}:0>'
                conn_list = [
                    ('out_p', 'NC_out' + suffix),
                    ('co_p', 'NC_co' + suffix),
                    ('so', 'NC_so' + suffix),
                ]
                self.rename_instance('XDUM', 'XDUM' + suffix, conn_list)
                if flop:
                    self.rename_instance('XNC_so', 'XNC_so' + suffix,
                                         [('noConn', 'NC_so' + suffix)])
                else:
                    self.remove_instance('XNC_so')
                self.rename_instance('XNC_co', 'XNC_co' + suffix,
                                     [('noConn', 'NC_co' + suffix)])
                self.rename_instance('XNC_out', 'XNC_out' + suffix,
                                     [('noConn', 'NC_out' + suffix)])
        else:
            for inst in ['XDUM', 'XNC_so', 'XNC_co', 'XNC_out']:
                self.remove_instance(inst)

        if output_sr_pins:
            if num_insts == 2:
                raise ValueError('oops not supported')
            pin_name_list = [
                ('bk', f'bk<{num_insts - 1}:0>'),
                ('b', f'b<{num_insts - 1}:0>'),
                ('a', f'a<{num_insts - 1}:0>'),
            ] if num_insts > 1 else []
            self.add_pin(f'srq<{num_insts-1}:0>', TermType.output)
            self.add_pin(f'srqb<{num_insts-1}:0>', TermType.output)
        else:
            pin_name_list = [
                ('bk', f'bk<{num_insts - 1}:0>'),
                ('b', f'b{num_insts - 1}'),
                ('a', f'a{num_insts - 1}'),
            ] if num_insts > 1 else []

        for old_name, new_name in pin_name_list:
            self.rename_pin(old_name, new_name)
예제 #6
0
def test_get_hash(val):
    """Check that get_hash() works properly. on supported datatypes"""
    ans = Param.get_hash(val)
    assert isinstance(ans, int)
예제 #7
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())
예제 #8
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]))
    def _create_masters(
        self, pinfo: MOSBasePlaceInfo, ridx_p: int, ridx_n: int,
        is_guarded: bool, invp_params_list: Sequence[Param],
        invn_params_list: Sequence[Param], pg_params: Param,
        sig_locs: Mapping[str, Union[float, HalfInt]], vertical_out: bool,
        vertical_in: bool
    ) -> Tuple[Sequence[InvCore], Sequence[InvCore], PassGateCore]:
        # configure sig_locs dictionary so we can connect more signals on hm_layer
        nout_tid = get_adj_tidx_list(self, ridx_n, sig_locs, MOSWireType.DS,
                                     'nout', False)
        pout_tid = get_adj_tidx_list(self, ridx_p, sig_locs, MOSWireType.DS,
                                     'pout', True)
        nin_tid = get_adj_tidx_list(self, ridx_n, sig_locs, MOSWireType.G,
                                    'nin', True)
        pin_tid = get_adj_tidx_list(self, ridx_p, sig_locs, MOSWireType.G,
                                    'pin', False)
        # TODO: this gate index hack fixes cases where you cannot short adjacent hm_layer
        # TODO: tracks with vm_layer.  Need more rigorous checking later so we can reduce
        # TODO: gate resistance
        even_gate_index = int(is_guarded)
        # create masters
        append_dict = dict(
            pinfo=pinfo,
            ridx_p=ridx_p,
            ridx_n=ridx_n,
            is_guarded=is_guarded,
        )
        sig_locs0 = dict(
            nout=nout_tid[0],
            pout=pout_tid[0],
            nin=nin_tid[even_gate_index],
            pin=pin_tid[even_gate_index],
        )
        sig_locs1 = dict(
            nout=nout_tid[1],
            pout=pout_tid[1],
            nin=nin_tid[1],
            pin=pin_tid[1],
        )
        invp0 = self.new_template(InvCore,
                                  params=invp_params_list[0].copy(
                                      append=dict(sig_locs=sig_locs0,
                                                  vertical_out=not is_guarded,
                                                  vertical_in=vertical_in,
                                                  **append_dict)))
        pg = self.new_template(PassGateCore,
                               params=pg_params.copy(append=dict(
                                   sig_locs=dict(
                                       nd=nout_tid[0],
                                       pd=pout_tid[0],
                                       ns=nout_tid[1],
                                       ps=pout_tid[1],
                                       en=nin_tid[1],
                                       enb=pin_tid[1],
                                   ),
                                   pinfo=pinfo,
                                   ridx_p=ridx_p,
                                   ridx_n=ridx_n,
                                   is_guarded=is_guarded,
                                   vertical_out=False,
                                   vertical_in=False,
                               )))
        invp1 = self.new_template(
            InvCore,
            params=invp_params_list[1].copy(append=dict(
                sig_locs=sig_locs0, vertical_out=vertical_out, **append_dict)))

        invn0 = self.new_template(InvCore,
                                  params=invn_params_list[0].copy(
                                      append=dict(sig_locs=sig_locs0,
                                                  vertical_out=not is_guarded,
                                                  vertical_in=vertical_in,
                                                  **append_dict)))
        invn1 = self.new_template(
            InvCore,
            params=invn_params_list[1].copy(append=dict(
                sig_locs=sig_locs1, vertical_out=not is_guarded, **
                append_dict)))
        invn2 = self.new_template(
            InvCore,
            params=invn_params_list[2].copy(append=dict(
                sig_locs=sig_locs0, vertical_out=vertical_out, **append_dict)))

        if is_guarded:
            # make sure vm input pin are on the same track
            n0_in = invn0.get_port('in').get_pins()[0]
            p0_in = invp0.get_port('in').get_pins()[0]
            n0_tidx = n0_in.track_id.base_index
            p0_tidx = p0_in.track_id.base_index
            if n0_tidx < p0_tidx:
                sig_locs0['in'] = n0_tidx
                invp0 = invp0.new_template_with(sig_locs=sig_locs0)
            elif p0_tidx < n0_tidx:
                sig_locs0['in'] = p0_tidx
                invn0 = invn0.new_template_with(sig_locs=sig_locs0)

        return [invp0, invp1], [invn0, invn1, invn2], pg