Exemple #1
0
def handle_edges_to_channels(conn, null_tile_wires, edge_assignments,
                             channel_wires_to_tracks):
    c = conn.cursor()

    c.execute("""
SELECT vcc_track_pkey, gnd_track_pkey FROM constant_sources;
    """)
    vcc_track_pkey, gnd_track_pkey = c.fetchone()
    const_tracks = {
        0: gnd_track_pkey,
        1: vcc_track_pkey,
    }

    for node_pkey, classification in progressbar_utils.progressbar(
            c.execute(
                """
SELECT pkey, classification FROM node WHERE classification != ?;
""", (NodeClassification.CHANNEL.value, ))):
        reason = NodeClassification(classification)

        if reason == NodeClassification.NULL:
            for (tile_type,
                 wire) in yield_logical_wire_info_from_node(conn, node_pkey):
                null_tile_wires.add((tile_type, wire))

        if reason != NodeClassification.EDGES_TO_CHANNEL:
            continue

        c2 = conn.cursor()
        for wire_pkey, phy_tile_pkey, tile_pkey, wire_in_tile_pkey in c2.execute(
                """
SELECT
    pkey, phy_tile_pkey, tile_pkey, wire_in_tile_pkey
FROM
    wire
WHERE
    node_pkey = ?;
    """, (node_pkey, )):
            c3 = conn.cursor()
            c3.execute("""
SELECT grid_x, grid_y FROM tile WHERE pkey = ?;""", (tile_pkey, ))
            (grid_x, grid_y) = c3.fetchone()

            c3.execute(
                """
SELECT
  name
FROM
  tile_type
WHERE
  pkey = (
    SELECT
      tile_type_pkey
    FROM
      tile
    WHERE
      pkey = ?
  );
                """, (tile_pkey, ))
            (tile_type, ) = c3.fetchone()

            wire = get_pin_name_of_wire(conn, wire_pkey)
            if wire is None:
                # This node has no site pin, don't need to assign pin direction.
                continue

            for other_phy_tile_pkey, other_wire_in_tile_pkey, pip_pkey, pip in c3.execute(
                    """
WITH wires_from_node(wire_in_tile_pkey, phy_tile_pkey) AS (
  SELECT
    wire_in_tile_pkey,
    phy_tile_pkey
  FROM
    wire
  WHERE
    node_pkey = ? AND phy_tile_pkey IS NOT NULL
),
  other_wires(other_phy_tile_pkey, pip_pkey, other_wire_in_tile_pkey) AS (
    SELECT
        wires_from_node.phy_tile_pkey,
        undirected_pips.pip_in_tile_pkey,
        undirected_pips.other_wire_in_tile_pkey
    FROM undirected_pips
    INNER JOIN wires_from_node ON
        undirected_pips.wire_in_tile_pkey = wires_from_node.wire_in_tile_pkey)
SELECT
  other_wires.other_phy_tile_pkey,
  other_wires.other_wire_in_tile_pkey,
  pip_in_tile.pkey,
  pip_in_tile.name
FROM
  other_wires
INNER JOIN pip_in_tile
ON pip_in_tile.pkey == other_wires.pip_pkey
WHERE
  pip_in_tile.is_directional = 1 AND pip_in_tile.is_pseudo = 0;
  """, (node_pkey, )):
                # Need to walk from the wire_in_tile table, to the wire table,
                # to the node table and get track_pkey.
                # other_wire_in_tile_pkey -> wire pkey -> node_pkey -> track_pkey
                c4 = conn.cursor()
                c4.execute(
                    """
SELECT
  track_pkey,
  classification
FROM
  node
WHERE
  pkey = (
    SELECT
      node_pkey
    FROM
      wire
    WHERE
      phy_tile_pkey = ?
      AND wire_in_tile_pkey = ?
  );""", (other_phy_tile_pkey, other_wire_in_tile_pkey))
                result = c4.fetchone()
                assert result is not None, (wire_pkey, pip_pkey, tile_pkey,
                                            wire_in_tile_pkey,
                                            other_wire_in_tile_pkey)
                (track_pkey, classification) = result

                # Some pips do connect to a track at all, e.g. null node
                if track_pkey is None:
                    # TODO: Handle weird connections.
                    #other_node_class = NodeClassification(classification)
                    #assert other_node_class == NodeClassification.NULL, (
                    #        node_pkey, pip_pkey, pip, other_node_class)
                    continue

                tracks_model = channel_wires_to_tracks[track_pkey]
                available_pins = set(
                    tracks_model.get_tracks_for_wire_at_coord(
                        (grid_x, grid_y)).keys())

                edge_assignments[(tile_type, wire)].append(available_pins)

                for constant in yield_ties_to_wire(wire):
                    tracks_model = channel_wires_to_tracks[
                        const_tracks[constant]]
                    available_pins = set(
                        tracks_model.get_tracks_for_wire_at_coord(
                            (grid_x, grid_y)).keys())
                    edge_assignments[(tile_type, wire)].append(available_pins)
Exemple #2
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--db_root',
                        help='Project X-Ray Database',
                        required=True)
    parser.add_argument('--connection_database',
                        help='Database of fabric connectivity',
                        required=True)
    parser.add_argument(
        '--pin_assignments',
        help=
        'Output JSON assigning pins to tile types and direction connections',
        required=True)

    args = parser.parse_args()

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

    edge_assignments = {}

    with DatabaseCache(args.connection_database, read_only=True) as conn:
        c = conn.cursor()

        edge_assignments, wires_in_tile_types = initialize_edge_assignments(
            db, conn)

        direct_connections = set()
        print('{} Processing direct connections.'.format(now()))
        handle_direction_connections(conn, direct_connections,
                                     edge_assignments)

        wires_not_in_channels = {}
        c = conn.cursor()
        print('{} Processing non-channel nodes.'.format(now()))
        for node_pkey, classification in progressbar_utils.progressbar(
                c.execute(
                    """
    SELECT pkey, classification FROM node WHERE classification != ?;
    """, (NodeClassification.CHANNEL.value, ))):
            reason = NodeClassification(classification)

            for (tile_type,
                 wire) in yield_logical_wire_info_from_node(conn, node_pkey):
                key = (tile_type, wire)

                # Sometimes nodes in particular tile instances are disconnected,
                # disregard classification changes if this is the case.
                if reason != NodeClassification.NULL:
                    if key not in wires_not_in_channels:
                        wires_not_in_channels[key] = reason
                    else:
                        other_reason = wires_not_in_channels[key]
                        assert reason == other_reason, (tile_type, wire,
                                                        reason, other_reason)

                if key in wires_in_tile_types:
                    wires_in_tile_types.remove(key)

        # List of nodes that are channels.
        channel_nodes = []

        # Map of (tile, wire) to track.  This will be used to find channels for pips
        # that come from EDGES_TO_CHANNEL.
        channel_wires_to_tracks = {}

        # Generate track models and verify that wires are either in a channel
        # or not in a channel.
        print('{} Creating models from tracks.'.format(now()))
        for node_pkey, track_pkey in progressbar_utils.progressbar(
                c.execute(
                    """
    SELECT pkey, track_pkey FROM node WHERE classification = ?;
    """, (NodeClassification.CHANNEL.value, ))):
            assert track_pkey is not None

            tracks_model, _ = get_track_model(conn, track_pkey)
            channel_nodes.append(tracks_model)
            channel_wires_to_tracks[track_pkey] = tracks_model

            for (tile_type,
                 wire) in yield_logical_wire_info_from_node(conn, node_pkey):
                key = (tile_type, wire)
                # Make sure all wires in channels always are in channels
                assert key not in wires_not_in_channels

                if key in wires_in_tile_types:
                    wires_in_tile_types.remove(key)

        # Make sure all wires appear to have been assigned.
        if len(wires_in_tile_types) > 0:
            for tile_type, wire in sorted(wires_in_tile_types):
                print(tile_type, wire)

        assert len(wires_in_tile_types) == 0

        # Verify that all tracks are sane.
        for node in channel_nodes:
            node.verify_tracks()

        null_tile_wires = set()

        # Verify that all nodes that are classified as edges to channels have at
        # least one site, and at least one live connection to a channel.
        #
        # If no live connections from the node are present, this node should've
        # been marked as NULL during channel formation.
        print('{} Handling edges to channels.'.format(now()))
        handle_edges_to_channels(conn, null_tile_wires, edge_assignments,
                                 channel_wires_to_tracks)

        print('{} Processing edge assignments.'.format(now()))
        final_edge_assignments = {}
        for key, available_pins in progressbar_utils.progressbar(
                edge_assignments.items()):
            (tile_type, wire) = key

            available_pins = [pins for pins in available_pins if len(pins) > 0]
            if len(available_pins) == 0:
                if (tile_type, wire) not in null_tile_wires:
                    # TODO: Figure out what is going on with these wires.  Appear to
                    # tile internal connections sometimes?
                    print((tile_type, wire))

                final_edge_assignments[key] = [tracks.Direction.RIGHT]
                continue

            pins = set(available_pins[0])
            for p in available_pins[1:]:
                pins &= set(p)

            if len(pins) > 0:
                final_edge_assignments[key] = [list(pins)[0]]
            else:
                # More than 2 pins are required, final the minimal number of pins
                pins = set()
                for p in available_pins:
                    pins |= set(p)

                while len(pins) > 2:
                    pins = list(pins)

                    prev_len = len(pins)

                    for idx in range(len(pins)):
                        pins_subset = list(pins)
                        del pins_subset[idx]

                        pins_subset = set(pins_subset)

                        bad_subset = False
                        for p in available_pins:
                            if len(pins_subset & set(p)) == 0:
                                bad_subset = True
                                break

                        if not bad_subset:
                            pins = list(pins_subset)
                            break

                    # Failed to remove any pins, stop.
                    if len(pins) == prev_len:
                        break

                final_edge_assignments[key] = pins

        for key, available_pins in edge_assignments.items():
            (tile_type, wire) = key
            pins = set(final_edge_assignments[key])

            for required_pins in available_pins:
                if len(required_pins) == 0:
                    continue

                assert len(pins & set(required_pins)) > 0, (tile_type, wire,
                                                            pins,
                                                            required_pins,
                                                            available_pins)

        pin_directions = {}
        for key, pins in progressbar_utils.progressbar(
                final_edge_assignments.items()):
            (tile_type, wire) = key
            if tile_type not in pin_directions:
                pin_directions[tile_type] = {}

            pin_directions[tile_type][wire] = [pin._name_ for pin in pins]

        with open(args.pin_assignments, 'w') as f:
            json.dump(
                {
                    'pin_directions':
                    pin_directions,
                    'direct_connections':
                    [d._asdict() for d in direct_connections],
                },
                f,
                indent=2)

        print('{} Flushing database back to file "{}"'.format(
            now(), args.connection_database))
Exemple #3
0
def handle_edges_to_channels(conn, null_tile_wires, edge_assignments, channel_wires_to_tracks):
    c = conn.cursor()

    for node_pkey, classification in progressbar.progressbar(c.execute("""
SELECT pkey, classification FROM node WHERE classification != ?;
""", (NodeClassification.CHANNEL.value,))):
        reason = NodeClassification(classification)

        if reason == NodeClassification.NULL:
            for (_, tile_type, wire) in yield_wire_info_from_node(conn, node_pkey):
                null_tile_wires.add((tile_type, wire))

        if reason != NodeClassification.EDGES_TO_CHANNEL:
            continue

        c2 = conn.cursor()
        for tile_pkey, wire_in_tile_pkey in c2.execute("""
SELECT tile_pkey, wire_in_tile_pkey FROM wire WHERE node_pkey = ?;""",
        (node_pkey,)):
            c3 = conn.cursor()
            c3.execute("""
SELECT name, grid_x, grid_y FROM tile WHERE pkey = ?;""",
                (tile_pkey,))
            (tile, grid_x, grid_y) = c3.fetchone()

            c3.execute("""
SELECT
  name
FROM
  tile_type
WHERE
  pkey = (
    SELECT
      tile_type_pkey
    FROM
      tile
    WHERE
      pkey = ?
  );
                """, (tile_pkey,))
            (tile_type,) = c3.fetchone()

            c3.execute("""
SELECT pkey, name, site_pin_pkey FROM wire_in_tile WHERE pkey = ?;""",
                    (wire_in_tile_pkey,))
            (wire_in_tile_pkey, wire, site_pin_pkey) = c3.fetchone()

            # This node has no site pin, don't need to assign pin direction.
            if site_pin_pkey is None:
                continue

            for pip_pkey, pip, src_wire_in_tile_pkey, dest_wire_in_tile_pkey in c3.execute("""
SELECT
  pkey,
  name,
  src_wire_in_tile_pkey,
  dest_wire_in_tile_pkey
FROM
  pip_in_tile
WHERE
  src_wire_in_tile_pkey = ?
  OR dest_wire_in_tile_pkey = ?;""", (wire_in_tile_pkey, wire_in_tile_pkey)):
                assert (
                    src_wire_in_tile_pkey == wire_in_tile_pkey or
                    dest_wire_in_tile_pkey == wire_in_tile_pkey), pip

                if src_wire_in_tile_pkey == wire_in_tile_pkey:
                    other_wire_in_tile_pkey = dest_wire_in_tile_pkey
                else:
                    other_wire_in_tile_pkey = src_wire_in_tile_pkey

                # Need to walk from the wire_in_tile table, to the wire table,
                # to the node table and get track_pkey.
                # other_wire_in_tile_pkey -> wire pkey -> node_pkey -> track_pkey
                c4 = conn.cursor()
                c4.execute("""
SELECT
  track_pkey,
  classification
FROM
  node
WHERE
  pkey = (
    SELECT
      node_pkey
    FROM
      wire
    WHERE
      tile_pkey = ?
      AND wire_in_tile_pkey = ?
  );""", (tile_pkey, other_wire_in_tile_pkey))
                (track_pkey, classification) = c4.fetchone()


                # Some pips do connect to a track at all, e.g. null node
                if track_pkey is None:
                    # TODO: Handle weird connections.
                    #other_node_class = NodeClassification(classification)
                    #assert other_node_class == NodeClassification.NULL, (
                    #        node_pkey, pip_pkey, pip, other_node_class)
                    continue

                tracks_model = channel_wires_to_tracks[track_pkey]
                available_pins = set(pin_dir for _, pin_dir in tracks_model.get_tracks_for_wire_at_coord((grid_x, grid_y)))
                edge_assignments[(tile_type, wire)].append(available_pins)