示例#1
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_r2r_dac_bcap_array(laygen,
                                objectname_pfix,
                                templib_logic,
                                placement_grid,
                                routing_grid_m4m5,
                                routing_grid_m5m6,
                                rg_m3m4_basic_thick,
                                rg_m5m6_thick,
                                m,
                                num_bits,
                                num_hori,
                                num_vert,
                                origin=np.array([0, 0])):
    """generate r2rdac """
    r2r_name = 'r2r_dac_bcap_vref'
    sar_name = 'sar_wsamp'
    ret_name = 'adc_retimer'
    tgate_name = 'tgate_' + str(m) + 'x'
    pg = placement_grid

    rg_m4m5 = routing_grid_m4m5
    rg_m5m6 = routing_grid_m5m6
    # rg_m4m5 = routing_grid_m4m5
    # rg_m4m5_basic_thick = routing_grid_m4m5_basic_thick
    # rg_m4m5_thick = routing_grid_m4m5_thick
    # rg_m5m6 = routing_grid_m5m6
    # rg_m5m6_thick = routing_grid_m5m6_thick
    # rg_m5m6_thick_basic = routing_grid_m5m6_thick_basic
    # rg_m6m7_thick = routing_grid_m6m7_thick

    # Calculate reference coordinate
    x1_phy = laygen.get_template_xy(
        name=r2r_name, gridname=None, libname=workinglib)[0] * num_hori
    pin_origin_x = laygen.grids.get_absgrid_x(rg_m5m6_thick_basic, x1_phy)
    y1_phy = origin[1] + laygen.get_template_xy(name=sar_name, gridname=None, libname=workinglib)[1] \
             + laygen.get_template_xy(name=ret_name, gridname=None, libname=workinglib)[1]
    pin_origin_y = laygen.grids.get_absgrid_y(rg_m5m6, y1_phy)
    pin_origin_y2_thick = origin[1] + \
                          laygen.get_template_pin_xy(sar_name, 'VREF<2>_M6_0', rg_m5m6_thick, libname=workinglib)[0][1] \
                          + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    pin_origin_y1_thick = origin[1] + \
                          laygen.get_template_pin_xy(sar_name, 'VREF<1>_M6_0', rg_m5m6_thick, libname=workinglib)[0][1] \
                          + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    pin_origin_y0_thick = origin[1] + \
                          laygen.get_template_pin_xy(sar_name, 'VREF<0>_M6_0', rg_m5m6_thick, libname=workinglib)[0][1] \
                          + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    # pin_origin_y0_thick = laygen.grids.get_absgrid_y(rg_m5m6_thick, y0_phy)

    # placement
    irdac = []
    for i in range(num_vert):
        if i == 0:
            irdac.append(
                laygen.relplace(name="I" + objectname_pfix + 'IBCAP' + str(i),
                                templatename=r2r_name,
                                gridname=pg,
                                refinstname=None,
                                xy=origin,
                                shape=[num_hori, 1],
                                template_libname=workinglib))
        else:
            irdac.append(
                laygen.relplace(name="I" + objectname_pfix + 'IBCAP' + str(i),
                                templatename=r2r_name,
                                gridname=pg,
                                refinstname=irdac[-1].name,
                                shape=[num_hori, 1],
                                template_libname=workinglib,
                                direction='top'))

    # output routing
    for k in range(4):
        rv2, rh2 = laygen.route_vh(
            laygen.layers['metal'][5],
            laygen.layers['metal'][6],
            xy0=laygen.get_inst_pin_xy(
                irdac[2].name, 'I', rg_m5m6_thick, index=np.array([0, 0]))[0] +
            np.array([2, 0]),
            xy1=np.array([pin_origin_x, pin_origin_y2_thick + k]),
            gridname0=rg_m5m6_thick)
        rv1, rh1 = laygen.route_vh(
            laygen.layers['metal'][5],
            laygen.layers['metal'][6],
            xy0=laygen.get_inst_pin_xy(
                irdac[1].name, 'I', rg_m5m6_thick, index=np.array([0, 0]))[0] +
            np.array([1, 0]),
            xy1=np.array([pin_origin_x, pin_origin_y1_thick + k]),
            gridname0=rg_m5m6_thick)
        rv0, rh0 = laygen.route_vh(
            laygen.layers['metal'][5],
            laygen.layers['metal'][6],
            xy0=laygen.get_inst_pin_xy(
                irdac[0].name, 'I', rg_m5m6_thick, index=np.array([0, 0]))[0] +
            np.array([0, 0]),
            xy1=np.array([pin_origin_x, pin_origin_y0_thick + k]),
            gridname0=rg_m5m6_thick)
        for j in range(num_vert):
            laygen.via(
                None,
                xy=laygen.get_inst_pin_xy(
                    irdac[j].name, 'I', rg_m4m5, index=np.array([0, 0]))[0] +
                np.array([j, 0]),
                gridname=rg_m4m5)
        laygen.boundary_pin_from_rect(rh2,
                                      rg_m5m6_thick,
                                      'VREF' + str(k) + '<' + str(2) + '>',
                                      laygen.layers['pin'][6],
                                      size=4,
                                      direction='right',
                                      netname='VREF<' + str(2) + '>')
        laygen.boundary_pin_from_rect(rh1,
                                      rg_m5m6_thick,
                                      'VREF' + str(k) + '<' + str(1) + '>',
                                      laygen.layers['pin'][6],
                                      size=4,
                                      direction='right',
                                      netname='VREF<' + str(1) + '>')
        laygen.boundary_pin_from_rect(rh0,
                                      rg_m5m6_thick,
                                      'VREF' + str(k) + '<' + str(0) + '>',
                                      laygen.layers['pin'][6],
                                      size=4,
                                      direction='right',
                                      netname='VREF<' + str(0) + '>')

    pin_origin_y2_thick = laygen.grids.get_absgrid_y(
        rg_m5m6_thick,
        laygen.grids.get_phygrid_y(rg_m5m6,
                                   pin_origin_y + 4 + num_hori * num_vert))
    # m5 supply
    pdict_m5m6_thick = laygen.get_inst_pin_xy(None, None, rg_m5m6_thick)
    rvdd_m5 = []
    rvss_m5 = []
    for i in range(num_hori):
        for p in pdict_m5m6_thick[irdac[0].name]:
            if p.startswith('VDD'):
                r0 = laygen.route(
                    None,
                    laygen.layers['metal'][5],
                    xy0=laygen.get_inst_pin_xy(irdac[0].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[0],
                    xy1=laygen.get_inst_pin_xy(irdac[num_vert - 1].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[1],
                    gridname0=rg_m5m6_thick)
                rvdd_m5.append(r0)
        for p in pdict_m5m6_thick[irdac[0].name]:
            if p.startswith('VSS'):
                r0 = laygen.route(
                    None,
                    laygen.layers['metal'][5],
                    xy0=laygen.get_inst_pin_xy(irdac[0].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[0],
                    xy1=laygen.get_inst_pin_xy(irdac[num_vert - 1].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[1],
                    gridname0=rg_m5m6_thick)
                rvss_m5.append(r0)

    #m6 (extract VDD/VSS grid from tisar and make power pins)
    tisar_name = 'tisaradc_body_core'
    tisar_libname = 'adc_sar_generated'
    rg_m5m6_thick_temp_tisar = 'route_M5_M6_thick_temp_tisar_VDD'
    # bnd = laygen.get_template(tisar_name, libname=tisar_libname).xy
    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'],
        bnd=None,
        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=0)
    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=0)
def generate_r2r_dac_bcap_array(laygen, objectname_pfix, templib_logic, placement_grid, routing_grid_m4m5, routing_grid_m5m6,
                           rg_m3m4_basic_thick, rg_m5m6_thick, m, num_bits, num_hori, num_vert,
                           origin=np.array([0, 0])):
    """generate r2rdac """
    r2r_name = 'r2r_dac_bcap'
    sar_name = 'sar_wsamp'
    tisar_name='tisaradc_body'
    ret_name = 'adc_retimer'
    tgate_name = 'tgate_' + str(m) + 'x'
    pg = placement_grid

    rg_m4m5 = routing_grid_m4m5
    rg_m5m6 = routing_grid_m5m6
    # rg_m4m5 = routing_grid_m4m5
    # rg_m4m5_basic_thick = routing_grid_m4m5_basic_thick
    # rg_m4m5_thick = routing_grid_m4m5_thick
    # rg_m5m6 = routing_grid_m5m6
    # rg_m5m6_thick = routing_grid_m5m6_thick
    # rg_m5m6_thick_basic = routing_grid_m5m6_thick_basic
    # rg_m6m7_thick = routing_grid_m6m7_thick

    # Calculate reference coordinate
    x1_phy = laygen.get_template_xy(name=r2r_name, gridname=None, libname=workinglib)[0] * num_hori
    pin_origin_x = laygen.grids.get_absgrid_x(rg_m5m6_thick_basic, x1_phy)
    if use_sf == True and vref_sf == True:
        y1_phy = origin[1] + laygen.get_template_xy(name=sar_name, gridname=None, libname=workinglib)[1] \
                       + laygen.get_template_xy(name=ret_name, gridname=None, libname=workinglib)[1]
        pin_origin_y = laygen.grids.get_absgrid_y(rg_m5m6, y1_phy)
    elif use_offset == True:
        pin_origin_y = origin[1] + laygen.get_template_pin_xy(tisar_name, 'OSM'+str(num_slices-1), gridname=rg_m5m6, libname=workinglib)[0][1] - num_slices*2 - 6
    else:
        y1_phy = origin[1] + laygen.get_template_xy(name=sar_name, gridname=None, libname=workinglib)[1] \
                       + laygen.get_template_xy(name=ret_name, gridname=None, libname=workinglib)[1]
        pin_origin_y = laygen.grids.get_absgrid_y(rg_m5m6, y1_phy)
    if use_sf == True:
        pin_origin_y1_thick = origin[1] + \
                              laygen.get_template_pin_xy(sar_name, 'SF_BIAS', rg_m5m6_thick, libname=workinglib)[0][1] \
                              + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    else:
        pin_origin_y1_thick = origin[1] + 0 \
                              + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    if vref_sf == True:
        pin_origin_y0_thick = origin[1] + \
                              laygen.get_template_pin_xy(sar_name, 'VREF_SF_BIAS', rg_m5m6_thick, libname=workinglib)[0][1] \
                              + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    else:
        pin_origin_y0_thick = origin[1] + 2 \
                              + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    # pin_origin_y0_thick = laygen.grids.get_absgrid_y(rg_m5m6_thick, y0_phy)

    # placement
    irdac = []
    for i in range(num_vert):
        if i == 0:
            irdac.append(laygen.relplace(name="I" + objectname_pfix + 'IBCAP' + str(i), templatename=r2r_name,
                                         gridname=pg, refinstname=None, xy=origin, shape=[num_hori, 1],
                                         template_libname=workinglib))
        else:
            irdac.append(laygen.relplace(name="I" + objectname_pfix + 'IBCAP' + str(i), templatename=r2r_name,
                                         gridname=pg, refinstname=irdac[-1].name, shape=[num_hori, 1],
                                         template_libname=workinglib, direction='top'))

    # output routing
    for i in range(num_hori):
        for j in range(num_vert):
            if i == num_hori - 1 and j == num_vert - 1:  # VREF_SF_BIAS routing with thick wire
                rv1, rh1 = laygen.route_vh(laygen.layers['metal'][5], laygen.layers['metal'][6],
                                           xy0=laygen.get_inst_pin_xy(irdac[j].name, 'I', rg_m5m6_thick,
                                                                      index=np.array([i, 0]))[0] + np.array([j, 0]),
                                           xy1=np.array([pin_origin_x, pin_origin_y0_thick]),
                                           gridname0=rg_m5m6_thick)
                laygen.via(None, xy=laygen.get_inst_pin_xy(irdac[j].name, 'I', rg_m4m5, index=np.array([i, 0]))[
                                        0] + np.array([j, 0]), gridname=rg_m4m5)
                laygen.boundary_pin_from_rect(rh1, rg_m5m6_thick, 'out<' + str(num_hori * j + i) + '>',
                                              laygen.layers['pin'][6], size=4, direction='right')
            elif num_hori * j + i == num_slices * 2:  # SF_BIAS routing with thick wire
                rv1, rh1 = laygen.route_vh(laygen.layers['metal'][5], laygen.layers['metal'][6],
                                           xy0=laygen.get_inst_pin_xy(irdac[j].name, 'I', rg_m5m6_thick,
                                                                      index=np.array([i, 0]))[0] + np.array([j, 0]),
                                           xy1=np.array([pin_origin_x, pin_origin_y1_thick]),
                                           gridname0=rg_m5m6_thick)
                laygen.via(None, xy=laygen.get_inst_pin_xy(irdac[j].name, 'I', rg_m4m5, index=np.array([i, 0]))[
                                        0] + np.array([j, 0]), gridname=rg_m4m5)
                laygen.boundary_pin_from_rect(rh1, rg_m5m6_thick, 'out<' + str(num_hori * j + i) + '>',
                                              laygen.layers['pin'][6], size=4, direction='right')
            else:
                rv0, rh0 = laygen.route_vh(laygen.layers['metal'][5], laygen.layers['metal'][6],
                                           xy0=laygen.get_inst_pin_xy(irdac[j].name, 'I', rg_m5m6_thick_basic,
                                                                      index=np.array([i, 0]))[0] + np.array([j, 0]),
                                           xy1=np.array([pin_origin_x, pin_origin_y + 4 + num_hori * j + i]),
                                           gridname0=rg_m5m6_thick_basic)
                laygen.via(None, xy=laygen.get_inst_pin_xy(irdac[j].name, 'I', rg_m4m5_thick, index=np.array([i, 0]))[
                                        0] + np.array([j, 0]), gridname=rg_m4m5_thick)
                laygen.boundary_pin_from_rect(rh0, rg_m5m6_thick_basic, 'out<' + str(num_hori * j + i) + '>',
                                              laygen.layers['pin'][6], size=4, direction='right')
    pin_origin_y2_thick = laygen.grids.get_absgrid_y(rg_m5m6_thick, laygen.grids.get_phygrid_y(rg_m5m6,
                                                                                               pin_origin_y + 4 + num_hori * num_vert))
    # m5 supply
    pdict_m5m6_thick = laygen.get_inst_pin_xy(None, None, rg_m5m6_thick)
    rvdd_m5 = []
    rvss_m5 = []
    for i in range(num_hori):
        for p in pdict_m5m6_thick[irdac[0].name]:
            if p.startswith('VDD'):
                r0 = laygen.route(None, laygen.layers['metal'][5],
                                  xy0=laygen.get_inst_pin_xy(irdac[0].name, p, rg_m5m6_thick, index=np.array([i, 0]))[
                                      0],
                                  xy1=laygen.get_inst_pin_xy(irdac[num_vert - 1].name, p, rg_m5m6_thick,
                                                             index=np.array([i, 0]))[1],
                                  gridname0=rg_m5m6_thick)
                rvdd_m5.append(r0)
        for p in pdict_m5m6_thick[irdac[0].name]:
            if p.startswith('VSS'):
                r0 = laygen.route(None, laygen.layers['metal'][5],
                                  xy0=laygen.get_inst_pin_xy(irdac[0].name, p, rg_m5m6_thick, index=np.array([i, 0]))[
                                      0],
                                  xy1=laygen.get_inst_pin_xy(irdac[num_vert - 1].name, p, rg_m5m6_thick,
                                                             index=np.array([i, 0]))[1],
                                  gridname0=rg_m5m6_thick)
                rvss_m5.append(r0)

    # m6
    # print(pin_origin_y0_thick, pin_origin_y1_thick, pin_origin_y2_thick)
    # input_rails_rect = [rvdd_m5, rvss_m5]
    # rvdd_m6_0, rvss_m6_0 = laygenhelper.generate_power_rails_from_rails_rect(laygen, routename_tag='_M6_0_',
    #                                                                          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=None,
    #                                                                          overwrite_end_coord=None,
    #                                                                          offset_start_index=0,
    #                                                                          overwrite_end_index=pin_origin_y0_thick - 2)
    # rvdd_m6_1, rvss_m6_1 = laygenhelper.generate_power_rails_from_rails_rect(laygen, routename_tag='_M6_1_',
    #                                                                          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=None,
    #                                                                          overwrite_end_coord=None,
    #                                                                          overwrite_start_index=pin_origin_y0_thick + 2,
    #                                                                          overwrite_end_index=pin_origin_y1_thick - 2)
    # rvdd_m6_2, rvss_m6_2 = laygenhelper.generate_power_rails_from_rails_rect(laygen, routename_tag='_M6_2_',
    #                                                                          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=None,
    #                                                                          overwrite_end_coord=None,
    #                                                                          overwrite_start_index=pin_origin_y2_thick + 2,
    #                                                                          offset_end_index=0)

    #m6 (extract VDD/VSS grid from tisar and make power pins)
    tisar_name = 'tisaradc_body_core'
    tisar_libname = 'adc_sar_generated'
    rg_m5m6_thick_temp_tisar='route_M5_M6_thick_temp_tisar_VDD'
    # bnd = laygen.get_template(tisar_name, libname=tisar_libname).xy
    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'], bnd=None, 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=0)
    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=0)
def generate_r2r_dac_array(laygen,
                           objectname_pfix,
                           templib_logic,
                           placement_grid,
                           routing_grid_m4m5,
                           routing_grid_m5m6,
                           rg_m3m4_basic_thick,
                           rg_m5m6_thick,
                           m,
                           num_bits,
                           num_hori,
                           num_vert,
                           origin=np.array([0, 0])):
    """generate r2rdac """
    r2r_name = 'r2r_dac_vref'
    bcap_name = 'r2r_dac_bcap_array_vref'
    sar_name = 'sar_wsamp'
    ret_name = 'adc_retimer'
    tgate_name = 'tgate_' + str(m) + 'x'
    pg = placement_grid

    rg_m4m5 = routing_grid_m4m5
    rg_m5m6 = routing_grid_m5m6
    # rg_m4m5 = routing_grid_m4m5
    # rg_m4m5_basic_thick = routing_grid_m4m5_basic_thick
    # rg_m4m5_thick = routing_grid_m4m5_thick
    # rg_m5m6 = routing_grid_m5m6
    # rg_m5m6_thick = routing_grid_m5m6_thick
    # rg_m5m6_thick_basic = routing_grid_m5m6_thick_basic
    # rg_m6m7_thick = routing_grid_m6m7_thick

    #boundaries
    x0=laygen.templates.get_template('capdac', workinglib).xy[1][0] - \
           laygen.templates.get_template('boundary_bottomleft').xy[1][0]*2
    m_bnd_float = x0 / laygen.templates.get_template(
        'boundary_bottom').xy[1][0]
    m_bnd = int(m_bnd_float)
    if not m_bnd_float == m_bnd:
        m_bnd += 1

    #Calculate reference coordinate
    bcap_origin = np.array([
        laygen.get_template_xy(name=r2r_name, gridname=pg,
                               libname=workinglib)[0] * num_hori, 0
    ])
    x1_phy = laygen.get_template_xy(name=r2r_name, gridname=None, libname=workinglib)[0]*num_hori \
             + laygen.get_template_xy(name=bcap_name, gridname=None, libname=workinglib)[0]
    pin_origin_x = laygen.grids.get_absgrid_x(rg_m5m6, x1_phy)
    pin_origin_x_thick = laygen.grids.get_absgrid_x(rg_m5m6_thick, x1_phy)
    y1_phy = origin[1] + laygen.get_template_xy(name=sar_name, gridname=None, libname=workinglib)[1] \
                   + laygen.get_template_xy(name=ret_name, gridname=None, libname=workinglib)[1]
    pin_origin_y = laygen.grids.get_absgrid_y(rg_m5m6, y1_phy)
    pin_origin_y2_thick = origin[1] + \
                          laygen.get_template_pin_xy(sar_name, 'VREF<2>_M6_0', rg_m5m6_thick, libname=workinglib)[0][1] \
                          + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    pin_origin_y1_thick = origin[1] + \
                          laygen.get_template_pin_xy(sar_name, 'VREF<1>_M6_0', rg_m5m6_thick, libname=workinglib)[0][1] \
                          + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    pin_origin_y0_thick = origin[1] + \
                          laygen.get_template_pin_xy(sar_name, 'VREF<0>_M6_0', rg_m5m6_thick, libname=workinglib)[0][1] \
                          + laygen.get_template_xy(name=ret_name, gridname=rg_m5m6_thick, libname=workinglib)[1]
    # pin_origin_y0_thick = laygen.grids.get_absgrid_y(rg_m5m6_thick, y0_phy)

    # placement
    irdac = []
    for i in range(num_vert):
        if i == 0:
            irdac.append(
                laygen.relplace(name="I" + objectname_pfix + 'IRDAC' + str(i),
                                templatename=r2r_name,
                                gridname=pg,
                                refinstname=None,
                                xy=origin,
                                shape=[num_hori, 1],
                                template_libname=workinglib))
        else:
            irdac.append(
                laygen.relplace(name="I" + objectname_pfix + 'IRDAC' + str(i),
                                templatename=r2r_name,
                                gridname=pg,
                                refinstname=irdac[-1].name,
                                shape=[num_hori, 1],
                                template_libname=workinglib,
                                direction='top'))
    ibcap = laygen.relplace(name="I" + objectname_pfix + 'IBCAP',
                            templatename=bcap_name,
                            gridname=pg,
                            refinstname=None,
                            xy=bcap_origin,
                            template_libname=workinglib)

    # output routing
    print(pin_origin_x)
    for k in range(4):
        rv2, rh2 = laygen.route_vh(
            laygen.layers['metal'][5],
            laygen.layers['metal'][6],
            xy0=laygen.get_inst_pin_xy(irdac[2].name,
                                       'out',
                                       rg_m5m6_basic_thick,
                                       index=np.array([0, 0]))[0] -
            np.array([2, -1]),
            xy1=np.array([pin_origin_x, pin_origin_y2_thick + k]),
            gridname0=rg_m5m6_basic_thick)
        rv1, rh1 = laygen.route_vh(
            laygen.layers['metal'][5],
            laygen.layers['metal'][6],
            xy0=laygen.get_inst_pin_xy(irdac[1].name,
                                       'out',
                                       rg_m5m6_basic_thick,
                                       index=np.array([0, 0]))[0] -
            np.array([1, -1]),
            xy1=np.array([pin_origin_x, pin_origin_y1_thick + k]),
            gridname0=rg_m5m6_basic_thick)
        rv0, rh0 = laygen.route_vh(
            laygen.layers['metal'][5],
            laygen.layers['metal'][6],
            xy0=laygen.get_inst_pin_xy(irdac[0].name,
                                       'out',
                                       rg_m5m6_basic_thick,
                                       index=np.array([0, 0]))[0] -
            np.array([0, -1]),
            xy1=np.array([pin_origin_x, pin_origin_y0_thick + k]),
            gridname0=rg_m5m6_basic_thick)
        for j in range(num_vert):
            laygen.via(
                None,
                xy=laygen.get_inst_pin_xy(
                    irdac[j].name, 'out', rg_m4m5, index=np.array([0, 0]))[0] -
                np.array([j, 0]),
                gridname=rg_m4m5)
        laygen.boundary_pin_from_rect(rh2,
                                      rg_m5m6_thick,
                                      'VREF' + str(k) + '<' + str(2) + '>',
                                      laygen.layers['pin'][6],
                                      size=4,
                                      direction='right',
                                      netname='VREF<' + str(2) + '>')
        laygen.boundary_pin_from_rect(rh1,
                                      rg_m5m6_thick,
                                      'VREF' + str(k) + '<' + str(1) + '>',
                                      laygen.layers['pin'][6],
                                      size=4,
                                      direction='right',
                                      netname='VREF<' + str(1) + '>')
        laygen.boundary_pin_from_rect(rh0,
                                      rg_m5m6_thick,
                                      'VREF' + str(k) + '<' + str(0) + '>',
                                      laygen.layers['pin'][6],
                                      size=4,
                                      direction='right',
                                      netname='VREF<' + str(0) + '>')

    # input routing
    # tgate_x = laygen.get_template_xy(tgate_name, gridname=rg_m4m5, libname=logictemplib)[0]
    for i in range(num_hori):
        for j in range(num_vert):
            x_ref = laygen.get_inst_pin_xy(irdac[j].name,
                                           'SEL<0>',
                                           rg_m4m5,
                                           index=np.array([i, 0]))[1][0]
            for k in range(num_bits):
                rh0, rv0 = laygen.route_hv(
                    laygen.layers['metal'][4],
                    laygen.layers['metal'][5],
                    xy0=laygen.get_inst_pin_xy(irdac[j].name,
                                               'SEL<' + str(k) + '>',
                                               rg_m4m5,
                                               index=np.array([i, 0]))[0],
                    xy1=np.array([x_ref + 12 + num_bits * j + k, 0]),
                    gridname0=rg_m4m5)
                laygen.boundary_pin_from_rect(
                    rv0,
                    rg_m4m5,
                    'SEL<' + str((num_hori * j + i) * num_bits + k) + '>',
                    laygen.layers['pin'][5],
                    size=4,
                    direction='bottom')

    # m5 supply
    pdict_m5m6_thick = laygen.get_inst_pin_xy(None, None, rg_m5m6_thick)
    rvdd_m5 = []
    rvss_m5 = []
    for i in range(num_hori):
        for p in pdict_m5m6_thick[irdac[0].name]:
            if p.startswith('VDD'):
                r0 = laygen.route(
                    None,
                    laygen.layers['metal'][5],
                    xy0=laygen.get_inst_pin_xy(irdac[0].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[0],
                    xy1=laygen.get_inst_pin_xy(irdac[num_vert - 1].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[1],
                    gridname0=rg_m5m6_thick)
                rvdd_m5.append(r0)
        for p in pdict_m5m6_thick[irdac[0].name]:
            if p.startswith('VSS'):
                r0 = laygen.route(
                    None,
                    laygen.layers['metal'][5],
                    xy0=laygen.get_inst_pin_xy(irdac[0].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[0],
                    xy1=laygen.get_inst_pin_xy(irdac[num_vert - 1].name,
                                               p,
                                               rg_m5m6_thick,
                                               index=np.array([i, 0]))[1],
                    gridname0=rg_m5m6_thick)
                rvss_m5.append(r0)

    # m6 (extract VDD/VSS grid from tisar and make power pins)
    tisar_name = 'tisaradc_body_core'
    tisar_libname = 'adc_sar_generated'
    rg_m5m6_thick_temp_tisar = 'route_M5_M6_thick_temp_tisar_VDD'
    # x_end = laygen.get_template_xy(r2r_name, gridname=rg_m5m6_thick_temp_tisar, libname=workinglib)[0] + \
    #         laygen.get_template_xy(bcap_name, gridname=rg_m5m6_thick_temp_tisar, libname=workinglib)[0]
    bnd = laygen.get_template(tisar_name, libname=tisar_libname).xy
    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=['VDDSAR'],
        bnd=bnd,
        xy_grid_type='ygrid')

    laygen.grids.display(libname=None, gridname=rg_m5m6_thick_temp_tisar)
    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=pin_origin_x_thick,
        offset_start_index=0,
        offset_end_index=0)
    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')
    laygen.grids.display(libname=None, gridname=rg_m5m6_thick_temp_tisar)
    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=pin_origin_x_thick,
        offset_start_index=0,
        offset_end_index=0)