Пример #1
0
    def _connect_supply(self, sup_warr, sup_intv, hm_w_sup, round_up=False):
        # gather list of track indices and wires
        warr_list = sup_warr.to_warr_list()
        min_tid = max_tid = None
        for warr in warr_list:
            tid = warr.track_id.base_index
            if min_tid is None:
                min_tid = max_tid = tid
            else:
                min_tid = min(tid, min_tid)
                max_tid = max(tid, max_tid)

        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        sup_idx = self.grid.get_middle_track(sup_intv[0], sup_intv[1] - 1, round_up=round_up)

        xl = self.grid.track_to_coord(self.conn_layer, min_tid, unit_mode=True)
        xr = self.grid.track_to_coord(self.conn_layer, max_tid, unit_mode=True)
        tl = self.grid.coord_to_nearest_track(vm_layer, xl, half_track=True,
                                              mode=1, unit_mode=True)
        tr = self.grid.coord_to_nearest_track(vm_layer, xr, half_track=True,
                                              mode=-1, unit_mode=True)

        num = int((tr - tl + 2) // 2)
        tid = TrackID(vm_layer, tl, num=num, pitch=2)
        sup = self.connect_to_tracks(warr_list, TrackID(hm_layer, sup_idx, width=hm_w_sup))
        return self.connect_to_tracks(sup, tid, min_len_mode=0)
Пример #2
0
    def _connect_ser_div_mux(self, ym_layer, tr_manager, serb, sert, div, mux,
                             x0, clk_locs, vddo_list, vsso_list, vddi_list,
                             vssi_list, test_box, show_pins):
        # get track locations
        ym_w_clk = tr_manager.get_width(ym_layer, 'clk')
        ym_w_sh = tr_manager.get_width(ym_layer, 'sh')
        ym_w_sig = tr_manager.get_width(ym_layer, 'sig')
        tr0 = self.grid.find_next_track(ym_layer,
                                        x0,
                                        half_track=True,
                                        unit_mode=True)
        en2_tid = TrackID(ym_layer, tr0 + clk_locs[0], width=ym_w_clk)
        sh_tid = TrackID(ym_layer,
                         tr0 + clk_locs[1],
                         width=ym_w_sh,
                         num=2,
                         pitch=clk_locs[4] - clk_locs[1])
        out0_tid = TrackID(ym_layer, tr0 + clk_locs[5], width=ym_w_sig)
        out1_tid = TrackID(ym_layer, tr0 + clk_locs[6], width=ym_w_sig)

        # connect clocks
        pidx = tr0 + clk_locs[2]
        nidx = tr0 + clk_locs[3]
        clkp = list(
            chain(div.port_pins_iter('clkp'), mux.port_pins_iter('clkp')))
        clkn = list(
            chain(div.port_pins_iter('clkn'), mux.port_pins_iter('clkn')))
        clkp, clkn = self.connect_differential_tracks(clkp,
                                                      clkn,
                                                      ym_layer,
                                                      pidx,
                                                      nidx,
                                                      width=ym_w_clk)
        self.add_pin('clkp', clkp, show=show_pins)
        self.add_pin('clkn', clkn, show=show_pins)

        # draw shield connections
        mux_yb, mux_yt = test_box.get_interval('y', unit_mode=True)
        for name, o_list, i_list in (('VDD', vddo_list, vddi_list),
                                     ('VSS', vsso_list, vssi_list)):
            for warr in div.port_pins_iter(name):
                yb, yt = warr.track_id.get_bounds(self.grid, unit_mode=True)
                if yt < mux_yb or yb > mux_yt:
                    o_list.append(warr)
                else:
                    i_list.append(warr)

        # connect seriailzier to mux
        self.connect_to_tracks(
            [serb.get_pin('out'), mux.get_pin('data0')], out0_tid)
        self.connect_to_tracks(
            [sert.get_pin('out'), mux.get_pin('data1')], out1_tid)

        scan_list = [div.get_pin('scan_div<3>'), div.get_pin('scan_div<2>')]
        self.connect_to_tracks(scan_list, sh_tid)
        self.connect_to_tracks(vsso_list, sh_tid)

        # draw en2 connections
        self.connect_to_tracks(div.get_all_port_pins('en2'), en2_tid)
Пример #3
0
    def connect_resistors(self, ndum, nser, bias_idx):
        nx = 2 * (nser + ndum)
        biasp = []
        biasn = []
        outp = outn = None
        for idx in range(ndum):
            biasp.extend(self.get_res_ports(0, idx))
            biasn.extend(self.get_res_ports(0, nx - 1 - idx))
        for idx in range(ndum, nser + ndum):
            cpl = self.get_res_ports(0, idx)
            cpr = self.get_res_ports(0, nx - 1 - idx)
            conn_par = (idx - ndum) % 2
            if idx == ndum:
                biasp.append(cpl[1 - conn_par])
                biasn.append(cpr[1 - conn_par])
            if idx == nser + ndum - 1:
                outp = cpl[conn_par]
                outn = cpr[conn_par]
            else:
                npl = self.get_res_ports(0, idx + 1)
                npr = self.get_res_ports(0, nx - 2 - idx)
                self.connect_wires([npl[conn_par], cpl[conn_par]])
                self.connect_wires([npr[conn_par], cpr[conn_par]])

        biasp = self.connect_wires(biasp)
        biasn = self.connect_wires(biasn)

        # connect bias wires to vertical tracks
        vm_layer = self.bot_layer_id + 1
        t0 = self.grid.find_next_track(vm_layer,
                                       0,
                                       half_track=True,
                                       mode=1,
                                       unit_mode=True)
        t1 = self.grid.find_next_track(vm_layer,
                                       self.bound_box.right_unit,
                                       half_track=True,
                                       mode=-1,
                                       unit_mode=True)
        bp_tid = TrackID(vm_layer, t0 + bias_idx + 1)
        bn_tid = TrackID(vm_layer, t1 - bias_idx - 1)
        biasp = self.connect_to_tracks(biasp, bp_tid)
        biasn = self.connect_to_tracks(biasn, bn_tid)
        vdd = self.add_wires(vm_layer,
                             t0,
                             biasp.lower_unit,
                             biasp.upper_unit,
                             num=2,
                             pitch=t1 - t0,
                             unit_mode=True)
        xl = self.grid.get_wire_bounds(vm_layer, t0 + 2, unit_mode=True)[1]
        xr = self.grid.get_wire_bounds(vm_layer, t1 - 2, unit_mode=True)[0]

        return vdd, biasp, biasn, outp, outn, xl, xr
Пример #4
0
    def draw_layout(self):
        row_layout_info = self.params['row_layout_info']
        num_col = self.params['num_col']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        sup_tids = self.params['sup_tids']
        end_mode = self.params['end_mode']
        abut_mode = self.params['abut_mode']
        abut_sp = self.params['abut_sp']
        show_pins = self.params['show_pins']

        hm_layer = self.conn_layer + 1
        xm_layer = hm_layer + 2
        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces, half_space=True)
        hm_w_sup = tr_manager.get_width(hm_layer, 'sup')
        xm_w_sup = tr_manager.get_width(xm_layer, 'sup')

        inc_col = 0
        if abut_mode & 1 != 0:
            # abut on left
            inc_col += abut_sp
            col_start = abut_sp
        else:
            col_start = 0
        if abut_mode & 2 != 0:
            # abut on right
            inc_col += abut_sp

        self.set_rows_direct(row_layout_info, num_col=num_col, end_mode=end_mode)

        # draw substrate
        vss_w, vdd_w = self._draw_substrate(col_start, num_col, num_col - inc_col)

        # fill space
        self.fill_space()

        # connect supply wires
        vss_intv = self.get_track_interval(0, 'ds')
        vdd_intv = self.get_track_interval(self.num_rows - 1, 'ds')
        vss = self._connect_supply(vss_w, vss_intv, hm_w_sup, round_up=False)
        vdd = self._connect_supply(vdd_w, vdd_intv, hm_w_sup, round_up=True)

        if sup_tids is not None:
            vdd = self.connect_to_tracks(vdd, TrackID(xm_layer, sup_tids[1], width=xm_w_sup))
            vss = self.connect_to_tracks(vss, TrackID(xm_layer, sup_tids[0], width=xm_w_sup))

        self.add_pin('VDD', vdd, show=show_pins)
        self.add_pin('VSS', vss, 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
Пример #5
0
def _connect_lv_por_vm(
        template: MOSBase, rstl: WireArray, rstr: WireArray, rstc: WireArray,
        rst_idx_list: List[HalfInt],
        rstc_idx: int) -> Tuple[WireArray, WireArray, WireArray]:
    vm_layer = template.conn_layer + 2
    vm_w = template.tr_manager.get_width(vm_layer, 'sig')

    rstl = template.connect_to_tracks(
        rstl, TrackID(vm_layer, rst_idx_list[0], width=vm_w))
    rstc = template.connect_to_tracks(
        rstc, TrackID(vm_layer, rst_idx_list[rstc_idx], width=vm_w))
    rstr = template.connect_to_tracks(
        rstr, TrackID(vm_layer, rst_idx_list[3], width=vm_w))
    return rstl, rstr, rstc
Пример #6
0
 def _connect_mirror(self, offset, loc1, loc2, port1, port2):
     r1, c1 = loc1
     r2, c2 = loc2
     for sgn in (-1, 1):
         cur_r1 = offset + sgn * r1
         cur_r2 = offset + sgn * r2
         if sgn < 0:
             cur_r1 -= 1
             cur_r2 -= 1
         if sgn < 0:
             cur_port1 = 1 - port1
             cur_port2 = 1 - port2
         else:
             cur_port1 = port1
             cur_port2 = port2
         wa1 = self.get_res_ports(cur_r1, c1)[cur_port1]
         wa2 = self.get_res_ports(cur_r2, c2)[cur_port2]
         if wa1.track_id.base_index == wa2.track_id.base_index:
             self.connect_wires([wa1, wa2])
         else:
             mode = -1 if c1 % 2 == 0 else 1
             vm_layer = wa1.layer_id + 1
             vm = self.grid.coord_to_nearest_track(vm_layer,
                                                   wa1.middle_unit,
                                                   mode=mode,
                                                   half_track=True,
                                                   unit_mode=True)
             self.connect_to_tracks([wa1, wa2], TrackID(vm_layer, vm))
Пример #7
0
 def to_warr(self, grid: RoutingGrid) -> WireArray:
     return WireArray(
         TrackID(self.layer,
                 self.track,
                 width=self.width,
                 num=self.num,
                 pitch=self.pitch,
                 grid=grid), self.lower, self.upper)
Пример #8
0
    def _connect_dummies(self, ncol, nr1, nr2, ndumr, ndumc):
        res_num_iter = chain(repeat(0, ndumc), repeat(nr1, ncol),
                             repeat(nr2, ncol), repeat(0, ndumc))
        nrow_half = max(nr1, nr2) + ndumr
        bot_warrs, top_warrs = [], []
        for col_idx, res_num in enumerate(res_num_iter):
            mode = -1 if col_idx % 2 == 0 else 1
            if res_num == 0:
                cur_ndum = nrow_half * 2
                bot_idx_list = [0]
            else:
                cur_ndum = nrow_half - res_num
                bot_idx_list = [0, nrow_half + res_num]

            for bot_idx in bot_idx_list:
                top_idx = bot_idx + cur_ndum
                warr_list = []
                for ridx in range(bot_idx, top_idx):
                    bp, tp = self.get_res_ports(ridx, col_idx)
                    warr_list.append(bp)
                    warr_list.append(tp)
                vm_layer = warr_list[0].layer_id + 1
                vm = self.grid.coord_to_nearest_track(vm_layer,
                                                      warr_list[0].middle_unit,
                                                      mode=mode,
                                                      half_track=True,
                                                      unit_mode=True)
                sup_warr = self.connect_to_tracks(warr_list,
                                                  TrackID(vm_layer, vm))
                if bot_idx == 0:
                    bot_warrs.append(sup_warr)
                if bot_idx != 0 or res_num == 0:
                    top_warrs.append(sup_warr)

        hm_layer = bot_warrs[0].layer_id + 1
        hm_pitch = self.grid.get_track_pitch(hm_layer, unit_mode=True)
        num_hm_tracks = self.array_box.height_unit // hm_pitch
        btr = self.connect_to_tracks(bot_warrs,
                                     TrackID(hm_layer, 0),
                                     track_lower=0)
        ttr = self.connect_to_tracks(top_warrs,
                                     TrackID(hm_layer, num_hm_tracks - 1),
                                     track_lower=0)

        return ttr, btr
Пример #9
0
 def _connect_supplies(self, supl_list, supr_list, show_pins):
     vm_layer = self.bot_layer_id + 1
     xm_layer = vm_layer + 1
     for sup_list, mode, name in ((supl_list, -1, 'VSSL'), (supr_list, 1,
                                                            'VSSR')):
         xc = sup_list[0].middle_unit
         vm_tr = self.grid.coord_to_nearest_track(vm_layer,
                                                  xc,
                                                  half_track=True,
                                                  mode=mode,
                                                  unit_mode=True)
         sup = self.connect_to_tracks(sup_list, TrackID(vm_layer, vm_tr))
         xm_tr = self.grid.coord_to_nearest_track(xm_layer,
                                                  sup.middle_unit,
                                                  half_track=True,
                                                  unit_mode=True)
         sup = self.connect_to_tracks(sup,
                                      TrackID(xm_layer, xm_tr),
                                      min_len_mode=mode)
         self.add_pin(name, sup, label='VSS:', show=show_pins)
Пример #10
0
    def _connect_mux_buf(self, ym_layer, tr_manager, mux, bufb, buft,
                         vddo_list, vsso_list, vddi_list, vssi_list, test_box,
                         show_pins):

        # gather supplies
        xl = 0
        test_yb, test_yt = test_box.get_interval('y', unit_mode=True)
        for name, o_list, i_list in (('VDD', vddo_list, vddi_list),
                                     ('VSS', vsso_list, vssi_list)):
            for warr in mux.port_pins_iter(name):
                xl = max(xl, warr.upper_unit)
                yb, yt = warr.track_id.get_bounds(self.grid, unit_mode=True)
                if yt < test_yb or yb > test_yt:
                    o_list.append(warr)
                else:
                    i_list.append(warr)

        vddi_list.extend(bufb.port_pins_iter('VDD'))
        vddi_list.extend(buft.port_pins_iter('VDD'))
        vssi_list.extend(bufb.port_pins_iter('VSS'))
        vssi_list.extend(buft.port_pins_iter('VSS'))

        # connect wires
        ym_w_sig = tr_manager.get_width(ym_layer, 'sig')
        xr = min(vddi_list[-1].lower_unit, vssi_list[-1].lower_unit)
        ym_tidx = self.grid.coord_to_nearest_track(ym_layer, (xl + xr) // 2,
                                                   mode=0,
                                                   unit_mode=True)
        warrs = [mux.get_pin('outp'), bufb.get_pin('in')]
        self.connect_to_tracks(warrs, TrackID(ym_layer,
                                              ym_tidx,
                                              width=ym_w_sig))
        warrs = [mux.get_pin('outn'), buft.get_pin('in')]
        self.connect_to_tracks(warrs, TrackID(ym_layer,
                                              ym_tidx,
                                              width=ym_w_sig))

        # export mux
        self.add_pin('outp', bufb.get_pin('out'), show=show_pins)
        self.add_pin('outn', buft.get_pin('out'), show=show_pins)
Пример #11
0
    def _export_to_ym(self, port, bot_layer):
        warr = port
        for off in range(1, 4):
            next_layer = bot_layer + off
            next_width = self.w_tracks[off]
            next_tr = self.grid.coord_to_nearest_track(next_layer,
                                                       warr.middle_unit,
                                                       half_track=True,
                                                       mode=0,
                                                       unit_mode=True)
            tid = TrackID(next_layer, next_tr, width=next_width)
            warr = self.connect_to_tracks(warr, tid, min_len_mode=0)

        return warr
Пример #12
0
    def _connect_ser_amp(self, ym_layer, tr_manager, ser, amp, x_route,
                         ibias_locs, ym_tr_w_ibias, show_pins):
        wp = self.connect_wires([ser.get_pin('outp'), amp.get_pin('inp')])[0]
        wn = self.connect_wires([ser.get_pin('outn'), amp.get_pin('inn')])[0]

        lower = min(
            wp.track_id.get_bounds(self.grid, unit_mode=True)[0],
            wn.track_id.get_bounds(self.grid, unit_mode=True)[0])
        upper = amp.bound_box.top_unit

        ym_tr_w_sh = tr_manager.get_width(ym_layer, 'sh')
        tr0 = self.grid.find_next_track(ym_layer,
                                        x_route,
                                        mode=1,
                                        half_track=True,
                                        unit_mode=True)

        sh = self.add_wires(ym_layer,
                            tr0 + ibias_locs[0],
                            lower,
                            upper,
                            width=ym_tr_w_sh,
                            num=2,
                            pitch=ibias_locs[2] - ibias_locs[0],
                            unit_mode=True)
        ibias_tid = TrackID(ym_layer, tr0 + ibias_locs[1], width=ym_tr_w_ibias)

        self.add_pin('ibias',
                     self.connect_to_tracks(amp.get_pin('ibias'),
                                            ibias_tid,
                                            track_lower=lower,
                                            track_upper=upper,
                                            unit_mode=True),
                     show=show_pins)

        for name in ('ser_reset', 'div_en', 'clock_tx_div', 'clkp', 'clkn'):
            self.reexport(ser.get_port(name), show=show_pins)
        for idx in range(32):
            self.reexport(ser.get_port('data_tx<%d>' % idx), show=show_pins)

        self.reexport(ser.get_port('VDD'), label='VDD:', show=show_pins)
        self.reexport(ser.get_port('VSS'), label='VSS:', show=show_pins)

        return sh
    def draw_layout(self):
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])
        flip_tile: bool = self.params['flip_tile']
        self.draw_base(pinfo, flip_tile=flip_tile)

        seg_dict: Dict[str, int] = self.params['seg_dict']
        w_dict: Dict[str, int] = self.params['w_dict']
        ridx_p: int = self.params['ridx_p']
        ridx_n: int = self.params['ridx_n']
        sig_locs: Mapping[str, Union[float, HalfInt]] = self.params['sig_locs']
        vertical_rst: bool = self.params['vertical_rst']
        substrate_row: bool = self.params['substrate_row']

        min_sep = self.min_sep_col

        seg_buf = seg_dict.get('buf', 1)
        seg_in = seg_dict.get('in', 1)
        seg_mux = seg_dict.get('mux', 1)
        seg_keep = seg_dict.get('keep', 1)
        seg_pass = seg_dict.get('pass', 1)
        seg_rst = seg_dict.get('rst', 1)
        seg_out = seg_dict.get('out', 1)

        tile0 = self.params['tile0']
        tile1 = self.params['tile1']
        if substrate_row:
            vss0_tid = None
            vdd_tid = None
            vss1_tid = None
        else:
            vss0_tid = self.get_track_id(ridx_n, MOSWireType.DS, 'sup', tile_idx=tile0)
            vdd_tid = self.get_track_id(ridx_p, MOSWireType.DS, 'sup')
            vss1_tid = self.get_track_id(ridx_n, MOSWireType.DS, 'sup', tile_idx=tile1)

        place_info = self.get_tile_pinfo(tile0)
        default_wn = place_info.get_row_place_info(ridx_n).row_info.width
        default_wp = place_info.get_row_place_info(ridx_p).row_info.width
        wp_buf = w_dict.get('p_buf', default_wp)
        wn_buf = w_dict.get('n_buf', default_wn)
        wp_in = w_dict.get('p_in', default_wp)
        wn_in = w_dict.get('n_in', default_wn)
        wp_mux = w_dict.get('p_mux', default_wp)
        wn_mux = w_dict.get('n_mux', default_wn)
        wp_keep = w_dict.get('p_keep', default_wp)
        wn_keep = w_dict.get('n_keep', default_wn)
        wp_pass = w_dict.get('p_pass', default_wp)
        wn_pass = w_dict.get('n_pass', default_wn)
        wp_rst = w_dict.get('p_rst', default_wp)
        wn_rst = w_dict.get('n_rst', default_wn)
        wp_out = w_dict.get('p_out', default_wp)
        wn_out = w_dict.get('n_out', default_wn)

        # tracks
        t0_nd0_tid = self.get_track_id(ridx_n, MOSWireType.DS, 'sig', wire_idx=0, tile_idx=tile0)
        t0_nd1_tid = self.get_track_id(ridx_n, MOSWireType.DS, 'sig', wire_idx=1, tile_idx=tile0)
        t0_ng0_tid = self.get_track_id(ridx_n, MOSWireType.G, 'sig', wire_idx=0, tile_idx=tile0)
        t0_ng1_tid = self.get_track_id(ridx_n, MOSWireType.G, 'sig', wire_idx=1, tile_idx=tile0)
        t0_pg0_tid = self.get_track_id(ridx_p, MOSWireType.G, 'sig', wire_idx=0, tile_idx=tile0)
        t0_pg1_tid = self.get_track_id(ridx_p, MOSWireType.G, 'sig', wire_idx=1, tile_idx=tile0)
        t0_pd0_tid = self.get_track_id(ridx_p, MOSWireType.DS, 'sig', wire_idx=0, tile_idx=tile0)
        t0_pd1_tid = self.get_track_id(ridx_p, MOSWireType.DS, 'sig', wire_idx=1, tile_idx=tile0)
        t1_pd1_tid = self.get_track_id(ridx_p, MOSWireType.DS, 'sig', wire_idx=1, tile_idx=tile1)
        t1_pd0_tid = self.get_track_id(ridx_p, MOSWireType.DS, 'sig', wire_idx=0, tile_idx=tile1)
        t1_pg1_tid = self.get_track_id(ridx_p, MOSWireType.G, 'sig', wire_idx=1, tile_idx=tile1)
        t1_pg0_tid = self.get_track_id(ridx_p, MOSWireType.G, 'sig', wire_idx=0, tile_idx=tile1)
        t1_ng1_tid = self.get_track_id(ridx_n, MOSWireType.G, 'sig', wire_idx=1, tile_idx=tile1)
        t1_ng0_tid = self.get_track_id(ridx_n, MOSWireType.G, 'sig', wire_idx=0, tile_idx=tile1)
        t1_nd1_tid = self.get_track_id(ridx_n, MOSWireType.DS, 'sig', wire_idx=1, tile_idx=tile1)
        t1_nd0_tid = self.get_track_id(ridx_n, MOSWireType.DS, 'sig', wire_idx=0, tile_idx=tile1)

        # placement
        # tile 0
        cur_col = 0
        mos_in_n = self.add_mos(ridx_n, cur_col, seg_in, w=wn_in, g_on_s=True, stack=2,
                                sep_g=True, tile_idx=tile0)
        mos_in_p = self.add_mos(ridx_p, cur_col, seg_in, w=wp_in, g_on_s=True, stack=2,
                                sep_g=True, tile_idx=tile0)
        cur_col += 2 * seg_in + min_sep

        mos_keep_n = self.add_mos(ridx_n, cur_col, seg_keep, w=wn_keep, g_on_s=True, stack=2,
                                  sep_g=True, tile_idx=tile0)
        mos_keep_p = self.add_mos(ridx_p, cur_col, seg_keep, w=wp_keep, g_on_s=True, stack=2,
                                  sep_g=True, tile_idx=tile0)
        cur_col += 2 * seg_keep + min_sep

        mos_pass_n = self.add_mos(ridx_n, cur_col, seg_pass, w=wn_pass, g_on_s=False,
                                  tile_idx=tile0)
        mos_pass_p = self.add_mos(ridx_p, cur_col, seg_pass, w=wp_pass, g_on_s=False,
                                  tile_idx=tile0)
        cur_col += seg_pass + min_sep

        mos_buf_n = self.add_mos(ridx_n, cur_col, 2 * seg_buf, w=wn_buf, g_on_s=True,
                                 sep_g=True, tile_idx=tile0)
        mos_buf_p = self.add_mos(ridx_p, cur_col, 2 * seg_buf, w=wp_buf, g_on_s=True,
                                 sep_g=True, tile_idx=tile0)

        cur_col += 2 * seg_buf + min_sep
        mos_out_n = self.add_mos(ridx_n, cur_col, 2 * seg_out, w=wn_out, tile_idx=tile0)
        mos_out_p = self.add_mos(ridx_p, cur_col, 2 * seg_out, w=wp_out, tile_idx=tile0)
        col_tot = cur_col + 2 * seg_out

        # tile 1
        cur_col = 0
        mos_si_n = self.add_mos(ridx_n, cur_col, seg_in, w=wn_in, g_on_s=True, stack=2,
                                sep_g=True, tile_idx=tile1)
        mos_si_p = self.add_mos(ridx_p, cur_col, seg_in, w=wp_in, g_on_s=True, stack=2,
                                sep_g=True, tile_idx=tile1)
        cur_col += 2 * seg_in + min_sep

        mos_mux_n = self.add_mos(ridx_n, cur_col, seg_mux, w=wn_mux, g_on_s=True, stack=2,
                                 sep_g=True, tile_idx=tile1)
        mos_mux_p = self.add_mos(ridx_p, cur_col, seg_mux, w=wp_mux, g_on_s=True, stack=2,
                                 sep_g=True, tile_idx=tile1)

        cur_col = col_tot - seg_rst - min_sep - 4 * seg_rst
        sub_col = cur_col
        mos_rst_n = self.add_mos(ridx_n, cur_col, 2 * seg_rst, w=wn_rst, g_on_s=True, stack=2,
                                 sep_g=True, tile_idx=tile1)
        mos_rst_p = self.add_mos(ridx_p, cur_col, 4 * seg_rst, w=wp_rst, g_on_s=True,
                                 sep_g=True, tile_idx=tile1)

        cur_col = col_tot - seg_rst
        mos_rst2_n = self.add_mos(ridx_n, cur_col, seg_rst, w=wn_rst, g_on_s=True, tile_idx=tile1)
        mos_rst2_p = self.add_mos(ridx_p, cur_col, seg_rst, w=wp_rst, g_on_s=False, tile_idx=tile1)

        if substrate_row:
            self._substrate_row_intvl.append((sub_col, self.num_cols-sub_col))
            for _tidx in range(pinfo[0].num_tiles):
                _pinfo = self.get_tile_pinfo(_tidx)
                for _ridx in range(_pinfo.num_rows):
                    rtype = _pinfo.get_row_place_info(_ridx).row_info.row_type
                    if rtype.is_substrate:
                        warrs = self.add_substrate_contact(_ridx, sub_col, tile_idx=_tidx,
                                                           seg=self.num_cols-sub_col)
                        sup_name = 'VDD' if rtype is MOSType.ntap else 'VSS'
                        self.add_pin(f'{sup_name}_sub', warrs, label=f'{sup_name}:')

        self.set_mos_size()

        # vertical routing track planning
        grid = self.grid
        tr_manager = self.tr_manager
        conn_layer = self.conn_layer
        hm_layer = conn_layer + 1
        vm_layer = hm_layer + 1
        vm_w = tr_manager.get_width(vm_layer, 'sig')
        vm_se_tidx = grid.coord_to_track(vm_layer, 0)
        vm_seb_tidx = tr_manager.get_next_track(vm_layer, vm_se_tidx, 'sig', 'sig')
        vm_o1_tidx = tr_manager.get_next_track(vm_layer, vm_seb_tidx, 'sig', 'sig')
        vm_ck1_tidx = tr_manager.get_next_track(vm_layer, vm_o1_tidx, 'sig', 'sig')
        x_ck1 = grid.track_to_coord(conn_layer, mos_mux_p.g0.track_id.base_index)
        vm_ck1_tidx = max(vm_ck1_tidx, grid.coord_to_track(vm_layer, x_ck1, mode=RoundMode.LESS_EQ))
        x_ck2 = grid.track_to_coord(conn_layer, mos_rst_p.g[-1].track_id.base_index)
        vm_ck2_tidx = grid.coord_to_track(vm_layer, x_ck2, mode=RoundMode.GREATER_EQ)
        vm_o5_tidx = tr_manager.get_next_track(vm_layer, vm_ck2_tidx, 'sig', 'sig')
        vm_o42_tidx = tr_manager.get_next_track(vm_layer, vm_o5_tidx, 'sig', 'sig')
        x_ckb = grid.track_to_coord(conn_layer, mos_buf_n.s[0].track_id.base_index)
        vm_ckb_tidx = grid.coord_to_track(vm_layer, x_ckb, mode=RoundMode.GREATER_EQ)
        vm_seb2_tidx = tr_manager.get_next_track(vm_layer, vm_ck2_tidx, 'sig', 'sig', up=False)
        x_o41 = grid.track_to_coord(conn_layer, mos_pass_n.d.track_id.base_index)
        vm_o41_tidx = grid.coord_to_track(vm_layer, x_o41, mode=RoundMode.LESS_EQ)
        x_o2 = x_o41 - self.place_info.sd_pitch * 2
        vm_o2_tidx = grid.coord_to_track(vm_layer, x_o2, mode=RoundMode.LESS_EQ)
        # routing
        # supplies
        vdd_list = [mos_in_p.s, mos_keep_p.d, mos_buf_p.d, mos_out_p.d,
                    mos_si_p.s, mos_mux_p.d, mos_rst_p.s[0:2], mos_rst2_p.s]
        vss0_list = [mos_in_n.s, mos_keep_n.d, mos_buf_n.d, mos_out_n.d]
        vss1_list = [mos_si_n.s, mos_mux_n.d, mos_rst_n.d]
        if substrate_row:
            if tile0 < tile1:
                self.add_pin('VSS1', vss1_list, label='VSS:')
                self.add_pin('VSS0', vss0_list, label='VSS:')
            else:
                self.add_pin('VSS1', vss0_list, label='VSS:')
                self.add_pin('VSS0', vss1_list, label='VSS:')
            self.add_pin('VDD', vdd_list, label='VDD:')
        else:
            self.add_pin('VDD', self.connect_to_tracks(vdd_list, vdd_tid))
            self.add_pin('VSS', self.connect_to_tracks(vss0_list, vss0_tid), connect=True)
            self.add_pin('VSS', self.connect_to_tracks(vss1_list, vss1_tid), connect=True)

        # input
        self.add_pin('in', self.connect_to_tracks([mos_in_n.g[0], mos_in_p.g[0]], t0_pg1_tid))
        # scan in
        self.add_pin('scan_in', self.connect_to_tracks([mos_si_n.g[0], mos_si_p.g[0]],
                                                       t1_ng1_tid))
        # scan enable
        se = self.connect_to_tracks([mos_in_p.g[1], mos_buf_p.g[1], mos_buf_n.g[1]], t0_pg0_tid)
        se_top = self.connect_to_tracks(mos_si_n.g[1], t1_ng0_tid, min_len_mode=MinLenMode.LOWER)
        se_vm = self.connect_to_tracks([se, se_top], TrackID(vm_layer, vm_se_tidx, width=vm_w))
        self.add_pin('scan_en', se)
        self.add_pin('scan_en_vm', se_vm, hide=True)

        # scan enable bar
        seb0 = self.connect_to_tracks(mos_buf_n.s[1], t0_nd0_tid, min_len_mode=MinLenMode.UPPER)
        seb1 = self.connect_to_tracks(mos_in_n.g[1], t0_ng1_tid, min_len_mode=MinLenMode.LOWER)
        seb2 = self.connect_to_tracks(mos_buf_p.s[1], t0_pd0_tid, min_len_mode=MinLenMode.LOWER)
        seb3 = self.connect_to_tracks(mos_si_p.g[1], t1_pg0_tid, min_len_mode=MinLenMode.LOWER)
        self.connect_to_tracks([seb1, seb2, seb3], TrackID(vm_layer, vm_seb_tidx, width=vm_w))
        self.connect_to_tracks([seb0, seb2], TrackID(vm_layer, vm_seb2_tidx, width=vm_w))

        # clk
        ck = self.connect_to_tracks([mos_keep_n.g[0], mos_pass_n.g, mos_buf_n.g[0], mos_buf_p.g[0]],
                                    t0_ng0_tid)
        ck1 = self.connect_to_tracks(mos_mux_p.g0, t1_pg0_tid, min_len_mode=MinLenMode.UPPER)
        ck_vm = self.connect_to_tracks([ck, ck1], TrackID(vm_layer, vm_ck1_tidx, width=vm_w))
        ck2 = self.connect_to_tracks(mos_rst_p.g[-1], t1_pg0_tid, min_len_mode=MinLenMode.UPPER)
        self.connect_to_tracks([ck, ck2], TrackID(vm_layer, vm_ck2_tidx, width=vm_w))
        self.add_pin('clk', ck)
        self.add_pin('clk_vm', ck_vm, hide=True)

        # clkb
        ckb0 = self.connect_to_tracks(mos_buf_n.s[0], t0_nd1_tid, min_len_mode=MinLenMode.UPPER)
        ckb1 = self.connect_to_tracks([mos_keep_p.g[0], mos_pass_p.g], t0_pg1_tid)
        ckb2 = self.connect_to_tracks(mos_buf_p.s[0], t0_pd1_tid, min_len_mode=MinLenMode.UPPER)
        ckb3 = self.connect_to_tracks([mos_mux_n.g[0], mos_rst2_n.g], t1_ng0_tid)
        self.connect_to_tracks([ckb0, ckb1, ckb2, ckb3], TrackID(vm_layer, vm_ckb_tidx, width=vm_w))

        # o1
        o10 = self.connect_to_tracks(mos_in_n.d, t0_nd1_tid, min_len_mode=MinLenMode.LOWER)
        o11 = self.connect_to_tracks([mos_in_p.d, mos_si_p.d], t1_pd0_tid,
                                     min_len_mode=MinLenMode.MIDDLE)
        o12 = self.connect_to_tracks([mos_mux_n.g[1], mos_mux_p.g[1]], t1_ng1_tid)
        o13 = self.connect_to_tracks(mos_si_n.d, t1_nd1_tid, min_len_mode=MinLenMode.MIDDLE)
        self.connect_to_tracks([o10, o11, o12, o13], TrackID(vm_layer, vm_o1_tidx, width=vm_w))

        # o2
        o20 = self.connect_to_tracks(mos_keep_n.s, t0_nd1_tid)
        o21 = self.connect_to_tracks([mos_keep_p.s, mos_mux_p.s], t1_pd1_tid)
        o22 = self.connect_to_tracks([mos_rst_n.g[0], mos_rst_p.g[0]], t1_pg0_tid)
        o23 = self.connect_to_tracks(mos_mux_n.s, t1_nd0_tid)
        self.connect_to_tracks([o20, o21, o22, o23], TrackID(vm_layer, vm_o2_tidx, width=vm_w))

        # o3
        o30 = self.connect_to_tracks([mos_keep_n.g[1], mos_keep_p.g[1]], t0_ng1_tid)
        o31 = self.connect_to_tracks(mos_rst_p.d[0], t1_pd0_tid)
        o32 = self.connect_to_tracks(mos_rst_n.s[0], t1_nd1_tid)
        o3_track = self.connect_wires([mos_pass_n.s, mos_pass_p.s])
        self.connect_to_track_wires([o30, o31, o32], o3_track)

        # o4
        o40 = self.connect_to_tracks(mos_pass_n.d, t0_nd0_tid, min_len_mode=MinLenMode.LOWER)
        o41 = self.connect_to_tracks([mos_out_n.g, mos_out_p.g], t0_pg1_tid)
        o42 = self.connect_to_tracks(mos_pass_p.d, t0_pd1_tid, min_len_mode=MinLenMode.LOWER)
        o43 = self.connect_to_tracks(mos_rst_p.d[1], t1_pd1_tid)
        o44 = self.connect_to_tracks(mos_rst2_n.s, t1_nd0_tid)
        self.connect_to_tracks([o40, o42, o43, o44], TrackID(vm_layer, vm_o41_tidx, width=vm_w))
        self.connect_to_tracks([o41, o43], TrackID(vm_layer, vm_o42_tidx, width=vm_w))

        # tp and tn
        self.connect_to_tracks([mos_rst_n.s[-1], mos_rst2_n.d], t1_nd1_tid)
        self.connect_to_tracks([mos_rst_p.s[-1], mos_rst2_p.d], t1_pd0_tid)

        # o5
        o50 = self.connect_to_tracks([mos_out_n.s[0], mos_out_p.s[0]], t0_pd1_tid,
                                     min_len_mode=MinLenMode.UPPER)
        o51 = self.connect_to_tracks([mos_rst_n.g[-1], mos_rst2_p.g], t1_ng1_tid)
        self.connect_to_tracks([o50, o51], TrackID(vm_layer, vm_o5_tidx, width=vm_w))

        # output
        out_idx = sig_locs.get('out', t0_ng1_tid.base_index)
        out = self.connect_to_tracks([mos_out_n.s[1], mos_out_p.s[1]], TrackID(hm_layer, out_idx))
        self.add_pin('out', out)

        # rstlb
        rstlb = self.connect_to_tracks([mos_rst_n.g[1], mos_rst_p.g[1]], t1_pg1_tid)
        self.add_pin('rstlb', rstlb)
        if vertical_rst:
            vm_idx = self.grid.coord_to_track(vm_layer, rstlb.middle, mode=RoundMode.NEAREST)
            avail = self.get_available_tracks(vm_layer, vm_ck1_tidx, vm_ck2_tidx, 0,
                                              self.bound_box.h)
            if vm_idx not in avail:
                raise ValueError(f'Recheck routing on layer {vm_layer}')
            rstlb_vm = self.connect_to_tracks(rstlb, TrackID(vm_layer, vm_idx, width=vm_w))
            self.add_pin('rstlb_vm', rstlb_vm)

        self.sch_params = dict(
            lch=place_info.lch,
            seg_dict={'buf': seg_buf, 'in': seg_in, 'mux': seg_mux, 'keep': seg_keep,
                      'pass': seg_pass, 'rst': seg_rst, 'out': seg_out},
            w_dict=dict(p_buf=wp_buf, n_buf=wn_buf, p_in=wp_in, n_in=wn_in,
                        p_mux=wp_mux, n_mux=wn_mux, p_keep=wp_keep, n_keep=wn_keep,
                        p_pass=wp_pass, n_pass=wn_pass, p_rst=wp_rst, n_rst=wn_rst,
                        p_out=wp_out, n_out=wn_out),
            th_p=place_info.get_row_place_info(ridx_p).row_info.threshold,
            th_n=place_info.get_row_place_info(ridx_n).row_info.threshold,
        )
Пример #14
0
    def draw_layout(self) -> None:
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])
        self.draw_base(pinfo, flip_tile=True)

        grid = self.grid
        tr_manager = self.tr_manager

        drv_params: Param = self.params['drv_params']
        data_lv_params: Param = self.params['data_lv_params']
        ctrl_lv_params: Param = self.params['ctrl_lv_params']
        buf_data_lv_params: Param = self.params['buf_data_lv_params']
        buf_ctrl_lv_params: Param = self.params['buf_ctrl_lv_params']
        ridx_p: int = self.params['ridx_p']
        ridx_n: int = self.params['ridx_n']
        rxhalf_ncol: int = self.params['rxhalf_ncol']

        conn_layer = self.conn_layer
        hm_layer = conn_layer + 1
        vm_layer = hm_layer + 1
        xm_layer = vm_layer + 1

        # setup master parameters
        append = dict(pinfo=pinfo, ridx_p=ridx_p, ridx_n=ridx_n)
        din_params = data_lv_params.copy(append=dict(
            dual_output=False,
            **append,
        ))
        itx_en_params = ctrl_lv_params.copy(append=dict(
            dual_output=True,
            **append,
        ))
        ctrl_params = itx_en_params.copy(append=dict(dual_output=False))
        ndrv_params = ctrl_params.copy(append=dict(invert_out=True))
        drv_params = drv_params.copy(append=append)

        # create masters
        lv_din_master = self.new_template(LevelShifterCoreOutBuffer, params=din_params)
        lv_itx_en_master = self.new_template(LevelShifterCoreOutBuffer, params=itx_en_params)
        lv_ndrv_master = self.new_template(LevelShifterCoreOutBuffer, params=ndrv_params)
        lv_ctrl_master = self.new_template(LevelShifterCoreOutBuffer, params=ctrl_params)
        drv_master: AIBOutputDriver = self.new_template(AIBOutputDriver, params=drv_params)
        buf_data_lv_master = self._get_buf_lv_master(buf_data_lv_params, append)
        buf_ctrl_lv_master = self._get_buf_lv_master(buf_ctrl_lv_params, append)

        # shift output tracks of weak_pullupenb, so it can cross into the other tile.
        tmp_tid = lv_ctrl_master.get_port('out').get_pins()[0].track_id
        pub_tidx = tr_manager.get_next_track(tmp_tid.layer_id, tmp_tid.base_index,
                                             'sig', 'sig', up=True)
        pub_params = ctrl_params.copy(append=dict(sig_locs=dict(outr=pub_tidx)))
        lv_pub_master = self.new_template(LevelShifterCoreOutBuffer, params=pub_params)

        # track definitions
        bot_vss = self.get_track_id(ridx_n, MOSWireType.DS, 'sup', tile_idx=1)
        top_vss = self.get_track_id(ridx_n, MOSWireType.DS, 'sup', tile_idx=2)
        in_pins = ['ipdrv_buf<0>', 'itx_en_buf',
                   'weak_pulldownen', 'weak_pullupenb',
                   'indrv_buf<0>', 'indrv_buf<1>',
                   'din', 'ipdrv_buf<1>']

        # Placement
        din_ncol = lv_din_master.num_cols
        ctrl_ncol = lv_ctrl_master.num_cols
        min_sep = self.min_sep_col
        sup_info = self.get_supply_column_info(xm_layer)

        # assume 2 inverter chains + margins have smaller width than a single lvl shifter
        if 2 * buf_data_lv_master.num_cols + min_sep > din_ncol:
            raise ValueError("input buffer too large compared to data level shifter's width")
        if 2 * buf_ctrl_lv_master.num_cols + min_sep > ctrl_ncol:
            raise ValueError("input buffer too large compared to control level shifter's width")

        # initialize supply data structures
        lay_range = range(conn_layer, xm_layer + 1)
        vdd_io_table = {lay: [] for lay in lay_range}
        vdd_core_table = {lay: [] for lay in lay_range}
        vss_table = {lay: [] for lay in lay_range}

        # instantiate cells and collect pins
        pin_dict = {'por': [], 'porb': [], 'VDDIO': [], 'VDD': [], 'VSS': []}
        cur_col = 0
        cur_col = draw_io_supply_column(self, cur_col, sup_info, vdd_io_table,
                                        vdd_core_table, vss_table, ridx_p, ridx_n, True)
        #  pdrv<0>, itx_en
        new_col = draw_io_shifters(self, cur_col, buf_ctrl_lv_master, buf_ctrl_lv_master,
                                   lv_ctrl_master, lv_itx_en_master,
                                   bot_vss, top_vss, in_pins[0], in_pins[1],
                                   True, True, False, pin_dict)
        ctrl_dual_ncol = new_col - cur_col
        cur_col = new_col
        cur_col = draw_io_supply_column(self, cur_col, sup_info, vdd_io_table,
                                        vdd_core_table, vss_table, ridx_p, ridx_n, False)
        core_ncol = get_io_shifters_ncol(self.sub_sep_col, lv_ctrl_master, lv_pub_master)
        self._core_ncol = max(core_ncol, rxhalf_ncol)
        # puen, puenb
        draw_io_shifters(self, cur_col, buf_ctrl_lv_master, buf_ctrl_lv_master,
                         lv_ctrl_master, lv_pub_master,
                         bot_vss, top_vss, in_pins[2], in_pins[3],
                         False, False, False, pin_dict)
        cur_col += self._core_ncol + min_sep + self.sub_sep_col // 2
        # ndrv<0>, ndrv<1>
        cur_col = draw_io_shifters(self, cur_col + self._core_ncol - core_ncol,
                                   buf_ctrl_lv_master, buf_ctrl_lv_master,
                                   lv_ndrv_master, lv_ndrv_master,
                                   bot_vss, top_vss, in_pins[4], in_pins[5],
                                   True, True, False, pin_dict)
        cur_col = draw_io_supply_column(self, cur_col, sup_info, vdd_io_table,
                                        vdd_core_table, vss_table, ridx_p, ridx_n, True)
        # din, pdrv<1>
        din_ncol_tot = get_io_shifters_ncol(self.sub_sep_col, lv_din_master, lv_ctrl_master)
        din_ncol_max = max(din_ncol_tot, ctrl_dual_ncol)
        self._lvshift_right_ncol = din_ncol_max
        cur_col = draw_io_shifters(self, cur_col + din_ncol_max - din_ncol_tot,
                                   buf_data_lv_master, buf_ctrl_lv_master,
                                   lv_din_master, lv_ctrl_master,
                                   bot_vss, top_vss, in_pins[6], in_pins[7],
                                   True, True, True, pin_dict)
        drv_inst = self.add_tile(drv_master, 1, cur_col)
        # add tapes on bottom tile
        max_col = self._draw_bot_supply_column(cur_col, drv_master.tap_columns, sup_info,
                                               vdd_core_table, vss_table, ridx_p, ridx_n)

        self.set_mos_size(num_cols=max_col)

        # connect and export supply pins
        vss_list = vdd_io_list = vdd_core_list = []
        for lay in range(hm_layer, xm_layer + 1, 2):
            vss = vss_table[lay]
            vdd_io = vdd_io_table[lay]
            vss.extend(drv_inst.port_pins_iter(f'VSS_{lay}'))
            vdd_io.extend(drv_inst.port_pins_iter(f'VDD_{lay}'))
            vss_list = self.connect_wires(vss)
            vdd_io_list = self.connect_wires(vdd_io)
            vdd_core_list = self.connect_wires(vdd_core_table[lay], upper=vdd_io[0].upper)

        self.add_pin('VDDIO', vdd_io_list)
        self.add_pin('VDDCore', vdd_core_list)
        self.add_pin('VSS', vss_list)
        self.add_pin('VDDIO_vm', vdd_io_table[vm_layer], hide=True)
        self.add_pin('VDDCore_vm', vdd_core_table[vm_layer], hide=True)
        self.add_pin('VSS_vm', vss_table[vm_layer], hide=True)
        self.add_pin('VDDIO_conn', vdd_io_table[conn_layer], hide=True)
        self.add_pin('VDDCore_conn', vdd_core_table[conn_layer], hide=True)
        self.add_pin('VSS_conn', vss_table[conn_layer], hide=True)
        self.reexport(drv_inst.get_port('VDD_vm'), net_name='VDDIO_vm')
        self.reexport(drv_inst.get_port('VSS_vm'))
        self.reexport(drv_inst.get_port('VDD_conn'), net_name='VDDIO_conn')
        self.reexport(drv_inst.get_port('VSS_conn'))

        # route input pins to the edge
        in0_tidx = tr_manager.get_next_track(xm_layer, vdd_core_list[0].track_id.base_index,
                                             'sup', 'sig', up=True)
        in_tidx_list = tr_manager.place_wires(xm_layer, ['sig'] * len(in_pins),
                                              align_track=in0_tidx)[1]
        tr_xm_w = tr_manager.get_width(xm_layer, 'sig')
        vm_w = tr_manager.get_width(vm_layer, 'sig')
        for buf_idx, (tidx, name) in enumerate(zip(in_tidx_list, in_pins)):
            hm_warr = pin_dict[name][0]
            vm_tidx_ref = pin_dict[name + '_buf'][1].track_id.base_index
            vm_tidx = tr_manager.get_next_track(vm_layer, vm_tidx_ref, 'sig', 'sig',
                                                up=((buf_idx & 1) == 0))
            vm_warr = self.connect_to_tracks(hm_warr, TrackID(vm_layer, vm_tidx, width=vm_w),
                                             min_len_mode=MinLenMode.LOWER)
            self.add_pin(name,
                         self.connect_to_tracks(vm_warr, TrackID(xm_layer, tidx, width=tr_xm_w),
                                                track_lower=0),
                         mode=PinMode.LOWER)

        # connect POR input
        # connect POR/POR_b
        por_tid = self.get_track_id(ridx_p, MOSWireType.DS, 'sig', wire_idx=2, tile_idx=2)
        porb_tid = self.get_track_id(ridx_p, MOSWireType.DS, 'sig', wire_idx=2, tile_idx=1)
        por = self.connect_to_tracks(pin_dict['por'], por_tid)
        porb = self.connect_to_tracks(pin_dict['porb'], porb_tid)
        self.add_pin('por_vccl', por)
        self.add_pin('porb_vccl', porb)

        # connect driver inputs
        # compute track indices
        # track order: weak_pden, n_enb_drv<0>, pad, p_en_drv<0>, weak_puenb, din
        # n_enb_drv<1>, tristateb, pad, tristate, p_en_drv<1>
        vdd_io_tidx = vdd_io_list[0].track_id.base_index
        pad_tr_w = tr_manager.get_width(xm_layer, 'padout')
        xm_hs_w = tr_manager.get_width(xm_layer, 'sig_hs')
        pad_0_tidx = grid.get_middle_track(vss_list[0].track_id[0].base_index, vdd_io_tidx,
                                           round_up=False)
        pad_1_tidx = grid.get_middle_track(vss_list[0].track_id[1].base_index, vdd_io_tidx,
                                           round_up=True)
        pad_2_tidx = grid.get_middle_track(vss_list[0].track_id[1].base_index,
                                           vdd_io_list[1].track_id.base_index,
                                           round_up=False)
        bb_tidx_list = tr_manager.place_wires(xm_layer, ['sig', 'sig', 'padout'],
                                              align_track=pad_0_tidx, align_idx=-1)[1]
        bt_tidx_list = tr_manager.place_wires(xm_layer, ['padout', 'sig', 'sig', 'sig_hs'],
                                              align_track=pad_0_tidx)[1]
        tb_tidx_list = tr_manager.place_wires(xm_layer, ['sig', 'sig', 'padout'],
                                              align_track=pad_1_tidx, align_idx=-1)[1]
        tt_tidx_list = tr_manager.place_wires(xm_layer, ['padout', 'sig', 'sig'],
                                              align_track=pad_1_tidx)[1]
        # connect wires
        self._connect_lv_drv(pin_dict, drv_inst, 'weak_pulldownen_out', 'weak_pden',
                             TrackID(xm_layer, bb_tidx_list[0], width=tr_xm_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'indrv_buf<0>_out', 'n_enb_drv<0>',
                             TrackID(xm_layer, bb_tidx_list[1], width=tr_xm_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'ipdrv_buf<0>_out', 'p_en_drv<0>',
                             TrackID(xm_layer, bt_tidx_list[1], width=tr_xm_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'weak_pullupenb_out', 'weak_puenb',
                             TrackID(xm_layer, bt_tidx_list[2], width=tr_xm_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'din_out', 'din',
                             TrackID(xm_layer, bt_tidx_list[3], width=xm_hs_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'indrv_buf<1>_out', 'n_enb_drv<1>',
                             TrackID(xm_layer, tb_tidx_list[0], width=tr_xm_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'itx_en_buf_out', 'tristateb',
                             TrackID(xm_layer, tb_tidx_list[1], width=tr_xm_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'itx_en_buf_outb', 'tristate',
                             TrackID(xm_layer, tt_tidx_list[1], width=tr_xm_w))
        self._connect_lv_drv(pin_dict, drv_inst, 'ipdrv_buf<1>_out', 'p_en_drv<1>',
                             TrackID(xm_layer, tt_tidx_list[2], width=tr_xm_w))

        # connect driver outputs
        pad_pitch = pad_2_tidx - pad_0_tidx
        pad_tid0 = TrackID(xm_layer, pad_0_tidx, width=pad_tr_w, num=2, pitch=pad_pitch)
        pad_tid1 = TrackID(xm_layer, pad_1_tidx, width=pad_tr_w, num=2, pitch=pad_pitch)
        pad_pin = drv_inst.get_pin('txpadout')
        self.add_pin('txpadout', [self.connect_to_tracks(pad_pin, pad_tid0),
                                  self.connect_to_tracks(pad_pin, pad_tid1)])
        self.add_pin('txpadout_vm', pad_pin, hide=True)

        # setup schematic parameters
        rm_keys = ['dual_output', 'invert_out']
        data_lv_sch_params = lv_din_master.sch_params.copy(remove=rm_keys)
        ctrl_lv_sch_params = lv_ctrl_master.sch_params.copy(remove=rm_keys)
        self.sch_params = dict(
            drv_params=drv_master.sch_params,
            data_lv_params=dict(
                lev_params=data_lv_sch_params,
                buf_params=buf_data_lv_master.sch_params.copy(remove=['dual_output']),
            ),
            ctrl_lv_params=dict(
                lev_params=ctrl_lv_sch_params,
                buf_params=buf_ctrl_lv_master.sch_params.copy(remove=['dual_output']),
            ),
        )
    def draw_layout(self):
        place_info = MOSBasePlaceInfo.make_place_info(self.grid,
                                                      self.params['pinfo'])
        self.draw_base(place_info)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        lch = arr_info.lch
        buf_params = ImmutableSortedDict(
            dict(
                lch=lch,
                w_p=w_pbuf,
                w_n=w_nbuf,
                th_p=th_dict['ps'],
                th_n=th_dict['nr'],
                seg=seg_obuf,
            ))
        obuf_params = buf_params if has_outbuf else None
        ibuf_params = buf_params.copy(append=dict(
            seg=seg_ibuf)) if has_inbuf else None
        self.sch_params = dict(
            core_params=ImmutableSortedDict(
                dict(
                    lch=lch,
                    seg_dict=ImmutableSortedDict(sch_seg_dict),
                    w_dict=w_dict,
                    th_dict=th_dict,
                )),
            outbuf_params=obuf_params,
            inbuf_params=ibuf_params,
            has_rstb=has_rstb,
        )
    def draw_layout(self) -> None:
        master: SRLatchSymmetricHalf = self.new_template(SRLatchSymmetricHalf,
                                                         params=self.params)
        self.draw_base(master.draw_base_info)

        swap_outbuf: bool = self.params['swap_outbuf']

        hm_w, q_tidx, qb_tidx = master.q_tr_info
        _, sr_hm_top, sr_hm_bot = master.sr_hm_tr_info
        vm_w, sr_vm_tidx, srb_vm_tidx = master.sr_vm_tr_info

        # placement
        nhalf = master.num_cols
        corel = self.add_tile(master, 0, nhalf, flip_lr=True)
        corer = self.add_tile(master, 0, nhalf)
        self.set_mos_size(num_cols=2 * nhalf)

        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        arr_info = self.arr_info
        vm0 = arr_info.col_to_track(vm_layer, 0)
        vmh = arr_info.col_to_track(vm_layer, nhalf)
        vmdr = vmh - vm0
        vmdl = vmh + vm0

        pr = corel.get_pin('psr')
        psb = corel.get_pin('psrb')
        nr = corel.get_pin('nsr')
        nsb = corel.get_pin('nsrb')
        ps = corer.get_pin('psr')
        prb = corer.get_pin('psrb')
        ns = corer.get_pin('nsr')
        nrb = corer.get_pin('nsrb')

        nr, nsb = self.connect_differential_tracks(nr,
                                                   nsb,
                                                   hm_layer,
                                                   sr_hm_top,
                                                   sr_hm_bot,
                                                   width=hm_w)
        ns, nrb = self.connect_differential_tracks(ns,
                                                   nrb,
                                                   hm_layer,
                                                   sr_hm_bot,
                                                   sr_hm_top,
                                                   width=hm_w)
        sb = self.connect_to_tracks([psb, nsb],
                                    TrackID(vm_layer,
                                            vmdl - srb_vm_tidx,
                                            width=vm_w))
        r = self.connect_to_tracks([pr, nr],
                                   TrackID(vm_layer,
                                           vmdl - sr_vm_tidx,
                                           width=vm_w),
                                   track_lower=sb.lower)
        s = self.connect_to_tracks([ps, ns],
                                   TrackID(vm_layer,
                                           vmdr + sr_vm_tidx,
                                           width=vm_w))
        rb = self.connect_to_tracks([prb, nrb],
                                    TrackID(vm_layer,
                                            vmdr + srb_vm_tidx,
                                            width=vm_w),
                                    track_lower=s.lower)

        self.add_pin('sb', sb)
        self.add_pin('rb', rb)
        if corel.has_port('sr_buf'):
            sbuf = corel.get_pin('sr_buf')
            rbuf = corer.get_pin('sr_buf')
            self.connect_to_tracks(sbuf, ns.track_id, track_upper=ns.upper)
            self.connect_to_tracks(rbuf, nr.track_id, track_lower=nr.lower)
        else:
            self.add_pin('s', s)
            self.add_pin('r', r)

        q_list = [corel.get_pin('q_vm'), corer.get_pin('qb')]
        qb_list = [corer.get_pin('q_vm'), corel.get_pin('qb')]
        if corel.has_port('buf_out'):
            if swap_outbuf:
                self.reexport(corel.get_port('buf_out'), net_name='qb')
                self.reexport(corer.get_port('buf_out'), net_name='q')
                q_list.append(corel.get_pin('buf_in'))
                qb_list.append(corer.get_pin('buf_in'))
            else:
                self.reexport(corel.get_port('buf_out'), net_name='q')
                self.reexport(corer.get_port('buf_out'), net_name='qb')
                q_list.append(corer.get_pin('buf_in'))
                qb_list.append(corel.get_pin('buf_in'))
        else:
            self.add_pin('q', q_list[0])
            self.add_pin('qb', qb_list[0])

        self.connect_differential_tracks(q_list,
                                         qb_list,
                                         self.conn_layer + 1,
                                         q_tidx,
                                         qb_tidx,
                                         width=hm_w)

        if corel.has_port('rstb'):
            self.reexport(corel.get_port('rstb'), net_name='rsthb')
            self.reexport(corer.get_port('rstb'), net_name='rstlb')

        self.add_pin(
            'VDD',
            self.connect_wires([corel.get_pin('VDD'),
                                corer.get_pin('VDD')]))
        self.add_pin(
            'VSS',
            self.connect_wires([corel.get_pin('VSS'),
                                corer.get_pin('VSS')]))

        self.sch_params = master.sch_params
Пример #17
0
def join_bias_vroutes(template,
                      vm_layer,
                      vdd_dx,
                      vss_dx,
                      xr,
                      num_vdd_tot,
                      num_vss_tot,
                      hm_bias_info_list,
                      bias_config,
                      vdd_pins,
                      vss_pins,
                      xl=0,
                      yt=None,
                      vss_warrs=None,
                      vdd_warrs=None):
    grid = template.grid

    vss_intvs = IntervalSet()
    vdd_intvs = IntervalSet()
    if vss_warrs is not None:
        for w in WireArray.single_warr_iter(vss_warrs):
            vss_intvs.add(w.track_id.get_bounds(grid, unit_mode=True), val=w)
    if vdd_warrs is not None:
        for w in WireArray.single_warr_iter(vdd_warrs):
            vdd_intvs.add(w.track_id.get_bounds(grid, unit_mode=True), val=w)

    vdd_xl, vdd_xr = vdd_dx
    vss_xl, vss_xr = vss_dx
    vdd_xl += xl
    vdd_xr += xl
    vss_xl += xl
    vss_xr += xl
    vss_params = dict(
        nwire=num_vss_tot,
        width=1,
        space_sig=0,
    )
    vdd_params = dict(
        nwire=num_vdd_tot,
        width=1,
        space_sig=0,
    )
    hm_layer = vm_layer + 1
    vss_hm_list = []
    vdd_hm_list = []
    inst_info_list = []
    vss_y_prev = vdd_y_prev = None
    params = dict(
        bot_layer=vm_layer,
        bias_config=bias_config,
    )
    for idx, (code, num, y0) in enumerate(hm_bias_info_list):
        if code == 0:
            params['bot_params'] = vss_params
            if vss_y_prev is not None and y0 > vss_y_prev:
                sup_warrs = list(vss_intvs.overlap_values((vss_y_prev, y0)))
                tmp = BiasShield.draw_bias_shields(template,
                                                   vm_layer,
                                                   bias_config,
                                                   num_vss_tot,
                                                   vss_xl,
                                                   vss_y_prev,
                                                   y0,
                                                   sup_warrs=sup_warrs)
                vss_hm_list.extend(tmp[0])
        else:
            params['bot_params'] = vdd_params
            if vdd_y_prev is not None and y0 > vdd_y_prev:
                sup_warrs = list(vdd_intvs.overlap_values((vdd_y_prev, y0)))
                tmp = BiasShield.draw_bias_shields(template,
                                                   vm_layer,
                                                   bias_config,
                                                   num_vdd_tot,
                                                   vdd_xl,
                                                   vdd_y_prev,
                                                   y0,
                                                   sup_warrs=sup_warrs)
                vdd_hm_list.extend(tmp[0])
            if vss_y_prev is not None and y0 > vss_y_prev:
                sup_warrs = list(vss_intvs.overlap_values((vss_y_prev, y0)))
                tmp = BiasShield.draw_bias_shields(template,
                                                   vm_layer,
                                                   bias_config,
                                                   num_vss_tot,
                                                   vss_xl,
                                                   vss_y_prev,
                                                   y0,
                                                   sup_warrs=sup_warrs)
                vss_hm_list.extend(tmp[0])

        params['top_params'] = dict(
            nwire=num,
            width=1,
            space_sig=0,
        )
        if idx == 0:
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldJoin)
            if code == 1:
                inst_info_list.append((1, master, vdd_xl, y0))
                BiasShield.draw_bias_shields(template, hm_layer, bias_config,
                                             num, y0, vdd_xr, xr)
                vdd_y_prev = y0 + master.array_box.top_unit
            else:
                inst_info_list.append((0, master, vss_xl, y0))
                BiasShield.draw_bias_shields(template, hm_layer, bias_config,
                                             num, y0, vss_xr, xr)
                vss_y_prev = y0 + master.array_box.top_unit
        elif code == 1:
            params['bot_open'] = True
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldJoin)
            inst_info_list.append((1, master, vdd_xl, y0))
            BiasShield.draw_bias_shields(template,
                                         hm_layer,
                                         bias_config,
                                         num,
                                         y0,
                                         vdd_xr,
                                         vss_xl,
                                         tb_mode=1)
            vdd_y_prev = y0 + master.array_box.top_unit
            params['draw_top'] = False
            params['bot_params'] = vss_params
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldCrossing)
            inst_info_list.append((0, master, vss_xl, y0))
            BiasShield.draw_bias_shields(template, hm_layer, bias_config, num,
                                         y0, vss_xr, xr)
            vss_y_prev = y0 + master.array_box.top_unit
        else:
            params['bot_open'] = True
            master = template.new_template(params=params,
                                           temp_cls=BiasShieldJoin)
            inst_info_list.append((0, master, vss_xl, y0))
            BiasShield.draw_bias_shields(template, hm_layer, bias_config, num,
                                         y0, vss_xr, xr)
            vss_y_prev = y0 + master.array_box.top_unit

    if yt is None:
        yt = max(vss_y_prev, vdd_y_prev)
    if vss_y_prev < yt:
        sup_warrs = list(vss_intvs.overlap_values((vss_y_prev, yt)))
        tmp = BiasShield.draw_bias_shields(template,
                                           vm_layer,
                                           bias_config,
                                           num_vss_tot,
                                           vss_xl,
                                           vss_y_prev,
                                           yt,
                                           sup_warrs=sup_warrs)
        vss_hm_list.extend(tmp[0])
    if vdd_y_prev < yt:
        sup_warrs = list(vdd_intvs.overlap_values((vdd_y_prev, yt)))
        tmp = BiasShield.draw_bias_shields(template,
                                           vm_layer,
                                           bias_config,
                                           num_vdd_tot,
                                           vdd_xl,
                                           vdd_y_prev,
                                           yt,
                                           sup_warrs=sup_warrs)
        vdd_hm_list.extend(tmp[0])

    sup_layer = hm_layer + 1
    vss_list = []
    vdd_list = []
    for code, master, x0, y0 in inst_info_list:
        inst = _add_inst_r180(template, master, x0, y0)
        if code == 1:
            vdd_list.extend(inst.port_pins_iter('sup', layer=sup_layer))
        else:
            vss_list.extend(inst.port_pins_iter('sup', layer=sup_layer))

    vdd_list = template.connect_wires(vdd_list, upper=yt, unit_mode=True)
    vss_list = template.connect_wires(vss_list, upper=yt, unit_mode=True)
    template.draw_vias_on_intersections(vdd_hm_list, vdd_list)
    template.draw_vias_on_intersections(vss_hm_list, vss_list)

    # connect pins
    vss_tidx_list = BiasShield.get_route_tids(grid, vm_layer, vss_xl,
                                              bias_config, num_vss_tot)
    vdd_tidx_list = BiasShield.get_route_tids(grid, vm_layer, vdd_xl,
                                              bias_config, num_vdd_tot)
    pin_map = {}
    vss_tr_warrs = []
    vdd_tr_warrs = []
    for pins, tidx_list, result_list in ((vss_pins, vss_tidx_list,
                                          vss_tr_warrs),
                                         (vdd_pins, vdd_tidx_list,
                                          vdd_tr_warrs)):
        next_idx = 0
        for name, warr in pins:
            if name in pin_map:
                cur_idx = pin_map[name]
                add_pin = False
            else:
                cur_idx = pin_map[name] = next_idx
                next_idx += 1
                add_pin = True
            tidx, tr_w = tidx_list[cur_idx + 1]
            tid = TrackID(vm_layer, tidx, width=tr_w)
            warr = template.connect_to_tracks(warr,
                                              tid,
                                              track_upper=yt,
                                              unit_mode=True)
            if add_pin:
                result_list.append((name, warr))

        pin_map.clear()

    return vdd_tr_warrs, vss_tr_warrs, vdd_list, vss_list
Пример #18
0
    def draw_layout(self):
        lch = self.params['lch']
        ptap_w = self.params['ptap_w']
        ntap_w = self.params['ntap_w']
        wp = self.params['wp']
        wn = self.params['wn']
        thp = self.params['thp']
        thn = self.params['thn']
        seg_list = self.params['seg_list']
        tr_widths = self.params['tr_widths']
        tr_spaces = self.params['tr_spaces']
        out_tid = self.params['out_tid']
        guard_ring_nf = self.params['guard_ring_nf']
        show_pins = self.params['show_pins']

        # get AnalogBaseInfo
        hm_layer = self.mos_conn_layer + 1
        layout_info = AnalogBaseInfo(self.grid, lch, guard_ring_nf, top_layer=hm_layer)
        fg_sep = layout_info.min_fg_sep

        fg_tot = sum(seg_list) + fg_sep * (len(seg_list) - 1)

        # construct track width/space dictionary from EM specs
        tr_manager = TrackManager(self.grid, tr_widths, tr_spaces, half_space=True)

        nw_list = [wn]
        pw_list = [wp]
        nth_list = [thn]
        pth_list = [thp]
        wire_dict_list = [dict(g=['out'])]
        wire_names = dict(nch=wire_dict_list, pch=wire_dict_list)
        # draw transistor rows
        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=['MX'], p_orientations=['R0'], guard_ring_nf=guard_ring_nf,
                       pgr_w=ptap_w, ngr_w=ntap_w, top_layer=hm_layer)

        ng_tid = self.get_wire_id('nch', 0, 'g', wire_idx=0)
        pg_tid = self.get_wire_id('pch', 0, 'g', wire_idx=0)
        num = len(seg_list)
        if out_tid is None:
            in0_tid = ng_tid
            out0_tid = pg_tid
        else:
            out0_tid = TrackID(hm_layer, out_tid[0], width=out_tid[1])
            if abs(pg_tid.base_index - out_tid[0]) < abs(ng_tid.base_index - out_tid[0]):
                in0_tid = ng_tid
            else:
                in0_tid = pg_tid

            if num % 2 == 0:
                tmp = in0_tid
                in0_tid = out0_tid
                out0_tid = tmp

        col = 0
        prev_out = None
        for idx, seg in enumerate(seg_list):
            out_name = 'out' if idx == num - 1 else 'mid%d' % idx
            pmos = self.draw_mos_conn('pch', 0, col, seg, 2, 0, d_net=out_name)
            nmos = self.draw_mos_conn('nch', 0, col, seg, 0, 2, d_net=out_name)
            self.connect_to_substrate('ptap', nmos['s'])
            self.connect_to_substrate('ntap', pmos['s'])
            if idx % 2 == 0:
                in_tid = in0_tid
                out_tid = out0_tid
            else:
                in_tid = out0_tid
                out_tid = in0_tid

            if prev_out is None:
                w_in = self.connect_to_tracks([nmos['g'], pmos['g']], in_tid)
                self.add_pin('in', w_in, show=show_pins)
            else:
                self.connect_to_track_wires([nmos['g'], pmos['g']], prev_out)
            prev_out = self.connect_to_tracks([nmos['d'], pmos['d']], out_tid)
            col += seg + fg_sep

        sup_tr_w = tr_manager.get_width(hm_layer, 'sup')
        vss, vdd = self.fill_dummy(vdd_width=sup_tr_w, vss_width=sup_tr_w)
        self.add_pin('VSS', vss, show=show_pins)
        self.add_pin('VDD', vdd, show=show_pins)
        self.add_pin('out', prev_out, show=show_pins)

        # get schematic parameters
        num_seg = len(seg_list)
        self._sch_params = dict(
            lch=lch,
            wp_list=[wp] * num_seg,
            wn_list=[wn] * num_seg,
            thp=thp,
            thn=thn,
            segp_list=seg_list,
            segn_list=seg_list,
            dum_info=self.get_sch_dummy_info(),
        )
Пример #19
0
    def _draw_data_path(self, anchor: int, se_master: MOSBase,
                        lv_data_master: MOSBase, inv_master: MOSBase,
                        vss_tid: TrackID, flip_lr: bool, prefix: str,
                        pin_dict: Dict[str, List[WireArray]]) -> None:
        tr_manager = self.tr_manager
        grid = self.grid
        vm_layer = self.conn_layer + 2

        dir_sign = 1 - 2 * int(flip_lr)
        inv_ncol = inv_master.num_cols
        inv_ncol += (inv_ncol & 1)
        inv = self.add_tile(inv_master, 0, anchor + dir_sign * inv_ncol, flip_lr=not flip_lr)
        se = self.add_tile(se_master, 1, anchor, flip_lr=flip_lr)
        min_sep = self.min_sep_col
        min_sep += (min_sep & 1)
        if flip_lr:
            lv_col = anchor - inv_ncol - min_sep
        else:
            lv_col = anchor + inv_ncol + min_sep

        lv = self.add_tile(lv_data_master, 0, lv_col, flip_lr=flip_lr)

        # figure out wire location for connecting data buffer to level shifter
        test_pin = se.get_pin('outp')
        vm_test = lv.get_pin('midl')
        test_coord = test_pin.lower if flip_lr else test_pin.upper
        vm_w = tr_manager.get_width(vm_layer, 'sig')
        test_tidx = tr_manager.get_next_track(vm_layer, vm_test.track_id.base_index,
                                              'sig', 'sig', up=-2 * dir_sign)
        test_wbnd = grid.get_wire_bounds(vm_layer, test_tidx, vm_w)[flip_lr]
        if (((test_wbnd < test_coord) and not flip_lr) or
                ((test_wbnd > test_coord) and flip_lr)):
            # closest wires don't work
            vm_ref = lv.get_pin('midr')
            tidx_p = tr_manager.get_next_track(vm_layer, vm_ref.track_id.base_index,
                                               'sig', 'sig', up=dir_sign)

        else:
            tidx_p = test_tidx
        tidx_n = tr_manager.get_next_track(vm_layer, tidx_p,
                                           'sig', 'sig', up=dir_sign)

        outp, outn = self.connect_differential_tracks(se.get_all_port_pins('outp'),
                                                      se.get_all_port_pins('outn'),
                                                      vm_layer, tidx_p, tidx_n, width=vm_w)
        self.connect_differential_wires(outp, outn, lv.get_pin('in'), lv.get_pin('inb'))
        self.connect_to_tracks(lv.get_pin('rst_outb'), vss_tid)

        pin_dict[prefix + 'en'] = [se.get_pin('en')]
        pin_dict[prefix + 'enb'] = [se.get_pin('enb')]
        pin_dict['por_core'].append(lv.get_pin('rst_out'))
        pin_dict['porb_core'].append(lv.get_pin('rst_casc'))

        vm_tidx_ref = inv.get_pin('out').track_id.base_index
        in_vm_tidx = tr_manager.get_next_track(vm_layer, vm_tidx_ref, 'sig', 'sig', up=False)
        in_vm = self.connect_to_tracks(inv.get_pin('in'), TrackID(vm_layer, in_vm_tidx, width=vm_w))
        if se.has_port('inp'):
            # clock path
            pin_dict[prefix + 'inp'] = [se.get_pin('inp')]
            pin_dict[prefix + 'inn'] = [se.get_pin('inn')]
            pin_dict[prefix + 'outp'] = [lv.get_pin('out')]
            pin_dict[prefix + 'outn'] = [lv.get_pin('outb')]
            self.connect_to_tracks(in_vm, vss_tid)
        else:
            # data path
            pin_dict[prefix + 'in'] = [se.get_pin('in')]
            pin_dict[prefix + 'out'] = [lv.get_pin('out')]
            pin_dict[prefix + 'async'] = [inv.get_pin('out')]
            self.connect_to_track_wires([lv.get_pin('poutb'), lv.get_pin('noutb')], in_vm)
Пример #20
0
    def draw_layout(self) -> None:
        ndio_cls_name: str = self.params['ndio_cls']
        pdio_cls_name: str = self.params['pdio_cls']
        ndio_params: Param = self.params['ndio_params']
        pdio_params: Param = self.params['pdio_params']
        fe_params: Param = self.params['fe_params']
        npadout: int = self.params['npadout']
        w_dio_min: int = self.params['w_dio_min']
        dio_margin: int = self.params['dio_margin']
        tb_margin: int = self.params['tb_margin']

        fe_ip_params = dict(
            cls_name='xbase.layout.mos.top.GenericWrapper',
            params=dict(
                cls_name=Frontend.get_qualified_name(),
                params=fe_params,
                export_hidden=True,
                half_blk_x=False,
            ),
        )

        # make masters
        fe_master: TemplateBase = self.new_template(IPMarginTemplate, params=fe_ip_params)
        ndio_cls = cast(Type[TemplateBase], import_class(ndio_cls_name))
        pdio_cls = cast(Type[TemplateBase], import_class(pdio_cls_name))
        nd_master: TemplateBase = self.new_template(ndio_cls, params=ndio_params)
        pd_master: TemplateBase = self.new_template(pdio_cls, params=pdio_params)

        # floorplan
        grid = self.grid
        top_layer = nd_master.top_layer
        w_blk, h_blk = grid.get_block_size(top_layer)
        tb_margin = -(-tb_margin // h_blk) * h_blk
        fe_box = fe_master.bound_box
        nd_box = nd_master.bound_box
        pd_box = pd_master.bound_box
        h_fe = fe_box.h
        h_nd = nd_box.h
        h_pd = pd_box.h
        w_fe = fe_box.w
        w_nd = nd_box.w
        w_pd = pd_box.w
        w_dio = max(w_dio_min + dio_margin, w_nd + w_pd)
        w_tot = w_fe + w_dio
        w_tot = -(-w_tot // w_blk) * w_blk
        h_tot = max(h_fe, h_nd, h_pd) + 2 * tb_margin
        y_fe = (h_tot - h_fe) // (2 * h_blk) * h_blk
        y_nd = (h_tot - h_nd) // (2 * h_blk) * h_blk
        y_pd = (h_tot - h_pd) // (2 * h_blk) * h_blk
        x_nd = w_fe
        x_pd = w_tot - w_pd

        # instantiate blocks
        fe = self.add_instance(fe_master, inst_name='XFE', xform=Transform(0, y_fe))
        nd = self.add_instance(nd_master, inst_name='XND', xform=Transform(x_nd, y_nd))
        pd = self.add_instance(pd_master, inst_name='XPD', xform=Transform(x_pd, y_pd))

        self.set_size_from_bound_box(top_layer, BBox(0, 0, w_tot, h_tot))

        # diode guard ring connections
        vlay = (fe.get_port('VSS').get_single_layer(), 'drawing')
        vdir = Direction.LOWER
        vss_list = []
        vdd_list = []
        vddio_list = []
        vss_bbox: List[BBox] = fe.get_all_port_pins('VSS', layer=vlay[0])
        vdd_bbox: List[BBox] = fe.get_all_port_pins('VDDCore', layer=vlay[0])
        vddio_bbox: List[BBox] = fe.get_all_port_pins('VDDIO', layer=vlay[0])

        vss_pd = pd.get_all_port_pins('gr')
        for bbox in vss_bbox:
            vss_list.extend(self.connect_bbox_to_track_wires(vdir, vlay, bbox, vss_pd))
        vss_list = self.connect_wires(vss_list)

        vddio_nd = nd.get_all_port_pins('gr')
        for bbox in vddio_bbox:
            vddio_list.extend(self.connect_bbox_to_track_wires(vdir, vlay, bbox, vddio_nd))
        vddio_list = self.connect_wires(vddio_list)

        # diode ports
        vddio_pd = pd.get_all_port_pins('sub')
        vss_nd = nd.get_all_port_pins('sub')
        dio_sp_le = grid.get_line_end_space(vss_nd[0].layer_id, vss_nd[0].track_id.width, even=True)
        dio_sp_le2 = dio_sp_le // 2
        if dio_margin < 0:
            dio_margin = dio_sp_le2
        dio_port_xh = w_tot - dio_margin
        x_dio_mid = (nd.bound_box.xh + pd.bound_box.xl) // 2
        vddio_pd = self.extend_wires(vddio_pd, lower=x_dio_mid + dio_sp_le2, upper=dio_port_xh)
        vss_nd = self.extend_wires(vss_nd, lower=x_nd, upper=x_dio_mid - dio_sp_le2)
        self.add_pin('VDDIO', vddio_pd)
        self.add_pin('VSS', vss_nd)
        pad = pd.get_all_port_pins('pad')
        pad.extend(nd.port_pins_iter('pad'))
        pad = self.connect_wires(pad, lower=x_nd, upper=dio_port_xh)[0]
        self.add_pin('iopad', pad)

        # short diode wires so we are LVS clean
        ym_layer = vddio_nd[0].layer_id - 1
        vss_tidx = grid.coord_to_track(ym_layer, x_nd + w_nd, mode=RoundMode.GREATER_EQ)
        vddio_tidx = grid.coord_to_track(ym_layer, x_pd, mode=RoundMode.LESS_EQ)
        iopad_tidx = grid.get_middle_track(vss_tidx, vddio_tidx, round_up=False)
        ym_w = grid.get_min_track_width(ym_layer, top_ntr=vddio_nd[0].track_id.width)
        vddio_pd.extend(vddio_list)
        vss_nd.extend(vss_list)
        self.connect_to_tracks(vddio_pd, TrackID(ym_layer, vddio_tidx, width=ym_w))
        self.connect_to_tracks(vss_nd, TrackID(ym_layer, vss_tidx, width=ym_w))
        self.connect_to_tracks(pad, TrackID(ym_layer, iopad_tidx, width=ym_w))

        # connect iopad and iclkn
        npad = pad.track_id.num
        pad_conn = pad[:npadout]
        iclkn_bnds = [COORD_MAX, COORD_MIN]
        iopad_out_list = []
        for bbox in fe.port_pins_iter('txpadout', layer=vlay[0]):
            warr = self.connect_bbox_to_track_wires(vdir, vlay, bbox, pad_conn)
            iopad_out_list.append(warr)

        for bbox in fe.port_pins_iter('rxpadin', layer=vlay[0]):
            cur_bnds = [0, 0]
            warr = self.connect_bbox_to_track_wires(vdir, vlay, bbox, pad_conn, ret_bnds=cur_bnds)
            iopad_out_list.append(warr)
            iclkn_bnds[0] = min(iclkn_bnds[0], cur_bnds[0])
            iclkn_bnds[1] = max(iclkn_bnds[1], cur_bnds[1])

        # export iopad_out
        pad_conn_tid = pad_conn.track_id
        pad_layer = pad_conn_tid.layer_id
        iopad_out_list = self.connect_wires(iopad_out_list)
        lower = iopad_out_list[0].lower
        pad_bnds = grid.get_wire_bounds(pad_layer, pad_conn_tid.base_index,
                                        width=pad_conn_tid.width)
        pin_len = grid.get_next_length(pad_layer, pad_conn_tid.width, pad_bnds[1] - pad_bnds[0],
                                       even=True)
        ms_params = self.add_res_metal_warr(pad_layer, pad_conn_tid.base_index,
                                            lower + pin_len, lower + 2 * pin_len,
                                            width=pad_conn_tid.width, num=pad_conn_tid.num,
                                            pitch=pad_conn_tid.pitch)

        self.add_pin('iopad_out', WireArray(pad_conn_tid, lower, lower + pin_len))

        bbox_iclkn = fe.get_pin('iclkn', layer=vlay[0])
        bbox_iclkn = bbox_iclkn.set_interval(Orient2D.y, iclkn_bnds[0], iclkn_bnds[1])
        # NOTE: some process require metal to be in same hierarchy as pin
        self.add_rect(vlay, bbox_iclkn)
        self.add_pin_primitive('iclkn', vlay[0], bbox_iclkn)

        # supply connections
        for idx in range(npad):
            tid = vss_nd[idx].track_id
            if idx == 0 or idx == npad - 1:
                cur_list = vdd_list
                cur_bbox = vdd_bbox
            elif idx & 1:
                cur_list = vss_list
                cur_bbox = vss_bbox
            else:
                cur_list = vddio_list
                cur_bbox = vddio_bbox

            for bbox in cur_bbox:
                cur_list.append(self.connect_bbox_to_tracks(vdir, vlay, bbox, tid))

        self.add_pin('VDDCore', self.connect_wires(vdd_list))
        self.add_pin('VDDIO', self.connect_wires(vddio_list))
        self.add_pin('VSS', self.connect_wires(vss_list))
        for name in ['VDDCore', 'VDDIO', 'VSS']:
            self.reexport(fe.get_port(f'{name}_xm'), net_name=name, hide=False)

        # reexport pins
        for name in ['din', 'ipdrv_buf<1>', 'ipdrv_buf<0>',
                     'indrv_buf<1>', 'indrv_buf<0>', 'itx_en_buf', 'weak_pulldownen',
                     'weak_pullupenb']:
            self.reexport(fe.get_port(name))

        for name in ['clk_en', 'data_en', 'por', 'odat', 'odat_async',
                     'oclkp', 'oclkn']:
            self.reexport(fe.get_port(name))

        self.sch_params = dict(
            fe_params=fe_master.sch_params,
            nd_params=nd_master.sch_params,
            pd_params=pd_master.sch_params,
            ms_params=ms_params,
        )
Пример #21
0
    def draw_layout(self):
        place_info = MOSBasePlaceInfo.make_place_info(self.grid,
                                                      self.params['pinfo'])
        self.draw_base(place_info)

        seg_dict: ImmutableSortedDict[str, int] = self.params['seg_dict']
        ridx_n: int = self.params['ridx_n']
        ridx_p: int = self.params['ridx_p']
        has_rstb: bool = self.params['has_rstb']
        has_bridge: bool = self.params['has_bridge']
        vertical_out: bool = self.params['vertical_out']
        vertical_rstb: bool = self.params['vertical_rstb']

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

        seg_in = seg_dict['in']
        seg_tail = seg_dict['tail']
        seg_nfb = seg_dict['nfb']
        seg_pfb = seg_dict['pfb']
        seg_swm = seg_dict['sw']
        w_in = w_dict['in']
        w_tail = w_dict['tail']
        w_nfb = w_dict['nfb']
        w_pfb = w_dict['pfb']

        if seg_in & 1 or (seg_tail % 4 != 0) or seg_nfb & 1 or seg_pfb & 1:
            raise ValueError(
                'in, tail, nfb, or pfb must have even number of segments')
        # NOTE: make seg_swo even so we can abut transistors
        seg_swo = seg_swm + (seg_swm & 1)
        seg_tail = seg_tail // 2

        # placement
        ridx_in = ridx_n + 1
        ridx_nfb = ridx_in + 1
        m_in = self.add_mos(ridx_in, 0, seg_in, w=w_in)
        m_nfb = self.add_mos(ridx_nfb, 0, seg_nfb, w=w_nfb)
        m_pfb = self.add_mos(ridx_p, 0, seg_pfb, w=w_pfb)

        ng_tid = self.get_track_id(ridx_nfb,
                                   MOSWireType.G,
                                   wire_name='sig',
                                   wire_idx=-1)
        mid_tid = self.get_track_id(ridx_nfb, MOSWireType.DS, wire_name='sig')
        pg_tid = self.get_track_id(ridx_p, MOSWireType.G, wire_name='sig')
        vdd_tid = self.get_track_id(ridx_p, MOSWireType.G, wire_name='sup')
        pclk_tid = pg_tid

        if has_rstb:
            vss_tid = self.get_track_id(ridx_n,
                                        MOSWireType.DS,
                                        wire_name='sup')
            nclk_tid = self.get_track_id(ridx_n,
                                         MOSWireType.G,
                                         wire_name='sig',
                                         wire_idx=0)
            nrst_tid = self.get_track_id(ridx_n,
                                         MOSWireType.G,
                                         wire_name='sig',
                                         wire_idx=1)
            prst_tid = self.get_track_id(ridx_p,
                                         MOSWireType.G,
                                         wire_name='sig',
                                         wire_idx=1)
            tail_tid = self.get_track_id(ridx_n,
                                         MOSWireType.DS,
                                         wire_name='tail')
            tail_in_tid = self.get_track_id(ridx_in,
                                            MOSWireType.DS,
                                            wire_name='sig')

            m_tail = self.add_mos(ridx_n,
                                  0,
                                  seg_tail,
                                  w=w_tail,
                                  g_on_s=True,
                                  stack=2,
                                  sep_g=True)
            m_swo_rst = self.add_mos(ridx_p, seg_pfb, seg_swo, w=w_pfb)
            m_swo = self.add_mos(ridx_p, seg_pfb + seg_swo, seg_swo, w=w_pfb)
            m_swm = self.add_mos(ridx_p,
                                 seg_pfb + 2 * seg_swo,
                                 seg_swm,
                                 w=w_pfb)
            vss_conn = m_tail.s
            tail_conn = m_tail.d
            g_conn = m_tail.g
            rstb_conn = g_conn[0::2]
            clk_conn = g_conn[1::2]
        else:
            vss_tid = self.get_track_id(ridx_n, MOSWireType.G, wire_name='sup')
            nclk_tid = self.get_track_id(ridx_n,
                                         MOSWireType.G,
                                         wire_name='sig',
                                         wire_idx=-1)
            nrst_tid = prst_tid = None
            tail_tid = self.get_track_id(ridx_n,
                                         MOSWireType.DS,
                                         wire_name='sig')
            tail_in_tid = tail_tid

            m_tail = self.add_mos(ridx_n, 0, seg_tail, w=w_tail)
            m_swo = self.add_mos(ridx_p, seg_pfb, seg_swo, w=w_pfb)
            m_swm = self.add_mos(ridx_p, seg_pfb + seg_swo, seg_swm, w=w_pfb)
            m_swo_rst = None
            vss_conn = m_tail.s
            tail_conn = m_tail.d
            rstb_conn = None
            clk_conn = m_tail.g

        # NOTE: force even number of columns to make sure VDD conn_layer wires are on even columns.
        ncol_tot = self.num_cols
        self.set_mos_size(num_cols=ncol_tot + (ncol_tot & 1))

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

        if has_rstb:
            nrst = self.connect_to_tracks(rstb_conn, nrst_tid)
            prst = self.connect_to_tracks([m_swo_rst.g], prst_tid)
            self.add_pin('nrstb', nrst)
            self.add_pin('prstb', prst)
            if vertical_rstb:
                xrst = grid.track_to_coord(conn_layer,
                                           m_swo_rst.g.track_id.base_index)
                vm_tidx = grid.coord_to_track(vm_layer,
                                              xrst,
                                              mode=RoundMode.GREATER_EQ)
                self.connect_to_tracks([nrst, prst],
                                       TrackID(vm_layer, vm_tidx, width=vm_w))

            tail = self.connect_to_tracks(tail_conn, tail_tid)
            in_d = m_in.d
            tail_in = self.connect_to_tracks(in_d, tail_in_tid)
            self.add_pin('tail_in', tail_in)
            tail_list = [tail, tail_in]
            for warr in in_d.warr_iter():
                xwire = grid.track_to_coord(conn_layer,
                                            warr.track_id.base_index)
                vm_tidx = grid.coord_to_track(vm_layer,
                                              xwire,
                                              mode=RoundMode.GREATER_EQ)
                self.connect_to_tracks(tail_list,
                                       TrackID(vm_layer, vm_tidx, width=vm_w))

            out = self.connect_wires([m_nfb.d, m_pfb.d, m_swo.d, m_swo_rst.d])
            vdd = self.connect_to_tracks(
                [m_pfb.s, m_swo.s, m_swm.s, m_swo_rst.s], vdd_tid)
            mid = self.connect_to_tracks([m_in.s, m_nfb.s, m_swm.d], mid_tid)
        else:
            tail = self.connect_to_tracks([tail_conn, m_in.d], tail_tid)
            out = self.connect_wires([m_nfb.d, m_pfb.d, m_swo.d])
            vdd = self.connect_to_tracks([m_pfb.s, m_swo.s, m_swm.s], vdd_tid)
            mid = self.connect_to_tracks([m_in.s, m_nfb.s, m_swm.d], mid_tid)

        vss = self.connect_to_tracks(vss_conn, vss_tid)
        nclk = self.connect_to_tracks(clk_conn, nclk_tid)
        nout = self.connect_to_tracks(m_nfb.g, ng_tid)
        pout = self.connect_to_tracks(m_pfb.g, pg_tid)
        pclk = self.connect_to_tracks([m_swo.g, m_swm.g], pclk_tid)

        xclk = grid.track_to_coord(conn_layer, m_swo.g.track_id.base_index)
        vm_tidx = grid.coord_to_track(vm_layer,
                                      xclk,
                                      mode=RoundMode.GREATER_EQ)
        clk_vm = self.connect_to_tracks([nclk, pclk],
                                        TrackID(vm_layer, vm_tidx, width=vm_w))
        self.add_pin('clk_vm', clk_vm)

        xout = grid.track_to_coord(conn_layer, m_pfb.g.track_id.base_index)
        vm_tidx = grid.coord_to_track(vm_layer,
                                      xout,
                                      mode=RoundMode.GREATER_EQ)

        if vertical_out:
            out_vm = self.connect_to_tracks([nout, pout],
                                            TrackID(vm_layer,
                                                    vm_tidx,
                                                    width=vm_w))
            self.add_pin('out_vm', out_vm)
        else:
            self.add_pin('pout', pout)
            self.add_pin('nout', nout)

        self.add_pin('VSS', vss)
        self.add_pin('VDD', vdd)
        self.add_pin('tail', tail)
        self.add_pin('clk', nclk)
        self.add_pin('in', m_in.g)
        self.add_pin('out', out)
        self.add_pin('mid', mid)

        append_dict = dict(swo=seg_swo, swm=seg_swm)
        if has_bridge:
            append_dict['br'] = 1
        sch_seg_dict = seg_dict.copy(append=append_dict, remove=['sw'])
        self.sch_params = dict(
            lch=self.arr_info.lch,
            seg_dict=sch_seg_dict,
            w_dict=w_dict,
            th_dict=th_dict,
            has_rstb=has_rstb,
            has_bridge=has_bridge,
        )
Пример #22
0
    def draw_layout(self):
        grid = self.grid
        params = self.params
        pinfo = MOSBasePlaceInfo.make_place_info(grid, params['pinfo'])
        self.draw_base(pinfo)

        tr_manager = self.tr_manager

        seg_p: int = params['seg_p']
        seg_n: int = params['seg_n']
        seg_nand: int = params['seg_nand']
        seg_nor: int = params['seg_nor']
        w_p: int = params['w_p']
        w_n: int = params['w_n']
        w_p_nand: int = params['w_p_nand']
        w_n_nand: int = params['w_n_nand']
        w_p_nor: int = params['w_p_nor']
        w_n_nor: int = params['w_n_nor']
        ridx_p: int = params['ridx_p']
        ridx_n: int = params['ridx_n']
        export_pins: bool = params['export_pins']

        vm_layer = self.conn_layer + 2

        #if (seg_p - seg_n) % 2 != 0:
        #    raise ValueError('seg_p - seg_n should be even')

        in0_tidx = self.get_track_index(ridx_n,
                                        MOSWireType.G,
                                        wire_name='sig',
                                        wire_idx=0)
        nout_tidx = self.get_track_index(ridx_n,
                                         MOSWireType.DS_GATE,
                                         wire_name='sig',
                                         wire_idx=0)
        pout_tidx = self.get_track_index(ridx_p,
                                         MOSWireType.DS_GATE,
                                         wire_name='sig',
                                         wire_idx=-1)
        pin_drv_tidx = self.get_track_index(ridx_p,
                                            MOSWireType.G,
                                            wire_name='sig',
                                            wire_idx=0)
        nin_drv_tidx = self.get_track_index(ridx_n,
                                            MOSWireType.G,
                                            wire_name='sig',
                                            wire_idx=2)
        sig_locs_gate = dict(nin=in0_tidx, nout=nout_tidx, pout=pout_tidx)
        sig_locs_drv = dict(pin=pin_drv_tidx, nin=nin_drv_tidx)
        nand_params = dict(
            pinfo=pinfo,
            seg=seg_nand,
            vertical_out=False,
            vertical_in=False,
            is_guarded=True,
            w_p=w_p_nand,
            w_n=w_n_nand,
            ridx_n=ridx_n,
            ridx_p=ridx_p,
            sig_locs=sig_locs_gate,
            min_len_mode=dict(
                in0=MinLenMode.LOWER,
                in1=MinLenMode.LOWER,
            ),
        )
        nor_params = nand_params.copy()
        nor_params['seg'] = seg_nor
        nor_params['w_p'] = w_p_nor
        nor_params['w_n'] = w_n_nor
        drv_params = dict(
            pinfo=pinfo,
            seg_p=seg_p,
            seg_n=seg_n,
            w_p=w_p,
            w_n=w_n,
            stack=1,
            ridx_p=ridx_p,
            ridx_n=ridx_n,
            sig_locs=sig_locs_drv,
        )

        # --- Placement --- #
        nand_master = self.new_template(NAND2Core, params=nand_params)
        nor_master = self.new_template(NOR2Core, params=nor_params)
        drv_master = self.new_template(PullUpDown, params=drv_params)

        nand_ncols = nand_master.num_cols
        nor_ncols = nor_master.num_cols
        drv_ncols = drv_master.num_cols
        min_sep = self.min_sep_col
        ncol_tot = nand_ncols + drv_ncols + nor_ncols + 2 * min_sep

        nand_inst = self.add_tile(nand_master, 0, nand_ncols, flip_lr=True)
        drv_inst = self.add_tile(drv_master, 0, nand_ncols + min_sep)
        nor_inst = self.add_tile(nor_master, 0, ncol_tot - nor_ncols)
        self.set_mos_size(num_cols=ncol_tot)

        # Routing
        pin = self.connect_wires(
            [nor_inst.get_pin('pin<0>'),
             nand_inst.get_pin('pin<0>')])
        nin = self.connect_wires(
            [nor_inst.get_pin('nin<0>'),
             nand_inst.get_pin('nin<0>')])
        self.add_pin('pin', pin, label='in:')
        self.add_pin('nin', nin, label='in:')

        bnd_box = self.bound_box
        vm_tr_w = tr_manager.get_width(vm_layer, 'sig')
        en_vm_tidx = grid.coord_to_track(vm_layer,
                                         bnd_box.xl,
                                         mode=RoundMode.GREATER_EQ)
        enb_vm_tidx = grid.coord_to_track(vm_layer,
                                          bnd_box.xh,
                                          mode=RoundMode.LESS_EQ)
        puenb_vm_tidx = tr_manager.get_next_track(vm_layer,
                                                  en_vm_tidx,
                                                  'sig',
                                                  'sig',
                                                  up=True)
        pden_vm_tidx = tr_manager.get_next_track(vm_layer,
                                                 enb_vm_tidx,
                                                 'sig',
                                                 'sig',
                                                 up=False)
        puenb = drv_inst.get_pin('puenb')
        pden = drv_inst.get_pin('pden')
        if export_pins:
            self.add_pin('nand_pu', puenb)
            self.add_pin('nor_pd', pden)
        self.connect_to_tracks(
            [nand_inst.get_pin('pout'),
             nand_inst.get_pin('nout'), puenb],
            TrackID(vm_layer, puenb_vm_tidx, width=vm_tr_w))
        self.connect_to_tracks(
            [nor_inst.get_pin('pout'),
             nor_inst.get_pin('nout'), pden],
            TrackID(vm_layer, pden_vm_tidx, width=vm_tr_w))
        en = self.connect_to_tracks(
            [nand_inst.get_pin('pin<1>'),
             nand_inst.get_pin('nin<1>')],
            TrackID(vm_layer, en_vm_tidx, width=vm_tr_w))
        enb = self.connect_to_tracks(
            [nor_inst.get_pin('pin<1>'),
             nor_inst.get_pin('nin<1>')],
            TrackID(vm_layer, enb_vm_tidx, width=vm_tr_w))
        self.add_pin('en', en)
        self.add_pin('enb', enb)
        self.reexport(drv_inst.get_port('out'))
        self.reexport(drv_inst.get_port('pout'))
        self.reexport(drv_inst.get_port('nout'))

        # connect vss and vdd
        vdd = self.connect_wires([
            nand_inst.get_pin('VDD'),
            nor_inst.get_pin('VDD'),
            drv_inst.get_pin('VDD')
        ])
        vss = self.connect_wires([
            nand_inst.get_pin('VSS'),
            nor_inst.get_pin('VSS'),
            drv_inst.get_pin('VSS')
        ])
        self.add_pin('VDD', vdd)
        self.add_pin('VSS', vss)

        # get schematic parameters
        self.sch_params = dict(
            nand_params=nand_master.sch_params,
            nor_params=nor_master.sch_params,
            pupd_params=drv_master.sch_params,
            export_pins=export_pins,
        )
Пример #23
0
    def draw_layout(self):
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid, self.params['pinfo'])
        self.draw_base(pinfo, flip_tile=True)

        conn_layer = self.conn_layer
        hm_layer = conn_layer + 1
        vm_layer = hm_layer + 1
        xm_layer = vm_layer + 1

        ridx_p: int = self.params['ridx_p']
        ridx_n: int = self.params['ridx_n']
        core_ncol: int = self.params['core_ncol']
        tap_info_list: ImmutableList[Tuple[int, bool]] = self.params['tap_info_list']

        tmp = self._make_masters(self, pinfo, self.params)
        (lv_data_master, lv_ctrl_master, lv_por_master, inv_master, data_master,
         clk_master, buf_ctrl_lv_master, buf_por_lv_master) = tmp

        inbuf_ncol = max(data_master.num_cols, clk_master.num_cols)

        # track definitions
        bot_vss = self.get_track_id(ridx_n, MOSWireType.DS, 'sup', tile_idx=1)
        top_vss = self.get_track_id(ridx_n, MOSWireType.DS, 'sup', tile_idx=2)
        # Placement
        lv_data_ncol = lv_data_master.num_cols
        lv_ctl_ncol = lv_ctrl_master.num_cols
        lv_por_ncol = lv_por_master.num_cols
        min_sep = self.min_sep_col
        sup_info = self.get_supply_column_info(xm_layer)

        inv_ncol = inv_master.num_cols
        inv_ncol += (inv_ncol & 1)
        half_ncol = max(lv_data_ncol + min_sep + inv_ncol, inbuf_ncol, core_ncol)

        # assume 2 inverter chains + margins have smaller width than a single lvl shifter
        if 2 * buf_ctrl_lv_master.num_cols + min_sep > lv_ctl_ncol:
            raise ValueError("buffer too large compared to data level shifter's width")
        if 2 * buf_por_lv_master.num_cols + min_sep > lv_por_ncol:
            raise ValueError("buffer too large compared to data level shifter's width")

        # initialize supply data structures
        lay_range = range(conn_layer, xm_layer + 1)
        vdd_io_table = {lay: [] for lay in lay_range}
        vdd_core_table = {lay: [] for lay in lay_range}
        vss_table = {lay: [] for lay in lay_range}

        # instantiate cells and collect pins
        pin_dict = {'por': [], 'porb': [], 'VDDIO': [], 'VSS': [], 'por_core': [],
                    'porb_core': [], 'VDD': []}
        in_pins = ['din_en', 'por_in', 'ck_en', 'unused']
        cur_col = 0
        cur_col = draw_io_supply_column(self, cur_col, sup_info, vdd_io_table,
                                        vdd_core_table, vss_table, ridx_p, ridx_n, True)
        new_col = draw_io_shifters(self, cur_col, buf_ctrl_lv_master, buf_por_lv_master,
                                   lv_ctrl_master, lv_por_master,
                                   bot_vss, top_vss, in_pins[0], in_pins[1],
                                   True, True, False, pin_dict)
        cur_col = new_col
        cur_col = draw_io_supply_column(self, cur_col, sup_info, vdd_io_table,
                                        vdd_core_table, vss_table, ridx_p, ridx_n, False)
        cur_col += half_ncol
        self._draw_data_path(cur_col, data_master, lv_data_master, inv_master,
                             bot_vss, True, 'data_', pin_dict)
        cur_col += min_sep
        self._draw_data_path(cur_col, clk_master, lv_data_master, inv_master,
                             bot_vss, False, 'clk_', pin_dict)
        cur_col += half_ncol + self.sub_sep_col // 2
        cur_col = draw_io_supply_column(self, cur_col, sup_info, vdd_io_table,
                                        vdd_core_table, vss_table, ridx_p, ridx_n, True)
        cur_col = draw_io_shifters(self, cur_col, buf_ctrl_lv_master, buf_por_lv_master,
                                   lv_ctrl_master, lv_por_master,
                                   bot_vss, top_vss, in_pins[2], in_pins[3],
                                   True, True, False, pin_dict, flip_lr=True)

        # add tapes on bottom tile
        max_col = self._draw_bot_supply_column(tap_info_list, sup_info, vdd_core_table, vss_table,
                                               ridx_p, ridx_n)
        max_col = max(cur_col, max_col)
        self.set_mos_size(num_cols=max_col)
        xh = self.bound_box.xh

        # connect and export supply pins
        vss_table[hm_layer].extend(pin_dict['VSS'])
        vdd_core_table[hm_layer].extend(pin_dict['VDD'])
        vdd_io_table[hm_layer].extend(pin_dict['VDDIO'])
        vss_list = vdd_io_list = vdd_core_list = []
        for lay in range(hm_layer, xm_layer + 1, 2):
            vss_list = self.connect_wires(vss_table[lay], upper=xh)
            vdd_core_list = self.connect_wires(vdd_core_table[lay], upper=xh)
            vdd_io_list = self.connect_wires(vdd_io_table[lay], upper=xh)

        vss_vm = vss_table[vm_layer]
        self.add_pin('VDDIO', vdd_io_list)
        self.add_pin('VDDCore', vdd_core_list)
        self.add_pin('VSS', vss_list)
        self.add_pin('VDDIO_vm', vdd_io_table[vm_layer], hide=True)
        self.add_pin('VDDCore_vm', vdd_core_table[vm_layer], hide=True)
        self.add_pin('VSS_vm', vss_vm, hide=True)
        self.add_pin('VDDIO_conn', vdd_io_table[conn_layer], hide=True)
        self.add_pin('VDDCore_conn', vdd_core_table[conn_layer], hide=True)
        self.add_pin('VSS_conn', vss_table[conn_layer], hide=True)

        # connect VDDCore signals
        grid = self.grid
        tr_manager = self.tr_manager
        vm_w = tr_manager.get_width(vm_layer, 'sig')
        xm_w = tr_manager.get_width(xm_layer, 'sig')
        xm_w_hs = tr_manager.get_width(xm_layer, 'sig_hs')
        # VDD, por_buf, clkn, clkp, data, data_async, porb_buf, data_en, clk_in, por_in
        idx_list = tr_manager.place_wires(xm_layer, ['sup', 'sig', 'sig_hs', 'sig_hs', 'sig_hs',
                                                     'sig_hs', 'sig', 'sig', 'sig', 'sig'],
                                          align_track=vdd_core_list[0].track_id.base_index)[1]
        # POR
        por_core, porb_core = pin_dict['por_in_buf']
        por_list = pin_dict['por_core']
        porb_list = pin_dict['porb_core']
        por_list.append(por_core)
        porb_list.append(porb_core)
        por_core, porb_core = self.connect_differential_tracks(por_list, porb_list, xm_layer,
                                                               idx_list[1], idx_list[6],
                                                               width=xm_w)
        # extend POR signals so they are symmetric with respect to center
        self.extend_wires([por_core, porb_core], upper=2 * self.bound_box.xm - por_core.lower)

        # VDDCore data and control signals
        match_wires = [pin_dict['data_out'], pin_dict['data_async'],
                       pin_dict['clk_outp'], pin_dict['clk_outn']]
        results = self.connect_matching_tracks(match_wires, xm_layer,
                                               [idx_list[4], idx_list[5], idx_list[3], idx_list[2]],
                                               width=xm_w_hs, track_lower=0)
        self.add_pin('odat', results[0], mode=PinMode.LOWER)
        self.add_pin('odat_async', results[1], mode=PinMode.LOWER)
        self.add_pin('oclkp', results[2], mode=PinMode.LOWER)
        self.add_pin('oclkn', results[3], mode=PinMode.LOWER)

        in_info_list = [('din_en', 'data_en', idx_list[7]), ('por_in', 'por', idx_list[9]),
                        ('unused', 'unused', -1), ('ck_en', 'clk_en', idx_list[8])]
        for buf_idx, (key, port_name, tidx) in enumerate(in_info_list):
            hm_warr = pin_dict[key][0]
            vm_tidx_ref = pin_dict[key + '_buf'][1].track_id.base_index
            vm_tidx = tr_manager.get_next_track(vm_layer, vm_tidx_ref, 'sig', 'sig',
                                                up=((buf_idx & 1) == 0))
            vm_warr = self.connect_to_tracks(hm_warr, TrackID(vm_layer, vm_tidx, width=vm_w),
                                             min_len_mode=MinLenMode.LOWER)
            if key == 'unused':
                self.connect_to_tracks(vm_warr, bot_vss)
            else:
                self.add_pin(port_name,
                             self.connect_to_tracks(vm_warr, TrackID(xm_layer, tidx, width=xm_w),
                                                    track_lower=0),
                             mode=PinMode.LOWER)

        # connect VDDIO signals
        idx_list = tr_manager.place_wires(xm_layer, ['sig', 'sig', 'sup', 'sig', 'sig'],
                                          align_track=vdd_io_list[0].track_id.base_index,
                                          align_idx=2)[1]
        for name, ename in [('din_en', 'data'), ('ck_en', 'clk')]:
            wp, wn = self.connect_differential_tracks(pin_dict[f'{name}_out'],
                                                      pin_dict[f'{name}_outb'],
                                                      xm_layer, idx_list[1], idx_list[3],
                                                      width=xm_w)
            self.connect_to_track_wires(wp, pin_dict[f'{ename}_en'])
            self.connect_to_track_wires(wn, pin_dict[f'{ename}_enb'])
        rp, rn = self.connect_differential_tracks(pin_dict['por_in_out'], pin_dict['por_in_outb'],
                                                  xm_layer, idx_list[0], idx_list[4], width=xm_w)
        self.connect_differential_wires(pin_dict['por'], pin_dict['porb'], rp, rn)

        idx_list = tr_manager.place_wires(vm_layer, ['sig', 'sig', 'sup'],
                                          align_track=vdd_io_table[vm_layer][0].track_id.base_index,
                                          align_idx=-1)[1]
        rp, rn = self.connect_differential_tracks(rp, rn, vm_layer, idx_list[0], idx_list[1],
                                                  width=tr_manager.get_width(vm_layer, 'sig'))
        self.add_pin('por_vccl', rp)
        self.add_pin('porb_vccl', rn)

        # connect io pad signals
        in_pins = pin_dict['data_in']
        in_pins.append(pin_dict['clk_inp'][0])
        clkn = pin_dict['clk_inn'][0]
        in_tidx = grid.coord_to_track(xm_layer, in_pins[0].middle, mode=RoundMode.GREATER_EQ)
        ck_tidx = grid.coord_to_track(xm_layer, clkn.middle, mode=RoundMode.LESS_EQ)
        io_w = tr_manager.get_width(xm_layer, 'padout')
        in_warr = self.connect_to_tracks(in_pins, TrackID(xm_layer, in_tidx, width=io_w),
                                         min_len_mode=MinLenMode.MIDDLE)
        clk_warr = self.connect_to_tracks(clkn, TrackID(xm_layer, ck_tidx, width=io_w),
                                          track_lower=in_warr.lower, track_upper=in_warr.upper)
        self.add_pin('iopad', in_warr)
        self.add_pin('iclkn', clk_warr)

        # setup schematic parameters
        rm_keys = ['dual_output', 'invert_out']
        data_lv_sch_params = lv_data_master.sch_params.copy(remove=rm_keys)
        ctrl_lv_sch_params = lv_ctrl_master.sch_params.copy(remove=rm_keys)
        por_lv_sch_params = lv_por_master.sch_params.copy(remove=rm_keys)
        self.sch_params = dict(
            data_params=data_master.sch_params,
            clk_params=clk_master.sch_params,
            data_lv_params=data_lv_sch_params,
            ctrl_lv_params=ctrl_lv_sch_params,
            por_lv_params=por_lv_sch_params,
            buf_ctrl_lv_params=buf_ctrl_lv_master.sch_params.copy(remove=['dual_output']),
            buf_por_lv_params=buf_por_lv_master.sch_params.copy(remove=['dual_output']),
            inv_params=inv_master.sch_params,
        )
Пример #24
0
    def draw_layout(self):
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid,
                                                 self.params['pinfo'])
        self.draw_base(pinfo)

        arr_info = self.arr_info
        tr_manager = self.tr_manager

        pupd_params: Param = self.params['pupd_params']
        unit_params: Param = self.params['unit_params']
        ridx_p: int = self.params['ridx_p']
        ridx_n: int = self.params['ridx_n']

        conn_layer = self.conn_layer
        hm_layer = conn_layer + 1
        vm_layer = hm_layer + 1
        xm_layer = vm_layer + 1
        ym_layer = xm_layer + 1

        # create masters
        unit_params = unit_params.copy(
            append=dict(pinfo=pinfo, ridx_p=ridx_p, ridx_n=ridx_n))
        unit_master = self.new_template(OutputDriverCore, params=unit_params)
        vm_tidx = unit_master.get_port('out').get_pins()[0].track_id.base_index
        pupd_params = pupd_params.copy(append=dict(pinfo=pinfo,
                                                   ridx_p=ridx_p,
                                                   ridx_n=ridx_n,
                                                   sig_locs=dict(out=vm_tidx)))
        pupd_master = self.new_template(PullUpDown, params=pupd_params)
        # placement
        # initialize supply data structures
        lay_range = range(conn_layer, xm_layer + 1)
        vdd_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range}
        vss_table: Dict[int, List[WireArray]] = {lay: [] for lay in lay_range}
        sup_info = self.get_supply_column_info(xm_layer)
        sub_sep = self.sub_sep_col
        sub_sep2 = sub_sep // 2

        # instantiate cells and collect pins
        pin_dict = {'din': [], 'out': [], 'out_hm': [], 'en': [], 'enb': []}
        cur_col = 0
        din_type = 'sig_hs'
        tap_list = []
        sup_unit_sep = sub_sep2

        # first column
        tap_list.append((cur_col, False))
        cur_col = self._draw_supply_column(cur_col, sup_info, vdd_table,
                                           vss_table, ridx_p, ridx_n, False)
        # make sure we have room for din wire
        sup_tidx = max(vdd_table[vm_layer][-1].track_id.base_index,
                       vss_table[vm_layer][-1].track_id.base_index)
        din_tidx = tr_manager.get_next_track(vm_layer,
                                             sup_tidx,
                                             'sup',
                                             din_type,
                                             up=True)
        en_tidx = tr_manager.get_next_track(vm_layer,
                                            din_tidx,
                                            din_type,
                                            'sig',
                                            up=True)
        unit_col = arr_info.coord_to_col(self.grid.track_to_coord(
            vm_layer, en_tidx),
                                         round_mode=RoundMode.GREATER_EQ)
        sup_unit_sep = max(sup_unit_sep, unit_col - cur_col)

        # make sure unit element is in pitch on ym_layer
        ncol_core = unit_master.num_cols + sup_info.ncol
        ncol_unit = 2 * sup_unit_sep + ncol_core
        if self.top_layer >= ym_layer:
            ncol_unit = arr_info.round_up_to_block_size(ym_layer,
                                                        ncol_unit,
                                                        even_diff=True,
                                                        half_blk=False)
        sup_unit_sep = (ncol_unit - ncol_core) // 2

        cur_col += sup_unit_sep
        cur_col = self._draw_unit_cells(cur_col, unit_master, pin_dict,
                                        range(4))
        cur_col += sup_unit_sep

        # second column
        tap_list.append((cur_col, False))
        cur_col = self._draw_supply_column(cur_col, sup_info, vdd_table,
                                           vss_table, ridx_p, ridx_n, False)
        cur_col += sup_unit_sep
        new_col = self._draw_unit_cells(cur_col, unit_master, pin_dict,
                                        range(1, 3))

        # pull up/pull down
        pupd_inst = self.add_tile(pupd_master, 0, cur_col)
        self._record_pins(pupd_inst, pin_dict, False)
        cur_col = max(new_col + sup_unit_sep,
                      cur_col + pupd_master.num_cols + sub_sep2)

        # last supply column
        tap_list.append((cur_col, True))
        cur_col = self._draw_supply_column(cur_col, sup_info, vdd_table,
                                           vss_table, ridx_p, ridx_n, True)
        self._tap_columns = ImmutableList(tap_list)
        self.set_mos_size(num_cols=cur_col)

        # routing
        # supplies
        vss = vdd = None
        for lay in range(hm_layer, xm_layer + 1, 2):
            vss = vss_table[lay]
            vdd = vdd_table[lay]
            if lay == hm_layer:
                vss.append(pupd_inst.get_pin('VSS'))
                vdd.append(pupd_inst.get_pin('VDD'))
            vdd = self.connect_wires(vdd)
            vss = self.connect_wires(vss)
            self.add_pin(f'VDD_{lay}', vdd, hide=True)
            self.add_pin(f'VSS_{lay}', vss, hide=True)
        vdd = vdd[0]
        vss = vss[0]
        self.add_pin('VDD', vdd)
        self.add_pin('VSS', vss)
        self.add_pin('VDD_vm',
                     self.connect_wires(vdd_table[vm_layer]),
                     hide=True)
        self.add_pin('VSS_vm', vss_table[vm_layer], hide=True)
        self.add_pin('VDD_conn', vdd_table[conn_layer], hide=True)
        self.add_pin('VSS_conn', vss_table[conn_layer], hide=True)

        # signals
        self.connect_wires(pin_dict['out_hm'])
        din = self.connect_wires(pin_dict['din'])
        out_list = pin_dict['out']
        out_upper = max((warr.upper for warr in out_list))
        out = self.connect_wires(out_list, upper=out_upper)[0]
        en_list = pin_dict['en']
        enb_list = pin_dict['enb']
        p_en_1 = self.connect_wires(en_list[4:])[0]
        n_enb_1 = self.connect_wires(enb_list[4:])[0]
        din = self.connect_to_tracks(
            din,
            TrackID(vm_layer,
                    din_tidx,
                    width=tr_manager.get_width(vm_layer, din_type)))
        pub = self.connect_to_tracks(pupd_inst.get_pin('puenb'),
                                     p_en_1.track_id,
                                     min_len_mode=MinLenMode.LOWER)
        pd = self.connect_to_tracks(pupd_inst.get_pin('pden'),
                                    n_enb_1.track_id,
                                    min_len_mode=MinLenMode.UPPER)

        self.add_pin('din', din)
        self.add_pin('p_en_drv<0>', en_list[0])
        self.add_pin('n_enb_drv<0>', enb_list[0])
        self.add_pin('tristateb', self.connect_wires(en_list[1:4]))
        self.add_pin('tristate', self.connect_wires(enb_list[1:4]))
        self.add_pin('p_en_drv<1>', p_en_1)
        self.add_pin('n_enb_drv<1>', n_enb_1)
        self.add_pin('weak_puenb', pub)
        self.add_pin('weak_pden', pd)
        self.add_pin('txpadout', out)
        self.sch_params = dict(
            unit_params=unit_master.sch_params,
            pupd_params=pupd_master.sch_params,
        )
Пример #25
0
    def _draw_row(self, unit_master: PhaseInterpUnit, inv_master: InvCore, tile_idx: int,
                  nbits: int, flip_en: bool, draw_sub: bool, prefix: str, vss_tile: int,
                  vdd_tile: int, abut_tristates: bool) -> Dict[str, Union[List[WireArray], WireArray]]:
        vm_layer = self.conn_layer + 2
        vm_sup_w = self.tr_manager.get_width(vm_layer, 'sup')
        vm_sup_l = self.grid.get_next_length(vm_layer, vm_sup_w, 0, even=True)

        if abut_tristates:
            unit_sep = 0
            col_margin = 0
        else:
            col_margin = unit_master.col_margin
            min_sep = self.min_sep_col
            min_sep += (min_sep & 1)
            unit_sep = max(min_sep - 2 * col_margin, 0)
            unit_sep += (unit_sep & 1)

        # gather wires, connect/export enable signals
        pin_list = ['pout', 'nout', 'nin', 'VDD', 'VSS', 'VDD_vm', 'VSS_vm']
        pin_dict = {name: [] for name in pin_list}
        cur_col = 1 if draw_sub else 0
        unit_ncol = unit_master.num_cols
        for idx in range(nbits):
            inst = self.add_tile(unit_master, tile_idx, cur_col)
            if abut_tristates:
                en = inst.get_pin('en')
                enb = inst.get_pin('enb')
                en_tr_idx = self.grid.coord_to_track(vm_layer, en.middle, RoundMode.LESS)
                enb_tr_idx = self.grid.coord_to_track(vm_layer, en.middle, RoundMode.GREATER)
                sup_tr_idx = self.tr_manager.get_next_track(vm_layer, en_tr_idx, 'sig', 'sup',
                                                            up=False)
                if flip_en:
                    en, enb = self.connect_differential_tracks(en, enb, vm_layer, en_tr_idx,
                                                               enb_tr_idx)
                else:
                    en, enb = self.connect_differential_tracks(en, enb, vm_layer, enb_tr_idx,
                                                               en_tr_idx)
                sup_w = self.add_wires(vm_layer, sup_tr_idx, en.middle - vm_sup_l // 2,
                                       en.middle + vm_sup_l // 2, width=vm_sup_w)
                if idx & 1:
                    pin_dict['VDD_vm'].append(sup_w)
                else:
                    pin_dict['VSS_vm'].append(sup_w)
                for pin in pin_list:
                    if pin not in ['VDD_vm', 'VSS_vm']:
                        pin_dict[pin].append(inst.get_pin(pin))
            else:
                for name in pin_list:
                    pin_dict[name].append(inst.get_pin(name))
                enl = inst.get_pin('enl')
                enr = inst.get_pin('enr')
                en = inst.get_pin('en')
                enb = inst.get_pin('enb')
                if flip_en:
                    en, enb = self.connect_differential_wires(en, enb, enr, enl)
                else:
                    en, enb = self.connect_differential_wires(en, enb, enl, enr)

            # NOTE: LSB closest to the output to help with nonlinearity
            bit_idx = nbits - 1 - idx
            self.add_pin(f'{prefix}_en<{bit_idx}>', en)
            self.add_pin(f'{prefix}_enb<{bit_idx}>', enb)
            cur_col += unit_ncol + unit_sep

        # short hm_layer wires
        pout = self.connect_wires(pin_dict['pout'])[0]
        nout = self.connect_wires(pin_dict['nout'])[0]
        in_warr = self.connect_wires(pin_dict['nin'])[0]
        self.add_pin(prefix + '_in', in_warr)

        # connect output inverter
        cur_col += self.min_sep_col
        vm_w = self.tr_manager.get_width(vm_layer, 'sig_hs')
        inst = self.add_tile(inv_master, tile_idx, cur_col)
        buf_out = inst.get_pin('out')
        vm_tidx = self.tr_manager.get_next_track(vm_layer, buf_out.track_id.base_index,
                                                 'sig', 'sig_hs', up=False)
        inv_in = self.connect_to_tracks([pout, nout, inst.get_pin('in')],
                                        TrackID(vm_layer, vm_tidx, width=vm_w))
        pin_dict['out'] = [inv_in]
        pin_dict['VDD'].extend(inst.port_pins_iter('VDD'))
        pin_dict['VSS'].extend(inst.port_pins_iter('VSS'))

        # connect supplies
        vss_tid = self.get_track_id(0, MOSWireType.DS, 'sup', tile_idx=vss_tile)
        vdd_tid = self.get_track_id(0, MOSWireType.DS, 'sup', tile_idx=vdd_tile)
        vss = self.connect_to_tracks(pin_dict['VSS'], vss_tid)
        vdd = self.connect_to_tracks(pin_dict['VDD'], vdd_tid)
        vss_vm_list = []
        vdd_vm_list = []
        for vss_vm, vdd_vm in zip(pin_dict['VSS_vm'], pin_dict['VDD_vm']):
            vss_vm, vdd_vm = self.connect_differential_wires(vss, vdd, vss_vm, vdd_vm)
            vss_vm_list.append(vss_vm)
            vdd_vm_list.append(vdd_vm)
        return {'mid': pin_dict['out'], 'out': buf_out, 'VSS': vss_vm_list, 'VDD': vdd_vm_list,
                'VSS_hm': vss, 'VDD_hm': [vdd]}
Пример #26
0
    def draw_layout(self):
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid,
                                                 self.params['pinfo'])
        self.draw_base(pinfo)

        seg_p: int = self.params['seg_p']
        seg_n: int = self.params['seg_n']
        w_p: int = self.params['w_p']
        w_n: int = self.params['w_n']
        stack: int = self.params['stack']
        ridx_p: int = self.params['ridx_p']
        ridx_n: int = self.params['ridx_n']
        sig_locs: Mapping[str, Union[float, HalfInt]] = self.params['sig_locs']

        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1

        #if (seg_p - seg_n) % 2 != 0:
        #    raise ValueError('seg_p - seg_n should be even')
        if w_p == 0:
            w_p = self.place_info.get_row_place_info(ridx_p).row_info.width
        if w_n == 0:
            w_n = self.place_info.get_row_place_info(ridx_n).row_info.width

        pin_tidx = sig_locs.get(
            'pin',
            self.get_track_index(ridx_p,
                                 MOSWireType.G,
                                 wire_name='sig',
                                 wire_idx=-1))
        nin_tidx = sig_locs.get(
            'nin',
            self.get_track_index(ridx_n,
                                 MOSWireType.G,
                                 wire_name='sig',
                                 wire_idx=0))
        nout_tid = self.get_track_id(ridx_n,
                                     MOSWireType.DS_GATE,
                                     wire_name='padout')
        pout_tid = self.get_track_id(ridx_p,
                                     MOSWireType.DS_GATE,
                                     wire_name='padout')

        fg_p = seg_p * stack
        fg_n = seg_n * stack
        num_col = max(fg_p, fg_n)
        p_col = (num_col - fg_p) // 2
        n_col = (num_col - fg_n) // 2
        pmos = self.add_mos(ridx_p, p_col, seg_p, w=w_p, stack=stack)
        nmos = self.add_mos(ridx_n, n_col, seg_n, w=w_n, stack=stack)
        self.set_mos_size(num_cols=num_col)

        # connect supplies
        vdd_tid = self.get_track_id(ridx_p,
                                    MOSWireType.DS_GATE,
                                    wire_name='sup')
        vss_tid = self.get_track_id(ridx_n,
                                    MOSWireType.DS_GATE,
                                    wire_name='sup')
        vdd = self.connect_to_tracks(pmos.s, vdd_tid)
        vss = self.connect_to_tracks(nmos.s, vss_tid)
        self.add_pin('VDD', vdd)
        self.add_pin('VSS', vss)

        # connect inputs
        hm_w = self.tr_manager.get_width(hm_layer, 'sig')
        pden = self.connect_to_tracks(nmos.g,
                                      TrackID(hm_layer, nin_tidx, width=hm_w),
                                      min_len_mode=MinLenMode.MIDDLE)
        puenb = self.connect_to_tracks(pmos.g,
                                       TrackID(hm_layer, pin_tidx, width=hm_w),
                                       min_len_mode=MinLenMode.MIDDLE)
        self.add_pin('pden', pden)
        self.add_pin('puenb', puenb)

        # connect output
        vm_w_pad = self.tr_manager.get_width(vm_layer, 'padout')
        nout = self.connect_to_tracks(nmos.d,
                                      nout_tid,
                                      min_len_mode=MinLenMode.MIDDLE)
        pout = self.connect_to_tracks(pmos.d,
                                      pout_tid,
                                      min_len_mode=MinLenMode.MIDDLE)
        vm_tidx = sig_locs.get(
            'out',
            self.grid.coord_to_track(vm_layer,
                                     nout.middle,
                                     mode=RoundMode.NEAREST))
        out = self.connect_to_tracks([nout, pout],
                                     TrackID(vm_layer, vm_tidx,
                                             width=vm_w_pad))
        self.add_pin('out', out)
        self.add_pin('nout', nout, hide=True)
        self.add_pin('pout', pout, hide=True)

        # compute schematic parameters.
        th_p = self.place_info.get_row_place_info(ridx_p).row_info.threshold
        th_n = self.place_info.get_row_place_info(ridx_n).row_info.threshold
        self.sch_params = dict(
            seg_p=seg_p,
            seg_n=seg_n,
            lch=self.place_info.lch,
            w_p=w_p,
            w_n=w_n,
            th_p=th_p,
            th_n=th_n,
            stack_p=stack,
            stack_n=stack,
        )
Пример #27
0
    def draw_layout(self):
        # type: () -> None
        route_layer = self.params['layer']
        bias_config = self.params['bias_config']
        nwire_real = self.params['nwire']
        width = self.params['width']
        space_sig = self.params['space_sig']
        top = self.params['top']
        is_end = self.params['is_end']

        grid = self.grid
        res = grid.resolution

        bot_layer = route_layer - 1
        top_layer = route_layer + 1
        route_dir = grid.get_direction(route_layer)
        is_horiz = (route_dir == 'x')

        # compute size
        tot_w, tot_h = self.get_block_size(grid,
                                           route_layer,
                                           bias_config,
                                           nwire_real,
                                           width=width,
                                           space_sig=space_sig)

        dim_par = tot_w if is_horiz else tot_h
        bbox = BBox(0, 0, tot_w, tot_h, res, unit_mode=True)
        self.prim_top_layer = top_layer
        self.prim_bound_box = bbox
        self.array_box = bbox
        self.add_cell_boundary(bbox)

        # compute wire location
        self._route_tids = locs = self.get_route_tids(self.grid,
                                                      route_layer,
                                                      0,
                                                      bias_config,
                                                      nwire_real,
                                                      width=width,
                                                      space_sig=space_sig)

        pitch = locs[nwire_real + 1][0] - locs[0][0]
        tr_upper = bbox.width_unit if is_horiz else bbox.height_unit
        sh_warr = self.add_wires(route_layer,
                                 locs[0][0],
                                 0,
                                 tr_upper,
                                 width=1,
                                 num=2,
                                 pitch=pitch,
                                 unit_mode=True)

        sup_layer = top_layer if top else bot_layer
        pitch2 = grid.get_track_pitch(sup_layer, unit_mode=True) // 2
        sup_np2, sup_w, sup_spe2, sup_p2 = bias_config[sup_layer]
        sup_unit = sup_np2 * pitch2
        num = dim_par // sup_unit
        if num == 1:
            num = 1 if sup_p2 == 0 else 1 + (sup_np2 - 2 * sup_spe2) // sup_p2
            sup_tid = TrackID(sup_layer, (sup_spe2 - 1) / 2,
                              width=sup_w,
                              num=num,
                              pitch=sup_p2 / 2)
        else:
            if sup_p2 == 0:
                sup_tid = TrackID(sup_layer, (sup_spe2 - 1) / 2,
                                  width=sup_w,
                                  num=num,
                                  pitch=sup_np2 / 2)
            else:
                # TODO: come back to fix this
                raise ValueError('umm...see Eric')

        if is_end:
            sup_n = sup_tid.num
            if sup_n > 1:
                sup_pitch = sup_tid.pitch
                new_tid = TrackID(sup_layer,
                                  sup_tid.base_index,
                                  width=sup_w,
                                  num=sup_n - 1,
                                  pitch=sup_pitch)
                warr = self.connect_to_tracks(sh_warr, new_tid)
                self.add_pin('sup', warr, show=False)
                sup_tid = TrackID(sup_layer,
                                  sup_tid.base_index + (sup_n - 1) * sup_pitch,
                                  width=sup_w)
            shl = grid.get_wire_bounds(route_layer,
                                       locs[0][0],
                                       width=1,
                                       unit_mode=True)[0]
            shr = grid.get_wire_bounds(route_layer,
                                       locs[nwire_real + 1][0],
                                       width=1,
                                       unit_mode=True)[1]
            sh_singles = sh_warr.to_warr_list()
            if top:
                test_warr = self.connect_to_tracks(sh_singles[0], sup_tid)
                vext = shl - test_warr.lower_unit
            else:
                test_warr = self.connect_to_tracks(sh_singles[1], sup_tid)
                vext = test_warr.upper_unit - shr
            warr = self.add_wires(sup_layer,
                                  sup_tid.base_index,
                                  shl - vext,
                                  shr + vext,
                                  width=sup_w,
                                  unit_mode=True)
        else:
            warr = self.connect_to_tracks(sh_warr, sup_tid)

        self.add_pin('shield', sh_warr, show=False)
        self.add_pin('sup', warr, show=False)
        sup_box = warr.get_bbox_array(self.grid).get_overall_bbox()
        self._sup_intv = sup_box.get_interval(route_dir, unit_mode=True)
Пример #28
0
    def draw_layout(self):
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid,
                                                 self.params['pinfo'])
        self.draw_base(pinfo, flip_tile=True)

        mux_params: Param = self.params['mux_params']
        flop_params: Param = self.params['flop_params']
        inv_params: Param = self.params['inv_params']
        vm_pitch: HalfInt = HalfInt.convert(self.params['vm_pitch'])

        vm_pitch_htr = vm_pitch.dbl_value
        # create masters
        mux_params = mux_params.copy(
            append=dict(pinfo=pinfo, vertical_sel=False))
        flop_params = flop_params.copy(append=dict(
            pinfo=pinfo, has_rstlb=True, swap_outbuf=True, out_pitch=vm_pitch))
        mux_master: Mux2to1Matched = self.new_template(Mux2to1Matched,
                                                       params=mux_params)
        flop_master: FlopStrongArm = self.new_template(FlopStrongArm,
                                                       params=flop_params)

        inv_in_tidx = mux_master.get_port(
            'in<0>').get_pins()[0].track_id.base_index
        inv_params = inv_params.copy(
            append=dict(pinfo=pinfo, sig_locs={'in': inv_in_tidx}))
        inv_master: InvCore = self.new_template(InvCore, params=inv_params)

        # placement
        min_sep = self.min_sep_col
        min_sep += (min_sep & 1)
        buf_ncol = inv_master.num_cols
        mux_ncol = mux_master.num_cols
        flop_ncol = flop_master.num_cols
        ncol_tot = max(flop_ncol, mux_ncol + 2 * min_sep + 2 * buf_ncol)
        mux_off = (ncol_tot - mux_ncol) // 2
        flop_off = (ncol_tot - flop_ncol) // 2

        mux_in = self.add_tile(mux_master, 0, mux_off)
        flop = self.add_tile(flop_master, 1, flop_off)
        mux_out = self.add_tile(mux_master, 3, mux_off)
        invl = self.add_tile(inv_master, 3, 0)
        invr = self.add_tile(inv_master, 3, ncol_tot, flip_lr=True)
        self.set_mos_size()
        yh = self.bound_box.yh
        xm = self.bound_box.xm

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

        # supplies
        vdd_list = []
        vss_list = []
        for inst in [mux_in, flop, mux_out, invl, invr]:
            vdd_list.extend(inst.port_pins_iter('VDD'))
            vss_list.extend(inst.port_pins_iter('VSS'))
        self.add_pin('VDD', self.connect_wires(vdd_list), connect=True)
        self.add_pin('VSS', self.connect_wires(vss_list), connect=True)

        # input mux
        flop_clk = mux_in.get_pin('out')
        self.connect_to_track_wires(flop_clk, flop.get_pin('clk'))
        in0 = mux_in.get_pin('in<0>')
        in1 = mux_in.get_pin('in<1>')
        clk_vm_tidx = flop_clk.track_id.base_index
        in_vm_test = tr_manager.get_next_track(vm_layer,
                                               clk_vm_tidx,
                                               'sig',
                                               'clk',
                                               up=True)
        in_dhtr = (-(in_vm_test - clk_vm_tidx).dbl_value //
                   vm_pitch_htr) * vm_pitch_htr
        in_delta = HalfInt(in_dhtr)
        in0 = self.connect_to_tracks(in0,
                                     TrackID(vm_layer,
                                             clk_vm_tidx + in_delta,
                                             width=vm_w_ck),
                                     min_len_mode=MinLenMode.LOWER)
        in1 = self.connect_to_tracks(in1,
                                     TrackID(vm_layer,
                                             clk_vm_tidx - in_delta,
                                             width=vm_w_ck),
                                     min_len_mode=MinLenMode.LOWER)
        self.add_pin('launch', in0)
        self.add_pin('measure', in1)

        # divider flop
        clkp = flop.get_pin('outp')
        clkn = flop.get_pin('outn')
        self.connect_differential_wires(mux_in.get_pin('nsel'),
                                        mux_in.get_pin('nselb'), clkp, clkn)
        self.connect_to_track_wires(clkp, mux_in.get_pin('psel'))
        self.connect_to_track_wires(clkn, mux_in.get_pin('pselb'))
        self.connect_to_track_wires(flop.get_pin('inn'), clkp)
        self.connect_to_track_wires(flop.get_pin('inp'), clkn)
        self.connect_to_tracks(mux_out.get_pin('in<0>'),
                               clkp.track_id,
                               track_upper=yh,
                               track_lower=clkp.lower)
        self.reexport(flop.get_port('rstlb'))
        self.reexport(flop.get_port('rstlb_vm_l'))
        self.reexport(flop.get_port('rsthb'))

        # output mux
        clkn_tid = clkn.track_id
        vm_sp_le = grid.get_line_end_space(vm_layer, clkn_tid.width)
        clk_dcd = self.connect_to_tracks(mux_out.get_pin('in<1>'),
                                         clkn_tid,
                                         track_lower=clkn.upper + vm_sp_le,
                                         track_upper=yh)
        clk_out = self.extend_wires(mux_out.get_pin('out'), upper=yh)
        self.add_pin('clk_dcd', clk_dcd)
        self.add_pin('clk_out', clk_out)

        # output mux select signals
        out_sel = invl.get_pin('out')
        out_selb = invr.get_pin('out')
        dcc_byp_delta = tr_manager.get_next_track(
            vm_layer, out_selb.track_id.base_index, 'sig', 'sig',
            up=True) - clk_vm_tidx
        dcc_byp_dhtr = -(-dcc_byp_delta.dbl_value //
                         vm_pitch_htr) * vm_pitch_htr
        dcc_byp_delta = HalfInt(dcc_byp_dhtr)
        dcc_byp_tidx = clk_vm_tidx + dcc_byp_delta
        out_selb_vm_tidx = clk_vm_tidx - dcc_byp_delta

        self.connect_to_track_wires(mux_out.get_pin('psel'), out_sel)
        self.connect_to_track_wires(mux_out.get_pin('pselb'), out_selb)
        nsel, nselb = self.connect_differential_wires(out_sel, out_selb,
                                                      mux_out.get_pin('nsel'),
                                                      mux_out.get_pin('nselb'))
        sel_hm_list = []
        selb_vm = self.connect_to_tracks([nselb, invl.get_pin('in')],
                                         TrackID(vm_layer,
                                                 out_selb_vm_tidx,
                                                 width=vm_w),
                                         track_upper=yh,
                                         ret_wire_list=sel_hm_list)
        # get differential matching
        xl = min((wire.lower for wire in sel_hm_list))
        xh = 2 * xm - xl
        self.extend_wires([nsel, nselb], lower=xl, upper=xh)

        dcc_byp = self.connect_to_tracks(invr.get_pin('in'),
                                         TrackID(vm_layer,
                                                 dcc_byp_tidx,
                                                 width=vm_w),
                                         track_lower=selb_vm.lower,
                                         track_upper=yh)
        self.add_pin('dcc_byp', dcc_byp)

        self.sch_params = dict(
            mux_params=mux_master.sch_params,
            flop_params=flop_master.sch_params,
            inv_params=inv_master.sch_params,
        )
Пример #29
0
    def connect_bias_shields(
            cls,  # type: BiasShield
            template,  # type: TemplateBase
            layer,  # type: int
            bias_config,  # type: Dict[int, Tuple[int, ...]]
            warr_list2,  # type: List[Union[WireArray, Iterable[WireArray]]]
            offset,  # type: int
            width=1,  # type: int
            space_sig=0,  # type: int
            tr_lower=None,  # type: Optional[int]
            tr_upper=None,  # type: Optional[int]
            lu_end_mode=0,  # type: int
            sup_warrs=None,  # type: Optional[Union[WireArray, List[WireArray]]]
            add_end=True,  # type: bool
            extend_tracks=True,  # type: bool
    ):
        # type: (...) -> BiasInfo
        grid = template.grid

        nwire = len(warr_list2)

        blk_w, blk_h = cls.get_block_size(grid,
                                          layer,
                                          bias_config,
                                          nwire,
                                          width=width,
                                          space_sig=space_sig)
        route_tids = cls.get_route_tids(grid,
                                        layer,
                                        offset,
                                        bias_config,
                                        nwire,
                                        width=width,
                                        space_sig=space_sig)
        tr_dir = grid.get_direction(layer)
        is_horiz = tr_dir == 'x'
        qdim = blk_w if is_horiz else blk_h
        if lu_end_mode == 0:
            min_len_mode = 0
        elif lu_end_mode & 2 != 0:
            min_len_mode = 1
        else:
            min_len_mode = -1
        tr_warr_list = []

        if tr_lower is not None:
            tr_offset = tr_lower % qdim
        elif tr_upper is not None:
            tr_offset = tr_upper % qdim
        else:
            tr_offset = 0

        for warr_list, (tidx,
                        tr_width) in zip(warr_list2,
                                         islice(route_tids, 1, nwire + 1)):
            if isinstance(warr_list, WireArray):
                warr_list = [warr_list]

            cur_tid = TrackID(layer, tidx, width=width)
            tr_warr = template.connect_to_tracks(warr_list,
                                                 cur_tid,
                                                 min_len_mode=min_len_mode)
            tr_warr_list.append(tr_warr)
            if tr_warr is not None:
                if tr_lower is None:
                    tr_lower = tr_warr.lower_unit
                else:
                    tr_lower = min(tr_lower, tr_warr.lower_unit)
                if tr_upper is None:
                    tr_upper = tr_warr.upper_unit
                else:
                    tr_upper = max(tr_upper, tr_warr.upper_unit)

        if tr_lower is None or tr_upper is None:
            raise ValueError('Cannot determine bias shield location.')

        # round lower/upper to nearest coordinates, then draw shields.
        nstart = (tr_lower - tr_offset) // qdim
        nstop = -(-(tr_upper - tr_offset) // qdim)
        tr_lower = nstart * qdim + tr_offset
        tr_upper = nstop * qdim + tr_offset

        tmp = cls.draw_bias_shields(template,
                                    layer,
                                    bias_config,
                                    nwire,
                                    offset,
                                    tr_lower,
                                    tr_upper,
                                    width=width,
                                    space_sig=space_sig,
                                    sup_warrs=sup_warrs)
        sup_warrs, shields = tmp

        # get bias information, extend tracks, and draw ends
        if is_horiz:
            p0 = (tr_lower, offset)
            p1 = (tr_upper, offset + blk_h)
        else:
            p0 = (offset, tr_lower)
            p1 = (offset + blk_w, tr_upper)
        if lu_end_mode == 0:
            if extend_tracks:
                tr_warr_list = template.extend_wires(tr_warr_list,
                                                     lower=tr_lower,
                                                     upper=tr_upper,
                                                     unit_mode=True)
        else:
            if lu_end_mode & 2 != 0:
                if extend_tracks:
                    tr_warr_list = template.extend_wires(tr_warr_list,
                                                         upper=tr_upper,
                                                         unit_mode=True)
                eorient = 'MY' if is_horiz else 'MX'
                loc = p0
            else:
                if extend_tracks:
                    tr_warr_list = template.extend_wires(tr_warr_list,
                                                         lower=tr_lower,
                                                         unit_mode=True)
                eorient = 'R0'
                loc = (tr_upper, offset) if is_horiz else (offset, tr_upper)
            if add_end:
                params = dict(
                    layer=layer,
                    nwire=nwire,
                    bias_config=bias_config,
                    width=width,
                    space_sig=space_sig,
                )
                end_master = template.new_template(params=params,
                                                   temp_cls=BiasShieldEnd)
                inst = template.add_instance(end_master,
                                             loc=loc,
                                             orient=eorient,
                                             unit_mode=True)
                sup_warrs.extend(inst.get_all_port_pins('sup',
                                                        layer=layer + 1))

        return BiasInfo(tracks=tr_warr_list,
                        supplies=sup_warrs,
                        p0=p0,
                        p1=p1,
                        shields=shields)
Пример #30
0
    def draw_layout(self):
        pinfo = MOSBasePlaceInfo.make_place_info(self.grid,
                                                 self.params['pinfo'])
        self.draw_base(pinfo)

        pi_params: Param = self.params['pi_params']
        dc_params: Param = self.params['dc_params']
        inv_params: Param = self.params['inv_params']
        nand_params: Param = self.params['nand_params']
        ncores: int = self.params['num_core']
        nbits: int = self.params['nbits']
        split_nand: bool = self.params['split_nand']
        split_inv: bool = self.params['split_inv']
        pi_tile: int = self.params['pi_tile']
        dc_tile: int = self.params['dc_tile']
        inv_tile_l = dc_tile + 1
        inv_tile_h = dc_tile + 3

        hm_layer = self.conn_layer + 1
        vm_layer = hm_layer + 1
        xm_layer = vm_layer + 1

        grid = self.grid
        tr_manager = self.tr_manager

        # Recompute sizes for the inverter and nand
        inv_seg: int = inv_params['seg']
        nand_seg: int = nand_params['seg']
        split_inv = split_inv and (inv_seg > 1)
        split_nand = split_nand and (nand_seg > 1)
        if split_inv:
            inv_seg_2 = inv_seg // 2
            inv_seg_1 = inv_seg - inv_seg_2
        else:
            inv_seg_1 = inv_seg
            inv_seg_2 = None
        if split_nand:
            nand_seg_2 = nand_seg // 2
            nand_seg_1 = nand_seg - nand_seg_2
        else:
            nand_seg_1 = nand_seg
            nand_seg_2 = None

        # create masters
        low_pinfo = self.get_tile_pinfo(inv_tile_l)
        high_pinfo = self.get_tile_pinfo(inv_tile_h)
        pi_params = pi_params.copy(
            append=dict(pinfo=pinfo, nbits=nbits + 1, flip_b_en=True))
        dc_params = dc_params.copy(append=dict(pinfo=pinfo,
                                               substrate_row=True,
                                               vertical_out=True,
                                               draw_substrate_row=False,
                                               tile0=3,
                                               tile1=1,
                                               flip_vm=True))
        pi_master: PhaseInterpolator = self.new_template(PhaseInterpolator,
                                                         params=pi_params)
        dc_master: DelayCellCore = self.new_template(DelayCellCore,
                                                     params=dc_params)
        dc0_params = dc_params.copy(append=dict(feedback=True))
        dc0_master: DelayCellCore = self.new_template(DelayCellCore,
                                                      params=dc0_params)

        # Place all the cells
        ntr, vert_trs = tr_manager.place_wires(vm_layer, ['sig', 'sig', 'sup'])
        ncol = self.arr_info.get_column_span(vm_layer, ntr)
        pi = self.add_tile(pi_master, pi_tile, ncol)
        dc_arr = [self.add_tile(dc0_master, dc_tile, 0)]
        sep = max(self.min_sep_col, self.get_hm_sp_le_sep_col())
        curr_col = dc_master.num_cols + sep
        for _ in range(ncores - 1):
            dc_arr.append(self.add_tile(dc_master, dc_tile, curr_col))
            curr_col += dc_master.num_cols + sep

        nand_params_l = nand_params.copy(append=dict(pinfo=low_pinfo,
                                                     vertical_sup=True,
                                                     vertical_out=False,
                                                     seg=nand_seg_1))
        nand_master_l: NAND2Core = self.new_template(NAND2Core,
                                                     params=nand_params_l)
        nand_l = self.add_tile(nand_master_l, inv_tile_l, curr_col)
        if split_nand:
            nand_params_h = nand_params.copy(append=dict(pinfo=high_pinfo,
                                                         vertical_sup=True,
                                                         vertical_out=False,
                                                         seg=nand_seg_2))
            nand_master_h: NAND2Core = self.new_template(NAND2Core,
                                                         params=nand_params_h)
            inv_in_tid_h = nand_master_h.get_track_index(1,
                                                         MOSWireType.G,
                                                         wire_name='sig',
                                                         wire_idx=0)
            nand_h = self.add_tile(nand_master_h, inv_tile_h, curr_col)
            nand_sch_params = [
                nand_master_l.sch_params, nand_master_h.sch_params
            ]
        else:
            inv_in_tid_h = None
            nand_h = None
            nand_sch_params = [nand_master_l.sch_params]
        inv_col = curr_col + nand_master_l.num_cols + sep
        inv_in_tid = nand_master_l.get_track_index(1,
                                                   MOSWireType.G,
                                                   wire_name='sig',
                                                   wire_idx=0)
        inv_params_l = inv_params.copy(append=dict(pinfo=low_pinfo,
                                                   vertical_sup=True,
                                                   seg=inv_seg_1,
                                                   vertical_out=False,
                                                   sig_locs=dict(
                                                       nin=inv_in_tid)))
        inv_master_l: InvCore = self.new_template(InvCore, params=inv_params_l)
        inv_l = self.add_tile(inv_master_l, inv_tile_l, inv_col)
        if split_inv:
            if inv_in_tid_h:
                inv_params_h = inv_params.copy(
                    append=dict(pinfo=high_pinfo,
                                vertical_sup=True,
                                seg=inv_seg_2,
                                vertical_out=False,
                                sig_locs=dict(nin=inv_in_tid_h)))
            else:
                inv_params_h = inv_params.copy(append=dict(pinfo=high_pinfo,
                                                           vertical_sup=True,
                                                           seg=inv_seg_2,
                                                           vertical_out=False))
            inv_master_h: InvCore = self.new_template(InvCore,
                                                      params=inv_params_h)
            inv_h = self.add_tile(inv_master_h, inv_tile_h, inv_col)
            inv_sch_params = [inv_master_l.sch_params, inv_master_h.sch_params]
        else:
            inv_h = None
            inv_sch_params = [inv_master_l.sch_params]

        # substrate taps
        vss_hm = [
            pi.get_pin('VSS0'),
            pi.get_pin('VSS1'),
            self.get_track_id(0, MOSWireType.DS, 'sup', tile_idx=8)
        ]
        vdd_hm = [
            pi.get_pin('VDD_hm'),
            self.get_track_id(0, MOSWireType.DS, 'sup', tile_idx=6)
        ]
        ncol_tot = self.num_cols
        sub = self.add_substrate_contact(0, 0, tile_idx=0, seg=ncol_tot)
        self.connect_to_track_wires(sub, vss_hm[0])
        sub = self.add_substrate_contact(0, 0, tile_idx=2, seg=ncol_tot)
        self.connect_to_track_wires(sub, vdd_hm[0])
        sub = self.add_substrate_contact(0, 0, tile_idx=4, seg=ncol_tot)
        self.connect_to_track_wires(sub, vss_hm[1])
        sub = self.add_substrate_contact(0, 0, tile_idx=6, seg=ncol_tot)
        sub_vdd1 = self.connect_to_tracks(sub, vdd_hm[1])
        vdd_hm[1] = sub_vdd1
        sub = self.add_substrate_contact(0, 0, tile_idx=8, seg=ncol_tot)
        sub_vss2 = self.connect_to_tracks(sub, vss_hm[2])
        vss_hm[2] = sub_vss2

        self.set_mos_size()
        xh = self.bound_box.xh

        # routing
        xm_w = tr_manager.get_width(xm_layer, 'sig')
        xm_w_sup = tr_manager.get_width(xm_layer, 'sup')
        xm_w_hs = tr_manager.get_width(xm_layer, 'sig_hs')
        vm_w = tr_manager.get_width(vm_layer, 'sig')
        vm_w_sup = tr_manager.get_width(vm_layer, 'sup')
        vm_sep_sup = tr_manager.get_sep(vm_layer, ('sup', 'sup'))

        xm_vss_tids, xm_vdd_tids = [], []
        for tid_arr, sup_hm_arr in [(xm_vss_tids, vss_hm),
                                    (xm_vdd_tids, vdd_hm)]:
            for sup_w in sup_hm_arr:
                y = grid.track_to_coord(hm_layer, sup_w.track_id.base_index)
                tid_arr.append(
                    TrackID(xm_layer,
                            grid.coord_to_track(xm_layer,
                                                y,
                                                mode=RoundMode.NEAREST),
                            width=xm_w_sup))
        tr_list = ['sup'] + ['sig'] * (nbits + 1)
        pidx_list_l = tr_manager.place_wires(
            xm_layer,
            tr_list,
            align_track=xm_vss_tids[0].base_index,
            align_idx=0)[1]
        pidx_list_h = tr_manager.place_wires(
            xm_layer,
            tr_list,
            align_track=xm_vss_tids[1].base_index,
            align_idx=0)[1]
        tr_list.reverse()
        nidx_list_l = tr_manager.place_wires(
            xm_layer,
            tr_list,
            align_track=xm_vss_tids[1].base_index,
            align_idx=-1)[1]
        nidx_list_h = tr_manager.place_wires(
            xm_layer,
            tr_list,
            align_track=xm_vss_tids[2].base_index,
            align_idx=-1)[1]
        io_idx_list = tr_manager.place_wires(
            xm_layer, ['sig_hs', 'sup', 'sig_hs'],
            align_track=xm_vdd_tids[0].base_index,
            align_idx=1)[1]
        int_idx_list = tr_manager.place_wires(
            xm_layer, ['sig_hs', 'sup', 'sig_hs'],
            align_track=xm_vdd_tids[1].base_index,
            align_idx=1)[1]

        # PI signals
        vss_list = pi.get_all_port_pins('VSS')
        vdd_list = pi.get_all_port_pins('VDD')
        suf = f'<{nbits}>'
        en_vss = self.connect_to_track_wires(vss_hm[0:2],
                                             pi.get_pin('a_enb' + suf))
        en_l = en_vss.lower
        en_u = en_vss.upper
        self.connect_to_tracks(vdd_hm[0],
                               pi.get_pin('a_en' + suf).track_id,
                               track_lower=en_l,
                               track_upper=en_u)
        en_xm_upper = None
        for idx in range(nbits):
            suf = f'<{idx}>'
            enb = self.connect_wires(
                [pi.get_pin('a_en' + suf),
                 pi.get_pin('b_enb' + suf)],
                lower=en_l,
                upper=en_u)
            en = self.connect_wires(
                [pi.get_pin('a_enb' + suf),
                 pi.get_pin('b_en' + suf)],
                lower=en_l,
                upper=en_u)
            ptid = TrackID(xm_layer, pidx_list_l[1 + idx], width=xm_w)
            ntid = TrackID(xm_layer, nidx_list_l[-idx - 2], width=xm_w)
            if idx == 0:
                en = self.connect_to_tracks(en, ptid, track_lower=0)
                en_xm_upper = en.upper
            else:
                en = self.connect_to_tracks(en,
                                            ptid,
                                            track_lower=0,
                                            track_upper=en_xm_upper)
            enb = self.connect_to_tracks(enb,
                                         ntid,
                                         track_lower=0,
                                         track_upper=en_xm_upper)
            self.add_pin('sp' + suf, en)
            self.add_pin('sn' + suf, enb)

        intout = self.connect_to_tracks(pi.get_pin('out'),
                                        TrackID(xm_layer,
                                                io_idx_list[2],
                                                width=xm_w_hs),
                                        track_lower=0)
        self.add_pin('intout', intout)
        vdd0 = self.connect_to_tracks(vdd_list,
                                      xm_vdd_tids[0],
                                      track_lower=0,
                                      track_upper=xh)
        vss0 = self.connect_to_tracks(vss_list,
                                      xm_vss_tids[0],
                                      track_lower=0,
                                      track_upper=xh)
        vss1 = self.connect_to_tracks(vss_list,
                                      xm_vss_tids[1],
                                      track_lower=0,
                                      track_upper=xh)

        # delay cell signals
        vdd_list, vss0_list, vss1_list = [], [], []
        for dc in dc_arr:
            vdd_list += dc.get_all_port_pins('VDD')
            vss0_list += dc.get_all_port_pins('VSS1')
            vss1_list += dc.get_all_port_pins('VSS0')
        vdd_list.extend(nand_l.get_all_port_pins('VDD'))
        vss0_list.extend(nand_l.get_all_port_pins('VSS'))
        if split_nand:
            vdd_list.extend(nand_h.get_all_port_pins('VDD'))
            vss1_list.extend(nand_h.get_all_port_pins('VSS'))
        vss0_list.extend(inv_l.get_all_port_pins('VSS'))
        vdd_list.extend(inv_l.get_all_port_pins('VDD'))
        if split_inv:
            vdd_list.extend(inv_h.get_all_port_pins('VDD'))
            vss1_list.extend(inv_h.get_all_port_pins('VSS'))
        vdd_list.extend([dc.get_pin('bk1_vm') for dc in dc_arr])
        self.connect_to_track_wires(vdd_list, vdd_hm[1])
        self.connect_to_track_wires(vss0_list, vss_hm[1])
        self.connect_to_track_wires(vss1_list, vss_hm[2])
        if ncores > 1:
            for idx in range(ncores - 1, 0, -1):
                cur_cop = dc_arr[idx].get_pin('co_p')
                next_in = dc_arr[idx - 1].get_pin('in_p')
                ptid = TrackID(xm_layer,
                               pidx_list_h[1 + (idx % 2)],
                               width=xm_w)
                self.connect_to_tracks([cur_cop, next_in], ptid)

                cur_ci = dc_arr[idx].get_pin('ci_p')
                next_out = dc_arr[idx - 1].get_pin('out_p')
                ntid = TrackID(xm_layer,
                               nidx_list_h[-2 - (idx % 2)],
                               width=xm_w)
                self.connect_to_tracks([cur_ci, next_out], ntid)

        # NAND to delay cell and PI
        nand_out_vm_tr = self.grid.coord_to_track(
            vm_layer,
            nand_l.get_pin('pout').middle, RoundMode.NEAREST)
        nand_out_pins = [nand_l.get_pin('pout'), nand_l.get_pin('nout')]
        if split_nand:
            nand_out_pins.extend(
                [nand_h.get_pin('pout'),
                 nand_h.get_pin('nout')])
        nand_out_vm_w = self.connect_to_tracks(
            nand_out_pins, TrackID(vm_layer, nand_out_vm_tr, vm_w))
        a_in_buf_xm = self.connect_to_tracks(
            [nand_out_vm_w, dc_arr[-1].get_pin('in_p')],
            TrackID(xm_layer, int_idx_list[0], xm_w))
        a_in_buf_vm = self.connect_to_tracks(
            [a_in_buf_xm, pi.get_pin('a_in')],
            TrackID(vm_layer, vert_trs[0], vm_w))

        # Delay Cell to PI
        b_in_xm = self.connect_to_tracks(
            dc_arr[-1].get_pin("out_p"),
            TrackID(xm_layer, int_idx_list[-1], xm_w))
        b_in_vm = self.connect_to_tracks([b_in_xm, pi.get_pin("b_in")],
                                         TrackID(vm_layer, vert_trs[1], vm_w))

        nand_in_hm = [nand_l.get_pin("nin<0>"), vdd_hm[1]]
        if split_nand:
            nand_in_hm.append(nand_h.get_pin("nin<0>"))
        nand_in_vm_tr = tr_manager.get_next_track_obj(nand_out_vm_w.track_id,
                                                      'sig', 'sig')
        self.connect_to_tracks(nand_in_hm, nand_in_vm_tr)

        # Inv out to nand in
        inv_out_tr = grid.coord_to_track(vm_layer,
                                         inv_l.get_pin("pout").middle,
                                         RoundMode.NEAREST)
        inv_out_hm_w = [
            inv_l.get_pin("pout"),
            inv_l.get_pin("nout"),
            nand_l.get_pin("nin<1>")
        ]
        inv_in_tr = tr_manager.get_next_track(vm_layer, inv_out_tr, 'sig',
                                              'sig')
        inv_in_hm_w = [inv_l.get_pin('in')]
        if split_inv:
            inv_out_hm_w.extend([inv_h.get_pin("nout"), inv_h.get_pin("pout")])
            inv_in_hm_w.append(inv_h.get_pin("in"))
        if split_nand:
            inv_out_hm_w.append(nand_h.get_pin("nin<1>"))
        inv_out_w = self.connect_to_tracks(inv_out_hm_w,
                                           TrackID(vm_layer, inv_out_tr, vm_w))
        a_in = self.connect_to_tracks(inv_in_hm_w,
                                      TrackID(vm_layer, inv_in_tr, vm_w))
        self.add_pin('a_in', a_in)

        # Supply routing over nand, dc, and inv
        vm_wires = [nand_out_vm_w, inv_out_w]
        for dc in dc_arr:
            for port_name in dc.port_names_iter():
                if port_name not in ['VDD', 'VSS0', 'VSS1']:
                    vm_wires.extend(dc.get_all_port_pins(port_name, vm_layer))
        # for idx, wire in enumerate(vm_wires):
        #     self.add_pin(f'vm_wire_{idx}', wire)
        vss_vm_arr = pi.get_all_port_pins('VSS')[0]
        vdd_vm_arr = pi.get_all_port_pins('VDD')[0]
        vss_vm, vdd_vm = [], []
        for wire_arr, target_wire, vm_list in [(vss_vm_arr, vss_hm[2], vss_vm),
                                               (vdd_vm_arr, vdd_hm[1], vdd_vm)
                                               ]:
            for wire in wire_arr.warr_iter():
                tr_idx = wire.track_id.base_index
                min_idx = tr_manager.get_next_track(vm_layer,
                                                    tr_idx,
                                                    'sup',
                                                    'sig',
                                                    up=False)
                max_idx = tr_manager.get_next_track(vm_layer,
                                                    tr_idx,
                                                    'sup',
                                                    'sig',
                                                    up=True)
                will_intersect = False
                for sig_wire in vm_wires:
                    if min_idx < sig_wire.track_id.base_index <= max_idx:
                        will_intersect = True
                if not will_intersect:
                    self.connect_to_tracks(wire, target_wire.track_id)
                    vm_list.append(wire)
        vdd1 = self.connect_to_tracks(vdd_vm,
                                      xm_vdd_tids[1],
                                      track_lower=0,
                                      track_upper=xh)
        vss2 = self.connect_to_tracks(vss_vm,
                                      xm_vss_tids[2],
                                      track_lower=0,
                                      track_upper=xh)
        self.add_pin('VDD', [vdd0, vdd1], connect=True)
        self.add_pin('VSS', [vss0, vss1, vss2], connect=True)

        tidx_list = self.get_available_tracks(vm_layer,
                                              0,
                                              inv_in_tr,
                                              0,
                                              self.bound_box.yh,
                                              width=vm_w_sup,
                                              sep=vm_sep_sup)
        for tidx in tidx_list:
            tid = TrackID(vm_layer, tidx, vm_w_sup)
            for wire in vdd_hm + [vss_hm[1], vdd0, vdd1, vss1]:
                self.connect_to_tracks(wire,
                                       tid,
                                       min_len_mode=MinLenMode.MIDDLE)
            for wire in [vss_hm[0], vss0]:
                self.connect_to_tracks(wire,
                                       tid,
                                       min_len_mode=MinLenMode.UPPER)
            for wire in [vss_hm[2], vss2]:
                self.connect_to_tracks(wire,
                                       tid,
                                       min_len_mode=MinLenMode.LOWER)

        if self.params['export_dc_in']:
            self.add_pin('a_in_buf', a_in_buf_vm)
        if self.params['export_dc_out']:
            self.add_pin('b_in', b_in_vm)

        # Set the schematic parameters
        self.sch_params = dict(
            pi_params=pi_master.sch_params,
            dc_params=dc_master.sch_params,
            inv_params=inv_sch_params,
            nand_params=nand_sch_params,
            num_core=ncores,
            export_dc_out=self.params['export_dc_out'],
            export_dc_in=self.params['export_dc_in'],
        )