def generate_sar_wsamp(laygen,
                       objectname_pfix,
                       workinglib,
                       samp_lib,
                       space_1x_lib,
                       sar_name,
                       samp_name,
                       space_1x_name,
                       placement_grid,
                       routing_grid_m5m6,
                       routing_grid_m3m4_basic_thick,
                       routing_grid_m5m6_thick,
                       routing_grid_m5m6_thick_basic,
                       num_inv_bb=0,
                       num_bits=9,
                       use_sf=False,
                       vref_sf=False,
                       origin=np.array([0, 0])):
    """generate sar with sampling frontend """
    pg = placement_grid

    rg_m5m6 = routing_grid_m5m6
    rg_m5m6_thick = routing_grid_m5m6_thick
    rg_m5m6_thick_basic = routing_grid_m5m6_thick_basic  #for clock routing

    # placement
    # sar
    isar = laygen.place(name="I" + objectname_pfix + 'SAR0',
                        templatename=sar_name,
                        gridname=pg,
                        xy=origin,
                        template_libname=workinglib)
    # samp
    isamp = laygen.relplace(name="I" + objectname_pfix + 'SAMP0',
                            templatename=samp_name,
                            gridname=pg,
                            refinstname=isar.name,
                            direction='top',
                            template_libname=samp_lib)

    # source follower
    sf_name = 'sourceFollower_diff'
    if use_sf == True:
        isf = laygen.relplace(name="I" + objectname_pfix + 'SF0',
                              templatename=sf_name,
                              gridname=pg,
                              refinstname=isamp.name,
                              direction='top',
                              template_libname=workinglib)
        sf_xy = isf.xy

    #prboundary
    sar_size = laygen.templates.get_template(sar_name, libname=workinglib).size
    samp_size = laygen.templates.get_template(samp_name, libname=samp_lib).size
    sf_size = laygen.templates.get_template(sf_name, libname=workinglib).size
    space_size = laygen.templates.get_template(space_1x_name,
                                               libname=space_1x_lib).size
    size_x = sar_size[0]
    size_y = int((sar_size[1] + samp_size[1]) / space_size[1] +
                 1) * space_size[1]
    if use_sf == True:
        size_y = int((sar_size[1] + samp_size[1] + sf_size[1]) /
                     space_size[1] + 1) * space_size[1]
    laygen.add_rect(None,
                    np.array([origin, origin + np.array([size_x, size_y])]),
                    laygen.layers['prbnd'])

    # template handles
    sar_template = laygen.templates.get_template(sar_name, workinglib)
    samp_template = laygen.templates.get_template(samp_name, samp_lib)
    sf_template = laygen.templates.get_template(sf_name, workinglib)

    #reference coordinates
    pdict_m5m6 = laygen.get_inst_pin_xy(None, None, rg_m5m6)
    pdict_m5m6_thick = laygen.get_inst_pin_xy(None, None, rg_m5m6_thick)
    pdict_m5m6_thick_basic = laygen.get_inst_pin_xy(None, None,
                                                    rg_m5m6_thick_basic)
    sar_pins = sar_template.pins
    samp_pins = samp_template.pins
    sf_pins = sf_template.pins
    #sar_xy=isar.xy[0]
    #samp_xy=isamp.xy[0]
    sar_xy = isar.xy
    samp_xy = isamp.xy

    #signal route (clk/inp/inm)
    #make virtual grids and route on the grids (assuming drc clearance of each block)
    rg_m5m6_thick_basic_temp_sig = 'route_M5_M6_thick_basic_temp_sig'
    laygenhelper.generate_grids_from_inst(
        laygen,
        gridname_input=rg_m5m6_thick_basic,
        gridname_output=rg_m5m6_thick_basic_temp_sig,
        instname=isamp.name,
        inst_pin_prefix=['ckout'],
        xy_grid_type='xgrid')
    pdict_m5m6_thick_basic_temp_sig = laygen.get_inst_pin_xy(
        None, None, rg_m5m6_thick_basic_temp_sig)
    rg_m4m5_basic_thick_temp_sig = 'route_M4_M5_basic_thick_temp_sig'
    laygenhelper.generate_grids_from_inst(
        laygen,
        gridname_input=rg_m4m5_basic_thick,
        gridname_output=rg_m4m5_basic_thick_temp_sig,
        instname=isamp.name,
        inst_pin_prefix=['outp', 'outn'],
        xy_grid_type='xgrid')
    pdict_m4m5_basic_thick_temp_sig = laygen.get_inst_pin_xy(
        None, None, rg_m4m5_basic_thick_temp_sig)
    #clock
    rclk0 = laygen.route(
        None,
        laygen.layers['metal'][5],
        xy0=pdict_m5m6_thick_basic_temp_sig[isamp.name]['ckout'][0],
        xy1=pdict_m5m6_thick_basic_temp_sig[isar.name]['CLK0'][1] -
        np.array([0, 1]),
        gridname0=rg_m5m6_thick_basic_temp_sig)
    laygen.via(None, pdict_m5m6_thick_basic_temp_sig[isar.name]['CLK0'][1],
               rg_m5m6_thick_basic_temp_sig)
    laygen.via(None, pdict_m5m6_thick_basic_temp_sig[isar.name]['CLK1'][1],
               rg_m5m6_thick_basic_temp_sig)
    #laygen.via(None,pdict_m5m6_thick_basic_temp_sig[isar.name]['CLK2'][1], rg_m5m6_thick_basic_temp_sig)
    #rclk0 = laygen.route(None, laygen.layers['metal'][5],
    #                     xy0=pdict_m5m6_thick_basic[isamp.name]['ckout'][0],
    #                     xy1=pdict_m5m6_thick_basic[isar.name]['CLK'][1]-np.array([0,1]), gridname0=rg_m5m6_thick_basic)
    #laygen.via(None,pdict_m5m6_thick_basic[isar.name]['CLK'][1], rg_m5m6_thick_basic)

    #frontend sig
    inp_y_list = []
    inm_y_list = []
    for pn, p in pdict_m4m5_basic_thick_temp_sig[isar.name].items():
        if pn.startswith('INP'):
            inp_y_list.append(p[0][1])
            pv = np.array([
                pdict_m4m5_basic_thick_temp_sig[isamp.name]['outp'][0][0],
                p[0][1]
            ])
            laygen.via(None, pv, rg_m4m5_basic_thick_temp_sig)
            #laygen.via(None,p[0], rg_m5m6_thick_basic_temp_sig)
        if pn.startswith('INM'):
            inm_y_list.append(p[0][1])
            pv = np.array([
                pdict_m4m5_basic_thick_temp_sig[isamp.name]['outn'][0][0],
                p[0][1]
            ])
            laygen.via(None, pv, rg_m4m5_basic_thick_temp_sig)
            #laygen.via(None,p[0], rg_m5m6_thick_basic_temp_sig)
    inp_y = min(inp_y_list)
    inm_y = min(inm_y_list)
    rinp0 = laygen.route(
        None,
        laygen.layers['metal'][5],
        xy0=pdict_m4m5_basic_thick_temp_sig[isamp.name]['outp'][0],
        xy1=np.array([
            pdict_m4m5_basic_thick_temp_sig[isamp.name]['outp'][0][0],
            inp_y - 1
        ]),
        gridname0=rg_m4m5_basic_thick_temp_sig)
    rinm0 = laygen.route(
        None,
        laygen.layers['metal'][5],
        xy0=pdict_m4m5_basic_thick_temp_sig[isamp.name]['outn'][0],
        xy1=np.array([
            pdict_m4m5_basic_thick_temp_sig[isamp.name]['outn'][0][0],
            inm_y - 1
        ]),
        gridname0=rg_m4m5_basic_thick_temp_sig)
    #rinp0 = laygen.route(None, laygen.layers['metal'][5],
    #                     xy0=pdict_m5m6_thick_basic_temp_sig[isamp.name]['outp'][0],
    #                     xy1=np.array([pdict_m5m6_thick_basic_temp_sig[isar.name]['INP0'][0][0],inp_y-1]),
    #                     gridname0=rg_m5m6_thick_basic_temp_sig)
    #rinm0 = laygen.route(None, laygen.layers['metal'][5],
    #                     xy0=pdict_m5m6_thick_basic_temp_sig[isamp.name]['outn'][0],
    #                     xy1=np.array([pdict_m5m6_thick_basic_temp_sig[isar.name]['INM0'][0][0],inm_y-1]),
    #                     gridname0=rg_m5m6_thick_basic_temp_sig)

    # source follower routing
    pdict_m4m5_thick = laygen.get_inst_pin_xy(None, None, rg_m4m5_thick)
    if use_sf == True:
        [rh0, rv0] = laygen.route_hv(laygen.layers['metal'][4],
                                     laygen.layers['metal'][5],
                                     pdict_m4m5_thick[isf.name]['outp'][0],
                                     pdict_m4m5_thick[isamp.name]['inp'][0],
                                     rg_m4m5_thick)
        [rh0, rv0] = laygen.route_hv(laygen.layers['metal'][4],
                                     laygen.layers['metal'][5],
                                     pdict_m4m5_thick[isf.name]['outn'][0],
                                     pdict_m4m5_thick[isamp.name]['inn'][0],
                                     rg_m4m5_thick)
        # VDD/VSS for source follower
        for pn, p in samp_pins.items():
            if pn.startswith('LVDD'):
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VDD0'][0],
                                rg_m4m5_thick)
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VDD1'][0],
                                rg_m4m5_thick)
            if pn.startswith('RVDD'):
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VDD0'][0],
                                rg_m4m5_thick)
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VDD1'][0],
                                rg_m4m5_thick)
            if pn.startswith('LVSS'):
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VSS0'][0],
                                rg_m4m5_thick)
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VSS1'][0],
                                rg_m4m5_thick)
            if pn.startswith('RVSS'):
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VSS0'][0],
                                rg_m4m5_thick)
                laygen.route_vh(laygen.layers['metal'][5],
                                laygen.layers['metal'][4],
                                pdict_m4m5_thick[isamp.name][pn][0],
                                pdict_m4m5_thick[isf.name]['VSS1'][0],
                                rg_m4m5_thick)

    #input pins (just duplicate from lower hierarchy cells)
    laygen.add_pin('CLK', 'CLK', samp_xy + samp_pins['ckin']['xy'],
                   samp_pins['ckin']['layer'])
    if use_sf == False:
        laygen.add_pin('INP', 'INP', samp_xy + samp_pins['inp']['xy'],
                       samp_pins['inp']['layer'])
        laygen.add_pin('INM', 'INM', samp_xy + samp_pins['inn']['xy'],
                       samp_pins['inn']['layer'])
    else:
        laygen.add_pin('INP', 'INP', sf_xy + sf_pins['inp']['xy'],
                       sf_pins['inp']['layer'])
        laygen.add_pin('INM', 'INM', sf_xy + sf_pins['inn']['xy'],
                       sf_pins['inn']['layer'])
        for pn, p in sf_pins.items():
            if pn.startswith('Voffp'):
                pxy = sf_xy + sf_pins[pn]['xy']
                laygen.add_pin('SF_' + pn, 'SF_Voffp', pxy,
                               sf_pins[pn]['layer'])
            if pn.startswith('Voffn'):
                pxy = sf_xy + sf_pins[pn]['xy']
                laygen.add_pin('SF_' + pn, 'SF_Voffn', pxy,
                               sf_pins[pn]['layer'])
            if pn.startswith('bypass'):
                pxy = sf_xy + sf_pins[pn]['xy']
                laygen.add_pin('SF_' + pn, 'SF_bypass', pxy,
                               sf_pins[pn]['layer'])
            if pn.startswith('VBIAS'):
                pxy = sf_xy + sf_pins[pn]['xy']
                laygen.add_pin('SF_BIAS', 'SF_BIAS', pxy, sf_pins[pn]['layer'])
            # if pn.startswith('VBIASn'):
            #     pxy = sf_xy + sf_pins[pn]['xy']
            #     laygen.add_pin('SF_BIASn', 'SF_BIASn', pxy, sf_pins[pn]['layer'])

    if vref_sf == True:
        laygen.add_pin('VREF_SF_BIAS', 'VREF_SF_BIAS',
                       sar_xy + sar_pins['SF_VBIAS']['xy'],
                       sar_pins['SF_VBIAS']['layer'])
        laygen.add_pin('VREF_SF_bypass', 'VREF_SF_bypass',
                       sar_xy + sar_pins['SF_bypass']['xy'],
                       sar_pins['SF_bypass']['layer'])

    laygen.add_pin('OSP', 'OSP', sar_xy + sar_pins['OSP']['xy'],
                   sar_pins['OSP']['layer'])
    laygen.add_pin('OSM', 'OSM', sar_xy + sar_pins['OSM']['xy'],
                   sar_pins['OSM']['layer'])
    for pn, p in sar_pins.items():
        if pn.startswith('VREF<0>'):
            pxy = sar_xy + sar_pins[pn]['xy']
            laygen.add_pin(pn, 'VREF<0>', pxy, sar_pins[pn]['layer'])
        if pn.startswith('VREF<1>'):
            pxy = sar_xy + sar_pins[pn]['xy']
            laygen.add_pin(pn, 'VREF<1>', pxy, sar_pins[pn]['layer'])
        if pn.startswith('VREF<2>'):
            pxy = sar_xy + sar_pins[pn]['xy']
            laygen.add_pin(pn, 'VREF<2>', pxy, sar_pins[pn]['layer'])
    #laygen.add_pin('VREF_M5R<2>', 'VREF<2>', sar_xy+sar_pins['VREF_M5R<2>']['xy'], sar_pins['VREF_M5R<2>']['layer'])
    #laygen.add_pin('VREF_M5R<1>', 'VREF<1>', sar_xy+sar_pins['VREF_M5R<1>']['xy'], sar_pins['VREF_M5R<1>']['layer'])
    #laygen.add_pin('VREF_M5R<0>', 'VREF<0>', sar_xy+sar_pins['VREF_M5R<0>']['xy'], sar_pins['VREF_M5R<0>']['layer'])
    #laygen.add_pin('VREF_M5L<2>', 'VREF<2>', sar_xy+sar_pins['VREF_M5L<2>']['xy'], sar_pins['VREF_M5L<2>']['layer'])
    #laygen.add_pin('VREF_M5L<1>', 'VREF<1>', sar_xy+sar_pins['VREF_M5L<1>']['xy'], sar_pins['VREF_M5L<1>']['layer'])
    #laygen.add_pin('VREF_M5L<0>', 'VREF<0>', sar_xy+sar_pins['VREF_M5L<0>']['xy'], sar_pins['VREF_M5L<0>']['layer'])
    laygen.add_pin('CKDSEL0<1>', 'CKDSEL0<1>',
                   sar_xy + sar_pins['CKDSEL0<1>']['xy'],
                   sar_pins['CKDSEL0<1>']['layer'])
    laygen.add_pin('CKDSEL0<0>', 'CKDSEL0<0>',
                   sar_xy + sar_pins['CKDSEL0<0>']['xy'],
                   sar_pins['CKDSEL0<0>']['layer'])
    laygen.add_pin('CKDSEL1<1>', 'CKDSEL1<1>',
                   sar_xy + sar_pins['CKDSEL1<1>']['xy'],
                   sar_pins['CKDSEL1<1>']['layer'])
    laygen.add_pin('CKDSEL1<0>', 'CKDSEL1<0>',
                   sar_xy + sar_pins['CKDSEL1<0>']['xy'],
                   sar_pins['CKDSEL1<0>']['layer'])
    #laygen.add_pin('EXTCLK', 'EXTCLK', sar_xy+sar_pins['EXTCLK']['xy'], sar_pins['EXTCLK']['layer'])
    laygen.add_pin('EXTSEL_CLK', 'EXTSEL_CLK',
                   sar_xy + sar_pins['EXTSEL_CLK']['xy'],
                   sar_pins['EXTSEL_CLK']['layer'])
    #output pins (just duplicate from lower hierarchy cells)
    for i in range(num_bits):
        pn = 'ADCOUT' + '<' + str(i) + '>'
        laygen.add_pin(pn, pn, sar_xy + sar_pins[pn]['xy'],
                       sar_pins[pn]['layer'])
    laygen.add_pin('CLKO0', 'CLKO', sar_xy + sar_pins['CLKOUT0']['xy'],
                   sar_pins['CLKOUT0']['layer'])
    laygen.add_pin('CLKO1', 'CLKO', sar_xy + sar_pins['CLKOUT1']['xy'],
                   sar_pins['CLKOUT1']['layer'])
    #laygen.add_pin('CLKO2', 'CLKO', sar_xy+sar_pins['CLKOUT2']['xy'], sar_pins['CLKOUT2']['layer'])

    #probe pins
    laygen.add_pin('CLK0', 'ICLK', sar_xy + sar_pins['CLK0']['xy'],
                   sar_pins['CLK0']['layer'])
    laygen.add_pin('CLK1', 'ICLK', sar_xy + sar_pins['CLK1']['xy'],
                   sar_pins['CLK1']['layer'])
    #laygen.add_pin('CLK2', 'ICLK', sar_xy+sar_pins['CLK2']['xy'], sar_pins['CLK2']['layer'])
    laygen.add_pin('CLKPRB_SAMP', 'CLKPRB_SAMP',
                   samp_xy + samp_pins['ckpg']['xy'],
                   samp_pins['ckpg']['layer'])
    #laygen.add_pin('CLKPRB_SAR', 'CLKPRB_SAR', sar_xy+sar_pins['CLKPRB']['xy'], sar_pins['CLKPRB']['layer'])
    laygen.add_pin('SAMPP', 'SAMPP', sar_xy + sar_pins['SAINP']['xy'],
                   sar_pins['SAINP']['layer'])
    laygen.add_pin('SAMPM', 'SAMPM', sar_xy + sar_pins['SAINM']['xy'],
                   sar_pins['SAINM']['layer'])
    laygen.add_pin('SAOP', 'SAOP', sar_xy + sar_pins['SAOP']['xy'],
                   sar_pins['SAOP']['layer'])
    laygen.add_pin('SAOM', 'SAOM', sar_xy + sar_pins['SAOM']['xy'],
                   sar_pins['SAOM']['layer'])
    laygen.add_pin('SARCLK', 'SARCLK', sar_xy + sar_pins['SARCLK']['xy'],
                   sar_pins['SARCLK']['layer'])
    laygen.add_pin('SARCLKB', 'SARCLKB', sar_xy + sar_pins['SARCLKB']['xy'],
                   sar_pins['SARCLKB']['layer'])
    #laygen.add_pin('COMPOUT', 'COMPOUT', sar_xy+sar_pins['COMPOUT']['xy'], sar_pins['COMPOUT']['layer'])
    laygen.add_pin('DONE', 'DONE', sar_xy + sar_pins['DONE']['xy'],
                   sar_pins['DONE']['layer'])
    laygen.add_pin('UP', 'UP', sar_xy + sar_pins['UP']['xy'],
                   sar_pins['UP']['layer'])
    laygen.add_pin('PHI0', 'PHI0', sar_xy + sar_pins['PHI0']['xy'],
                   sar_pins['PHI0']['layer'])
    for i in range(num_bits):
        pn = 'ZP' + '<' + str(i) + '>'
        laygen.add_pin(pn, pn, sar_xy + sar_pins[pn]['xy'],
                       sar_pins[pn]['layer'])
        pn = 'ZMID' + '<' + str(i) + '>'
        laygen.add_pin(pn, pn, sar_xy + sar_pins[pn]['xy'],
                       sar_pins[pn]['layer'])
        pn = 'ZM' + '<' + str(i) + '>'
        laygen.add_pin(pn, pn, sar_xy + sar_pins[pn]['xy'],
                       sar_pins[pn]['layer'])
        pn = 'SB' + '<' + str(i) + '>'
        laygen.add_pin(pn, pn, sar_xy + sar_pins[pn]['xy'],
                       sar_pins[pn]['layer'])
    for i in range(num_bits - 1):
        pn = 'VOL' + '<' + str(i) + '>'
        laygen.add_pin(pn, pn, sar_xy + sar_pins[pn]['xy'],
                       sar_pins[pn]['layer'])
        pn = 'VOR' + '<' + str(i) + '>'
        laygen.add_pin(pn, pn, sar_xy + sar_pins[pn]['xy'],
                       sar_pins[pn]['layer'])

    #VDD/VSS pin
    vddcnt = 0
    vsscnt = 0
    for p in pdict_m5m6[isar.name]:
        if p.startswith('VDD'):
            xy0 = pdict_m5m6_thick[isar.name][p]
            laygen.pin(name='VDDSAR' + str(vddcnt),
                       layer=laygen.layers['pin'][6],
                       xy=xy0,
                       gridname=rg_m5m6_thick,
                       netname='VDDSAR')
            vddcnt += 1
        if p.startswith('VSS'):
            xy0 = pdict_m5m6_thick[isar.name][p]
            laygen.pin(name='VSSSAR' + str(vsscnt),
                       layer=laygen.layers['pin'][6],
                       xy=xy0,
                       gridname=rg_m5m6_thick,
                       netname='VSS:')
            #laygen.pin(name='VSSSAR' + str(vsscnt), layer=laygen.layers['pin'][6], xy=xy0, gridname=rg_m5m6_thick, netname='VSS')
            vsscnt += 1
    #extract VDD/VSS grid from samp and make power pins
    rg_m5m6_thick_temp_samp = 'route_M5_M6_thick_temp_samp'
    laygenhelper.generate_grids_from_inst(
        laygen,
        gridname_input=rg_m5m6_thick,
        gridname_output=rg_m5m6_thick_temp_samp,
        instname=isamp.name,
        inst_pin_prefix=['VDD', 'VSS', 'samp_body'],
        xy_grid_type='ygrid')
    pdict_m5m6_thick_temp_samp = laygen.get_inst_pin_xy(
        None, None, rg_m5m6_thick_temp_samp)
    vddcnt = 0
    vsscnt = 0
    bodycnt = 0
    for p in pdict_m5m6_thick_temp_samp[isamp.name]:
        if p.startswith('VDD'):
            xy0 = pdict_m5m6_thick_temp_samp[isamp.name][p]
            laygen.pin(name='VDDSAMP' + str(vddcnt),
                       layer=laygen.layers['pin'][6],
                       xy=xy0,
                       gridname=rg_m5m6_thick_temp_samp,
                       netname='VDDSAMP')
            vddcnt += 1
        if p.startswith('VSS'):
            xy0 = pdict_m5m6_thick_temp_samp[isamp.name][p]
            laygen.pin(name='VSSSAMP' + str(vsscnt),
                       layer=laygen.layers['pin'][6],
                       xy=xy0,
                       gridname=rg_m5m6_thick_temp_samp,
                       netname='VSS:')
            #laygen.pin(name='VSSSAMP' + str(vsscnt), layer=laygen.layers['pin'][6], xy=xy0, gridname=rg_m5m6_thick_temp_samp, netname='VSS')
            vsscnt += 1
        if p.startswith('samp_body'):
            xy0 = pdict_m5m6_thick_temp_samp[isamp.name][p]
            laygen.pin(name='samp_body',
                       layer=laygen.layers['pin'][6],
                       xy=xy0,
                       gridname=rg_m5m6_thick_temp_samp,
                       netname='samp_body')
            bodycnt += 1
    # VBB
    pdict_m3m4 = laygen.get_inst_pin_xy(None, None, rg_m3m4_basic_thick)
    if not num_inv_bb == 0:
        rvbb_m3 = []
        for p in pdict_m3m4[isar.name]:
            if p.startswith('VBB') and p.endswith('0'):
                rvbb_m3.append(pdict_m3m4[isar.name][p])
                # laygen.pin(name='bottom_body'+str(p), layer=laygen.layers['pin'][3], xy=pdict_m3m4[isar.name][p], gridname=rg_m3m4, netname='bottom_body')
        rvbb_m4 = laygenhelper.generate_power_rails_from_rails_xy(
            laygen,
            routename_tag='_M4_',
            layer=laygen.layers['metal'][4],
            gridname=rg_m3m4_basic_thick,
            netnames=['bottom_body'],
            direction='x',
            input_rails_xy=[rvbb_m3],
            generate_pin=False,
            overwrite_start_coord=None,
            overwrite_end_coord=None,
            offset_start_index=0,
            offset_end_index=0)
        rvbb_m5 = laygenhelper.generate_power_rails_from_rails_rect(
            laygen,
            routename_tag='_M5_',
            layer=laygen.layers['metal'][5],
            gridname=rg_m4m5_thick,
            netnames=['bottom_body'],
            direction='y',
            input_rails_rect=rvbb_m4,
            generate_pin=False,
            overwrite_start_coord=None,
            overwrite_end_coord=None,
            offset_start_index=0,
            offset_end_index=-2)
        rvbb_m6 = laygenhelper.generate_power_rails_from_rails_rect(
            laygen,
            routename_tag='_M6_',
            layer=laygen.layers['metal'][6],
            gridname=rg_m5m6_thick,
            netnames=['bottom_body'],
            direction='x',
            input_rails_rect=rvbb_m5,
            generate_pin=False,
            overwrite_start_coord=None,
            overwrite_end_coord=None,
            offset_start_index=0,
            offset_end_index=0)
        num_m6 = len(rvbb_m6[0])
        for i in range(num_m6):
            if i % 2 == 1:
                rvbb_m6[0].remove(rvbb_m6[0][num_m6 - i - 1])
            print(rvbb_m6[0])
        rvbb_m7 = laygenhelper.generate_power_rails_from_rails_rect(
            laygen,
            routename_tag='_M7_',
            layer=laygen.layers['pin'][7],
            gridname=rg_m6m7_thick,
            netnames=['bottom_body'],
            direction='y',
            input_rails_rect=rvbb_m6,
            generate_pin=True,
            overwrite_start_coord=None,
            overwrite_end_coord=None,
            offset_start_index=0,
            offset_end_index=0)
Ejemplo n.º 2
0
def generate_tisaradc_space(laygen,
                            objectname_pfix,
                            tisar_libname,
                            space_libname,
                            tisar_name,
                            space_name,
                            placement_grid,
                            routing_grid_m3m4_thick,
                            routing_grid_m4m5_thick,
                            routing_grid_m5m6_thick,
                            origin=np.array([0, 0])):
    """generate tisar space """
    pg = placement_grid
    ttisar = laygen.templates.get_template(tisar_name, libname=tisar_libname)
    tspace = laygen.templates.get_template(space_name, libname=space_libname)
    tbnd_bottom = laygen.templates.get_template('boundary_bottom')
    tbnd_bleft = laygen.templates.get_template('boundary_bottomleft')
    space_xy = np.array([tspace.size[0], ttisar.size[1]])
    laygen.add_rect(
        None,
        np.array([
            origin,
            origin + space_xy + 2 * tbnd_bleft.size[0] * np.array([1, 0])
        ]), laygen.layers['prbnd'])
    num_space = int(
        (ttisar.size[1] - 2 * tbnd_bottom.size[1]) / tspace.size[1])
    #space_xy=np.array([tspace.size[0], 56.88]) #change it after finishing the clock part
    #num_space=int((56.88-2*tbnd_bottom.size[1])/tspace.size[1]) #should be changed after finishing the clock part
    space_origin = origin + laygen.get_template_size('boundary_bottomleft', pg)
    ispace = [
        laygen.place(name="I" + objectname_pfix + 'SP0',
                     templatename=space_name,
                     gridname=pg,
                     xy=space_origin,
                     template_libname=space_libname)
    ]
    #devname_bnd_left = ['nmos4_fast_left', 'pmos4_fast_left']
    #devname_bnd_right = ['nmos4_fast_right', 'pmos4_fast_right']
    devname_bnd_left = ['ptap_fast_left', 'ntap_fast_left']
    devname_bnd_right = ['ptap_fast_right', 'ntap_fast_right']
    transform_bnd_left = ['R0', 'MX']
    transform_bnd_right = ['R0', 'MX']
    for i in range(1, num_space):
        if i % 2 == 0:
            ispace.append(
                laygen.relplace(name="I" + objectname_pfix + 'SP' + str(i),
                                templatename=space_name,
                                gridname=pg,
                                refinstname=ispace[-1].name,
                                direction='top',
                                transform='R0',
                                template_libname=space_libname))
            #devname_bnd_left += ['nmos4_fast_left', 'pmos4_fast_left']
            #devname_bnd_right += ['nmos4_fast_right', 'pmos4_fast_right']
            devname_bnd_left += ['ptap_fast_left', 'ntap_fast_left']
            devname_bnd_right += ['ptap_fast_right', 'ntap_fast_right']
            transform_bnd_left += ['R0', 'MX']
            transform_bnd_right += ['R0', 'MX']
        else:
            ispace.append(
                laygen.relplace(name="I" + objectname_pfix + 'SP' + str(i),
                                templatename=space_name,
                                gridname=pg,
                                refinstname=ispace[-1].name,
                                direction='top',
                                transform='MX',
                                template_libname=space_libname))
            #devname_bnd_left += ['pmos4_fast_left', 'nmos4_fast_left']
            #devname_bnd_right += ['pmos4_fast_right', 'nmos4_fast_right']
            devname_bnd_left += ['ntap_fast_left', 'ptap_fast_left']
            devname_bnd_right += ['ntap_fast_right', 'ptap_fast_right']
            transform_bnd_left += ['R0', 'MX']
            transform_bnd_right += ['R0', 'MX']
            #transform_bnd_left +=  ['MX', 'R0']
            #transform_bnd_right += ['MX', 'R0']

    m_bnd = int(space_xy[0] / tbnd_bottom.size[0])
    [bnd_bottom, bnd_top, bnd_left, bnd_right] \
        = laygenhelper.generate_boundary(laygen, objectname_pfix='BND0', placement_grid=pg,
                            devname_bottom=['boundary_bottomleft', 'boundary_bottom', 'boundary_bottomright'],
                            shape_bottom=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_top=['boundary_topleft', 'boundary_top', 'boundary_topright'],
                            shape_top=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_left=devname_bnd_left,
                            transform_left=transform_bnd_left,
                            devname_right=devname_bnd_right,
                            transform_right=transform_bnd_right,
                            origin=origin)
    #vdd/vss
    #m3
    rvdd_xy_m3 = []
    rvss_xy_m3 = []
    space_template = laygen.templates.get_template(space_name, workinglib)
    space_pins = space_template.pins
    space_origin_phy = laygen.get_inst_bbox_phygrid(ispace[0].name)[0]
    vddcnt = 0
    vsscnt = 0
    for pn, p in space_pins.items():
        if pn.startswith('VDD'):
            pxy = space_origin_phy + np.array(
                [p['xy'][0], p['xy'][1] * np.array([1, num_space])])
            laygen.add_rect(None, pxy, p['layer'])
            rvdd_xy_m3.append(
                laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick,
                                                      xy0=pxy[0],
                                                      xy1=pxy[1]))
            vddcnt += 1
        if pn.startswith('VSS'):
            pxy = space_origin_phy + np.array(
                [p['xy'][0], p['xy'][1] * np.array([1, num_space])])
            laygen.add_rect(None, pxy, p['layer'])
            rvss_xy_m3.append(
                laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick,
                                                      xy0=pxy[0],
                                                      xy1=pxy[1]))
            vsscnt += 1
    #m4
    input_rails_xy = [rvdd_xy_m3, rvss_xy_m3]
    rvdd_m4, rvss_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_M4_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        overwrite_num_routes=80,
        offset_start_index=0,
        offset_end_index=0)
    #exclude_phycoord_list=[[23.4,34.7]])
    #m5
    input_rails_rect = [rvdd_m4, rvss_m4]
    rvdd_m5, rvss_m5 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M5_',
        layer=laygen.layers['metal'][5],
        gridname=rg_m4m5_thick,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    #m6 (extract VDD/VSS grid from tisar and make power pins)
    rg_m5m6_thick_temp_tisar = 'route_M5_M6_thick_temp_tisar_VDD'
    laygenhelper.generate_grids_from_template(
        laygen,
        gridname_input=rg_m5m6_thick,
        gridname_output=rg_m5m6_thick_temp_tisar,
        template_name=tisar_name,
        template_libname=tisar_libname,
        template_pin_prefix=['VDD'],
        xy_grid_type='ygrid')
    input_rails_rect = [rvdd_m5]
    rvdd_m6 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_',
        layer=laygen.layers['pin'][6],
        gridname=rg_m5m6_thick_temp_tisar,
        netnames=['VDD'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=True,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=-1)
    rg_m5m6_thick_temp_tisar = 'route_M5_M6_thick_temp_tisar_VSS'
    laygenhelper.generate_grids_from_template(
        laygen,
        gridname_input=rg_m5m6_thick,
        gridname_output=rg_m5m6_thick_temp_tisar,
        template_name=tisar_name,
        template_libname=tisar_libname,
        template_pin_prefix=['VSS'],
        xy_grid_type='ygrid')
    input_rails_rect = [rvss_m5]
    rvss_m6 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_',
        layer=laygen.layers['pin'][6],
        gridname=rg_m5m6_thick_temp_tisar,
        netnames=['VSS'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=True,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=-2)
def generate_sarafe_nsw(laygen, objectname_pfix, workinglib, placement_grid,
                    routing_grid_m2m3_thick, routing_grid_m3m4_thick,
                    routing_grid_m4m5_thick, routing_grid_m5m6_thick,
                    routing_grid_m5m6, routing_grid_m6m7,
                    num_bits=8, num_bits_vertical=6, m_sa=8, origin=np.array([0, 0])):
    """generate sar analog frontend """
    pg = placement_grid

    rg_m3m4_thick = routing_grid_m3m4_thick
    rg_m5m6 = routing_grid_m5m6
    rg_m6m7 = routing_grid_m6m7

    tap_name='tap'
    cdrv_name='capdrv_nsw_array_'+str(num_bits)+'b'
    #cdac_name='capdac_'+str(num_bits)+'b'
    cdac_name='capdac'
    sa_name='salatch_pmos'

    # placement
    xy0 = origin + (laygen.get_template_size(cdrv_name, gridname=pg, libname=workinglib)*np.array([1, 0]) )
    icdrvl = laygen.place(name="I" + objectname_pfix + 'CDRVL0', templatename=cdrv_name, gridname=pg,
                          xy=xy0, template_libname = workinglib, transform='MY')
    icdrvr = laygen.place(name="I" + objectname_pfix + 'CDRVR0', templatename=cdrv_name, gridname=pg,
                          xy=xy0, template_libname = workinglib)
    xy0 = origin + laygen.get_template_size(cdrv_name, gridname=pg, libname=workinglib)*np.array([0, 1]) \
                 + laygen.get_template_size(sa_name, gridname=pg, libname=workinglib) * np.array([0, 1])
    isa = laygen.place(name="I" + objectname_pfix + 'SA0', templatename=sa_name, gridname=pg,
                       xy=xy0, template_libname = workinglib, transform='MX')
    xy0 = origin + laygen.get_template_size(cdrv_name, gridname=pg, libname=workinglib)*np.array([0, 1]) \
                 + laygen.get_template_size(sa_name, gridname=pg, libname=workinglib) * np.array([0, 1]) \
                 + laygen.get_template_size(cdac_name, gridname=pg, libname=workinglib)*np.array([1, 0])
    icdacl = laygen.place(name="I" + objectname_pfix + 'CDACL0', templatename=cdac_name, gridname=pg,
                          xy=xy0, template_libname = workinglib, transform='MY')
    xy0 = origin + laygen.get_template_size(cdrv_name, gridname=pg, libname=workinglib)*np.array([2, 1]) \
                 + laygen.get_template_size(sa_name, gridname=pg, libname=workinglib) * np.array([0, 1]) \
                 - laygen.get_template_size(cdac_name, gridname=pg, libname=workinglib)*np.array([1, 0])
    icdacr = laygen.place(name="I" + objectname_pfix + 'CDACR0', templatename=cdac_name, gridname=pg,
                          xy=xy0, template_libname = workinglib)

    # pin informations
    pdict_m3m4_thick=laygen.get_inst_pin_coord(None, None, rg_m3m4_thick)

    # internal pins
    icdrvl_vo_xy = []
    icdacl_i_xy = []
    icdrvr_vo_xy = []
    icdacr_i_xy = []

    icdrvl_vo_c0_xy = laygen.get_inst_pin_coord(icdrvl.name, 'VO_C0', rg_m5m6)
    icdacl_i_c0_xy = laygen.get_inst_pin_coord(icdacl.name, 'I_C0', rg_m5m6)
    icdrvr_vo_c0_xy = laygen.get_inst_pin_coord(icdrvr.name, 'VO_C0', rg_m5m6)
    icdacr_i_c0_xy = laygen.get_inst_pin_coord(icdacr.name, 'I_C0', rg_m5m6)
    for i in range(num_bits):
        icdrvl_vo_xy.append(laygen.get_inst_pin_coord(icdrvl.name, 'VO<' + str(i) + '>', rg_m5m6))
        icdacl_i_xy.append(laygen.get_inst_pin_coord(icdacl.name, 'I<' + str(i) + '>', rg_m5m6))
        icdrvr_vo_xy.append(laygen.get_inst_pin_coord(icdrvr.name, 'VO<' + str(i) + '>', rg_m5m6))
        icdacr_i_xy.append(laygen.get_inst_pin_coord(icdacr.name, 'I<' + str(i) + '>', rg_m5m6))

    #route
    #capdrv to capdac
    #y0 = origin[1] + laygen.get_template_size(cdrv_name, gridname=rg_m5m6, libname=workinglib)[1]-2 #refer to capdrv
    y0 = origin[1] + laygen.get_template_size(cdrv_name, gridname=rg_m5m6, libname=workinglib)[1] \
         + laygen.get_template_size(sa_name, gridname=rg_m5m6, libname=workinglib)[1]-4 #refer to sa
    [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][5], laygen.layers['metal'][6], icdrvl_vo_c0_xy[0],
                                       icdacl_i_c0_xy[0], y0 + 2, rg_m5m6, layerv1=laygen.layers['metal'][7], gridname1=rg_m6m7)
    laygen.create_boundary_pin_form_rect(rv0, rg_m5m6, "VOL_C0", laygen.layers['pin'][5], size=4, direction='bottom', netname='VREF<1>')
    [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][5], laygen.layers['metal'][6], icdrvr_vo_c0_xy[0],
                                       icdacr_i_c0_xy[0], y0 + 2, rg_m5m6, layerv1=laygen.layers['metal'][7], gridname1=rg_m6m7)
    laygen.create_boundary_pin_form_rect(rv0, rg_m5m6, "VOR_C0", laygen.layers['pin'][5], size=4, direction='bottom', netname='VREF<1>')

    for i in range(num_bits):
        [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][5], laygen.layers['metal'][6], icdrvl_vo_xy[i][0],
                                           icdacl_i_xy[i][0], y0 - i, rg_m5m6, layerv1=laygen.layers['metal'][7], gridname1=rg_m6m7)
        laygen.create_boundary_pin_form_rect(rv0, rg_m5m6, "VOL<"+str(i)+">", laygen.layers['pin'][5], size=4, direction='bottom')
        [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][5], laygen.layers['metal'][6], icdrvr_vo_xy[i][0],
                                           icdacr_i_xy[i][0], y0 - i, rg_m5m6, layerv1=laygen.layers['metal'][7], gridname1=rg_m6m7)
        laygen.create_boundary_pin_form_rect(rv0, rg_m5m6, "VOR<"+str(i)+">", laygen.layers['pin'][5], size=4, direction='bottom')


    #vref
    rvref0=laygen.route(None, laygen.layers['metal'][4], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                        refinstname0=icdrvl.name, refpinname0='VREF<0>', gridname0=rg_m4m5,
                        refinstname1=icdrvr.name, refpinname1='VREF<0>')
    rvref1=laygen.route(None, laygen.layers['metal'][4], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                        refinstname0=icdrvl.name, refpinname0='VREF<1>', gridname0=rg_m4m5,
                        refinstname1=icdrvr.name, refpinname1='VREF<1>')
    rvref2=laygen.route(None, laygen.layers['metal'][4], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                        refinstname0=icdrvl.name, refpinname0='VREF<2>', gridname0=rg_m4m5,
                        refinstname1=icdrvr.name, refpinname1='VREF<2>')
    #input pins
    #y0 = laygen.get_inst_pin_coord(icdrvl.name, 'EN0<0>', rg_m4m5, index=np.array([0, 0]), sort=True)[0][1]
    y0 = 0
    rclkb=laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                      refinstname0=isa.name, refpinname0='CLKB', gridname0=rg_m4m5, direction='y')
    routp=laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                      refinstname0=isa.name, refpinname0='OUTP', gridname0=rg_m4m5, direction='y')
    routm=laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                      refinstname0=isa.name, refpinname0='OUTM', gridname0=rg_m4m5, direction='y')
    rosp=laygen.route(None, laygen.layers['metal'][3], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                      refinstname0=isa.name, refpinname0='OSP', gridname0=rg_m2m3, direction='y')
    rosm=laygen.route(None, laygen.layers['metal'][3], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                      refinstname0=isa.name, refpinname0='OSM', gridname0=rg_m2m3, direction='y')
    renl0 = []
    renl1 = []
    renl2 = []
    renr0 = []
    renr1 = []
    renr2 = []
    for i in range(num_bits):
        renl0.append(laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                     refinstname0=icdrvl.name, refpinname0='EN'+str(i)+'<0>', gridname0=rg_m5m6, direction='y'))
        renl1.append(laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                     refinstname0=icdrvl.name, refpinname0='EN'+str(i)+'<1>', gridname0=rg_m5m6, direction='y'))
        renl2.append(laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                     refinstname0=icdrvl.name, refpinname0='EN'+str(i)+'<2>', gridname0=rg_m5m6, direction='y'))
        renr0.append(laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                     refinstname0=icdrvr.name, refpinname0='EN'+str(i)+'<0>', gridname0=rg_m5m6, direction='y'))
        renr1.append(laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                     refinstname0=icdrvr.name, refpinname0='EN'+str(i)+'<1>', gridname0=rg_m5m6, direction='y'))
        renr2.append(laygen.route(None, laygen.layers['metal'][5], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
                     refinstname0=icdrvr.name, refpinname0='EN'+str(i)+'<2>', gridname0=rg_m5m6, direction='y'))
    #inp/inm
    pdict_m5m6 = laygen.get_inst_pin_coord(None, None, rg_m5m6)
    outcnt=0
    for pn in pdict_m5m6[icdacl.name]:
        if pn.startswith('O'): #out pin
            outcnt+=1
    x0 = laygen.get_inst_xy(icdacl.name, rg_m5m6)[0] - 8
    x1 = laygen.get_inst_xy(icdacr.name, rg_m5m6)[0] + 8
    nrin = 16  # number of M6 horizontal route stacks
    rinp=[]
    rinm=[]
    for i in range(nrin):
        xy0=laygen.get_inst_pin_coord(icdacl.name, "O"+str(outcnt-1-i), rg_m5m6, index=np.array([0, 0]), sort=True)[0]
        r = laygen.route(None, laygen.layers['metal'][6], xy0=xy0, xy1=np.array([x0, xy0[1]]), gridname0=rg_m5m6)
        rinp.append(r)
        xy0=laygen.get_inst_pin_coord(icdacr.name, "O"+str(outcnt-1-i), rg_m5m6, index=np.array([0, 0]), sort=True)[1]
        r = laygen.route(None, laygen.layers['metal'][6], xy0=xy0, xy1=np.array([x1, xy0[1]]), gridname0=rg_m5m6)
        rinm.append(r)

    nrin_sa = 4  # number of M6 horizontal route stacks for cdac to sa
    for i in range(nrin_sa):
        xy0=laygen.get_inst_pin_coord(icdacl.name, "O"+str(i), rg_m5m6, index=np.array([0, 0]), sort=True)[0]
        laygen.route(None, laygen.layers['metal'][6], xy0=xy0, xy1=np.array([x0, xy0[1]]), gridname0=rg_m5m6)
        for j in range(4):
            laygen.via(None, [x0-2*j, xy0[1]], rg_m5m6)
        xy0=laygen.get_inst_pin_coord(icdacr.name, "O"+str(i), rg_m5m6, index=np.array([0, 0]), sort=True)[1]
        laygen.route(None, laygen.layers['metal'][6], xy0=xy0, xy1=np.array([x1, xy0[1]]), gridname0=rg_m5m6)
        for j in range(4):
            laygen.via(None, [x1+2*j, xy0[1]], rg_m5m6)
    xy0 = laygen.get_inst_pin_coord(isa.name, "INP", rg_m3m4, index=np.array([0, 0]), sort=True)[0]
    xy1 = laygen.get_inst_pin_coord(icdacl.name, "O"+str(nrin_sa-1), rg_m5m6, index=np.array([0, 0]), sort=True)[0]
    for j in range(4):
        laygen.route(None, laygen.layers['metal'][5], xy0=np.array([x0-2*j, xy0[1]]), xy1=np.array([x0-2*j, xy1[1]]), gridname0=rg_m5m6)
    xy0 = laygen.get_inst_pin_coord(isa.name, "INM", rg_m4m5, index=np.array([0, 0]), sort=True)[0]
    xy1 = laygen.get_inst_pin_coord(icdacr.name, "O"+str(nrin_sa-1), rg_m5m6, index=np.array([0, 0]), sort=True)[0]
    for j in range(4):
        laygen.route(None, laygen.layers['metal'][5], xy0=np.array([x1+2*j, xy0[1]]), xy1=np.array([x1+2*j, xy1[1]]), gridname0=rg_m5m6)
    #inp/inm - sa to capdac
    xy0 = laygen.get_inst_pin_coord(isa.name, "INP", rg_m4m5, index=np.array([0, 0]), sort=True)[0]
    xy1 = laygen.get_inst_pin_coord(isa.name, "INM", rg_m4m5, index=np.array([0, 0]), sort=True)[0]
    rsainp=laygen.route(None, laygen.layers['metal'][4], xy0=np.array([x0-8, xy0[1]]), xy1=xy0, gridname0=rg_m4m5)
    rsainm=laygen.route(None, laygen.layers['metal'][4], xy0=np.array([x1+8, xy1[1]]), xy1=xy1, gridname0=rg_m4m5)
    for j in range(4):
        laygen.via(None, [x0 - 2 * j, xy0[1]], rg_m4m5)
        laygen.via(None, [x1 + 2 * j, xy1[1]], rg_m4m5)
    x0 = laygen.get_inst_xy(icdacl.name, rg_m3m4)[0] - 1
    x1 = laygen.get_inst_xy(icdacr.name, rg_m3m4)[0] + 1
    xy0 = laygen.get_inst_pin_coord(isa.name, "INP", rg_m3m4, index=np.array([0, 0]), sort=True)[0]
    xy1 = laygen.get_inst_pin_coord(isa.name, "INM", rg_m3m4, index=np.array([0, 0]), sort=True)[0]
    laygen.route(None, laygen.layers['metal'][4], xy0=np.array([x0, xy0[1]]), xy1=xy0, gridname0=rg_m3m4, addvia1=True)
    laygen.route(None, laygen.layers['metal'][4], xy0=np.array([x1, xy1[1]]), xy1=xy1, gridname0=rg_m3m4, addvia1=True)

    #vdd/vss - route
    #cdrv_left_m4
    rvdd_cdrvl_m3=[]
    rvss_cdrvl_m3=[]
    for pn, p in pdict_m3m4_thick[icdrvl.name].items():
        if pn.startswith('VDDR'):
            rvdd_cdrvl_m3.append(p)
        if pn.startswith('VSSR'):
            rvss_cdrvl_m3.append(p)
    input_rails_xy = [rvdd_cdrvl_m3, rvss_cdrvl_m3]
    rvdd_cdrvl_m4, rvss_cdrvl_m4 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_CDRVL_M4_', 
                layer=laygen.layers['metal'][4], gridname=rg_m3m4_thick, netnames=['VDD', 'VSS'], direction='x', 
                input_rails_xy=input_rails_xy, generate_pin=False, overwrite_start_coord=0, overwrite_end_coord=None,
                offset_start_index=0, offset_end_index=0)
    #cdrv_right_m4
    x1 = laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m3m4_thick)[0]\
         +laygen.get_template_size(name=icdrvr.cellname, gridname=rg_m3m4_thick, libname=workinglib)[0]
    rvdd_cdrvr_m3=[]
    rvss_cdrvr_m3=[]
    for pn, p in pdict_m3m4_thick[icdrvr.name].items():
        if pn.startswith('VDDR'):
            rvdd_cdrvr_m3.append(p)
        if pn.startswith('VSSR'):
            rvss_cdrvr_m3.append(p)
    input_rails_xy = [rvdd_cdrvr_m3, rvss_cdrvr_m3]
    rvdd_cdrvr_m4, rvss_cdrvr_m4 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_CDRVR_M4_', 
                layer=laygen.layers['metal'][4], gridname=rg_m3m4_thick, netnames=['VDD', 'VSS'], direction='x', 
                input_rails_xy=input_rails_xy, generate_pin=False, overwrite_start_coord=None, overwrite_end_coord=x1, 
                offset_start_index=0, offset_end_index=0)
    #sa_left_m4_m5
    rvdd_sal_m3=[]
    rvss_sal_m3=[]
    for pn, p in pdict_m3m4_thick[isa.name].items():
        if pn.startswith('VDDL'):
            rvdd_sal_m3.append(p)
        if pn.startswith('VSSL'):
            rvss_sal_m3.append(p)
    input_rails_xy = [rvdd_sal_m3, rvss_sal_m3]
    rvdd_sal_m4, rvss_sal_m4 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_SAL_M4_', 
                layer=laygen.layers['metal'][4], gridname=rg_m3m4_thick, netnames=['VDD', 'VSS'], direction='x', 
                input_rails_xy=input_rails_xy, generate_pin=False, overwrite_start_coord=0, overwrite_end_coord=None,
                offset_start_index=0, offset_end_index=0)
    input_rails_rect = [rvdd_sal_m4+rvdd_cdrvl_m4, rvss_sal_m4+rvss_cdrvl_m4]
    rvdd_sal_m5, rvss_sal_m5 = laygenhelper.generate_power_rails_from_rails_rect(laygen, routename_tag='_SAL_M5_', 
                layer=laygen.layers['metal'][5], gridname=rg_m4m5_thick, netnames=['VDD', 'VSS'], direction='y', 
                input_rails_rect=input_rails_rect, generate_pin=False, overwrite_start_coord=0, overwrite_end_coord=None,
                offset_start_index=1, offset_end_index=-5)
    #sa_right_m4_m5
    x1 = laygen.get_inst_xy(name=isa.name, gridname=rg_m3m4_thick)[0]\
         +laygen.get_template_size(name=isa.cellname, gridname=rg_m3m4_thick, libname=workinglib)[0]
    rvdd_sar_m3=[]
    rvss_sar_m3=[]
    for pn, p in pdict_m3m4_thick[isa.name].items():
        if pn.startswith('VDDR'):
            rvdd_sar_m3.append(p)
        if pn.startswith('VSSR'):
            rvss_sar_m3.append(p)
    input_rails_xy = [rvdd_sar_m3, rvss_sar_m3]
    rvdd_sar_m4, rvss_sar_m4 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_SAR_M4_', 
                layer=laygen.layers['metal'][4], gridname=rg_m3m4_thick, netnames=['VDD', 'VSS'], direction='x', 
                input_rails_xy=input_rails_xy, generate_pin=False, overwrite_start_coord=None, overwrite_end_coord=x1,
                offset_start_index=0, offset_end_index=0)
    input_rails_rect = [rvdd_sar_m4+rvdd_cdrvr_m4, rvss_sar_m4+rvss_cdrvr_m4]
    rvdd_sar_m5, rvss_sar_m5 = laygenhelper.generate_power_rails_from_rails_rect(laygen, routename_tag='_SAR_M5_', 
                layer=laygen.layers['metal'][5], gridname=rg_m4m5_thick, netnames=['VDD', 'VSS'], direction='y', 
                input_rails_rect=input_rails_rect, generate_pin=False, overwrite_start_coord=0, overwrite_end_coord=None,
                offset_start_index=5, offset_end_index=0)
    #sa_m6
    x1 = laygen.get_inst_xy(name=isa.name, gridname=rg_m5m6_thick)[0]\
         +laygen.get_template_size(name=isa.cellname, gridname=rg_m5m6_thick, libname=workinglib)[0]
    y1 = laygen.get_inst_xy(name=isa.name, gridname=rg_m5m6_thick)[1]
    input_rails_rect = [rvdd_sal_m5+rvdd_sar_m5, rvss_sal_m5+rvss_sar_m5]
    rvdd_sa_m6, rvss_sa_m6 = laygenhelper.generate_power_rails_from_rails_rect(laygen, routename_tag='_M6_', 
                layer=laygen.layers['pin'][6], gridname=rg_m5m6_thick, netnames=['VDD', 'VSS'], direction='x', 
                input_rails_rect=input_rails_rect, generate_pin=True, overwrite_start_coord=0, overwrite_end_coord=x1,
                offset_start_index=int(y1/2)+4, offset_end_index=-2+2)

    #pins
    laygen.pin(name='VREF<0>', layer=laygen.layers['pin'][4], xy=laygen.get_rect_xy(rvref0.name, rg_m4m5), gridname=rg_m4m5)
    laygen.pin(name='VREF<1>', layer=laygen.layers['pin'][4], xy=laygen.get_rect_xy(rvref1.name, rg_m4m5), gridname=rg_m4m5)
    laygen.pin(name='VREF<2>', layer=laygen.layers['pin'][4], xy=laygen.get_rect_xy(rvref2.name, rg_m4m5), gridname=rg_m4m5)
    t = laygen.templates.get_template(icdrvl.cellname, libname=workinglib)
    vref0vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_coord(t.name, 'VREF_M5<0>', rg_m4m5, libname=workinglib)
    vref1vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_coord(t.name, 'VREF_M5<1>', rg_m4m5, libname=workinglib)
    vref2vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_coord(t.name, 'VREF_M5<2>', rg_m4m5, libname=workinglib)
    vref0vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_coord(t.name, 'VREF_M5<0>', rg_m4m5, libname=workinglib)
    vref1vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_coord(t.name, 'VREF_M5<1>', rg_m4m5, libname=workinglib)
    vref2vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_coord(t.name, 'VREF_M5<2>', rg_m4m5, libname=workinglib)
    laygen.pin(name='VREF_M5L<0>', layer=laygen.layers['pin'][5], xy=vref0vl_pin_xy, gridname=rg_m4m5, netname='VREF<0>')
    laygen.pin(name='VREF_M5L<1>', layer=laygen.layers['pin'][5], xy=vref1vl_pin_xy, gridname=rg_m4m5, netname='VREF<1>')
    laygen.pin(name='VREF_M5L<2>', layer=laygen.layers['pin'][5], xy=vref2vl_pin_xy, gridname=rg_m4m5, netname='VREF<2>')
    laygen.pin(name='VREF_M5R<0>', layer=laygen.layers['pin'][5], xy=vref0vr_pin_xy, gridname=rg_m4m5, netname='VREF<0>')
    laygen.pin(name='VREF_M5R<1>', layer=laygen.layers['pin'][5], xy=vref1vr_pin_xy, gridname=rg_m4m5, netname='VREF<1>')
    laygen.pin(name='VREF_M5R<2>', layer=laygen.layers['pin'][5], xy=vref2vr_pin_xy, gridname=rg_m4m5, netname='VREF<2>')

    laygen.create_boundary_pin_form_rect(rclkb, rg_m4m5, "CLKB", laygen.layers['pin'][5], size=4, direction='bottom')
    laygen.create_boundary_pin_form_rect(routp, rg_m4m5, "OUTP", laygen.layers['pin'][5], size=4, direction='bottom')
    laygen.create_boundary_pin_form_rect(routm, rg_m4m5, "OUTM", laygen.layers['pin'][5], size=4, direction='bottom')
    laygen.create_boundary_pin_form_rect(rosp, rg_m2m3, "OSP", laygen.layers['pin'][3], size=4, direction='bottom')
    laygen.create_boundary_pin_form_rect(rosm, rg_m2m3, "OSM", laygen.layers['pin'][3], size=4, direction='bottom')
    for i in range(num_bits):
        laygen.create_boundary_pin_form_rect(renl0[i], rg_m5m6, "ENL"+str(i)+"<0>", laygen.layers['pin'][5], size=4, direction='bottom')
        laygen.create_boundary_pin_form_rect(renl1[i], rg_m5m6, "ENL"+str(i)+"<1>", laygen.layers['pin'][5], size=4, direction='bottom')
        laygen.create_boundary_pin_form_rect(renl2[i], rg_m5m6, "ENL"+str(i)+"<2>", laygen.layers['pin'][5], size=4, direction='bottom')
        laygen.create_boundary_pin_form_rect(renr0[i], rg_m5m6, "ENR"+str(i)+"<0>", laygen.layers['pin'][5], size=4, direction='bottom')
        laygen.create_boundary_pin_form_rect(renr1[i], rg_m5m6, "ENR"+str(i)+"<1>", laygen.layers['pin'][5], size=4, direction='bottom')
        laygen.create_boundary_pin_form_rect(renr2[i], rg_m5m6, "ENR"+str(i)+"<2>", laygen.layers['pin'][5], size=4, direction='bottom')

    laygen.pin_from_rect(name='SAINP', layer=laygen.layers['pin'][4], rect=rsainp, gridname=rg_m4m5, netname='INP')
    laygen.pin_from_rect(name='SAINM', layer=laygen.layers['pin'][4], rect=rsainm, gridname=rg_m4m5, netname='INM')
    for i, r in enumerate(rinp):
        laygen.create_boundary_pin_form_rect(r, rg_m5m6, "INP"+str(i), laygen.layers['pin'][6], size=8, direction='right', netname="INP")
    for i, r in enumerate(rinm):
        laygen.create_boundary_pin_form_rect(r, rg_m5m6, "INM"+str(i), laygen.layers['pin'][6], size=8, direction='left', netname="INM")
Ejemplo n.º 4
0
def generate_tisaradc_space2(laygen,
                             objectname_pfix,
                             tisar_libname,
                             space_libname,
                             tisar_name,
                             space_name,
                             placement_grid,
                             routing_grid_m3m4_thick,
                             routing_grid_m4m5_thick,
                             routing_grid_m5m6_thick,
                             origin=np.array([0, 0])):
    """generate tisar space """
    pg = placement_grid
    ttisar = laygen.templates.get_template(tisar_name, libname=tisar_libname)
    tspace = laygen.templates.get_template(space_name, libname=space_libname)

    sar_pins = ttisar.pins

    tbnd_bottom = laygen.templates.get_template('boundary_bottom')
    tbnd_bleft = laygen.templates.get_template('boundary_bottomleft')
    space_xy = np.array([tspace.size[0], ttisar.size[1]])
    laygen.add_rect(
        None,
        np.array([
            origin,
            origin + space_xy + 2 * tbnd_bleft.size[0] * np.array([1, 0])
        ]), laygen.layers['prbnd'])
    num_space_tot = int(
        (ttisar.size[1] - 2 * tbnd_bottom.size[1]) / tspace.size[1])
    tbnd_bleft_size = tbnd_bleft.size

    #VDD/VSS/VREF integration
    rvddclkd = []
    rvddsamp = []
    rvddsar = []
    rvddsar_upper = []
    rvref0 = []
    rvref1 = []
    rvref2 = []
    rvssclkd = []
    rvsssamp = []
    rvsssar = []
    rvsssar_upper = []
    vddclkd_xy = []
    vddsamp_xy = []
    vddsar_xy = []
    vddsar_upper_xy = []
    vssclkd_xy = []
    vsssamp_xy = []
    vsssar_xy = []
    vsssar_upper_xy = []
    y_vddsar_max = 0
    y_vddsar_lower_max = 0
    y_vddsamp_min = 500000
    y_vddsamp_max = 0
    y_vddclkd_min = 500000
    y_vref0 = sar_pins['VREF0<0>']['xy'][0][1]

    #categorize vdd pins and figure out thresholds
    for pn, p in sar_pins.items():
        '''
        if pn.startswith('VDDCLKD'):
            pxy=np.array([[0, sar_pins[pn]['xy'][0][1]], 
                          [2*tbnd_bleft_size[0]+space_xy[0], sar_pins[pn]['xy'][1][1]]])
            rvddclkd.append(laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
            if pxy[1][1]<y_vddclkd_min:
                y_vddclkd_min=pxy[1][1]
            vddclkd_xy.append(pxy)
        '''
        if pn.startswith('VDDSAMP'):
            pxy = np.array([[0, sar_pins[pn]['xy'][0][1]],
                            [
                                2 * tbnd_bleft_size[0] + space_xy[0],
                                sar_pins[pn]['xy'][1][1]
                            ]])
            rvddsamp.append(
                laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
            if pxy[1][1] < y_vddsamp_min:
                y_vddsamp_min = pxy[1][1]
            if pxy[1][1] > y_vddsamp_max:
                y_vddsamp_max = pxy[1][1]
            vddsamp_xy.append(pxy)
        if pn.startswith('VDDSAR'):
            pxy = np.array([[0, sar_pins[pn]['xy'][0][1]],
                            [
                                2 * tbnd_bleft_size[0] + space_xy[0],
                                sar_pins[pn]['xy'][1][1]
                            ]])
            if pxy[0][1] > y_vref0:
                rvddsar_upper.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
                vddsar_upper_xy.append(pxy)
            else:
                rvddsar.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
                vddsar_xy.append(pxy)
                if pxy[1][1] > y_vddsar_lower_max:
                    y_vddsar_lower_max = pxy[1][1]
            if pxy[1][1] > y_vddsar_max:
                y_vddsar_max = pxy[1][1]
        if pn.startswith('VREF'):
            pxy = np.array([[0, sar_pins[pn]['xy'][0][1]],
                            [
                                2 * tbnd_bleft_size[0] + space_xy[0],
                                sar_pins[pn]['xy'][1][1]
                            ]])
            if pn.endswith('<0>'):
                rvref0.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
            if pn.endswith('<1>'):
                rvref1.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
            if pn.endswith('<2>'):
                rvref2.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
    y_vss_th = 0.5 * (y_vddsar_max + y_vddsamp_min
                      )  #find out threshold (sar/samp)
    #y_vss_th2=0.5*(y_vddsamp_max+y_vddclkd_min) #(samp/clkd)
    y_vss_th2 = 100000
    for pn, p in sar_pins.items():
        if pn.startswith('VSS'):
            pxy = np.array([[0, sar_pins[pn]['xy'][0][1]],
                            [
                                2 * tbnd_bleft_size[0] + space_xy[0],
                                sar_pins[pn]['xy'][1][1]
                            ]])
            if pxy[0][1] > y_vss_th2:
                rvssclkd.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
                vssclkd_xy.append(pxy)
            elif pxy[0][1] > y_vss_th:
                rvsssamp.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
                vsssamp_xy.append(pxy)
            elif pxy[0][1] > y_vref0:
                rvsssar_upper.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
                vsssar_upper_xy.append(pxy)
            else:
                rvsssar.append(
                    laygen.add_rect(None, pxy, laygen.layers['metal'][6]))
                vsssar_xy.append(pxy)

    #vddsar cap
    num_space_sar = int(
        (y_vss_th - 2 * tbnd_bottom.size[1]) / tspace.size[1]) + 4
    space_origin = origin + laygen.get_template_size('boundary_bottomleft', pg)
    ispace_sar = [
        laygen.place(name="I" + objectname_pfix + 'SPSAR0',
                     templatename=space_name,
                     gridname=pg,
                     xy=space_origin,
                     template_libname=space_libname)
    ]
    devname_bnd_left = ['nmos4_fast_left', 'pmos4_fast_left']
    devname_bnd_right = ['nmos4_fast_right', 'pmos4_fast_right']
    transform_bnd_left = ['R0', 'MX']
    transform_bnd_right = ['R0', 'MX']

    for i in range(1, num_space_sar):
        if i % 2 == 0:
            ispace_sar.append(
                laygen.relplace(name="I" + objectname_pfix + 'SPSAR' + str(i),
                                templatename=space_name,
                                gridname=pg,
                                refinstname=ispace_sar[-1].name,
                                direction='top',
                                transform='R0',
                                template_libname=space_libname))
            devname_bnd_left += ['nmos4_fast_left', 'pmos4_fast_left']
            devname_bnd_right += ['nmos4_fast_right', 'pmos4_fast_right']
            transform_bnd_left += ['R0', 'MX']
            transform_bnd_right += ['R0', 'MX']
        else:
            ispace_sar.append(
                laygen.relplace(name="I" + objectname_pfix + 'SPSAR' + str(i),
                                templatename=space_name,
                                gridname=pg,
                                refinstname=ispace_sar[-1].name,
                                direction='top',
                                transform='MX',
                                template_libname=space_libname))
            devname_bnd_left += ['pmos4_fast_left', 'nmos4_fast_left']
            devname_bnd_right += ['pmos4_fast_right', 'nmos4_fast_right']
            transform_bnd_left += ['R0', 'MX']
            transform_bnd_right += ['R0', 'MX']

    m_bnd = int(space_xy[0] / tbnd_bottom.size[0])
    [bnd_bottom, bnd_top, bnd_left, bnd_right] \
        = laygenhelper.generate_boundary(laygen, objectname_pfix='BNDSAR0', placement_grid=pg,
                            devname_bottom=['boundary_bottomleft', 'boundary_bottom', 'boundary_bottomright'],
                            shape_bottom=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_top=['boundary_topleft', 'boundary_top', 'boundary_topright'],
                            shape_top=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_left=devname_bnd_left,
                            transform_left=transform_bnd_left,
                            devname_right=devname_bnd_right,
                            transform_right=transform_bnd_right,
                            origin=origin)

    #vddsamp cap
    num_space_samp = num_space_tot - num_space_sar - 1
    space_origin = origin + laygen.get_template_size(
        'boundary_bottomleft', pg) * np.array([1, (3 + 2 * num_space_sar)])
    ispace_samp = [
        laygen.place(name="I" + objectname_pfix + 'SPSAMP0',
                     templatename=space_name,
                     gridname=pg,
                     xy=space_origin,
                     template_libname=space_libname)
    ]
    devname_bnd_left = ['nmos4_fast_left', 'pmos4_fast_left']
    devname_bnd_right = ['nmos4_fast_right', 'pmos4_fast_right']
    transform_bnd_left = ['R0', 'MX']
    transform_bnd_right = ['R0', 'MX']

    for i in range(1, num_space_samp):
        if i % 2 == 0:
            ispace_samp.append(
                laygen.relplace(name="I" + objectname_pfix + 'SPSAMP' + str(i),
                                templatename=space_name,
                                gridname=pg,
                                refinstname=ispace_samp[-1].name,
                                direction='top',
                                transform='R0',
                                template_libname=space_libname))
            devname_bnd_left += ['nmos4_fast_left', 'pmos4_fast_left']
            devname_bnd_right += ['nmos4_fast_right', 'pmos4_fast_right']
            transform_bnd_left += ['R0', 'MX']
            transform_bnd_right += ['R0', 'MX']
        else:
            ispace_samp.append(
                laygen.relplace(name="I" + objectname_pfix + 'SPSAMP' + str(i),
                                templatename=space_name,
                                gridname=pg,
                                refinstname=ispace_samp[-1].name,
                                direction='top',
                                transform='MX',
                                template_libname=space_libname))
            devname_bnd_left += ['pmos4_fast_left', 'nmos4_fast_left']
            devname_bnd_right += ['pmos4_fast_right', 'nmos4_fast_right']
            transform_bnd_left += ['R0', 'MX']
            transform_bnd_right += ['R0', 'MX']

    m_bnd = int(space_xy[0] / tbnd_bottom.size[0])
    [bnd_bottom, bnd_top, bnd_left, bnd_right] \
        = laygenhelper.generate_boundary(laygen, objectname_pfix='BNDSAMP0', placement_grid=pg,
                            devname_bottom=['boundary_bottomleft', 'boundary_bottom', 'boundary_bottomright'],
                            shape_bottom=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_top=['boundary_topleft', 'boundary_top', 'boundary_topright'],
                            shape_top=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_left=devname_bnd_left,
                            transform_left=transform_bnd_left,
                            devname_right=devname_bnd_right,
                            transform_right=transform_bnd_right,
                            origin=space_origin-laygen.get_template_size('boundary_bottomleft', pg))
    #vdd/vss
    #m3
    rvdd_sar_xy_m3 = []
    rvss_sar_xy_m3 = []
    space_template = laygen.templates.get_template(space_name, workinglib)
    space_pins = space_template.pins
    space_origin_phy = laygen.get_inst_bbox_phygrid(ispace_sar[0].name)[0]
    vddcnt = 0
    vsscnt = 0
    for pn, p in space_pins.items():
        if pn.startswith('VDD'):
            pxy = space_origin_phy + np.array(
                [p['xy'][0], p['xy'][1] * np.array([1, num_space_sar])])
            pxy[1][1] = y_vddsar_lower_max
            laygen.add_rect(None, pxy, laygen.layers['metal'][3])
            rvdd_sar_xy_m3.append(
                laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick,
                                                      xy0=pxy[0],
                                                      xy1=pxy[1]))
            vddcnt += 1
        if pn.startswith('VSS'):
            pxy = space_origin_phy + np.array(
                [p['xy'][0], p['xy'][1] * np.array([1, num_space_sar])])
            pxy[1][1] = y_vddsar_lower_max
            laygen.add_rect(None, pxy, laygen.layers['metal'][3])
            rvss_sar_xy_m3.append(
                laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick,
                                                      xy0=pxy[0],
                                                      xy1=pxy[1]))
            vsscnt += 1
    rvdd_samp_xy_m3 = []
    rvss_samp_xy_m3 = []
    space_template = laygen.templates.get_template(space_name, workinglib)
    space_pins = space_template.pins
    space_origin_phy = laygen.get_inst_bbox_phygrid(ispace_samp[0].name)[0]
    vddcnt = 0
    vsscnt = 0
    for pn, p in space_pins.items():
        if pn.startswith('VDD'):
            pxy = space_origin_phy + np.array(
                [p['xy'][0], p['xy'][1] * np.array([1, num_space_samp])])
            laygen.add_rect(None, pxy, laygen.layers['metal'][3])
            rvdd_samp_xy_m3.append(
                laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick,
                                                      xy0=pxy[0],
                                                      xy1=pxy[1]))
            vddcnt += 1
        if pn.startswith('VSS'):
            pxy = space_origin_phy + np.array(
                [p['xy'][0], p['xy'][1] * np.array([1, num_space_samp])])
            laygen.add_rect(None, pxy, laygen.layers['metal'][3])
            rvss_samp_xy_m3.append(
                laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick,
                                                      xy0=pxy[0],
                                                      xy1=pxy[1]))
            vsscnt += 1
    #m4
    input_rails_xy = [rvdd_samp_xy_m3, rvss_samp_xy_m3]
    rvdd_samp_m4, rvss_samp_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_M4_SAMP_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VDDSAMP', 'VSSSAMP'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    input_rails_xy = [rvdd_sar_xy_m3, rvss_sar_xy_m3]
    rvdd_sar_m4, rvss_sar_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_M4_SAR_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VDDSAR', 'VSSSAR'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    #m5
    input_rails_rect = [rvdd_samp_m4, rvss_samp_m4]
    rvdd_samp_m5, rvss_samp_m5 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M5_SAMP',
        layer=laygen.layers['metal'][5],
        gridname=rg_m4m5_thick,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    input_rails_rect = [rvdd_sar_m4, rvss_sar_m4]
    rvdd_sar_m5, rvss_sar_m5 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M5_SAR',
        layer=laygen.layers['metal'][5],
        gridname=rg_m4m5_thick,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)

    #m6 (extract VDD/VSS grid from tisar and make power pins)
    rg_m5m6_sar_vdd = 'route_M5_M6_thick_temp_tisar_sar_vdd'
    laygenhelper.generate_grids_from_xy(laygen,
                                        gridname_input=rg_m5m6_thick,
                                        gridname_output=rg_m5m6_sar_vdd,
                                        xy=vddsar_xy,
                                        xy_grid_type='ygrid')
    input_rails_rect = [rvdd_sar_m5]
    [rvdd_sar_m6] = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_SAR_',
        layer=laygen.layers['pin'][6],
        gridname=rg_m5m6_sar_vdd,
        netnames=['VDDSAR'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=True,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)

    rg_m5m6_sar_vss = 'route_M5_M6_thick_temp_tisar_sar_vss'
    laygenhelper.generate_grids_from_xy(laygen,
                                        gridname_input=rg_m5m6_thick,
                                        gridname_output=rg_m5m6_sar_vss,
                                        xy=vsssar_xy,
                                        xy_grid_type='ygrid')
    input_rails_rect = [rvss_sar_m5]
    [rvss_sar_m6] = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_SAR_',
        layer=laygen.layers['pin'][6],
        gridname=rg_m5m6_sar_vss,
        netnames=['VSS:'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=True,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)

    rg_m5m6_samp = 'route_M5_M6_thick_temp_tisar_samp_vdd'
    laygenhelper.generate_grids_from_xy(laygen,
                                        gridname_input=rg_m5m6_thick,
                                        gridname_output=rg_m5m6_samp,
                                        xy=vddsamp_xy,
                                        xy_grid_type='ygrid')
    input_rails_rect = [rvdd_samp_m5]
    [rvdd_samp_m6] = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_SAMP_',
        layer=laygen.layers['pin'][6],
        gridname=rg_m5m6_samp,
        netnames=['VDDSAMP'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=True,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    rg_m5m6_samp = 'route_M5_M6_thick_temp_tisar_samp_vss'
    laygenhelper.generate_grids_from_xy(laygen,
                                        gridname_input=rg_m5m6_thick,
                                        gridname_output=rg_m5m6_samp,
                                        xy=vsssamp_xy,
                                        xy_grid_type='ygrid')
    input_rails_rect = [rvss_samp_m5]
    [rvss_samp_m6] = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_SAMP_',
        layer=laygen.layers['pin'][6],
        gridname=rg_m5m6_samp,
        netnames=['VSS:'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=True,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    '''
    rg_m5m6_clkd='route_M5_M6_thick_temp_tisar_clkd'
    laygenhelper.generate_grids_from_xy(laygen, gridname_input=rg_m5m6_thick, gridname_output=rg_m5m6_clkd, xy=vddclkd_xy + vssclkd_xy, xy_grid_type='ygrid')
    input_rails_rect = [rvdd_samp_m5, rvss_samp_m5]
    [rvdd_clkd_m6, rvss_clkd_m6] = laygenhelper.generate_power_rails_from_rails_rect(laygen, routename_tag='_M6_CLKD_', 
                            layer=laygen.layers['pin'][6], gridname=rg_m5m6_clkd, netnames=['VDDSAMP', 'VSS:'], direction='x', 
                            input_rails_rect=input_rails_rect, generate_pin=True, overwrite_start_coord=None, overwrite_end_coord=None,
                            offset_start_index=0, offset_end_index=0)
    '''
    print(num_space_sar, num_space_samp)

    yamlfile_output = "adc_sar_size.yaml"
    #write to file
    with open(yamlfile_output, 'r') as stream:
        outdict = yaml.load(stream)
    outdict['num_space_sar'] = num_space_sar
    outdict['num_space_samp'] = num_space_samp
    with open(yamlfile_output, 'w') as stream:
        yaml.dump(outdict, stream)
Ejemplo n.º 5
0
def generate_samp(laygen,
                  objectname_pfix,
                  workinglib,
                  placement_grid='placement_basic',
                  routing_grid_m4m5='route_M4_M5_basic_thick',
                  power_grid_m3m4='route_M3_M4_basic_thick',
                  power_grid_m4m5='route_M4_M5_thick',
                  power_grid_m5m6='route_M5_M6_thick',
                  origin=np.array([0, 0])):
    """generate a sampler with clock buffers. used when AnalogMOS is not available
    """
    #variable/cell namings
    pg = placement_grid
    rg45bt = routing_grid_m4m5
    pg34bt = power_grid_m3m4
    pg45t = power_grid_m4m5
    pg56t = power_grid_m5m6

    # placement
    core_origin = origin + laygen.get_xy(
        obj=laygen.get_template(name='boundary_bottomleft'), gridname=pg)
    # sampler body
    isamp = laygen.relplace(name=None,
                            templatename='sarsamp_body',
                            gridname=pg,
                            template_libname=workinglib,
                            transform='R0',
                            xy=core_origin)
    # clock buffer
    if tgate == True:
        ibuf = laygen.relplace(name=None,
                               templatename='sarsamp_buf',
                               gridname=pg,
                               refobj=isamp,
                               direction='top',
                               template_libname=workinglib,
                               transform='MX')
    else:
        ibuf = laygen.relplace(name=None,
                               templatename='sarsamp_buf',
                               gridname=pg,
                               refobj=isamp,
                               direction='top',
                               template_libname=workinglib,
                               transform='R0')
    # boundaries
    a = laygen.get_xy(obj=laygen.get_template(name='sarsamp_body',
                                              libname=workinglib),
                      gridname=pg)[0]
    b = laygen.get_xy(obj=laygen.get_template(name='boundary_bottom'),
                      gridname=pg)[0]
    m_bnd = int(a / b)
    if tgate == True:
        devname_bnd_left = ['nmos4_fast_left', 'pmos4_fast_left'
                            ] + ['pmos4_fast_left', 'nmos4_fast_left']
        devname_bnd_right = ['nmos4_fast_right', 'pmos4_fast_right'
                             ] + ['pmos4_fast_right', 'nmos4_fast_right']
        transform_bnd_left = ['R0', 'MX'] + ['MX', 'R0']
        transform_bnd_right = ['R0', 'MX'] + ['MX', 'R0']
    else:
        devname_bnd_left = ['nmos4_fast_left', 'nmos4_fast_left'
                            ] + ['nmos4_fast_left', 'pmos4_fast_left']
        devname_bnd_right = ['nmos4_fast_right', 'nmos4_fast_right'
                             ] + ['nmos4_fast_right', 'pmos4_fast_right']
        transform_bnd_left = ['R0', 'MX'] + ['R0', 'MX']
        transform_bnd_right = ['R0', 'MX'] + ['R0', 'MX']
    [bnd_bottom, bnd_top, bnd_left, bnd_right] \
        = laygenhelper.generate_boundary(laygen, objectname_pfix='BND0', placement_grid=pg,
                            devname_bottom=['boundary_bottomleft', 'boundary_bottom', 'boundary_bottomright'],
                            shape_bottom=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_top=['boundary_topleft', 'boundary_top', 'boundary_topright'],
                            shape_top=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
                            devname_left=devname_bnd_left,
                            transform_left=transform_bnd_left,
                            devname_right=devname_bnd_right,
                            transform_right=transform_bnd_right,
                            origin=origin)

    # route
    x_center=int((laygen.get_inst_bbox(name=ibuf.name, gridname=rg45bt, sort=True)[1][0] \
                  -laygen.get_inst_bbox(name=ibuf.name, gridname=rg45bt, sort=True)[0][0])/2\
                  +laygen.get_inst_bbox(name=ibuf.name, gridname=rg45bt, sort=True)[0][0])
    y_top = int(
        laygen.get_inst_bbox(name=ibuf.name, gridname=rg45bt, sort=True)[1][1])
    #in
    xy0 = laygen.get_inst_pin_xy(name=isamp.name,
                                 pinname='IP',
                                 gridname=rg45bt,
                                 sort=True)[0]
    xy1 = [x_center - 3, y_top]
    rh0, rinp0 = laygen.route_hv(xy0=xy0, xy1=xy1, gridname0=rg45bt)
    xy0 = laygen.get_inst_pin_xy(name=isamp.name,
                                 pinname='IM',
                                 gridname=rg45bt,
                                 sort=True)[0]
    xy1 = [x_center + 3, y_top]
    rh0, rinn0 = laygen.route_hv(xy0=xy0, xy1=xy1, gridname0=rg45bt)
    #out
    xy0 = laygen.get_inst_pin_xy(name=isamp.name,
                                 pinname='OP',
                                 gridname=rg45bt,
                                 sort=True)[0]
    xy1 = [x_center - 3, 0]
    rh0, routp0 = laygen.route_hv(xy0=xy0, xy1=xy1, gridname0=rg45bt)
    xy0 = laygen.get_inst_pin_xy(name=isamp.name,
                                 pinname='OM',
                                 gridname=rg45bt,
                                 sort=True)[0]
    xy1 = [x_center + 3, 0]
    rh0, routn0 = laygen.route_hv(xy0=xy0, xy1=xy1, gridname0=rg45bt)
    #en
    xy0 = laygen.get_inst_pin_xy(name=ibuf.name,
                                 pinname='OUT_SW',
                                 gridname=rg45bt,
                                 sort=True)[0]
    xy1 = laygen.get_inst_pin_xy(name=isamp.name,
                                 pinname='EN',
                                 gridname=rg45bt,
                                 sort=True)[0]
    rh0, rckpg0, rh1 = laygen.route_hvh(xy0=xy0,
                                        xy1=xy1,
                                        track_x=x_center - 1,
                                        gridname0=rg45bt)
    rh0, rv0, rh1 = laygen.route_hvh(xy0=xy0,
                                     xy1=xy1,
                                     track_x=x_center + 1,
                                     gridname0=rg45bt)
    #enb
    if tgate == True:
        xy0 = laygen.get_inst_pin_xy(name=ibuf.name,
                                     pinname='out_int<0>',
                                     gridname=rg45bt,
                                     sort=True)[0]
        xy1 = laygen.get_inst_pin_xy(name=isamp.name,
                                     pinname='ENB',
                                     gridname=rg45bt,
                                     sort=True)[0]
        rh0, rckint0, rh1 = laygen.route_hvh(xy0=xy0,
                                             xy1=xy1,
                                             track_x=x_center - 2,
                                             gridname0=rg45bt)
        rh0, rv0, rh1 = laygen.route_hvh(xy0=xy0,
                                         xy1=xy1,
                                         track_x=x_center + 2,
                                         gridname0=rg45bt)
    #ckin
    xy0 = laygen.get_inst_pin_xy(name=ibuf.name,
                                 pinname='IN',
                                 gridname=rg45bt,
                                 sort=True)[0]
    xy1 = [xy0[0], y_top]
    rh0, rckin0 = laygen.route_hv(xy0=xy0, xy1=xy1, gridname0=rg45bt)
    #ckout
    xy0 = laygen.get_inst_pin_xy(name=ibuf.name,
                                 pinname='OUT_BUF',
                                 gridname=rg45bt,
                                 sort=True)[0]
    xy1 = [x_center, 0]
    rh0, rckout0 = laygen.route_hv(xy0=xy0, xy1=xy1, gridname0=rg45bt)

    # signal pins
    for p, r in zip(['inp', 'inn', 'outp', 'outn', 'ckin', 'ckout', 'ckpg'],
                    [rinp0, rinn0, routp0, routn0, rckin0, rckout0, rckpg0]):
        laygen.pin(name=p,
                   layer=laygen.layers['pin'][5],
                   refobj=r,
                   gridname=rg45bt)

    #vdd/vss - route
    #samp_m3_xy
    rvss_samp_m3 = [[], []]
    for pn, p in laygen.get_inst(isamp.name).pins.items():
        if pn.startswith('VSSL'):
            xy = laygen.get_inst_pin_xy(name=isamp.name,
                                        pinname=pn,
                                        gridname=pg34bt,
                                        sort=True)
            rvss_samp_m3[0].append(xy)
        if pn.startswith('VSSR'):
            xy = laygen.get_inst_pin_xy(name=isamp.name,
                                        pinname=pn,
                                        gridname=pg34bt,
                                        sort=True)
            rvss_samp_m3[1].append(xy)
    #samp_m4
    rvss_samp_m4 = [None, None]
    input_rails_xy = [rvss_samp_m3[0]]
    rvss_samp_m4[0] = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_SAMPL_M4_',
        layer=laygen.layers['metal'][4],
        gridname=pg34bt,
        netnames=['VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=-1)[0]
    input_rails_xy = [rvss_samp_m3[1]]
    rvss_samp_m4[1] = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_SAMPR_M4_',
        layer=laygen.layers['metal'][4],
        gridname=pg34bt,
        netnames=['VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=-1)[0]
    #buf_m3_xy
    rvdd_buf_m3 = [[], []]
    rvss_buf_m3 = [[], []]
    for pn, p in laygen.get_inst(ibuf.name).pins.items():
        if pn.startswith('VSSL'):
            xy = laygen.get_inst_pin_xy(name=ibuf.name,
                                        pinname=pn,
                                        gridname=pg34bt,
                                        sort=True)
            rvss_buf_m3[0].append(xy)
        if pn.startswith('VSSR'):
            xy = laygen.get_inst_pin_xy(name=ibuf.name,
                                        pinname=pn,
                                        gridname=pg34bt,
                                        sort=True)
            rvss_buf_m3[1].append(xy)
        if pn.startswith('VDDL'):
            xy = laygen.get_inst_pin_xy(name=ibuf.name,
                                        pinname=pn,
                                        gridname=pg34bt,
                                        sort=True)
            rvdd_buf_m3[0].append(xy)
        if pn.startswith('VDDR'):
            xy = laygen.get_inst_pin_xy(name=ibuf.name,
                                        pinname=pn,
                                        gridname=pg34bt,
                                        sort=True)
            rvdd_buf_m3[1].append(xy)
    #buf_m4
    rvss_buf_m4 = [None, None]
    rvdd_buf_m4 = [None, None]
    input_rails_xy = [rvdd_buf_m3[0], rvss_buf_m3[0]]
    rvdd_buf_m4[0], rvss_buf_m4[
        0] = laygenhelper.generate_power_rails_from_rails_xy(
            laygen,
            routename_tag='_BUFL_M4_',
            layer=laygen.layers['metal'][4],
            gridname=pg34bt,
            netnames=['VDD', 'VSS'],
            direction='x',
            input_rails_xy=input_rails_xy,
            generate_pin=False,
            overwrite_start_coord=None,
            overwrite_end_coord=None,
            offset_start_index=1,
            offset_end_index=0)
    input_rails_xy = [rvdd_buf_m3[1], rvss_buf_m3[1]]
    rvdd_buf_m4[1], rvss_buf_m4[
        1] = laygenhelper.generate_power_rails_from_rails_xy(
            laygen,
            routename_tag='_BUFR_M4_',
            layer=laygen.layers['metal'][4],
            gridname=pg34bt,
            netnames=['VDD', 'VSS'],
            direction='x',
            input_rails_xy=input_rails_xy,
            generate_pin=False,
            overwrite_start_coord=None,
            overwrite_end_coord=None,
            offset_start_index=1,
            offset_end_index=0)
    #m4
    rvss_m4 = [
        rvss_samp_m4[0] + rvss_buf_m4[0], rvss_samp_m4[1] + rvss_buf_m4[1]
    ]
    rvdd_m4 = rvdd_buf_m4
    #m5
    rvss_m5 = [None, None]
    rvdd_m5 = [None, None]
    input_rails_rect = [rvdd_m4[0], rvss_m4[0]]
    rvdd_m5[0], rvss_m5[0] = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='L_M5_',
        layer=laygen.layers['metal'][5],
        gridname=pg45t,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    input_rails_rect = [rvdd_m4[1], rvss_m4[1]]
    rvdd_m5[1], rvss_m5[1] = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='R_M5_',
        layer=laygen.layers['metal'][5],
        gridname=pg45t,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    #m6
    input_rails_rect = [rvdd_m5[0] + rvdd_m5[1], rvss_m5[0] + rvss_m5[1]]
    x1 = laygen.get_inst_bbox(
        name=ibuf.name, gridname=pg56t)[1][0] + laygen.get_xy(
            obj=laygen.get_template(name='nmos4_fast_left'), gridname=pg56t)[0]
    rvdd_m6, rvss_m6 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_',
        layer=laygen.layers['metal'][6],
        gridname=pg56t,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=x1,
        offset_start_index=0,
        offset_end_index=0)
    #trimming and pinning
    x1_phy = laygen.get_inst_bbox(name=ibuf.name)[1][0] + laygen.get_xy(
        obj=laygen.get_template(name='nmos4_fast_left'))[0]
    for r in rvdd_m6:
        r.xy1[0] = x1_phy
        p = laygen.pin(name='VDD_M6_' + r.name,
                       layer=laygen.layers['pin'][6],
                       refobj=r,
                       gridname=pg56t,
                       netname='VDD')
        p.xy1[0] = x1_phy
    for r in rvss_m6:
        r.xy1[0] = x1_phy
        p = laygen.pin(name='VSS_M6_' + r.name,
                       layer=laygen.layers['pin'][6],
                       refobj=r,
                       gridname=pg56t,
                       netname='VSS')
        p.xy1[0] = x1_phy
Ejemplo n.º 6
0
def generate_serializer(laygen, objectname_pfix, templib_logic, placement_grid, routing_grid_m2m3,
                          routing_grid_m4m5, num_ser=8, num_ser_3rd=4, m_ser=1, origin=np.array([0, 0])):
    export_dict = {'boundaries': {'lib_name': 'ge_tech_logic_templates',
                                  'lr_width': 8,
                                  'tb_height': 0.5},
                   'cells': {cell_name: {'cell_name': cell_name,
                                                 'lib_name': workinglib,
                                                 'size': [40, 1]}},
                   'spaces': [{'cell_name': 'space_4x',
                               'lib_name': 'ge_tech_logic_templates',
                               'num_col': 4},
                              {'cell_name': 'space_2x',
                               'lib_name': 'ge_tech_logic_templates',
                               'num_col': 2}],
                   'tech_params': {'col_pitch': 0.09,
                                   'directions': ['x', 'y', 'x', 'y'],
                                   'height': 0.96,
                                   'layers': [2, 3, 4, 5],
                                   'spaces': [0.064, 0.05, 0.05, 0.05],
                                   'widths': [0.032, 0.04, 0.04, 0.04]}}
    export_ports = dict()
    pg = placement_grid

    rg_m2m3 = routing_grid_m2m3
    rg_m4m5 = routing_grid_m4m5

    sub_ser = int(num_ser/2)
    ser_name = 'ser_2Nto1_'+str(num_ser)+'to1'
    ser_3rd_name = 'ser_'+str(num_ser_3rd)+'to1'
    ser_overall = int(num_ser * num_ser_3rd)
    # placement
    iser_3rd=[]
    for i in range(num_ser):
        if i==0:
            iser_3rd.append(laygen.place(name = "I" + objectname_pfix + 'SER3rd'+str(i), templatename = ser_3rd_name,
            gridname = pg, xy=origin, transform="R0", shape=np.array([1,1]), template_libname = workinglib))
        else:
            iser_3rd.append(laygen.relplace(name = "I" + objectname_pfix + 'SER3rd'+str(i), templatename = ser_3rd_name,
            gridname = pg, refinstname = iser_3rd[-1].name, transform="R0", shape=np.array([1,1]), template_libname = workinglib, direction = 'top'))
            refi=iser_3rd[-1]
    iser_2stg=laygen.relplace(name = "I" + objectname_pfix + 'SER2stg', templatename = ser_name,
            gridname = pg, refinstname = refi.name, transform="MY", shape=np.array([1,1]), template_libname = workinglib, direction = 'top')

    #Internal Pins
    ser2Nto1_clkb_xy=laygen.get_inst_pin_xy(iser_2stg.name, 'CLKB', rg_m3m4)
    ser2Nto1_clk_xy=laygen.get_inst_pin_xy(iser_2stg.name, 'CLK', rg_m3m4)
    ser2Nto1_rst_xy=[]
    ser2Nto1_rst_xy45=[]
    for i in range(2):
        ser2Nto1_rst_xy.append(laygen.get_inst_pin_xy(iser_2stg.name, 'RST' + str(i), rg_m3m4))
        ser2Nto1_rst_xy45.append(laygen.get_inst_pin_xy(iser_2stg.name, 'RST' + str(i), rg_m4m5))
    ser2Nto1_out_xy=laygen.get_inst_pin_xy(iser_2stg.name, 'out', rg_m3m4)
    ser2Nto1_div_xy=laygen.get_inst_pin_xy(iser_2stg.name, 'divclk', rg_m3m4)
    ser2Nto1_in_xy=[]
    ser3rd_in_xy=[]
    ser3rd_rst_xy=[]
    ser3rd_rst_xy45=[]
    ser3rd_clk_xy=[]
    ser3rd_out_xy=[]
    for i in range(num_ser):
        ser2Nto1_in_xy.append(laygen.get_inst_pin_xy(iser_2stg.name, 'in<' + str(i) + '>', rg_m3m4))
        ser3rd_rst_xy.append(laygen.get_inst_pin_xy(iser_3rd[i].name, 'RST', rg_m3m4))
        ser3rd_rst_xy45.append(laygen.get_inst_pin_xy(iser_3rd[i].name, 'RST', rg_m4m5))
        ser3rd_clk_xy.append(laygen.get_inst_pin_xy(iser_3rd[i].name, 'clk_in', rg_m3m4))
        ser3rd_out_xy.append(laygen.get_inst_pin_xy(iser_3rd[i].name, 'out', rg_m3m4))
        for j in range(num_ser_3rd):
            ser3rd_in_xy.append(laygen.get_inst_pin_xy(iser_3rd[i].name, 'in<' + str(j) + '>', rg_m3m4))
    print(ser3rd_in_xy[10])

    # Route
    for i in range(num_ser):
        [rh0, rv0, rh1] = laygen.route_hvh(laygen.layers['metal'][4], laygen.layers['metal'][3], 
                ser3rd_out_xy[i][0], ser2Nto1_in_xy[i][0], ser3rd_out_xy[i][0][0]+16+i, rg_m3m4)
        via_out = laygen.via(None, ser3rd_out_xy[i][0], gridname=rg_m3m4)
        [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][3], laygen.layers['metal'][4], 
                ser2Nto1_div_xy[0], ser3rd_clk_xy[i][1], ser2Nto1_div_xy[0][1]-10, rg_m3m4)
        via_div = laygen.via(None, ser3rd_clk_xy[i][1], gridname=rg_m3m4)
        [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][3], laygen.layers['metal'][4], 
                ser2Nto1_rst_xy[0][0], ser3rd_rst_xy[i][1]-np.array([5,1]), ser2Nto1_rst_xy[0][0][1]-2, rg_m3m4,
                layerv1=laygen.layers['metal'][3], gridname1=rg_m3m4)
        [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][3], laygen.layers['metal'][4], 
                ser3rd_rst_xy[i][0], ser3rd_rst_xy[i][1]-np.array([5,1]), ser3rd_rst_xy[i][1][1], rg_m3m4,
                layerv1=laygen.layers['metal'][3], gridname1=rg_m3m4)
    #[rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][3], laygen.layers['metal'][4], 
    #            ser2Nto1_rst_xy[0][0], ser2Nto1_rst_xy45[0][0]-np.array([4,1]), ser2Nto1_rst_xy[0][1][1], rg_m3m4,
    #            layerv1=laygen.layers['metal'][5], gridname1=rg_m4m5)
    [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][3], laygen.layers['metal'][4], 
                ser2Nto1_rst_xy[1][0], ser2Nto1_rst_xy[1][1]-np.array([3,1]), ser2Nto1_rst_xy[1][1][1], rg_m3m4,
                layerv1=laygen.layers['metal'][3], gridname1=rg_m3m4)
    [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][3], laygen.layers['metal'][4], 
                ser2Nto1_rst_xy[0][0], ser2Nto1_rst_xy[1][1]-np.array([3,1]), ser2Nto1_rst_xy[0][0][1]-2, rg_m3m4,
                layerv1=laygen.layers['metal'][3], gridname1=rg_m3m4)

    #Pin
    #CLK_pin=laygen.pin(name='CLK', layer=laygen.layers['pin'][4], xy=ser2Nto1_clk_xy, gridname=rg_m3m4)
    rCLK=laygen.route(None, laygen.layers['metal'][4], xy0=ser2Nto1_clk_xy[0], xy1=ser2Nto1_clk_xy[1], gridname0=rg_m3m4)
    CLK_pin=laygen.boundary_pin_from_rect(rCLK, rg_m3m4, 'CLK', laygen.layers['pin'][4], size=0, direction='top', netname='CLK')
    export_ports = add_to_export_ports(export_ports, CLK_pin)
    #CLKB_pin=laygen.pin(name='CLKB', layer=laygen.layers['pin'][4], xy=ser2Nto1_clkb_xy, gridname=rg_m3m4)
    rCLKB=laygen.route(None, laygen.layers['metal'][4], xy0=ser2Nto1_clkb_xy[0], xy1=ser2Nto1_clkb_xy[1], gridname0=rg_m3m4)
    CLKB_pin=laygen.boundary_pin_from_rect(rCLKB, rg_m3m4, 'CLKB', laygen.layers['pin'][4], size=0, direction='top', netname='CLKB')
    export_ports = add_to_export_ports(export_ports, CLKB_pin)
    #out_pin=laygen.pin(name='out', layer=laygen.layers['pin'][4], xy=ser2Nto1_out_xy, gridname=rg_m3m4)
    rout=laygen.route(None, laygen.layers['metal'][4], xy0=ser2Nto1_out_xy[0]+np.array([-2,0]), xy1=ser2Nto1_out_xy[1]+np.array([-2,0]), gridname0=rg_m3m4)
    out_pin=laygen.boundary_pin_from_rect(rout, rg_m3m4, 'out', laygen.layers['pin'][4], size=0, direction='top', netname='out')
    export_ports = add_to_export_ports(export_ports, out_pin)
    #RST_pin=laygen.pin(name='RST', layer=laygen.layers['pin'][3], xy=ser2Nto1_rst_xy[1], netname='RST', gridname=rg_m3m4)
    rRST=laygen.route(None, laygen.layers['metal'][3], xy0=ser2Nto1_rst_xy[1][0], xy1=ser2Nto1_rst_xy[1][1], gridname0=rg_m3m4)
    RST_pin=laygen.boundary_pin_from_rect(rRST, rg_m3m4, 'RST', laygen.layers['pin'][3], size=0, direction='left', netname='RST')
    export_ports = add_to_export_ports(export_ports, RST_pin)

    for i in range(num_ser):
        for j in range(ser_overall):
            if j%num_ser==i:
                in_pin=laygen.pin(name='in<'+str(j)+'>', layer=laygen.layers['pin'][4], xy=ser3rd_in_xy[i*num_ser_3rd+int(j/num_ser)], gridname=rg_m3m4)
                export_ports = add_to_export_ports(export_ports, in_pin)

    # power pin
    pwr_dim=laygen.get_xy(obj=laygen.get_template(name='tap', libname=logictemplib), gridname=rg_m2m3)
    rvdd = []
    rvss = []
    print(int(pwr_dim[0]))
    for i in range(-2, int(pwr_dim[0]/2)*2-2):
        subser0_vdd_xy=laygen.get_inst_pin_xy(iser_3rd[0].name, 'VDD' + str(i), rg_m2m3)
        subser0_vss_xy=laygen.get_inst_pin_xy(iser_3rd[0].name, 'VSS' + str(i), rg_m2m3)
        subser1_vdd_xy=laygen.get_inst_pin_xy(iser_2stg.name, 'VDD' + str(i), rg_m2m3)
        subser1_vss_xy=laygen.get_inst_pin_xy(iser_2stg.name, 'VSS' + str(i), rg_m2m3)
        rvdd.append(laygen.route(None, laygen.layers['metal'][3], xy0=np.array([subser1_vdd_xy[1][0],0]), xy1=subser1_vdd_xy[1], gridname0=rg_m2m3))
        rvss.append(laygen.route(None, laygen.layers['metal'][3], xy0=np.array([subser1_vss_xy[1][0],0]), xy1=subser1_vss_xy[1], gridname0=rg_m2m3))
        VDD_pin=laygen.pin(name = 'VDD'+str(i), layer = laygen.layers['pin'][3], refobj = rvdd[-1], gridname=rg_m2m3, netname='VDD')
        export_ports = add_to_export_ports(export_ports, VDD_pin)
        VSS_pin=laygen.pin(name = 'VSS'+str(i), layer = laygen.layers['pin'][3], refobj = rvss[-1], gridname=rg_m2m3, netname='VSS')
        export_ports = add_to_export_ports(export_ports, VSS_pin)

    x1=laygen.get_template_size(ser_name, rg_m3m4_thick, workinglib)[0]
    rvss_m4_xy=[]
    rvdd_m4_xy=[]
    for i in range(num_ser):
        ref_xy=laygen.get_inst_xy(iser_3rd[i].name, rg_m3m4_thick)
        rvss_m4=laygen.route(None, laygen.layers['metal'][4], xy0=ref_xy, xy1=np.array([x1,ref_xy[1]]), gridname0=rg_m3m4_thick)
        rvdd_m4=laygen.route(None, laygen.layers['metal'][4], xy0=ref_xy-[0,1], xy1=np.array([x1,ref_xy[1]-1]), gridname0=rg_m3m4_thick)
        rvss_m4_xy.append(laygen.get_rect_xy(name=rvss_m4.name, gridname=rg_m4m5_thick))
        rvdd_m4_xy.append(laygen.get_rect_xy(name=rvdd_m4.name, gridname=rg_m4m5_thick))
    ser_xy=laygen.get_inst_xy(iser_2stg.name, rg_m3m4_thick)
    print(ser_xy)
    y1=laygen.get_template_size(ser_name, rg_m3m4_thick, workinglib)[1]
    rvss_2stg_m4=laygen.route(None, laygen.layers['metal'][4], xy0=np.array([0, ser_xy[1]+y1]), xy1=np.array([x1,ser_xy[1]+y1]), gridname0=rg_m3m4_thick)
    rvdd_2stg_m4=laygen.route(None, laygen.layers['metal'][4], xy0=np.array([0, ser_xy[1]+y1-1]), xy1=np.array([x1,ser_xy[1]-1+y1]), gridname0=rg_m3m4_thick)
    rvss_m4_xy.append(laygen.get_rect_xy(name=rvss_2stg_m4.name, gridname=rg_m4m5_thick))
    rvdd_m4_xy.append(laygen.get_rect_xy(name=rvdd_2stg_m4.name, gridname=rg_m4m5_thick))
    print(rvss_m4_xy)
    input_rails_xy = [rvss_m4_xy, rvdd_m4_xy]
    rvss_m5 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_SER_M5_', 
                layer=laygen.layers['metal'][5], gridname=rg_m4m5_thick, netnames=['VSS', 'VDD'], direction='y', 
                input_rails_xy=input_rails_xy, generate_pin=False, overwrite_start_coord=None, overwrite_end_coord=None,
                offset_start_index=0, offset_end_index=0)

    '''
    input_rails_xy=[]
    rvssr_m3_xy=[]
    rvddr_m3_xy=[]
    rvssl_m3_xy=[]
    rvddl_m3_xy=[]
    for i in range(-2, int(pwr_dim[0]/2)*2-2):
        if i%2==0:
            rvssr_m3_xy.append(laygen.get_rect_xy(name=rvss[i].name, gridname=rg_m3m4_thick))
            rvddr_m3_xy.append(laygen.get_rect_xy(name=rvdd[i].name, gridname=rg_m3m4_thick))
        else:
            rvssl_m3_xy.append(laygen.get_rect_xy(name=rvss[i].name, gridname=rg_m3m4_thick))
            rvddl_m3_xy.append(laygen.get_rect_xy(name=rvdd[i].name, gridname=rg_m3m4_thick))
    input_rails_xy = [rvssl_m3_xy, rvddl_m3_xy]
    rvssl_m4 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_CDRVL_M4_', 
                layer=laygen.layers['metal'][4], gridname=rg_m3m4_thick, netnames=['VSS', 'VDD'], direction='x', 
                input_rails_xy=input_rails_xy, generate_pin=False, overwrite_start_coord=None, overwrite_end_coord=None,
                offset_start_index=0, offset_end_index=0)
    input_rails_xy = [rvssr_m3_xy, rvddr_m3_xy]
    rvssr_m4 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_CDRVL_M4_', 
                layer=laygen.layers['metal'][4], gridname=rg_m3m4_thick, netnames=['VSS', 'VDD'], direction='x', 
                input_rails_xy=input_rails_xy, generate_pin=False, overwrite_start_coord=None, overwrite_end_coord=None,
                offset_start_index=0, offset_end_index=0)
    '''
    # export_dict will be written to a yaml file for using with StdCellBase
    size_x=laygen.templates.get_template(ser_name, workinglib).xy[1][0]
    size_y=laygen.templates.get_template(ser_name, workinglib).xy[1][1] + num_ser*laygen.templates.get_template(ser_3rd_name, workinglib).xy[1][1]

    export_dict['cells'][cell_name]['ports'] = export_ports
    export_dict['cells'][cell_name]['size_um'] = [float(int(size_x*1e3))/1e3, float(int(size_y*1e3))/1e3]
    #export_dict['cells']['clk_dis_N_units']['num_ways'] = num_ways
    # print('export_dict:')
    # pprint(export_dict)
    # save_path = path.dirname(path.dirname(path.realpath(__file__))) + '/dsn_scripts/'
    save_path = 'ser_generated' 
    #if path.isdir(save_path) == False:
    #    mkdir(save_path)
    with open(save_path + '_int.yaml', 'w') as f:
        yaml.dump(export_dict, f, default_flow_style=False)
def generate_sarafe_nsw(laygen,
                        objectname_pfix,
                        workinglib,
                        placement_grid,
                        routing_grid_m2m3_thick,
                        routing_grid_m3m4_thick,
                        routing_grid_m4m5_thick,
                        routing_grid_m5m6,
                        routing_grid_m5m6_thick,
                        routing_grid_m5m6_basic_thick,
                        routing_grid_m6m7,
                        num_bits=8,
                        num_bits_vertical=6,
                        num_cdrv_output_routes=2,
                        m_sa=8,
                        origin=np.array([0, 0])):
    """generate sar analog frontend """
    pg = placement_grid

    rg_m3m4_thick = routing_grid_m3m4_thick
    rg_m5m6 = routing_grid_m5m6
    rg_m6m7 = routing_grid_m6m7

    tap_name = 'tap'
    cdrv_name = 'capdrv_nsw_array'
    #cdac_name='capdac_'+str(num_bits)+'b'
    cdac_name = 'capdac'
    sa_name = 'doubleSA_pmos'

    # placement
    xy0 = origin + (laygen.get_template_size(
        cdrv_name, gridname=pg, libname=workinglib) * np.array([1, 0]))
    icdrvl = laygen.place(name="I" + objectname_pfix + 'CDRVL0',
                          templatename=cdrv_name,
                          gridname=pg,
                          xy=xy0,
                          template_libname=workinglib,
                          transform='MY')
    icdrvr = laygen.place(name="I" + objectname_pfix + 'CDRVR0',
                          templatename=cdrv_name,
                          gridname=pg,
                          xy=xy0,
                          template_libname=workinglib)
    xy0 = origin + laygen.get_template_size(cdrv_name, gridname=pg, libname=workinglib)*np.array([0, 1]) \
                 + laygen.get_template_size(sa_name, gridname=pg, libname=workinglib) * np.array([0, 1])
    isa = laygen.place(name="I" + objectname_pfix + 'SA0',
                       templatename=sa_name,
                       gridname=pg,
                       xy=xy0,
                       template_libname=workinglib,
                       transform='MX')
    xy0 = origin + laygen.get_template_size(cdrv_name, gridname=pg, libname=workinglib)*np.array([0, 1]) \
                 + laygen.get_template_size(sa_name, gridname=pg, libname=workinglib) * np.array([0, 1]) \
                 + laygen.get_template_size(cdac_name, gridname=pg, libname=workinglib)*np.array([1, 0])
    icdacl = laygen.place(name="I" + objectname_pfix + 'CDACL0',
                          templatename=cdac_name,
                          gridname=pg,
                          xy=xy0,
                          template_libname=workinglib,
                          transform='MY')
    xy0 = origin + laygen.get_template_size(cdrv_name, gridname=pg, libname=workinglib)*np.array([2, 1]) \
                 + laygen.get_template_size(sa_name, gridname=pg, libname=workinglib) * np.array([0, 1]) \
                 - laygen.get_template_size(cdac_name, gridname=pg, libname=workinglib)*np.array([1, 0])
    icdacr = laygen.place(name="I" + objectname_pfix + 'CDACR0',
                          templatename=cdac_name,
                          gridname=pg,
                          xy=xy0,
                          template_libname=workinglib)

    # pin informations
    pdict_m3m4_thick = laygen.get_inst_pin_xy(None, None, rg_m3m4_thick)

    # internal pins
    icdrvl_vo_xy = []
    icdacl_i_xy = []
    icdacl_i2_xy = []
    icdrvr_vo_xy = []
    icdacr_i_xy = []
    icdacr_i2_xy = []

    icdrvl_vo_c0_xy = laygen.get_inst_pin_xy(icdrvl.name, 'VO_C0', rg_m5m6)
    icdacl_i_c0_xy = laygen.get_inst_pin_xy(icdacl.name, 'I_C0', rg_m5m6)
    icdrvr_vo_c0_xy = laygen.get_inst_pin_xy(icdrvr.name, 'VO_C0', rg_m5m6)
    icdacr_i_c0_xy = laygen.get_inst_pin_xy(icdacr.name, 'I_C0', rg_m5m6)
    for i in range(num_bits):
        icdacl_i_xy.append(
            laygen.get_inst_pin_xy(icdacl.name, 'I<' + str(i) + '>', rg_m4m5))
        icdacr_i_xy.append(
            laygen.get_inst_pin_xy(icdacr.name, 'I<' + str(i) + '>', rg_m4m5))
        if i >= num_bits_vertical:
            icdacl_i2_xy.append(
                laygen.get_inst_pin_xy(icdacl.name, 'I2<' + str(i) + '>',
                                       rg_m4m5))
            icdacr_i2_xy.append(
                laygen.get_inst_pin_xy(icdacr.name, 'I2<' + str(i) + '>',
                                       rg_m4m5))

    for j in range(num_cdrv_output_routes):
        for i in range(num_bits):
            icdrvl_vo_xy.append(
                laygen.get_inst_pin_xy(icdrvl.name,
                                       'VO' + str(j) + '<' + str(i) + '>',
                                       rg_m5m6))
            icdrvr_vo_xy.append(
                laygen.get_inst_pin_xy(icdrvr.name,
                                       'VO' + str(j) + '<' + str(i) + '>',
                                       rg_m5m6))

    #route
    #capdrv to capdac
    #y0 = origin[1] + laygen.get_template_size(cdrv_name, gridname=rg_m5m6, libname=workinglib)[1]-2 #refer to capdrv
    y0 = origin[1] + laygen.get_template_size(cdrv_name, gridname=rg_m4m5, libname=workinglib)[1] \
         + laygen.get_template_size(sa_name, gridname=rg_m4m5, libname=workinglib)[1]-4 #refer to sa
    [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                       laygen.layers['metal'][6],
                                       icdrvl_vo_c0_xy[0],
                                       icdacl_i_c0_xy[0],
                                       y0 + 1,
                                       rg_m5m6,
                                       layerv1=laygen.layers['metal'][5],
                                       gridname1=rg_m5m6)
    laygen.boundary_pin_from_rect(rv0,
                                  rg_m4m5,
                                  "VOL_C0",
                                  laygen.layers['pin'][5],
                                  size=4,
                                  direction='bottom',
                                  netname='VREF<1>')
    [rv0, rh0, rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                       laygen.layers['metal'][6],
                                       icdrvr_vo_c0_xy[0],
                                       icdacr_i_c0_xy[0],
                                       y0 + 1,
                                       rg_m5m6,
                                       layerv1=laygen.layers['metal'][5],
                                       gridname1=rg_m5m6)
    laygen.boundary_pin_from_rect(rv0,
                                  rg_m4m5,
                                  "VOR_C0",
                                  laygen.layers['pin'][5],
                                  size=4,
                                  direction='bottom',
                                  netname='VREF<1>')

    for j in range(num_cdrv_output_routes):
        for i in range(num_bits):
            if i in range(num_bits_vertical) and i % 2 == (num_bits_vertical +
                                                           1) % 2:
                #if not i%2==num_bits_vertical%2:
                [rv0l, rh0,
                 rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                         laygen.layers['metal'][4],
                                         icdrvl_vo_xy[i + j * num_bits][0],
                                         icdacl_i_xy[i][0],
                                         y0 - i - 1,
                                         rg_m4m5,
                                         layerv1=laygen.layers['metal'][3],
                                         gridname1=rg_m3m4)
                [rv0r, rh0,
                 rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                         laygen.layers['metal'][4],
                                         icdrvr_vo_xy[i + j * num_bits][0],
                                         icdacr_i_xy[i][0],
                                         y0 - i - 1,
                                         rg_m4m5,
                                         layerv1=laygen.layers['metal'][3],
                                         gridname1=rg_m3m4)
            else:
                [rv0l, rh0,
                 rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                         laygen.layers['metal'][6],
                                         icdrvl_vo_xy[i + j * num_bits][0],
                                         icdacl_i_xy[i][0],
                                         y0 - i - 1,
                                         rg_m5m6,
                                         layerv1=laygen.layers['metal'][5],
                                         gridname1=rg_m5m6)
                [rv0r, rh0,
                 rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                         laygen.layers['metal'][6],
                                         icdrvr_vo_xy[i + j * num_bits][0],
                                         icdacr_i_xy[i][0],
                                         y0 - i - 1,
                                         rg_m5m6,
                                         layerv1=laygen.layers['metal'][5],
                                         gridname1=rg_m5m6)
            laygen.boundary_pin_from_rect(rv0l,
                                          rg_m4m5,
                                          "VOL<" + str(i) + ">",
                                          laygen.layers['pin'][5],
                                          size=4,
                                          direction='bottom')
            laygen.boundary_pin_from_rect(rv0r,
                                          rg_m4m5,
                                          "VOR<" + str(i) + ">",
                                          laygen.layers['pin'][5],
                                          size=4,
                                          direction='bottom')
            #more routes for horizontal dacs
            if i >= num_bits_vertical:
                [rv0, rh0,
                 rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                         laygen.layers['metal'][4],
                                         icdrvl_vo_xy[i + j * num_bits][0],
                                         icdacl_i_xy[i][0],
                                         y0 + 2 + i - num_bits_vertical,
                                         rg_m4m5,
                                         layerv1=laygen.layers['metal'][5],
                                         gridname1=rg_m4m5)
                [rv0, rh0,
                 rv1] = laygen.route_vhv(laygen.layers['metal'][5],
                                         laygen.layers['metal'][4],
                                         icdrvr_vo_xy[i + j * num_bits][0],
                                         icdacr_i_xy[i][0],
                                         y0 + 2 + i - num_bits_vertical,
                                         rg_m4m5,
                                         layerv1=laygen.layers['metal'][5],
                                         gridname1=rg_m4m5)
                [rv0, rh0, rv1
                 ] = laygen.route_vhv(laygen.layers['metal'][5],
                                      laygen.layers['metal'][4],
                                      icdrvl_vo_xy[i + j * num_bits][0],
                                      icdacl_i2_xy[i - num_bits_vertical][0],
                                      y0 + 2 + i - num_bits_vertical,
                                      rg_m4m5,
                                      layerv1=laygen.layers['metal'][5],
                                      gridname1=rg_m4m5)
                [rv0, rh0, rv1
                 ] = laygen.route_vhv(laygen.layers['metal'][5],
                                      laygen.layers['metal'][4],
                                      icdrvr_vo_xy[i + j * num_bits][0],
                                      icdacr_i2_xy[i - num_bits_vertical][0],
                                      y0 + 2 + i - num_bits_vertical,
                                      rg_m4m5,
                                      layerv1=laygen.layers['metal'][5],
                                      gridname1=rg_m4m5)

    #vref
    rvref0 = laygen.route(None,
                          laygen.layers['metal'][4],
                          xy0=np.array([0, 0]),
                          xy1=np.array([0, 0]),
                          refinstname0=icdrvl.name,
                          refpinname0='VREF<0>',
                          gridname0=rg_m4m5,
                          refinstname1=icdrvr.name,
                          refpinname1='VREF<0>')
    rvref1 = laygen.route(None,
                          laygen.layers['metal'][4],
                          xy0=np.array([0, 0]),
                          xy1=np.array([0, 0]),
                          refinstname0=icdrvl.name,
                          refpinname0='VREF<1>',
                          gridname0=rg_m4m5,
                          refinstname1=icdrvr.name,
                          refpinname1='VREF<1>')
    rvref2 = laygen.route(None,
                          laygen.layers['metal'][4],
                          xy0=np.array([0, 0]),
                          xy1=np.array([0, 0]),
                          refinstname0=icdrvl.name,
                          refpinname0='VREF<2>',
                          gridname0=rg_m4m5,
                          refinstname1=icdrvr.name,
                          refpinname1='VREF<2>')
    #input pins
    #y0 = laygen.get_inst_pin_xy(icdrvl.name, 'EN0<0>', rg_m4m5, index=np.array([0, 0]), sort=True)[0][1]
    y0 = 0
    rclkb = laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=isa.name,
                         refpinname0='CLKB',
                         gridname0=rg_m4m5,
                         direction='y')
    routp = laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=isa.name,
                         refpinname0='OUTP',
                         gridname0=rg_m4m5,
                         direction='y')
    routm = laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=isa.name,
                         refpinname0='OUTM',
                         gridname0=rg_m4m5,
                         direction='y')
    #rosp=laygen.route(None, laygen.layers['metal'][3], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
    #                  refinstname0=isa.name, refpinname0='OSP', gridname0=rg_m2m3, direction='y')
    #rosm=laygen.route(None, laygen.layers['metal'][3], xy0=np.array([0, 0]), xy1=np.array([0, 0]),
    #                  refinstname0=isa.name, refpinname0='OSM', gridname0=rg_m2m3, direction='y')
    pdict_m3m4 = laygen.get_inst_pin_xy(None, None, rg_m3m4)
    yos=laygen.get_inst_xy(isa.name, rg_m3m4)[1] \
        - laygen.get_template_size(name=isa.cellname, gridname=rg_m3m4, libname=workinglib)[1]
    [rv0, rh0, rosp] = laygen.route_vhv(
        laygen.layers['metal'][3], laygen.layers['metal'][4],
        pdict_m3m4[isa.name]['OSP'][0],
        np.array([pdict_m3m4[isa.name]['OSP'][0][0] + m_sa, 0]), yos, rg_m3m4)
    [rv0, rh0, rosm] = laygen.route_vhv(
        laygen.layers['metal'][3], laygen.layers['metal'][4],
        pdict_m3m4[isa.name]['OSM'][0],
        np.array([pdict_m3m4[isa.name]['OSM'][0][0] - m_sa, 0]), yos, rg_m3m4)
    renl0 = []
    renl1 = []
    renl2 = []
    renr0 = []
    renr1 = []
    renr2 = []
    for i in range(num_bits):
        renl0.append(
            laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=icdrvl.name,
                         refpinname0='EN' + str(i) + '<0>',
                         gridname0=rg_m5m6,
                         direction='y'))
        renl1.append(
            laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=icdrvl.name,
                         refpinname0='EN' + str(i) + '<1>',
                         gridname0=rg_m5m6,
                         direction='y'))
        renl2.append(
            laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=icdrvl.name,
                         refpinname0='EN' + str(i) + '<2>',
                         gridname0=rg_m5m6,
                         direction='y'))
        renr0.append(
            laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=icdrvr.name,
                         refpinname0='EN' + str(i) + '<0>',
                         gridname0=rg_m5m6,
                         direction='y'))
        renr1.append(
            laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=icdrvr.name,
                         refpinname0='EN' + str(i) + '<1>',
                         gridname0=rg_m5m6,
                         direction='y'))
        renr2.append(
            laygen.route(None,
                         laygen.layers['metal'][5],
                         xy0=np.array([0, 0]),
                         xy1=np.array([0, 0]),
                         refinstname0=icdrvr.name,
                         refpinname0='EN' + str(i) + '<2>',
                         gridname0=rg_m5m6,
                         direction='y'))
    #inp/inm
    pdict_m3m4 = laygen.get_inst_pin_xy(None, None, rg_m3m4)
    outcnt = 0
    for pn in pdict_m3m4[icdacl.name]:
        if pn.startswith('O'):  #out pin
            outcnt += 1
    x0 = laygen.get_inst_xy(icdacl.name, rg_m3m4)[0] - 8
    x1 = laygen.get_inst_xy(icdacr.name, rg_m3m4)[0] + 8
    nrin_sa = 4  # number of M6 horizontal route stacks for cdac to sa
    nrin = 2**num_bits_vertical - 2 * nrin_sa  # number of M6 horizontal route stacks
    if nrin < 1:
        nrin = 2**num_bits_vertical - nrin_sa
    rinp = []
    rinm = []
    for i in range(nrin):
        xy0 = laygen.get_inst_pin_xy(icdacl.name,
                                     "O" + str(outcnt - 1 - i),
                                     rg_m3m4,
                                     index=np.array([0, 0]),
                                     sort=True)[0]
        r = laygen.route(None,
                         laygen.layers['metal'][4],
                         xy0=xy0,
                         xy1=np.array([x0, xy0[1]]),
                         gridname0=rg_m3m4)
        rinp.append(r)
        '''
        #additional routes for dummy for density rules; may not process portable
        for j in range(3):
            laygen.route(None, laygen.layers['metal'][6], xy0=xy0+np.array([0, 2*j+2]), xy1=np.array([x0, xy0[1]+2*j+2]), gridname0=rg_m5m6)
        '''
        xy0 = laygen.get_inst_pin_xy(icdacr.name,
                                     "O" + str(outcnt - 1 - i),
                                     rg_m3m4,
                                     index=np.array([0, 0]),
                                     sort=True)[1]
        r = laygen.route(None,
                         laygen.layers['metal'][4],
                         xy0=xy0,
                         xy1=np.array([x1, xy0[1]]),
                         gridname0=rg_m3m4)
        rinm.append(r)
        '''
        #additional routes for dummy for density rules; may not process portable
        for j in range(3):
            laygen.route(None, laygen.layers['metal'][6], xy0=xy0+np.array([0, 2*j+2]), xy1=np.array([x1, xy0[1]+2*j+2]), gridname0=rg_m5m6)
        '''

    for i in range(nrin_sa):
        xy0 = laygen.get_inst_pin_xy(icdacl.name,
                                     "O" + str(i),
                                     rg_m3m4,
                                     index=np.array([0, 0]),
                                     sort=True)[0]
        laygen.route(None,
                     laygen.layers['metal'][4],
                     xy0=xy0,
                     xy1=np.array([x0, xy0[1]]),
                     gridname0=rg_m4m5)
        for j in range(4):
            laygen.via(None, [x0 - 2 * j, xy0[1]], rg_m4m5)
        xy0 = laygen.get_inst_pin_xy(icdacr.name,
                                     "O" + str(i),
                                     rg_m3m4,
                                     index=np.array([0, 0]),
                                     sort=True)[1]
        laygen.route(None,
                     laygen.layers['metal'][4],
                     xy0=xy0,
                     xy1=np.array([x1, xy0[1]]),
                     gridname0=rg_m4m5)
        for j in range(4):
            laygen.via(None, [x1 + 2 * j, xy0[1]], rg_m4m5)
    xy0 = laygen.get_inst_pin_xy(isa.name,
                                 "INP",
                                 rg_m3m4,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    xy1 = laygen.get_inst_pin_xy(icdacl.name,
                                 "O" + str(nrin_sa - 1),
                                 rg_m4m5,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    for j in range(4):
        laygen.route(None,
                     laygen.layers['metal'][5],
                     xy0=np.array([x0 - 2 * j, xy0[1]]),
                     xy1=np.array([x0 - 2 * j, xy1[1]]),
                     gridname0=rg_m5m6)
    xy0 = laygen.get_inst_pin_xy(isa.name,
                                 "INM",
                                 rg_m4m5,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    xy1 = laygen.get_inst_pin_xy(icdacr.name,
                                 "O" + str(nrin_sa - 1),
                                 rg_m5m6,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    for j in range(4):
        laygen.route(None,
                     laygen.layers['metal'][5],
                     xy0=np.array([x1 + 2 * j, xy0[1]]),
                     xy1=np.array([x1 + 2 * j, xy1[1]]),
                     gridname0=rg_m5m6)
    #inp/inm - sa to capdac
    xy0 = laygen.get_inst_pin_xy(isa.name,
                                 "INP",
                                 rg_m4m5,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    xy1 = laygen.get_inst_pin_xy(isa.name,
                                 "INM",
                                 rg_m4m5,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    rsainp = laygen.route(None,
                          laygen.layers['metal'][4],
                          xy0=np.array([x0 - 8, xy0[1]]),
                          xy1=xy0,
                          gridname0=rg_m4m5)
    rsainm = laygen.route(None,
                          laygen.layers['metal'][4],
                          xy0=np.array([x1 + 8, xy1[1]]),
                          xy1=xy1,
                          gridname0=rg_m4m5)
    for j in range(4):
        laygen.via(None, [x0 - 2 * j, xy0[1]], rg_m4m5)
        laygen.via(None, [x1 + 2 * j, xy1[1]], rg_m4m5)
    x0 = laygen.get_inst_xy(icdacl.name, rg_m3m4)[0] - 1
    x1 = laygen.get_inst_xy(icdacr.name, rg_m3m4)[0] + 1
    xy0 = laygen.get_inst_pin_xy(isa.name,
                                 "INP",
                                 rg_m3m4,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    xy1 = laygen.get_inst_pin_xy(isa.name,
                                 "INM",
                                 rg_m3m4,
                                 index=np.array([0, 0]),
                                 sort=True)[0]
    laygen.route(None,
                 laygen.layers['metal'][4],
                 xy0=np.array([x0, xy0[1]]),
                 xy1=xy0,
                 gridname0=rg_m3m4,
                 via1=[[0, 0]])
    laygen.route(None,
                 laygen.layers['metal'][4],
                 xy0=np.array([x1, xy1[1]]),
                 xy1=xy1,
                 gridname0=rg_m3m4,
                 via1=[[0, 0]])

    #vdd/vss - route
    #cdrv_left_m4
    rvdd_cdrvl_m3 = []
    rvss_cdrvl_m3 = []
    for pn, p in pdict_m3m4_thick[icdrvl.name].items():
        if pn.startswith('VSSR'):
            rvss_cdrvl_m3.append(p)
    input_rails_xy = [rvss_cdrvl_m3]
    rvss_cdrvl_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_CDRVL_M4_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=0)
    rvss_cdrvl_m4 = rvss_cdrvl_m4[0]
    #cdrv_right_m4
    x1 = laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m3m4_thick)[0]\
         +laygen.get_template_size(name=icdrvr.cellname, gridname=rg_m3m4_thick, libname=workinglib)[0]
    rvdd_cdrvr_m3 = []
    rvss_cdrvr_m3 = []
    for pn, p in pdict_m3m4_thick[icdrvr.name].items():
        if pn.startswith('VSSR'):
            rvss_cdrvr_m3.append(p)
    input_rails_xy = [rvss_cdrvr_m3]
    rvss_cdrvr_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_CDRVR_M4_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=x1,
        offset_start_index=0,
        offset_end_index=0)
    rvss_cdrvr_m4 = rvss_cdrvr_m4[0]
    #sa_left_m4_m5
    rvdd_sal_m3 = []
    rvss_sal_m3 = []
    for pn, p in pdict_m3m4_thick[isa.name].items():
        if pn.startswith('VDDL'):
            rvdd_sal_m3.append(p)
        if pn.startswith('VSSL'):
            rvss_sal_m3.append(p)
    input_rails_xy = [rvdd_sal_m3, rvss_sal_m3]
    rvdd_sal_m4, rvss_sal_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_SAL_M4_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=None,
        offset_start_index=0,
        offset_end_index=-4)
    #input_rails_rect = [rvdd_sal_m4+rvdd_cdrvl_m4, rvss_sal_m4+rvss_cdrvl_m4]
    input_rails_rect = [rvdd_sal_m4, rvss_sal_m4 + rvss_cdrvl_m4]
    rvdd_sal_m5, rvss_sal_m5 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_SAL_M5_',
        layer=laygen.layers['metal'][5],
        gridname=rg_m4m5_thick,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=None,
        offset_start_index=1,
        offset_end_index=-6)
    #sa_right_m4_m5
    x1 = laygen.get_inst_xy(name=isa.name, gridname=rg_m3m4_thick)[0]\
         +laygen.get_template_size(name=isa.cellname, gridname=rg_m3m4_thick, libname=workinglib)[0]
    rvdd_sar_m3 = []
    rvss_sar_m3 = []
    for pn, p in pdict_m3m4_thick[isa.name].items():
        if pn.startswith('VDDR'):
            rvdd_sar_m3.append(p)
        if pn.startswith('VSSR'):
            rvss_sar_m3.append(p)
    input_rails_xy = [rvdd_sar_m3, rvss_sar_m3]
    rvdd_sar_m4, rvss_sar_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_SAR_M4_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=None,
        overwrite_end_coord=x1,
        offset_start_index=0,
        offset_end_index=-4)
    #input_rails_rect = [rvdd_sar_m4+rvdd_cdrvr_m4, rvss_sar_m4+rvss_cdrvr_m4]
    input_rails_rect = [rvdd_sar_m4, rvss_sar_m4 + rvss_cdrvr_m4]
    rvdd_sar_m5, rvss_sar_m5 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_SAR_M5_',
        layer=laygen.layers['metal'][5],
        gridname=rg_m4m5_thick,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=None,
        offset_start_index=8,
        offset_end_index=0)
    #sa_m6
    num_vref_routes_m6 = 4
    x1 = laygen.get_inst_xy(name=isa.name, gridname=rg_m5m6_thick)[0]\
         +laygen.get_template_size(name=isa.cellname, gridname=rg_m5m6_thick, libname=workinglib)[0]
    x1_phy = laygen.get_inst_xy(name=isa.name)[0]\
         +laygen.get_template_size(name=isa.cellname, libname=workinglib)[0]
    y1 = laygen.get_inst_xy(name=isa.name, gridname=rg_m5m6_thick)[1]
    input_rails_rect = [rvdd_sal_m5 + rvdd_sar_m5, rvss_sal_m5 + rvss_sar_m5]
    #sa_m6_bottom_shield
    rvdd_sa_m6, rvss_sa_m6 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_0_',
        layer=laygen.layers['metal'][6],
        gridname=rg_m5m6_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=x1,
        overwrite_start_index=2,
        overwrite_end_index=4)
    #trimming
    for r in rvdd_sa_m6:
        r.xy1[0] = x1_phy
    for r in rvss_sa_m6:
        r.xy1[0] = x1_phy
    #sa_m6_mid and top_shield
    for i in range(3):
        rvss_sa_m6 = laygenhelper.generate_power_rails_from_rails_rect(
            laygen,
            routename_tag='_M6_' + str(i + 1) + '_',
            layer=laygen.layers['metal'][6],
            gridname=rg_m5m6_thick,
            netnames=['VSS'],
            direction='x',
            input_rails_rect=[rvss_sal_m5 + rvss_sar_m5],
            generate_pin=False,
            overwrite_start_coord=0,
            overwrite_end_coord=x1,
            overwrite_start_index=4 + (1 + num_vref_routes_m6) * (i + 1) - 1,
            overwrite_num_routes=0
        )  #overwrite_end_index=4+(1+num_vref_routes_m6)*(i+1))
        #trimming
        for r in rvss_sa_m6[0]:
            r.xy1[0] = x1_phy
    #sa_m6_top_main_route
    rvdd_sa_m6, rvss_sa_m6 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_',
        layer=laygen.layers['metal'][6],
        gridname=rg_m5m6_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=x1,
        offset_start_index=4 + (1 + num_vref_routes_m6) * 3,
        offset_end_index=0)
    #trimming and pinning
    for r in rvdd_sa_m6:
        r.xy1[0] = x1_phy
        p = laygen.pin_from_rect(name='VDD_M6_' + r.name,
                                 layer=laygen.layers['pin'][6],
                                 rect=r,
                                 gridname=rg_m5m6_thick,
                                 netname='VDD')
        p.xy1[0] = x1_phy
    for r in rvss_sa_m6:
        r.xy1[0] = x1_phy
        p = laygen.pin_from_rect(name='VSS_M6_' + r.name,
                                 layer=laygen.layers['pin'][6],
                                 rect=r,
                                 gridname=rg_m5m6_thick,
                                 netname='VSS')
        p.xy1[0] = x1_phy
    #pins
    #laygen.pin(name='VREF<0>', layer=laygen.layers['pin'][4], xy=laygen.get_rect_xy(rvref0.name, rg_m4m5), gridname=rg_m4m5)
    #laygen.pin(name='VREF<1>', layer=laygen.layers['pin'][4], xy=laygen.get_rect_xy(rvref1.name, rg_m4m5), gridname=rg_m4m5)
    #laygen.pin(name='VREF<2>', layer=laygen.layers['pin'][4], xy=laygen.get_rect_xy(rvref2.name, rg_m4m5), gridname=rg_m4m5)
    '''
    t = laygen.templates.get_template(icdrvl.cellname, libname=workinglib)
    vref0vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5<0>', rg_m4m5, libname=workinglib)
    vref1vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5<1>', rg_m4m5, libname=workinglib)
    vref2vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5<2>', rg_m4m5, libname=workinglib)
    vref0vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5<0>', rg_m4m5, libname=workinglib)
    vref1vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5<1>', rg_m4m5, libname=workinglib)
    vref2vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5<2>', rg_m4m5, libname=workinglib)
    laygen.pin(name='VREF_M5L<0>', layer=laygen.layers['pin'][5], xy=vref0vl_pin_xy, gridname=rg_m4m5, netname='VREF<0>')
    laygen.pin(name='VREF_M5L<1>', layer=laygen.layers['pin'][5], xy=vref1vl_pin_xy, gridname=rg_m4m5, netname='VREF<1>')
    laygen.pin(name='VREF_M5L<2>', layer=laygen.layers['pin'][5], xy=vref2vl_pin_xy, gridname=rg_m4m5, netname='VREF<2>')
    laygen.pin(name='VREF_M5R<0>', layer=laygen.layers['pin'][5], xy=vref0vr_pin_xy, gridname=rg_m4m5, netname='VREF<0>')
    laygen.pin(name='VREF_M5R<1>', layer=laygen.layers['pin'][5], xy=vref1vr_pin_xy, gridname=rg_m4m5, netname='VREF<1>')
    laygen.pin(name='VREF_M5R<2>', layer=laygen.layers['pin'][5], xy=vref2vr_pin_xy, gridname=rg_m4m5, netname='VREF<2>')
    vref0vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5_2<0>', rg_m4m5, libname=workinglib)
    vref1vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5_2<1>', rg_m4m5, libname=workinglib)
    vref2vl_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvl.name, gridname=rg_m4m5), (2,1))\
                   + np.array([-1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5_2<2>', rg_m4m5, libname=workinglib)
    vref0vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5_2<0>', rg_m4m5, libname=workinglib)
    vref1vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5_2<1>', rg_m4m5, libname=workinglib)
    vref2vr_pin_xy=np.tile(laygen.get_inst_xy(name=icdrvr.name, gridname=rg_m4m5), (2,1))\
                   + np.array([1, 1]) * laygen.get_template_pin_xy(t.name, 'VREF_M5_2<2>', rg_m4m5, libname=workinglib)
    laygen.pin(name='VREF_M5L_2<0>', layer=laygen.layers['pin'][5], xy=vref0vl_pin_xy, gridname=rg_m4m5, netname='VREF<0>')
    laygen.pin(name='VREF_M5L_2<1>', layer=laygen.layers['pin'][5], xy=vref1vl_pin_xy, gridname=rg_m4m5, netname='VREF<1>')
    laygen.pin(name='VREF_M5L_2<2>', layer=laygen.layers['pin'][5], xy=vref2vl_pin_xy, gridname=rg_m4m5, netname='VREF<2>')
    laygen.pin(name='VREF_M5R_2<0>', layer=laygen.layers['pin'][5], xy=vref0vr_pin_xy, gridname=rg_m4m5, netname='VREF<0>')
    laygen.pin(name='VREF_M5R_2<1>', layer=laygen.layers['pin'][5], xy=vref1vr_pin_xy, gridname=rg_m4m5, netname='VREF<1>')
    laygen.pin(name='VREF_M5R_2<2>', layer=laygen.layers['pin'][5], xy=vref2vr_pin_xy, gridname=rg_m4m5, netname='VREF<2>')
    '''
    pdict_vref = laygen.get_inst_pin_xy(None, None, rg_m5m6_basic_thick)
    x1 = laygen.get_inst_xy(name=isa.name, gridname=rg_m5m6_basic_thick)[0]\
         +laygen.get_template_size(name=isa.cellname, gridname=rg_m5m6_basic_thick, libname=workinglib)[0]
    for i in range(3):
        laygen.route(
            None,
            laygen.layers['metal'][5],
            gridname0=rg_m5m6_basic_thick,
            xy0=pdict_vref[icdrvl.name]['VREF_M5<' + str(i) + '>'][0],
            xy1=pdict_vref[icdrvl.name]['VREF_M5<' + str(i) + '>'][0] +
            np.array([0, (num_vref_routes_m6 + 1) * 3 + 4]))
        laygen.route(
            None,
            laygen.layers['metal'][5],
            gridname0=rg_m5m6_basic_thick,
            xy0=pdict_vref[icdrvr.name]['VREF_M5<' + str(i) + '>'][0],
            xy1=pdict_vref[icdrvr.name]['VREF_M5<' + str(i) + '>'][0] +
            np.array([0, (num_vref_routes_m6 + 1) * 3 + 4]))
        laygen.route(
            None,
            laygen.layers['metal'][5],
            gridname0=rg_m5m6_basic_thick,
            xy0=pdict_vref[icdrvl.name]['VREF_M5_2<' + str(i) + '>'][0],
            xy1=pdict_vref[icdrvl.name]['VREF_M5_2<' + str(i) + '>'][0] +
            np.array([0, (num_vref_routes_m6 + 1) * 3 + 4]))
        laygen.route(
            None,
            laygen.layers['metal'][5],
            gridname0=rg_m5m6_basic_thick,
            xy0=pdict_vref[icdrvr.name]['VREF_M5_2<' + str(i) + '>'][0],
            xy1=pdict_vref[icdrvr.name]['VREF_M5_2<' + str(i) + '>'][0] +
            np.array([0, (num_vref_routes_m6 + 1) * 3 + 4]))
        input_rails_xy = [[
            pdict_vref[icdrvl.name]['VREF_M5<' + str(i) + '>'],
            pdict_vref[icdrvl.name]['VREF_M5_2<' + str(i) + '>'],
            pdict_vref[icdrvr.name]['VREF_M5<' + str(i) + '>'],
            pdict_vref[icdrvr.name]['VREF_M5_2<' + str(i) + '>']
        ]]
        laygenhelper.generate_power_rails_from_rails_xy(
            laygen,
            routename_tag='_M6_',
            layer=laygen.layers['pin'][6],
            gridname=rg_m5m6_basic_thick,
            netnames=['VREF<' + str(i) + '>'],
            direction='x',
            input_rails_xy=input_rails_xy,
            generate_pin=True,
            overwrite_start_coord=0,
            overwrite_end_coord=x1,
            overwrite_start_index=4 + (num_vref_routes_m6 + 1) * i,
            overwrite_end_index=4 + (num_vref_routes_m6 + 1) * i +
            num_vref_routes_m6 - 1)

    laygen.boundary_pin_from_rect(rclkb,
                                  rg_m4m5,
                                  "CLKB",
                                  laygen.layers['pin'][5],
                                  size=4,
                                  direction='bottom')
    laygen.boundary_pin_from_rect(routp,
                                  rg_m4m5,
                                  "OUTP",
                                  laygen.layers['pin'][5],
                                  size=4,
                                  direction='bottom')
    laygen.boundary_pin_from_rect(routm,
                                  rg_m4m5,
                                  "OUTM",
                                  laygen.layers['pin'][5],
                                  size=4,
                                  direction='bottom')
    laygen.boundary_pin_from_rect(rosp,
                                  rg_m2m3,
                                  "OSP",
                                  laygen.layers['pin'][3],
                                  size=4,
                                  direction='bottom')
    laygen.boundary_pin_from_rect(rosm,
                                  rg_m2m3,
                                  "OSM",
                                  laygen.layers['pin'][3],
                                  size=4,
                                  direction='bottom')
    for i in range(num_bits):
        laygen.boundary_pin_from_rect(renl0[i],
                                      rg_m5m6,
                                      "ENL" + str(i) + "<0>",
                                      laygen.layers['pin'][5],
                                      size=4,
                                      direction='bottom')
        laygen.boundary_pin_from_rect(renl1[i],
                                      rg_m5m6,
                                      "ENL" + str(i) + "<1>",
                                      laygen.layers['pin'][5],
                                      size=4,
                                      direction='bottom')
        laygen.boundary_pin_from_rect(renl2[i],
                                      rg_m5m6,
                                      "ENL" + str(i) + "<2>",
                                      laygen.layers['pin'][5],
                                      size=4,
                                      direction='bottom')
        laygen.boundary_pin_from_rect(renr0[i],
                                      rg_m5m6,
                                      "ENR" + str(i) + "<0>",
                                      laygen.layers['pin'][5],
                                      size=4,
                                      direction='bottom')
        laygen.boundary_pin_from_rect(renr1[i],
                                      rg_m5m6,
                                      "ENR" + str(i) + "<1>",
                                      laygen.layers['pin'][5],
                                      size=4,
                                      direction='bottom')
        laygen.boundary_pin_from_rect(renr2[i],
                                      rg_m5m6,
                                      "ENR" + str(i) + "<2>",
                                      laygen.layers['pin'][5],
                                      size=4,
                                      direction='bottom')

    laygen.pin_from_rect(name='SAINP',
                         layer=laygen.layers['pin'][4],
                         rect=rsainp,
                         gridname=rg_m4m5,
                         netname='INP')
    laygen.pin_from_rect(name='SAINM',
                         layer=laygen.layers['pin'][4],
                         rect=rsainm,
                         gridname=rg_m4m5,
                         netname='INM')
    for i, r in enumerate(rinp):
        laygen.boundary_pin_from_rect(r,
                                      rg_m4m5,
                                      "INP" + str(i),
                                      laygen.layers['pin'][4],
                                      size=8,
                                      direction='right',
                                      netname="INP")
    for i, r in enumerate(rinm):
        laygen.boundary_pin_from_rect(r,
                                      rg_m4m5,
                                      "INM" + str(i),
                                      laygen.layers['pin'][4],
                                      size=8,
                                      direction='left',
                                      netname="INM")
Ejemplo n.º 8
0
def generate_space_array(laygen,
                         objectname_pfix,
                         tisar_libname,
                         space_libname,
                         tisar_name,
                         space_name,
                         placement_grid,
                         routing_grid_m3m4_thick,
                         routing_grid_m4m5_thick,
                         routing_grid_m5m6_thick,
                         origin=np.array([0, 0])):
    """generate tisar space """
    pg = placement_grid
    ttisar = laygen.templates.get_template(tisar_name, libname=tisar_libname)
    tspace = laygen.templates.get_template(space_name, libname=space_libname)

    sar_pins = ttisar.pins

    tbnd_bottom = laygen.templates.get_template('boundary_bottom')
    tbnd_bleft = laygen.templates.get_template('boundary_bottomleft')
    space_xy = np.array([tspace.size[0], ttisar.size[1]])
    # laygen.add_rect(None, np.array([origin, origin+space_xy+2*tbnd_bleft.size[0]*np.array([1, 0])]), laygen.layers['prbnd'])
    # num_space_tot=int((ttisar.size[1]-2*tbnd_bottom.size[1])/tspace.size[1])
    # tbnd_bleft_size=tbnd_bleft.size

    #VDD/VSS/VREF integration
    rvddclkd = []
    rvddsamp = []
    rvddsar = []
    rvddsar_upper = []
    rvref0 = []
    rvref1 = []
    rvref2 = []
    rvssclkd = []
    rvsssamp = []
    rvsssar = []
    rvsssar_upper = []
    vddclkd_xy = []
    vddsamp_xy = []
    vddsar_xy = []
    vddsar_upper_xy = []
    vssclkd_xy = []
    vsssamp_xy = []
    vsssar_xy = []
    vsssar_upper_xy = []
    y_vddsar_max = 0
    y_vddsar_lower_max = 0
    y_vddsamp_min = 500000
    y_vddsamp_max = 0
    y_vddclkd_min = 500000
    y_vref0 = sar_pins['VREF0<0>']['xy'][0][1]

    num_unit_row = 4
    num_unit_col = 3
    ispace_sar = []
    for col in range(num_unit_col):
        ispace_sar.append([])
        space_origin = origin + [
            col * laygen.get_template_xy(space_name, pg, workinglib)[0], 0
        ]
        ispace_sar[col].append(
            laygen.place(name="I" + objectname_pfix + 'SPSAR' + str(col),
                         templatename=space_name,
                         gridname=pg,
                         xy=space_origin,
                         template_libname=space_libname))

        for i in range(1, num_unit_row):
            if i % 2 == 0:
                ispace_sar[col].append(
                    laygen.relplace(name="I" + objectname_pfix + 'SPSAR' +
                                    str(col) + str(i),
                                    templatename=space_name,
                                    gridname=pg,
                                    refinstname=ispace_sar[col][-1].name,
                                    direction='top',
                                    transform='R0',
                                    template_libname=space_libname))
            else:
                ispace_sar[col].append(
                    laygen.relplace(name="I" + objectname_pfix + 'SPSAR' +
                                    str(col) + str(i),
                                    templatename=space_name,
                                    gridname=pg,
                                    refinstname=ispace_sar[col][-1].name,
                                    direction='top',
                                    transform='MX',
                                    template_libname=space_libname))
    #
    # m_bnd = int(space_xy[0] / tbnd_bottom.size[0])
    # [bnd_bottom, bnd_top, bnd_left, bnd_right] \
    #     = laygenhelper.generate_boundary(laygen, objectname_pfix='BNDSAR0', placement_grid=pg,
    #                         devname_bottom=['boundary_bottomleft', 'boundary_bottom', 'boundary_bottomright'],
    #                         shape_bottom=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
    #                         devname_top=['boundary_topleft', 'boundary_top', 'boundary_topright'],
    #                         shape_top=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
    #                         devname_left=devname_bnd_left,
    #                         transform_left=transform_bnd_left,
    #                         devname_right=devname_bnd_right,
    #                         transform_right=transform_bnd_right,
    #                         origin=origin)

    # #vddsamp cap
    # num_space_samp=num_space_tot-num_space_sar-1
    # space_origin = origin + laygen.get_xy(obj=laygen.get_template(name = 'boundary_bottomleft'), gridname = pg) * np.array([1, (3 + 2 * num_space_sar)])
    # ispace_samp = [laygen.place(name="I" + objectname_pfix + 'SPSAMP0', templatename=space_name,
    #                       gridname=pg, xy=space_origin, template_libname=space_libname)]
    # devname_bnd_left = ['nmos4_fast_left', 'pmos4_fast_left']
    # devname_bnd_right = ['nmos4_fast_right', 'pmos4_fast_right']
    # transform_bnd_left = ['R0', 'MX']
    # transform_bnd_right = ['R0', 'MX']
    #
    # for i in range(1, num_space_samp):
    #     if i % 2 == 0:
    #         ispace_samp.append(laygen.relplace(name="I" + objectname_pfix + 'SPSAMP' + str(i), templatename=space_name,
    #                                    gridname=pg, refinstname=ispace_samp[-1].name, direction='top', transform='R0',
    #                                    template_libname=space_libname))
    #         devname_bnd_left += ['nmos4_fast_left', 'pmos4_fast_left']
    #         devname_bnd_right += ['nmos4_fast_right', 'pmos4_fast_right']
    #         transform_bnd_left += ['R0', 'MX']
    #         transform_bnd_right += ['R0', 'MX']
    #     else:
    #         ispace_samp.append(laygen.relplace(name="I" + objectname_pfix + 'SPSAMP' + str(i), templatename=space_name,
    #                                    gridname=pg, refinstname=ispace_samp[-1].name, direction='top', transform='MX',
    #                                    template_libname=space_libname))
    #         devname_bnd_left += ['pmos4_fast_left', 'nmos4_fast_left']
    #         devname_bnd_right += ['pmos4_fast_right', 'nmos4_fast_right']
    #         transform_bnd_left += ['R0', 'MX']
    #         transform_bnd_right += ['R0', 'MX']
    #
    # m_bnd = int(space_xy[0] / tbnd_bottom.size[0])
    # [bnd_bottom, bnd_top, bnd_left, bnd_right] \
    #     = laygenhelper.generate_boundary(laygen, objectname_pfix='BNDSAMP0', placement_grid=pg,
    #                                      devname_bottom=['boundary_bottomleft', 'boundary_bottom', 'boundary_bottomright'],
    #                                      shape_bottom=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
    #                                      devname_top=['boundary_topleft', 'boundary_top', 'boundary_topright'],
    #                                      shape_top=[np.array([1, 1]), np.array([m_bnd, 1]), np.array([1, 1])],
    #                                      devname_left=devname_bnd_left,
    #                                      transform_left=transform_bnd_left,
    #                                      devname_right=devname_bnd_right,
    #                                      transform_right=transform_bnd_right,
    #                                      origin=space_origin-laygen.get_xy(obj=laygen.get_template(name = 'boundary_bottomleft'), gridname = pg))
    #vdd/vss
    #m3
    rvdd_sar_xy_m3 = []
    rvss_sar_xy_m3 = []
    space_template = laygen.templates.get_template(space_name, workinglib)
    space_pins = space_template.pins
    vddcnt = 0
    vsscnt = 0
    for col in range(num_unit_col):
        space_origin_phy = ispace_sar[col][0].bbox[0]
        for pn, p in space_pins.items():
            if pn.startswith('VDD'):
                pxy = space_origin_phy + np.array(
                    [p['xy'][0], p['xy'][1] * np.array([1, num_unit_row])])
                pxy[0][1] = y_vddsar_lower_max
                pxy[1][1] = ispace_sar[0][-1].bbox[1][1]
                laygen.add_rect(None, pxy, laygen.layers['metal'][3])
                rvdd_sar_xy_m3.append(
                    laygen.grids.get_absgrid_coord_region(
                        gridname=rg_m3m4_thick, xy0=pxy[0], xy1=pxy[1]))
                vddcnt += 1
            if pn.startswith('VSS'):
                pxy = space_origin_phy + np.array(
                    [p['xy'][0], p['xy'][1] * np.array([1, num_unit_row])])
                pxy[0][1] = y_vddsar_lower_max
                pxy[1][1] = ispace_sar[0][-1].bbox[1][1]
                laygen.add_rect(None, pxy, laygen.layers['metal'][3])
                rvss_sar_xy_m3.append(
                    laygen.grids.get_absgrid_coord_region(
                        gridname=rg_m3m4_thick, xy0=pxy[0], xy1=pxy[1]))
                vsscnt += 1

    print(vddcnt, vsscnt)
    # rvdd_samp_xy_m3=[]
    # rvss_samp_xy_m3=[]
    # space_template = laygen.templates.get_template(space_name, workinglib)
    # space_pins=space_template.pins
    # space_origin_phy = ispace_samp[0].bbox[0]
    # vddcnt=0
    # vsscnt=0
    # for pn, p in space_pins.items():
    #     if pn.startswith('VDD'):
    #         pxy=space_origin_phy+np.array([p['xy'][0], p['xy'][1]*np.array([1, num_space_samp])])
    #         laygen.add_rect(None, pxy, laygen.layers['metal'][3])
    #         rvdd_samp_xy_m3.append(laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick, xy0=pxy[0], xy1=pxy[1]))
    #         vddcnt += 1
    #     if pn.startswith('VSS'):
    #         pxy=space_origin_phy+np.array([p['xy'][0], p['xy'][1]*np.array([1, num_space_samp])])
    #         laygen.add_rect(None, pxy, laygen.layers['metal'][3])
    #         rvss_samp_xy_m3.append(laygen.grids.get_absgrid_coord_region(gridname=rg_m3m4_thick, xy0=pxy[0], xy1=pxy[1]))
    #         vsscnt += 1
    #m4
    # input_rails_xy = [rvdd_samp_xy_m3, rvss_samp_xy_m3]
    # rvdd_samp_m4, rvss_samp_m4 = laygenhelper.generate_power_rails_from_rails_xy(laygen, routename_tag='_M4_SAMP_', layer=laygen.layers['metal'][4],
    #                                     gridname=rg_m3m4_thick, netnames=['VDDSAMP', 'VSSSAMP'], direction='x',
    #                                     input_rails_xy=input_rails_xy, generate_pin=False,
    #                                     overwrite_start_coord=None, overwrite_end_coord=None,
    #                                     offset_start_index=0, offset_end_index=0)
    end = laygen.get_xy(obj = ispace_sar[-1][0], gridname=rg_m3m4_thick)[0]\
         +laygen.get_xy(obj = ispace_sar[-1][0].template, gridname=rg_m3m4_thick)[0]
    input_rails_xy = [rvdd_sar_xy_m3, rvss_sar_xy_m3]
    rvdd_sar_m4, rvss_sar_m4 = laygenhelper.generate_power_rails_from_rails_xy(
        laygen,
        routename_tag='_M4_',
        layer=laygen.layers['metal'][4],
        gridname=rg_m3m4_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_xy=input_rails_xy,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=end,
        offset_start_index=0,
        offset_end_index=0)

    end = laygen.get_xy(obj=ispace_sar[-1][-1], gridname=rg_m4m5_thick)[1]
    if num_unit_row % 2 == 1:
        end = end + laygen.get_xy(obj=ispace_sar[-1][0].template,
                                  gridname=rg_m4m5_thick)[1]
    input_rails_rect = [rvdd_sar_m4, rvss_sar_m4]
    rvdd_sar_m5, rvss_sar_m5 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M5_',
        layer=laygen.layers['metal'][5],
        gridname=rg_m4m5_thick,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=end,
        offset_start_index=0,
        offset_end_index=0)

    end = laygen.get_xy(obj = ispace_sar[-1][0], gridname=rg_m5m6_thick)[0]\
         +laygen.get_xy(obj = ispace_sar[-1][0].template, gridname=rg_m5m6_thick)[0]
    input_rails_rect = [rvdd_sar_m5, rvss_sar_m5]
    rvdd_sar_m6, rvss_sar_m6 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M6_',
        layer=laygen.layers['metal'][6],
        gridname=rg_m5m6_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=end,
        offset_start_index=0,
        offset_end_index=0)

    end = laygen.get_xy(obj=ispace_sar[-1][-1], gridname=rg_m6m7_thick)[1]
    if num_unit_row % 2 == 1:
        end = end + laygen.get_xy(obj=ispace_sar[-1][0].template,
                                  gridname=rg_m6m7_thick)[1]
    input_rails_rect = [rvdd_sar_m6, rvss_sar_m6]
    rvdd_sar_m7, rvss_sar_m7 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M7_',
        layer=laygen.layers['metal'][7],
        gridname=rg_m6m7_thick,
        netnames=['VDD', 'VSS'],
        direction='y',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=end,
        offset_start_index=1,
        offset_end_index=0)

    for _idx, _vdd in enumerate(rvdd_sar_m6):
        xy0 = laygen.get_xy(obj=_vdd, gridname=rg_m5m6_thick)
        laygen.pin(name='VDD_M6' + str(_idx),
                   layer=laygen.layers['pin'][6],
                   xy=xy0,
                   gridname=rg_m5m6_thick,
                   netname='VDD')

    for _idx, _vdd in enumerate(rvss_sar_m6):
        xy0 = laygen.get_xy(obj=_vdd, gridname=rg_m5m6_thick)
        laygen.pin(name='VSS_M6' + str(_idx),
                   layer=laygen.layers['pin'][6],
                   xy=xy0,
                   gridname=rg_m5m6_thick,
                   netname='VSS')
    #
    end = laygen.get_xy(obj = ispace_sar[-1][0], gridname=rg_m7m8_thick)[0]\
         +laygen.get_xy(obj = ispace_sar[-1][0].template, gridname=rg_m7m8_thick)[0]
    input_rails_rect = [rvdd_sar_m7, rvss_sar_m7]
    rvdd_sar_m6, rvss_sar_m6 = laygenhelper.generate_power_rails_from_rails_rect(
        laygen,
        routename_tag='_M8_',
        layer=laygen.layers['metal'][8],
        gridname=rg_m7m8_thick,
        netnames=['VDD', 'VSS'],
        direction='x',
        input_rails_rect=input_rails_rect,
        generate_pin=False,
        overwrite_start_coord=0,
        overwrite_end_coord=end,
        offset_start_index=0,
        offset_end_index=0)