예제 #1
0
def main():
    parser = argparse.ArgumentParser(description=__doc__,
                                     fromfile_prefix_chars='@',
                                     prefix_chars='-~')

    parser.add_argument('--db_root', help="""Project X-Ray database to use.""")

    parser.add_argument('--part', help="""FPGA part to use.""")

    parser.add_argument('--site_type', help="""Site type to generate for""")

    parser.add_argument('--output-pb-type',
                        nargs='?',
                        type=argparse.FileType('w'),
                        default=sys.stdout,
                        help="""File to write the output too.""")

    parser.add_argument('--output-model',
                        nargs='?',
                        type=argparse.FileType('w'),
                        default=sys.stdout,
                        help="""File to write the output too.""")

    args = parser.parse_args()

    db = prjxray.db.Database(args.db_root, args.part)

    site_type = db.get_site_type(args.site_type.upper())

    pb_type_xml = ET.Element(
        'pb_type',
        {
            'name': 'DUMMY-{}'.format(args.site_type),
        },
    )

    for site_pin_name in site_type.get_site_pins():
        site_pin = site_type.get_site_pin(site_pin_name)
        if site_pin.direction == prjxray.site_type.SitePinDirection.IN:
            ET.SubElement(pb_type_xml, 'input', {
                'name': site_pin.name,
            })
        elif site_pin.direction == prjxray.site_type.SitePinDirection.OUT:
            ET.SubElement(pb_type_xml, 'output', {
                'name': site_pin.name,
            })
        else:
            assert False, site_pin

    pb_type_str = ET.tostring(pb_type_xml, pretty_print=True).decode('utf-8')
    args.output_pb_type.write(pb_type_str)
    args.output_pb_type.close()

    model_xml = ET.Element('models')

    model_str = ET.tostring(model_xml, pretty_print=True).decode('utf-8')
    args.output_model.write(model_str)
    args.output_model.close()
예제 #2
0
def main():
    mydir = os.path.dirname(__file__)
    prjxray_db = os.path.abspath(
        os.path.join(mydir, "..", "..", "third_party", "prjxray-db"))

    db_types = prjxray.db.get_available_databases(prjxray_db)

    parser = argparse.ArgumentParser(description=__doc__,
                                     fromfile_prefix_chars='@',
                                     prefix_chars='-~')

    parser.add_argument(
        '--part',
        choices=[os.path.basename(db_type) for db_type in db_types],
        help="""Project X-Ray database to use.""")

    parser.add_argument('--site_type', help="""Site type to generate for""")

    parser.add_argument('--output-pb-type',
                        nargs='?',
                        type=argparse.FileType('w'),
                        default=sys.stdout,
                        help="""File to write the output too.""")

    parser.add_argument('--output-model',
                        nargs='?',
                        type=argparse.FileType('w'),
                        default=sys.stdout,
                        help="""File to write the output too.""")

    args = parser.parse_args()

    db = prjxray.db.Database(os.path.join(prjxray_db, args.part))

    site_type = db.get_site_type(args.site_type.upper())

    pb_type_xml = ET.Element(
        'pb_type',
        {
            'name': 'DUMMY-{}'.format(args.site_type),
        },
    )

    for site_pin_name in site_type.get_site_pins():
        site_pin = site_type.get_site_pin(site_pin_name)
        if site_pin.direction == prjxray.site_type.SitePinDirection.IN:
            ET.SubElement(pb_type_xml, 'input', {
                'name': site_pin.name,
            })
        elif site_pin.direction == prjxray.site_type.SitePinDirection.OUT:
            ET.SubElement(pb_type_xml, 'output', {
                'name': site_pin.name,
            })
        else:
            assert False, site_pin

    pb_type_str = ET.tostring(pb_type_xml, pretty_print=True).decode('utf-8')
    args.output_pb_type.write(pb_type_str)
    args.output_pb_type.close()

    model_xml = ET.Element('models')

    model_str = ET.tostring(model_xml, pretty_print=True).decode('utf-8')
    args.output_model.write(model_str)
    args.output_model.close()
def import_site_as_tile(db, args):
    """ Create a root-level pb_type with the same pin names as a site type.
    """
    site_type = db.get_site_type(args.tile)

    # Wires sink to a site within the tile are input wires.
    input_wires = set()

    # Wires source from a site within the tile are output wires.
    output_wires = set()

    site_type_instances = parse_site_type_instance(args.site_types)
    assert len(site_type_instances) == 1
    assert args.tile in site_type_instances
    assert len(site_type_instances[args.tile]) == 1

    for site_pin in site_type.get_site_pins():
        site_type_pin = site_type.get_site_pin(site_pin)

        if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
            input_wires.add(site_type_pin.name)
        elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
            output_wires.add(site_type_pin.name)
        else:
            assert False, site_type_pin.direction

    ##########################################################################
    # Generate the model.xml file                                            #
    ##########################################################################
    model = ModelXml(f=args.output_model, site_directory=args.site_directory)
    model.add_model_include(args.tile, site_type_instances[args.tile][0])
    model.write_model()

    ##########################################################################
    # Generate the pb_type.xml file                                          #
    ##########################################################################

    tile_name = args.tile
    pb_type_xml = start_pb_type(tile_name, args.pin_assignments, input_wires,
                                output_wires)

    site = args.tile
    site_instance = site_type_instances[args.tile][0]

    site_pbtype = args.site_directory + "/{0}/{1}.pb_type.xml"
    site_type_path = site_pbtype.format(site.lower(), site_instance.lower())
    ET.SubElement(pb_type_xml, XI_INCLUDE, {
        'href': site_type_path,
    })

    cell_pb_type = ET.ElementTree()
    root_element = cell_pb_type.parse(site_type_path)
    site_name = root_element.attrib['name']

    interconnect_xml = ET.Element('interconnect')

    interconnect_xml.append(ET.Comment(" Tile->Site "))
    for site_pin in sorted(site_type.get_site_pins()):
        site_type_pin = site_type.get_site_pin(site_pin)
        if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
            add_direct(interconnect_xml,
                       input=object_ref(add_vpr_tile_prefix(tile_name),
                                        site_pin),
                       output=object_ref(site_name, site_pin))
        elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
            pass
        else:
            assert False, site_type_pin.direction

    interconnect_xml.append(ET.Comment(" Site->Tile "))
    for site_pin in sorted(site_type.get_site_pins()):
        site_type_pin = site_type.get_site_pin(site_pin)
        if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
            pass
        elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
            add_direct(
                interconnect_xml,
                input=object_ref(site_name, site_pin),
                output=object_ref(add_vpr_tile_prefix(tile_name), site_pin),
            )
        else:
            assert False, site_type_pin.direction

    pb_type_xml.append(interconnect_xml)

    write_xml(args.output_pb_type, pb_type_xml)
def import_tile(db, args):
    """ Create a root-level pb_type with the pin names that match tile wires.

    This will either have 1 intermediate pb_type per site, or 1 large site
    for the entire tile if args.fused_sites is set to true.
    """

    tile = db.get_tile_type(args.tile)

    # Wires sink to a site within the tile are input wires.
    input_wires = set()

    # Wires source from a site within the tile are output wires.
    output_wires = set()

    if args.filter_x:
        xs = list(map(int, args.filter_x.split(',')))

        def x_filter_func(site):
            return site.x in xs

        x_filter = x_filter_func
    else:

        def x_filter_func(site):
            return True

        x_filter = x_filter_func

    if not args.fused_sites:
        site_type_instances = parse_site_type_instance(args.site_types)

        imported_site_types = set()
        ignored_site_types = set()

        for site in tile.get_sites():
            site_type = db.get_site_type(site.type)

            if site.type not in site_type_instances:
                ignored_site_types.add(site.type)
                continue

            imported_site_types.add(site.type)

            for site_pin in site.site_pins:
                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    if site_pin.wire is not None:
                        input_wires.add(site_pin.wire)
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    if site_pin.wire is not None:
                        output_wires.add(site_pin.wire)
                else:
                    if site.type != "PS7":
                        assert False, site_type_pin.direction

        # Make sure all requested site types actually get imported.
        assert len(set(site_type_instances.keys()) -
                   imported_site_types) == 0, (site_type_instances.keys(),
                                               imported_site_types)

        for ignored_site_type in ignored_site_types:
            print(
                '*** WARNING *** Ignored site type {} in tile type {}'.format(
                    ignored_site_type, args.tile),
                file=sys.stderr)
    else:
        for site in tile.get_sites():
            site_type = db.get_site_type(site.type)

            for site_pin in site.site_pins:
                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    if site_pin.wire is not None:
                        input_wires.add(site_pin.wire)
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    if site_pin.wire is not None:
                        output_wires.add(site_pin.wire)
                else:
                    assert False, site_type_pin.direction

    site_pbtype = args.site_directory + "/{0}/{1}.pb_type.xml"

    ##########################################################################
    # Generate the model.xml file                                            #
    ##########################################################################

    model = ModelXml(f=args.output_model, site_directory=args.site_directory)

    if args.fused_sites:
        fused_site_name = args.tile.lower()

        model.add_model_include(fused_site_name, fused_site_name)

    ##########################################################################
    # Utility functions for pb_type                                          #
    ##########################################################################
    tile_name = args.tile

    pb_type_xml = start_pb_type(tile_name, args.pin_assignments, input_wires,
                                output_wires)

    cell_names = {}

    interconnect_xml = ET.Element('interconnect')

    if not args.fused_sites:
        site_type_count = {}
        site_prefixes = {}
        cells_idx = {}
        models_added = set()

        site_type_ports = {}
        idx = 0
        for site in tile.get_sites():
            if site.type in ignored_site_types:
                continue

            if not x_filter(site):
                continue

            if site.type not in site_type_count:
                site_type_count[site.type] = 0
                site_prefixes[site.type] = []

            cells_idx[idx] = site_type_count[site.type]
            site_type_count[site.type] += 1

            site_coords = args.site_coords.upper()
            if site_coords == 'X':
                site_prefix = '{}_X{}'.format(site.type, site.x)
            elif site_coords == 'Y':
                site_prefix = '{}_Y{}'.format(site.type, site.y)
            elif site_coords == 'XY':
                site_prefix = '{}.{}_X{}Y{}'.format(site.type, site.type,
                                                    site.x, site.y)
            else:
                assert False, "Invalid --site-coords value '{}'".format(
                    site_coords)

            site_instance = site_type_instances[site.type][cells_idx[idx]]
            idx += 1

            if (site.type, site_instance) not in models_added:
                models_added.add((site.type, site_instance))
                model.add_model_include(site.type, site_instance)

            site_type_path = site_pbtype.format(site.type.lower(),
                                                site_instance.lower())
            cell_pb_type = ET.ElementTree()
            root_element = cell_pb_type.parse(site_type_path)
            cell_names[site_instance] = root_element.attrib['name']

            ports = {}
            for inputs in root_element.iter('input'):
                ports[inputs.attrib['name']] = int(inputs.attrib['num_pins'])

            for clocks in root_element.iter('clock'):
                ports[clocks.attrib['name']] = int(clocks.attrib['num_pins'])

            for outputs in root_element.iter('output'):
                ports[outputs.attrib['name']] = int(outputs.attrib['num_pins'])

            assert site_instance not in site_type_ports, (
                site_instance, site_type_ports.keys())
            site_type_ports[site_instance] = ports

            attrib = dict(root_element.attrib)
            include_xml = ET.SubElement(pb_type_xml, 'pb_type', attrib)
            ET.SubElement(
                include_xml, XI_INCLUDE, {
                    'href':
                    site_type_path,
                    'xpointer':
                    "xpointer(pb_type/child::node()[local-name()!='metadata'])",
                })

            metadata_xml = ET.SubElement(include_xml, 'metadata')

            if not args.no_fasm_prefix:
                ET.SubElement(metadata_xml, 'meta', {
                    'name': 'fasm_prefix',
                }).text = site_prefix

            # Import pb_type metadata if it exists.
            if any(child.tag == 'metadata' for child in root_element):
                ET.SubElement(
                    metadata_xml, XI_INCLUDE, {
                        'href': site_type_path,
                        'xpointer': "xpointer(pb_type/metadata/child::node())",
                    })

            # Prevent emitting empty metadata
            if not any(child.tag == 'meta' for child in metadata_xml):
                include_xml.remove(metadata_xml)

        idx = 0
        for site in tile.get_sites():
            if site.type in ignored_site_types:
                continue

            site_idx = cells_idx[idx]
            idx += 1

            if not x_filter(site):
                continue

            site_instance = site_type_instances[site.type][site_idx]
            site_name = cell_names[site_instance]

            site_type = db.get_site_type(site.type)

            interconnect_xml.append(ET.Comment(" Tile->Site "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port = find_port(site_pin.name, site_type_ports[site_instance])
                if port is None:
                    print(
                        "*** WARNING *** Didn't find port for name {} for site type {}"
                        .format(site_pin.name, site.type),
                        file=sys.stderr)
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    add_direct(interconnect_xml,
                               input=object_ref(add_vpr_tile_prefix(tile_name),
                                                site_pin.wire),
                               output=object_ref(site_name, **port))
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    pass
                else:
                    if site.type != "PS7":
                        assert False, site_type_pin.direction

            interconnect_xml.append(ET.Comment(" Site->Tile "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port = find_port(site_pin.name, site_type_ports[site_instance])
                if port is None:
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    pass
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    add_direct(
                        interconnect_xml,
                        input=object_ref(site_name, **port),
                        output=object_ref(add_vpr_tile_prefix(tile_name),
                                          site_pin.wire),
                    )
                else:
                    if site.type != "PS7":
                        assert False, site_type_pin.direction
    else:
        site_type_ports = {}

        site_type_path = site_pbtype.format(fused_site_name, fused_site_name)
        cell_pb_type = ET.ElementTree()
        root_element = cell_pb_type.parse(site_type_path)

        ports = {}
        for inputs in root_element.iter('input'):
            ports[inputs.attrib['name']] = int(inputs.attrib['num_pins'])

        for clocks in root_element.iter('clock'):
            ports[clocks.attrib['name']] = int(clocks.attrib['num_pins'])

        for outputs in root_element.iter('output'):
            ports[outputs.attrib['name']] = int(outputs.attrib['num_pins'])

        attrib = dict(root_element.attrib)
        include_xml = ET.SubElement(pb_type_xml, 'pb_type', attrib)
        ET.SubElement(
            include_xml, XI_INCLUDE, {
                'href': site_type_path,
                'xpointer': "xpointer(pb_type/child::node())",
            })

        site_name = root_element.attrib['name']

        def fused_port_name(site, site_pin):
            return '{}_{}_{}'.format(site.prefix, site.name, site_pin.name)

        for site in tile.get_sites():
            site_type = db.get_site_type(site.type)

            interconnect_xml.append(ET.Comment(" Tile->Site "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port_name = fused_port_name(site, site_pin)
                port = find_port(port_name, ports)
                if port is None:
                    print(
                        "*** WARNING *** Didn't find port for name {} for site type {}"
                        .format(port_name, site.type),
                        file=sys.stderr)
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    add_direct(interconnect_xml,
                               input=object_ref(add_vpr_tile_prefix(tile_name),
                                                site_pin.wire),
                               output=object_ref(site_name, **port))
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    pass
                else:
                    if site.type != "PS7":
                        assert False, site_type_pin.direction

            interconnect_xml.append(ET.Comment(" Site->Tile "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port = find_port(fused_port_name(site, site_pin), ports)
                if port is None:
                    # Already warned above
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    pass
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    add_direct(
                        interconnect_xml,
                        input=object_ref(site_name, **port),
                        output=object_ref(add_vpr_tile_prefix(tile_name),
                                          site_pin.wire),
                    )
                else:
                    if site.type != "PS7":
                        assert False, site_type_pin.direction

    pb_type_xml.append(interconnect_xml)

    model.write_model()
    write_xml(args.output_pb_type, pb_type_xml)
예제 #5
0
def main():
    mydir = os.path.dirname(__file__)
    prjxray_db = os.path.abspath(
        os.path.join(mydir, "..", "..", "third_party", "prjxray-db"))

    db_types = prjxray.db.get_available_databases(prjxray_db)

    parser = argparse.ArgumentParser(description=__doc__,
                                     fromfile_prefix_chars='@',
                                     prefix_chars='-~')

    parser.add_argument(
        '--part',
        choices=[os.path.basename(db_type) for db_type in db_types],
        help="""Project X-Ray database to use.""")

    parser.add_argument('--tile', help="""Tile to generate for""")

    parser.add_argument('--site_directory',
                        help="""Diretory where sites are defined""")

    parser.add_argument('--output-pb-type',
                        nargs='?',
                        type=argparse.FileType('w'),
                        default=sys.stdout,
                        help="""File to write the output too.""")

    parser.add_argument('--output-model',
                        nargs='?',
                        type=argparse.FileType('w'),
                        default=sys.stdout,
                        help="""File to write the output too.""")

    parser.add_argument('--pin_assignments',
                        required=True,
                        type=argparse.FileType('r'))

    parser.add_argument(
        '--site_types',
        required=True,
        help="Comma seperated list of site types to include in this tile.")

    parser.add_argument(
        '--fused_sites',
        action='store_true',
        help=
        "Typically a tile can treat the sites within the tile as independent.  For tiles where this is not true, fused sites only imports 1 primatative for the entire tile, which should be named the same as the tile type."
    )

    args = parser.parse_args()

    db = prjxray.db.Database(os.path.join(prjxray_db, args.part))

    tile = db.get_tile_type(args.tile)

    # Wires sink to a site within the tile are input wires.
    input_wires = set()

    # Wires source from a site within the tile are output wires.
    output_wires = set()

    if not args.fused_sites:
        site_type_instances = {}
        for s in args.site_types.split(','):
            site_type, site_type_instance = s.split('/')

            if site_type not in site_type_instances:
                site_type_instances[site_type] = []

            site_type_instances[site_type].append(site_type_instance)

        imported_site_types = set()
        ignored_site_types = set()

        for site in tile.get_sites():
            site_type = db.get_site_type(site.type)

            if site.type not in site_type_instances:
                ignored_site_types.add(site.type)
                continue

            imported_site_types.add(site.type)

            for site_pin in site.site_pins:
                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    if site_pin.wire is not None:
                        input_wires.add(site_pin.wire)
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    if site_pin.wire is not None:
                        output_wires.add(site_pin.wire)
                else:
                    assert False, site_type_pin.direction

        # Make sure all requested site types actually get imported.
        assert len(set(site_type_instances.keys()) -
                   imported_site_types) == 0, (site_type_instances.keys(),
                                               imported_site_types)

        for ignored_site_type in ignored_site_types:
            print(
                '*** WARNING *** Ignored site type {} in tile type {}'.format(
                    ignored_site_type, args.tile),
                file=sys.stderr)
    else:
        for site in tile.get_sites():
            site_type = db.get_site_type(site.type)

            for site_pin in site.site_pins:
                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    if site_pin.wire is not None:
                        input_wires.add(site_pin.wire)
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    if site_pin.wire is not None:
                        output_wires.add(site_pin.wire)
                else:
                    assert False, site_type_pin.direction

    site_model = args.site_directory + "/{0}/{1}.model.xml"
    site_pbtype = args.site_directory + "/{0}/{1}.pb_type.xml"

    xi_url = "http://www.w3.org/2001/XInclude"
    ET.register_namespace('xi', xi_url)
    xi_include = "{%s}include" % xi_url

    ##########################################################################
    # Generate the model.xml file                                            #
    ##########################################################################

    model_xml = ET.Element(
        'models',
        nsmap={'xi': xi_url},
    )

    def add_model_include(site_type, instance_name):
        ET.SubElement(
            model_xml, xi_include, {
                'href': site_model.format(site_type.lower(),
                                          instance_name.lower()),
                'xpointer': "xpointer(models/child::node())"
            })

    if not args.fused_sites:
        site_types = set(site.type for site in tile.get_sites())
        for site_type in site_types:
            if site_type in ignored_site_types:
                continue

            for instance in site_type_instances[site_type]:
                add_model_include(site_type, instance)
    else:
        fused_site_name = args.tile.lower()

        add_model_include(fused_site_name, fused_site_name)

    model_str = ET.tostring(model_xml, pretty_print=True).decode('utf-8')
    args.output_model.write(model_str)
    args.output_model.close()

    ##########################################################################
    # Generate the pb_type.xml file                                          #
    ##########################################################################

    def add_direct(xml, input, output):
        ET.SubElement(
            xml, 'direct', {
                'name': '{}_to_{}'.format(input, output),
                'input': input,
                'output': output
            })

    tile_name = "BLK_TI-{}".format(args.tile)

    pb_type_xml = ET.Element(
        'pb_type',
        {
            'name': tile_name,
        },
        nsmap={'xi': xi_url},
    )

    fc_xml = ET.SubElement(pb_type_xml, 'fc', {
        'in_type': 'abs',
        'in_val': '2',
        'out_type': 'abs',
        'out_val': '2',
    })

    interconnect_xml = ET.Element('interconnect')

    pb_type_xml.append(ET.Comment(" Tile Inputs "))

    # Input definitions for the TILE
    for name in sorted(input_wires):
        input_type = 'input'

        if 'CLK' in name:
            input_type = 'clock'

        ET.SubElement(
            pb_type_xml,
            input_type,
            {
                'name': name,
                'num_pins': '1'
            },
        )

    pb_type_xml.append(ET.Comment(" Tile Outputs "))
    for name in sorted(output_wires):
        # Output definitions for the TILE
        ET.SubElement(
            pb_type_xml,
            'output',
            {
                'name': name,
                'num_pins': '1'
            },
        )

    pb_type_xml.append(ET.Comment(" Internal Sites "))

    cell_names = {}

    if not args.fused_sites:
        site_type_count = {}
        site_prefixes = {}
        cells_idx = []

        site_type_ports = {}
        for idx, site in enumerate(tile.get_sites()):
            if site.type in ignored_site_types:
                continue

            if site.type not in site_type_count:
                site_type_count[site.type] = 0
                site_prefixes[site.type] = []

            cells_idx.append(site_type_count[site.type])
            site_type_count[site.type] += 1
            site_prefix = '{}_X{}'.format(site.type, site.x)

            site_instance = site_type_instances[site.type][cells_idx[idx]]

            print(site_prefix, site_instance)

            site_type_path = site_pbtype.format(site.type.lower(),
                                                site_instance.lower())
            cell_pb_type = ET.ElementTree()
            root_element = cell_pb_type.parse(site_type_path)
            cell_names[site_instance] = root_element.attrib['name']

            ports = {}
            for inputs in root_element.iter('input'):
                ports[inputs.attrib['name']] = int(inputs.attrib['num_pins'])

            for clocks in root_element.iter('clock'):
                ports[clocks.attrib['name']] = int(clocks.attrib['num_pins'])

            for outputs in root_element.iter('output'):
                ports[outputs.attrib['name']] = int(outputs.attrib['num_pins'])

            assert site_instance not in site_type_ports, (
                site_instance, site_type_ports.keys())
            site_type_ports[site_instance] = ports

            attrib = dict(root_element.attrib)
            include_xml = ET.SubElement(pb_type_xml, 'pb_type', attrib)
            ET.SubElement(
                include_xml, xi_include, {
                    'href':
                    site_type_path,
                    'xpointer':
                    "xpointer(pb_type/child::node()[local-name()!='metadata'])",
                })

            metadata_xml = ET.SubElement(include_xml, 'metadata')
            ET.SubElement(metadata_xml, 'meta', {
                'name': 'fasm_prefix',
            }).text = site_prefix

            # Import pb_type metadata if it exists.
            if any(child.tag == 'metadata' for child in root_element):
                ET.SubElement(
                    metadata_xml, xi_include, {
                        'href': site_type_path,
                        'xpointer': "xpointer(pb_type/metadata/child::node())",
                    })

        for idx, site in enumerate(tile.get_sites()):
            if site.type in ignored_site_types:
                continue

            site_idx = cells_idx[idx]
            site_instance = site_type_instances[site.type][site_idx]
            site_name = cell_names[site_instance]

            site_type = db.get_site_type(site.type)

            interconnect_xml.append(ET.Comment(" Tile->Site "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port = find_port(site_pin.name, site_type_ports[site_instance])
                if port is None:
                    print(
                        "*** WARNING *** Didn't find port for name {} for site type {}"
                        .format(site_pin.name, site.type),
                        file=sys.stderr)
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    add_direct(interconnect_xml,
                               input=object_ref(tile_name, site_pin.wire),
                               output=object_ref(site_name, **port))
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    pass
                else:
                    assert False, site_type_pin.direction

            interconnect_xml.append(ET.Comment(" Site->Tile "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port = find_port(site_pin.name, site_type_ports[site_instance])
                if port is None:
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    pass
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    add_direct(
                        interconnect_xml,
                        input=object_ref(site_name, **port),
                        output=object_ref(tile_name, site_pin.wire),
                    )
                else:
                    assert False, site_type_pin.direction
    else:
        site_type_ports = {}

        site_type_path = site_pbtype.format(fused_site_name, fused_site_name)
        cell_pb_type = ET.ElementTree()
        root_element = cell_pb_type.parse(site_type_path)

        ports = {}
        for inputs in root_element.iter('input'):
            ports[inputs.attrib['name']] = int(inputs.attrib['num_pins'])

        for clocks in root_element.iter('clock'):
            ports[clocks.attrib['name']] = int(clocks.attrib['num_pins'])

        for outputs in root_element.iter('output'):
            ports[outputs.attrib['name']] = int(outputs.attrib['num_pins'])

        attrib = dict(root_element.attrib)
        include_xml = ET.SubElement(pb_type_xml, 'pb_type', attrib)
        ET.SubElement(
            include_xml, xi_include, {
                'href': site_type_path,
                'xpointer': "xpointer(pb_type/child::node())",
            })

        site_name = root_element.attrib['name']

        def fused_port_name(site, site_pin):
            return '{}_{}_{}'.format(site.prefix, site.name, site_pin.name)

        for idx, site in enumerate(tile.get_sites()):
            site_type = db.get_site_type(site.type)

            interconnect_xml.append(ET.Comment(" Tile->Site "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port_name = fused_port_name(site, site_pin)
                port = find_port(port_name, ports)
                if port is None:
                    print(
                        "*** WARNING *** Didn't find port for name {} for site type {}"
                        .format(port_name, site.type),
                        file=sys.stderr)
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    add_direct(interconnect_xml,
                               input=object_ref(tile_name, site_pin.wire),
                               output=object_ref(site_name, **port))
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    pass
                else:
                    assert False, site_type_pin.direction

            interconnect_xml.append(ET.Comment(" Site->Tile "))
            for site_pin in sorted(site.site_pins,
                                   key=lambda site_pin: site_pin.name):
                if site_pin.wire is None:
                    continue

                port = find_port(fused_port_name(site, site_pin), ports)
                if port is None:
                    # Already warned above
                    continue

                site_type_pin = site_type.get_site_pin(site_pin.name)

                if site_type_pin.direction == prjxray.site_type.SitePinDirection.IN:
                    pass
                elif site_type_pin.direction == prjxray.site_type.SitePinDirection.OUT:
                    add_direct(
                        interconnect_xml,
                        input=object_ref(site_name, **port),
                        output=object_ref(tile_name, site_pin.wire),
                    )
                else:
                    assert False, site_type_pin.direction

    pb_type_xml.append(interconnect_xml)

    ET.SubElement(pb_type_xml, 'switchblock_locations', {
        'pattern': 'all',
    })

    pinlocations_xml = ET.SubElement(pb_type_xml, 'pinlocations', {
        'pattern': 'custom',
    })

    if len(input_wires) > 0 or len(output_wires) > 0:
        pin_assignments = json.load(args.pin_assignments)

        sides = {}
        for pin in input_wires | output_wires:
            for side in pin_assignments['pin_directions'][args.tile][pin]:
                if side not in sides:
                    sides[side] = []

                sides[side].append(object_ref(tile_name, pin))

        for side, pins in sides.items():
            ET.SubElement(pinlocations_xml, 'loc', {
                'side': side.lower(),
            }).text = ' '.join(pins)

    metadata_xml = ET.SubElement(pb_type_xml, 'metadata')
    ET.SubElement(metadata_xml, 'meta', {
        'name': 'fasm_prefix',
    }).text = args.tile

    direct_pins = set()
    for direct in pin_assignments['direct_connections']:
        if direct['from_pin'].split('.')[0] == args.tile:
            direct_pins.add(direct['from_pin'].split('.')[1])

        if direct['to_pin'].split('.')[0] == args.tile:
            direct_pins.add(direct['to_pin'].split('.')[1])

    for fc_override in direct_pins:
        ET.SubElement(fc_xml, 'fc_override', {
            'fc_type': 'frac',
            'fc_val': '0.0',
            'port_name': fc_override,
        })

    pb_type_str = ET.tostring(pb_type_xml, pretty_print=True).decode('utf-8')
    args.output_pb_type.write(pb_type_str)
    args.output_pb_type.close()