Exemplo n.º 1
0
    def draw_layout(self):
        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']
        top_layer = self.params['top_layer']

        nw_list = [w_dict['n']]
        pw_list = [w_dict['p']] * 2
        nth_list = [th_dict['n']]
        pth_list = [th_dict['p']] * 2

        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
        hm_layer = self.mos_conn_layer + 1
        wtr_in = tr_manager.get_width(hm_layer, 'in')
        wtr_out = tr_manager.get_width(hm_layer, 'out')
        wtr_en = tr_manager.get_width(hm_layer, 'en')
        wtr_mid = tr_manager.get_width(hm_layer, 'mid')
        sp_io = tr_manager.get_space(hm_layer, ('in', 'out'))
        sp_mid = tr_manager.get_space(hm_layer, ('in', 'mid'))

        seg_invp = seg_dict['invp']
        seg_enp = seg_dict['enp']
        seg_invn = seg_dict['invn']
        seg_enn = seg_dict['enn']
        seg_single = max(seg_invp, seg_invn, seg_enp)

        if (seg_invp - seg_invn) % 4 != 0 or (seg_enp - seg_invp) % 4 != 0:
            raise ValueError(
                'We assume seg_invp/seg_invn/seg_enp differ by multiples of 4.'
            )

        # compute total number of fingers
        ana_info = AnalogBaseInfo(self.grid, lch, 0, top_layer=top_layer)
        if ana_info.abut_analog_mos:
            fg_sep = 0
        else:
            fg_sep = ana_info.min_fg_sep

        enp_idx = ndum + (seg_single - seg_enp) // 2
        invp_idx = ndum + (seg_single - seg_invp) // 2
        invn_idx = ndum + (seg_single - seg_invn) // 2
        enn_idx = max(enp_idx + seg_enp, invn_idx + seg_invn + fg_sep)
        seg_tot = max(seg_single + 2 * ndum, enn_idx + seg_enn + ndum)

        # draw transistor rows
        ng_tracks = [wtr_out + sp_io]
        pg_tracks = [wtr_in, wtr_en]
        pds_tracks = [sp_mid + wtr_mid, 0]
        nds_tracks = [0]
        p_orient = ['R0', 'MX']
        n_orient = ['MX']
        self.draw_base(
            lch,
            seg_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_orient,
            p_orientations=p_orient,
            top_layer=top_layer,
        )

        # draw transistors
        invn = self.draw_mos_conn('nch',
                                  0,
                                  invn_idx,
                                  seg_invn,
                                  0,
                                  2,
                                  s_net='',
                                  d_net='out')
        enn = self.draw_mos_conn('nch',
                                 0,
                                 enn_idx,
                                 seg_enn,
                                 0,
                                 2,
                                 s_net='',
                                 d_net='out')
        invp = self.draw_mos_conn('pch',
                                  0,
                                  invp_idx,
                                  seg_invp,
                                  2,
                                  0,
                                  s_net='mid',
                                  d_net='out')
        enp = self.draw_mos_conn('pch',
                                 1,
                                 enp_idx,
                                 seg_enp,
                                 0,
                                 2,
                                 s_net='mid',
                                 d_net='')

        # connect supplies
        self.connect_to_substrate('ntap', enp['d'])
        self.connect_to_substrate('ptap', invn['s'])
        self.connect_to_substrate('ptap', enn['s'])

        # connect output
        loc = tr_manager.align_wires(hm_layer, ['out'],
                                     ng_tracks[0],
                                     alignment=1)[0]
        tid = self.make_track_id('nch', 0, 'g', loc, width=wtr_out)
        warr = self.connect_to_tracks([invp['d'], invn['d'], enn['d']], tid)
        self.add_pin('out', warr, show=show_pins)
        # connect input
        loc = tr_manager.align_wires(hm_layer, ['in'],
                                     pg_tracks[0],
                                     alignment=1)[0]
        tid = self.make_track_id('pch', 0, 'g', loc, width=wtr_in)
        warr = self.connect_to_tracks([invp['g'], invn['g']], tid)
        self.add_pin('in', warr, show=show_pins)
        # connect mid
        loc = tr_manager.align_wires(hm_layer, ['mid'],
                                     pds_tracks[0],
                                     alignment=1)[0]
        tid = self.make_track_id('pch', 0, 'ds', loc, width=wtr_mid)
        self.connect_to_tracks([invp['s'], enp['s']], tid)
        # connect enable
        loc = tr_manager.align_wires(hm_layer, ['en'],
                                     pg_tracks[1],
                                     alignment=1)[0]
        tid = self.make_track_id('pch', 1, 'g', loc, width=wtr_en)
        warr = self.connect_to_tracks([enp['g'], enn['g']], tid)
        self.add_pin('enb', warr, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy()
        # export supplies
        self.add_pin('VSS', ptap_wire_arrs)
        self.add_pin('VDD', ntap_wire_arrs)

        # 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(),
        )
Exemplo n.º 2
0
    def draw_layout(self):
        # type: () -> None

        config_file = self.params['config_file']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        top_layer = self.params['top_layer']
        hm_sp_sig = self.params['hm_sp_sig']
        hm_mid_idx_off = self.params['hm_mid_idx_off']
        show_pins = self.params['show_pins']

        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)

        # use standard cell routing grid
        self.update_routing_grid()

        self.set_draw_boundaries(True)

        # create masters
        tap_params = dict(cell_name='tap_pwr', config_file=config_file)
        tap_master = self.new_template(params=tap_params, temp_cls=StdCellTemplate)
        flop_params = dict(cell_name='dff_1x', config_file=config_file)
        flop_master = self.new_template(params=flop_params, temp_cls=StdCellTemplate)
        inv_params = dict(cell_name='inv_clk_16x', config_file=config_file)
        inv_master = self.new_template(params=inv_params, temp_cls=StdCellTemplate)

        # place instances
        flop_ncol = flop_master.std_size[0]
        tap_ncol = tap_master.std_size[0]
        inv_ncol = inv_master.std_size[0]
        space_ncol = 2
        tap_list = [self.add_std_instance(tap_master, 'XTAP00', loc=(0, 0)),
                    self.add_std_instance(tap_master, 'XTAP01', loc=(0, 1))]
        xcur = tap_ncol + space_ncol
        ff_bot0 = self.add_std_instance(flop_master, 'XFFB0', loc=(xcur, 0))
        ff_bot1 = self.add_std_instance(flop_master, 'XFFB1', loc=(xcur + flop_ncol, 0))
        ff_top0 = self.add_std_instance(flop_master, 'XFFT0', loc=(xcur, 1))
        ff_top1 = self.add_std_instance(flop_master, 'XFFT1', loc=(xcur + flop_ncol, 1))
        xcur += 2 * flop_ncol
        inv_bot0 = self.add_std_instance(inv_master, 'XINVB0', loc=(xcur, 0))
        inv_bot1 = self.add_std_instance(inv_master, 'XINVB1', loc=(xcur + inv_ncol, 0))
        inv_top0 = self.add_std_instance(inv_master, 'XINVT0', loc=(xcur, 1))
        inv_top1 = self.add_std_instance(inv_master, 'XINVT1', loc=(xcur + inv_ncol, 1))
        xcur += 2 * inv_ncol + space_ncol
        tap_list.append(self.add_std_instance(tap_master, 'XTAP10', loc=(xcur, 0)))
        tap_list.append(self.add_std_instance(tap_master, 'XTAP11', loc=(xcur, 1)))

        # set template size and draw space/boundaries
        self.set_std_size((xcur + tap_ncol, 2), top_layer=top_layer)
        self.fill_space()
        self.draw_boundaries()

        # connect signals
        warr_dict = {}
        for inst, name in ((ff_bot0, 'FB0'), (ff_bot1, 'FB1'), (ff_top0, 'FT0'), (ff_top1, 'FT1'),
                           (inv_bot0, 'IB0'), (inv_bot1, 'IB1'), (inv_top0, 'IT0'), (inv_top1, 'IT1')):
            warr_dict['%s%s' % (name, 'I')] = inst.get_all_port_pins('I')[0]
            warr_dict['%s%s' % (name, 'O')] = inst.get_all_port_pins('O')[0]

        port_layer = warr_dict['FB0I'].layer_id
        hm_layer = port_layer + 1
        vm_layer = hm_layer + 1
        if vm_layer < self.grid.top_private_layer + 1:
            raise ValueError('This generator assumes layer %d is public.' % vm_layer)

        mid_tidx = self.grid.coord_to_nearest_track(hm_layer, self.bound_box.height_unit // 2, half_track=True,
                                                    mode=0, unit_mode=True)
        mid_tidx += hm_mid_idx_off
        top_tidx = mid_tidx + 1 + hm_sp_sig
        bot_tidx = mid_tidx - 1 - hm_sp_sig
        bot_tid = TrackID(hm_layer, bot_tidx)
        top_tid = TrackID(hm_layer, top_tidx)
        mid_tid = TrackID(hm_layer, mid_tidx)
        self.connect_to_tracks([warr_dict['FB0O'], warr_dict['FB1I'], warr_dict['IB0I']], bot_tid)
        self.connect_to_tracks([warr_dict['FT0O'], warr_dict['FT1I']], top_tid)
        self.connect_to_tracks([warr_dict['FT1O'], warr_dict['FB0I'], warr_dict['IT0I']], mid_tid)
        self.connect_to_tracks([warr_dict['IB0O'], warr_dict['IB1I']], bot_tid)
        self.connect_to_tracks([warr_dict['IT0O'], warr_dict['IT1I']], top_tid)

        # gather/connect supply wires on port layer
        vdd_warrs, vss_warrs = [], []
        for inst in tap_list:
            vdd_warrs.extend(inst.get_all_port_pins('VDD'))
            vss_warrs.extend(inst.get_all_port_pins('VSS'))
        vdd_warrs = self.connect_wires(vdd_warrs)
        vss_warrs = self.connect_wires(vss_warrs)

        # connect rst
        w_rst = tr_manager.get_width(hm_layer, 'rst')
        rst = warr_dict['FT0I']
        rst = self.connect_to_tracks(rst, top_tid, min_len_mode=True)
        vm_tidx = self.grid.coord_to_nearest_track(vm_layer, rst.middle, half_track=True)
        vm_tid = TrackID(vm_layer, vm_tidx, width=w_rst)
        self.add_pin('rst', self.connect_to_tracks(rst, vm_tid, min_len_mode=0), show=show_pins)
        # connect enables
        hm_w_en = tr_manager.get_width(hm_layer, 'en')
        vm_w_en = tr_manager.get_width(vm_layer, 'en')
        for name, pin in (('IT1O', 'rstp'), ('IB1O', 'rstn')):
            warr = warr_dict[name]
            tid = warr.track_id.base_index
            coord = self.grid.track_to_coord(port_layer, tid, unit_mode=True)
            vm_tidx = self.grid.coord_to_nearest_track(vm_layer, coord, half_track=True, mode=1, unit_mode=True)
            warrs = self.connect_with_via_stack(warr, TrackID(vm_layer, vm_tidx, width=vm_w_en),
                                                tr_w_list=[hm_w_en], min_len_mode_list=0)
            self.add_pin(pin, warrs[-1], show=show_pins)
        # connect clocks and supplies
        clkp = [ff_top0.get_all_port_pins('CLK')[0], ff_top1.get_all_port_pins('CLK')[0]]
        clkn = [ff_bot0.get_all_port_pins('CLK')[0], ff_bot1.get_all_port_pins('CLK')[0]]
        top_tidx = self.grid.coord_to_nearest_track(hm_layer, self.bound_box.height_unit,
                                                    half_track=False, unit_mode=True, mode=1)
        bot_tidx = -1
        hm_w_clk = tr_manager.get_width(hm_layer, 'clk')
        vm_w_clk = tr_manager.get_width(vm_layer, 'clk')
        ntr, ploc_list = tr_manager.place_wires(hm_layer, ['clk', 'sup', 'sup'], start_idx=top_tidx)
        _, nloc_list = tr_manager.place_wires(hm_layer, ['sup', 'sup', 'clk'], start_idx=bot_tidx - ntr)
        clk_tidx = None
        for name, warrs, tidx, wdir in [('clkp', clkp, ploc_list[0], 1), ('clkn', clkn, nloc_list[2], -1)]:
            tid = TrackID(hm_layer, tidx, width=hm_w_clk)
            warr = self.connect_to_tracks(warrs, tid, min_len_mode=0)
            if clk_tidx is None:
                clk_tidx = self.grid.coord_to_nearest_track(vm_layer, warr.middle, mode=0, half_track=True)
            tid = TrackID(vm_layer, clk_tidx, width=vm_w_clk)
            warr = self.connect_to_tracks(warr, tid, min_len_mode=wdir)
            self.add_pin(name, warr, show=show_pins)

        hm_w_sup = tr_manager.get_width(hm_layer, 'sup')
        vm_w_sup = tr_manager.get_width(vm_layer, 'sup')
        vss_list = [self.connect_to_tracks(vss_warrs, TrackID(hm_layer, ploc_list[1], width=hm_w_sup)),
                    self.connect_to_tracks(vss_warrs, TrackID(hm_layer, nloc_list[1], width=hm_w_sup))]
        vdd_list = [self.connect_to_tracks(vdd_warrs, TrackID(hm_layer, ploc_list[2], width=hm_w_sup)),
                    self.connect_to_tracks(vdd_warrs, TrackID(hm_layer, nloc_list[0], width=hm_w_sup))]

        _, sup_loc_list = tr_manager.place_wires(vm_layer, ['clk', 'sup', 'sup'])
        vdd_idx = sup_loc_list[2] + clk_tidx - sup_loc_list[0]
        vss_idx = sup_loc_list[1] + clk_tidx - sup_loc_list[0]
        vss = self.connect_to_tracks(vss_list, TrackID(vm_layer, vss_idx, width=vm_w_sup))
        vdd = self.connect_to_tracks(vdd_list, TrackID(vm_layer, vdd_idx, width=vm_w_sup))

        # export pins
        self.add_pin('VDD', vdd, show=show_pins)
        self.add_pin('VSS', vss, show=show_pins)

        # compute schematic parameters
        self._sch_params = dict(
            flop_info=flop_master.get_sch_master_info(),
            inv_info=inv_master.get_sch_master_info(),
        )
Exemplo n.º 3
0
    def draw_layout(self):
        """Draw the layout of a dynamic latch chain.
        """
        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']
        fg_dum = self.params['fg_dum']
        flip_out_sd = self.params['flip_out_sd']
        guard_ring_nf = self.params['guard_ring_nf']
        top_layer = self.params['top_layer']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        show_pins = self.params['show_pins']
        options = self.params['options']

        if options is None:
            options = {}

        # make SerdesRXBaseInfo and compute total number of fingers.
        serdes_info = SerdesRXBaseInfo(self.grid,
                                       lch,
                                       guard_ring_nf,
                                       top_layer=top_layer)
        diffamp_info = serdes_info.get_diffamp_info(seg_dict,
                                                    fg_dum=fg_dum,
                                                    flip_out_sd=flip_out_sd)
        fg_tot = diffamp_info['fg_tot']

        # construct number of tracks dictionary
        row_names = ['load', 'casc', 'in', 'sw', 'en', 'tail']
        gtr_lists = [['bias'], ['bias'], ['in', 'in'], ['bias'], ['bias'],
                     ['bias']]
        dtr_lists = [['out', 'out'], ['mid'], [], ['vdd'], ['tail'], ['tail']]
        dtr_names = [['outp', 'outn'], [('midp', 'midn')], [], ['vddn'],
                     ['tail'], ['tail']]

        # rename tail row drain net name if enable row exists
        if w_dict.get('en', 0) > 0:
            dtr_lists[-1][0] = 'foot'

        hm_layer = self.mos_conn_layer + 1
        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
        g_ntr_dict, ds_ntr_dict, tr_indices = {}, {}, {}
        for row_name, gtr_list, dtr_list, dtr_name_list in \
                zip(row_names, gtr_lists, dtr_lists, dtr_names):
            w_row = w_dict.get(row_name, 0)
            if w_row > 0:
                num_gtr, _ = tr_manager.place_wires(hm_layer, gtr_list)
                if dtr_list:
                    dtr_sp = tr_manager.get_space(hm_layer, dtr_list[0])
                    num_dtr, didx_list = tr_manager.place_wires(
                        hm_layer, dtr_list, start_idx=dtr_sp)
                    for dtr_name, dtr_idx in zip(dtr_name_list, didx_list):
                        if isinstance(dtr_name, tuple):
                            for dtr_n in dtr_name:
                                tr_indices[dtr_n] = dtr_idx
                        else:
                            tr_indices[dtr_name] = dtr_idx
                    num_dtr += 2 * dtr_sp
                else:
                    num_dtr = 1

                g_ntr_dict[row_name] = num_gtr
                ds_ntr_dict[row_name] = num_dtr

        # draw transistor rows
        self.draw_rows(lch,
                       fg_tot,
                       ptap_w,
                       ntap_w,
                       w_dict,
                       th_dict,
                       g_ntr_dict,
                       ds_ntr_dict,
                       guard_ring_nf=guard_ring_nf,
                       **options)

        # draw diffamp
        amp_ports, _ = self.draw_diffamp(0,
                                         seg_dict,
                                         tr_widths=tr_widths,
                                         tr_spaces=tr_spaces,
                                         tr_indices=tr_indices,
                                         fg_dum=fg_dum,
                                         flip_out_sd=flip_out_sd)

        # add dummies and pins
        vss_warrs, vdd_warrs = self.fill_dummy()
        self.add_pin('VSS', vss_warrs)
        self.add_pin('VDD', vdd_warrs)
        hide_pins = {'midp', 'midn', 'tail', 'foot'}
        for pname, warrs in amp_ports.items():
            self.add_pin(pname,
                         warrs,
                         show=show_pins and pname not in hide_pins)

        # compute schematic parameters
        self._sch_params = dict(
            lch=lch,
            w_dict=w_dict.copy(),
            th_dict=th_dict.copy(),
            seg_dict=seg_dict.copy(),
            dum_info=self.get_sch_dummy_info(),
        )
Exemplo n.º 4
0
    def draw_layout(self):
        # get parameters
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        show_pins = self.params['show_pins']
        export_probe = self.params['export_probe']

        sum_master, end_row_master, div2_master, div3_master = self._make_masters(
        )

        end_row_box = end_row_master.array_box
        sum_arr_box = sum_master.array_box

        # place instances
        vm_layer = top_layer = sum_master.top_layer
        bot_row = self.add_instance(end_row_master,
                                    'XROWB',
                                    loc=(0, 0),
                                    unit_mode=True)
        y1 = ycur = end_row_box.top_unit
        inst1 = self.add_instance(sum_master,
                                  'X1',
                                  loc=(0, ycur),
                                  unit_mode=True)
        ycur += sum_arr_box.top_unit + sum_arr_box.top_unit
        inst2 = self.add_instance(sum_master,
                                  'X2',
                                  loc=(0, ycur),
                                  orient='MX',
                                  unit_mode=True)
        inst0 = self.add_instance(sum_master,
                                  'X0',
                                  loc=(0, ycur),
                                  unit_mode=True)
        y3 = ycur = ycur + sum_arr_box.top_unit + sum_arr_box.top_unit
        inst3 = self.add_instance(sum_master,
                                  'X3',
                                  loc=(0, ycur),
                                  orient='MX',
                                  unit_mode=True)
        ycur += end_row_box.top_unit
        top_row = self.add_instance(end_row_master,
                                    'XROWT',
                                    loc=(0, ycur),
                                    orient='MX',
                                    unit_mode=True)
        inst_list = [inst0, inst1, inst2, inst3]
        self.fill_box = inst1.fill_box.merge(inst3.fill_box)
        blockage_y = [0, top_row.bound_box.top_unit]

        div_grp_x0, div_grp_y0 = sum_master.div_grp_loc
        div_grp_x = div_grp_x0 - div3_master.array_box.left_unit
        div_grp_y3 = div_grp_y0 + y1
        div_grp_y2 = y3 - div_grp_y0
        div3_inst = self.add_instance(div3_master,
                                      'XDIV3',
                                      loc=(div_grp_x, div_grp_y3),
                                      unit_mode=True)
        div2_inst = self.add_instance(div2_master,
                                      'XDIV2',
                                      loc=(div_grp_x, div_grp_y2),
                                      orient='MX',
                                      unit_mode=True)

        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)

        # re-export supply pins
        vdd_list = list(
            chain(div3_inst.port_pins_iter('VDD'),
                  div2_inst.port_pins_iter('VDD'),
                  *(inst.port_pins_iter('VDD') for inst in inst_list)))
        vss_list = list(
            chain(div3_inst.port_pins_iter('VSS'),
                  div2_inst.port_pins_iter('VSS'),
                  *(inst.port_pins_iter('VSS') for inst in inst_list)))
        vdd_list = self.connect_wires(vdd_list)
        vss_list = self.connect_wires(vss_list)
        self.add_pin('VDD', vdd_list, show=show_pins)
        self.add_pin('VSS', vss_list, show=show_pins)

        # draw wires
        # compute output wire tracks
        xr = vdd_list[0].upper_unit
        tidx0 = self.grid.find_next_track(vm_layer, xr, mode=1, unit_mode=True)
        _, out_locs = tr_manager.place_wires(
            vm_layer, [1, 'out', 'out', 1, 'out', 'out', 1, 'out', 'out', 1],
            start_idx=tidx0)

        # re-export ports, and gather wires
        outp_warrs = [[], [], [], []]
        outn_warrs = [[], [], [], []]
        en_warrs = [[div2_inst.get_pin('qb')], [div3_inst.get_pin('qb')],
                    [div2_inst.get_pin('q')], [div3_inst.get_pin('q')]]
        biasf_warrs = []
        clk_warrs = [
            list(
                chain(div2_inst.port_pins_iter('clkp'),
                      div3_inst.port_pins_iter('clkp'))),
            list(
                chain(div2_inst.port_pins_iter('clkn'),
                      div3_inst.port_pins_iter('clkn')))
        ]
        biasd_warrs = []
        biasm_warrs = []
        for idx, inst in enumerate(inst_list):
            pidx = (idx + 1) % 4
            nidx = (idx - 1) % 4
            outp_warrs[idx].extend(inst.port_pins_iter('outp_m'))
            outn_warrs[idx].extend(inst.port_pins_iter('outn_m'))
            outp_warrs[pidx].extend(inst.port_pins_iter('fbp'))
            outn_warrs[pidx].extend(inst.port_pins_iter('fbn'))
            biasf_warrs.extend(inst.port_pins_iter('biasp_f'))
            biasm_warrs.extend(inst.port_pins_iter('biasp_m'))
            biasd_warrs.extend(inst_list[pidx].port_pins_iter('biasn_d'))
            for off in range(4):
                en_pin = 'en<%d>' % off
                en_idx = (off + idx + 1) % 4
                if inst.has_port(en_pin):
                    en_warrs[en_idx].extend(inst.port_pins_iter(en_pin))

            self.reexport(inst.get_port('inp'),
                          net_name='inp<%d>' % pidx,
                          show=show_pins)
            self.reexport(inst.get_port('inn'),
                          net_name='inn<%d>' % pidx,
                          show=show_pins)
            self.reexport(inst.get_port('outp_main'),
                          net_name='outp<%d>' % idx,
                          show=show_pins)
            self.reexport(inst.get_port('outn_main'),
                          net_name='outn<%d>' % idx,
                          show=show_pins)
            self.reexport(inst.get_port('outp_d'),
                          net_name='outp_d<%d>' % nidx,
                          show=show_pins)
            self.reexport(inst.get_port('outn_d'),
                          net_name='outn_d<%d>' % nidx,
                          show=show_pins)
            if idx % 2 == 1:
                clk_warrs[0].extend(inst.port_pins_iter('clkp'))
                clk_warrs[1].extend(inst.port_pins_iter('clkn'))
            else:
                clk_warrs[1].extend(inst.port_pins_iter('clkp'))
                clk_warrs[0].extend(inst.port_pins_iter('clkn'))

        # connect output wires
        out_map = [4, 4, 1, 1]
        vm_w_out = tr_manager.get_width(vm_layer, 'out')
        for outp, outn, idx in zip(outp_warrs, outn_warrs, out_map):
            self.connect_differential_tracks(outp,
                                             outn,
                                             vm_layer,
                                             out_locs[idx],
                                             out_locs[idx + 1],
                                             width=vm_w_out)

        # draw enable wires
        en_locs = sum_master.en_locs
        vm_w_en = tr_manager.get_width(vm_layer, 'en')
        for en_idx, (tr_idx, en_warr) in enumerate(zip(en_locs, en_warrs)):
            en_warr = self.connect_to_tracks(
                en_warr, TrackID(vm_layer, tr_idx, width=vm_w_en))
            if export_probe:
                self.add_pin('en<%d>' % en_idx, en_warr, show=show_pins)

        # draw clock/bias_f wires
        vm_w_clk = tr_manager.get_width(vm_layer, 'clk')
        start_idx0 = en_locs[3] - (vm_w_en - 1) / 2
        ntr = out_locs[0] + 1 - start_idx0
        try:
            clk_locs = tr_manager.spread_wires(
                vm_layer, ['en', 1, 'clk', 'clk', 'clk', 'clk', 1],
                ntr, ('clk', ''),
                alignment=1,
                start_idx=start_idx0)
        except ValueError:
            sp_min = self.grid.get_num_space_tracks(vm_layer,
                                                    vm_w_clk,
                                                    half_space=True)
            clk_locs = tr_manager.spread_wires(
                vm_layer, ['en', 1, 'clk', 'clk', 'clk', 'clk', 1],
                ntr, ('clk', ''),
                alignment=1,
                start_idx=start_idx0,
                sp_override={('clk', 'clk'): {
                                 vm_layer: sp_min
                             }})

        clkn, clkp = self.connect_differential_tracks(clk_warrs[1],
                                                      clk_warrs[0],
                                                      vm_layer,
                                                      clk_locs[2],
                                                      clk_locs[5],
                                                      width=vm_w_clk)
        bf0, bf3 = self.connect_differential_tracks(biasf_warrs[0],
                                                    biasf_warrs[3],
                                                    vm_layer,
                                                    clk_locs[3],
                                                    clk_locs[4],
                                                    width=vm_w_clk)
        bf2, bf1 = self.connect_differential_tracks(biasf_warrs[2],
                                                    biasf_warrs[1],
                                                    vm_layer,
                                                    clk_locs[3],
                                                    clk_locs[4],
                                                    width=vm_w_clk)
        self.add_pin('clkp', clkp, show=show_pins)
        self.add_pin('clkn', clkn, show=show_pins)
        self.add_pin('bias_f<0>', bf0, show=show_pins, edge_mode=1)
        blockage_y[1] = min(blockage_y[1], bf0.lower_unit)
        self.add_pin('bias_f<1>', bf1, show=show_pins, edge_mode=-1)
        blockage_y[0] = max(blockage_y[0], bf1.upper_unit)
        self.add_pin('bias_f<2>', bf2, show=show_pins, edge_mode=-1)
        self.add_pin('bias_f<3>', bf3, show=show_pins, edge_mode=1)

        # compute bias_m/bias_d wires locations
        shield_tidr = tr_manager.get_next_track(vm_layer,
                                                en_locs[0],
                                                'en',
                                                1,
                                                up=False)
        sp_clk = clk_locs[3] - clk_locs[2]
        sp_clk_shield = clk_locs[2] - clk_locs[1]
        right_tidx = shield_tidr - sp_clk_shield
        bias_locs = [right_tidx + idx * sp_clk for idx in range(-3, 1, 1)]
        shield_tidl = bias_locs[0] - sp_clk_shield
        # draw shields
        self._blockage_intvs = []
        sh_tid = TrackID(vm_layer,
                         shield_tidl,
                         num=2,
                         pitch=shield_tidr - shield_tidl)
        sh_warrs = self.connect_to_tracks(vss_list, sh_tid, unit_mode=True)
        tr_lower, tr_upper = sh_warrs.lower_unit, sh_warrs.upper_unit
        sh_box = sh_warrs.get_bbox_array(self.grid).get_overall_bbox()
        self._blockage_intvs.append(sh_box.get_interval('x', unit_mode=True))
        self.add_pin('VSS', sh_warrs, show=show_pins)

        sh_pitch = out_locs[3] - out_locs[0]
        out_sh_tid = TrackID(vm_layer,
                             out_locs[0] + sh_pitch,
                             num=2,
                             pitch=sh_pitch)
        sh_warrs = self.connect_to_tracks(vdd_list,
                                          out_sh_tid,
                                          track_lower=tr_lower,
                                          track_upper=tr_upper,
                                          unit_mode=True)
        self.add_pin('VDD', sh_warrs, show=show_pins)

        clk_sh_tid = TrackID(vm_layer,
                             clk_locs[1],
                             num=2,
                             pitch=out_locs[0] - clk_locs[1])
        sh_warrs = self.connect_to_tracks(vdd_list,
                                          clk_sh_tid,
                                          track_lower=tr_lower,
                                          track_upper=tr_upper,
                                          unit_mode=True)
        sh_box = sh_warrs.get_bbox_array(self.grid).get_overall_bbox()
        self._blockage_intvs.append(sh_box.get_interval('x', unit_mode=True))
        self.add_pin('VDD', sh_warrs, show=show_pins)
        self.add_pin('VDD_ext', sh_warrs, show=False)

        bm0, bm3 = self.connect_differential_tracks(biasm_warrs[0],
                                                    biasm_warrs[3],
                                                    vm_layer,
                                                    bias_locs[0],
                                                    bias_locs[3],
                                                    width=vm_w_clk)
        bm2, bm1 = self.connect_differential_tracks(biasm_warrs[2],
                                                    biasm_warrs[1],
                                                    vm_layer,
                                                    bias_locs[0],
                                                    bias_locs[3],
                                                    width=vm_w_clk)
        bd2, bd3 = self.connect_differential_tracks(biasd_warrs[2],
                                                    biasd_warrs[3],
                                                    vm_layer,
                                                    bias_locs[1],
                                                    bias_locs[2],
                                                    width=vm_w_clk)
        bd0, bd1 = self.connect_differential_tracks(biasd_warrs[0],
                                                    biasd_warrs[1],
                                                    vm_layer,
                                                    bias_locs[1],
                                                    bias_locs[2],
                                                    width=vm_w_clk)
        self.add_pin('bias_m<0>', bm0, show=show_pins, edge_mode=1)
        blockage_y[1] = min(blockage_y[1], bm0.lower_unit)
        self.add_pin('bias_m<1>', bm1, show=show_pins, edge_mode=-1)
        blockage_y[0] = max(blockage_y[0], bm1.upper_unit)
        self.add_pin('bias_m<2>', bm2, show=show_pins, edge_mode=-1)
        self.add_pin('bias_m<3>', bm3, show=show_pins, edge_mode=1)
        self.add_pin('bias_d<0>', bd0, show=show_pins, edge_mode=-1)
        self.add_pin('bias_d<1>', bd1, show=show_pins, edge_mode=-1)
        blockage_y[0] = max(blockage_y[0], bd1.upper_unit)
        self.add_pin('bias_d<2>', bd2, show=show_pins, edge_mode=1)
        blockage_y[1] = min(blockage_y[1], bd2.lower_unit)
        self.add_pin('bias_d<3>', bd3, show=show_pins, edge_mode=1)

        # set size
        bnd_box = bot_row.bound_box.merge(top_row.bound_box)
        bnd_xr = self.grid.track_to_coord(vm_layer,
                                          out_locs[0] + 2 * sh_pitch + 0.5,
                                          unit_mode=True)
        bnd_box = bnd_box.extend(x=bnd_xr, unit_mode=True)
        self.set_size_from_bound_box(top_layer, bnd_box)
        self.array_box = bnd_box
        self.add_cell_boundary(bnd_box)

        # mark blockages
        res = self.grid.resolution
        for xl, xu in self._blockage_intvs:
            self.mark_bbox_used(
                vm_layer,
                BBox(xl,
                     bnd_box.bottom_unit,
                     xu,
                     blockage_y[0],
                     res,
                     unit_mode=True))
            self.mark_bbox_used(
                vm_layer,
                BBox(xl,
                     blockage_y[1],
                     xu,
                     bnd_box.top_unit,
                     res,
                     unit_mode=True))
        # draw en_div/scan wires
        tr_scan = shield_tidl - 1
        tr_en2 = tr_scan - sp_clk_shield
        tr_en_div = tr_en2 - sp_clk_shield
        scan_tid = TrackID(vm_layer, tr_scan)
        en2_tid = TrackID(vm_layer, tr_en2, width=vm_w_clk)
        en_div_tid = TrackID(vm_layer, tr_en_div)
        scan3 = self.connect_to_tracks(div3_inst.get_pin('scan_s'),
                                       scan_tid,
                                       min_len_mode=1)
        scan2 = self.connect_to_tracks(div2_inst.get_pin('scan_s'),
                                       scan_tid,
                                       min_len_mode=-1)
        self.add_pin('scan_div<3>', scan3, show=show_pins)
        self.add_pin('scan_div<2>', scan2, show=show_pins)
        self.connect_to_tracks(
            [div3_inst.get_pin('en2'),
             div2_inst.get_pin('en2')], en2_tid)
        en_div = self.connect_to_tracks(div3_inst.get_pin('in'),
                                        en_div_tid,
                                        min_len_mode=1)
        self.add_pin('en_div', en_div, show=show_pins)

        # set schematic parameters
        self._sch_params = dict(
            sum_params=sum_master.sch_params['sum_params'],
            lat_params=sum_master.sch_params['lat_params'],
            div_params=div3_master.sch_params,
            export_probe=export_probe,
        )
        inp = sum_master.get_port('inp').get_pins()[0].track_id
        inn = sum_master.get_port('inn').get_pins()[0].track_id
        outp_m = sum_master.get_port('outp_m').get_pins()[0].track_id
        outn_m = sum_master.get_port('outn_m').get_pins()[0].track_id
        self._in_tr_info = (inp.base_index, inn.base_index, inp.width)
        self._out_tr_info = (outp_m.base_index, outn_m.base_index,
                             outp_m.width)
        self._data_tr_info = sum_master.data_tr_info
        self._div_tr_info = sum_master.div_tr_info
        self._sum_row_info = sum_master.sum_row_info
        self._lat_row_info = sum_master.lat_row_info
Exemplo n.º 5
0
    def draw_layout(self):
        """Draw the layout of a dynamic latch chain.
        """
        w_dict = self.params['w_dict']
        th_dict = self.params['th_dict']
        seg_dict = self.params['seg_dict']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        top_layer = self.params['top_layer']
        draw_boundaries = self.params['draw_boundaries']
        end_mode = self.params['end_mode']
        min_height = self.params['min_height']
        sup_tids = self.params['sup_tids']
        clk_tidx = self.params['clk_tidx']
        show_pins = self.params['show_pins']
        export_probe = self.params['export_probe'] and show_pins

        n_in = seg_dict['in']
        n_tail = seg_dict['tail']
        n_ninv = seg_dict['ninv']
        n_pinv = seg_dict['pinv']
        n_rst = seg_dict['rst']
        n_dum = seg_dict['dum']
        n_nand = seg_dict['nand']
        n_buf = seg_dict['buf']
        blk_sp = seg_dict.get('sp', 2)

        if n_tail > n_in or n_in > n_ninv:
            raise ValueError(
                'This generator only works for seg_tail <= seg_in <= seg_ninv')

        # error checking
        for name, val in seg_dict.items():
            if name != 'sp' and (val % 2 != 0 or val <= 0):
                raise ValueError('seg_%s = %d is not even or positive.' %
                                 (name, val))

        w_sub = self.params['config']['w_sub']
        w_tail = w_dict['tail']
        w_in = w_dict['in']
        w_ninv = w_dict['ninv']
        w_pinv = w_dict['pinv']

        th_tail = th_dict['tail']
        th_in = th_dict['in']
        th_ninv = th_dict['ninv']
        th_pinv = th_dict['pinv']

        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)

        # get row information
        row_list = ['ptap', 'ptap', 'nch', 'nch', 'nch', 'pch', 'ntap', 'ntap']
        orient_list = ['R0', 'R0', 'R0', 'MX', 'MX', 'R0', 'MX', 'MX']
        thres_list = [
            th_tail, th_tail, th_tail, th_in, th_ninv, th_pinv, th_pinv,
            th_pinv
        ]
        w_list = [w_sub, w_sub, w_tail, w_in, w_ninv, w_pinv, w_sub, w_sub]
        if end_mode is None:
            end_mode = 15 if draw_boundaries else 0

        # get track information
        wire_names = [
            dict(ds=['sup'], ),
            dict(ds=['sup'], ),
            dict(
                g=['clk'],
                gb=['tail'],
            ),
            dict(
                g=['in', 'in'],
                gb=['out'],
            ),
            dict(
                g=['out', 'out'],
                gb=['out'],
            ),
            dict(
                g=['out', 'out'],
                gb=['out', 'out'],
            ),
            dict(ds=['sup'], ),
            dict(ds=['sup'], ),
        ]

        # determine number of blocks
        laygo_info = self.laygo_info
        lch = laygo_info.lch
        hm_layer = self.conn_layer + 1
        ym_layer = hm_layer + 1
        xm_layer = ym_layer + 1
        # determine number of separation blocks needed for mid reset wires to be DRC clean
        hm_w_out = tr_manager.get_width(hm_layer, 'out')
        vm_w = self.grid.get_track_width(hm_layer - 1, 1,
                                         unit_mode=True)  # type: int
        hm_out_vext = self.grid.get_via_extensions(
            hm_layer - 1, 1, hm_w_out, unit_mode=True)[1]  # type: int
        hm_out_sple = self.grid.get_line_end_space(hm_layer,
                                                   hm_w_out,
                                                   unit_mode=True)  # type: int
        n_sep = -(-(vm_w + hm_out_vext * 2 + hm_out_sple) //
                  (2 * laygo_info.col_width)) * 2
        # determine total number of latch blocks
        n_ptot = n_pinv + 2 * n_rst
        n_ntot = max(n_ninv, n_in, n_tail)
        n_single = max(n_ptot, n_ntot)
        n_latch = n_sep + 2 * (n_single + n_dum)
        col_p = n_dum + n_single - n_ptot
        col_ninv = n_dum + n_single - n_ninv
        col_in = n_dum + n_single - n_in
        col_tail = n_dum + n_single - n_tail

        # find space between latch and nand gates from wire placement
        # step 1: find relative track index of clock
        clk_col = n_dum + n_single + n_sep // 2
        clk_ridx = laygo_info.col_to_nearest_rel_track(ym_layer,
                                                       clk_col,
                                                       half_track=True,
                                                       mode=0)
        # step 2: find relative track index of outp
        op_col = col_ninv + n_ninv // 2
        op_ridx = laygo_info.col_to_nearest_rel_track(ym_layer,
                                                      op_col,
                                                      half_track=True,
                                                      mode=-1)
        # make sure spacing between outp and clk is satisfied.
        op_ridx2 = tr_manager.get_next_track(ym_layer,
                                             clk_ridx,
                                             'clk',
                                             'out',
                                             up=False)
        op_ridx = min(op_ridx, op_ridx2)
        # step 3: find NAND outp relative track index
        num_ym_tracks, loc_ym = tr_manager.place_wires(ym_layer, ['out'] * 6)
        on_ridx = clk_ridx + (clk_ridx - op_ridx)
        nand_op_ridx = on_ridx + loc_ym[-1] - loc_ym[0]
        # step 4: find left NAND gate column index, then compute number of space columns
        col_nand = laygo_info.rel_track_to_nearest_col(ym_layer,
                                                       nand_op_ridx,
                                                       mode=1)
        n_sp = max(col_nand - n_latch - n_nand - blk_sp - n_buf, blk_sp)
        n_sr_tot = 2 * n_buf + 3 * blk_sp + 4 * n_nand
        n_tot = n_latch + n_sp + n_sr_tot

        # specify row types
        self.set_row_types(row_list,
                           w_list,
                           orient_list,
                           thres_list,
                           draw_boundaries,
                           end_mode,
                           top_layer=top_layer,
                           num_col=n_tot,
                           min_height=min_height,
                           tr_manager=tr_manager,
                           wire_names=wire_names)

        # calculate clk/outp/outn vertical track indices
        clk_idx = laygo_info.col_to_track(ym_layer, clk_col)
        op_idx = laygo_info.col_to_track(ym_layer, op_col)
        op_idx2 = tr_manager.get_next_track(ym_layer,
                                            clk_idx,
                                            'clk',
                                            'out',
                                            up=False)
        op_idx = min(op_idx, op_idx2)
        on_idx = clk_idx + (clk_idx - op_idx)

        # add blocks
        ndum_list, pdum_list, dum_info_list = [], [], []

        # nwell tap
        row_off = 1
        cur_col, row_idx = 0, 7
        nw_tap1 = self.add_laygo_mos(row_idx, cur_col, n_tot)
        row_idx -= 1
        nw_tap0 = self.add_laygo_mos(row_idx, cur_col, n_tot)
        row_idx -= 1

        # pmos inverter row
        cur_col = 0
        pdum_list.append(self.add_laygo_mos(row_idx, cur_col, col_p))
        cur_col += col_p
        rst_midp = self.add_laygo_mos(row_idx, cur_col, n_rst)
        cur_col += n_rst
        rst_outp = self.add_laygo_mos(row_idx, cur_col, n_rst)
        cur_col += n_rst
        pinv_outp = self.add_laygo_mos(row_idx, cur_col, n_pinv)
        cur_col += n_pinv
        pdum_list.append(self.add_laygo_mos(row_idx, cur_col, n_sep))
        cur_col += n_sep
        pinv_outn = self.add_laygo_mos(row_idx, cur_col, n_pinv)
        cur_col += n_pinv
        rst_outn = self.add_laygo_mos(row_idx, cur_col, n_rst)
        cur_col += n_rst
        rst_midn = self.add_laygo_mos(row_idx, cur_col, n_rst)
        cur_col += n_rst
        pdum_list.append(self.add_laygo_mos(row_idx, cur_col, col_p))
        cur_col += col_p + n_sp
        pbufl = self.add_laygo_mos(row_idx, cur_col, n_buf)
        cur_col += n_buf + blk_sp
        nandpl = self.add_laygo_mos(row_idx, cur_col, n_nand * 2, gate_loc='s')
        cur_col += n_nand * 2 + blk_sp
        nandpr = self.add_laygo_mos(row_idx, cur_col, n_nand * 2, gate_loc='s')
        cur_col += n_nand * 2 + blk_sp
        pbufr = self.add_laygo_mos(row_idx, cur_col, n_buf)
        dum_info_list.append(
            (('pch', w_pinv, lch, th_pinv, '', ''), 2 * col_p + n_sep))
        row_idx -= 1

        # nmos inverter row
        cur_col = 0
        cur_col = self._draw_nedge_dummy(row_idx,
                                         cur_col,
                                         col_ninv,
                                         ndum_list,
                                         left=True)
        ninv_outp = self.add_laygo_mos(row_idx, cur_col, n_ninv)
        cur_col += n_ninv
        cur_col = self._draw_nsep_dummy(row_idx, cur_col, n_sep, ndum_list)
        ninv_outn = self.add_laygo_mos(row_idx, cur_col, n_ninv)
        cur_col += n_ninv
        cur_col = self._draw_nedge_dummy(row_idx,
                                         cur_col,
                                         col_ninv,
                                         ndum_list,
                                         left=False)
        cur_col += n_sp
        nbufl = self.add_laygo_mos(row_idx, cur_col, n_buf)
        cur_col += n_buf + blk_sp
        nandnl = self.add_laygo_mos(row_idx,
                                    cur_col,
                                    n_nand,
                                    stack=True,
                                    gate_loc='s')
        cur_col += n_nand * 2 + blk_sp
        nandnr = self.add_laygo_mos(row_idx,
                                    cur_col,
                                    n_nand,
                                    stack=True,
                                    gate_loc='s')
        cur_col += n_nand * 2 + blk_sp
        nbufr = self.add_laygo_mos(row_idx, cur_col, n_buf)
        dum_info_list.append(
            (('nch', w_ninv, lch, th_ninv, '', ''), 2 * col_ninv + n_sep - 4))
        dum_info_list.append((('nch', w_ninv, lch, th_ninv, '', 'intp'), 2))
        dum_info_list.append((('nch', w_ninv, lch, th_ninv, '', 'intn'), 2))
        row_idx -= 1

        # nmos input row
        cur_col = 0
        cur_col = self._draw_nedge_dummy(row_idx,
                                         cur_col,
                                         col_in,
                                         ndum_list,
                                         left=True)
        inn = self.add_laygo_mos(row_idx, cur_col, n_in)
        cur_col += n_in
        cur_col = self._draw_nsep_dummy(row_idx, cur_col, n_sep, ndum_list)
        inp = self.add_laygo_mos(row_idx, cur_col, n_in)
        cur_col += n_in
        ndum = n_tot - cur_col
        self._draw_nedge_dummy(row_idx, cur_col, ndum, ndum_list, left=False)
        dum_info_list.append(
            (('nch', w_in, lch, th_in, '', ''), col_in + ndum + n_sep - 4))
        dum_info_list.append((('nch', w_in, lch, th_in, '', 'intp'), 2))
        dum_info_list.append((('nch', w_in, lch, th_in, '', 'intn'), 2))
        row_idx -= 1

        # nmos tail row
        cur_col = 0
        ndum_list.append((self.add_laygo_mos(row_idx, cur_col, col_tail), 0))
        cur_col += col_tail
        tailn = self.add_laygo_mos(row_idx, cur_col, n_tail)
        cur_col += n_tail
        ndum_list.append((self.add_laygo_mos(row_idx, cur_col, n_sep), 0))
        cur_col += n_sep
        tailp = self.add_laygo_mos(row_idx, cur_col, n_tail)
        cur_col += n_tail
        ndum = n_tot - cur_col
        ndum_list.append((self.add_laygo_mos(row_idx, cur_col, ndum), 0))
        dum_info_list.append(
            (('nch', w_tail, lch, th_tail, '', ''), col_in + ndum + n_sep))
        row_idx -= 1

        # pwell tap
        cur_col = 0
        pw_tap0 = self.add_laygo_mos(row_idx, cur_col, n_tot)
        row_idx -= 1
        pw_tap1 = self.add_laygo_mos(row_idx, cur_col, n_tot)

        # fill dummy
        self.fill_space()
        sup_tid = self.get_sup_tid(n_tot)

        # connect inputs
        inn_tid = self.get_wire_id(row_off + 2, 'g', wire_idx=0)
        inp_tid = self.get_wire_id(row_off + 2, 'g', wire_idx=1)
        inp_idx, inn_idx = inp_tid.base_index, inn_tid.base_index
        inp_warr, inn_warr = self.connect_differential_tracks(
            inp['g'],
            inn['g'],
            hm_layer,
            inp_idx,
            inn_idx,
            width=inp_tid.width)
        ym_w_in = tr_manager.get_width(ym_layer, 'in')
        shr_idx = sup_tid.base_index
        inp_idx = tr_manager.get_next_track(ym_layer,
                                            shr_idx,
                                            1,
                                            'in',
                                            up=False)
        inn_idx = tr_manager.get_next_track(ym_layer,
                                            inp_idx,
                                            'in',
                                            'in',
                                            up=False)
        shl_idx = tr_manager.get_next_track(ym_layer,
                                            inn_idx,
                                            'in',
                                            1,
                                            up=False)
        inp_ym, inn_ym = self.connect_differential_tracks(inp_warr,
                                                          inn_warr,
                                                          ym_layer,
                                                          inp_idx,
                                                          inn_idx,
                                                          width=ym_w_in)
        shields = self.add_wires(ym_layer,
                                 shl_idx,
                                 inp_ym.lower_unit,
                                 inp_ym.upper_unit,
                                 num=2,
                                 pitch=shr_idx - shl_idx,
                                 unit_mode=True)

        self.add_pin('inp', inp_ym, show=show_pins)
        self.add_pin('inn', inn_ym, show=show_pins)

        # connect vss
        xm_w_sup = tr_manager.get_width(xm_layer, 'sup')
        vss_s = [
            pw_tap0['VSS_s'], tailn['s'], tailp['s'], nandnl['s'], nandnr['s'],
            nbufl['s'], nbufr['s'], pw_tap1['VSS_s']
        ]
        vss_d = [pw_tap0['VSS_d'], pw_tap1['VSS_d']]
        for inst, mode in ndum_list:
            if mode == 0:
                vss_s.append(inst['s'])
            vss_d.append(inst['d'])
            vss_d.append(inst['g'])

        vss_s_tid = self.get_wire_id(row_off, 'ds')
        vss_s_tid2 = self.get_wire_id(0, 'ds')
        self.connect_wires(vss_d)
        vss_s_warrs = self.connect_to_tracks(vss_s, vss_s_tid)
        vss_s2_warrs = self.connect_to_tracks(vss_s, vss_s_tid2)
        vss_warrs = self.connect_to_tracks([vss_s_warrs, vss_s2_warrs],
                                           sup_tid)
        if sup_tids is not None:
            vss_warrs = self.connect_to_tracks(
                vss_warrs, TrackID(xm_layer, sup_tids[0], width=xm_w_sup))
        self.add_pin('VSS', vss_warrs, show=show_pins)

        # connect vdd
        vdd_s = [
            nw_tap0['VDD_s'], pinv_outp['s'], pinv_outn['s'], rst_midp['s'],
            rst_midn['s'], nandpl['s'], nandpr['s'], pbufl['s'], pbufr['s'],
            nw_tap1['VDD_s']
        ]
        vdd_d = [nw_tap0['VDD_d'], nw_tap1['VDD_d']]
        for inst in pdum_list:
            vdd_d.append(inst['d'])
            vdd_d.append(inst['g'])
            vdd_s.append(inst['s'])
        vdd_s_tid = self.get_wire_id(row_off + 5, 'ds')
        vdd_s2_tid = self.get_wire_id(row_off + 6, 'ds')
        self.connect_wires(vdd_d)
        vdd_s_warrs = self.connect_to_tracks(vdd_s, vdd_s_tid)
        vdd_s2_warrs = self.connect_to_tracks(vdd_s, vdd_s2_tid)
        vdd_hm_list = [vdd_s_warrs, vdd_s2_warrs]
        vdd_warrs = self.connect_to_tracks(vdd_hm_list, sup_tid)
        if shields is not None:
            self.connect_to_tracks(vdd_hm_list, shields.track_id)
            vdd_warrs = [vdd_warrs, shields]
        if sup_tids is not None:
            vdd_warrs = self.connect_to_tracks(
                vdd_warrs, TrackID(xm_layer, sup_tids[1], width=xm_w_sup))
        self.add_pin('VDD', vdd_warrs, show=show_pins)

        # connect tail
        tail = [tailp['d'], tailn['d'], inp['d'], inn['d']]
        tail_tid = self.get_wire_id(row_off + 1, 'gb', wire_idx=0)
        self.connect_to_tracks(tail, tail_tid)

        # connect tail clk
        tclk_tid = self.get_wire_id(row_off + 1, 'g', wire_idx=0)
        clk_list = [self.connect_to_tracks([tailp['g'], tailn['g']], tclk_tid)]

        # get output/mid horizontal track id
        nout_tid = self.get_wire_id(row_off + 3, 'gb', wire_idx=0)
        mid_tid = self.get_wire_id(row_off + 2, 'gb', wire_idx=0)
        # connect nmos mid
        nmidp = [inn['s'], ninv_outp['s']]
        nmidn = [inp['s'], ninv_outn['s']]
        nmidp = self.connect_to_tracks(nmidp, mid_tid)
        nmidn = self.connect_to_tracks(nmidn, mid_tid)

        # connect pmos mid
        mid_tid = self.get_wire_id(row_off + 4, 'gb', wire_idx=1)
        pmidp = self.connect_to_tracks(rst_midp['d'], mid_tid, min_len_mode=-1)
        pmidn = self.connect_to_tracks(rst_midn['d'], mid_tid, min_len_mode=1)

        # connect nmos output
        noutp = self.connect_to_tracks(ninv_outp['d'],
                                       nout_tid,
                                       min_len_mode=0)
        noutn = self.connect_to_tracks(ninv_outn['d'],
                                       nout_tid,
                                       min_len_mode=0)

        # connect pmos output
        pout_tid = self.get_wire_id(row_off + 4, 'gb', wire_idx=0)
        poutp = [pinv_outp['d'], rst_outp['d']]
        poutn = [pinv_outn['d'], rst_outn['d']]
        poutp = self.connect_to_tracks(poutp, pout_tid)
        poutn = self.connect_to_tracks(poutn, pout_tid)

        # connect clock in inverter row
        pclk = [rst_midp['g'], rst_midn['g'], rst_outp['g'], rst_outn['g']]
        pclk_tid = self.get_wire_id(row_off + 4, 'g', wire_idx=0)
        clk_list.append(self.connect_to_tracks(pclk, pclk_tid))

        # connect inverter gate
        invg_tid = self.get_wire_id(row_off + 3, 'g', wire_idx=1)
        invgp = self.connect_to_tracks([ninv_outp['g'], pinv_outp['g']],
                                       invg_tid)
        invgn = self.connect_to_tracks([ninv_outn['g'], pinv_outn['g']],
                                       invg_tid)

        # connect nand
        nand_gbl_tid = self.get_wire_id(row_off + 3, 'g', wire_idx=0)
        nand_gtl_tid = self.get_wire_id(row_off + 3, 'g', wire_idx=1)
        nand_gtr_tid = self.get_wire_id(row_off + 4, 'g', wire_idx=0)
        nand_gbr_tid = self.get_wire_id(row_off + 4, 'g', wire_idx=1)
        nand_nmos_out_tid = self.get_wire_id(row_off + 3, 'gb', wire_idx=0)
        nand_outnl = self.connect_to_tracks(nandnl['d'],
                                            nand_nmos_out_tid,
                                            min_len_mode=0)
        nand_outnr = self.connect_to_tracks(nandnr['d'],
                                            nand_nmos_out_tid,
                                            min_len_mode=0)

        nand_gtl = [
            nandnl['g1'], nandpl['g1'], nandpr['d'], nbufr['g'], pbufr['g']
        ]
        nand_gtr = [
            nandnr['g1'], nandpr['g1'], nandpl['d'], nbufl['g'], pbufl['g']
        ]
        tr_w = nand_gtr_tid.width
        pidx = nand_gtr_tid.base_index
        nidx = nand_gtl_tid.base_index
        nand_outpl, nand_outpr = self.connect_differential_tracks(nand_gtr,
                                                                  nand_gtl,
                                                                  hm_layer,
                                                                  pidx,
                                                                  nidx,
                                                                  width=tr_w)
        nand_gbl = self.connect_to_tracks([nandnl['g0'], nandpl['g0']],
                                          nand_gbl_tid)
        nand_gbr = self.connect_to_tracks([nandnr['g0'], nandpr['g0']],
                                          nand_gbr_tid)

        # connect buffer
        buf_pmos_out_tid = self.get_wire_id(row_off + 4, 'gb', wire_idx=0)
        buf_noutl = self.connect_to_tracks(nbufl['d'],
                                           nand_nmos_out_tid,
                                           min_len_mode=0)
        buf_noutr = self.connect_to_tracks(nbufr['d'],
                                           nand_nmos_out_tid,
                                           min_len_mode=0)
        buf_poutl = self.connect_to_tracks(pbufl['d'],
                                           buf_pmos_out_tid,
                                           min_len_mode=0)
        buf_poutr = self.connect_to_tracks(pbufr['d'],
                                           buf_pmos_out_tid,
                                           min_len_mode=0)

        # connect buffer ym wires
        ym_w_out = tr_manager.get_width(ym_layer, 'out')
        outb_tid = self.grid.coord_to_nearest_track(ym_layer,
                                                    buf_noutl.middle_unit,
                                                    half_track=True,
                                                    mode=1,
                                                    unit_mode=True)
        out_tid = self.grid.coord_to_nearest_track(ym_layer,
                                                   buf_noutr.middle_unit,
                                                   half_track=True,
                                                   mode=-1,
                                                   unit_mode=True)
        self.connect_to_tracks([buf_noutl, buf_poutl],
                               TrackID(ym_layer, outb_tid, width=ym_w_out))
        out_warr = self.connect_to_tracks([buf_noutr, buf_poutr],
                                          TrackID(ym_layer,
                                                  out_tid,
                                                  width=ym_w_out))

        # connect nand ym wires
        nand_outl_id = self.grid.coord_to_nearest_track(ym_layer,
                                                        nand_outnl.middle_unit,
                                                        half_track=True,
                                                        mode=1,
                                                        unit_mode=True)
        nand_outr_id = self.grid.coord_to_nearest_track(ym_layer,
                                                        nand_outnr.middle_unit,
                                                        half_track=True,
                                                        mode=-1,
                                                        unit_mode=True)
        nand_gbr_yt = self.grid.get_wire_bounds(hm_layer,
                                                nand_gbr_tid.base_index,
                                                unit_mode=True)[1]
        ym_via_ext = self.grid.get_via_extensions(hm_layer,
                                                  1,
                                                  1,
                                                  unit_mode=True)[1]
        out_upper = nand_gbr_yt + ym_via_ext
        nand_outl, nand_outr = self.connect_differential_tracks(
            nand_outpl,
            nand_outpr,
            ym_layer,
            nand_outl_id,
            nand_outr_id,
            track_upper=out_upper,
            width=ym_w_out,
            unit_mode=True)
        nand_outl = self.connect_to_tracks(nand_outnl,
                                           nand_outl.track_id,
                                           track_upper=out_upper,
                                           unit_mode=True)
        nand_outr = self.connect_to_tracks(nand_outnr,
                                           nand_outr.track_id,
                                           track_upper=out_upper,
                                           unit_mode=True)
        self.add_pin('qp', nand_outl, show=export_probe)
        self.add_pin('qn', nand_outr, show=export_probe)

        ym_pitch_out = tr_manager.get_space(ym_layer,
                                            ('out', 'out')) + ym_w_out
        nand_inn_tid = nand_outl_id - ym_pitch_out
        nand_inp_tid = nand_outr_id + ym_pitch_out
        self.connect_differential_tracks(nand_gbl,
                                         nand_gbr,
                                         ym_layer,
                                         nand_inn_tid,
                                         nand_inp_tid,
                                         width=ym_w_out)

        # connect ym wires
        clk_tid = TrackID(ym_layer,
                          clk_idx,
                          width=tr_manager.get_width(ym_layer, 'clk'))
        clk_warr = self.connect_to_tracks(clk_list, clk_tid)
        if clk_tidx is not None:
            clk_tid = TrackID(xm_layer,
                              clk_tidx,
                              width=tr_manager.get_width(xm_layer, 'clk'))
            clk_warr = self.connect_to_tracks(clk_warr, clk_tid)
        self.add_pin('clk', clk_warr, show=show_pins)

        tr_w_out_ym = tr_manager.get_width(ym_layer, 'out')
        sp_out_ym = tr_manager.get_space(ym_layer,
                                         ('out', 'out')) + tr_w_out_ym
        op_tid = TrackID(ym_layer, op_idx, width=tr_w_out_ym)
        outp1 = self.connect_to_tracks([poutp, noutp], op_tid)
        on_tid = TrackID(ym_layer, on_idx, width=tr_w_out_ym)
        outn1 = self.connect_to_tracks([poutn, noutn], on_tid)
        op_tid = TrackID(ym_layer, on_idx + sp_out_ym, width=tr_w_out_ym)
        on_tid = TrackID(ym_layer, op_idx - sp_out_ym, width=tr_w_out_ym)
        outp2 = self.connect_to_tracks(invgn, op_tid)
        outn2 = self.connect_to_tracks(invgp, on_tid)

        ym_sp_out = tr_manager.get_space(ym_layer, ('out', 'out'))
        sp_out_mid = sp_out_ym + ym_sp_out + (ym_w_out + tr_w_out_ym) / 2
        mn_tid = TrackID(ym_layer, on_idx + sp_out_mid, width=ym_w_out)
        mp_tid = TrackID(ym_layer, op_idx - sp_out_mid, width=ym_w_out)
        self.connect_to_tracks([nmidn, pmidn], mn_tid)
        self.connect_to_tracks([nmidp, pmidp], mp_tid)

        om_idx = self.grid.coord_to_nearest_track(xm_layer,
                                                  outp1.middle,
                                                  half_track=True)
        _, loc_xm_out = tr_manager.place_wires(xm_layer, ['out', 'out'])
        out_mid_idx = (loc_xm_out[0] + loc_xm_out[1]) / 2
        midp_idx = loc_xm_out[1] + om_idx - out_mid_idx
        midn_idx = loc_xm_out[0] + om_idx - out_mid_idx
        tr_w_out_xm = tr_manager.get_width(xm_layer, 'out')
        midp, midn = self.connect_differential_tracks([outp1, outp2],
                                                      [outn1, outn2],
                                                      xm_layer,
                                                      midp_idx,
                                                      midn_idx,
                                                      width=tr_w_out_xm)
        self.add_pin('midp', midp, show=export_probe)
        self.add_pin('midn', midn, show=export_probe)
        self.connect_differential_tracks(midn,
                                         midp,
                                         ym_layer,
                                         nand_inn_tid,
                                         nand_inp_tid,
                                         width=ym_w_out)

        out_xm_idx = self.grid.get_middle_track(midn_idx,
                                                midp_idx,
                                                round_up=True)
        out_warr = self.connect_to_tracks(
            out_warr, TrackID(xm_layer, out_xm_idx, width=tr_w_out_xm))
        self.add_pin('out', out_warr, show=show_pins)

        # do max space fill
        for lay_id in range(1, xm_layer):
            self.do_max_space_fill(lay_id)
        self.fill_box = self.bound_box

        # set schematic parameters
        self._sch_params = dict(
            lch=lch,
            w_dict=w_dict,
            th_dict=th_dict,
            seg_dict=seg_dict,
            dum_info=dum_info_list,
            export_probe=export_probe,
        )
        self._fg_tot = n_tot
Exemplo n.º 6
0
    def draw_layout(self):
        blk_sp = 2
        fanout = 4

        config = self.params['config']

        seg = self.params['seg']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        wp = self.params['wp']
        wn = self.params['wn']
        row_layout_info = self.params['row_layout_info']
        sig_locs = self.params['sig_locs']
        show_pins = self.params['show_pins']

        wp_row = config['wp']
        wn_row = config['wn']
        if wp is None:
            wp = wp_row
        if wn is None:
            wn = wn_row
        if wp < 0 or wp > wp_row or wn < 0 or wn > wn_row:
            raise ValueError('Invalid choice of wp and/or wn.')
        if sig_locs is None:
            sig_locs = {}

        # setup floorplan
        params = self.params.copy()
        params['wp'] = wp
        params['wn'] = wn
        params['show_pins'] = False
        params['sig_locs'] = None
        params['out_vm'] = True
        if row_layout_info is not None:
            self.initialize(row_layout_info, 1)
        else:
            inv_master = self.new_template(params=params, temp_cls=Inverter)
            params[
                'row_layout_info'] = row_layout_info = inv_master.row_layout_info
            self.initialize(row_layout_info, 1)

        # compute track locations
        hm_layer = self.conn_layer + 1
        ym_layer = hm_layer + 1
        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)
        g_locs = tr_manager.place_wires(hm_layer, ['in', 'in'])[1]
        d_locs = tr_manager.place_wires(hm_layer, ['out', 'out'])[1]
        ng0_tidx = self.get_track_index(0, 'g', g_locs[0])
        ng1_tidx = self.get_track_index(0, 'g', g_locs[1])
        pg0_tidx = self.get_track_index(1, 'g', g_locs[0])
        pg1_tidx = self.get_track_index(1, 'g', g_locs[1])
        nd0_tidx = self.get_track_index(0, 'gb', d_locs[0])
        nd1_tidx = self.get_track_index(0, 'gb', d_locs[1])
        pd0_tidx = self.get_track_index(1, 'gb', d_locs[0])
        pd1_tidx = self.get_track_index(1, 'gb', d_locs[1])

        pen_tidx = sig_locs.get('pen', pg1_tidx)
        nen_tidx = sig_locs.get('nen', ng1_tidx)
        in0_tidx = sig_locs.get('in0', pg0_tidx)
        in1_tidx = sig_locs.get('in1', ng0_tidx)
        out_vm_tidx = sig_locs.get('out', None)

        # make masters
        seg_in = max(1, int(round(seg / (fanout // 2))))
        seg_sel = max(1, int(round(seg_in // fanout)))
        params['sig_locs'] = {
            'in': pen_tidx,
            'pout': pd0_tidx,
            'nout': nd0_tidx
        }
        params['out_vm'] = False
        inv_master = self.new_template(params=params, temp_cls=Inverter)

        params['seg'] = seg_sel
        params['sig_locs'] = {
            'in': pen_tidx,
            'pout': pd0_tidx,
            'nout': nd0_tidx
        }
        params['out_vm'] = True
        sel_master = self.new_template(params=params, temp_cls=Inverter)

        params['seg'] = seg_in
        params['sig_locs'] = {
            'in': in0_tidx,
            'pout': pd1_tidx,
            'nout': nd1_tidx,
            'en': nen_tidx,
            'enb': pen_tidx
        }
        params['out_vm'] = False
        t0_master = self.new_template(params=params, temp_cls=InverterTristate)
        params['sig_locs'] = {
            'in': in1_tidx,
            'pout': pd1_tidx,
            'nout': nd1_tidx,
            'en': nen_tidx,
            'enb': pen_tidx
        }
        t1_master = self.new_template(params=params, temp_cls=InverterTristate)

        # set size
        sel_ncol = sel_master.num_cols
        sel_sep = blk_sp + 1 if sel_ncol % 2 == 1 else blk_sp
        t0_ncol = t0_master.num_cols
        t1_ncol = t1_master.num_cols
        inv_ncol = inv_master.num_cols
        num_cols = sel_ncol + t0_ncol + t1_ncol + inv_ncol + 2 * blk_sp + sel_sep
        self.set_digital_size(num_cols)

        # add instances
        t0_col = sel_ncol + sel_sep
        t1_col = t0_col + t0_ncol + blk_sp
        inv_col = num_cols - inv_ncol
        sel = self.add_digital_block(sel_master, (0, 0))
        t0 = self.add_digital_block(t0_master, (t0_col, 0))
        t1 = self.add_digital_block(t1_master, (t1_col, 0))
        inv = self.add_digital_block(inv_master, (inv_col, 0))

        self.fill_space()

        # connect/export VSS/VDD
        vss_list, vdd_list = [], []
        for inst in (sel, t0, t1, inv):
            vss_list.append(inst.get_pin('VSS'))
            vdd_list.append(inst.get_pin('VDD'))
        self.add_pin('VSS', self.connect_wires(vss_list), show=show_pins)
        self.add_pin('VDD', self.connect_wires(vdd_list), show=show_pins)

        # export input/output
        self.add_pin('in0', t0.get_pin('in'), show=show_pins)
        self.add_pin('in1', t1.get_pin('in'), show=show_pins)
        pout = inv.get_pin('pout')
        nout = inv.get_pin('nout')
        if out_vm_tidx is None:
            out_vm_tidx = self.laygo_info.col_to_track(ym_layer, num_cols - 1)

        out = self.connect_to_tracks([pout, nout],
                                     TrackID(ym_layer, out_vm_tidx))
        self.add_pin('out', out, show=show_pins)

        # connect middle node
        col_idx = inv_col - blk_sp // 2
        tr_idx = self.laygo_info.col_to_track(ym_layer, col_idx)
        hm_list = [
            t0.get_pin('pout'),
            t0.get_pin('nout'),
            t1.get_pin('pout'),
            t1.get_pin('nout'),
            inv.get_pin('in')
        ]
        self.connect_to_tracks(hm_list, TrackID(ym_layer, tr_idx))

        # connect enables
        sel0l = self.extend_wires(t0.get_pin('en'), min_len_mode=0)[0]
        sel0r = self.extend_wires(t1.get_pin('enb'), min_len_mode=0)[0]
        sel1l = self.connect_wires([sel.get_pin('in'), t0.get_pin('enb')])[0]
        sel1r = self.extend_wires(t1.get_pin('en'), min_len_mode=0)[0]
        self.add_pin('sel1_hm', sel1l, label='sel1', show=False)

        self.connect_to_track_wires(sel.get_pin('out'), sel0l)

        ym_tidx = self.grid.coord_to_nearest_track(ym_layer,
                                                   sel0l.middle_unit,
                                                   mode=1,
                                                   half_track=True,
                                                   unit_mode=True)
        ym_tid = TrackID(ym_layer, ym_tidx)
        sel0l = self.connect_to_tracks(sel0l, ym_tid, min_len_mode=-1)
        sel1l = self.connect_to_tracks(sel1l, ym_tid, min_len_mode=1)
        self.add_pin('sel1', sel1l, show=show_pins)
        sel0l = self.connect_to_tracks(sel0l,
                                       TrackID(hm_layer, nd0_tidx),
                                       min_len_mode=1)
        sel1l = self.connect_to_tracks(sel1l,
                                       TrackID(hm_layer, pd0_tidx),
                                       min_len_mode=1)

        sel0_tidx = self.grid.find_next_track(ym_layer,
                                              sel0r.middle_unit,
                                              mode=-1,
                                              half_track=True,
                                              unit_mode=True)
        sel1_tidx = sel0_tidx + 1
        self.connect_to_tracks([sel0l, sel0r], TrackID(ym_layer, sel0_tidx))
        self.connect_to_tracks([sel1l, sel1r], TrackID(ym_layer, sel1_tidx))

        # set properties
        pseg_t0 = t0_master.sch_params['segp']
        nseg_t0 = t0_master.sch_params['segn']
        psel = sel_master.sch_params['segp']
        nsel = sel_master.sch_params['segn']
        self._sch_params = dict(
            lch=config['lch'],
            wp=wp,
            wn=wn,
            thp=config['thp'],
            thn=config['thn'],
            seg_dict=dict(pinv=seg,
                          ninv=seg,
                          pt0=pseg_t0,
                          nt0=nseg_t0,
                          psel=psel,
                          nsel=nsel),
        )
        self._seg_in = seg_in
Exemplo n.º 7
0
    def draw_layout(self):
        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']
        fg_duml = self.params['fg_duml']
        fg_dumr = self.params['fg_dumr']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        top_layer = self.params['top_layer']
        end_mode = self.params['end_mode']
        guard_ring_nf = self.params['guard_ring_nf']
        options = self.params['options']
        show_pins = self.params['show_pins']
        tech_cls_name = self.params['tech_cls_name']

        if options is None:
            options = {}
        if tech_cls_name is not None:
            self.set_tech_class(tech_cls_name)

        seg_gm = seg_dict['gm']
        seg_tail = seg_dict['tail']
        stack_gm = stack_dict['gm']
        stack_tail = stack_dict['tail']

        if seg_gm % 2 != 0 or seg_tail % 2 != 0:
            raise ValueError('seg_gm and seg_tail must be even')

        fg_gm = seg_gm * stack_gm
        fg_tail = seg_tail * stack_tail

        # get fg_sep, make sure it is even
        info = AnalogBaseInfo(self.grid,
                              lch,
                              guard_ring_nf,
                              top_layer=top_layer,
                              end_mode=end_mode)
        fg_sep = info.min_fg_sep
        fg_sep = -(-fg_sep // 2) * 2

        # get number of fingers
        fg_single = max(fg_gm, fg_tail)
        fg_tot = fg_duml + fg_dumr + 2 * fg_single + fg_sep

        # get row information
        nw_list = [w_dict['tail'], w_dict['gm']]
        nth_list = [th_dict['tail'], th_dict['gm']]
        n_orientations = ['R0', 'R0']
        pw_list = pth_list = p_orientations = []

        # get track manager and wire names
        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)
        wire_names = dict(
            nch=[
                dict(g=['bias'], ds2=['tail']),
                dict(g2=['out', 'out'], ds2=['out', 'out']),
            ],
            pch=[],
        )
        # 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,
                       options=options)

        # draw transistors
        col_taill = fg_duml + fg_single - fg_tail
        col_gml = fg_duml + fg_single - fg_gm
        col_gmr = col_tailr = fg_duml + fg_single + fg_sep
        taill = self.draw_mos_conn('nch',
                                   0,
                                   col_taill,
                                   fg_tail,
                                   2,
                                   0,
                                   s_net='tail',
                                   d_net='',
                                   stack=stack_tail)
        tailr = self.draw_mos_conn('nch',
                                   0,
                                   col_tailr,
                                   fg_tail,
                                   2,
                                   0,
                                   s_net='tail',
                                   d_net='',
                                   stack=stack_tail)
        gml = self.draw_mos_conn('nch',
                                 1,
                                 col_gml,
                                 fg_gm,
                                 0,
                                 2,
                                 s_net='tail',
                                 d_net='outp',
                                 stack=stack_gm)
        gmr = self.draw_mos_conn('nch',
                                 1,
                                 col_gmr,
                                 fg_gm,
                                 0,
                                 2,
                                 s_net='tail',
                                 d_net='outn',
                                 stack=stack_gm)

        # draw connections
        # VSS
        self.connect_to_substrate('ptap', [taill['d'], tailr['d']])
        # tail
        tail_tid = self.get_wire_id('nch', 0, 'ds2', wire_name='tail')
        self.connect_to_tracks([taill['s'], tailr['s'], gml['s'], gmr['s']],
                               tail_tid)
        # bias
        bias_tid = self.get_wire_id('nch', 0, 'g', wire_name='bias')
        bias = self.connect_to_tracks([taill['g'], tailr['g']], bias_tid)
        # input differential pair
        outn_tid = self.get_wire_id('nch',
                                    1,
                                    'g2',
                                    wire_name='out',
                                    wire_idx=0)
        outp_tid = self.get_wire_id('nch',
                                    1,
                                    'g2',
                                    wire_name='out',
                                    wire_idx=1)
        outp_g, outn_g = self.connect_differential_tracks(gmr['g'],
                                                          gml['g'],
                                                          outn_tid.layer_id,
                                                          outp_tid.base_index,
                                                          outn_tid.base_index,
                                                          width=outp_tid.width)
        # output differential pair
        outn_tid = self.get_wire_id('nch',
                                    1,
                                    'ds2',
                                    wire_name='out',
                                    wire_idx=0)
        outp_tid = self.get_wire_id('nch',
                                    1,
                                    'ds2',
                                    wire_name='out',
                                    wire_idx=1)
        outp_d, outn_d = self.connect_differential_tracks(gml['d'],
                                                          gmr['d'],
                                                          outn_tid.layer_id,
                                                          outp_tid.base_index,
                                                          outn_tid.base_index,
                                                          width=outp_tid.width)

        # fill dummies
        vss, vdd = self.fill_dummy()

        # add pins
        self.add_pin('VSS', vss, show=show_pins)
        self.add_pin('bias', bias, show=show_pins)
        self.add_pin('outp', outp_g, label='outp:', show=show_pins)
        self.add_pin('outn', outn_g, label='outn:', show=show_pins)
        self.add_pin('outp', outp_d, label='outp:', show=show_pins)
        self.add_pin('outn', outn_d, label='outn:', 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(),
        )
Exemplo n.º 8
0
    def draw_layout(self):
        config = self.params['config']
        seg_list = self.params['seg_list']
        stack_list = self.params['stack_list']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        wp_list = self.params['wp_list']
        wn_list = self.params['wn_list']
        sig_locs = self.params['sig_locs']
        row_layout_info = self.params['row_layout_info']
        show_pins = self.params['show_pins']

        ninv = len(seg_list)
        wp_row = config['wp']
        wn_row = config['wn']
        if wp_list is None:
            wp_list = [wp_row] * ninv
        elif len(wp_list) != ninv:
            raise ValueError('length of wp_list != %d' % ninv)
        if wn_list is None:
            wn_list = [wn_row] * ninv
        elif len(wn_list) != ninv:
            raise ValueError('length of wn_list != %d' % ninv)
        if stack_list is None:
            stack_list = [False] * ninv
        elif len(stack_list) != ninv:
            raise ValueError('length of stack_list != %d' % ninv)

        # TODO: remove restriction
        if ninv != 2:
            raise ValueError('Now only 2 inverters are supported.')

        seg_in, seg_out = seg_list
        stack_in, stack_out = stack_list
        seg_tot = self.compute_num_cols(seg_list, stack_list=stack_list)
        vss_tid, vdd_tid = self.setup_floorplan(config, row_layout_info,
                                                seg_tot)

        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)

        if sig_locs is None:
            sig_locs = {}

        # get track information
        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        hm_w_g = tr_manager.get_width(hm_layer, 'in')
        hm_w_d = tr_manager.get_width(hm_layer, 'out')
        vm_w_d = tr_manager.get_width(vm_layer, 'out')
        g_locs = tr_manager.place_wires(hm_layer, ['in', 'in'])[1]
        d_locs = tr_manager.place_wires(hm_layer, ['out', 'out'])[1]
        ng0_tid = self.make_track_id(0, 'g', g_locs[0], width=hm_w_g)
        pg0_tid = self.make_track_id(1, 'g', g_locs[0], width=hm_w_g)
        nd0_tid = self.make_track_id(0, 'gb', d_locs[0], width=hm_w_d)
        nd1_tid = self.make_track_id(0, 'gb', d_locs[1], width=hm_w_d)
        pd0_tid = self.make_track_id(1, 'gb', d_locs[0], width=hm_w_d)
        pd1_tid = self.make_track_id(1, 'gb', d_locs[1], width=hm_w_d)

        if 'mid' in sig_locs:
            mid_tid = TrackID(hm_layer, sig_locs['mid'])
        else:
            mid_tid = None
        if 'in' in sig_locs:
            in_tid = TrackID(hm_layer, sig_locs['in'], width=hm_w_g)
            if mid_tid is None:
                if in_tid.base_index == pg0_tid.base_index:
                    mid_tid = ng0_tid
                else:
                    mid_tid = pg0_tid
        else:
            in_tid = ng0_tid
            if mid_tid is None:
                mid_tid = pg0_tid

        # add blocks and collect wires
        pinv0 = self.add_laygo_mos(1, 0, seg_in, w=wp_list[0], stack=stack_in)
        ninv0 = self.add_laygo_mos(0, 0, seg_in, w=wn_list[0], stack=stack_in)
        fg_in = seg_in * 2 if stack_in else seg_in
        col = fg_in if seg_in % 2 == 0 else fg_in + self.blk_sp
        pinv1 = self.add_laygo_mos(1,
                                   col,
                                   seg_out,
                                   w=wp_list[1],
                                   stack=stack_out)
        ninv1 = self.add_laygo_mos(0,
                                   col,
                                   seg_out,
                                   w=wn_list[1],
                                   stack=stack_out)

        # compute overall block size and fill spaces
        self.fill_space()

        # connect input
        in_warr = self.connect_to_tracks([pinv0['g'], ninv0['g']],
                                         in_tid,
                                         min_len_mode=0)
        self.add_pin('in', in_warr, show=show_pins)

        # connect output
        pout_warr = self.connect_to_tracks(pinv1['d'], pd0_tid, min_len_mode=0)
        nout_warr = self.connect_to_tracks(ninv1['d'], nd0_tid, min_len_mode=0)
        if 'out' in sig_locs:
            out_tidx = sig_locs['out']
        else:
            out_tidx = self.grid.coord_to_nearest_track(vm_layer,
                                                        pout_warr.middle,
                                                        half_track=True)
        tid = TrackID(vm_layer, out_tidx, width=vm_w_d)
        out_warr = self.connect_to_tracks([pout_warr, nout_warr], tid)
        self.add_pin('out', out_warr, show=show_pins)

        # connect middle
        pout_warr = self.connect_to_tracks(pinv0['d'], pd1_tid, min_len_mode=0)
        nout_warr = self.connect_to_tracks(ninv0['d'], nd1_tid, min_len_mode=0)
        mid_warr = self.connect_to_tracks([pinv1['g'], ninv1['g']],
                                          mid_tid,
                                          min_len_mode=-1)
        mid_tidx = self.grid.coord_to_nearest_track(vm_layer,
                                                    pout_warr.middle,
                                                    half_track=True)
        tid = TrackID(vm_layer, mid_tidx, width=vm_w_d)
        self.connect_to_tracks([pout_warr, nout_warr, mid_warr], tid)

        # connect supplies
        vdd = [pinv0['s'], pinv1['s']]
        vss = [ninv0['s'], ninv1['s']]
        vss_warr = self.connect_to_tracks(vss, vss_tid)
        vdd_warr = self.connect_to_tracks(vdd, vdd_tid)
        self.add_pin('VSS', vss_warr, show=show_pins)
        self.add_pin('VDD', vdd_warr, show=show_pins)

        # set properties
        self._sch_params = dict(
            lch=config['lch'],
            thp=config['thp'],
            thn=config['thn'],
            segp_list=seg_list,
            segn_list=seg_list,
            wp_list=wp_list,
            wn_list=wn_list,
            stack_list=stack_list,
        )
        self._mid_tidx = mid_tidx
Exemplo n.º 9
0
    def draw_layout(self):
        config = self.params['config']
        seg = self.params['seg']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        wp = self.params['wp']
        wn = self.params['wn']
        stack = self.params['stack']
        row_layout_info = self.params['row_layout_info']
        sig_locs = self.params['sig_locs']
        out_vm = self.params['out_vm']
        show_pins = self.params['show_pins']

        wp_row = config['wp']
        wn_row = config['wn']
        if wp is None:
            wp = wp_row
        if wn is None:
            wn = wn_row
        if wp < 0 or wp > wp_row or wn < 0 or wn > wn_row:
            raise ValueError('Invalid choice of wp and/or wn.')

        if sig_locs is None:
            sig_locs = {}
        in_tidx = sig_locs.get('in', None)
        pout_tidx = sig_locs.get('pout', None)
        nout_tidx = sig_locs.get('nout', None)
        out_tidx = sig_locs.get('out', None)

        fg = seg * 2 if stack else seg
        vss_tid, vdd_tid = self.setup_floorplan(config, row_layout_info, fg)

        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)

        # get track information
        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        tr_w_in = tr_manager.get_width(hm_layer, 'in')
        tr_w_out_h = tr_manager.get_width(hm_layer, 'out')
        tr_w_out_v = tr_manager.get_width(vm_layer, 'out')

        # add blocks and collect wires
        pinv = self.add_laygo_mos(1, 0, seg, w=wp, gate_loc='d', stack=stack)
        ninv = self.add_laygo_mos(0, 0, seg, w=wn, gate_loc='d', stack=stack)
        vdd = pinv['s']
        vss = ninv['s']
        pout = pinv['d']
        nout = ninv['d']
        pin = pinv['g']
        nin = ninv['g']

        # compute overall block size and fill spaces
        self.fill_space()

        # connect input
        if in_tidx is None:
            loc = tr_manager.place_wires(hm_layer, ['in'])[1][0]
            in_tidx = self.get_track_index(0, 'g', loc)
        tid = TrackID(hm_layer, in_tidx, width=tr_w_in)
        in_warr = self.connect_to_tracks([pin, nin], tid)

        # connect output
        out_loc = tr_manager.place_wires(hm_layer, ['out'])[1][0]
        if pout_tidx is None:
            pout_tidx = self.get_track_index(1, 'gb', out_loc)
        tid = TrackID(hm_layer, pout_tidx, width=tr_w_out_h)
        pout_warr = self.connect_to_tracks(pout, tid, min_len_mode=0)
        if nout_tidx is None:
            nout_tidx = self.get_track_index(0, 'gb', out_loc)
        tid = TrackID(hm_layer, nout_tidx, width=tr_w_out_h)
        nout_warr = self.connect_to_tracks(nout, tid, min_len_mode=0)
        if out_vm:
            if out_tidx is None:
                out_tidx = self.grid.coord_to_nearest_track(vm_layer,
                                                            pout_warr.middle,
                                                            half_track=True)
            tid = TrackID(vm_layer, out_tidx, width=tr_w_out_v)
            out_warr = self.connect_to_tracks([pout_warr, nout_warr], tid)
            self.add_pin('out', out_warr, show=show_pins)

        # connect supplies
        vss_warr = self.connect_to_tracks(vss, vss_tid)
        vdd_warr = self.connect_to_tracks(vdd, vdd_tid)

        # export
        self.add_pin('VSS', vss_warr, show=show_pins)
        self.add_pin('VDD', vdd_warr, show=show_pins)
        self.add_pin('in', in_warr, show=show_pins)
        self.add_pin('pout', pout_warr, label='out', show=False)
        self.add_pin('nout', nout_warr, label='out', show=False)

        # set properties
        self._sch_params = dict(
            lch=config['lch'],
            wp=wp,
            wn=wn,
            thp=config['thp'],
            thn=config['thn'],
            segp=seg,
            segn=seg,
            stack=stack,
        )
Exemplo n.º 10
0
    def draw_layout(self):
        blk_sp = 2
        in_fanout = 4
        fb_fanout = 8

        config = self.params['config']

        seg = self.params['seg']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        wp = self.params['wp']
        wn = self.params['wn']
        row_layout_info = self.params['row_layout_info']
        sig_locs = self.params['sig_locs']
        pass_zero = self.params['pass_zero']
        show_pins = self.params['show_pins']

        wp_row = config['wp']
        wn_row = config['wn']
        if wp is None:
            wp = wp_row
        if wn is None:
            wn = wn_row
        if wp < 0 or wp > wp_row or wn < 0 or wn > wn_row:
            raise ValueError('Invalid choice of wp and/or wn.')
        if sig_locs is None:
            sig_locs = {}

        # setup floorplan
        params = self.params.copy()
        params['wp'] = wp
        params['wn'] = wn
        params['show_pins'] = False
        params['sig_locs'] = None
        params['out_vm'] = True
        if row_layout_info is not None:
            self.initialize(row_layout_info, 1)
        else:
            inv_master = self.new_template(params=params, temp_cls=Inverter)
            params[
                'row_layout_info'] = row_layout_info = inv_master.row_layout_info
            self.initialize(row_layout_info, 1)

        # compute track locations
        hm_layer = self.conn_layer + 1
        ym_layer = hm_layer + 1
        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)
        ym_w_in = tr_manager.get_width(ym_layer, 'in')
        g_locs = tr_manager.place_wires(hm_layer, ['in', 'in'])[1]
        d_locs = tr_manager.place_wires(hm_layer, ['out', 'out'])[1]
        ng0_tidx = self.get_track_index(0, 'g', g_locs[0])
        ng1_tidx = self.get_track_index(0, 'g', g_locs[1])
        pg0_tidx = self.get_track_index(1, 'g', g_locs[0])
        pg1_tidx = self.get_track_index(1, 'g', g_locs[1])
        nd0_tidx = self.get_track_index(0, 'gb', d_locs[0])
        nd1_tidx = self.get_track_index(0, 'gb', d_locs[1])
        pd0_tidx = self.get_track_index(1, 'gb', d_locs[0])
        pd1_tidx = self.get_track_index(1, 'gb', d_locs[1])

        t0_in_tidx = sig_locs.get('in', pg1_tidx)
        t0_enb_tidx = sig_locs.get('pclkb', pg0_tidx)
        t0_en_tidx = sig_locs.get('nclk', ng0_tidx)
        t1_en_tidx = sig_locs.get('nclkb', ng1_tidx)
        clk_tidx = sig_locs.get('clk', None)
        clkb_tidx = sig_locs.get('clkb', None)

        # make masters
        seg_t1 = max(1, int(round(seg / (2 * fb_fanout))) * 2)
        seg_t0 = max(2 * seg_t1, max(2, int(round(seg / (2 * in_fanout))) * 2))
        params['sig_locs'] = {
            'in': t0_en_tidx,
            'pout': pd1_tidx,
            'nout': nd1_tidx
        }
        inv_master = self.new_template(params=params, temp_cls=Inverter)
        params['seg'] = seg_t0
        params['out_vm'] = False
        params['sig_locs'] = {
            'in': t0_in_tidx,
            'pout': pd0_tidx,
            'nout': nd0_tidx,
            'en': t0_en_tidx,
            'enb': t0_enb_tidx
        }
        params['pmos_switch'] = not pass_zero
        t0_master = self.new_template(params=params, temp_cls=InverterTristate)
        params['seg'] = seg_t1
        params['sig_locs'] = {
            'in': t0_enb_tidx,
            'pout': pd0_tidx,
            'nout': nd0_tidx,
            'en': t1_en_tidx,
            'enb': t0_in_tidx
        }
        params['pmos_switch'] = True
        t1_master = self.new_template(params=params, temp_cls=InverterTristate)

        # set size
        t0_ncol = t0_master.num_cols
        t1_ncol = t1_master.num_cols
        inv_ncol = inv_master.num_cols
        num_cols = t0_ncol + t1_ncol + inv_ncol + blk_sp * 2
        self.set_digital_size(num_cols)

        # add instances
        t1_col = t0_ncol + blk_sp
        inv_col = num_cols - inv_ncol
        t0 = self.add_digital_block(t0_master, (0, 0))
        t1 = self.add_digital_block(t1_master, (t1_col, 0))
        inv = self.add_digital_block(inv_master, (inv_col, 0))

        self.fill_space()

        # connect/export VSS/VDD
        vss_list, vdd_list = [], []
        for inst in (t0, t1, inv):
            vss_list.append(inst.get_pin('VSS'))
            vdd_list.append(inst.get_pin('VDD'))
        self.add_pin('VSS', self.connect_wires(vss_list), show=show_pins)
        self.add_pin('VDD', self.connect_wires(vdd_list), show=show_pins)

        # export input
        self.add_pin('in', t0.get_pin('in'), show=show_pins)

        # connect output
        out = inv.get_pin('out')
        in2 = t1.get_pin('in')
        self.connect_to_track_wires(in2, out)
        self.add_pin('out', out, show=show_pins)
        self.add_pin('out_hm', in2, label='out', show=show_pins)

        # connect middle node
        lay_info = self.laygo_info
        col = inv_col - blk_sp // 2
        ym_tid = TrackID(ym_layer,
                         lay_info.col_to_track(ym_layer, col),
                         width=ym_w_in)
        warrs = [
            t0.get_pin('pout'),
            t0.get_pin('nout'),
            t1.get_pin('pout'),
            t1.get_pin('nout'),
            inv.get_pin('in')
        ]
        self.connect_to_tracks(warrs, ym_tid)

        # connect clocks
        clk_col = t1_col + 1
        clkb_col = t1_col - blk_sp - 1
        if clk_tidx is None:
            clk_tidx = lay_info.col_to_track(ym_layer, clk_col)
        clk_tid = TrackID(ym_layer, clk_tidx, width=ym_w_in)
        if clkb_tidx is None:
            clkb_tidx = lay_info.col_to_track(ym_layer, clkb_col)
        clkb_tid = TrackID(ym_layer, clkb_tidx, width=ym_w_in)
        t0_en = t0.get_pin('en')
        t1_en = t1.get_pin('en')
        t1_enb = t1.get_pin('enb')
        t1_enb = self.extend_wires(t1_enb, min_len_mode=-1)[0]
        clk = self.connect_to_tracks([t0_en, t1_enb], clk_tid)
        if not pass_zero:
            t0_enb = t0.get_pin('enb')
            t0_enb = self.extend_wires(t0_enb, min_len_mode=1)[0]
            clkb = self.connect_to_tracks([t0_enb, t1_en], clkb_tid)
            self.add_pin('pclkb', t0_enb, label='clkb', show=False)
        else:
            clkb = self.connect_to_tracks(t1_en, clkb_tid, min_len_mode=0)
        self.add_pin('clk', clk, show=show_pins)
        self.add_pin('clkb', clkb, show=show_pins)
        self.add_pin('nclk', t0_en, label='clk', show=False)
        self.add_pin('pclk', t1_enb, label='clk', show=False)
        self.add_pin('nclkb', t1_en, label='clkb', show=False)

        # set properties
        pseg_t0 = t0_master.sch_params['segp']
        self._sch_params = dict(
            lch=config['lch'],
            wp=wp,
            wn=wn,
            thp=config['thp'],
            thn=config['thn'],
            seg_dict=dict(pinv=seg,
                          ninv=seg,
                          pt0=pseg_t0,
                          nt0=seg_t0,
                          pt1=seg_t1,
                          nt1=seg_t1),
            pass_zero=pass_zero,
        )
        self._seg_in = seg_t0
Exemplo n.º 11
0
    def draw_layout(self):
        config = self.params['config']
        seg = self.params['seg']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        wp = self.params['wp']
        wn = self.params['wn']
        row_layout_info = self.params['row_layout_info']
        sig_locs = self.params['sig_locs']
        out_vm = self.params['out_vm']
        pmos_switch = self.params['pmos_switch']
        show_pins = self.params['show_pins']

        wp_row = config['wp']
        wn_row = config['wn']
        if wp is None:
            wp = wp_row
        if wn is None:
            wn = wn_row
        if wp < 0 or wp > wp_row or wn < 0 or wn > wn_row:
            raise ValueError('Invalid choice of wp and/or wn.')

        vss_tid, vdd_tid = self.setup_floorplan(config, row_layout_info,
                                                seg * 2)

        if sig_locs is None:
            sig_locs = {}
        in_tidx = sig_locs.get('in', None)
        pout_tidx = sig_locs.get('pout', None)
        nout_tidx = sig_locs.get('nout', None)
        out_tidx = sig_locs.get('out', None)
        enb_tidx = sig_locs.get('enb', None)
        en_tidx = sig_locs.get('en', None)

        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)

        # get track information
        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        tr_w_in = tr_manager.get_width(hm_layer, 'in')
        tr_w_en = tr_manager.get_width(hm_layer, 'en')
        tr_w_out_h = tr_manager.get_width(hm_layer, 'out')
        tr_w_out_v = tr_manager.get_width(vm_layer, 'out')

        # add blocks and collect wires
        pseg = seg if pmos_switch else 2 * seg
        pinv = self.add_laygo_mos(1,
                                  0,
                                  pseg,
                                  gate_loc='s',
                                  stack=pmos_switch,
                                  w=wp)
        ninv = self.add_laygo_mos(0, 0, seg, gate_loc='s', stack=True, w=wn)
        vdd = pinv['s']
        vss = ninv['s']
        pout = pinv['d']
        nout = ninv['d']
        enb = pinv['g1']
        en = ninv['g1']
        pin = pinv['g0']
        nin = ninv['g0']

        # compute overall block size and fill spaces
        self.fill_space()

        # get track locations
        if en_tidx is None:
            ntr = self.get_num_tracks(0, 'g')
            loc = tr_manager.align_wires(hm_layer, ['en'], ntr, alignment=1)[0]
            en_tidx = self.get_track_index(0, 'g', loc)
        if enb_tidx is None:
            ntr = self.get_num_tracks(1, 'g')
            loc = tr_manager.align_wires(hm_layer, ['en'], ntr, alignment=1)[0]
            enb_tidx = self.get_track_index(1, 'g', loc)
        if in_tidx is None:
            in_tidx2 = int(round(2 * (en_tidx + enb_tidx)))
            if in_tidx2 % 4 == 0:
                in_tidx = in_tidx2 // 4
            elif in_tidx2 % 2 == 0:
                in_tidx = in_tidx2 / 4
            else:
                in_tidx = (in_tidx2 + 1) / 4
        out_loc = tr_manager.place_wires(hm_layer, ['out'])[1][0]
        if pout_tidx is None:
            pout_tidx = self.get_track_index(1, 'gb', out_loc)
        if nout_tidx is None:
            nout_tidx = self.get_track_index(0, 'gb', out_loc)

        # connect wires
        in_warr_list = [pin, nin]
        if pmos_switch:
            tid = TrackID(hm_layer, enb_tidx, width=tr_w_en)
            enb_warr = self.connect_to_tracks(enb, tid)
            self.add_pin('enb', enb_warr, show=show_pins)
        else:
            in_warr_list.append(enb)

        tid = TrackID(hm_layer, in_tidx, width=tr_w_in)
        in_warr = self.connect_to_tracks(in_warr_list, tid)
        tid = TrackID(hm_layer, en_tidx, width=tr_w_en)
        en_warr = self.connect_to_tracks(en, tid)
        tid = TrackID(hm_layer, pout_tidx, width=tr_w_out_h)
        pout_warr = self.connect_to_tracks(pout, tid, min_len_mode=0)
        tid = TrackID(hm_layer, nout_tidx, width=tr_w_out_h)
        nout_warr = self.connect_to_tracks(nout, tid, min_len_mode=0)

        # connect output
        if out_vm:
            if out_tidx is None:
                out_tidx = self.grid.coord_to_nearest_track(vm_layer,
                                                            pout_warr.middle,
                                                            half_track=True)
            tid = TrackID(vm_layer, out_tidx, width=tr_w_out_v)
            out_warr = self.connect_to_tracks([pout_warr, nout_warr], tid)
            self.add_pin('out', out_warr, show=show_pins)

        # connect supplies
        vss_warr = self.connect_to_tracks(vss, vss_tid)
        vdd_warr = self.connect_to_tracks(vdd, vdd_tid)

        # export
        self.add_pin('VSS', vss_warr, show=show_pins)
        self.add_pin('VDD', vdd_warr, show=show_pins)
        self.add_pin('in', in_warr, show=show_pins)
        self.add_pin('en', en_warr, show=show_pins)
        self.add_pin('pout', pout_warr, label='out', show=False)
        self.add_pin('nout', nout_warr, label='out', show=False)

        # set properties
        self._sch_params = dict(
            lch=config['lch'],
            wp=wp,
            wn=wn,
            thp=config['thp'],
            thn=config['thn'],
            segp=pseg,
            segn=seg,
            pmos_switch=pmos_switch,
        )
Exemplo n.º 12
0
    def draw_layout(self):
        blk_sp = 2
        fanout = 4

        config = self.params['config']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        wp = self.params['wp']
        wn = self.params['wn']
        row_layout_info = self.params['row_layout_info']
        sig_locs = self.params['sig_locs']
        pass_zero = self.params['pass_zero']
        show_pins = self.params['show_pins']

        wp_row = config['wp']
        wn_row = config['wn']
        if wp is None:
            wp = wp_row
        if wn is None:
            wn = wn_row
        if wp < 0 or wp > wp_row or wn < 0 or wn > wn_row:
            raise ValueError('Invalid choice of wp and/or wn.')
        if sig_locs is None:
            sig_locs = {}

        # setup floorplan
        params = self.params.copy()
        params['wp'] = wp
        params['wn'] = wn
        params['show_pins'] = False
        params['sig_locs'] = None
        if row_layout_info is not None:
            self.initialize(row_layout_info, 1)
        else:
            m_master = self.new_template(params=params, temp_cls=LatchCK2)
            params[
                'row_layout_info'] = row_layout_info = m_master.row_layout_info
            self.initialize(row_layout_info, 1)

        # compute track locations
        hm_layer = self.conn_layer + 1
        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)
        g_locs = tr_manager.place_wires(hm_layer, ['in', 'in'])[1]
        ng0_tidx = self.get_track_index(0, 'g', g_locs[0])
        ng1_tidx = self.get_track_index(0, 'g', g_locs[1])
        pg0_tidx = self.get_track_index(1, 'g', g_locs[0])
        pg1_tidx = self.get_track_index(1, 'g', g_locs[1])

        in_tidx = sig_locs.get('in', pg0_tidx)
        pclkb_tidx = sig_locs.get('pclkb', pg1_tidx)

        # make masters
        params['sig_locs'] = {'nclk': ng1_tidx, 'nclkb': ng0_tidx}
        s_master = self.new_template(params=params, temp_cls=LatchCK2)
        seg_m = max(2, int(round(s_master.seg_in / (2 * fanout))) * 2)
        params['seg'] = seg_m
        params['sig_locs'] = {
            'in': in_tidx,
            'pclkb': pclkb_tidx,
            'clkb': sig_locs.get('clk', None),
            'clk': sig_locs.get('clkb', None)
        }
        m_master = self.new_template(params=params, temp_cls=LatchCK2)

        # set size
        m_ncol = m_master.num_cols
        s_ncol = s_master.num_cols
        num_cols = m_ncol + s_ncol + blk_sp
        self.set_digital_size(num_cols)

        # add instances
        s_col = m_ncol + blk_sp
        m_inst = self.add_digital_block(m_master, (0, 0))
        s_inst = self.add_digital_block(s_master, (s_col, 0))

        self.fill_space()

        # connect/export VSS/VDD
        vss_list, vdd_list = [], []
        for inst in (m_inst, s_inst):
            vss_list.append(inst.get_pin('VSS'))
            vdd_list.append(inst.get_pin('VDD'))
        self.add_pin('VSS', self.connect_wires(vss_list), show=show_pins)
        self.add_pin('VDD', self.connect_wires(vdd_list), show=show_pins)

        # connect intermediate node
        self.connect_wires([s_inst.get_pin('in'), m_inst.get_pin('out_hm')])
        # connect clocks
        self.connect_wires([s_inst.get_pin('nclk'), m_inst.get_pin('nclkb')])
        if pass_zero:
            self.connect_to_track_wires(s_inst.get_pin('clkb'),
                                        m_inst.get_pin('pclk'))
        else:
            self.connect_wires(
                [s_inst.get_pin('pclkb'),
                 m_inst.get_pin('pclk')])
        # add pins
        self.add_pin('in', m_inst.get_pin('in'), show=show_pins)
        self.add_pin('out', s_inst.get_pin('out'), show=show_pins)
        self.add_pin('out_hm', s_inst.get_pin('out_hm'), show=show_pins)
        self.add_pin('clk', m_inst.get_pin('clkb'), show=show_pins)
        self.add_pin('clkb', m_inst.get_pin('clk'), show=show_pins)
        self.add_pin('clkb_hm',
                     m_inst.get_pin('nclk'),
                     label='clkb',
                     show=show_pins)
        self.add_pin('clk_hm',
                     m_inst.get_pin('nclkb'),
                     label='clk',
                     show=show_pins)

        # set properties
        self._sch_params = dict(
            lch=config['lch'],
            wp=wp,
            wn=wn,
            thp=config['thp'],
            thn=config['thn'],
            seg_m=m_master.sch_params['seg_dict'],
            seg_s=s_master.sch_params['seg_dict'],
            pass_zero=pass_zero,
        )
        self._seg_in = m_master.seg_in
Exemplo n.º 13
0
    def draw_diffamp(
            self,  # type: SerdesRXBase
            col_idx,  # type: int
            seg_dict,  # type: Dict[str, int]
            tr_widths=None,  # type: Optional[Dict[str, Dict[int, int]]]
            tr_spaces=None,  # type: Optional[Dict[Union[str, Tuple[str, str]], Dict[int, int]]]
            tr_indices=None,  # type: Optional[Dict[str, int]]
            fg_min=0,  # type: int
            fg_dum=0,  # type: int
            flip_out_sd=False,  # type: bool
            net_prefix='',  # type: str
    ):
        # type: (...) -> Tuple[Dict[str, WireArray], Dict[str, Any]]
        """Draw a differential amplifier.

        Parameters
        ----------
        col_idx : int
            the left-most transistor index.  0 is the left-most transistor.
        seg_dict : Dict[str, int]
            a dictionary containing number of segments per transistor type.
        tr_widths : Optional[Dict[str, Dict[int, int]]]
            the track width dictionary.
        tr_spaces : Optional[Dict[Union[str, Tuple[str, str]], Dict[int, int]]]
            the track spacing dictionary.
        tr_indices : Optional[Dict[str, int]]
            the track index dictionary.  Maps from net name to relative track index.
        fg_min : int
            minimum number of total fingers.
        fg_dum : int
            minimum single-sided number of dummy fingers.
        flip_out_sd : bool
            True to draw output on source instead of drain.
        net_prefix : str
            this prefit will be added to net names in draw_mos_conn() method and the
            returned port dictionary.

        Returns
        -------
        port_dict : Dict[str, WireArray]
            a dictionary from connection name to WireArrays on horizontal routing layer.
        amp_info : Dict[str, Any]
            the amplifier layout information dictionary
        """
        if tr_widths is None:
            tr_widths = {}
        if tr_spaces is None:
            tr_spaces = {}
        if tr_indices is None:
            tr_indices = {}

        # get layout information
        amp_info = self._serdes_info.get_diffamp_info(seg_dict,
                                                      fg_min=fg_min,
                                                      fg_dum=fg_dum,
                                                      flip_out_sd=flip_out_sd)
        fg_tot = amp_info['fg_tot']
        fg_single = amp_info['fg_single']
        fg_sep = amp_info['fg_sep']
        fg_dum = amp_info['fg_dum']
        tran_info = amp_info['tran_info']

        # draw main transistors and collect ports
        warr_dict = self._draw_diffamp_mos(col_idx, seg_dict, tran_info,
                                           fg_single, fg_dum, fg_sep,
                                           net_prefix)

        # draw load/tail reference transistor
        for tran_name, mos_type, sup_name in (('tail', 'nch', 'VSS'),
                                              ('load', 'pch', 'VDD')):
            fg_name = '%s_ref' % tran_name
            fg_ref = seg_dict.get(fg_name, 0)
            if fg_ref > 0:
                mos_type, row_idx = self.get_row_index(tran_name)
                # error checking
                if (fg_tot - fg_ref) % 2 != 0:
                    raise ValueError(
                        'fg_tot = %d and fg_%s = %d has opposite parity.' %
                        (fg_tot, fg_name, fg_ref))
                # get reference column index
                col_ref = col_idx + (fg_tot - fg_ref) // 2

                # get drain/source name/direction
                cur_info = tran_info[tran_name]
                dname, sname, ddir, sdir = cur_info[1:]
                gname = 'bias_%s' % tran_name
                if dname == sup_name:
                    sname = gname
                else:
                    dname = gname

                # draw transistor
                warrs = self.draw_mos_conn(mos_type,
                                           row_idx,
                                           col_ref,
                                           fg_ref,
                                           sdir,
                                           ddir,
                                           s_net=net_prefix + sname,
                                           d_net=net_prefix + dname)
                self._append_to_warr_dict(warr_dict, gname, warrs['g'])
                self._append_to_warr_dict(warr_dict, dname, warrs['d'])
                self._append_to_warr_dict(warr_dict, sname, warrs['s'])

        # draw load/tail decap transistor
        for tran_name, mos_type, sup_name in (('tail', 'nch', 'VSS'),
                                              ('load', 'pch', 'VDD')):
            fg_name = '%s_cap' % tran_name
            fg_cap = seg_dict.get(fg_name, 0)
            if fg_cap > 0:
                mos_type, row_idx = self.get_row_index(tran_name)
                # compute decap column index
                fg_row_tot = amp_info['fg_%s_tot' % tran_name]
                col_l = col_idx + fg_dum + fg_single - fg_row_tot
                col_r = col_idx + fg_dum + fg_single + fg_sep + fg_row_tot - fg_cap

                fg_cap_single = fg_cap // 2
                p_warrs = self.draw_mos_decap(mos_type,
                                              row_idx,
                                              col_l,
                                              fg_cap_single,
                                              False,
                                              export_gate=True)
                n_warrs = self.draw_mos_decap(mos_type,
                                              row_idx,
                                              col_r,
                                              fg_cap_single,
                                              False,
                                              export_gate=True)
                gname = 'bias_%s' % tran_name
                self._append_to_warr_dict(warr_dict, gname, p_warrs['g'])
                self._append_to_warr_dict(warr_dict, gname, n_warrs['g'])

        # connect to horizontal wires
        # nets relative index parameters
        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
        nets = [
            'outp', 'outn', 'bias_load', 'midp', 'midn', 'bias_casc', 'tail',
            'inp', 'inn', 'vddn', 'clk_sw', 'foot', 'enable', 'bias_tail'
        ]
        rows = [
            'load', 'load', 'load', 'casc', 'casc', 'casc', 'tail', 'in', 'in',
            'sw', 'sw', 'tail', 'en', 'tail'
        ]
        trns = [
            'ds', 'ds', 'g', 'ds', 'ds', 'g', 'ds', 'g', 'g', 'ds', 'g', 'ds',
            'g', 'g'
        ]

        tr_type_dict = dict(
            outp='out',
            outn='out',
            bias_load='bias',
            midp='mid',
            midn='mid',
            bias_casc='bias',
            tail='tail',
            inp='in',
            inn='in',
            vddn='vdd',
            clk_sw='bias',
            foot='tail',
            enable='bias',
            bias_tail='bias',
        )

        # tail net should be connected on enable row if it exists
        if 'enable' in warr_dict:
            rows[6] = 'en'

        # compute default inp/inn/outp/outn indices.
        hm_layer = self.mos_conn_layer + 1
        for tran_name, net_type, net_base, order in (('in', 'g', 'in', -1),
                                                     ('load', 'ds', 'out', 1)):
            pname, nname = '%sp' % net_base, '%sn' % net_base
            if pname not in tr_indices or nname not in tr_indices:
                tr_indices = tr_indices.copy()
                ntr_used, (netp_idx, netn_idx) = tr_manager.place_wires(
                    hm_layer, [net_base, net_base])
                if order < 0:
                    netp_idx, netn_idx = netn_idx, netp_idx
                mos_type, row_idx = self.get_row_index(tran_name)
                ntr_tot = self.get_num_tracks(mos_type, row_idx, net_type)
                if ntr_tot < ntr_used:
                    raise ValueError(
                        'Need at least %d tracks to draw %s and %s' %
                        (ntr_used, pname, nname))
                tr_indices[pname] = netp_idx + (ntr_tot - ntr_used)
                tr_indices[nname] = netn_idx + (ntr_tot - ntr_used)

        # connect horizontal wires
        result = {}
        inp_tidx, inn_tidx, outp_tidx, outn_tidx = 0, 0, 0, 0
        for net_name, row_type, tr_type in zip(nets, rows, trns):
            if net_name in warr_dict:
                mos_type, row_idx = self.get_row_index(row_type)
                tr_w = tr_manager.get_width(hm_layer, tr_type_dict[net_name])
                if net_name in tr_indices:
                    # use specified relative index
                    tr_idx = tr_indices[net_name]
                else:
                    # compute default relative index.  Try to use the tracks closest to transistor.
                    ntr_used, (tr_idx, ) = tr_manager.place_wires(
                        hm_layer, [tr_type_dict[net_name]])
                    ntr_tot = self.get_num_tracks(mos_type, row_idx, tr_type)
                    if ntr_tot < ntr_used:
                        raise ValueError(
                            'Need at least %d %s tracks to draw %s track' %
                            (ntr_used, tr_type, net_name))
                    if tr_type == 'g':
                        tr_idx += (ntr_tot - ntr_used)

                # get track locations and connect
                if net_name == 'inp':
                    inp_tidx = self.get_track_index(mos_type, row_idx, tr_type,
                                                    tr_idx)
                elif net_name == 'inn':
                    inn_tidx = self.get_track_index(mos_type, row_idx, tr_type,
                                                    tr_idx)
                elif net_name == 'outp':
                    outp_tidx = self.get_track_index(mos_type, row_idx,
                                                     tr_type, tr_idx)
                elif net_name == 'outn':
                    outn_tidx = self.get_track_index(mos_type, row_idx,
                                                     tr_type, tr_idx)
                else:
                    tid = self.make_track_id(mos_type,
                                             row_idx,
                                             tr_type,
                                             tr_idx,
                                             width=tr_w)
                    result[net_prefix + net_name] = self.connect_to_tracks(
                        warr_dict[net_name], tid)

        # connect differential input/output
        inp_warr, inn_warr = self.connect_differential_tracks(
            warr_dict['inp'],
            warr_dict['inn'],
            hm_layer,
            inp_tidx,
            inn_tidx,
            width=tr_manager.get_width(hm_layer, 'in'))
        outp_warr, outn_warr = self.connect_differential_tracks(
            warr_dict['outp'],
            warr_dict['outn'],
            hm_layer,
            outp_tidx,
            outn_tidx,
            width=tr_manager.get_width(hm_layer, 'out'))
        result[net_prefix + 'inp'] = inp_warr
        result[net_prefix + 'inn'] = inn_warr
        result[net_prefix + 'outp'] = outp_warr
        result[net_prefix + 'outn'] = outn_warr

        # connect VDD and VSS
        self.connect_to_substrate('ptap', warr_dict['VSS'])
        if 'VDD' in warr_dict:
            self.connect_to_substrate('ntap', warr_dict['VDD'])
        # return result
        return result, amp_info
Exemplo n.º 14
0
    def draw_layout(self):
        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_main = self.params['seg_main']
        seg_fb = self.params['seg_fb']
        fg_dumr = self.params['fg_dum']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        fg_min = self.params['fg_min']
        options = self.params['options']
        min_height = self.params['min_height']
        sup_tids = self.params['sup_tids']
        sch_hp_params = self.params['sch_hp_params']
        show_pins = self.params['show_pins']

        if options is None:
            options = {}
        end_mode = 12

        # get track manager and wire names
        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)
        wire_names = {
            'tail': dict(g=['clk'], ds=['ntail']),
            'nen': dict(g=['en'], ds=['ntail']),
            'in': dict(g2=['in', 'in']),
            'pen': dict(ds2=['out', 'out'], g=['en', 'en']),
            'load': dict(ds=['ptail'], g=['clk', 'clk']),
        }

        # get total number of fingers
        hm_layer = self.mos_conn_layer + 1
        top_layer = hm_layer + 1
        qdr_info = HybridQDRBaseInfo(self.grid,
                                     lch,
                                     0,
                                     top_layer=top_layer,
                                     end_mode=end_mode,
                                     **options)
        fg_sep_out = qdr_info.get_fg_sep_from_hm_space(tr_manager.get_width(
            hm_layer, 'out'),
                                                       round_even=True)
        # TODO: find this properly.  We need to check if there are fg=2, gate on source
        # TODO: transistors, and if they need larger spacing
        fg_sep_out = 4
        fg_sep_hm = qdr_info.get_fg_sep_from_hm_space(tr_manager.get_width(
            hm_layer, 1),
                                                      round_even=True)
        fg_sep_hm = max(0, fg_sep_hm)

        main_info = qdr_info.get_integ_amp_info(seg_main,
                                                fg_dum=0,
                                                fg_sep_hm=fg_sep_hm)
        fb_info = qdr_info.get_integ_amp_info(seg_fb,
                                              fg_dum=0,
                                              fg_sep_hm=fg_sep_hm)

        fg_main = main_info['fg_tot']
        fg_amp = fg_main + fb_info['fg_tot'] + fg_sep_out
        fg_tot = max(fg_min, fg_amp + 2 * fg_dumr)
        fg_duml = fg_tot - fg_dumr - fg_amp

        self.draw_rows(lch,
                       fg_tot,
                       ptap_w,
                       ntap_w,
                       w_dict,
                       th_dict,
                       tr_manager,
                       wire_names,
                       top_layer=top_layer,
                       end_mode=end_mode,
                       min_height=min_height,
                       **options)

        # draw amplifier
        main_ports, _ = self.draw_integ_amp(fg_duml,
                                            seg_main,
                                            fg_dum=0,
                                            fg_sep_hm=fg_sep_hm)
        col_main_end = fg_duml + fg_main
        col_fb = col_main_end + fg_sep_out
        col_mid = col_main_end + (fg_sep_out // 2)
        fb_ports, _ = self.draw_integ_amp(col_fb,
                                          seg_fb,
                                          invert=True,
                                          fg_dum=0,
                                          fg_sep_hm=fg_sep_hm)

        w_sup = tr_manager.get_width(hm_layer, 'sup')
        vss_warrs, vdd_warrs = self.fill_dummy(vdd_width=w_sup,
                                               vss_width=w_sup,
                                               sup_tids=sup_tids)
        ports_list = [main_ports, fb_ports]

        for name in ('outp', 'outn', 'en2', 'clkp', 'clkn'):
            if name == 'en2':
                wname = 'pen2'
                port_name = 'en<2>'
            else:
                wname = port_name = name
            wlist = [p[wname] for p in ports_list if wname in p]
            cur_warr = self.connect_wires(wlist)
            self.add_pin(port_name, cur_warr, show=show_pins)
        for name in ('pen3', 'nen3'):
            wlist = [p[name] for p in ports_list if name in p]
            cur_warr = self.connect_wires(wlist)
            self.add_pin('en<3>', cur_warr, label='en<3>:', show=show_pins)

        self.add_pin('biasp_m', main_ports['biasp'], show=show_pins)
        self.add_pin('biasp_f', fb_ports['biasp'], show=show_pins)
        self.add_pin('inp', main_ports['inp'], show=show_pins)
        self.add_pin('inn', main_ports['inn'], show=show_pins)
        self.add_pin('fbp', fb_ports['inp'], show=show_pins)
        self.add_pin('fbn', fb_ports['inn'], show=show_pins)

        self.add_pin('VSS', vss_warrs, show=show_pins)
        self.add_pin('VDD', vdd_warrs, show=show_pins)

        # do max space fill
        bnd_box = self.bound_box
        for lay_id in range(1, hm_layer):
            self.do_max_space_fill(lay_id, bound_box=bnd_box, fill_pitch=1.5)
        self.fill_box = bnd_box

        # set properties
        self._sch_params = dict(
            lch=lch,
            w_dict=w_dict,
            th_dict=th_dict,
            seg_main=seg_main,
            seg_fb=seg_fb,
            hp_params=sch_hp_params,
            m_dum_info=self.get_sch_dummy_info(col_start=0, col_stop=col_mid),
            f_dum_info=self.get_sch_dummy_info(col_start=col_mid,
                                               col_stop=None),
        )
        self._fg_tot = fg_tot
Exemplo n.º 15
0
    def draw_layout(self):
        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']
        top_layer = self.params['top_layer']

        nw_list = [w_dict['n']]
        pw_list = [w_dict['p']] * 2
        nth_list = [th_dict['n']]
        pth_list = [th_dict['p']] * 2

        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces)
        hm_layer = self.mos_conn_layer + 1
        wtr_out = tr_manager.get_width(hm_layer, 'out')
        wtr_in = tr_manager.get_width(hm_layer, 'in')
        wtr_en = tr_manager.get_width(hm_layer, 'en')
        wtr_mid = tr_manager.get_width(hm_layer, 'mid')
        sp_io = tr_manager.get_space(hm_layer, ('in', 'out'))
        sp_mid = tr_manager.get_space(hm_layer, ('in', 'mid'))

        seg_p = seg_dict['p']
        seg_n = seg_dict['n']
        seg_single = max(seg_p, seg_n)
        seg_tot = seg_single + 2 * ndum

        if (seg_p - seg_n) % 4 != 0:
            raise ValueError(
                'We assume seg_p and seg_n differ by multiples of 4.')

        # draw transistor rows
        ng_tracks = [wtr_in + sp_io]
        pg_tracks = [wtr_out, wtr_en]
        pds_tracks = [sp_mid + wtr_mid, 0]
        nds_tracks = [0]
        p_orient = ['R0', 'MX']
        n_orient = ['MX']
        self.draw_base(
            lch,
            seg_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_orient,
            p_orientations=p_orient,
            top_layer=top_layer,
        )

        # draw transistors
        pidx = ndum + (seg_single - seg_p) // 2
        nidx = ndum + (seg_single - seg_n) // 2
        p_ports = self.draw_mos_conn('pch',
                                     0,
                                     pidx,
                                     seg_p,
                                     2,
                                     0,
                                     s_net='',
                                     d_net='out')
        n_ports = self.draw_mos_conn('nch',
                                     0,
                                     nidx,
                                     seg_n,
                                     0,
                                     2,
                                     s_net='',
                                     d_net='out')

        # connect supplies
        self.connect_to_substrate('ntap', p_ports['s'])
        self.connect_to_substrate('ptap', n_ports['s'])

        # connect input
        loc = tr_manager.align_wires(hm_layer, ['in'],
                                     ng_tracks[0],
                                     alignment=1)[0]
        tid = self.make_track_id('nch', 0, 'g', loc, width=wtr_in)
        warr = self.connect_to_tracks([p_ports['g'], n_ports['g']], tid)
        self.add_pin('in', warr, show=show_pins)
        # connect output
        loc = tr_manager.align_wires(hm_layer, ['out'],
                                     pg_tracks[0],
                                     alignment=1)[0]
        tid = self.make_track_id('pch', 0, 'g', loc, width=wtr_out)
        warr = self.connect_to_tracks([p_ports['d'], n_ports['d']], tid)
        self.add_pin('out', warr, show=show_pins)

        # draw dummies
        ptap_wire_arrs, ntap_wire_arrs = self.fill_dummy()
        # export supplies
        self.add_pin('VSS', ptap_wire_arrs)
        self.add_pin('VDD', ntap_wire_arrs)

        # 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(),
        )
Exemplo n.º 16
0
    def draw_layout(self):
        w = self.params['w']
        h_unit = self.params['h_unit']
        lch = self.params['lch']
        ptap_w = self.params['ptap_w']
        threshold = self.params['threshold']
        top_layer = self.params['top_layer']
        nser = self.params['nser']
        ndum = self.params['ndum']
        in_tr_info = self.params['in_tr_info']
        out_tr_info = self.params['out_tr_info']
        vdd_tr_info = self.params['vdd_tr_info']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        res_type = self.params['res_type']
        res_options = self.params['res_options']
        cap_spx = self.params['cap_spx']
        cap_spy = self.params['cap_spy']
        cap_margin = self.params['cap_margin']
        ana_options = self.params['ana_options']
        sub_tids = self.params['sub_tids']
        show_pins = self.params['show_pins']

        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)
        sub_tr_w = tr_manager.get_width(top_layer - 1, 'sup')

        rc_params = dict(w=w,
                         h_unit=h_unit,
                         sub_w=ptap_w,
                         sub_lch=lch,
                         sub_type='ptap',
                         threshold=threshold,
                         top_layer=top_layer,
                         nser=nser,
                         ndum=ndum,
                         in_tr_info=in_tr_info,
                         out_tr_info=out_tr_info,
                         bias_idx=0,
                         vdd_tr_info=vdd_tr_info,
                         res_type=res_type,
                         res_options=res_options,
                         cap_spx=cap_spx,
                         cap_spy=cap_spy,
                         cap_margin=cap_margin,
                         end_mode=12,
                         sub_tr_w=sub_tr_w,
                         sub_tids=sub_tids,
                         show_pins=False)
        master0 = self.new_template(params=rc_params, temp_cls=HighPassDiff)
        rc_params['bias_idx'] = 1
        master1 = self.new_template(params=rc_params, temp_cls=HighPassDiff)
        fg_sub = master0.fg_sub

        # place instances
        if fg_sub > 0:
            end_params = dict(
                lch=lch,
                fg=fg_sub,
                sub_type='ptap',
                threshold=threshold,
                top_layer=top_layer,
                end_mode=0b11,
                guard_ring_nf=0,
                options=ana_options,
            )
            end_master = self.new_template(params=end_params,
                                           temp_cls=AnalogBaseEnd)
            end_row_box = end_master.array_box

            bot_inst = self.add_instance(end_master,
                                         'XROWB',
                                         loc=(0, 0),
                                         unit_mode=True)
            ycur = end_row_box.top_unit
            ycur, inst_list = self._place_instances(ycur, master0, master1)
            ycur += end_row_box.top_unit
            top_inst = self.add_instance(end_master,
                                         'XROWT',
                                         loc=(0, ycur),
                                         orient='MX',
                                         unit_mode=True)
            self.fill_box = inst_list[0].bound_box.merge(
                inst_list[-1].bound_box)
            bound_box = bot_inst.bound_box.merge(top_inst.bound_box)
        else:
            _, inst_list = self._place_instances(0, master0, master1)
            self.fill_box = bound_box = inst_list[0].bound_box.merge(
                inst_list[-1].bound_box)

        vdd_list = []
        vss_list = []
        vdd_vm_list = []
        for idx, inst in enumerate(inst_list):
            suffix = '<%d>' % idx
            for name in inst.port_names_iter():
                if name == 'VDD':
                    vdd_list.extend(inst.port_pins_iter('VDD'))
                elif name == 'VSS':
                    vss_list.extend(inst.port_pins_iter('VSS'))
                elif name == 'VDD_vm':
                    vdd_vm_list.extend(inst.port_pins_iter('VDD_vm'))
                else:
                    self.reexport(inst.get_port(name),
                                  net_name=name + suffix,
                                  show=show_pins)

        vdd_vm_list = self.connect_wires(vdd_vm_list)
        self.add_pin('VDD', vdd_list, label='VDD', show=show_pins)
        self.add_pin('VSS', vss_list, label='VSS:', show=show_pins)
        self.add_pin('VDD_vm', vdd_vm_list, label='VDD', show=show_pins)

        # set size
        self.set_size_from_bound_box(top_layer, bound_box)
        self.array_box = bound_box

        # set schematic parameters
        self._sch_params = master0.sch_params.copy()
Exemplo n.º 17
0
    def draw_layout(self):
        # Get parameters from the specifications
        top_layer = self.params['top_layer']
        show_pins = self.params['show_pins']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        guard_ring_nf = self.params['guard_ring_nf']

        # Set up the sub-instance parameters. Some parametes are shared from the top-hierarchy to the sub-instances
        params_d2s = self.params['D2S_params']
        params_d2s['tr_widths'] = tr_widths
        params_d2s['tr_spaces'] = tr_spaces

        params_dtsa = self.params['DTSA_params']
        params_dtsa['tr_widths'] = tr_widths
        params_dtsa['tr_spaces'] = tr_spaces

        # Define the instance masters
        master_dtsa = self.new_template(params=params_dtsa,
                                        temp_cls=DoubleTailSenseAmplifier)
        master_d2s = self.new_template(params=params_d2s,
                                       temp_cls=DynamicToStaticLatch)

        # Define horizontal and vertical connection layers. Set up TrackManager
        horz_conn_layer = self.get_mos_conn_layer() + 1
        vert_conn_layer = self.get_mos_conn_layer() + 2
        power_grid_layer = self.get_mos_conn_layer() + 3
        tr_manager = TrackManager(grid=self.grid,
                                  tr_widths=tr_widths,
                                  tr_spaces=tr_spaces)

        # Calculate x placement of the DTSA and D2S based on which is wider. Center the smaller in the x direction.
        if master_dtsa.bound_box.width_unit > master_d2s.bound_box.width_unit:
            x_offset_unit_dtsa = 0
            x_offset_unit_d2s = (master_dtsa.bound_box.width_unit -
                                 master_d2s.bound_box.width_unit) // 2
            x_total = master_dtsa.bound_box.width_unit
        else:
            x_offset_unit_dtsa = (master_d2s.bound_box.width_unit -
                                  master_dtsa.bound_box.width_unit) // 2
            x_offset_unit_d2s = 0
            x_total = master_d2s.bound_box.width_unit

        # Place the DTSA:
        # Find the closest x and y offsets that will result in the instance being placed on-track
        x_dtsa, y_dtsa = self.place_instance_on_track(
            master_dtsa,
            x_offset=x_offset_unit_dtsa,
            y_offset=0,
            unit_mode=True,
            mode=(0, 0),
            half_track=False)
        # Instantiate the instance
        inst_dtsa = self.add_instance(master_dtsa,
                                      'X_DTSA',
                                      loc=(x_dtsa, y_dtsa),
                                      orient='R0',
                                      unit_mode=True)

        # Place the D2S:  Note it will be flipped MX so we to account for that extra y offset
        x_d2s, y_d2s = self.place_instance_on_track(
            master_d2s,
            x_offset=x_offset_unit_d2s,
            y_offset=inst_dtsa.bound_box.top_unit +
            master_d2s.bound_box.height_unit,
            unit_mode=True,
            mode=(0, 0),
            half_track=False)
        inst_d2s = self.add_instance(master_d2s,
                                     'X_D2S',
                                     loc=(x_d2s, y_d2s),
                                     orient='MX',
                                     unit_mode=True)

        # Set block width of the top level hierarchy
        [blk_w, blk_h] = self.grid.get_block_size(top_layer, unit_mode=True)
        right = math.ceil(x_total / blk_w) * blk_w
        top = math.ceil(inst_d2s.bound_box.top_unit / blk_h) * blk_h
        bound_box = BBox(left=0,
                         bottom=0,
                         right=right,
                         top=top,
                         resolution=self.grid.resolution,
                         unit_mode=True)
        self.set_size_from_bound_box(top_layer, bound_box)

        # Get the output wires of the DTSA and the input wires of the D2S, and connect them
        warr_dtsa_vop_h = inst_dtsa.get_all_port_pins(name='VOP',
                                                      layer=horz_conn_layer)[0]
        warr_dtsa_von_h = inst_dtsa.get_all_port_pins(name='VON',
                                                      layer=horz_conn_layer)[0]

        warr_d2s_r_in_v = inst_d2s.get_all_port_pins(name='R',
                                                     layer=vert_conn_layer)
        warr_d2s_s_in_v = inst_d2s.get_all_port_pins(name='S',
                                                     layer=vert_conn_layer)

        self.connect_differential_wires(
            pin_warrs=warr_d2s_r_in_v,
            nin_warrs=warr_d2s_s_in_v,
            pout_warr=warr_dtsa_von_h,
            nout_warr=warr_dtsa_vop_h,
        )

        # Reexport the VIP, VIN, DIP DIN, Q, and Q_B pins
        self.reexport(port=inst_dtsa.get_port('VIP'), show=show_pins)
        self.reexport(port=inst_dtsa.get_port('VIN'), show=show_pins)
        self.reexport(port=inst_dtsa.get_port('DIP'), show=show_pins)
        self.reexport(port=inst_dtsa.get_port('DIN'), show=show_pins)
        self.reexport(port=inst_d2s.get_port('Q'), show=show_pins)
        self.reexport(port=inst_d2s.get_port('Q_B'), show=show_pins)
        self.reexport(port=inst_dtsa.get_port('CLK'), show=show_pins)
        self.reexport(port=inst_dtsa.get_port('CLK_B'), show=show_pins)

        # Create list of VSS and VDD wire arrays, from bottom to top of layout
        warr_vss = []
        warr_vdd = []

        warr_vss_list = []
        warr_vdd_list = []
        warr_vss_list.append(inst_dtsa.get_all_port_pins(name='VSS'))
        warr_vss_list.append(inst_d2s.get_all_port_pins(name='VSS'))
        warr_vdd_list.append(inst_dtsa.get_all_port_pins(name='VDD'))
        warr_vdd_list.append(inst_d2s.get_all_port_pins(name='VDD'))

        for warr_list in warr_vss_list:
            warr_vss.extend(warr_list)
        for warr_list in warr_vdd_list:
            warr_vdd.extend(warr_list)

        # Extend each horizontal power strap to the width of the block, minus some margin
        for i, warr in enumerate(warr_vss):
            warr_vss[i] = self.extend_wires(
                warr,
                lower=self.bound_box.left_unit +
                self.grid.get_track_pitch(vert_conn_layer, unit_mode=True),
                upper=self.bound_box.right_unit -
                self.grid.get_track_pitch(vert_conn_layer, unit_mode=True),
                unit_mode=True)[0]
        for i, warr in enumerate(warr_vdd):
            warr_vdd[i] = self.extend_wires(
                warr,
                lower=self.bound_box.left_unit +
                self.grid.get_track_pitch(vert_conn_layer, unit_mode=True),
                upper=self.bound_box.right_unit -
                self.grid.get_track_pitch(vert_conn_layer, unit_mode=True),
                unit_mode=True)[0]

        # Power grid space / width parameters
        vert_power_grid_width_tracks = 2
        vert_power_grid_space_tracks = 2
        horz_power_grid_width_tracks = 2
        horz_power_grid_space_tracks = 2

        warr_vdd, warr_vss = self.do_power_fill(
            layer_id=vert_conn_layer,
            space=2 *
            self.grid.get_track_pitch(vert_conn_layer, unit_mode=True),
            space_le=3 * self.grid.get_line_end_space(
                vert_conn_layer, vert_power_grid_width_tracks, unit_mode=True),
            vdd_warrs=warr_vdd,
            vss_warrs=warr_vss,
            fill_width=vert_power_grid_width_tracks,
            fill_space=vert_power_grid_space_tracks,
            x_margin=self.grid.get_track_pitch(vert_conn_layer,
                                               unit_mode=True),
            y_margin=self.grid.get_track_pitch(vert_conn_layer,
                                               unit_mode=True),
            unit_mode=True,
            min_len=self.grid.get_track_width(power_grid_layer,
                                              horz_power_grid_width_tracks,
                                              unit_mode=True))

        warr_vdd, warr_vss = self.do_power_fill(
            layer_id=power_grid_layer,
            space=self.grid.get_track_pitch(power_grid_layer, unit_mode=True),
            space_le=3 * self.grid.get_line_end_space(
                power_grid_layer, horz_power_grid_width_tracks,
                unit_mode=True),
            vdd_warrs=warr_vdd,
            vss_warrs=warr_vss,
            fill_width=horz_power_grid_width_tracks,
            fill_space=horz_power_grid_space_tracks,
            x_margin=self.grid.get_track_pitch(power_grid_layer,
                                               unit_mode=True),
            y_margin=self.grid.get_track_pitch(power_grid_layer,
                                               unit_mode=True),
            unit_mode=True,
        )

        self.add_pin('VDD', warr_vdd, show=show_pins)
        self.add_pin('VSS', warr_vss, show=show_pins)

        # Assign schematic parameters
        self._sch_params = dict(
            DTSA_params=master_dtsa.sch_params,
            D2S_params=master_d2s.sch_params,
        )
Exemplo n.º 18
0
    def draw_layout(self):
        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']
        fg_duml = self.params['fg_duml']
        fg_dumr = self.params['fg_dumr']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        flip_sign = self.params['flip_sign']
        but_sw = self.params['but_sw']
        top_layer = self.params['top_layer']
        end_mode = self.params['end_mode']
        options = self.params['options']
        min_height = self.params['min_height']
        vss_tid = self.params['vss_tid']
        vdd_tid = self.params['vdd_tid']
        sch_hp_params = self.params['sch_hp_params']
        show_pins = self.params['show_pins']
        export_probe = self.params['export_probe']

        if options is None:
            options = {}

        if but_sw:
            casc_g = [1, 1]
        else:
            casc_g = [1]

        # get track manager and wire names
        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces, half_space=True)
        wire_names = {
            'tail': dict(g=['clk'], ds=[1]),
            'nen': dict(g=['clk', 'en'], ds=['ntail']),
            # add a track in input row drain/source for VDD of tail switch
            'in': dict(g2=['in', 'in']),
            'casc': dict(g=casc_g, ds=['ptail']),
            'pen': dict(ds2=['out', 'out'], g=['en', 'en']),
            'load': dict(ds=['ptail'], g=['clk', 'clk']),
        }

        # get total number of fingers
        hm_layer = self.mos_conn_layer + 1
        if top_layer is None:
            top_layer = hm_layer

        fg_amp, fg_sep_hm = self.get_amp_fg_info(self.grid, lch, seg_dict)
        fg_tot = fg_amp + fg_duml + fg_dumr
        self.draw_rows(lch, fg_tot, ptap_w, ntap_w, w_dict, th_dict, tr_manager, wire_names,
                       top_layer=top_layer, end_mode=end_mode, min_height=min_height, **options)

        # draw amplifier
        ports, _ = self.draw_integ_amp(fg_duml, seg_dict, invert=flip_sign,
                                       fg_dum=0, fg_sep_hm=fg_sep_hm)

        if seg_dict.get('tsw', 0) > 0:
            clkn_label = 'clkn:'
            self.add_pin('nclkn', ports['nclkn'], label=clkn_label, show=show_pins)
        else:
            clkn_label = 'clkn'

        w_sup = tr_manager.get_width(hm_layer, 'sup')
        sup_tids = [None, None]
        if vss_tid is None:
            vss_width = w_sup
        else:
            sup_tids[0] = vss_tid[0]
            vss_width = vss_tid[1]
        if vdd_tid is None:
            vdd_width = w_sup
        else:
            sup_tids[1] = vdd_tid[0]
            vdd_width = vdd_tid[1]
        vss_warrs, vdd_warrs = self.fill_dummy(vdd_width=vdd_width, vss_width=vss_width,
                                               sup_tids=sup_tids)
        vss_warr = vss_warrs[0]
        vdd_warr = vdd_warrs[0]
        self.add_pin('VSS', vss_warr, show=show_pins)
        self.add_pin('VDD', vdd_warr, show=show_pins)
        self._track_info = dict(
            VSS=(vss_warr.track_id.base_index, vss_warr.track_id.width),
            VDD=(vdd_warr.track_id.base_index, vdd_warr.track_id.width),
        )

        for name in ('inp', 'inn', 'outp', 'outn', 'biasp'):
            warr = ports[name]
            self.add_pin(name, warr, show=show_pins)
            self._track_info[name] = (warr.track_id.base_index, warr.track_id.width)

        for name in ('foot', 'tail'):
            warr = ports[name]
            self._track_info[name] = (warr.track_id.base_index, warr.track_id.width)
            if export_probe:
                self.add_pin(name, warr, show=True)

        nen3 = ports['nen3']
        self.add_pin('nen3', nen3, show=False)
        self._track_info['nen3'] = (nen3.track_id.base_index, nen3.track_id.width)
        if 'pen3' in ports:
            self.add_pin('pen3', ports['pen3'], show=False)
            self.add_pin('en<3>', nen3, label='en<3>:', show=show_pins)
            self.add_pin('en<3>', ports['pen3'], label='en<3>:', show=show_pins)
        else:
            self.add_pin('en<3>', nen3, show=show_pins)

        for value in (('pen2', 'en<2>'), ('clkp', 'clkp'), ('clkn', 'clkn', clkn_label),
                      ('casc', 'casc'), ('casc<0>', 'casc<0>'), ('casc<1>', 'casc<1>')):
            name, port_name = value[:2]
            if len(value) > 2:
                label = value[2]
            else:
                label = port_name
            if name in ports:
                warr = ports[name]
                self.add_pin(port_name, warr, label=label, show=show_pins)
                if port_name == 'clkp' or port_name == 'clkn':
                    self._track_info[port_name] = (warr.track_id.base_index, warr.track_id.width)

        # get intermediate wire intervals
        lower, upper = None, None
        for name in ('foot', 'tail', 'pm0p', 'pm0n', 'pm1p', 'pm1n', 'nmp', 'nmn'):
            if name in ports:
                warr = ports[name]
                if lower is None:
                    lower = warr.lower_unit
                    upper = warr.upper_unit
                else:
                    lower = min(lower, warr.lower_unit)
                    upper = max(upper, warr.upper_unit)

        self.fill_box = self.bound_box

        # set schematic parameters and other properties
        self._sch_params = self._get_sch_params(lch, w_dict, th_dict, seg_dict, sch_hp_params,
                                                flip_sign, export_probe)
        self._fg_tot = fg_tot
        self._hm_widths = (tr_manager.get_width(hm_layer, 'in'),
                           tr_manager.get_width(hm_layer, 'out'))
        self._hm_intvs = ((lower, upper),
                          (ports['inp'].lower_unit, ports['inp'].upper_unit),
                          (ports['outp'].lower_unit, ports['outp'].upper_unit))
Exemplo n.º 19
0
    def draw_layout(self):
        config = self.params['config']
        seg = self.params['seg']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        wp = self.params['wp']
        wn = self.params['wn']
        row_layout_info = self.params['row_layout_info']
        show_pins = self.params['show_pins']

        wp_row = config['wp']
        wn_row = config['wn']
        if wp is None:
            wp = wp_row
        if wn is None:
            wn = wn_row
        if wp < 0 or wp > wp_row or wn < 0 or wn > wn_row:
            raise ValueError('Invalid choice of wp and/or wn.')
        if seg % 2 != 0:
            raise ValueError('seg = %d must be even.' % seg)

        vss_tid, vdd_tid = self.setup_floorplan(config, row_layout_info, seg)

        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)

        # get track information
        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        hm_w_out = tr_manager.get_width(hm_layer, 'out')
        vm_w_out = tr_manager.get_width(vm_layer, 'out')
        pg_tid = self.make_track_id(1, 'g', -1, width=hm_w_out)
        ng_tid = self.make_track_id(0, 'g', -1, width=hm_w_out)
        pd_tid = self.make_track_id(1, 'gb', 0, width=hm_w_out)
        nd_tid = self.make_track_id(0, 'gb', 0, width=hm_w_out)
        mid_tidx = self.grid.get_middle_track(pg_tid.base_index,
                                              ng_tid.base_index)
        mid_tid = TrackID(hm_layer, mid_tidx, width=hm_w_out)
        vm_coord = self.laygo_info.col_to_coord(seg // 2, unit_mode=True)
        vm_tid = TrackID(vm_layer,
                         self.grid.coord_to_track(vm_layer,
                                                  vm_coord,
                                                  unit_mode=True),
                         width=vm_w_out)

        # add blocks
        pmos = self.add_laygo_mos(1, 0, seg, w=wp)
        nmos = self.add_laygo_mos(0, 0, seg, w=wn)
        # compute overall block size and fill spaces
        self.fill_space()

        # connect wires
        s_warr = self.connect_to_tracks([pmos['s'], nmos['s']], mid_tid)
        self.add_pin('s', s_warr, show=show_pins)
        pd = self.connect_to_tracks(pmos['d'], pd_tid, min_len_mode=0)
        nd = self.connect_to_tracks(nmos['d'], nd_tid, min_len_mode=0)
        d_warr = self.connect_to_tracks([pd, nd], vm_tid)
        self.add_pin('pd', pd, show=False)
        self.add_pin('nd', nd, show=False)
        self.add_pin('d', d_warr, show=show_pins)
        en = self.connect_to_tracks(nmos['g'], ng_tid, min_len_mode=0)
        enb = self.connect_to_tracks(pmos['g'], pg_tid, min_len_mode=0)
        self.add_pin('en', en, show=show_pins)
        self.add_pin('enb', enb, show=show_pins)

        # draw VDD/VSS
        sup_w = vss_tid.width
        xl, xr = self.bound_box.left_unit, self.bound_box.right_unit
        vss = self.add_wires(hm_layer,
                             vss_tid.base_index,
                             xl,
                             xr,
                             width=sup_w,
                             unit_mode=True)
        vdd = self.add_wires(hm_layer,
                             vdd_tid.base_index,
                             xl,
                             xr,
                             width=sup_w,
                             unit_mode=True)
        self.add_pin('VSS', vss, show=show_pins)
        self.add_pin('VDD', vdd, show=show_pins)

        # set properties
        self._sch_params = dict(
            lch=config['lch'],
            wp=wp,
            wn=wn,
            thp=config['thp'],
            thn=config['thn'],
            segp=seg,
            segn=seg,
        )
Exemplo n.º 20
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(),
        )
Exemplo n.º 21
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(),
        )
Exemplo n.º 22
0
    def draw_layout(self):
        # get parameters
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        show_pins = self.params['show_pins']

        tr_manager = TrackManager(self.grid,
                                  tr_widths,
                                  tr_spaces,
                                  half_space=True)
        l_master, m_master = self._make_masters(tr_manager)

        ml_margin, mr_margin = m_master.layout_info.edge_margins
        m_arr_box = m_master.array_box
        m_bnd_box = m_master.bound_box
        # place instances
        top_layer = m_master.top_layer
        m_inst = self.add_instance(m_master,
                                   'XMAIN',
                                   loc=(0, 0),
                                   unit_mode=True)
        y_lat = m_arr_box.top_unit + l_master.array_box.top_unit
        x_lat = m_bnd_box.right_unit - mr_margin - l_master.array_box.right_unit
        l_inst = self.add_instance(l_master,
                                   'XLAT',
                                   loc=(x_lat, y_lat),
                                   orient='MX',
                                   unit_mode=True)
        self._div_grp_loc = (ml_margin, m_arr_box.top_unit)

        # set size
        l_bnd_box = l_inst.bound_box
        self.array_box = m_arr_box.extend(y=l_inst.array_box.top_unit,
                                          unit_mode=True)
        self.fill_box = bnd_box = m_bnd_box.extend(y=l_bnd_box.top_unit,
                                                   unit_mode=True)
        self.set_size_from_bound_box(top_layer, bnd_box)
        self.add_cell_boundary(bnd_box)

        # export pins in-place
        exp_list = [
            (m_inst, 'outp', 'outp_m', True),
            (m_inst, 'outn', 'outn_m', True),
            (m_inst, 'inp', 'inp', False),
            (m_inst, 'inn', 'inn', False),
            (m_inst, 'fbp', 'fbp', False),
            (m_inst, 'fbn', 'fbn', False),
            (m_inst, 'en<3>', 'en<3>', True),
            (m_inst, 'en<2>', 'en<2>', True),
            (m_inst, 'VDD', 'VDD', True),
            (m_inst, 'VSS', 'VSS', True),
            (m_inst, 'clkp', 'clkp', True),
            (m_inst, 'clkn', 'clkn', True),
            (m_inst, 'biasp_m', 'biasp_m', False),
            (m_inst, 'biasp_f', 'biasp_f', False),
            (l_inst, 'inp', 'outp_m', True),
            (l_inst, 'inn', 'outn_m', True),
            (l_inst, 'outp', 'outp_d', False),
            (l_inst, 'outn', 'outn_d', False),
            (l_inst, 'en<3>', 'en<2>', True),
            (l_inst, 'en<2>', 'en<1>', False),
            (l_inst, 'clkp', 'clkn', True),
            (l_inst, 'clkn', 'clkp', True),
            (l_inst, 'VDD', 'VDD', True),
            (l_inst, 'VSS', 'VSS', True),
            (l_inst, 'biasp', 'biasn_d', False),
        ]

        for inst, port_name, name, vconn in exp_list:
            port = inst.get_port(port_name)
            label = name + ':' if vconn else name
            self.reexport(port, net_name=name, label=label, show=show_pins)
            if inst is m_inst and (port_name == 'outp' or port_name == 'outn'):
                self.reexport(port, net_name=port_name + '_main', show=False)

        self._en_locs = self._get_en_locs(l_inst, tr_manager)

        for lay_id in range(1, top_layer - 1):
            self.do_max_space_fill(lay_id, bound_box=l_bnd_box, fill_pitch=1.5)

        # set schematic parameters
        l_outp_tid = l_inst.get_pin('outp').track_id
        self._sch_params = dict(
            sum_params=m_master.sch_params,
            lat_params=l_master.sch_params,
        )
        self._fg_tot = m_master.fg_tot
        self._data_tr_info = (l_outp_tid.base_index,
                              l_inst.get_pin('outn').track_id.base_index,
                              l_outp_tid.width)
        m_tr_info = l_master.track_info
        en3_info = m_tr_info['nen3']
        tr_info = dict(
            VDD=m_tr_info['VDD'],
            VSS=m_tr_info['VSS'],
            q=m_tr_info['inp'],
            qb=m_tr_info['inn'],
            en=(en3_info[0] - 2, en3_info[1]),
            clkp=m_tr_info['clkp'],
            clkn=m_tr_info['clkn'],
            inp=m_tr_info['inp'],
            inn=m_tr_info['inn'],
            outp=m_tr_info['outp'],
            outn=m_tr_info['outn'],
            foot=m_tr_info['foot'],
            tail=m_tr_info['tail'],
        )
        self._div_tr_info = tr_info
        self._sum_row_info = m_master.row_layout_info
        self._lat_row_info = l_master.row_layout_info
        self._left_edge_info = l_master.lr_edge_info[0]