Exemplo n.º 1
0
 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())"
         })
 def add_model_include(self, site_type, instance_name):
     ET.SubElement(
         self.model_xml, XI_INCLUDE, {
             'href':
             self.site_model.format(site_type.lower(),
                                    instance_name.lower()),
             'xpointer':
             "xpointer(models/child::node())"
         })
def import_tile_from_database(conn, args):
    """ Create a root-level pb_type using the site pins and sites from the database.
    """

    # 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()

    cur = conn.cursor()
    cur2 = conn.cursor()

    cur.execute("SELECT pkey FROM tile_type WHERE name = ?", (args.tile, ))
    tile_type_pkey = cur.fetchone()[0]

    # Find instances of sites, sorted by their original tile type.
    # Then choice the first of each site type as the wire set.
    # This ensures a unique and internally consistent site set for analyzing
    # connectivity.
    #
    # Note:  This does assume that only one instance of each site is present
    # in each tile, which is checked.
    sites = {}
    sites_in_tiles = set()
    cur.execute(
        """
SELECT
    site.site_type_pkey, wire_in_tile.site_pkey, wire_in_tile.phy_tile_type_pkey
FROM wire_in_tile
INNER JOIN site
ON site.pkey = wire_in_tile.site_pkey
WHERE
    wire_in_tile.tile_type_pkey = ?
GROUP BY site.site_type_pkey, wire_in_tile.phy_tile_type_pkey
ORDER BY wire_in_tile.phy_tile_type_pkey;""", (tile_type_pkey, ))
    for site_type_pkey, site_pkey, phy_tile_type_pkey in cur:
        if site_type_pkey not in sites:
            sites[site_type_pkey] = site_pkey

        # Verify that assumption that each site type is only used once per tile
        # is true.
        key = (site_type_pkey, phy_tile_type_pkey)
        assert key not in sites_in_tiles, key
        sites_in_tiles.add(key)

    # Retrieve initial top-level port names
    top_level_pins = {}
    for site_pkey in sites.values():
        for wire_in_tile_pkey, wire_name, direction in cur.execute(
                """
SELECT
    wire_in_tile.pkey, wire_in_tile.name, site_pin.direction
FROM wire_in_tile
INNER JOIN site_pin
ON wire_in_tile.site_pin_pkey = site_pin.pkey
WHERE
    site_pkey = ?""", (site_pkey, )):
            direction = prjxray.site_type.SitePinDirection(direction)

            assert wire_name not in top_level_pins
            top_level_pins[wire_name] = (site_pkey, wire_in_tile_pkey)

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

    ##########################################################################
    # Generate the model.xml file                                            #
    ##########################################################################
    model = ModelXml(f=args.output_model, site_directory=args.site_directory)
    site_type_instances = parse_site_type_instance(args.site_types)

    for site_type_pkey in sites:
        cur.execute("SELECT name FROM site_type WHERE pkey = ?",
                    (site_type_pkey, ))
        site_type = cur.fetchone()[0]
        for instance in site_type_instances[site_type]:
            model.add_model_include(site_type, instance)
    model.write_model()

    # Determine which input/output wires connection to other site pins, and no
    # others.
    top_level_connections, internal_connections = find_connections(
        conn, input_wires, output_wires, tile_type_pkey)

    ##########################################################################
    # 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)

    cell_names = {}

    interconnect_xml = ET.Element('interconnect')

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

    site_type_count = {}
    site_prefixes = {}
    cells_idx = []

    ignored_site_types = set()

    cur.execute(
        """
WITH tiles_per_tile(num_tiles) AS (
  SELECT count()
  FROM tile_map
  INNER JOIN tile
  ON tile_map.tile_pkey = tile.pkey
  WHERE tile.tile_type_pkey = ?
  GROUP BY tile_map.tile_pkey
)
SELECT max(num_tiles) FROM tiles_per_tile;
        """, (tile_type_pkey, ))
    max_tile_count = cur.fetchone()[0]
    need_tile_prefixs = max_tile_count > 1

    site_type_ports = {}
    cur.execute(
        """
SELECT DISTINCT
  site_type.name, site_instance.y_coord % 2
FROM
  site
INNER JOIN
  site_type
ON site.site_type_pkey = site_type.pkey
INNER JOIN
  site_instance
ON site.pkey = site_instance.site_pkey
WHERE
  site.pkey IN (
    SELECT
      DISTINCT site_pkey
    FROM
      wire_in_tile
    WHERE
      tile_type_pkey = ?
      AND site_pin_pkey IS NOT NULL
  )
    """, (tile_type_pkey, ))
    for idx, (site_type, site_y) in enumerate(cur):
        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 = '{}_Y{}'.format(normalize_site_type(site_type), site_y)

        # When tiles are merged, additional tile prefixes are required here
        # to disambiguate which physical tile this site belongs too
        if need_tile_prefixs:
            tile_prefix = get_tile_prefix(conn, tile_type_pkey, site_type)
            site_prefix = '{}.{}'.format(tile_prefix, site_prefix)

        site_instance = site_type_instances[site_type][cells_idx[idx]]

        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)

    # Iterate over sites in tile
    cur.execute(
        """
SELECT
  site_type.name,
  site.pkey
FROM
  site
  INNER JOIN site_type ON site.site_type_pkey = site_type.pkey
WHERE
  site.pkey IN (
    SELECT
      DISTINCT site_pkey
    FROM
      wire_in_tile
    WHERE
      tile_type_pkey = ?
      AND site_pin_pkey IS NOT NULL
  )
GROUP BY
  site.site_type_pkey,
  site.x_coord,
  site.y_coord
    """, (tile_type_pkey, ))
    for idx, (site_type, site_pkey) in enumerate(cur):
        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]

        interconnect_xml.append(ET.Comment(" Tile->Site "))

        # Iterate over pins in site
        cur2.execute(
            """
SELECT
  site_pin.name,
  site_pin.direction,
  wire_in_tile.name
FROM
  wire_in_tile
  INNER JOIN site_pin ON wire_in_tile.site_pin_pkey = site_pin.pkey
WHERE
  wire_in_tile.tile_type_pkey = ?
  AND wire_in_tile.site_pkey = ?
  AND wire_in_tile.site_pin_pkey IS NOT NULL;
        """, (tile_type_pkey, site_pkey))
        site_pins = list(cur2)
        for site_pin_name, site_pin_direction, site_pin_wire in site_pins:
            site_pin_direction = prjxray.site_type.SitePinDirection(
                site_pin_direction)
            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

            # Sanity check top_level_connections
            if site_pin_wire not in top_level_connections:
                continue

            assert top_level_connections[site_pin_wire] == (site_type,
                                                            site_pin_name)

            if site_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_pin_direction == prjxray.site_type.SitePinDirection.OUT:
                pass
            else:
                assert False, site_pin_direction

        interconnect_xml.append(ET.Comment(" Site->Tile "))

        # Iterate over pins in site
        cur2.execute("")
        for site_pin_name, site_pin_direction, site_pin_wire in site_pins:
            site_pin_direction = prjxray.site_type.SitePinDirection(
                site_pin_direction)
            port = find_port(site_pin_name, site_type_ports[site_instance])
            if port is None:
                continue

            # Sanity check top_level_connections
            if site_pin_wire not in top_level_connections:
                continue

            assert top_level_connections[site_pin_wire] == (site_type,
                                                            site_pin_name)

            if site_pin_direction == prjxray.site_type.SitePinDirection.IN:
                pass
            elif site_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:
                assert False, site_pin_direction

    interconnect_xml.append(ET.Comment(" Site->Site "))

    for (dest_site_type, dest_site_pin_name), (src_site_type, src_site_pin_name) in \
            sorted(internal_connections.items(), key=lambda x: (x[1], x[0])):
        # Only handling single instance per site type right now
        assert len(site_type_instances[src_site_type]) == 1
        assert len(site_type_instances[dest_site_type]) == 1

        src_site_instance = site_type_instances[src_site_type][0]
        src_port = find_port(src_site_pin_name,
                             site_type_ports[src_site_instance])
        src_site_name = cell_names[src_site_instance]
        if src_port is None:
            print(
                "*** WARNING *** Didn't find port for name {} for site type {}"
                .format(src_site_pin_name, src_site_type),
                file=sys.stderr)
            continue

        dest_site_instance = site_type_instances[dest_site_type][0]
        dest_port = find_port(dest_site_pin_name,
                              site_type_ports[dest_site_instance])
        dest_site_name = cell_names[dest_site_instance]
        if dest_port is None:
            print(
                "*** WARNING *** Didn't find port for name {} for site type {}"
                .format(dest_site_pin_name, dest_site_type),
                file=sys.stderr)
            continue

        add_direct(
            interconnect_xml,
            input=object_ref(src_site_name, **src_port),
            output=object_ref(dest_site_name, **dest_port),
        )

    pb_type_xml.append(interconnect_xml)

    write_xml(args.output_pb_type, pb_type_xml)
def create_pb_type(conn, pin_assignments, site_directory, output_directory,
                   pb_type, site_type_pkeys, tile_type_pkeys, site_remaps,
                   site_name_remaps, node_tile_map):
    cur = conn.cursor()
    cur2 = conn.cursor()

    wire_to_site_pin = {}
    internal_connections = {}
    top_level_pin_external = set()
    top_level_wire_external = set()

    all_pb_type_input_pins = None
    all_pb_type_output_pins = None

    for tile_type_pkey in tile_type_pkeys:
        pb_type_input_pins = set()
        pb_type_output_pins = set()

        for node_set in node_tile_map[tile_type_pkey]:
            ipin_count = 0
            opin_count = 0
            node_set_has_external = False

            pins_used_in_node_sets = set()
            input_pins = set()
            output_pins = set()

            for node_pkey in node_set:
                cur.execute(
                    """
SELECT
    tile.tile_type_pkey,
    wire_in_tile.name,
    site_type.pkey,
    site_type.name,
    site_pin.name,
    site_pin.direction,
    count()
FROM wire
INNER JOIN wire_in_tile
ON wire.wire_in_tile_pkey = wire_in_tile.pkey
INNER JOIN site_pin
ON site_pin.pkey = wire_in_tile.site_pin_pkey
INNER JOIN tile
ON wire.tile_pkey = tile.pkey
INNER JOIN site_type
ON site_type.pkey = site_pin.site_type_pkey
WHERE
    wire.node_pkey = ?
AND
    wire_in_tile.site_pin_pkey IS NOT NULL
GROUP BY site_pin.direction;
        """, (node_pkey, ))
                for (wire_tile_type_pkey, wire_name, site_type_pkey,
                     site_type_name, site_pin_name, direction, count) in cur:

                    if wire_tile_type_pkey == tile_type_pkey:
                        if site_type_pkey not in site_type_pkeys:
                            # Remap if a mapping exists
                            site_type_name = site_name_remaps.get(
                                site_type_name, site_type_name)
                            cur2.execute(
                                "SELECT pkey FROM site_type WHERE name = ?",
                                (site_type_name, ))
                            new_site_type_pkey = cur2.fetchone()[0]
                            assert new_site_type_pkey in site_type_pkeys, (
                                pb_type, tile_type_pkey, node_pkey,
                                site_type_pkey, new_site_type_pkey,
                                site_type_pkeys, site_type_name)

                        direction = prjxray.site_type.SitePinDirection(
                            direction)
                        value = (site_type_name, site_pin_name, direction)
                        if wire_name in wire_to_site_pin:
                            assert value == wire_to_site_pin[wire_name], (
                                wire_name, value, wire_to_site_pin[wire_name])
                        else:
                            wire_to_site_pin[wire_name] = value

                        pins_used_in_node_sets.add(
                            (wire_name, site_type_name, site_pin_name))

                        if direction == prjxray.site_type.SitePinDirection.IN:
                            output_pins.add(wire_name)
                            pb_type_output_pins.add(
                                (site_type_name, site_pin_name))
                            opin_count += count
                        elif direction == prjxray.site_type.SitePinDirection.OUT:
                            input_pins.add(wire_name)
                            pb_type_input_pins.add(
                                (site_type_name, site_pin_name))
                            ipin_count += count
                        else:
                            assert False, (node_pkey, direction)
                    else:
                        node_set_has_external = True

            assert len(input_pins) in [0, 1], input_pins

            if ipin_count == 0 or opin_count == 0 or node_set_has_external or len(
                    site_type_pkeys) == 1:
                # This node set is connected externally, mark as such
                for wire_name, site_type_name, site_pin_name in pins_used_in_node_sets:
                    top_level_wire_external.add(wire_name)
                    top_level_pin_external.add((site_type_name, site_pin_name))

            if len(site_type_pkeys) == 1:
                continue

            if ipin_count > 0 and opin_count > 0:
                # TODO: Add check that pips and site pins on these internal
                # connections are 0 delay.
                assert len(input_pins) == 1
                input_wire = input_pins.pop()

                for wire_name in output_pins:
                    k = wire_to_site_pin[wire_name]
                    v = wire_to_site_pin[input_wire]
                    if k in internal_connections:
                        assert v == internal_connections[k], (
                            v, internal_connections[k])
                    else:
                        internal_connections[k] = v

        pb_type_input_pins = set(v for v in pb_type_input_pins
                                 if v in top_level_pin_external)
        pb_type_output_pins = set(v for v in pb_type_output_pins
                                  if v in top_level_pin_external)

        if all_pb_type_input_pins is None:
            all_pb_type_input_pins = pb_type_input_pins
            all_pb_type_output_pins = pb_type_output_pins
        else:
            all_pb_type_input_pins &= pb_type_input_pins
            all_pb_type_output_pins &= pb_type_output_pins

    ##########################################################################
    # Generate the model.xml file                                            #
    ##########################################################################
    model = ModelXml(f=os.path.join(output_directory, pb_type.lower(),
                                    '{}.model.xml'.format(pb_type.lower())),
                     site_directory=site_directory)

    for site_type_pkey in site_type_pkeys:
        cur.execute("SELECT name FROM site_type WHERE pkey = ?",
                    (site_type_pkey, ))
        site_type = cur.fetchone()[0]
        model.add_model_include(site_type, site_type)
    model.write_model()

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

    pb_type_xml = start_pb_type(
        pb_type,
        pin_assignments,
        ['{}_{}'.format(site, pin) for site, pin in all_pb_type_output_pins],
        ['{}_{}'.format(site, pin) for site, pin in all_pb_type_input_pins],
    )

    interconnect_xml = ET.Element('interconnect')

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

    site_prefixes = get_tile_prefixes(conn, tile_type_pkeys, site_type_pkeys,
                                      site_remaps)

    cell_names = {}
    site_type_ports = {}

    for site_type_pkey in site_type_pkeys:
        cur.execute("SELECT name FROM site_type WHERE pkey = ?",
                    (site_type_pkey, ))
        site_type = cur.fetchone()[0]
        site_prefix = site_prefixes[site_type_pkey]
        site_type_path = site_pbtype.format(site_type.lower(),
                                            site_type.lower())

        cell_pb_type = ET.ElementTree()
        root_element = cell_pb_type.parse(site_type_path)
        cell_names[site_type] = 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_type not in site_type_ports, (site_type,
                                                  site_type_ports.keys())
        site_type_ports[site_type] = 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 len(site_type_pkeys) > 1:
            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 site_type, site_pin_name in top_level_pin_external:
        port = find_port(site_pin_name, site_type_ports[site_type])
        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_name = cell_names[site_type]
        is_input = (site_type, site_pin_name) in all_pb_type_input_pins
        is_output = (site_type, site_pin_name) in all_pb_type_output_pins

        if not is_input and not is_output:
            continue

        if is_input:
            add_direct(
                interconnect_xml,
                input=object_ref(site_name, **port),
                output=object_ref(
                    add_vpr_tile_prefix(pb_type),
                    '{}_{}'.format(site_type, site_pin_name),
                ),
            )

    for site_type, site_pin_name in top_level_pin_external:
        port = find_port(site_pin_name, site_type_ports[site_type])
        if port is None:
            continue

        site_name = cell_names[site_type]
        is_input = (site_type, site_pin_name) in all_pb_type_input_pins
        is_output = (site_type, site_pin_name) in all_pb_type_output_pins

        if not is_input and not is_output:
            continue

        if is_output:
            add_direct(
                interconnect_xml,
                input=object_ref(add_vpr_tile_prefix(pb_type),
                                 '{}_{}'.format(site_type, site_pin_name)),
                output=object_ref(site_name, **port),
            )

    for (dest_site_type, dest_site_pin_name, _), (src_site_type, src_site_pin_name, _) in \
            sorted(internal_connections.items(), key=lambda x: (x[1], x[0])):
        src_port = find_port(src_site_pin_name, site_type_ports[src_site_type])
        src_site_name = cell_names[src_site_type]
        if src_port is None:
            print(
                "*** WARNING *** Didn't find port for name {} for site type {}"
                .format(src_site_pin_name, src_site_type),
                file=sys.stderr)
            continue

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

        add_direct(
            interconnect_xml,
            input=object_ref(src_site_name, **src_port),
            output=object_ref(dest_site_name, **dest_port),
        )

    pb_type_xml.append(interconnect_xml)

    write_xml(
        os.path.join(output_directory, pb_type.lower(),
                     '{}.pb_type.xml'.format(pb_type.lower())), pb_type_xml)

    top_level_connections = {}
    for wire in sorted(top_level_wire_external):
        site_type, site_pin_name, _ = wire_to_site_pin[wire]
        is_input = (site_type, site_pin_name) in all_pb_type_input_pins
        is_output = (site_type, site_pin_name) in all_pb_type_output_pins

        if not is_input and not is_output:
            continue

        top_level_connections[wire] = wire_to_site_pin[wire]

    return top_level_connections