Esempio n. 1
0
    def draw_layout(self):
        lch = self.params['lch']
        guard_ring_nf = self.params['guard_ring_nf']
        layout_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf)

        bot_inst, top_inst, col_idx_dict = self.place(layout_info)
        self.connect(layout_info, bot_inst, top_inst, col_idx_dict)
        self._col_idx_dict = col_idx_dict
Esempio n. 2
0
 def __init__(self,
              grid,
              lch,
              guard_ring_nf,
              top_layer=None,
              end_mode=15,
              min_fg_sep=0,
              fg_tot=None):
     # type: (RoutingGrid, float, int, Optional[int], int, int, Optional[int]) -> None
     AnalogBaseInfo.__init__(self,
                             grid,
                             lch,
                             guard_ring_nf,
                             top_layer=top_layer,
                             end_mode=end_mode,
                             min_fg_sep=min_fg_sep,
                             fg_tot=fg_tot)
Esempio n. 3
0
    def find_fg_tot(self, res, lch, width, larger_mode=False, unit_mode=True):
        # type: (float, float, Union[float, int], bool, bool) -> int
        """
        find track width just larger than given width
        will be done by eric in future
        Parameters
        -------------
        res: float
            the layout grid resolution.
        layer: int
            metal layer id
        width: float
            width of metal layer
        larger_mode: bool
            find larger track or smaller track
        unit_mode: bool
            True if width and points are given as resolution units instead of layout units.

        Return
        -------------
            track width
        """

        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)

        if unit_mode is False:
            width = round(width / res)

        width_try = 0
        i = 0
        while width >= width_try:
            i += 1
            width_try = layout_info.get_total_width(i)

        if larger_mode is True:
            return i
        else:
            return i - 1
Esempio n. 4
0
    def connect(self, inst_list, col_idx_dict):
        lch = self.params['lch']
        guard_ring_nf = self.params['guard_ring_nf']
        layout_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf)
        hm_layer_id = layout_info.mconn_port_layer + 1
        vm_layer_id = hm_layer_id + 1
        diff_space = self.params['diff_space']

        # connect inputs of even and odd paths
        route_col_intv = col_idx_dict['integ']
        ptr_idx = layout_info.get_center_tracks(vm_layer_id, 2 + diff_space,
                                                route_col_intv)
        ntr_idx = ptr_idx + diff_space + 1
        p_list = []
        n_list = []
        for inst in inst_list:
            p_list += inst.get_port('integ_inp').get_pins(hm_layer_id)
            n_list += inst.get_port('integ_inn').get_pins(hm_layer_id)

        inp, inn = self.connect_differential_tracks(p_list, n_list,
                                                    vm_layer_id, ptr_idx,
                                                    ntr_idx)
        self.add_pin('inp', inp, show=True)
        self.add_pin('inn', inn, show=True)
Esempio n. 5
0
    def draw_layout(self):
        """Draw the layout of a dynamic latch chain.
        """
        # type: () -> None

        lch = self.params['lch']
        ptap_w = self.params['ptap_w']
        ntap_w = self.params['ntap_w']
        w_dict = self.params['w_dict']
        th_dict = self.params['th_dict']
        seg_dict = self.params['seg_dict']
        stack_dict = self.params['stack_dict']
        ndum = self.params['ndum']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        show_pins = self.params['show_pins']
        guard_ring_nf = self.params['guard_ring_nf']
        top_layer = self.params['top_layer']

        ana_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf, top_layer=top_layer)
        min_fg_sep = ana_info.min_fg_sep

        # calculate total number of fingers
        seg_tail1 = seg_dict['tail1']
        seg_tail2 = seg_dict['tail2']
        seg_tailcm = seg_dict['tailcm']
        seg_in = seg_dict['in']
        seg_ref = seg_dict['ref']
        seg_diode1 = seg_dict['diode1']
        seg_ngm1 = seg_dict['ngm1']
        seg_diode2 = seg_dict['diode2']
        seg_ngm2 = seg_dict['ngm2']

        stack_tail = stack_dict['tail']
        stack_in = stack_dict['in']
        stack_diode = stack_dict['diode']
        stack_ngm = stack_dict['ngm']

        fg_tail1 = seg_tail1 * stack_tail
        fg_tail2 = seg_tail2 * stack_tail
        fg_tailcm = seg_tailcm * stack_tail
        fg_in = seg_in * stack_in
        fg_diode1 = seg_diode1 * stack_diode
        fg_ngm1 = seg_ngm1 * stack_ngm
        fg_diode2 = seg_diode2 * stack_diode
        fg_ngm2 = seg_ngm2 * stack_ngm
        fg_ref = seg_ref * stack_in

        fg_load = fg_diode1 + fg_ngm1
        fg_in2 = fg_diode2 + fg_ngm2
        fg_bias2 = fg_tail2 + fg_tailcm

        # error checking
        if fg_tail1 != fg_in:
            raise ValueError('This template assumes fg_tail = fg_in')
        if stack_tail % stack_in != 0 and stack_in % stack_tail != 0:
            raise ValueError('one of stack_tail/stack_in must divide the other.')
        if stack_ngm % stack_in != 0 and stack_in % stack_ngm != 0:
            raise ValueError('one of stack_ngm/stack_in must divide the other.')

        fg_single1 = max(fg_in, fg_load)
        fg_single2 = max(fg_bias2, fg_in2)
        fg_tot = 2 * (fg_single1 + fg_single2 + ndum) + 4 * min_fg_sep + fg_ref

        # get width/threshold/orientation info
        nw_list = [w_dict['load']]
        nth_list = [th_dict['load']]
        n_orientations = ['MX']
        pw_list = [w_dict['in'], w_dict['tail']]
        pth_list = [th_dict['in'], th_dict['tail']]
        p_orientations = ['MX', 'MX']

        # get tracks information
        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
        hm_layer = self.get_mos_conn_layer(self.grid.tech_info) + 1
        vm_layer = hm_layer + 1

        # allocate tracks
        wire_names = dict(
            nch=[
                dict(ds=[],
                     g=['out', 'out']),
            ],
            pch=[
                dict(ds=['bias', 'tail'],
                     g=['in', 'in', 'in', 'in']),
                dict(ds=['tail'],
                     g=['bias', 'bias']),
            ],
        )

        # draw base
        self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list,
                       tr_manager=tr_manager, wire_names=wire_names,
                       n_orientations=n_orientations, p_orientations=p_orientations,
                       guard_ring_nf=guard_ring_nf, top_layer=top_layer)

        # draw stage1 transistors
        col_left = ndum + fg_single2 + fg_single1 + min_fg_sep
        col_right = col_left + 2 * min_fg_sep + fg_ref
        diode1l = self.draw_mos_conn('nch', 0, col_left - fg_load, fg_diode1, 2, 0,
                                     stack=stack_diode, s_net='midn', d_net='')
        ngm1l = self.draw_mos_conn('nch', 0, col_left - fg_ngm1, fg_ngm1, 2, 0,
                                   stack=stack_ngm, s_net='midn', d_net='')
        ngm1r = self.draw_mos_conn('nch', 0, col_right, fg_ngm1, 2, 0,
                                   stack=stack_ngm, s_net='midp', d_net='')
        diode1r = self.draw_mos_conn('nch', 0, col_right + fg_ngm1, fg_diode1, 2, 0,
                                     stack=stack_diode, s_net='midp', d_net='')
        inl = self.draw_mos_conn('pch', 0, col_left - fg_in, fg_in, 0, 2,
                                 stack=stack_in, s_net='midn', d_net='tail')
        inm = self.draw_mos_conn('pch', 0, col_left + min_fg_sep, fg_ref, 0, 2,
                                 stack=stack_in, s_net='bias', d_net='tail_ref')
        inr = self.draw_mos_conn('pch', 0, col_right, fg_in, 0, 2,
                                 stack=stack_in, s_net='midp', d_net='tail')
        bias1l = self.draw_mos_conn('pch', 1, col_left - fg_tail1, fg_tail1, 2, 0,
                                    stack=stack_tail, s_net='', d_net='tail')
        biasm = self.draw_mos_conn('pch', 1, col_left + min_fg_sep, fg_ref, 2, 0,
                                   stack=stack_tail, s_net='', d_net='tail_ref')
        bias1r = self.draw_mos_conn('pch', 1, col_right, fg_tail1, 2, 0,
                                    stack=stack_tail, s_net='', d_net='tail')
        # draw stage2 transistors
        col_left = ndum + fg_single2
        col_right += fg_single1 + min_fg_sep
        diode2l = self.draw_mos_conn('nch', 0, col_left - fg_in2, fg_diode2, 0, 2,
                                     stack=stack_diode, s_net='', d_net='outp')
        ngm2l = self.draw_mos_conn('nch', 0, col_left - fg_ngm2, fg_ngm2, 0, 2,
                                   stack=stack_ngm, s_net='', d_net='outp')
        ngm2r = self.draw_mos_conn('nch', 0, col_right, fg_ngm2, 0, 2,
                                   stack=stack_ngm, s_net='', d_net='outn')
        diode2r = self.draw_mos_conn('nch', 0, col_right + fg_ngm2, fg_diode2, 0, 2,
                                     stack=stack_diode, s_net='', d_net='outn')
        cm2l = self.draw_mos_conn('pch', 1, col_left - fg_bias2, fg_tailcm, 2, 0,
                                  stack=stack_tail, s_net='', d_net='outp')
        bias2l = self.draw_mos_conn('pch', 1, col_left - fg_tail2, fg_tail2, 2, 0,
                                    stack=stack_tail, s_net='', d_net='outp')
        bias2r = self.draw_mos_conn('pch', 1, col_right, fg_tail2, 2, 0,
                                    stack=stack_tail, s_net='', d_net='outn')
        cm2r = self.draw_mos_conn('pch', 1, col_right + fg_tail2, fg_tailcm, 2, 0,
                                  stack=stack_tail, s_net='', d_net='outn')

        # get track locations
        midp_tid = self.get_wire_id('nch', 0, 'g', wire_idx=1)
        midn_tid = self.get_wire_id('nch', 0, 'g', wire_idx=0)
        tail2_tid = self.get_wire_id('pch', 0, 'ds', wire_name='tail')
        bias2_tid = self.get_wire_id('pch', 0, 'ds', wire_name='bias')
        inc1_tid = self.get_wire_id('pch', 0, 'g', wire_idx=3)
        inp_tid = self.get_wire_id('pch', 0, 'g', wire_idx=2)
        inn_tid = self.get_wire_id('pch', 0, 'g', wire_idx=1)
        inc2_tid = self.get_wire_id('pch', 0, 'g', wire_idx=0)
        tail1_tid = self.get_wire_id('pch', 1, 'ds', wire_name='tail')
        cm_tid = self.get_wire_id('pch', 1, 'g', wire_idx=1)
        bias1_tid = self.get_wire_id('pch', 1, 'g', wire_idx=0)
        w_bias = cm_tid.width
        w_tail = tail1_tid.width
        w_out = midp_tid.width
        w_in = inp_tid.width

        # draw connections
        # connect VDD/VSS
        self.connect_to_substrate('ntap', [bias1l['s'], biasm['s'], bias1r['s'], cm2l['s'],
                                           cm2r['s'], bias2l['s'], bias2r['s']])
        self.connect_to_substrate('ptap', [diode1l['d'], ngm1l['d'], ngm1r['d'], diode1r['d'],
                                           diode2l['s'], ngm2l['s'], ngm2r['s'], diode2r['s']])

        # connect bias/tail wires
        self.connect_differential_tracks([inl['d'], inr['d'], bias1l['d'], bias1r['d']],
                                         [biasm['d'], inm['d']], hm_layer, tail2_tid.base_index,
                                         tail1_tid.base_index, width=w_tail)
        bias2 = self.connect_to_tracks(inm['s'], bias2_tid)

        bias1_warrs = [bias1l['g'], biasm['g'], bias1r['g'], bias2l['g'], bias2r['g']]
        cm_warrs = [cm2l['g'], cm2r['g']]
        bias1, cmbias = self.connect_differential_tracks(bias1_warrs, cm_warrs, hm_layer,
                                                         bias1_tid.base_index, cm_tid.base_index,
                                                         width=w_bias)
        mid_tid = self.grid.coord_to_nearest_track(vm_layer, bias1.middle)
        bias_vtid = TrackID(vm_layer, mid_tid, width=tr_manager.get_width(vm_layer, 'bias'))
        bias = self.connect_to_tracks([bias1, bias2], bias_vtid)

        # connect middle wires
        midp_warrs = [inr['s'], ngm1r['s'], diode1r['s'], diode1r['g'], ngm1l['g'],
                      diode2r['g'], ngm2r['g']]
        midn_warrs = [inl['s'], ngm1l['s'], diode1l['s'], diode1l['g'], ngm1r['g'],
                      diode2l['g'], ngm2l['g']]
        midp, midn = self.connect_differential_tracks(midp_warrs, midn_warrs, hm_layer,
                                                      midp_tid.base_index, midn_tid.base_index,
                                                      width=w_out)

        # connect inputs
        inc1_warrs = inc2_warrs = inm['g']
        inp_warrs = inl['g']
        inn_warrs = inr['g']
        inp_tidx, inn_tidx = inp_tid.base_index, inn_tid.base_index
        inc1, inp, inn, inc2 = self.connect_matching_tracks(
            [inc1_warrs, inp_warrs, inn_warrs, inc2_warrs], hm_layer,
            [inc1_tid.base_index, inp_tidx, inn_tidx, inc2_tid.base_index], width=w_in)

        # connect outputs
        out_tidx = self.grid.get_middle_track(inp_tidx, inn_tidx)
        outp = self.connect_to_tracks([diode2l['d'], ngm2l['d'], bias2l['d'], cm2l['d']],
                                      TrackID(hm_layer, out_tidx, width=w_out))
        outn = self.connect_to_tracks([diode2r['d'], ngm2r['d'], bias2r['d'], cm2r['d']],
                                      TrackID(hm_layer, out_tidx, width=w_out))

        # fill dummies
        sup_width = tr_manager.get_width(hm_layer, 'sup')
        vss_warrs, vdd_warrs = self.fill_dummy(vdd_width=sup_width, vss_width=sup_width)

        # add pins
        self.add_pin('ref', [inc1, inc2], show=show_pins)
        self.add_pin('inp', inp, show=show_pins)
        self.add_pin('inn', inn, show=show_pins)
        self.add_pin('bias', bias, show=show_pins)
        self.add_pin('cmbias', cmbias, show=show_pins)
        self.add_pin('midp', midp, show=show_pins)
        self.add_pin('midn', midn, show=show_pins)
        self.add_pin('outp', outp, show=show_pins)
        self.add_pin('outn', outn, show=show_pins)
        self.add_pin('VSS', vss_warrs, show=show_pins)
        self.add_pin('VDD', vdd_warrs, show=show_pins)

        # compute schematic parameters
        self._sch_params = dict(
            lch=lch,
            w_dict=w_dict,
            th_dict=th_dict,
            seg_dict=seg_dict,
            stack_dict=stack_dict,
            dum_info=self.get_sch_dummy_info(),
        )
Esempio n. 6
0
    def _draw_layout_helper(self, lch, wn, wp, nfn, nfp, g_space, ds_space,
                            ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent,
                            ndum, ndum_side, show_pins, power_width_ntr, debug,
                            **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nfn % 2 != 0 or nfp % 2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = ndum_side * 2 + ndum + max(nfn, nfp) * 2

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr + g_sp_ntr + g_space]
        pg_tracks = [g_width_ntr + g_sp_ntr + g_space]
        nds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space]
        pds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=p_orientation,
        )

        # get gate and drain index
        ngate_id = self.make_track_id('nch', 0, 'g', g_space, width=1)
        pgate_id = self.make_track_id('pch', 0, 'g', g_space, width=1)
        nout_id = self.make_track_id('nch', 0, 'ds', ds_space, width=1)
        pout_id = self.make_track_id('pch', 0, 'ds', ds_space, width=1)
        ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1)
        pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1)

        # nor
        nor_n0_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side,
                                          nfn,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='O')
        nor_p0_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side,
                                          nfp,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='ps')
        col_idx = ndum_side + max(nfn, nfp) + ndum
        nor_n1_ports = self.draw_mos_conn('nch',
                                          0,
                                          col_idx,
                                          nfn,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='O')
        nor_p1_ports = self.draw_mos_conn('pch',
                                          0,
                                          col_idx,
                                          nfp,
                                          1,
                                          1,
                                          s_net='ps',
                                          d_net='O')

        # connect nor
        nor_gn0_warr = self.connect_to_tracks(nor_n0_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        nor_gp0_warr = self.connect_to_tracks(nor_p0_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        nor_g0_idx = self.grid.coord_to_nearest_track(
            nor_gn0_warr.layer_id + 1, nor_gn0_warr.middle)
        nor_g0_tid = TrackID(nor_gn0_warr.layer_id + 1, nor_g0_idx)
        nor_g0 = self.connect_to_tracks([nor_gn0_warr, nor_gp0_warr],
                                        nor_g0_tid,
                                        min_len_mode=0)

        nor_gn1_warr = self.connect_to_tracks(nor_n1_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        nor_gp1_warr = self.connect_to_tracks(nor_p1_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        nor_g1_idx = self.grid.coord_to_nearest_track(
            nor_gn0_warr.layer_id + 1, nor_gn1_warr.middle)
        nor_g1_tid = TrackID(nor_gn0_warr.layer_id + 1, nor_g1_idx)
        nor_g1 = self.connect_to_tracks([nor_gn1_warr, nor_gp1_warr],
                                        nor_g1_tid,
                                        min_len_mode=0)

        # connect nor_n0 and nor_n1
        self.connect_to_tracks([nor_p0_ports['d'], nor_p1_ports['s']],
                               pdrain_id,
                               min_len_mode=0)

        self.connect_to_substrate('ptap',
                                  [nor_n0_ports['s'], nor_n1_ports['s']])
        self.connect_to_substrate('ntap', nor_p0_ports['s'])

        # connect drain to output
        o = self.connect_to_tracks(
            [nor_n0_ports['d'], nor_n1_ports['d'], nor_p1_ports['d']],
            nout_id,
            min_len_mode=0)

        # add pins
        self.add_pin('A', nor_g0, show=show_pins)
        self.add_pin('B', nor_g1, show=show_pins)
        self.add_pin('O', o, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(
            vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size
        self.size = self.set_size_from_array_box(m5v_layer)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()
        self._sch_params = dict(
            lch=lch,
            wn=wn,
            wp=wp,
            nfn=nfn,
            nfp=nfp,
            intent=intent,
            dum_info=dum_info,
            debug=debug,
        )
Esempio n. 7
0
    def _draw_layout_helper(self, lch, wn, wp, nf_inv0, nf_inv1, nf_inv2,
                            nf_inv3, nf_tinv0_0, nf_tinv0_1, nf_tinv1_0,
                            nf_tinv1_1, nf_tinv2_0, nf_tinv2_1, nf_tinv3_0,
                            nf_tinv3_1, ptap_w, ntap_w, g_width_ntr,
                            ds_width_ntr, intent, ndum, ndum_side, show_pins,
                            g_space, ds_space, power_width_ntr, debug,
                            **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # TODO: assumption1 -- all nmos/pmos have same finger number
        # TODO: assumption2 -- all nmos/pmos finger number are even

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nf_inv0%2 != 0 or nf_inv1%2 != 0 or nf_inv2%2 != 0 or nf_inv3%2 != 0 or \
            nf_tinv0_0%2 != 0 or nf_tinv1_0%2 != 0 or nf_tinv2_0%2 != 0 or nf_tinv3_0%2 != 0 or \
            nf_tinv0_1%2 != 0 or nf_tinv1_1%2 != 0 or nf_tinv2_1%2 != 0 or nf_tinv3_1%2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = ndum_side*2 + ndum*11 + nf_inv0 + nf_inv1 + nf_inv2 + nf_inv3 + \
                 nf_tinv0_0 + nf_tinv1_0 + nf_tinv2_0 + nf_tinv3_0 + \
                 nf_tinv0_1 + nf_tinv1_1 + nf_tinv2_1 + nf_tinv3_1 + 2

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr * 2 + g_sp_ntr + g_space]
        pg_tracks = [g_width_ntr * 2 + g_sp_ntr + g_space]
        nds_tracks = [ds_width_ntr * 2 + ds_sp_ntr + ds_space]
        pds_tracks = [ds_width_ntr * 2 + ds_sp_ntr + ds_space]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=p_orientation,
        )

        # get gate and drain index
        ck_id = self.make_track_id('nch', 0, 'g', 0, width=1)
        ckb_id = self.make_track_id('pch', 0, 'g', 0, width=1)
        ngate_id = self.make_track_id('nch', 0, 'g', 1, width=1)
        pgate_id = self.make_track_id('pch', 0, 'g', 1, width=1)
        nout_id = self.make_track_id('nch', 0, 'ds', 1, width=1)
        pout_id = self.make_track_id('pch', 0, 'ds', 1, width=1)
        ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1)
        pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1)

        # Step1: connect inverter
        # group transistors
        # inv2
        inv2_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side,
                                          nf_inv2,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='iclkb')
        inv2_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side,
                                          nf_inv2,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='iclkb')
        # inv3
        inv3_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side + ndum + nf_inv2,
                                          nf_inv3,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='iclk')
        inv3_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side + ndum + nf_inv2,
                                          nf_inv3,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='iclk')
        # tinv0
        tinv0_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            ndum_side + ndum * 2 + nf_inv2 +
                                            nf_inv3,
                                            nf_tinv0_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv0_ns')
        tinv0_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            ndum_side + ndum * 2 + nf_inv2 +
                                            nf_inv3,
                                            nf_tinv0_0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv0_ps')
        col_idx = ndum_side + ndum * 3 + nf_inv2 + nf_inv3 + nf_tinv0_0 + 2
        tinv0_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv0_1,
                                            1,
                                            1,
                                            s_net='tinv0_ns',
                                            d_net='mem1')
        tinv0_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv0_1,
                                            1,
                                            1,
                                            s_net='tinv0_ps',
                                            d_net='mem1')
        # inv0
        col_idx = ndum_side + ndum * 4 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + 2
        inv0_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          col_idx,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='latch')
        inv0_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          col_idx,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='latch')
        # tinv1
        col_idx = ndum_side + ndum * 5 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + 2
        tinv1_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv1_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv1_ns')
        tinv1_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv1_0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv1_ps')
        col_idx = ndum_side + ndum * 6 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 +\
                  nf_tinv1_0 + 2
        tinv1_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv1_1,
                                            1,
                                            1,
                                            s_net='tinv1_ns',
                                            d_net='mem1')
        tinv1_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv1_1,
                                            1,
                                            1,
                                            s_net='tinv1_ps',
                                            d_net='mem1')
        # tinv2
        col_idx = ndum_side + ndum * 7 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \
                  nf_tinv1_0 + nf_tinv1_1 + 2
        tinv2_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv2_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv2_ns')
        tinv2_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv2_0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv2_ps')
        col_idx = ndum_side + ndum * 8 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \
                  nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + 2
        tinv2_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv2_1,
                                            1,
                                            1,
                                            s_net='tinv2_ns',
                                            d_net='mem2')
        tinv2_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv2_1,
                                            1,
                                            1,
                                            s_net='tinv2_ps',
                                            d_net='mem2')
        # inv1
        col_idx = ndum_side + ndum * 9 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \
                  nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + nf_tinv2_1 + 2
        inv1_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          col_idx,
                                          nf_inv1,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='o')
        inv1_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          col_idx,
                                          nf_inv1,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='o')
        # tinv3
        col_idx = ndum_side + ndum * 10 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \
                  nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + nf_tinv2_1 + nf_inv1 + 2
        tinv3_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv3_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv3_ns')
        tinv3_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv3_0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv3_ps')
        col_idx = ndum_side + ndum * 11 + nf_inv2 + nf_inv3 + nf_tinv0_0 + nf_tinv0_1 + nf_inv0 + \
                  nf_tinv1_0 + nf_tinv1_1 + nf_tinv2_0 + nf_tinv2_1 + nf_inv1 + nf_tinv3_0 + 2
        tinv3_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv3_1,
                                            1,
                                            1,
                                            s_net='tinv3_ns',
                                            d_net='mem2')
        tinv3_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv3_1,
                                            1,
                                            1,
                                            s_net='tinv3_ps',
                                            d_net='mem2')

        # connect inv2, inv3 (clock buffers)
        # inv2
        inv2_n_warr = self.connect_to_tracks(inv2_n_ports['g'],
                                             ngate_id,
                                             min_len_mode=0)
        inv2_p_warr = self.connect_to_tracks(inv2_p_ports['g'],
                                             pgate_id,
                                             min_len_mode=0)
        inv2_idx = self.grid.coord_to_nearest_track(inv2_n_warr.layer_id + 1,
                                                    inv2_n_warr.middle)
        inv2_tid = TrackID(inv2_n_warr.layer_id + 1, inv2_idx)
        clk = self.connect_to_tracks([inv2_n_warr, inv2_p_warr], inv2_tid)

        self.connect_to_substrate('ptap', inv2_n_ports['s'])
        self.connect_to_substrate('ntap', inv2_p_ports['s'])

        # inv3
        inv3_n_warr = self.connect_to_tracks(inv3_n_ports['g'],
                                             ngate_id,
                                             min_len_mode=0)
        inv3_p_warr = self.connect_to_tracks(inv3_p_ports['g'],
                                             pgate_id,
                                             min_len_mode=0)
        inv3_idx = self.grid.coord_to_nearest_track(inv3_n_warr.layer_id + 1,
                                                    inv3_n_warr.middle)
        inv3_tid = TrackID(inv3_n_warr.layer_id + 1, inv3_idx)
        inv3_g_wire = self.connect_to_tracks([inv3_n_warr, inv3_p_warr],
                                             inv3_tid)
        self.connect_to_tracks(
            [inv2_n_ports['d'], inv2_p_ports['d'], inv3_g_wire], pout_id)
        iclkb = inv3_g_wire

        self.connect_to_substrate('ptap', inv3_n_ports['s'])
        self.connect_to_substrate('ntap', inv3_p_ports['s'])

        inv3_d_wire = self.connect_to_tracks(
            [inv3_n_ports['d'], inv3_p_ports['d']], nout_id, min_len_mode=0)
        iclk_idx = self.grid.coord_to_nearest_track(inv3_d_wire.layer_id + 1,
                                                    inv3_d_wire.lower)
        iclk_tid = TrackID(inv3_d_wire.layer_id + 1, iclk_idx)
        iclk = self.connect_to_tracks(inv3_d_wire, iclk_tid)

        # tinv0
        i_n_warr = self.connect_to_tracks(tinv0_n0_ports['g'],
                                          ngate_id,
                                          min_len_mode=0)
        i_p_warr = self.connect_to_tracks(tinv0_p0_ports['g'],
                                          pgate_id,
                                          min_len_mode=0)
        i_idx = self.grid.coord_to_nearest_track(i_n_warr.layer_id + 1,
                                                 i_n_warr.middle)
        i_tid = TrackID(i_n_warr.layer_id + 1, i_idx)
        i = self.connect_to_tracks([i_n_warr, i_p_warr], i_tid)

        self.connect_to_substrate('ptap', tinv0_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv0_p0_ports['s'])

        self.connect_to_tracks([tinv0_n0_ports['d'], tinv0_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv0_p0_ports['d'], tinv0_p1_ports['s']],
                               pdrain_id)

        # inv0
        inv0_gn_warr = self.connect_to_tracks(inv0_n_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        inv0_gp_warr = self.connect_to_tracks(inv0_p_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        inv0_g_idx = self.grid.coord_to_nearest_track(
            inv0_gn_warr.layer_id + 1, inv0_gn_warr.middle)
        inv0_g_tid = TrackID(inv0_gn_warr.layer_id + 1, inv0_g_idx)
        inv0_g = self.connect_to_tracks([inv0_gn_warr, inv0_gp_warr],
                                        inv0_g_tid)
        # mem1 = self.connect_to_tracks([tinv0_n1_ports['d'], tinv0_p1_ports['d'], inv0_g], nout_id)

        self.connect_to_substrate('ptap', inv0_n_ports['s'])
        self.connect_to_substrate('ntap', inv0_p_ports['s'])

        # tinv1
        tinv1_gn_warr = self.connect_to_tracks(tinv1_n0_ports['g'],
                                               ngate_id,
                                               min_len_mode=0)
        tinv1_gp_warr = self.connect_to_tracks(tinv1_p0_ports['g'],
                                               pgate_id,
                                               min_len_mode=0)
        tinv1_g_idx = self.grid.coord_to_nearest_track(
            tinv1_gn_warr.layer_id + 1, tinv1_gn_warr.middle)
        tinv1_g_tid = TrackID(tinv1_gn_warr.layer_id + 1, tinv1_g_idx)
        tinv1_g = self.connect_to_tracks([tinv1_gn_warr, tinv1_gp_warr],
                                         tinv1_g_tid)
        # latch = self.connect_to_tracks([inv0_n_ports['d'], inv0_p_ports['d'], tinv1_g], nout_id)

        self.connect_to_tracks([tinv1_n0_ports['d'], tinv1_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv1_p0_ports['d'], tinv1_p1_ports['s']],
                               pdrain_id)

        self.connect_to_substrate('ptap', tinv1_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv1_p0_ports['s'])

        mem1 = self.connect_to_tracks([
            tinv0_n1_ports['d'], tinv0_p1_ports['d'], inv0_g,
            tinv1_n1_ports['d'], tinv1_p1_ports['d']
        ], pout_id)

        # tinv2
        tinv2_gn_warr = self.connect_to_tracks(tinv2_n0_ports['g'],
                                               ngate_id,
                                               min_len_mode=0)
        tinv2_gp_warr = self.connect_to_tracks(tinv2_p0_ports['g'],
                                               pgate_id,
                                               min_len_mode=0)
        tinv2_g_idx = self.grid.coord_to_nearest_track(
            tinv2_gn_warr.layer_id + 1, tinv2_gn_warr.middle)
        tinv2_g_tid = TrackID(tinv2_gn_warr.layer_id + 1, tinv2_g_idx)
        tinv2_g = self.connect_to_tracks([tinv2_gn_warr, tinv2_gp_warr],
                                         tinv2_g_tid)
        latch = self.connect_to_tracks(
            [inv0_n_ports['d'], inv0_p_ports['d'], tinv1_g, tinv2_g], nout_id)

        self.connect_to_substrate('ptap', tinv2_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv2_p0_ports['s'])

        self.connect_to_tracks([tinv2_n0_ports['d'], tinv2_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv2_p0_ports['d'], tinv2_p1_ports['s']],
                               pdrain_id)

        # inv1
        inv1_gn_warr = self.connect_to_tracks(inv1_n_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        inv1_gp_warr = self.connect_to_tracks(inv1_p_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        inv1_g_idx = self.grid.coord_to_nearest_track(
            inv1_gn_warr.layer_id + 1, inv1_gn_warr.middle)
        inv1_g_tid = TrackID(inv1_gn_warr.layer_id + 1, inv1_g_idx)
        inv1_g = self.connect_to_tracks([inv1_gn_warr, inv1_gp_warr],
                                        inv1_g_tid)

        self.connect_to_substrate('ptap', inv1_n_ports['s'])
        self.connect_to_substrate('ntap', inv1_p_ports['s'])

        # tinv3
        tinv3_gn_warr = self.connect_to_tracks(tinv3_n0_ports['g'],
                                               ngate_id,
                                               min_len_mode=0)
        tinv3_gp_warr = self.connect_to_tracks(tinv3_p0_ports['g'],
                                               pgate_id,
                                               min_len_mode=0)
        tinv3_g_idx = self.grid.coord_to_nearest_track(
            tinv3_gn_warr.layer_id + 1, tinv3_gn_warr.middle)
        tinv3_g_tid = TrackID(tinv3_gn_warr.layer_id + 1, tinv3_g_idx)
        tinv3_g = self.connect_to_tracks([tinv3_gn_warr, tinv3_gp_warr],
                                         tinv3_g_tid)
        self.connect_to_tracks([inv1_n_ports['d'], inv1_p_ports['d'], tinv3_g],
                               nout_id)
        o = tinv3_g

        self.connect_to_tracks([tinv3_n0_ports['d'], tinv3_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv3_p0_ports['d'], tinv3_p1_ports['s']],
                               pdrain_id)

        self.connect_to_substrate('ptap', tinv3_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv3_p0_ports['s'])

        mem2 = self.connect_to_tracks([
            tinv2_n1_ports['d'], tinv2_p1_ports['d'], inv1_g,
            tinv3_n1_ports['d'], tinv3_p1_ports['d']
        ], pout_id)

        # connect iclk, iclkb
        tinv0_gn1 = self.connect_to_tracks(tinv0_n1_ports['g'],
                                           ngate_id,
                                           min_len_mode=0)
        tinv0_gn1_idx = self.grid.coord_to_nearest_track(
            tinv0_gn1.layer_id + 1, tinv0_gn1.lower)
        tinv0_gn1_tid = TrackID(tinv0_gn1.layer_id + 1, tinv0_gn1_idx)
        tinv0_gn1 = self.connect_to_tracks(tinv0_gn1, tinv0_gn1_tid)

        tinv0_gp1 = self.connect_to_tracks(tinv0_p1_ports['g'],
                                           pgate_id,
                                           min_len_mode=0)
        tinv0_gp1_idx = self.grid.coord_to_nearest_track(
            tinv0_gp1.layer_id + 1, tinv0_gp1.upper)
        tinv0_gp1_tid = TrackID(tinv0_gp1.layer_id + 1, tinv0_gp1_idx)
        tinv0_gp1 = self.connect_to_tracks(tinv0_gp1, tinv0_gp1_tid)

        tinv1_gn1 = self.connect_to_tracks(tinv1_n1_ports['g'],
                                           ngate_id,
                                           min_len_mode=0)
        tinv1_gn1_idx = self.grid.coord_to_nearest_track(
            tinv1_gn1.layer_id + 1, tinv1_gn1.middle)
        tinv1_gn1_tid = TrackID(tinv1_gn1.layer_id + 1, tinv1_gn1_idx)
        tinv1_gn1 = self.connect_to_tracks(tinv1_gn1, tinv1_gn1_tid)

        tinv1_gp1 = self.connect_to_tracks(tinv1_p1_ports['g'],
                                           pgate_id,
                                           min_len_mode=0)
        tinv1_gp1_idx = self.grid.coord_to_nearest_track(
            tinv1_gp1.layer_id + 1, tinv1_gp1.upper)
        tinv1_gp1_tid = TrackID(tinv1_gp1.layer_id + 1, tinv1_gp1_idx)
        tinv1_gp1 = self.connect_to_tracks(tinv1_gp1, tinv1_gp1_tid)

        tinv2_gn1 = self.connect_to_tracks(tinv2_n1_ports['g'],
                                           ngate_id,
                                           min_len_mode=0)
        tinv2_gn1_idx = self.grid.coord_to_nearest_track(
            tinv2_gn1.layer_id + 1, tinv2_gn1.middle)
        tinv2_gn1_tid = TrackID(tinv2_gn1.layer_id + 1, tinv2_gn1_idx)
        tinv2_gn1 = self.connect_to_tracks(tinv2_gn1, tinv2_gn1_tid)

        tinv2_gp1 = self.connect_to_tracks(tinv2_p1_ports['g'],
                                           pgate_id,
                                           min_len_mode=0)
        tinv2_gp1_idx = self.grid.coord_to_nearest_track(
            tinv2_gp1.layer_id + 1, tinv2_gp1.upper)
        tinv2_gp1_tid = TrackID(tinv2_gp1.layer_id + 1, tinv2_gp1_idx)
        tinv2_gp1 = self.connect_to_tracks(tinv2_gp1, tinv2_gp1_tid)

        tinv3_gn1 = self.connect_to_tracks(tinv3_n1_ports['g'],
                                           ngate_id,
                                           min_len_mode=0)
        tinv3_gn1_idx = self.grid.coord_to_nearest_track(
            tinv3_gn1.layer_id + 1, tinv3_gn1.middle)
        tinv3_gn1_tid = TrackID(tinv3_gn1.layer_id + 1, tinv3_gn1_idx)
        tinv3_gn1 = self.connect_to_tracks(tinv3_gn1, tinv3_gn1_tid)

        tinv3_gp1 = self.connect_to_tracks(tinv3_p1_ports['g'],
                                           pgate_id,
                                           min_len_mode=0)
        tinv3_gp1_idx = self.grid.coord_to_nearest_track(
            tinv3_gp1.layer_id + 1, tinv3_gp1.upper)
        tinv3_gp1_tid = TrackID(tinv3_gp1.layer_id + 1,
                                tinv3_gp1_idx + 1)  # to avoid short
        tinv3_gp1 = self.connect_to_tracks(tinv3_gp1, tinv3_gp1_tid)

        self.connect_to_tracks(
            [tinv0_gp1, tinv1_gn1, tinv2_gn1, tinv3_gp1, iclk], ck_id)
        self.connect_to_tracks(
            [tinv0_gn1, tinv1_gp1, tinv2_gp1, tinv3_gn1, iclkb], ckb_id)

        # add pins
        self.add_pin('CLK', clk, show=show_pins)
        self.add_pin('I', i, show=show_pins)
        self.add_pin('O', o, show=show_pins)
        if debug is True:
            self.add_pin('latch', latch, show=show_pins)
            self.add_pin('iclk', iclk, show=show_pins)
            self.add_pin('iclkb', iclkb, show=show_pins)
            self.add_pin('mem1', mem1, show=show_pins)
            self.add_pin('mem2', mem2, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(
            vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size
        self.size = self.grid.get_size_tuple(m5v_layer,
                                             width=self.bound_box.width,
                                             height=self.bound_box.height,
                                             round_up=True)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()

        self._sch_params = dict(
            lch=lch,
            wn=wn,
            wp=wp,
            nf_inv0=nf_inv0,
            nf_inv1=nf_inv1,
            nf_inv2=nf_inv2,
            nf_inv3=nf_inv3,
            nf_tinv0_0=nf_tinv0_0,
            nf_tinv0_1=nf_tinv0_1,
            nf_tinv1_0=nf_tinv1_0,
            nf_tinv1_1=nf_tinv1_1,
            nf_tinv2_0=nf_tinv2_0,
            nf_tinv2_1=nf_tinv2_1,
            nf_tinv3_0=nf_tinv3_0,
            nf_tinv3_1=nf_tinv3_1,
            intent=intent,
            dum_info=dum_info,
            debug=debug,
        )
Esempio n. 8
0
    def _draw_layout_helper(self, lch, wn, wp, nf_inv0, nf_inv1, nf_inv2,
                            nf_inv3, nf_tinv0_0, nf_tinv0_1, nf_tinv1_0,
                            nf_tinv1_1, nfn_nand0, nfp_nand0, nfn_nand1,
                            nfp_nand1, nfn_nand2, nfp_nand2, nfn_nand3,
                            nfp_nand3, nf_tgate0, nf_tgate1, ptap_w, ntap_w,
                            g_width_ntr, ds_width_ntr, intent, ndum, ndum_side,
                            show_pins, power_width_ntr, debug, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # TODO: assumption1 -- all nmos/pmos have same finger number
        # TODO: assumption2 -- all nmos/pmos finger number are even

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nf_inv0%2 != 0 or nf_inv1%2 != 0 or nf_inv2%2 != 0 or nf_inv3%2 != 0 or \
            nf_tinv0_0%2 != 0 or nf_tinv1_0%2 != 0 or nf_tinv0_1%2 != 0 or nf_tinv1_1%2 != 0 or\
            nfn_nand0%2 != 0 or nfp_nand0%2 != 0 or nfn_nand1%2 != 0 or nfp_nand1%2 != 0 or\
            nfn_nand2%2 != 0 or nfp_nand2%2 != 0 or nfn_nand3%2 != 0 or nfp_nand3%2 != 0 or\
            nf_tgate0%2 != 0 or nf_tgate1%2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = ndum_side*2 + ndum*17 + nf_inv0 + nf_inv1 + nf_inv2 + nf_inv3 + \
                 nf_tinv0_0 + nf_tinv0_1 + nf_tinv1_0 + nf_tinv1_1 + \
                 max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                 max(nfn_nand2, nfp_nand2) * 2 + max(nfn_nand3, nfp_nand3) * 2 + \
                 nf_tgate0 + nf_tgate1 + 2

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr * 3 + g_sp_ntr * 2]
        pg_tracks = [g_width_ntr * 3 + g_sp_ntr * 2]
        nds_tracks = [ds_width_ntr * 2 + ds_sp_ntr]
        pds_tracks = [ds_width_ntr * 2 + ds_sp_ntr]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=p_orientation,
        )

        # get gate and drain index
        ck_id = self.make_track_id('nch', 0, 'g', 1, width=1)
        ckb_id = self.make_track_id('pch', 0, 'g', 1, width=1)
        ngate_id = self.make_track_id('nch', 0, 'g', 2, width=1)
        pgate_id = self.make_track_id('pch', 0, 'g', 2, width=1)
        nout_id = self.make_track_id('nch', 0, 'ds', 1, width=1)
        pout_id = self.make_track_id('pch', 0, 'ds', 1, width=1)
        ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1)
        pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1)
        st_id = self.make_track_id('nch', 0, 'g', 0, width=1)
        rst_id = self.make_track_id('pch', 0, 'g', 0, width=1)

        # Step1: connect inverter
        # group transistors
        # inv2
        inv2_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side,
                                          nf_inv2,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='stb')
        inv2_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side,
                                          nf_inv2,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='stb')
        # inv3
        inv3_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side + ndum + nf_inv2,
                                          nf_inv3,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='rstb')
        inv3_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side + ndum + nf_inv2,
                                          nf_inv3,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='rstb')
        # inv0
        col_idx = ndum_side + ndum * 2 + nf_inv2 + nf_inv3
        inv0_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          col_idx,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='iclkb')
        inv0_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          col_idx,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='iclkb')
        # inv1
        col_idx = ndum_side + ndum * 3 + nf_inv2 + nf_inv3 + nf_inv0
        inv1_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          col_idx,
                                          nf_inv1,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='iclk')
        inv1_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          col_idx,
                                          nf_inv1,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='iclk')
        # tinv0
        col_idx = ndum_side + ndum * 4 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1
        tinv0_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv0_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv0_ns')
        tinv0_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv0_0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv0_ps')
        col_idx = ndum_side + ndum * 5 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + 2  # for drc
        tinv0_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv0_1,
                                            1,
                                            1,
                                            s_net='tinv0_ns',
                                            d_net='mem1')
        tinv0_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv0_1,
                                            1,
                                            1,
                                            s_net='tinv0_ps',
                                            d_net='mem1')
        # nand0
        col_idx = ndum_side + ndum * 6 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + 2
        nand0_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='nand0_ns')
        nand0_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='latch')
        col_idx = ndum_side + ndum * 7 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) + 2
        nand0_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand0,
                                            1,
                                            1,
                                            s_net='nand0_ns',
                                            d_net='latch')
        nand0_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='latch')
        # nand1
        col_idx = ndum_side + ndum * 8 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + 2
        nand1_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand1,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='nand1_ns')
        nand1_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand1,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='rstm1')
        col_idx = ndum_side + ndum * 9 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) + 2
        nand1_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand1,
                                            1,
                                            1,
                                            s_net='nand1_ns',
                                            d_net='rstm1')
        nand1_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand1,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='rstm1')
        # tgate0
        col_idx = ndum_side + ndum * 10 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + 2
        tgate0_n_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tgate0,
                                            1,
                                            1,
                                            s_net='rstm1',
                                            d_net='mem1')
        tgate0_p_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tgate0,
                                            1,
                                            1,
                                            s_net='rstm1',
                                            d_net='mem1')

        # tinv1
        col_idx = ndum_side + ndum * 11 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                  nf_tgate0 + 2
        tinv1_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv1_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv1_ns')
        tinv1_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv1_0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv1_ps')
        col_idx = ndum_side + ndum * 12 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                  nf_tgate0 + nf_tinv1_0 + 2
        tinv1_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv1_1,
                                            1,
                                            1,
                                            s_net='tinv1_ns',
                                            d_net='mem2')
        tinv1_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv1_1,
                                            1,
                                            1,
                                            s_net='tinv1_ps',
                                            d_net='mem2')
        # nand2
        col_idx = ndum_side + ndum * 13 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                  nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + 2
        nand2_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand2,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='nand2_ns')
        nand2_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand2,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='O')
        col_idx = ndum_side + ndum * 14 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                  nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) + 2
        nand2_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand2,
                                            1,
                                            1,
                                            s_net='nand2_ns',
                                            d_net='O')
        nand2_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand2,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='O')
        # nand3
        col_idx = ndum_side + ndum * 15 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                  nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) * 2 + 2
        nand3_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand3,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='nand3_ns')
        nand3_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand3,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='rstm2')
        col_idx = ndum_side + ndum * 16 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                  nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) * 2 +\
                  max(nfn_nand3, nfp_nand3) + 2
        nand3_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nfn_nand3,
                                            1,
                                            1,
                                            s_net='nand3_ns',
                                            d_net='rstm2')
        nand3_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nfp_nand3,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='rstm2')
        # tgate1
        col_idx = ndum_side + ndum * 17 + nf_inv2 + nf_inv3 + nf_inv0 + nf_inv1 + nf_tinv0_0 + \
                  nf_tinv0_1 + max(nfn_nand0, nfp_nand0) * 2 + max(nfn_nand1, nfp_nand1) * 2 + \
                  nf_tgate0 + nf_tinv1_0 + nf_tinv1_1 + max(nfn_nand2, nfp_nand2) * 2 + \
                  max(nfn_nand3, nfp_nand3) * 2 + 2
        tgate1_n_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tgate1,
                                            1,
                                            1,
                                            s_net='rstm2',
                                            d_net='mem2')
        tgate1_p_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tgate1,
                                            1,
                                            1,
                                            s_net='rstm2',
                                            d_net='mem2')

        # connect inv2, inv3 (rst, st buffers)
        # inv2
        inv2_n_warr = self.connect_to_tracks(inv2_n_ports['g'],
                                             ngate_id,
                                             min_len_mode=0)
        inv2_p_warr = self.connect_to_tracks(inv2_p_ports['g'],
                                             pgate_id,
                                             min_len_mode=0)
        inv2_idx = self.grid.coord_to_nearest_track(inv2_n_warr.layer_id + 1,
                                                    inv2_n_warr.middle)
        inv2_tid = TrackID(inv2_n_warr.layer_id + 1, inv2_idx)
        st = self.connect_to_tracks([inv2_n_warr, inv2_p_warr], inv2_tid)

        self.connect_to_substrate('ptap', inv2_n_ports['s'])
        self.connect_to_substrate('ntap', inv2_p_ports['s'])

        inv2_d_wire = self.connect_to_tracks(
            [inv2_n_ports['d'], inv2_p_ports['d']], nout_id, min_len_mode=0)
        stb_idx = self.grid.coord_to_nearest_track(inv2_d_wire.layer_id + 1,
                                                   inv2_d_wire.lower)
        stb_tid = TrackID(inv2_d_wire.layer_id + 1, stb_idx)
        stb = self.connect_to_tracks(inv2_d_wire, stb_tid, min_len_mode=0)

        # inv3
        inv3_n_warr = self.connect_to_tracks(inv3_n_ports['g'],
                                             ngate_id,
                                             min_len_mode=0)
        inv3_p_warr = self.connect_to_tracks(inv3_p_ports['g'],
                                             pgate_id,
                                             min_len_mode=0)
        inv3_idx = self.grid.coord_to_nearest_track(inv3_n_warr.layer_id + 1,
                                                    inv3_n_warr.middle)
        inv3_tid = TrackID(inv3_n_warr.layer_id + 1, inv3_idx)
        rst = self.connect_to_tracks([inv3_n_warr, inv3_p_warr], inv3_tid)

        self.connect_to_substrate('ptap', inv3_n_ports['s'])
        self.connect_to_substrate('ntap', inv3_p_ports['s'])

        inv3_d_wire = self.connect_to_tracks(
            [inv3_n_ports['d'], inv3_p_ports['d']], nout_id)
        rstb_idx = self.grid.coord_to_nearest_track(inv3_d_wire.layer_id + 1,
                                                    inv3_d_wire.upper)
        rstb_tid = TrackID(inv3_d_wire.layer_id + 1, rstb_idx + 1)
        rstb = self.connect_to_tracks(inv3_d_wire, rstb_tid)

        # connect inv0, inv1 (clock buffer)
        # inv0
        inv0_n_warr = self.connect_to_tracks(inv0_n_ports['g'],
                                             ngate_id,
                                             min_len_mode=0)
        inv0_p_warr = self.connect_to_tracks(inv0_p_ports['g'],
                                             pgate_id,
                                             min_len_mode=0)
        inv0_idx = self.grid.coord_to_nearest_track(inv0_n_warr.layer_id + 1,
                                                    inv0_n_warr.middle)
        inv0_tid = TrackID(inv0_n_warr.layer_id + 1, inv0_idx)
        clk = self.connect_to_tracks([inv0_n_warr, inv0_p_warr], inv0_tid)

        self.connect_to_substrate('ptap', inv0_n_ports['s'])
        self.connect_to_substrate('ntap', inv0_p_ports['s'])

        # inv1
        inv1_n_warr = self.connect_to_tracks(inv1_n_ports['g'],
                                             ngate_id,
                                             min_len_mode=0)
        inv1_p_warr = self.connect_to_tracks(inv1_p_ports['g'],
                                             pgate_id,
                                             min_len_mode=0)
        inv1_idx = self.grid.coord_to_nearest_track(inv1_n_warr.layer_id + 1,
                                                    inv1_n_warr.middle)
        inv1_tid = TrackID(inv1_n_warr.layer_id + 1, inv1_idx)
        inv1_g_wire = self.connect_to_tracks([inv1_n_warr, inv1_p_warr],
                                             inv1_tid)
        self.connect_to_tracks(
            [inv0_n_ports['d'], inv0_p_ports['d'], inv1_g_wire], pout_id)
        iclkb = inv1_g_wire

        self.connect_to_substrate('ptap', inv1_n_ports['s'])
        self.connect_to_substrate('ntap', inv1_p_ports['s'])

        inv1_d_wire = self.connect_to_tracks(
            [inv1_n_ports['d'], inv1_p_ports['d']], nout_id)
        iclk_idx = self.grid.coord_to_nearest_track(inv1_d_wire.layer_id + 1,
                                                    inv1_d_wire.upper)
        iclk_tid = TrackID(inv1_d_wire.layer_id + 1, iclk_idx + 1)
        iclk = self.connect_to_tracks(inv1_d_wire, iclk_tid)

        # tinv0
        i_n_warr = self.connect_to_tracks(tinv0_n0_ports['g'],
                                          ngate_id,
                                          min_len_mode=0)
        i_p_warr = self.connect_to_tracks(tinv0_p0_ports['g'],
                                          pgate_id,
                                          min_len_mode=0)
        i_idx = self.grid.coord_to_nearest_track(i_n_warr.layer_id + 1,
                                                 i_n_warr.middle)
        i_tid = TrackID(i_n_warr.layer_id + 1, i_idx)
        i = self.connect_to_tracks([i_n_warr, i_p_warr], i_tid)

        self.connect_to_substrate('ptap', tinv0_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv0_p0_ports['s'])

        self.connect_to_tracks([tinv0_n0_ports['d'], tinv0_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv0_p0_ports['d'], tinv0_p1_ports['s']],
                               pdrain_id)

        # nand0
        nand0_gn0_warr = self.connect_to_tracks(nand0_n0_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand0_gp0_warr = self.connect_to_tracks(nand0_p0_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand0_g0_idx = self.grid.coord_to_nearest_track(
            nand0_gn0_warr.layer_id + 1, nand0_gn0_warr.middle)
        nand0_g0_tid = TrackID(nand0_gn0_warr.layer_id + 1, nand0_g0_idx)
        nand0_g0 = self.connect_to_tracks([nand0_gn0_warr, nand0_gp0_warr],
                                          nand0_g0_tid)

        # # connect nand0_g0
        # self.connect_to_tracks([tinv0_n1_ports['d'], tinv0_p1_ports['d'], nand0_g0], nout_id)
        # connect nand_n0 and nand_n1
        self.connect_to_tracks([nand0_n0_ports['d'], nand0_n1_ports['s']],
                               ndrain_id)

        self.connect_to_substrate('ptap', nand0_n0_ports['s'])
        self.connect_to_substrate('ntap',
                                  [nand0_p0_ports['s'], nand0_p1_ports['s']])

        # # connect drain to output
        # self.connect_to_tracks([nand0_p0_ports['d'], nand0_p1_ports['d'], nand0_n1_ports['d']], nout_id)

        # nand1
        nand1_gn0_warr = self.connect_to_tracks(nand1_n0_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand1_gp0_warr = self.connect_to_tracks(nand1_p0_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand1_g0_idx = self.grid.coord_to_nearest_track(
            nand1_gn0_warr.layer_id + 1, nand1_gn0_warr.middle)
        nand1_g0_tid = TrackID(nand1_gn0_warr.layer_id + 1, nand1_g0_idx)
        nand1_g0 = self.connect_to_tracks([nand1_gn0_warr, nand1_gp0_warr],
                                          nand1_g0_tid)
        # connect nand_n0 and nand_n1
        self.connect_to_tracks([nand1_n0_ports['d'], nand1_n1_ports['s']],
                               ndrain_id)

        self.connect_to_substrate('ptap', nand1_n0_ports['s'])
        self.connect_to_substrate('ntap',
                                  [nand1_p0_ports['s'], nand1_p1_ports['s']])

        # tgate0
        # connect nand1 drain to tgage drain
        rstm1 = self.connect_to_tracks([
            nand1_p0_ports['d'], nand1_p1_ports['d'], nand1_n1_ports['d'],
            tgate0_n_ports['s'], tgate0_p_ports['s']
        ], pdrain_id)

        # connect tgate0 drain, tinv0_n1/p1 drain and nand
        mem1 = self.connect_to_tracks([
            tgate0_n_ports['d'], tgate0_p_ports['d'], tinv0_n1_ports['d'],
            tinv0_p1_ports['d'], nand0_g0
        ], nout_id)

        # tinv1
        tinv1_ng0_warr = self.connect_to_tracks(tinv1_n0_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        tinv1_pg0_warr = self.connect_to_tracks(tinv1_p0_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        tinv1_g0_idx = self.grid.coord_to_nearest_track(
            tinv1_ng0_warr.layer_id + 1, tinv1_ng0_warr.middle)
        tinv1_g0_tid = TrackID(tinv1_ng0_warr.layer_id + 1, tinv1_g0_idx)
        tinv1_g0 = self.connect_to_tracks([tinv1_ng0_warr, tinv1_pg0_warr],
                                          tinv1_g0_tid)
        latch = self.connect_to_tracks([
            nand0_n1_ports['d'], nand0_p0_ports['d'], nand0_p1_ports['d'],
            nand1_g0, tinv1_g0
        ], pout_id)

        self.connect_to_substrate('ptap', tinv1_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv1_p0_ports['s'])

        self.connect_to_tracks([tinv1_n0_ports['d'], tinv1_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv1_p0_ports['d'], tinv1_p1_ports['s']],
                               pdrain_id)

        # nand2
        nand2_gn0_warr = self.connect_to_tracks(nand2_n0_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand2_gp0_warr = self.connect_to_tracks(nand2_p0_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand2_g0_idx = self.grid.coord_to_nearest_track(
            nand2_gn0_warr.layer_id + 1, nand2_gn0_warr.middle)
        nand2_g0_tid = TrackID(nand2_gn0_warr.layer_id + 1, nand2_g0_idx)
        nand2_g0 = self.connect_to_tracks([nand2_gn0_warr, nand2_gp0_warr],
                                          nand2_g0_tid)

        # # connect nand2_g0
        # self.connect_to_tracks([tinv0_n1_ports['d'], tinv0_p1_ports['d'], nand2_g0], nout_id)
        # connect nand_n0 and nand_n1
        self.connect_to_tracks([nand2_n0_ports['d'], nand2_n1_ports['s']],
                               ndrain_id)

        self.connect_to_substrate('ptap', nand2_n0_ports['s'])
        self.connect_to_substrate('ntap',
                                  [nand2_p0_ports['s'], nand2_p1_ports['s']])

        # # connect drain to output
        # self.connect_to_tracks([nand0_p0_ports['d'], nand0_p1_ports['d'], nand0_n1_ports['d']], nout_id)

        # nand3
        nand3_gn0_warr = self.connect_to_tracks(nand3_n0_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand3_gp0_warr = self.connect_to_tracks(nand3_p0_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand3_g0_idx = self.grid.coord_to_nearest_track(
            nand3_gn0_warr.layer_id + 1, nand3_gn0_warr.middle)
        nand3_g0_tid = TrackID(nand3_gn0_warr.layer_id + 1, nand3_g0_idx)
        nand3_g0 = self.connect_to_tracks([nand3_gn0_warr, nand3_gp0_warr],
                                          nand3_g0_tid)

        # connect nand3_n0 and nand3_n1
        self.connect_to_tracks([nand3_n0_ports['d'], nand3_n1_ports['s']],
                               ndrain_id)

        self.connect_to_substrate('ptap', nand3_n0_ports['s'])
        self.connect_to_substrate('ntap',
                                  [nand3_p0_ports['s'], nand3_p1_ports['s']])

        # tgate1
        # connect nand3 drain to tgate drain
        rstm2 = self.connect_to_tracks([
            nand3_p0_ports['d'], nand3_p1_ports['d'], nand3_n1_ports['d'],
            tgate1_n_ports['s'], tgate1_p_ports['s']
        ], pdrain_id)

        # connect tgate1 drain, tinv1_n1/p1 drain and nand2 gate
        mem2 = self.connect_to_tracks([
            tgate1_n_ports['d'], tgate1_p_ports['d'], tinv1_n1_ports['d'],
            tinv1_p1_ports['d'], nand2_g0
        ], nout_id)

        # connect nand2 drain and nand3 gate
        o = self.connect_to_tracks([
            nand2_n1_ports['d'], nand2_p0_ports['d'], nand2_p1_ports['d'],
            nand3_g0
        ], pout_id)

        # connect stb, rstb
        nand0_gn1_warr = self.connect_to_tracks(nand0_n1_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand0_gp1_warr = self.connect_to_tracks(nand0_p1_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand0_g1_idx = self.grid.coord_to_nearest_track(
            nand0_gn1_warr.layer_id + 1, nand0_gn1_warr.middle)
        nand0_g1_tid = TrackID(nand0_gn1_warr.layer_id + 1, nand0_g1_idx)
        nand0_g1 = self.connect_to_tracks([nand0_gn1_warr, nand0_gp1_warr],
                                          nand0_g1_tid,
                                          min_len_mode=0)

        nand1_gn1_warr = self.connect_to_tracks(nand1_n1_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand1_gp1_warr = self.connect_to_tracks(nand1_p1_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand1_g1_idx = self.grid.coord_to_nearest_track(
            nand1_gn1_warr.layer_id + 1, nand1_gn1_warr.middle)
        nand1_g1_tid = TrackID(nand1_gn1_warr.layer_id + 1, nand1_g1_idx)
        nand1_g1 = self.connect_to_tracks([nand1_gn1_warr, nand1_gp1_warr],
                                          nand1_g1_tid,
                                          min_len_mode=0)

        nand2_gn1_warr = self.connect_to_tracks(nand2_n1_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand2_gp1_warr = self.connect_to_tracks(nand2_p1_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand2_g1_idx = self.grid.coord_to_nearest_track(
            nand2_gn1_warr.layer_id + 1, nand2_gn1_warr.middle)
        nand2_g1_tid = TrackID(nand2_gn1_warr.layer_id + 1, nand2_g1_idx)
        nand2_g1 = self.connect_to_tracks([nand2_gn1_warr, nand2_gp1_warr],
                                          nand2_g1_tid,
                                          min_len_mode=0)

        nand3_gn1_warr = self.connect_to_tracks(nand3_n1_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        nand3_gp1_warr = self.connect_to_tracks(nand3_p1_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        nand3_g1_idx = self.grid.coord_to_nearest_track(
            nand3_gn1_warr.layer_id + 1, nand3_gn1_warr.middle)
        nand3_g1_tid = TrackID(nand3_gn1_warr.layer_id + 1, nand3_g1_idx)
        nand3_g1 = self.connect_to_tracks([nand3_gn1_warr, nand3_gp1_warr],
                                          nand3_g1_tid,
                                          min_len_mode=0)

        stb = self.connect_to_tracks([nand0_g1, nand2_g1, stb], st_id)
        rstb = self.connect_to_tracks([nand1_g1, nand3_g1, rstb], rst_id)

        # connect iclk, iclkb
        tinv0_gn1 = self.connect_to_tracks(tinv0_n1_ports['g'],
                                           ngate_id,
                                           min_len_mode=0)
        tinv0_gn1_idx = self.grid.coord_to_nearest_track(
            tinv0_gn1.layer_id + 1, tinv0_gn1.lower)
        tinv0_gn1_tid = TrackID(tinv0_gn1.layer_id + 1, tinv0_gn1_idx)
        tinv0_gn1 = self.connect_to_tracks(tinv0_gn1, tinv0_gn1_tid)

        tinv0_gp1 = self.connect_to_tracks(tinv0_p1_ports['g'],
                                           pgate_id,
                                           min_len_mode=0)
        tinv0_gp1_idx = self.grid.coord_to_nearest_track(
            tinv0_gp1.layer_id + 1, tinv0_gp1.upper)
        tinv0_gp1_tid = TrackID(tinv0_gp1.layer_id + 1, tinv0_gp1_idx)
        tinv0_gp1 = self.connect_to_tracks(tinv0_gp1, tinv0_gp1_tid)

        tinv1_gn1 = self.connect_to_tracks(tinv1_n1_ports['g'],
                                           ngate_id,
                                           min_len_mode=0)
        tinv1_gn1_idx = self.grid.coord_to_nearest_track(
            tinv1_gn1.layer_id + 1, tinv1_gn1.middle)
        tinv1_gn1_tid = TrackID(tinv1_gn1.layer_id + 1, tinv1_gn1_idx)
        tinv1_gn1 = self.connect_to_tracks(tinv1_gn1, tinv1_gn1_tid)

        tinv1_gp1 = self.connect_to_tracks(tinv1_p1_ports['g'],
                                           pgate_id,
                                           min_len_mode=0)
        tinv1_gp1_idx = self.grid.coord_to_nearest_track(
            tinv1_gp1.layer_id + 1, tinv1_gp1.upper)
        tinv1_gp1_tid = TrackID(tinv1_gp1.layer_id + 1, tinv1_gp1_idx)
        tinv1_gp1 = self.connect_to_tracks(tinv1_gp1, tinv1_gp1_tid)

        # tgate0
        tgate0_gn = self.connect_to_tracks(tgate0_n_ports['g'],
                                           ngate_id,
                                           min_len_mode=0)
        tgate0_gn_idx = self.grid.coord_to_nearest_track(
            tgate0_gn.layer_id + 1, tgate0_gn.middle)
        tgate0_gn_tid = TrackID(tgate0_gn.layer_id + 1, tgate0_gn_idx)
        tgate0_n = self.connect_to_tracks(tgate0_gn, tgate0_gn_tid)
        tgate0_gp = self.connect_to_tracks(tgate0_p_ports['g'],
                                           pgate_id,
                                           min_len_mode=0)
        tgate0_gp_idx = self.grid.coord_to_nearest_track(
            tgate0_gp.layer_id + 1, tgate0_gp.upper)
        tgate0_gp_tid = TrackID(tgate0_gp.layer_id + 1, tgate0_gp_idx)
        tgate0_p = self.connect_to_tracks(tgate0_gp, tgate0_gp_tid)

        # tgate1
        tgate1_gn = self.connect_to_tracks([tgate1_n_ports['g']],
                                           ngate_id,
                                           min_len_mode=0)
        tgate1_gn_idx = self.grid.coord_to_nearest_track(
            tgate1_gn.layer_id + 1, tgate1_gn.middle)
        tgate1_gn_tid = TrackID(tgate1_gn.layer_id + 1, tgate1_gn_idx)
        tgate1_n = self.connect_to_tracks(tgate1_gn, tgate1_gn_tid)
        tgate1_gp = self.connect_to_tracks([tgate1_p_ports['g']],
                                           pgate_id,
                                           min_len_mode=0)
        tgate1_gp_idx = self.grid.coord_to_nearest_track(
            tgate1_gp.layer_id + 1, tgate1_gp.upper)
        tgate1_gp_tid = TrackID(tgate1_gp.layer_id + 1, tgate1_gp_idx + 1)
        tgate1_p = self.connect_to_tracks(tgate1_gp, tgate1_gp_tid)

        self.connect_to_tracks(
            [tinv0_gp1, tinv1_gn1, tgate0_n, tgate1_p, iclk], ck_id)
        self.connect_to_tracks(
            [tinv0_gn1, tinv1_gp1, tgate0_p, tgate1_n, iclkb], ckb_id)

        # add pins
        self.add_pin('CLK', clk, show=show_pins)
        self.add_pin('ST', st, show=show_pins)
        self.add_pin('RST', rst, show=show_pins)
        self.add_pin('I', i, show=show_pins)
        self.add_pin('O', [o, nand3_g0], show=show_pins)
        if debug is True:
            # test signals
            self.add_pin('latch', latch, show=show_pins)
            self.add_pin('mem1', mem1, show=show_pins)
            self.add_pin('mem2', mem2, show=show_pins)
            self.add_pin('rstm1', rstm1, show=show_pins)
            self.add_pin('rstm2', rstm2, show=show_pins)
            self.add_pin('iclk', iclk, show=show_pins)
            self.add_pin('iclkb', iclkb, show=show_pins)
            self.add_pin('stb', stb, show=show_pins)
            self.add_pin('rstb', rstb, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(
            vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size
        self.size = self.grid.get_size_tuple(m5v_layer,
                                             width=self.bound_box.width,
                                             height=self.bound_box.height,
                                             round_up=True)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()

        self._sch_params = dict(
            lch=lch,
            wn=wn,
            wp=wp,
            nf_inv0=nf_inv0,
            nf_inv1=nf_inv1,
            nf_inv2=nf_inv3,
            nf_inv3=nf_inv3,
            nf_tinv0_0=nf_tinv0_0,
            nf_tinv0_1=nf_tinv0_1,
            nf_tinv1_0=nf_tinv1_0,
            nf_tinv1_1=nf_tinv1_1,
            nfn_nand0=nfn_nand0,
            nfp_nand0=nfp_nand0,
            nfn_nand1=nfn_nand1,
            nfp_nand1=nfp_nand1,
            nfn_nand2=nfn_nand2,
            nfp_nand2=nfp_nand2,
            nfn_nand3=nfn_nand3,
            nfp_nand3=nfp_nand3,
            nf_tgate0=nf_tgate0,
            nf_tgate1=nf_tgate1,
            intent=intent,
            dum_info=dum_info,
            debug=debug,
        )
Esempio n. 9
0
    def _draw_layout_helper(self, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        lch = self.params['lch']
        wn = self.params['wn']
        wp = self.params['wp']
        nfn_inv = self.params['nfn_inv']
        nfp_inv = self.params['nfp_inv']
        nfn_tinv0 = self.params['nfn_tinv0']
        nfp_tinv0 = self.params['nfp_tinv0']
        nfn_tinv1 = self.params['nfn_tinv1']
        nfp_tinv1 = self.params['nfp_tinv1']
        ndum = self.params['ndum']
        intent = self.params['intent']
        ptap_w = self.params['ptap_w']
        ntap_w = self.params['ntap_w']
        g_width_ntr = self.params['g_width_ntr']
        ds_width_ntr = self.params['ds_width_ntr']
        show_pins = self.params['show_pins']

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nfn_inv%2 != 0 or nfp_inv%2 != 0 or nfn_tinv0%2 != 0 or nfn_tinv1%2 != 0 or\
            nfp_tinv0%2 != 0 or nfp_tinv1%2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = ndum * 4 + max(nfn_inv, nfp_inv) + max(
            nfn_tinv0, nfp_tinv0) + max(nfn_tinv1, nfp_tinv1)

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr]
        pg_tracks = [g_width_ntr]
        nds_tracks = [ds_width_ntr * 2]
        pds_tracks = [ds_width_ntr * 2]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=p_orientation,
        )

        # get gate and drain index
        ngate_id = self.make_track_id('nch', 0, 'g', 0, width=g_width_ntr)
        pgate_id = self.make_track_id('pch', 0, 'g', 0, width=g_width_ntr)
        out_id = self.make_track_id('nch', 0, 'ds', 1, width=ds_width_ntr)
        ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr)
        pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=ds_width_ntr)

        # Step1: connect inverter
        # group transistors
        inv_n_ports = self.draw_mos_conn('nch', 0, ndum, nfn_inv, 1, 1)
        inv_p_ports = self.draw_mos_conn('pch', 0, ndum, nfp_inv, 1, 1)

        # connect gate
        ng_inv_warr = self.connect_to_tracks(inv_n_ports['g'], ngate_id)
        pg_inv_warr = self.connect_to_tracks(inv_p_ports['g'], pgate_id)
        # connect gate vertically
        vgate_idx = self.grid.coord_to_nearest_track(m5v_layer,
                                                     ng_inv_warr.lower)
        vgate_tid = TrackID(m5v_layer, vgate_idx)
        inv_in_warr = self.connect_to_tracks([ng_inv_warr, pg_inv_warr],
                                             vgate_tid)
        # connect drain
        inv_d_warr = self.connect_to_tracks(
            [inv_n_ports['d'], inv_p_ports['d']], out_id)
        # connect gate
        self.connect_to_substrate('ptap', inv_n_ports['s'])
        self.connect_to_substrate('ntap', inv_p_ports['s'])

        # Step2: connect tri-inverter
        nf_inv = max(nfn_inv, nfp_inv)
        nf_tinv0 = max(nfn_tinv0, nfp_tinv0)
        # group transistors
        tinv0_n_ports = self.draw_mos_conn('nch', 0, nf_inv + 2 * ndum,
                                           nfn_tinv0, 1, 1)
        tinv0_p_ports = self.draw_mos_conn('pch', 0, nf_inv + 2 * ndum,
                                           nfp_tinv0, 1, 1)
        tinv1_n_ports = self.draw_mos_conn('nch', 0,
                                           nf_tinv0 + nf_inv + 3 * ndum,
                                           nfn_tinv1, 1, 1)
        tinv1_p_ports = self.draw_mos_conn('pch', 0,
                                           nf_tinv0 + nf_inv + 3 * ndum,
                                           nfp_tinv1, 1, 1)

        # connect top/bottom MOSs
        # connect gate
        ng_tinv0_warr = self.connect_to_tracks(tinv0_n_ports['g'], ngate_id)
        pg_tinv0_warr = self.connect_to_tracks(tinv0_p_ports['g'], pgate_id)
        # connect gate vertically
        vgate_idx = self.grid.coord_to_nearest_track(m5v_layer,
                                                     ng_tinv0_warr.lower)
        vgate_tid = TrackID(m5v_layer, vgate_idx)
        # also connect inverter drain
        tinv0_g_warr = self.connect_to_tracks(
            [inv_d_warr, ng_tinv0_warr, pg_tinv0_warr], vgate_tid)

        # connect middle MOSs
        ng_tinv1_warr = self.connect_to_tracks(tinv1_n_ports['g'], ngate_id)
        pg_tinv1_warr = self.connect_to_tracks(tinv1_p_ports['g'], pgate_id)
        # connect source
        ns_tinv0_warr = self.connect_to_tracks(
            [tinv0_n_ports['d'], tinv1_n_ports['s']], ndrain_id)
        ps_tinv0_warr = self.connect_to_tracks(
            [tinv0_p_ports['d'], tinv1_p_ports['s']], pdrain_id)
        # connect drain
        tinv_out_warr = self.connect_to_tracks(
            [tinv1_n_ports['d'], tinv1_p_ports['d']], out_id)
        # connect source
        self.connect_to_substrate('ptap', tinv0_n_ports['s'])
        self.connect_to_substrate('ntap', tinv0_p_ports['s'])

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy()

        # add pins
        self.add_pin('clk_i', inv_in_warr)
        self.add_pin('clk_o', tinv_out_warr)
        self.add_pin('ctrl', ng_tinv1_warr)
        self.add_pin('ctrl_b', pg_tinv1_warr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size
        self.size = self.set_size_from_array_box(m5v_layer)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()
        dum_nmos = dum_info[0][1]
        dum_pmos = dum_info[1][1]
        print(dum_info)
        self._sch_params = dict(
            lch=self.params['lch'],
            wn=self.params['wn'],
            wp=self.params['wp'],
            nf_inv=self.params['nfn_inv'],
            nfp_inv=self.params['nfp_inv'],
            nfn_tinv0=self.params['nfn_tinv0'],
            nfp_tinv0=self.params['nfp_tinv0'],
            nfn_tinv1=self.params['nfn_tinv1'],
            nfp_tinv1=self.params['nfp_tinv1'],
            intent=self.params['intent'],
            dum_n0=dum_nmos - 2,
            dum_n1=2,
            dum_p0=dum_pmos - 2,
            dum_p1=2,
        )
Esempio n. 10
0
    def _draw_layout_helper(self, lch, wn, wp, nf_inv0, nf_tinv_0, nf_tinv_1,
                            nf_inv2, ptap_w, ntap_w, g_width_ntr, ds_width_ntr,
                            intent, ndum, ndum_side, g_space, ds_space,
                            show_pins, power_width_ntr, debug, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # TODO: assumption1 -- all nmos/pmos have same finger number
        # TODO: assumption2 -- all nmos/pmos finger number are even

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nf_inv0 % 2 != 0 or nf_tinv_0 % 2 != 0 or nf_tinv_1 % 2 != 0 or nf_inv2 % 2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = ndum_side * 2 + ndum * 6 + nf_inv0 * 2 + nf_tinv_0 * 2 + nf_tinv_1 * 2 + nf_inv2 + 2

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr * 2 + g_space]
        pg_tracks = [g_width_ntr * 2 + g_space]
        nds_tracks = [ds_width_ntr * 2 + ds_space]
        pds_tracks = [ds_width_ntr * 2 + ds_space]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=p_orientation,
        )

        # get gate and drain index
        seli_id = self.make_track_id('nch', 0, 'g', 0, width=1)
        selib_id = self.make_track_id('pch', 0, 'g', 0, width=1)
        ngate_id = self.make_track_id('nch', 0, 'g', 1, width=1)
        pgate_id = self.make_track_id('pch', 0, 'g', 1, width=1)
        nout_id = self.make_track_id('nch', 0, 'ds', 1, width=1)
        pout_id = self.make_track_id('pch', 0, 'ds', 1, width=1)
        ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1)
        pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1)

        # Step1: connect inverter
        # group transistors
        # inv0
        inv0_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='sel_ib')
        inv0_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='sel_ib')
        # inv1
        inv1_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side + ndum + nf_inv0,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='sel_i')
        inv1_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side + ndum + nf_inv0,
                                          nf_inv0,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='sel_i')
        # xor logic
        tinv0_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            ndum_side + ndum * 2 + nf_inv0 * 2,
                                            nf_tinv_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv0_ns')
        tinv0_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            ndum_side + ndum * 2 + nf_inv0 * 2,
                                            nf_tinv_0,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv0_ps')
        tinv0_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            ndum_side + ndum * 3 +
                                            nf_inv0 * 2 + nf_tinv_0,
                                            nf_tinv_1,
                                            1,
                                            1,
                                            s_net='tinv0_ns',
                                            d_net='mux_b')
        tinv0_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            ndum_side + ndum * 3 +
                                            nf_inv0 * 2 + nf_tinv_0,
                                            nf_tinv_1,
                                            1,
                                            1,
                                            s_net='tinv0_ps',
                                            d_net='mxu_b')
        col_idx = ndum_side + ndum * 4 + nf_inv0 * 2 + nf_tinv_0 + nf_tinv_1
        tinv1_n0_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv_0,
                                            1,
                                            1,
                                            s_net='VSS',
                                            d_net='tinv1_ns')
        tinv1_p0_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv_1,
                                            1,
                                            1,
                                            s_net='VDD',
                                            d_net='tinv1_ps')
        col_idx = ndum_side + ndum * 5 + nf_inv0 * 2 + nf_tinv_0 * 2 + nf_tinv_1 + 2  # 1 to pass drc
        tinv1_n1_ports = self.draw_mos_conn('nch',
                                            0,
                                            col_idx,
                                            nf_tinv_1,
                                            1,
                                            1,
                                            s_net='tinv1_ns',
                                            d_net='mux_b')
        tinv1_p1_ports = self.draw_mos_conn('pch',
                                            0,
                                            col_idx,
                                            nf_tinv_1,
                                            1,
                                            1,
                                            s_net='tinv1_ps',
                                            d_net='mux_b')
        col_idx = ndum_side + ndum * 6 + nf_inv0 * 2 + nf_tinv_0 * 2 + nf_tinv_1 * 2 + 2
        inv2_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          col_idx,
                                          nf_inv2,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='o')
        inv2_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          col_idx,
                                          nf_inv2,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='o')

        # connect inv0, inv1 (buffers)
        # inv0
        inv0_gn_warr = self.connect_to_tracks(inv0_n_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        inv0_gp_warr = self.connect_to_tracks(inv0_p_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        inv0_g_idx = self.grid.coord_to_nearest_track(
            inv0_gn_warr.layer_id + 1, inv0_gn_warr.lower)
        inv0_g_tid = TrackID(inv0_gn_warr.layer_id + 1, inv0_g_idx)
        sel = self.connect_to_tracks([inv0_gn_warr, inv0_gp_warr], inv0_g_tid)
        # inv0 drain
        sel_ib = self.connect_to_tracks([inv0_n_ports['d'], inv0_p_ports['d']],
                                        nout_id)
        # inv0 source
        self.connect_to_substrate('ptap', inv0_n_ports['s'])
        self.connect_to_substrate('ntap', inv0_p_ports['s'])

        # inv1
        inv1_gn_warr = self.connect_to_tracks(inv1_n_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        inv1_gp_warr = self.connect_to_tracks(inv1_p_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        inv1_g_idx = self.grid.coord_to_nearest_track(
            inv1_gn_warr.layer_id + 1, inv1_gn_warr.middle)
        inv1_g_tid = TrackID(inv1_gn_warr.layer_id + 1, inv1_g_idx)
        # inv0 drain, inv1 gate
        sel_ib = self.connect_to_tracks([inv1_gn_warr, inv1_gp_warr, sel_ib],
                                        inv1_g_tid)
        # inv1 source
        self.connect_to_substrate('ptap', inv1_n_ports['s'])
        self.connect_to_substrate('ntap', inv1_p_ports['s'])
        # inv1 drain
        sel_i = self.connect_to_tracks([inv1_n_ports['d'], inv1_p_ports['d']],
                                       pout_id,
                                       min_len_mode=0)
        sel_i_idx = self.grid.coord_to_nearest_track(sel_i.layer_id + 1,
                                                     sel_i.upper)
        sel_i_tid = TrackID(sel_i.layer_id + 1, sel_i_idx + 1)
        sel_i = self.connect_to_tracks(sel_i, sel_i_tid)

        # tinv0 MOSs
        # tinv0_0 gate
        tinv0_gn0_warr = self.connect_to_tracks(tinv0_n0_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        tinv0_gp0_warr = self.connect_to_tracks(tinv0_p0_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        tinv0_g0_idx = self.grid.coord_to_nearest_track(
            tinv0_gn0_warr.layer_id + 1, tinv0_gn0_warr.middle)
        tinv0_g0_tid = TrackID(tinv0_gn0_warr.layer_id + 1, tinv0_g0_idx)
        i0 = self.connect_to_tracks([tinv0_gn0_warr, tinv0_gp0_warr],
                                    tinv0_g0_tid)
        # tinv0_1 NMOS gate
        tinv0_gn1_warr = self.connect_to_tracks(tinv0_n1_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        tinv0_gn1_idx = self.grid.coord_to_nearest_track(
            tinv0_gn1_warr.layer_id + 1, tinv0_gn1_warr.middle)
        tinv0_gn1_tid = TrackID(tinv0_gn1_warr.layer_id + 1, tinv0_gn1_idx)
        tinv0_gn1 = self.connect_to_tracks(tinv0_gn1_warr, tinv0_gn1_tid)
        # tinv0_1 PMOS gate
        tinv0_gp1_warr = self.connect_to_tracks(tinv0_p1_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        tinv0_gp1_idx = self.grid.coord_to_nearest_track(
            tinv0_gp1_warr.layer_id + 1, tinv0_gp1_warr.upper)
        tinv0_gp1_tid = TrackID(tinv0_gp1_warr.layer_id + 1, tinv0_gp1_idx)
        tinv0_gp1 = self.connect_to_tracks(tinv0_gp1_warr, tinv0_gp1_tid)
        # tinv0_0 source
        self.connect_to_substrate('ptap', tinv0_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv0_p0_ports['s'])
        # tinv0_0 drain and tinv0_1 source
        self.connect_to_tracks([tinv0_n0_ports['d'], tinv0_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv0_p0_ports['d'], tinv0_p1_ports['s']],
                               pdrain_id)
        # tinv0 output
        tinv0_d = self.connect_to_tracks(
            [tinv0_n1_ports['d'], tinv0_p1_ports['d']], nout_id)

        # tinv1 MOSs
        tinv1_gn0_warr = self.connect_to_tracks(tinv1_n0_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        tinv1_gp0_warr = self.connect_to_tracks(tinv1_p0_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        tinv1_g0_idx = self.grid.coord_to_nearest_track(
            tinv1_gn0_warr.layer_id + 1, tinv1_gn0_warr.middle)
        tinv1_g0_tid = TrackID(tinv1_gn0_warr.layer_id + 1, tinv1_g0_idx)
        i1 = self.connect_to_tracks([tinv1_gn0_warr, tinv1_gp0_warr],
                                    tinv1_g0_tid)
        # tinv1_1 NMOS gate
        tinv1_gn1_warr = self.connect_to_tracks(tinv1_n1_ports['g'],
                                                ngate_id,
                                                min_len_mode=0)
        tinv1_gn1_idx = self.grid.coord_to_nearest_track(
            tinv1_gn1_warr.layer_id + 1, tinv1_gn1_warr.lower)
        tinv1_gn1_tid = TrackID(tinv1_gn1_warr.layer_id + 1, tinv1_gn1_idx)
        tinv1_gn1 = self.connect_to_tracks(tinv1_gn1_warr, tinv1_gn1_tid)
        # tinv1_1 PMOS gate
        tinv1_gp1_warr = self.connect_to_tracks(tinv1_p1_ports['g'],
                                                pgate_id,
                                                min_len_mode=0)
        tinv1_gp1_idx = self.grid.coord_to_nearest_track(
            tinv1_gp1_warr.layer_id + 1, tinv1_gp1_warr.upper)
        tinv1_gp1_tid = TrackID(tinv1_gp1_warr.layer_id + 1, tinv1_gp1_idx)
        tinv1_gp1 = self.connect_to_tracks(tinv1_gp1_warr, tinv1_gp1_tid)
        # tinv1_0 source
        self.connect_to_substrate('ptap', tinv1_n0_ports['s'])
        self.connect_to_substrate('ntap', tinv1_p0_ports['s'])
        # tinv1_0 drain and tinv1_1 source
        self.connect_to_tracks([tinv1_n0_ports['d'], tinv1_n1_ports['s']],
                               ndrain_id)
        self.connect_to_tracks([tinv1_p0_ports['d'], tinv1_p1_ports['s']],
                               pdrain_id)
        # tinv1 output
        tinv1_d = self.connect_to_tracks(
            [tinv1_n1_ports['d'], tinv1_p1_ports['d']], nout_id)

        # inv2
        inv2_gn_warr = self.connect_to_tracks(inv2_n_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        inv2_gp_warr = self.connect_to_tracks(inv2_p_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        inv2_g_idx = self.grid.coord_to_nearest_track(
            inv2_gn_warr.layer_id + 1, inv2_gn_warr.middle)
        inv2_g_tid = TrackID(inv2_gn_warr.layer_id + 1, inv2_g_idx)
        mux_b = self.connect_to_tracks(
            [inv2_gn_warr, inv2_gp_warr, tinv0_d, tinv1_d], inv2_g_tid)
        # inv2 source
        self.connect_to_substrate('ptap', inv2_n_ports['s'])
        self.connect_to_substrate('ntap', inv2_p_ports['s'])
        # inv2 drain
        o = self.connect_to_tracks([inv2_n_ports['d'], inv2_p_ports['d']],
                                   pout_id,
                                   min_len_mode=1)

        # connect mux control
        sel_i = self.connect_to_tracks([sel_i, tinv0_gp1, tinv1_gn1], selib_id)
        sel_ib = self.connect_to_tracks([sel_ib, tinv0_gn1, tinv1_gp1],
                                        seli_id)

        # # get upper metal index
        # self._upper_idx = seli_id.base_index

        # add pins
        self.add_pin('i0', i0, show=show_pins)
        self.add_pin('i1', i1, show=show_pins)
        self.add_pin('sel', sel, show=show_pins)
        self.add_pin('o', o, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(
            vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size
        self.size = self.grid.get_size_tuple(m5v_layer,
                                             width=self.bound_box.width,
                                             height=self.bound_box.height,
                                             round_up=True)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()
        self._sch_params = dict(
            lch=lch,
            wn=wn,
            wp=wp,
            nf_inv0=nf_inv0,
            nf_tinv_0=nf_tinv_0,
            nf_tinv_1=nf_tinv_1,
            nf_inv2=nf_inv2,
            intent=intent,
            dum_info=dum_info,
            debug=debug,
        )
Esempio n. 11
0
    def _draw_layout_helper(self, lch, wn, wp, nf_inv, nf_xnor, ptap_w, ntap_w,
                            g_width_ntr, ds_width_ntr, intent, ndum, ndum_side,
                            g_space, ds_space, show_pins, power_width_ntr,
                            debug, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # TODO: assumption1 -- all nmos/pmos have same finger number
        # TODO: assumption2 -- all nmos/pmos finger number are even

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nf_inv % 2 != 0 or nf_xnor % 2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = ndum_side * 2 + ndum * 5 + nf_inv * 2 + nf_xnor * 4

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr * 3 + g_sp_ntr + g_space]
        pg_tracks = [g_width_ntr * 3 + g_sp_ntr + g_space]
        nds_tracks = [ds_width_ntr * 2 + ds_space]
        pds_tracks = [ds_width_ntr * 2 + ds_space]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=p_orientation,
        )

        # get gate and drain index
        a_id = self.make_track_id('nch', 0, 'g', 0, width=1)
        ab_id = self.make_track_id('nch', 0, 'g', 1, width=1)
        b_id = self.make_track_id('pch', 0, 'g', 0, width=1)
        bb_id = self.make_track_id('pch', 0, 'g', 1, width=1)
        ngate_id = self.make_track_id('nch', 0, 'g', 2, width=1)
        pgate_id = self.make_track_id('pch', 0, 'g', 2, width=1)
        nout_id = self.make_track_id('nch', 0, 'ds', 0, width=1)
        pout_id = self.make_track_id('pch', 0, 'ds', 0, width=1)
        out_id = self.make_track_id('nch', 0, 'ds', 1, width=1)

        # Step1: connect inverter
        # group transistors
        # inv0
        inv0_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side,
                                          nf_inv,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='a_b')
        inv0_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side,
                                          nf_inv,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='a_b')
        # inv1
        inv1_n_ports = self.draw_mos_conn('nch',
                                          0,
                                          ndum_side + ndum + nf_inv,
                                          nf_inv,
                                          1,
                                          1,
                                          s_net='VSS',
                                          d_net='b_b')
        inv1_p_ports = self.draw_mos_conn('pch',
                                          0,
                                          ndum_side + ndum + nf_inv,
                                          nf_inv,
                                          1,
                                          1,
                                          s_net='VDD',
                                          d_net='b_b')
        # xnor logic
        xnor0_n_ports = self.draw_mos_conn('nch',
                                           0,
                                           ndum_side + ndum * 2 + nf_inv * 2,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='VSS',
                                           d_net='ns0')
        xnor0_p_ports = self.draw_mos_conn('pch',
                                           0,
                                           ndum_side + ndum * 2 + nf_inv * 2,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='VDD',
                                           d_net='ps0')
        xnor1_n_ports = self.draw_mos_conn('nch',
                                           0,
                                           ndum_side + ndum * 3 + nf_inv * 2 +
                                           nf_xnor,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='ns0',
                                           d_net='o')
        xnor1_p_ports = self.draw_mos_conn('pch',
                                           0,
                                           ndum_side + ndum * 3 + nf_inv * 2 +
                                           nf_xnor,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='ps0',
                                           d_net='o')
        xnor2_n_ports = self.draw_mos_conn('nch',
                                           0,
                                           ndum_side + ndum * 4 + nf_inv * 2 +
                                           nf_xnor * 2,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='VSS',
                                           d_net='ns1')
        xnor2_p_ports = self.draw_mos_conn('pch',
                                           0,
                                           ndum_side + ndum * 4 + nf_inv * 2 +
                                           nf_xnor * 2,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='VDD',
                                           d_net='ps1')
        xnor3_n_ports = self.draw_mos_conn('nch',
                                           0,
                                           ndum_side + ndum * 5 + nf_inv * 2 +
                                           nf_xnor * 3,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='ns1',
                                           d_net='o')
        xnor3_p_ports = self.draw_mos_conn('pch',
                                           0,
                                           ndum_side + ndum * 5 + nf_inv * 2 +
                                           nf_xnor * 3,
                                           nf_xnor,
                                           1,
                                           1,
                                           s_net='ps1',
                                           d_net='o')

        # connect inv2, inv3 (clock buffers)
        # inv0
        inv0_gn_warr = self.connect_to_tracks(inv0_n_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        inv0_gp_warr = self.connect_to_tracks(inv0_p_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        inv0_g_idx = self.grid.coord_to_nearest_track(
            inv0_gn_warr.layer_id + 1, inv0_gn_warr.lower)
        inv0_g_tid = TrackID(inv0_gn_warr.layer_id + 1, inv0_g_idx)
        a = self.connect_to_tracks([inv0_gn_warr, inv0_gp_warr], inv0_g_tid)

        inv0_dn_warr = self.connect_to_tracks(inv0_n_ports['d'],
                                              nout_id,
                                              min_len_mode=0)
        inv0_dp_warr = self.connect_to_tracks(inv0_p_ports['d'],
                                              pout_id,
                                              min_len_mode=0)
        inv0_d_idx = self.grid.coord_to_nearest_track(
            inv0_dn_warr.layer_id + 1, inv0_dn_warr.upper)
        inv0_d_tid = TrackID(inv0_dn_warr.layer_id + 1, inv0_d_idx)
        a_b = self.connect_to_tracks([inv0_dn_warr, inv0_dp_warr], inv0_d_tid)

        self.connect_to_substrate('ptap', inv0_n_ports['s'])
        self.connect_to_substrate('ntap', inv0_p_ports['s'])

        # inv1
        inv1_gn_warr = self.connect_to_tracks(inv1_n_ports['g'],
                                              ngate_id,
                                              min_len_mode=0)
        inv1_gp_warr = self.connect_to_tracks(inv1_p_ports['g'],
                                              pgate_id,
                                              min_len_mode=0)
        inv1_g_idx = self.grid.coord_to_nearest_track(
            inv1_gn_warr.layer_id + 1, inv1_gn_warr.lower)
        inv1_g_tid = TrackID(inv1_gn_warr.layer_id + 1, inv1_g_idx)
        b = self.connect_to_tracks([inv1_gn_warr, inv1_gp_warr], inv1_g_tid)

        inv1_dn_warr = self.connect_to_tracks(inv1_n_ports['d'],
                                              nout_id,
                                              min_len_mode=0)
        inv1_dp_warr = self.connect_to_tracks(inv1_p_ports['d'],
                                              pout_id,
                                              min_len_mode=0)
        inv1_d_idx = self.grid.coord_to_nearest_track(
            inv1_dn_warr.layer_id + 1, inv1_dn_warr.upper)
        inv1_d_tid = TrackID(inv1_dn_warr.layer_id + 1, inv1_d_idx)
        b_b = self.connect_to_tracks([inv1_dn_warr, inv1_dp_warr], inv1_d_tid)

        self.connect_to_substrate('ptap', inv1_n_ports['s'])
        self.connect_to_substrate('ntap', inv1_p_ports['s'])

        # xnor MOSs
        xnor0_gn_warr = self.connect_to_tracks(xnor0_n_ports['g'],
                                               ngate_id,
                                               min_len_mode=0)
        xnor0_gn_idx = self.grid.coord_to_nearest_track(
            xnor0_gn_warr.layer_id + 1, xnor0_gn_warr.lower)
        xnor0_gn_tid = TrackID(xnor0_gn_warr.layer_id + 1, xnor0_gn_idx)
        xnor0_n = self.connect_to_tracks(xnor0_gn_warr, xnor0_gn_tid)

        xnor0_gp_warr = self.connect_to_tracks(xnor0_p_ports['g'],
                                               pgate_id,
                                               min_len_mode=0)
        xnor0_gp_idx = self.grid.coord_to_nearest_track(
            xnor0_gp_warr.layer_id + 1, xnor0_gp_warr.upper)
        xnor0_gp_tid = TrackID(xnor0_gp_warr.layer_id + 1, xnor0_gp_idx)
        xnor0_p = self.connect_to_tracks(xnor0_gp_warr, xnor0_gp_tid)

        xnor1_gn_warr = self.connect_to_tracks(xnor1_n_ports['g'],
                                               ngate_id,
                                               min_len_mode=0)
        xnor1_gn_idx = self.grid.coord_to_nearest_track(
            xnor1_gn_warr.layer_id + 1, xnor1_gn_warr.lower)
        xnor1_gn_tid = TrackID(xnor1_gn_warr.layer_id + 1, xnor1_gn_idx)
        xnor1_n = self.connect_to_tracks(xnor1_gn_warr, xnor1_gn_tid)

        xnor1_gp_warr = self.connect_to_tracks(xnor1_p_ports['g'],
                                               pgate_id,
                                               min_len_mode=0)
        xnor1_gp_idx = self.grid.coord_to_nearest_track(
            xnor1_gp_warr.layer_id + 1, xnor1_gp_warr.upper)
        xnor1_gp_tid = TrackID(xnor1_gp_warr.layer_id + 1, xnor1_gp_idx)
        xnor1_p = self.connect_to_tracks(xnor1_gp_warr, xnor1_gp_tid)

        xnor2_gn_warr = self.connect_to_tracks(xnor2_n_ports['g'],
                                               ngate_id,
                                               min_len_mode=0)
        xnor2_gn_idx = self.grid.coord_to_nearest_track(
            xnor2_gn_warr.layer_id + 1, xnor2_gn_warr.lower)
        xnor2_gn_tid = TrackID(xnor2_gn_warr.layer_id + 1, xnor2_gn_idx)
        xnor2_n = self.connect_to_tracks(xnor2_gn_warr, xnor2_gn_tid)

        xnor2_gp_warr = self.connect_to_tracks(xnor2_p_ports['g'],
                                               pgate_id,
                                               min_len_mode=0)
        xnor2_gp_idx = self.grid.coord_to_nearest_track(
            xnor2_gp_warr.layer_id + 1, xnor2_gp_warr.upper)
        xnor2_gp_tid = TrackID(xnor2_gp_warr.layer_id + 1, xnor2_gp_idx)
        xnor2_p = self.connect_to_tracks(xnor2_gp_warr, xnor2_gp_tid)

        xnor3_gn_warr = self.connect_to_tracks(xnor3_n_ports['g'],
                                               ngate_id,
                                               min_len_mode=0)
        xnor3_gn_idx = self.grid.coord_to_nearest_track(
            xnor3_gn_warr.layer_id + 1, xnor3_gn_warr.lower)
        xnor3_gn_tid = TrackID(xnor3_gn_warr.layer_id + 1, xnor3_gn_idx)
        xnor3_n = self.connect_to_tracks(xnor3_gn_warr, xnor3_gn_tid)

        xnor3_gp_warr = self.connect_to_tracks(xnor3_p_ports['g'],
                                               pgate_id,
                                               min_len_mode=0)
        xnor3_gp_idx = self.grid.coord_to_nearest_track(
            xnor3_gp_warr.layer_id + 1, xnor3_gp_warr.upper)
        xnor3_gp_tid = TrackID(xnor3_gp_warr.layer_id + 1, xnor3_gp_idx)
        xnor3_p = self.connect_to_tracks(xnor3_gp_warr, xnor3_gp_tid)

        # connect a, a_b, b, b_b
        self.connect_to_tracks([a, xnor0_p, xnor2_n], a_id)
        self.connect_to_tracks([a_b, xnor1_n, xnor2_p], ab_id)
        self.connect_to_tracks([b, xnor1_p, xnor0_n], b_id)
        self.connect_to_tracks([b_b, xnor3_p, xnor3_n], bb_id)

        self.connect_to_tracks([xnor0_n_ports['d'], xnor1_n_ports['s']],
                               nout_id)
        self.connect_to_tracks([xnor0_p_ports['d'], xnor1_p_ports['s']],
                               pout_id)
        self.connect_to_tracks([xnor2_n_ports['d'], xnor3_n_ports['s']],
                               nout_id)
        self.connect_to_tracks([xnor2_p_ports['d'], xnor3_p_ports['s']],
                               pout_id)

        o = self.connect_to_tracks([
            xnor1_n_ports['d'], xnor1_p_ports['d'], xnor3_n_ports['d'],
            xnor3_p_ports['d']
        ], out_id)

        self.connect_to_substrate('ptap',
                                  [xnor0_n_ports['s'], xnor2_n_ports['s']])
        self.connect_to_substrate('ntap',
                                  [xnor0_p_ports['s'], xnor2_p_ports['s']])

        # add pins
        self.add_pin('A', a, show=show_pins)
        self.add_pin('B', b, show=show_pins)
        self.add_pin('O', o, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(
            vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size
        self.size = self.grid.get_size_tuple(m5v_layer,
                                             width=self.bound_box.width,
                                             height=self.bound_box.height,
                                             round_up=True)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()

        self._sch_params = dict(
            lch=lch,
            wn=wn,
            wp=wp,
            nf_inv=nf_inv,
            nf_xnor=nf_xnor,
            intent=intent,
            dum_info=dum_info,
            debug=debug,
        )
Esempio n. 12
0
    def _draw_layout_helper(self, cbuf_params, clk_params):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # get resolution
        res = self.grid.resolution

        # get parameters
        lch = cbuf_params['lch']
        wn = cbuf_params['w']
        wp = cbuf_params['nfn']
        intent = cbuf_params['intent']
        ptap_w = cbuf_params['ptap_w']
        ntap_w = cbuf_params['ntap_w']
        g_width_ntr = cbuf_params['g_width_ntr']
        ds_width_ntr = cbuf_params['ds_width_ntr']
        # ndum
        # show_pins

        # buffer fingers
        nfn_inv0_buf = cbuf_params['nfn_inv0']
        nfn_inv1_buf = cbuf_params['nfn_inv1']
        nfp_inv0_buf = cbuf_params['nfp_inv0']
        nfp_inv1_buf = cbuf_params['nfp_inv1']

        # clk_cell fingers
        nfn_inv_clk = clk_params['nfn_inv']
        nfp_inv_clk = clk_params['nfp_inv']
        nfn_tinv0_clk = clk_params['nfn_tinv0']
        nfn_tinv1_clk = clk_params['nfn_tinv1']
        nfp_tinv0_clk = clk_params['nfp_tinv0']
        nfp_tinv1_clk = clk_params['nfp_tinv1']

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = round(self.find_fg_tot(res, lch, width) / 4) * 4
        print(fg_tot)

        # some constant
        wm5_unit = 16

        # check nfn
        if nfn % 4 != 0:
            raise ValueError(
                "To guarantee even finger number, need 'nfn' being divisible by 4!"
            )
        nfn_cal = int(
            nfn /
            2)  # divide finger number by 2, as we will have even/odd rows

        # calculate row number and fingers per row
        fg_eff = int((fg_tot - ndum_min * 2 - ndum_cen * 2) /
                     2)  # max effective finger numbers in a row
        row = math.ceil(nfn_cal / fg_eff)  # row number
        avg = math.ceil(nfn_cal / row)  # avg number per row
        if avg % 2 != 0:
            avg += 1
        rem = nfn_cal - (row - 1) * avg  # finger number in last row
        ndum1 = int((fg_tot - avg * 2 - ndum_cen * 2) /
                    2)  # dummy finger number except last row
        ndum2 = int((fg_tot - rem * 2 - ndum_cen * 2) /
                    2)  # dummy finger number for last row

        # draw transistor rows
        nw_list = [w, w] * row
        pw_list = []
        nth_list = [intent, intent] * row
        pth_list = []
        num_track_sep = 1
        ng_tracks = [g_width_ntr + g_sp_ntr, 0] * row
        # ng_tracks = [g_width_ntr, 0] * row
        pg_tracks = []
        # need have some gap for drain/source connection
        # also we try to share tracks for different row to make area smaller
        if row == 1:
            nds_tracks = [
                ds_width_ntr * 2 + ds_sp_ntr, ds_width_ntr * 2 + ds_sp_ntr
            ]
        elif row == 2:
            nds_tracks = [
                ds_width_ntr * 2 + ds_sp_ntr, ds_width_ntr, ds_width_ntr,
                ds_width_ntr * 2 + ds_sp_ntr
            ]
        else:
            nds_tracks = [ds_width_ntr*2 + ds_sp_ntr, ds_width_ntr+ds_sp_ntr] + \
                         [ds_width_ntr, ds_width_ntr+ds_sp_ntr] * (row-2) + \
                         [ds_width_ntr, ds_width_ntr*2 + ds_sp_ntr]
        pds_tracks = []
        n_orientation = ['MX', 'R0'] * row
        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            num_track_sep,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=[],
        )

        # initial some list for metals
        gleft_warr = []
        gright_warr = []
        deven_warr = []
        dodd_warr = []
        seven_warr = []
        sodd_warr = []

        # vertical M5 width
        wm5 = math.ceil(min(avg, rem) / wm5_unit)

        for i in range(row):
            # get gate track ID
            gate_id = self.make_track_id('nch',
                                         2 * i,
                                         'g',
                                         0,
                                         width=g_width_ntr)
            # get output track ID
            if i == 0:
                if row == 1:
                    deven_id = self.make_track_id('nch',
                                                  0,
                                                  'ds',
                                                  0,
                                                  width=ds_width_ntr)
                    seven_id = self.make_track_id('nch',
                                                  0,
                                                  'ds',
                                                  1,
                                                  width=ds_width_ntr)
                    dodd_id = self.make_track_id('nch',
                                                 1,
                                                 'ds',
                                                 0,
                                                 width=ds_width_ntr)
                    sodd_id = self.make_track_id('nch',
                                                 1,
                                                 'ds',
                                                 1,
                                                 width=ds_width_ntr)
                else:
                    deven_id = self.make_track_id('nch',
                                                  0,
                                                  'ds',
                                                  0,
                                                  width=ds_width_ntr)
                    seven_id = self.make_track_id('nch',
                                                  0,
                                                  'ds',
                                                  1,
                                                  width=ds_width_ntr)
                    dodd_id = self.make_track_id('nch',
                                                 1,
                                                 'ds',
                                                 0,
                                                 width=ds_width_ntr)
                    sodd_id = self.make_track_id('nch',
                                                 2,
                                                 'ds',
                                                 0,
                                                 width=ds_width_ntr)
            elif i == row - 1:
                deven_id = self.make_track_id('nch',
                                              2 * i - 1,
                                              'ds',
                                              0,
                                              width=ds_width_ntr)
                seven_id = self.make_track_id('nch',
                                              2 * i,
                                              'ds',
                                              0,
                                              width=ds_width_ntr)
                dodd_id = self.make_track_id('nch',
                                             2 * i + 1,
                                             'ds',
                                             0,
                                             width=ds_width_ntr)
                sodd_id = self.make_track_id('nch',
                                             2 * i + 1,
                                             'ds',
                                             1,
                                             width=ds_width_ntr)
            else:
                deven_id = self.make_track_id('nch',
                                              2 * i - 1,
                                              'ds',
                                              0,
                                              width=ds_width_ntr)
                seven_id = self.make_track_id('nch',
                                              2 * i,
                                              'ds',
                                              0,
                                              width=ds_width_ntr)
                dodd_id = self.make_track_id('nch',
                                             2 * i + 1,
                                             'ds',
                                             0,
                                             width=ds_width_ntr)
                sodd_id = self.make_track_id('nch',
                                             2 * i + 2,
                                             'ds',
                                             0,
                                             width=ds_width_ntr)

            if i == row - 1:
                # get ports
                leven_ports = self.draw_mos_conn('nch', 2 * i, ndum2, rem, 1,
                                                 1)
                reven_ports = self.draw_mos_conn('nch', 2 * i,
                                                 ndum2 + rem + ndum_cen * 2,
                                                 rem, 1, 1)
                lodd_ports = self.draw_mos_conn('nch', 2 * i + 1, ndum2, rem,
                                                1, 1)
                rodd_ports = self.draw_mos_conn('nch', 2 * i + 1,
                                                ndum2 + rem + ndum_cen * 2,
                                                rem, 1, 1)
            else:
                # get ports
                leven_ports = self.draw_mos_conn('nch', 2 * i, ndum1, avg, 1,
                                                 1)
                reven_ports = self.draw_mos_conn('nch', 2 * i,
                                                 ndum1 + avg + ndum_cen * 2,
                                                 avg, 1, 1)
                lodd_ports = self.draw_mos_conn('nch', 2 * i + 1, ndum1, avg,
                                                1, 1)
                rodd_ports = self.draw_mos_conn('nch', 2 * i + 1,
                                                ndum1 + avg + ndum_cen * 2,
                                                avg, 1, 1)

            # connect gates on both side
            gright_warr.append(
                self.connect_to_tracks([reven_ports['g']] + [rodd_ports['g']],
                                       gate_id))
            gleft_warr.append(
                self.connect_to_tracks([leven_ports['g']] + [lodd_ports['g']],
                                       gate_id))

            # connect drain/source
            deven_warr.append(
                self.connect_to_tracks([leven_ports['d'], reven_ports['d']],
                                       deven_id))
            seven_warr.append(
                self.connect_to_tracks([leven_ports['s'], reven_ports['s']],
                                       seven_id))
            dodd_warr.append(
                self.connect_to_tracks([lodd_ports['d'], rodd_ports['d']],
                                       dodd_id))
            sodd_warr.append(
                self.connect_to_tracks([lodd_ports['s'], rodd_ports['s']],
                                       sodd_id))

        # connect all vctrl vertically
        vctrl_idx = self.grid.coord_to_nearest_track(m5v_layer,
                                                     self.bound_box.xc,
                                                     half_track=True)
        vctrl_tid = TrackID(m5v_layer, vctrl_idx, width=1)
        # vctrl = self.connect_to_tracks(seven_warr, vctrl_tid)
        vctrl = self.connect_to_tracks(
            deven_warr + seven_warr + dodd_warr + sodd_warr, vctrl_tid)
        self.add_pin(self.get_pin_name('VCTRL'), vctrl, show=show_pins)

        # connect all output vertically for left side
        out_idx_left = self.grid.coord_to_nearest_track(m5v_layer,
                                                        gleft_warr[-1].middle,
                                                        half_track=True)
        out_tid_left = TrackID(m5v_layer, out_idx_left, width=wm5)
        out_left = self.connect_to_tracks(gleft_warr, out_tid_left)
        self.add_pin(self.get_pin_name('OUTP'), out_left, show=show_pins)

        # right side
        out_idx_right = self.grid.coord_to_nearest_track(
            m5v_layer, gright_warr[-1].middle, half_track=True)
        out_tid_right = TrackID(m5v_layer, out_idx_right, width=wm5)
        out_right = self.connect_to_tracks(gright_warr, out_tid_right)
        self.add_pin(self.get_pin_name('OUTN'), out_right, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(
            vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size of block in resolution
        blk_w = self.bound_box.width_unit
        blk_h = self.bound_box.top_unit
        # blk_w, blk_h = self.grid.get_size_dimension(self.size, unit_mode=True)

        # get pitch of top 2 layers
        w_pitch, h_pitch = self.grid.get_size_pitch(m5v_layer, unit_mode=True)
        # print([w_pitch, h_pitch])

        # get size rounded to top 2 layers pitch
        blk_w_new = -(-blk_w // w_pitch)
        blk_h_new = -(-blk_h // h_pitch)

        # get size and array box
        self.size = m5v_layer, blk_w_new, blk_h_new
        self.array_box = BBox(0, 0, blk_w, blk_h, res, unit_mode=True)

        # get fg_tot
        self._fg_tot = fg_tot

        self._sch_params = dict(
            lch=self.params['lch'],
            w=self.params['w'],
            nfn=self.params['nfn'],
            fg_wid=self._fg_tot,
            ndum_min=self.params['ndum_min'],
            ndum_cen=self.params['ndum_cen'],
            intent=self.params['intent'],
        )
Esempio n. 13
0
    def _draw_layout_helper(self, lch, wn, wp, nfn, nfp, g_space, ds_space,
                            ptap_w, ntap_w, g_width_ntr, ds_width_ntr, intent,
                            ndum_side, show_pins, power_width_ntr, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nfn % 2 != 0 or nfp % 2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        fg_tot = ndum_side * 2 + max(nfn, nfp)

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr + g_sp_ntr + g_space]
        pg_tracks = [g_width_ntr + g_sp_ntr + g_space]
        nds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space]
        pds_tracks = [ds_width_ntr + ds_sp_ntr + ds_space]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(lch,
                       fg_tot,
                       ptap_w,
                       ntap_w,
                       nw_list,
                       nth_list,
                       pw_list,
                       pth_list,
                       ng_tracks=ng_tracks,
                       nds_tracks=nds_tracks,
                       pg_tracks=pg_tracks,
                       pds_tracks=pds_tracks,
                       n_orientations=n_orientation,
                       p_orientations=p_orientation,
                       top_layer=m5v_layer)

        # get gate and drain index
        ngate_id = self.make_track_id('nch', 0, 'g', g_space, width=1)
        pgate_id = self.make_track_id('pch', 0, 'g', g_space, width=1)
        nout_id = self.make_track_id('nch', 0, 'ds', ds_space, width=1)
        pout_id = self.make_track_id('pch', 0, 'ds', ds_space, width=1)
        ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1)
        pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1)

        # nor
        inv_n_ports = self.draw_mos_conn('nch',
                                         0,
                                         ndum_side,
                                         nfn,
                                         1,
                                         1,
                                         s_net='VSS',
                                         d_net='VSS')
        inv_p_ports = self.draw_mos_conn('pch',
                                         0,
                                         ndum_side,
                                         nfp,
                                         1,
                                         1,
                                         s_net='VDD',
                                         d_net='VSS')

        # connect inv
        inv_gn_warr = self.connect_to_tracks(inv_n_ports['g'],
                                             ngate_id,
                                             min_len_mode=0)
        inv_gp_warr = self.connect_to_tracks(inv_p_ports['g'],
                                             pgate_id,
                                             min_len_mode=0)
        inv_g_idx = self.grid.coord_to_nearest_track(inv_gn_warr.layer_id + 1,
                                                     inv_gn_warr.lower)
        inv_g_tid = TrackID(inv_gn_warr.layer_id + 1, inv_g_idx)
        inv_g = self.connect_to_tracks([inv_gn_warr, inv_gp_warr], inv_g_tid)

        inv_dn_warr = self.connect_to_tracks(inv_n_ports['d'],
                                             nout_id,
                                             min_len_mode=0)
        inv_dp_warr = self.connect_to_tracks(inv_p_ports['d'],
                                             pout_id,
                                             min_len_mode=0)

        # connect source
        self.connect_to_substrate('ptap', inv_n_ports['s'])
        self.connect_to_substrate('ntap', inv_p_ports['s'])

        # add pins
        self.add_pin('I', inv_g, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(
            vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        idx = self.grid.coord_to_nearest_track(inv_dn_warr.layer_id + 1,
                                               inv_dn_warr.upper)
        tid = TrackID(inv_dn_warr.layer_id + 1, idx)
        ptap_wire_arrs.append(inv_dn_warr)
        ntap_wire_arrs.append(inv_dp_warr)
        self.connect_to_tracks(ptap_wire_arrs, tid)
        self.connect_to_tracks(ntap_wire_arrs, tid)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()
        self._sch_params = dict(
            lch=lch,
            wn=wn,
            wp=wp,
            nfn=nfn,
            nfp=nfp,
            intent=intent,
            dum_info=dum_info,
        )
Esempio n. 14
0
    def draw_layout(self):
        """Draw the layout of a dynamic latch chain.
        """
        # type: () -> None

        lch = self.params['lch']
        ptap_w = self.params['ptap_w']
        ntap_w = self.params['ntap_w']
        w_dict = self.params['w_dict']
        th_dict = self.params['th_dict']
        seg_dict = self.params['seg_dict']
        ndum = self.params['ndum']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        show_pins = self.params['show_pins']
        guard_ring_nf = self.params['guard_ring_nf']
        top_layer = self.params['top_layer']
        tech_cls_name = self.params['tech_cls_name']

        if tech_cls_name is not None:
            self.set_tech_class(tech_cls_name)

        ana_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf, top_layer=top_layer,
                                  tech_cls_name=tech_cls_name)
        min_fg_sep = ana_info.min_fg_sep

        # calculate total number of fingers
        seg_ptail = seg_dict['ptail']
        seg_ntail = seg_dict['ntail']
        seg_pin = seg_dict['pin']
        seg_nin = seg_dict['nin']

        fg_ptail = seg_ptail
        fg_ntail = seg_ntail
        fg_pin = seg_pin
        fg_nin = seg_nin

        # error checking
        if fg_pin % 2 != 0 or fg_nin % 2 != 0 or fg_ptail % 2 != 0 or fg_ntail % 2 != 0:
            raise ValueError('Only even number of fingers are supported.')
        if (fg_pin - fg_nin) % 4 != 0:
            raise ValueError('This code now only works if fg_pin and fg_nin differ by '
                             'multiples of 4.')

        fg_single_in = max(fg_pin, fg_nin)
        fg_single = max(fg_ptail, fg_ntail, fg_pin, fg_nin)
        in_mid_idx = ndum + fg_single - fg_single_in // 2
        fg_tot = 2 * (fg_single + ndum) + min_fg_sep
        ndum_pin = in_mid_idx - fg_pin // 2
        ndum_nin = in_mid_idx - fg_nin // 2
        if fg_ntail <= fg_nin:
            ndum_ntail = ndum_nin + fg_nin - fg_ntail
        else:
            ndum_ntail = min(ndum_nin, ndum + fg_single - fg_ntail)
        if fg_ptail <= fg_pin:
            ndum_ptail = ndum_pin + fg_pin - fg_ptail
        else:
            ndum_ptail = min(ndum_pin, ndum + fg_single - fg_ptail)

        # get width/threshold/orientation info
        nw_list = [w_dict['ntail'], w_dict['nin']]
        nth_list = [th_dict['ntail'], th_dict['nin']]
        n_orientations = ['MX', 'MX']
        pw_list = [w_dict['pin'], w_dict['ptail']]
        pth_list = [th_dict['pin'], th_dict['ptail']]
        p_orientations = ['R0', 'R0']

        # get tracks information
        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
        hm_layer = self.mos_conn_layer + 1

        # allocate tracks
        wire_names = dict(
            nch=[
                dict(g=['bias'],
                     ds=['tail']),
                dict(g=['in', 'out'],
                     ds=[]),
            ],
            pch=[
                dict(g=['in'],
                     ds=[]),
                dict(g=['bias'],
                     ds=['tail']),
            ],
        )

        # draw base
        self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list, nth_list, pw_list, pth_list,
                       tr_manager=tr_manager, wire_names=wire_names,
                       n_orientations=n_orientations, p_orientations=p_orientations,
                       guard_ring_nf=guard_ring_nf, top_layer=top_layer)

        # draw transistors
        ntaill = self.draw_mos_conn('nch', 0, ndum_ntail, fg_ntail, 2, 0,
                                    s_net='ntail', d_net='')
        ntailr = self.draw_mos_conn('nch', 0, fg_tot - ndum_ntail - fg_ntail, fg_ntail, 2, 0,
                                    s_net='ntail', d_net='')
        ptaill = self.draw_mos_conn('pch', 1, ndum_ptail, fg_ptail, 0, 2,
                                    s_net='ptail', d_net='')
        ptailr = self.draw_mos_conn('pch', 1, fg_tot - ndum_ptail - fg_ptail, fg_ptail, 0, 2,
                                    s_net='ptail', d_net='')
        if (ndum_nin - ndum_ntail) % 2 == 1:
            tail_nin_port, out_nin_port = 'd', 's'
            sdir, ddir = 2, 0
            s_netl, s_netr, d_netl, d_netr = 'outn', 'outp', 'ntail', 'ntail'
        else:
            tail_nin_port, out_nin_port = 's', 'd'
            sdir, ddir = 0, 2
            s_netl, s_netr, d_netl, d_netr = 'ntail', 'ntail', 'outn', 'outp'
        ninl = self.draw_mos_conn('nch', 1, ndum_nin, fg_nin, sdir, ddir,
                                  s_net=s_netl, d_net=d_netl)
        ninr = self.draw_mos_conn('nch', 1, fg_tot - ndum_nin - fg_nin, fg_nin, sdir, ddir,
                                  s_net=s_netr, d_net=d_netr)
        if (ndum_pin - ndum_ptail) % 2 == 1:
            tail_pin_port, out_pin_port = 'd', 's'
            sdir, ddir = 0, 2
            s_netl, s_netr, d_netl, d_netr = 'outn', 'outp', 'ptail', 'ptail'
        else:
            tail_pin_port, out_pin_port = 's', 'd'
            sdir, ddir = 2, 0
            s_netl, s_netr, d_netl, d_netr = 'ptail', 'ptail', 'outn', 'outp'
        pinl = self.draw_mos_conn('pch', 0, ndum_pin, fg_pin, sdir, ddir,
                                  s_net=s_netl, d_net=d_netl)
        pinr = self.draw_mos_conn('pch', 0, fg_tot - ndum_pin - fg_pin, fg_pin, sdir, ddir,
                                  s_net=s_netr, d_net=d_netr)

        # draw connections
        # VDD/VSS
        self.connect_to_substrate('ptap', [ntaill['d'], ntailr['d']])
        self.connect_to_substrate('ntap', [ptaill['d'], ptailr['d']])
        # NMOS/PMOS tail
        tail_tid = self.get_wire_id('nch', 0, 'ds', wire_name='tail')
        self.connect_to_tracks([ntaill['s'], ntailr['s'], ninl[tail_nin_port],
                                ninr[tail_nin_port]], tail_tid)
        tail_tid = self.get_wire_id('pch', 1, 'ds', wire_name='tail')
        self.connect_to_tracks([ptaill['s'], ptailr['s'], pinl[tail_pin_port],
                                pinr[tail_pin_port]], tail_tid)
        # NMOS/PMOS tail bias
        bn_tid = self.get_wire_id('nch', 0, 'g', wire_name='bias')
        bp_tid = self.get_wire_id('pch', 1, 'g', wire_name='bias')
        self.connect_to_tracks([ntaill['g'], ntailr['g'], ninl['d'], pinl['d']], bn_tid)
        self.connect_to_tracks([ptaill['g'], ptailr['g'], ninl['d'], pinl['d']], bp_tid)
        # input/output
        inn_tid = self.get_wire_id('nch', 1, 'g', wire_name='in')
        inp_tid = self.get_wire_id('pch', 0, 'g', wire_name='in')
        inp_idx = inp_tid.base_index
        inn_idx = inn_tid.base_index
        in_sum2 = int(round(2 * (inp_idx + inn_idx)))
        if in_sum2 % 2 == 1:
            # move inp_idx down so output is centered wrt inputs
            inp_idx -= 0.5
            in_sum2 -= 1
        out_tid = TrackID(hm_layer, in_sum2 / 4, width=tr_manager.get_width(hm_layer, 'out'))
        # connect input/output
        inp, inn = self.connect_differential_tracks([ninl['g'], pinl['g']], [ninr['g'], pinr['g']],
                                                    hm_layer, inp_idx, inn_idx, width=inn_tid.width)
        out = self.connect_to_tracks([ninr[out_nin_port], pinr[out_pin_port]],
                                     out_tid, min_len_mode=0)

        # fill dummies
        tr_w = tr_manager.get_width(hm_layer, 'sup')
        vss_warrs, vdd_warrs = self.fill_dummy(vdd_width=tr_w, vss_width=tr_w)

        # add pins
        self.add_pin('inp', inp, show=show_pins)
        self.add_pin('inn', inn, show=show_pins)
        self.add_pin('out', out, show=show_pins)
        self.add_pin('VSS', vss_warrs, show=show_pins)
        self.add_pin('VDD', vdd_warrs, show=show_pins)

        # compute schematic parameters
        self._sch_params = dict(
            lch=lch,
            w_dict=w_dict,
            th_dict=th_dict,
            seg_dict=seg_dict,
            dum_info=self.get_sch_dummy_info(),
        )
Esempio n. 15
0
    def _draw_layout_helper(self, lch, wn, wp, nfn, nfp, nf_inv, g_space,
                            ds_space, ptap_w, ntap_w, g_width_ntr,
                            ds_width_ntr, intent, ndum, ndum_side, show_pins,
                            fg_tot, debug, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # get resolution
        res = self.grid.resolution

        # make sure all fingers are even number
        if nfn % 2 != 0 or nfp % 2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        if fg_tot is None or fg_tot < ndum_side * 2 + ndum * 2 + max(
                nfn, nfp) * 2 + nf_inv:
            fg_tot = ndum_side * 2 + ndum * 2 + max(nfn, nfp) * 2 + nf_inv
        else:
            ndum_side = (fg_tot - ndum * 2 - max(nfn, nfp) * 2 - nf_inv) // 2

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr * 2 + g_space]
        pg_tracks = [g_width_ntr * 2 + g_space]
        nds_tracks = [ds_width_ntr * 2 + ds_space]
        pds_tracks = [ds_width_ntr * 2 + ds_space]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(
            lch,
            fg_tot,
            ptap_w,
            ntap_w,
            nw_list,
            nth_list,
            pw_list,
            pth_list,
            ng_tracks=ng_tracks,
            nds_tracks=nds_tracks,
            pg_tracks=pg_tracks,
            pds_tracks=pds_tracks,
            n_orientations=n_orientation,
            p_orientations=p_orientation,
        )

        # # get gate and drain index
        # ngate_id = self.make_track_id('nch', 0, 'g', g_space, width=1)
        # pgate_id = self.make_track_id('pch', 0, 'g', g_space, width=1)
        # nout_id = self.make_track_id('nch', 0, 'ds', ds_space, width=1)
        # pout_id = self.make_track_id('pch', 0, 'ds', ds_space, width=1)
        # ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=1)
        # pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=1)
        #
        # # nand
        # nand_n0_ports = self.draw_mos_conn('nch', 0, ndum_side, nfn, 1, 1,
        #                                    s_net='VSS', d_net='ns')
        # nand_p0_ports = self.draw_mos_conn('pch', 0, ndum_side, nfp, 1, 1,
        #                                    s_net='VDD', d_net='o_b')
        # col_idx = ndum_side + max(nfn, nfp) + ndum
        # nand_n1_ports = self.draw_mos_conn('nch', 0, col_idx, nfn, 1, 1,
        #                                    s_net='ns', d_net='o_b')
        # nand_p1_ports = self.draw_mos_conn('pch', 0, col_idx, nfp, 1, 1,
        #                                    s_net='VDD', d_net='o_b')
        # col_idx = ndum_side + max(nfn, nfp) + ndum*2 + nf_inv
        # inv_n_ports = self.draw_mos_conn('nch', 0, col_idx, nf_inv, 1, 1,
        #                                  s_net='VSS', d_net='O')
        # inv_p_ports = self.draw_mos_conn('pch', 0, col_idx, nf_inv, 1, 1,
        #                                  s_net='VDD', d_net='O')

        # # connect nand
        # nand_gn0_warr = self.connect_to_tracks(nand_n0_ports['g'], ngate_id)
        # nand_gp0_warr = self.connect_to_tracks(nand_p0_ports['g'], pgate_id)
        # nand_g0_idx = self.grid.coord_to_nearest_track(nand_gn0_warr.layer_id + 1, nand_gn0_warr.lower)
        # nand_g0_tid = TrackID(nand_gn0_warr.layer_id + 1, nand_g0_idx)
        # nand_g0 = self.connect_to_tracks([nand_gn0_warr, nand_gp0_warr], nand_g0_tid)
        #
        # nand_gn1_warr = self.connect_to_tracks(nand_n1_ports['g'], ngate_id)
        # nand_gp1_warr = self.connect_to_tracks(nand_p1_ports['g'], pgate_id)
        # nand_g1_idx = self.grid.coord_to_nearest_track(nand_gn0_warr.layer_id + 1, nand_gn1_warr.lower)
        # nand_g1_tid = TrackID(nand_gn0_warr.layer_id + 1, nand_g1_idx)
        # nand_g1 = self.connect_to_tracks([nand_gn1_warr, nand_gp1_warr], nand_g1_tid)
        # # connect nand_n0 and nand_n1
        # self.connect_to_tracks([nand_n0_ports['d'], nand_n1_ports['s']], ndrain_id)
        # self.connect_to_substrate('ptap', nand_n0_ports['s'])
        # self.connect_to_substrate('ntap', [nand_p0_ports['s'], nand_p1_ports['s']])
        #
        # # connect inv
        # inv_gn_warr = self.connect_to_tracks(inv_n_ports['g'], ngate_id)
        # inv_gp_warr = self.connect_to_tracks(inv_p_ports['g'], pgate_id)
        # inv_g_idx = self.grid.coord_to_nearest_track(inv_gn_warr.layer_id + 1, inv_gn_warr.lower)
        # inv_g_tid = TrackID(inv_gn_warr.layer_id + 1, inv_g_idx)
        # inv_g = self.connect_to_tracks([inv_gn_warr, inv_gp_warr], inv_g_tid)
        # # connect gate
        # o_b = self.connect_to_tracks([nand_p0_ports['d'], nand_p1_ports['d'], nand_n1_ports['d'], inv_g],
        #                              pout_id)
        # o_b = inv_g     # use M5 for o_b
        # # connect drain
        # o = self.connect_to_tracks([inv_n_ports['d'], inv_p_ports['d']], nout_id)
        # self.connect_to_substrate('ptap', inv_n_ports['s'])
        # self.connect_to_substrate('ntap', inv_p_ports['s'])
        #
        # # add pins
        # self.add_pin('A', nand_g0, show=show_pins)
        # self.add_pin('B', nand_g1, show=show_pins)
        # if debug is True:
        #     self.add_pin('o_b', o_b, show=show_pins)
        # self.add_pin('O', o, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy()

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get size
        self.size = self.grid.get_size_tuple(m5v_layer,
                                             width=self.bound_box.width,
                                             height=self.bound_box.height,
                                             round_up=True)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()
        self._sch_params = dict(
            lch=lch,
            wn=wn,
            wp=wp,
            nfn=nfn,
            nfp=nfp,
            nf_inv=nf_inv,
            intent=intent,
            dum_info=dum_info,
            debug=debug,
        )
Esempio n. 16
0
    def _draw_layout_helper(self, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # define some global variables
        global ngate_id, pgate_id, out_id, outp_id
        global ndum, ndum_side, ndum_cell, nf_inv0, nf_inv1
        global m4h_layer, m5v_layer
        global fg_cell

        # get parameters
        pi_res = self.params['pi_res']
        lch = self.params['lch']
        wn = self.params['wn']
        wp = self.params['wp']
        nf_inv0 = self.params['nf_inv0']
        nf_inv1 = self.params['nf_inv1']
        ndum = self.params['ndum']
        ndum_side = self.params['ndum_side']
        ndum_cell = self.params['ndum_cell']
        intent = self.params['intent']
        ptap_w = self.params['ptap_w']
        ntap_w = self.params['ntap_w']
        g_width_ntr = self.params['g_width_ntr']
        ds_width_ntr = self.params['ds_width_ntr']
        show_pins = self.params['show_pins']
        power_width_ntr = self.params['power_width_ntr']
        g_space = self.params['g_space']
        ds_space = self.params['ds_space']

        if ndum_cell is None:
            ndum_cell = ndum

        # get resolution
        res = self.grid.resolution

        # finger number
        fg_cell = ndum + ndum_cell + nf_inv0 + nf_inv1
        fg_tot = ndum_side * 2 + fg_cell * (pi_res+2) + ndum*(pi_res+1)

        # make sure all fingers are even number
        if nf_inv0 % 2 != 0 or nf_inv1 % 2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr+g_space]
        pg_tracks = [g_width_ntr+g_space]
        nds_tracks = [ds_width_ntr+ds_space]
        pds_tracks = [ds_width_ntr+ds_space]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list,
                       nth_list, pw_list, pth_list,
                       ng_tracks=ng_tracks, nds_tracks=nds_tracks,
                       pg_tracks=pg_tracks, pds_tracks=pds_tracks,
                       n_orientations=n_orientation, p_orientations=p_orientation,
                       top_layer=m5v_layer)

        # get gate and draiin index
        ngate_id = self.make_track_id('nch', 0, 'g', 0, width=g_width_ntr)
        pgate_id = self.make_track_id('pch', 0, 'g', 0, width=g_width_ntr)
        out_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr)
        outp_id = self.make_track_id('pch', 0, 'ds', 0, width=ds_width_ntr)

        # define wire array
        dum_in_arr = []
        ctrli_in_arr = []
        ctrlq_in_arr = []
        ctrlib_in_arr = []
        ctrlqb_in_arr = []
        ctrli_o_arr = []
        ctrlq_o_arr = []
        ctrlib_o_arr = []
        ctrlqb_o_arr = []
        ctrli_ob_arr = []
        ctrlq_ob_arr = []
        ctrlib_ob_arr = []
        ctrlqb_ob_arr = []

        # Step1: draw dummy cell
        inv0_in, inv0_out, inv1_out = self.draw_ctrl_buf(idx=0, dum=True)
        dum_in_arr.append(inv0_in)
        inv0_in, inv0_out, inv1_out = self.draw_ctrl_buf(idx=pi_res+1, dum=True)
        dum_in_arr.append(inv0_in)

        # Step2: draw cells
        for i in range(0, pi_res):
            inv0_in, inv0_out, inv1_out = self.draw_ctrl_buf(idx=i+1)
            if i % 4 == 0:
                ctrli_in_arr.append(inv0_in)
                ctrli_o_arr.append(inv1_out)
                ctrli_ob_arr.append(inv0_out)
            elif i % 4 == 1:
                ctrlq_in_arr.append(inv0_in)
                ctrlq_o_arr.append(inv1_out)
                ctrlq_ob_arr.append(inv0_out)
            elif i % 4 == 2:
                ctrlib_in_arr.append(inv0_in)
                ctrlib_o_arr.append(inv1_out)
                ctrlib_ob_arr.append(inv0_out)
            else:
                ctrlqb_in_arr.append(inv0_in)
                ctrlqb_o_arr.append(inv1_out)
                ctrlqb_ob_arr.append(inv0_out)

        ctrl_in_arr = ctrli_in_arr + ctrlq_in_arr + ctrlib_in_arr + ctrlqb_in_arr
        ctrl_o_arr = ctrli_o_arr + ctrlq_o_arr + ctrlib_o_arr + ctrlqb_o_arr
        ctrl_ob_arr = ctrli_ob_arr + ctrlq_ob_arr + ctrlib_ob_arr + ctrlqb_ob_arr

        # add pins
        for i, ctrl_in in enumerate(ctrl_in_arr):
            self.add_pin('ctrl<{}>'.format(i), ctrl_in, show=show_pins)
        for i, ctrl_o in enumerate(ctrl_o_arr):
            self.add_pin('ctrl_o<{}>'.format(i), ctrl_o, show=show_pins)
        for i, ctrl_ob in enumerate(ctrl_ob_arr):
            self.add_pin('ctrl_ob<{}>'.format(i), ctrl_ob, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # connect dummy input to ground
        for dum_in in dum_in_arr:
            self.connect_to_tracks(ptap_wire_arrs, dum_in.track_id,
                                   track_upper=dum_in.get_bbox_array(self.grid).top_unit, unit_mode=True,
                                   min_len_mode=0)

        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()
        self._sch_params = dict(
            pi_res=self.params['pi_res'],
            lch=self.params['lch'],
            wn=self.params['wn'],
            wp=self.params['wp'],
            nf_inv0=self.params['nf_inv0'],
            nf_inv1=self.params['nf_inv1'],
            intent=self.params['intent'],
            dum_info=dum_info,
        )
Esempio n. 17
0
    def _draw_layout_helper(self, **kwargs):
        """Draw the layout of a transistor for characterization.
        Notes
        -------
        The number of fingers are for only half (or one side) of the tank.
        Total number should be 2x
        """

        # define some global variables
        global ngate_id, ngate1_id, pgate_id, out_id, outp_id, ndrain_id, pdrain_id
        global ndum, ndum_side, nf_inv, nf_tinv0, nf_tinv1
        global m4h_layer, m5v_layer
        global fg_cell

        # get parameters
        pi_res = self.params['pi_res']
        lch = self.params['lch']
        wn = self.params['wn']
        wp = self.params['wp']
        nf_inv = self.params['nf_inv']
        nf_inv = self.params['nf_inv']
        nf_tinv0 = self.params['nf_tinv0']
        nf_tinv0 = self.params['nf_tinv0']
        nf_tinv1 = self.params['nf_tinv1']
        nf_tinv1 = self.params['nf_tinv1']
        ndum = self.params['ndum']
        ndum_side = self.params['ndum_side']
        intent = self.params['intent']
        ptap_w = self.params['ptap_w']
        ntap_w = self.params['ntap_w']
        g_width_ntr = self.params['g_width_ntr']
        ds_width_ntr = self.params['ds_width_ntr']
        show_pins = self.params['show_pins']
        power_width_ntr = self.params['power_width_ntr']

        # get resolution
        res = self.grid.resolution

        # finger number
        fg_cell = ndum * 2 + max(nf_inv, nf_inv) + max(nf_tinv0, nf_tinv0) + max(nf_tinv1, nf_tinv1)
        fg_tot = ndum_side * 2 + fg_cell * (pi_res+2) + ndum*(pi_res+1)

        # make sure all fingers are even number
        if nf_inv % 2 != 0 or nf_inv % 2 != 0 or nf_tinv0 % 2 != 0 or nf_tinv1 % 2 != 0 or\
            nf_tinv0 % 2 != 0 or nf_tinv1 % 2 != 0:
            raise ValueError("Need all finger number to be even!")

        # get layer separation space
        layout_info = AnalogBaseInfo(self.grid.copy(), lch, 0)
        m4h_layer = layout_info.mconn_port_layer + 1
        m5v_layer = layout_info.mconn_port_layer + 2
        g_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, g_width_ntr)
        ds_sp_ntr = self.grid.get_num_space_tracks(m4h_layer, ds_width_ntr)

        # draw transistor rows
        nw_list = [wn]
        pw_list = [wp]
        nth_list = [intent]
        pth_list = [intent]
        ng_tracks = [g_width_ntr*2]
        pg_tracks = [g_width_ntr*2]
        nds_tracks = [ds_width_ntr*2]
        pds_tracks = [ds_width_ntr*2]
        n_orientation = ['R0']
        p_orientation = ['MX']

        self.draw_base(lch, fg_tot, ptap_w, ntap_w, nw_list,
                       nth_list, pw_list, pth_list,
                       ng_tracks=ng_tracks, nds_tracks=nds_tracks,
                       pg_tracks=pg_tracks, pds_tracks=pds_tracks,
                       n_orientations=n_orientation, p_orientations=p_orientation,
                       top_layer=m5v_layer)

        # get gate and draiin index
        ngate_id = self.make_track_id('nch', 0, 'g', 0, width=g_width_ntr)
        ngate1_id = self.make_track_id('nch', 0, 'g', 1, width=g_width_ntr)
        pgate_id = self.make_track_id('pch', 0, 'g', 0, width=g_width_ntr)
        out_id = self.make_track_id('nch', 0, 'ds', 1, width=ds_width_ntr)
        outp_id = self.make_track_id('pch', 0, 'ds', 1, width=ds_width_ntr)
        ndrain_id = self.make_track_id('nch', 0, 'ds', 0, width=ds_width_ntr)
        pdrain_id = self.make_track_id('pch', 0, 'ds', 0, width=ds_width_ntr)

        # define wire array
        dum_in_arr = []
        dum_ctrl_arr = []
        dum_ctrlb_arr = []
        clk_i_arr = []
        clk_q_arr = []
        clk_ib_arr = []
        clk_qb_arr = []
        clko_arr = []
        ctrli_arr = []
        ctrli_b_arr = []
        ctrlq_arr = []
        ctrlq_b_arr = []
        ctrlib_arr = []
        ctrlib_b_arr = []
        ctrlqb_arr = []
        ctrlqb_b_arr = []

        # draw dummy
        inv_in, ng_tinv1, pg_tinv1, tinv_out = self.draw_clk_cell(idx=0, dum=True)
        dum_in_arr.append(inv_in)
        dum_ctrl_arr.append(ng_tinv1)
        dum_ctrlb_arr.append(pg_tinv1)

        inv_in, ng_tinv1, pg_tinv1, tinv_out = self.draw_clk_cell(idx=pi_res+1, dum=True)
        dum_in_arr.append(inv_in)
        dum_ctrl_arr.append(ng_tinv1)
        dum_ctrlb_arr.append(pg_tinv1)

        for i in range(pi_res):
            # draw clk cell
            inv_in, ng_tinv1, pg_tinv1, tinv_out = self.draw_clk_cell(idx=i+1)      # 1 is for dummy
            if i % 4 == 0:
                clk_i_arr.append(inv_in)
                ctrli_arr.append(ng_tinv1)
                ctrli_b_arr.append(pg_tinv1)
                clko_arr.append(tinv_out)
            elif i % 4 == 1:
                clk_q_arr.append(inv_in)
                ctrlq_arr.append(ng_tinv1)
                ctrlq_b_arr.append(pg_tinv1)
                clko_arr.append(tinv_out)
            elif i % 4 == 2:
                clk_ib_arr.append(inv_in)
                ctrlib_arr.append(ng_tinv1)
                ctrlib_b_arr.append(pg_tinv1)
                clko_arr.append(tinv_out)
            else:
                clk_qb_arr.append(inv_in)
                ctrlqb_arr.append(ng_tinv1)
                ctrlqb_b_arr.append(pg_tinv1)
                clko_arr.append(tinv_out)

        ctrl_arr = ctrli_arr + ctrlq_arr + ctrlib_arr + ctrlqb_arr
        ctrlb_arr = ctrli_b_arr + ctrlq_b_arr + ctrlib_b_arr + ctrlqb_b_arr

        # connect all clk_i_arr
        idx = self.grid.coord_to_nearest_track(clk_i_arr[0].layer_id+1,
                                               clk_i_arr[0].get_bbox_array(self.grid).bottom_unit, unit_mode=True)
        tid_i = TrackID(clk_i_arr[0].layer_id+1, idx+1)
        tid_q = TrackID(clk_i_arr[0].layer_id+1, idx+2)
        tid_ib = TrackID(clk_i_arr[0].layer_id+1, idx+3)
        tid_qb = TrackID(clk_i_arr[0].layer_id+1, idx+4)

        clk_i = self.connect_to_tracks(clk_i_arr, tid_i, min_len_mode=0)
        clk_q = self.connect_to_tracks(clk_q_arr, tid_q, min_len_mode=0)
        clk_ib = self.connect_to_tracks(clk_ib_arr, tid_ib, min_len_mode=0)
        clk_qb = self.connect_to_tracks(clk_qb_arr, tid_qb, min_len_mode=0)

        # connect all clk_o
        idx = self.grid.coord_to_nearest_track(clko_arr[0].layer_id + 1,
                                               clk_i_arr[0].get_bbox_array(self.grid).top_unit, unit_mode=True)
        tid = TrackID(clko_arr[0].layer_id+1, idx+2)
        clko = self.connect_to_tracks(clko_arr, tid, min_len_mode=0)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy(vdd_width=power_width_ntr, vss_width=power_width_ntr)

        # connect dummy
        for dum_in in dum_in_arr:
            self.connect_to_tracks(ptap_wire_arrs, dum_in.track_id,
                                   track_upper=dum_in.get_bbox_array(self.grid).top_unit,
                                   unit_mode=True, min_len_mode=0)
        for dum_ctrl in dum_ctrl_arr:
            idx = self.grid.coord_to_nearest_track(dum_ctrl.layer_id+1, dum_ctrl.middle)
            tid = TrackID(dum_ctrl.layer_id+1, idx)
            self.connect_to_tracks([ptap_wire_arrs[0], dum_ctrl], tid,
                                   track_lower=dum_ctrl.get_bbox_array(self.grid).top_unit, min_len_mode=0)
        for dum_ctrlb in dum_ctrlb_arr:
            idx = self.grid.coord_to_nearest_track(dum_ctrlb.layer_id + 1, dum_ctrlb.middle)
            tid = TrackID(dum_ctrlb.layer_id + 1, idx)
            self.connect_to_tracks([ntap_wire_arrs[0], dum_ctrlb], tid,
                                   track_lower=dum_ctrlb.get_bbox_array(self.grid).top_unit, min_len_mode=0)

        # add pins
        self.add_pin('clko', clko, show=show_pins)
        self.add_pin('clk_i', clk_i, show=show_pins)
        self.add_pin('clk_q', clk_q, show=show_pins)
        self.add_pin('clk_ib', clk_ib, show=show_pins)
        self.add_pin('clk_qb', clk_qb, show=show_pins)
        for i, ctrl in enumerate(ctrl_arr):
            self.add_pin('ctrl<{}>'.format(i), ctrl, show=show_pins)
        for i, ctrlb in enumerate(ctrlb_arr):
            self.add_pin('ctrlb<{}>'.format(i), ctrlb, show=show_pins)
        # export supplies
        self.add_pin(self.get_pin_name('VSS'), ptap_wire_arrs, show=show_pins)
        self.add_pin(self.get_pin_name('VDD'), ntap_wire_arrs, show=show_pins)

        # get schematic parameters
        dum_info = self.get_sch_dummy_info()
        self._sch_params = dict(
            pi_res=self.params['pi_res'],
            lch=self.params['lch'],
            wn=self.params['wn'],
            wp=self.params['wp'],
            nf_inv=self.params['nf_inv'],
            nf_tinv0=self.params['nf_tinv0'],
            nf_tinv1=self.params['nf_tinv1'],
            intent=self.params['intent'],
            dum_info=dum_info,
        )