Esempio n. 1
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))
Esempio n. 2
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)
Esempio n. 3
0
def handle_direction_connections(conn, direct_connections, edge_assignments):
    # Edges with mux should have one source tile and one destination_tile.
    # The pin from the source_tile should face the destination_tile.
    #
    # It is expected that all edges_with_mux will lies in a line (e.g. X only or
    # Y only).
    c = conn.cursor()
    for src_wire_pkey, dest_wire_pkey, pip_in_tile_pkey, switch_pkey in progressbar_utils.progressbar(
            c.execute("""
SELECT src_wire_pkey, dest_wire_pkey, pip_in_tile_pkey, switch_pkey FROM edge_with_mux;"""
                      )):

        c2 = conn.cursor()

        # Get the node that is attached to the source.
        c2.execute("""
SELECT node_pkey FROM wire WHERE pkey = ?""", (src_wire_pkey, ))
        (src_node_pkey, ) = c2.fetchone()

        # Find the wire connected to the source.
        src_wire = list(node_to_site_pins(conn, src_node_pkey))
        assert len(src_wire) == 1
        source_wire_pkey, src_tile_pkey, src_wire_in_tile_pkey = src_wire[0]

        c2.execute(
            """
SELECT tile_type_pkey, grid_x, grid_y FROM tile WHERE pkey = ?""",
            (src_tile_pkey, ))
        src_tile_type_pkey, source_loc_grid_x, source_loc_grid_y = c2.fetchone(
        )

        c2.execute("""
SELECT name FROM tile_type WHERE pkey = ?""", (src_tile_type_pkey, ))
        (source_tile_type, ) = c2.fetchone()

        source_wire = get_pin_name_of_wire(conn, source_wire_pkey)

        # Get the node that is attached to the sink.
        c2.execute("""
SELECT node_pkey FROM wire WHERE pkey = ?""", (dest_wire_pkey, ))
        (dest_node_pkey, ) = c2.fetchone()

        # Find the wire connected to the sink.
        dest_wire = list(node_to_site_pins(conn, dest_node_pkey))
        assert len(dest_wire) == 1
        destination_wire_pkey, dest_tile_pkey, dest_wire_in_tile_pkey = dest_wire[
            0]

        c2.execute(
            """
SELECT tile_type_pkey, grid_x, grid_y FROM tile WHERE pkey = ?;""",
            (dest_tile_pkey, ))
        dest_tile_type_pkey, destination_loc_grid_x, destination_loc_grid_y = c2.fetchone(
        )

        c2.execute("""
SELECT name FROM tile_type WHERE pkey = ?""", (dest_tile_type_pkey, ))
        (destination_tile_type, ) = c2.fetchone()

        destination_wire = get_pin_name_of_wire(conn, destination_wire_pkey)

        c2.execute("SELECT name FROM switch WHERE pkey = ?"
                   "", (switch_pkey, ))
        switch_name = c2.fetchone()[0]

        direct_connections.add(
            DirectConnection(
                from_pin='{}.{}'.format(source_tile_type, source_wire),
                to_pin='{}.{}'.format(destination_tile_type, destination_wire),
                switch_name=switch_name,
                x_offset=destination_loc_grid_x - source_loc_grid_x,
                y_offset=destination_loc_grid_y - source_loc_grid_y,
            ))

        if destination_loc_grid_x == source_loc_grid_x:
            if destination_loc_grid_y > source_loc_grid_y:
                source_dir = tracks.Direction.TOP
                destination_dir = tracks.Direction.BOTTOM
            else:
                source_dir = tracks.Direction.BOTTOM
                destination_dir = tracks.Direction.TOP
        else:
            if destination_loc_grid_x > source_loc_grid_x:
                source_dir = tracks.Direction.RIGHT
                destination_dir = tracks.Direction.LEFT
            else:
                source_dir = tracks.Direction.LEFT
                destination_dir = tracks.Direction.RIGHT

        edge_assignments[(source_tile_type, source_wire)].append(
            (source_dir, ))
        edge_assignments[(destination_tile_type, destination_wire)].append(
            (destination_dir, ))
def import_tracks(conn, alive_tracks, node_mapping, graph, default_segment_id):
    cur = conn.cursor()
    cur2 = conn.cursor()
    for (graph_node_pkey, track_pkey, graph_node_type, x_low, x_high, y_low,
         y_high, ptc, capacitance,
         resistance) in progressbar_utils.progressbar(
             cur.execute("""
SELECT
    pkey,
    track_pkey,
    graph_node_type,
    x_low,
    x_high,
    y_low,
    y_high,
    ptc,
    capacitance,
    resistance
FROM
    graph_node WHERE track_pkey IS NOT NULL;""")):
        if track_pkey not in alive_tracks:
            continue

        cur2.execute(
            """
SELECT name FROM segment WHERE pkey = (
    SELECT segment_pkey FROM track WHERE pkey = ?
)""", (track_pkey, ))
        result = cur2.fetchone()
        if result is not None:
            segment_name = result[0]
            segment_id = graph.get_segment_id_from_name(segment_name)
        else:
            segment_id = default_segment_id

        node_type = graph2.NodeType(graph_node_type)

        if node_type == graph2.NodeType.CHANX:
            direction = 'X'
            x_low = max(x_low, 1)
        elif node_type == graph2.NodeType.CHANY:
            direction = 'Y'
            y_low = max(y_low, 1)
        else:
            assert False, node_type

        canonical_loc = None
        cur2.execute(
            """
SELECT grid_x, grid_y FROM phy_tile WHERE pkey = (
    SELECT canon_phy_tile_pkey FROM track WHERE pkey = ?
    )""", (track_pkey, ))
        result = cur2.fetchone()
        if result:
            canonical_loc = graph2.CanonicalLoc(x=result[0], y=result[1])

        track = tracks.Track(
            direction=direction,
            x_low=x_low,
            x_high=x_high,
            y_low=y_low,
            y_high=y_high,
        )
        assert graph_node_pkey not in node_mapping
        node_mapping[graph_node_pkey] = graph.add_track(
            track=track,
            segment_id=segment_id,
            ptc=ptc,
            timing=graph2.NodeTiming(
                r=resistance,
                c=capacitance,
            ),
            canonical_loc=canonical_loc)
Esempio n. 5
0
    def create_channels(self, pad_segment, pool=None):
        """ Pack tracks into channels and return Channels definition for tracks."""
        assert len(self.tracks) > 0

        xs = []
        ys = []

        for track in self.tracks:
            track_node = self.nodes[track]

            xs.append(track_node.loc.x_low)
            xs.append(track_node.loc.x_high)
            ys.append(track_node.loc.y_low)
            ys.append(track_node.loc.y_high)

        x_tracks = {}
        y_tracks = {}

        for track in self.tracks:
            track_node = self.nodes[track]

            if track_node.type == NodeType.CHANX:
                assert track_node.loc.y_low == track_node.loc.y_high

                x1, x2 = sorted((track_node.loc.x_low, track_node.loc.x_high))

                if track_node.loc.y_low not in x_tracks:
                    x_tracks[track_node.loc.y_low] = []

                x_tracks[track_node.loc.y_low].append((x1, x2, track))
            elif track_node.type == NodeType.CHANY:
                assert track_node.loc.x_low == track_node.loc.x_high

                y1, y2 = sorted((track_node.loc.y_low, track_node.loc.y_high))

                if track_node.loc.x_low not in y_tracks:
                    y_tracks[track_node.loc.x_low] = []

                y_tracks[track_node.loc.x_low].append((y1, y2, track))
            else:
                assert False, track_node

        x_list = []
        y_list = []

        x_channel_models = {}
        y_channel_models = {}

        if pool is not None:
            for y in x_tracks:
                x_channel_models[y] = pool.apply_async(process_track,
                                                       (x_tracks[y], ))

            for x in y_tracks:
                y_channel_models[x] = pool.apply_async(process_track,
                                                       (y_tracks[x], ))

        for y in progressbar_utils.progressbar(range(max(x_tracks) + 1)):
            if y in x_tracks:
                if pool is None:
                    x_channel_models[y] = process_track(x_tracks[y])
                else:
                    x_channel_models[y] = x_channel_models[y].get()

                x_list.append(len(x_channel_models[y].trees))
                for idx, tree in enumerate(x_channel_models[y].trees):
                    for i in tree:
                        self.set_track_ptc(track=i[2], ptc=idx)
            else:
                x_list.append(0)

        for x in progressbar_utils.progressbar(range(max(y_tracks) + 1)):
            if x in y_tracks:
                if pool is None:
                    y_channel_models[x] = process_track(y_tracks[x])
                else:
                    y_channel_models[x] = y_channel_models[x].get()

                y_list.append(len(y_channel_models[x].trees))
                for idx, tree in enumerate(y_channel_models[x].trees):
                    for i in tree:
                        self.set_track_ptc(track=i[2], ptc=idx)
            else:
                y_list.append(0)

        x_min = min(xs)
        y_min = min(ys)
        x_max = max(xs)
        y_max = max(ys)

        num_padding = 0
        for chan, channel_model in x_channel_models.items():
            for ptc, start, end in channel_model.fill_empty(
                    max(x_min, 1), x_max):
                num_padding += 1
                self.add_track(track=Track(
                    direction='X',
                    x_low=start,
                    y_low=chan,
                    x_high=end,
                    y_high=chan,
                ),
                               segment_id=pad_segment,
                               capacity=0,
                               timing=None,
                               ptc=ptc)

        for chan, channel_model in y_channel_models.items():
            for ptc, start, end in channel_model.fill_empty(
                    max(y_min, 1), y_max):
                num_padding += 1
                self.add_track(track=Track(
                    direction='Y',
                    x_low=chan,
                    y_low=start,
                    x_high=chan,
                    y_high=end,
                ),
                               segment_id=pad_segment,
                               capacity=0,
                               timing=None,
                               ptc=ptc)

        print('Number padding nodes {}'.format(num_padding))

        return Channels(
            chan_width_max=max(max(x_list), max(y_list)),
            x_min=x_min,
            y_min=y_min,
            x_max=x_max,
            y_max=y_max,
            x_list=[ChannelList(idx, info) for idx, info in enumerate(x_list)],
            y_list=[ChannelList(idx, info) for idx, info in enumerate(y_list)],
        )
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--db_root',
                        required=True,
                        help='Project X-Ray Database')
    parser.add_argument('--connection_database',
                        help='Database of fabric connectivity',
                        required=True)
    parser.add_argument('--pin_assignments',
                        help='Pin assignments JSON',
                        required=True)
    parser.add_argument(
        '--synth_tiles',
        help=
        'If using an ROI, synthetic tile defintion from prjxray-arch-import')

    args = parser.parse_args()

    pool = multiprocessing.Pool(20)

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

    with DatabaseCache(args.connection_database) as conn:

        with open(args.pin_assignments) as f:
            pin_assignments = json.load(f)

        tile_wires = []
        for tile_type, wire_map in pin_assignments['pin_directions'].items():
            for wire in wire_map.keys():
                tile_wires.append((tile_type, wire))

        for tile_type, wire in progressbar_utils.progressbar(tile_wires):
            pins = [
                direction_to_enum(pin)
                for pin in pin_assignments['pin_directions'][tile_type][wire]
            ]
            add_graph_nodes_for_pins(conn, tile_type, wire, pins)

        if args.synth_tiles:
            use_roi = True
            with open(args.synth_tiles) as f:
                synth_tiles = json.load(f)

            roi = Roi(
                db=db,
                x1=synth_tiles['info']['GRID_X_MIN'],
                y1=synth_tiles['info']['GRID_Y_MIN'],
                x2=synth_tiles['info']['GRID_X_MAX'],
                y2=synth_tiles['info']['GRID_Y_MAX'],
            )

            print('{} generating routing graph for ROI.'.format(now()))
        else:
            use_roi = False

        output_only_nodes = set()
        input_only_nodes = set()

        find_pip = create_find_pip(conn)
        find_wire = create_find_wire(conn)
        find_connector = create_find_connector(conn)

        const_connectors = create_const_connectors(conn)

        print('{} Finding nodes belonging to ROI'.format(now()))
        if use_roi:
            for loc in progressbar_utils.progressbar(grid.tile_locations()):
                gridinfo = grid.gridinfo_at_loc(loc)
                tile_name = grid.tilename_at_loc(loc)

                if tile_name in synth_tiles['tiles']:
                    assert len(synth_tiles['tiles'][tile_name]['pins']) == 1
                    for pin in synth_tiles['tiles'][tile_name]['pins']:
                        if pin['port_type'] not in ['input', 'output']:
                            continue

                        _, _, _, node_pkey = find_wire(tile_name,
                                                       gridinfo.tile_type,
                                                       pin['wire'])

                        if pin['port_type'] == 'input':
                            # This track can output be used as a sink.
                            input_only_nodes |= set((node_pkey, ))
                        elif pin['port_type'] == 'output':
                            # This track can output be used as a src.
                            output_only_nodes |= set((node_pkey, ))
                        else:
                            assert False, pin

        write_cur = conn.cursor()
        write_cur.execute('SELECT pkey FROM switch WHERE name = ?;',
                          ('__vpr_delayless_switch__', ))
        delayless_switch_pkey = write_cur.fetchone()[0]

        edges = []

        edge_set = set()

        for loc in progressbar_utils.progressbar(grid.tile_locations()):
            gridinfo = grid.gridinfo_at_loc(loc)
            tile_name = grid.tilename_at_loc(loc)

            # Not a synth node, check if in ROI.
            if use_roi and not roi.tile_in_roi(loc):
                continue

            tile_type = db.get_tile_type(gridinfo.tile_type)

            for pip in tile_type.get_pips():
                if pip.is_pseudo:
                    continue

                connections = make_connection(
                    conn=conn,
                    input_only_nodes=input_only_nodes,
                    output_only_nodes=output_only_nodes,
                    find_pip=find_pip,
                    find_wire=find_wire,
                    find_connector=find_connector,
                    tile_name=tile_name,
                    tile_type=gridinfo.tile_type,
                    pip=pip,
                    delayless_switch_pkey=delayless_switch_pkey,
                    const_connectors=const_connectors)

                if connections:
                    for connection in connections:
                        key = tuple(connection[0:3])
                        if key in edge_set:
                            continue

                        edge_set.add(key)

                        edges.append(connection)

        print('{} Created {} edges, inserting'.format(now(), len(edges)))

        write_cur.execute("""BEGIN EXCLUSIVE TRANSACTION;""")
        for edge in progressbar_utils.progressbar(edges):
            write_cur.execute(
                """
                INSERT INTO graph_edge(
                    src_graph_node_pkey, dest_graph_node_pkey, switch_pkey,
                    phy_tile_pkey, pip_in_tile_pkey, backward) VALUES (?, ?, ?, ?, ?, ?)""",
                edge)

        write_cur.execute("""COMMIT TRANSACTION;""")

        print('{} Inserted edges'.format(now()))

        write_cur.execute(
            """CREATE INDEX src_node_index ON graph_edge(src_graph_node_pkey);"""
        )
        write_cur.execute(
            """CREATE INDEX dest_node_index ON graph_edge(dest_graph_node_pkey);"""
        )
        write_cur.connection.commit()

        print('{} Indices created, marking track liveness'.format(now()))

        alive_tracks = set()
        mark_track_liveness(conn, pool, input_only_nodes, output_only_nodes,
                            alive_tracks)

        print('{} Flushing database back to file "{}"'.format(
            now(), args.connection_database))

    with DatabaseCache(args.connection_database, read_only=True) as conn:
        verify_channels(conn, alive_tracks)
        print("{}: Channels verified".format(datetime.datetime.now()))
def build_channels(conn, pool, active_tracks):
    write_cur = conn.cursor()

    xs = []
    ys = []

    x_tracks = {}
    y_tracks = {}
    for pkey, track_pkey, graph_node_type, x_low, x_high, y_low, y_high in write_cur.execute(
            """
SELECT
  pkey,
  track_pkey,
  graph_node_type,
  x_low,
  x_high,
  y_low,
  y_high
FROM
  graph_node
WHERE
  track_pkey IS NOT NULL;"""):
        if track_pkey not in active_tracks:
            continue

        xs.append(x_low)
        xs.append(x_high)
        ys.append(y_low)
        ys.append(y_high)

        node_type = graph2.NodeType(graph_node_type)
        if node_type == graph2.NodeType.CHANX:
            assert y_low == y_high, (pkey, track_pkey)

            if y_low not in x_tracks:
                x_tracks[y_low] = []

            x_tracks[y_low].append((x_low, x_high, pkey))
        elif node_type == graph2.NodeType.CHANY:
            assert x_low == x_high, (pkey, track_pkey)

            if x_low not in y_tracks:
                y_tracks[x_low] = []

            y_tracks[x_low].append((y_low, y_high, pkey))
        else:
            assert False, node_type

    x_list = []
    y_list = []

    x_channel_models = {}
    y_channel_models = {}

    for y in x_tracks:
        x_channel_models[y] = pool.apply_async(graph2.process_track,
                                               (x_tracks[y], ))

    for x in y_tracks:
        y_channel_models[x] = pool.apply_async(graph2.process_track,
                                               (y_tracks[x], ))

    write_cur.execute("""BEGIN EXCLUSIVE TRANSACTION;""")

    for y in progressbar_utils.progressbar(range(max(x_tracks) + 1)):
        if y in x_tracks:
            x_channel_models[y] = x_channel_models[y].get()

            x_list.append(len(x_channel_models[y].trees))

            for idx, tree in enumerate(x_channel_models[y].trees):
                for i in tree:
                    write_cur.execute(
                        'UPDATE graph_node SET ptc = ? WHERE pkey = ?;',
                        (idx, i[2]))
        else:
            x_list.append(0)

    for x in progressbar_utils.progressbar(range(max(y_tracks) + 1)):
        if x in y_tracks:
            y_channel_models[x] = y_channel_models[x].get()

            y_list.append(len(y_channel_models[x].trees))

            for idx, tree in enumerate(y_channel_models[x].trees):
                for i in tree:
                    write_cur.execute(
                        'UPDATE graph_node SET ptc = ? WHERE pkey = ?;',
                        (idx, i[2]))
        else:
            y_list.append(0)

    x_min = min(xs)
    y_min = min(ys)
    x_max = max(xs)
    y_max = max(ys)

    write_cur.execute(
        """
    INSERT INTO channel(chan_width_max, x_min, x_max, y_min, y_max) VALUES
        (?, ?, ?, ?, ?);""",
        (max(max(x_list), max(y_list)), x_min, x_max, y_min, y_max))

    for idx, info in enumerate(x_list):
        write_cur.execute(
            """
        INSERT INTO x_list(idx, info) VALUES (?, ?);""", (idx, info))

    for idx, info in enumerate(y_list):
        write_cur.execute(
            """
        INSERT INTO y_list(idx, info) VALUES (?, ?);""", (idx, info))

    write_cur.execute("""COMMIT TRANSACTION;""")
Esempio n. 8
0
def main():

    # Parse arguments
    parser = argparse.ArgumentParser(
        description=__doc__,
        formatter_class=argparse.RawDescriptionHelpFormatter)

    parser.add_argument("--vpr-db",
                        type=str,
                        required=True,
                        help="VPR database file")
    parser.add_argument("--rr-graph-in",
                        type=str,
                        required=True,
                        help="Input RR graph XML file")
    parser.add_argument("--rr-graph-out",
                        type=str,
                        default="rr_graph.xml",
                        help="Output RR graph XML file (def. rr_graph.xml)")

    args = parser.parse_args()

    # Load data from the database
    print("Loading database...")
    with open(args.vpr_db, "rb") as fp:
        db = pickle.load(fp)

        vpr_quadrants = db["vpr_quadrants"]
        vpr_clock_cells = db["vpr_clock_cells"]
        loc_map = db["loc_map"]
        vpr_tile_types = db["vpr_tile_types"]
        vpr_tile_grid = db["vpr_tile_grid"]
        vpr_switchbox_types = db["vpr_switchbox_types"]
        vpr_switchbox_grid = db["vpr_switchbox_grid"]
        connections = db["connections"]
        switches = db["switches"]

    # Load the routing graph, build SOURCE -> OPIN and IPIN -> SINK edges.
    print("Loading rr graph...")
    xml_graph = rr_xml.Graph(input_file_name=args.rr_graph_in,
                             output_file_name=args.rr_graph_out,
                             progressbar=progressbar_utils.progressbar)

    # Add back the switches that were unused in the arch.xml and got pruned
    # byt VPR.
    for switch in switches:
        try:
            xml_graph.graph.get_switch_id(switch.name)
            continue
        except KeyError:
            xml_graph.add_switch(
                rr.Switch(
                    id=None,
                    name=switch.name,
                    type=rr.SwitchType[switch.type.upper()],
                    timing=rr.SwitchTiming(
                        r=switch.r,
                        c_in=switch.c_in,
                        c_out=switch.c_out,
                        c_internal=switch.c_int,
                        t_del=switch.t_del,
                    ),
                    sizing=rr.SwitchSizing(
                        mux_trans_size=0,
                        buf_size=0,
                    ),
                ))

    print("Building maps...")

    # Add a switch map to the graph
    switch_map = {}
    for switch in xml_graph.graph.switches:
        assert switch.id not in switch_map, switch
        switch_map[switch.id] = switch

    xml_graph.graph.switch_map = switch_map

    # Build node id to node map
    nodes_by_id = {node.id: node for node in xml_graph.graph.nodes}

    # Build tile pin names to rr node ids map
    tile_pin_to_node = build_tile_pin_to_node_map(xml_graph.graph, nodes_by_id,
                                                  vpr_tile_types,
                                                  vpr_tile_grid)

    # Add const network
    const_node_map = {}
    for const in ["VCC", "GND"]:
        m = add_tracks_for_const_network(xml_graph.graph, const, vpr_tile_grid)
        const_node_map[const] = m

    # Connection loc (endpoint) to node map. Map ConnectionLoc objects to VPR
    # rr graph node ids.
    connection_loc_to_node = {}

    # Build a map of connections to/from tiles and rr nodes. The map points
    # to an IPIN/OPIN node for a connection loc that mentions it.
    node_map = build_tile_connection_map(xml_graph.graph, nodes_by_id,
                                         vpr_tile_grid, connections)
    connection_loc_to_node.update(node_map)

    # Build the global clock network
    print("Building the global clock network...")

    # GMUX to QMUX and QMUX to CAND tracks
    node_map = create_quadrant_clock_tracks(xml_graph.graph, connections,
                                            connection_loc_to_node)
    connection_loc_to_node.update(node_map)

    # Clock column tracks
    cand_node_map = create_column_clock_tracks(xml_graph.graph,
                                               vpr_clock_cells, vpr_quadrants)

    # Add switchbox models.
    print("Building switchbox models...")
    switchbox_models = {}

    # Gather QMUX cells
    qmux_cells = {}
    for cell in vpr_clock_cells.values():
        if cell.type == "QMUX":
            loc = cell.loc

            if loc not in qmux_cells:
                qmux_cells[loc] = {}

            qmux_cells[loc][cell.name] = cell

    # Create the models
    for loc, type in vpr_switchbox_grid.items():
        phy_loc = loc_map.bwd[loc]

        # QMUX switchbox model
        if loc in qmux_cells:
            switchbox_models[loc] = QmuxSwitchboxModel(
                graph=xml_graph.graph,
                loc=loc,
                phy_loc=phy_loc,
                switchbox=vpr_switchbox_types[type],
                qmux_cells=qmux_cells[loc],
                connections=[c for c in connections if is_clock(c)])

        # Regular switchbox model
        else:
            switchbox_models[loc] = SwitchboxModel(
                graph=xml_graph.graph,
                loc=loc,
                phy_loc=phy_loc,
                switchbox=vpr_switchbox_types[type],
            )

    # Build switchbox models
    for switchbox_model in progressbar_utils.progressbar(
            switchbox_models.values()):
        switchbox_model.build()

    # Build the global clock network cell models
    print("Building QMUX and CAND models...")

    # Add QMUX and CAND models
    for cell in progressbar_utils.progressbar(vpr_clock_cells.values()):
        phy_loc = loc_map.bwd[cell.loc]

        if cell.type == "QMUX":
            QmuxModel(graph=xml_graph.graph,
                      cell=cell,
                      phy_loc=phy_loc,
                      switchbox_model=switchbox_models[cell.loc],
                      connections=connections,
                      node_map=connection_loc_to_node)

        if cell.type == "CAND":
            CandModel(graph=xml_graph.graph,
                      cell=cell,
                      phy_loc=phy_loc,
                      connections=connections,
                      node_map=connection_loc_to_node,
                      cand_node_map=cand_node_map)

    # Populate connections to the switchbox models
    print("Populating connections...")
    populate_hop_connections(xml_graph.graph, switchbox_models, connections)
    populate_tile_connections(xml_graph.graph, switchbox_models, connections,
                              connection_loc_to_node)
    populate_direct_connections(xml_graph.graph, connections,
                                connection_loc_to_node)
    populate_cand_connections(xml_graph.graph, switchbox_models, cand_node_map)
    populate_const_connections(xml_graph.graph, switchbox_models,
                               vpr_tile_types, vpr_tile_grid, tile_pin_to_node,
                               const_node_map)

    # Create channels from tracks
    pad_segment_id = xml_graph.graph.get_segment_id_from_name("pad")
    channels_obj = xml_graph.graph.create_channels(pad_segment=pad_segment_id)

    # Remove padding channels
    print("Removing padding nodes...")
    xml_graph.graph.nodes = [
        n for n in xml_graph.graph.nodes if n.capacity > 0
    ]

    # Build node id to node map again since there have been new nodes added.
    nodes_by_id = {node.id: node for node in xml_graph.graph.nodes}

    # Sanity check edges
    print("Sanity checking edges...")
    node_ids = set([n.id for n in xml_graph.graph.nodes])
    for edge in xml_graph.graph.edges:
        assert edge.src_node in node_ids, edge
        assert edge.sink_node in node_ids, edge
        assert edge.src_node != edge.sink_node, edge

    # Sanity check IPIN/OPIN connections. There must be no tile completely
    # disconnected from the routing network
    print("Sanity checking tile connections...")

    connected_locs = set()
    for edge in xml_graph.graph.edges:
        src = nodes_by_id[edge.src_node]
        dst = nodes_by_id[edge.sink_node]

        if src.type == rr.NodeType.OPIN:
            loc = (src.loc.x_low, src.loc.y_low)
            connected_locs.add(loc)

        if dst.type == rr.NodeType.IPIN:
            loc = (src.loc.x_low, src.loc.y_low)
            connected_locs.add(loc)

    non_empty_locs = set((loc.x, loc.y) for loc in xml_graph.graph.grid
                         if loc.block_type_id > 0)

    unconnected_locs = non_empty_locs - connected_locs
    for loc in unconnected_locs:
        block_type = xml_graph.graph.block_type_at_loc(loc)
        print(" ERROR: Tile '{}' at ({}, {}) is not connected!".format(
            block_type, loc[0], loc[1]))

    # Write the routing graph
    nodes_obj = xml_graph.graph.nodes
    edges_obj = xml_graph.graph.edges

    print("Serializing the rr graph...")
    xml_graph.serialize_to_xml(
        channels_obj=channels_obj,
        nodes_obj=nodes_obj,
        edges_obj=yield_edges(edges_obj),
        node_remap=lambda x: x,
    )
Esempio n. 9
0
def insert_tracks(conn, tracks_to_insert):
    write_cur = conn.cursor()
    write_cur.execute('SELECT pkey FROM switch WHERE name = "short";')
    short_pkey = write_cur.fetchone()[0]

    track_graph_nodes = {}
    track_pkeys = []
    for node, tracks_list, track_connections, tracks_model in progressbar_utils.progressbar(
            tracks_to_insert):
        write_cur.execute("""INSERT INTO track DEFAULT VALUES""")
        track_pkey = write_cur.lastrowid
        track_pkeys.append(track_pkey)

        write_cur.execute("""UPDATE node SET track_pkey = ? WHERE pkey = ?""",
                          (track_pkey, node))

        track_graph_node_pkey = []
        for idx, track in enumerate(tracks_list):
            if track.direction == 'X':
                node_type = graph2.NodeType.CHANX
            elif track.direction == 'Y':
                node_type = graph2.NodeType.CHANY
            else:
                assert False, track.direction

            if idx == 0:
                capacitance, resistance = get_node_rc(conn, node)
            else:
                capacitance = 0
                resistance = 0

            write_cur.execute(
                """
INSERT INTO graph_node(
  graph_node_type, track_pkey, node_pkey,
  x_low, x_high, y_low, y_high, capacity, capacitance, resistance
)
VALUES
  (?, ?, ?, ?, ?, ?, ?, 1, ?, ?)""",
                (node_type.value, track_pkey, node, track.x_low, track.x_high,
                 track.y_low, track.y_high, capacitance, resistance))
            track_graph_node_pkey.append(write_cur.lastrowid)

        track_graph_nodes[node] = track_graph_node_pkey

        for connection in track_connections:
            write_cur.execute(
                """
INSERT INTO graph_edge(
  src_graph_node_pkey, dest_graph_node_pkey,
  switch_pkey, track_pkey
)
VALUES
  (?, ?, ?, ?),
  (?, ?, ?, ?)""", (
                    track_graph_node_pkey[connection[0]],
                    track_graph_node_pkey[connection[1]],
                    short_pkey,
                    track_pkey,
                    track_graph_node_pkey[connection[1]],
                    track_graph_node_pkey[connection[0]],
                    short_pkey,
                    track_pkey,
                ))

    conn.commit()

    wire_to_graph = {}
    for node, tracks_list, track_connections, tracks_model in progressbar_utils.progressbar(
            tracks_to_insert):
        track_graph_node_pkey = track_graph_nodes[node]

        write_cur.execute(
            """
WITH wires_from_node(wire_pkey, tile_pkey) AS (
  SELECT
    pkey,
    tile_pkey
  FROM
    wire
  WHERE
    node_pkey = ?
)
SELECT
  wires_from_node.wire_pkey,
  tile.grid_x,
  tile.grid_y
FROM
  tile
  INNER JOIN wires_from_node ON tile.pkey = wires_from_node.tile_pkey;
  """, (node, ))

        wires = write_cur.fetchall()

        for wire_pkey, grid_x, grid_y in wires:
            connections = list(
                tracks_model.get_tracks_for_wire_at_coord((grid_x, grid_y)))
            assert len(connections) > 0, (wire_pkey, track_pkey, grid_x,
                                          grid_y)
            graph_node_pkey = track_graph_node_pkey[connections[0][0]]

            wire_to_graph[wire_pkey] = graph_node_pkey

    for wire_pkey, graph_node_pkey in progressbar_utils.progressbar(
            wire_to_graph.items()):
        write_cur.execute(
            """
        UPDATE wire SET graph_node_pkey = ?
            WHERE pkey = ?""", (graph_node_pkey, wire_pkey))

    conn.commit()

    write_cur.execute(
        """CREATE INDEX graph_node_nodes ON graph_node(node_pkey);""")
    write_cur.execute(
        """CREATE INDEX graph_node_tracks ON graph_node(track_pkey);""")
    write_cur.execute(
        """CREATE INDEX graph_edge_tracks ON graph_edge(track_pkey);""")

    conn.commit()
    return track_pkeys
Esempio n. 10
0
def classify_nodes(conn, get_switch_timing):
    write_cur = conn.cursor()

    # Nodes are NULL if they they only have either a site pin or 1 pip, but
    # nothing else.
    write_cur.execute(
        """
UPDATE node SET classification = ?
    WHERE (node.site_wire_pkey IS NULL AND node.number_pips <= 1) OR
          (node.site_wire_pkey IS NOT NULL AND node.number_pips == 0)
    ;""", (NodeClassification.NULL.value, ))
    write_cur.execute(
        """
UPDATE node SET classification = ?
    WHERE node.number_pips > 1 and node.site_wire_pkey IS NULL;""",
        (NodeClassification.CHANNEL.value, ))
    write_cur.execute(
        """
UPDATE node SET classification = ?
    WHERE node.number_pips > 1 and node.site_wire_pkey IS NOT NULL;""",
        (NodeClassification.EDGES_TO_CHANNEL.value, ))

    null_nodes = []
    edges_to_channel = []
    edge_with_mux = []

    cur = conn.cursor()
    cur.execute("""
SELECT
  count(pkey)
FROM
  node
WHERE
  number_pips == 1
  AND site_wire_pkey IS NOT NULL;""")
    num_nodes = cur.fetchone()[0]
    with progressbar_utils.ProgressBar(max_value=num_nodes) as bar:
        bar.update(0)
        for idx, (node, site_wire_pkey) in enumerate(
                cur.execute("""
SELECT
  pkey,
  site_wire_pkey
FROM
  node
WHERE
  number_pips == 1
  AND site_wire_pkey IS NOT NULL;""")):
            bar.update(idx)

            write_cur.execute(
                """
WITH wire_in_node(
  wire_pkey, phy_tile_pkey, wire_in_tile_pkey
) AS (
  SELECT
    wire.pkey,
    wire.phy_tile_pkey,
    wire.wire_in_tile_pkey
  FROM
    wire
  WHERE
    wire.node_pkey = ?
)
SELECT
  pip_in_tile.pkey,
  pip_in_tile.src_wire_in_tile_pkey,
  pip_in_tile.dest_wire_in_tile_pkey,
  wire_in_node.wire_pkey,
  wire_in_node.wire_in_tile_pkey,
  wire_in_node.phy_tile_pkey
FROM
  wire_in_node
  INNER JOIN pip_in_tile
WHERE
  pip_in_tile.is_pseudo = 0 AND (
  pip_in_tile.src_wire_in_tile_pkey = wire_in_node.wire_in_tile_pkey
  OR pip_in_tile.dest_wire_in_tile_pkey = wire_in_node.wire_in_tile_pkey)
LIMIT
  1;
""", (node, ))

            (pip_pkey, src_wire_in_tile_pkey, dest_wire_in_tile_pkey,
             wire_in_node_pkey, wire_in_tile_pkey,
             phy_tile_pkey) = write_cur.fetchone()
            assert write_cur.fetchone() is None, node

            assert (wire_in_tile_pkey == src_wire_in_tile_pkey
                    or wire_in_tile_pkey
                    == dest_wire_in_tile_pkey), (wire_in_tile_pkey, pip_pkey)

            if src_wire_in_tile_pkey == wire_in_tile_pkey:
                other_wire = dest_wire_in_tile_pkey
            else:
                other_wire = src_wire_in_tile_pkey

            write_cur.execute(
                """
            SELECT node_pkey FROM wire WHERE
                wire_in_tile_pkey = ? AND
                phy_tile_pkey = ?;
                """, (other_wire, phy_tile_pkey))

            (other_node_pkey, ) = write_cur.fetchone()
            assert write_cur.fetchone() is None
            assert other_node_pkey is not None, (other_wire, phy_tile_pkey)

            write_cur.execute(
                """
            SELECT site_wire_pkey, number_pips
                FROM node WHERE pkey = ?;
                """, (other_node_pkey, ))

            result = write_cur.fetchone()
            assert result is not None, other_node_pkey
            other_site_wire_pkey, other_number_pips = result
            assert write_cur.fetchone() is None

            if other_site_wire_pkey is not None and other_number_pips == 1:
                if src_wire_in_tile_pkey == wire_in_tile_pkey:
                    src_wire_pkey = site_wire_pkey
                    dest_wire_pkey = other_site_wire_pkey
                else:
                    src_wire_pkey = other_site_wire_pkey
                    dest_wire_pkey = site_wire_pkey

                edge_with_mux.append(((node, other_node_pkey), src_wire_pkey,
                                      dest_wire_pkey, pip_pkey))
            elif other_site_wire_pkey is None and other_number_pips == 1:
                null_nodes.append(node)
                null_nodes.append(other_node_pkey)
                pass
            else:
                edges_to_channel.append(node)

    for nodes, src_wire_pkey, dest_wire_pkey, pip_pkey in progressbar_utils.progressbar(
            edge_with_mux):
        assert len(nodes) == 2

        switch_pkey = check_edge_with_mux_timing(conn, get_switch_timing,
                                                 src_wire_pkey, dest_wire_pkey,
                                                 pip_pkey)
        write_cur.execute(
            """
        UPDATE node SET classification = ?
            WHERE pkey IN (?, ?);""",
            (NodeClassification.EDGE_WITH_MUX.value, nodes[0], nodes[1]))

        write_cur.execute(
            """
INSERT INTO edge_with_mux(src_wire_pkey, dest_wire_pkey, pip_in_tile_pkey, switch_pkey)
VALUES
  (?, ?, ?, ?);""", (src_wire_pkey, dest_wire_pkey, pip_pkey, switch_pkey))

    for node in progressbar_utils.progressbar(edges_to_channel):
        write_cur.execute(
            """
        UPDATE node SET classification = ?
            WHERE pkey = ?;""", (
                NodeClassification.EDGES_TO_CHANNEL.value,
                node,
            ))

    for null_node in progressbar_utils.progressbar(null_nodes):
        write_cur.execute(
            """
        UPDATE node SET classification = ?
            WHERE pkey = ?;""", (
                NodeClassification.NULL.value,
                null_node,
            ))

    write_cur.execute("CREATE INDEX node_type_index ON node(classification);")
    write_cur.connection.commit()
Esempio n. 11
0
def import_nodes(db, grid, conn):
    # Some nodes are just 1 wire, so start by enumerating all wires.

    cur = conn.cursor()
    write_cur = conn.cursor()
    write_cur.execute("""BEGIN EXCLUSIVE TRANSACTION;""")

    tile_wire_map = {}
    wires = {}
    for tile in progressbar_utils.progressbar(grid.tiles()):
        gridinfo = grid.gridinfo_at_tilename(tile)
        tile_type = db.get_tile_type(gridinfo.tile_type)

        cur.execute(
            """SELECT pkey, tile_type_pkey FROM phy_tile WHERE name = ?;""",
            (tile, ))
        phy_tile_pkey, tile_type_pkey = cur.fetchone()

        for wire in tile_type.get_wires():
            # pkey node_pkey tile_pkey wire_in_tile_pkey
            cur.execute(
                """
SELECT pkey FROM wire_in_tile WHERE name = ? and tile_type_pkey = ?;""",
                (wire, tile_type_pkey))
            (wire_in_tile_pkey, ) = cur.fetchone()

            write_cur.execute(
                """
INSERT INTO wire(phy_tile_pkey, wire_in_tile_pkey)
VALUES
  (?, ?);""", (phy_tile_pkey, wire_in_tile_pkey))

            assert (tile, wire) not in tile_wire_map
            wire_pkey = write_cur.lastrowid
            tile_wire_map[(tile, wire)] = wire_pkey
            wires[wire_pkey] = None

    write_cur.execute("""COMMIT TRANSACTION;""")

    connections = db.connections()

    for connection in progressbar_utils.progressbar(
            connections.get_connections()):
        a_pkey = tile_wire_map[(connection.wire_a.tile,
                                connection.wire_a.wire)]
        b_pkey = tile_wire_map[(connection.wire_b.tile,
                                connection.wire_b.wire)]

        a_node = wires[a_pkey]
        b_node = wires[b_pkey]

        if a_node is None:
            a_node = set((a_pkey, ))

        if b_node is None:
            b_node = set((b_pkey, ))

        if a_node is not b_node:
            a_node |= b_node

            for wire in a_node:
                wires[wire] = a_node

    nodes = {}
    for wire_pkey, node in wires.items():
        if node is None:
            node = set((wire_pkey, ))

        assert wire_pkey in node

        nodes[id(node)] = node

    wires_assigned = set()
    for node in progressbar_utils.progressbar(nodes.values()):
        write_cur.execute("""INSERT INTO node(number_pips) VALUES (0);""")
        node_pkey = write_cur.lastrowid

        for wire_pkey in node:
            wires_assigned.add(wire_pkey)
            write_cur.execute(
                """
            UPDATE wire
                SET node_pkey = ?
                WHERE pkey = ?
            ;""", (node_pkey, wire_pkey))

    assert len(set(wires.keys()) ^ wires_assigned) == 0

    del tile_wire_map
    del nodes
    del wires

    write_cur.execute(
        "CREATE INDEX wire_in_tile_index ON wire(wire_in_tile_pkey);")
    write_cur.execute(
        "CREATE INDEX wire_index ON wire(phy_tile_pkey, wire_in_tile_pkey);")
    write_cur.execute("CREATE INDEX wire_node_index ON wire(node_pkey);")

    write_cur.connection.commit()
Esempio n. 12
0
def create_vpr_grid(conn):
    """ Create VPR grid from prjxray grid. """
    cur = conn.cursor()
    cur2 = conn.cursor()

    write_cur = conn.cursor()
    write_cur.execute("""BEGIN EXCLUSIVE TRANSACTION;""")

    # Insert synthetic tile types for CLB sites.
    write_cur.execute('INSERT INTO tile_type(name) VALUES ("SLICEL");')
    slicel_tile_type_pkey = write_cur.lastrowid

    write_cur.execute('INSERT INTO tile_type(name) VALUES ("SLICEM");')
    slicem_tile_type_pkey = write_cur.lastrowid

    slice_types = {
        'SLICEL': slicel_tile_type_pkey,
        'SLICEM': slicem_tile_type_pkey,
    }

    tiles_to_split = {
        'CLBLL_L': tile_splitter.grid.WEST,
        'CLBLL_R': tile_splitter.grid.EAST,
        'CLBLM_L': tile_splitter.grid.WEST,
        'CLBLM_R': tile_splitter.grid.EAST,
    }

    # Create initial grid using sites and locations from phy_tile's
    # Also build up tile_to_tile_type_pkeys, which is a map from original
    # tile_type_pkey, to array of split tile type pkeys, (e.g. SLICEL/SLICEM).
    tile_to_tile_type_pkeys = {}
    grid_loc_map = {}
    for phy_tile_pkey, tile_type_pkey, grid_x, grid_y in progressbar_utils.progressbar(
            cur.execute("""
        SELECT pkey, tile_type_pkey, grid_x, grid_y FROM phy_tile;
        """)):

        cur2.execute("SELECT name FROM tile_type WHERE pkey = ?;",
                     (tile_type_pkey, ))
        tile_type_name = cur2.fetchone()[0]

        sites = []
        site_pkeys = set()
        for (site_pkey, ) in cur2.execute(
                """
            SELECT site_pkey FROM wire_in_tile WHERE tile_type_pkey = ? AND site_pkey IS NOT NULL;""",
            (tile_type_pkey, )):
            site_pkeys.add(site_pkey)

        for site_pkey in site_pkeys:
            cur2.execute(
                """
                SELECT x_coord, y_coord, site_type_pkey
                FROM site WHERE pkey = ?;""", (site_pkey, ))
            result = cur2.fetchone()
            assert result is not None, (tile_type_pkey, site_pkey)
            x, y, site_type_pkey = result

            cur2.execute("SELECT name FROM site_type WHERE pkey = ?;",
                         ((site_type_pkey, )))
            site_type_name = cur2.fetchone()[0]

            sites.append(
                tile_splitter.grid.Site(name=site_type_name,
                                        phy_tile_pkey=phy_tile_pkey,
                                        tile_type_pkey=tile_type_pkey,
                                        site_type_pkey=site_type_pkey,
                                        site_pkey=site_pkey,
                                        x=x,
                                        y=y))

        sites = sorted(sites, key=lambda s: (s.x, s.y))

        if tile_type_name in tiles_to_split:
            tile_type_pkeys = []
            for site in sites:
                tile_type_pkeys.append(slice_types[site.name])

            if tile_type_name in tile_to_tile_type_pkeys:
                assert tile_to_tile_type_pkeys[tile_type_name] == \
                        tile_type_pkeys, (tile_type_name,)
            else:
                tile_to_tile_type_pkeys[tile_type_name] = tile_type_pkeys

        grid_loc_map[(grid_x, grid_y)] = tile_splitter.grid.Tile(
            root_phy_tile_pkeys=[phy_tile_pkey],
            phy_tile_pkeys=[phy_tile_pkey],
            tile_type_pkey=tile_type_pkey,
            sites=sites)

    cur.execute('SELECT pkey FROM tile_type WHERE name = "NULL";')
    empty_tile_type_pkey = cur.fetchone()[0]

    tile_types = {}
    for tile_type, split_direction in tiles_to_split.items():
        cur.execute('SELECT pkey FROM tile_type WHERE name = ?;',
                    (tile_type, ))
        tile_type_pkey = cur.fetchone()[0]
        tile_types[tile_type] = tile_type_pkey

    vpr_grid = tile_splitter.grid.Grid(
        grid_loc_map=grid_loc_map, empty_tile_type_pkey=empty_tile_type_pkey)

    for tile_type, split_direction in tiles_to_split.items():
        vpr_grid.split_tile_type(
            tile_type_pkey=tile_types[tile_type],
            tile_type_pkeys=tile_to_tile_type_pkeys[tile_type],
            split_direction=split_direction)

    new_grid = vpr_grid.output_grid()
    # Create tile rows for each tile in the VPR grid.  As provide map entries
    # to physical grid and alias map from split tile type to original tile
    # type.
    for (grid_x, grid_y), tile in new_grid.items():
        # TODO: Merging of tiles isn't supported yet, so don't handle multiple
        # phy_tile_pkeys yet. The phy_tile_pkey to add to the new VPR tile
        # should be the tile to use on the FASM prefix.
        assert len(tile.phy_tile_pkeys) == 1
        assert len(tile.root_phy_tile_pkeys) in [0, 1], len(
            tile.root_phy_tile_pkeys)

        if tile.split_sites:
            assert len(tile.sites) == 1
            write_cur.execute(
                """
SELECT pkey, parent_tile_type_pkey FROM site_as_tile WHERE tile_type_pkey = ? AND site_pkey = ?""",
                (tile.sites[0].tile_type_pkey, tile.sites[0].site_pkey))
            result = write_cur.fetchone()

            if result is None:
                write_cur.execute(
                    """
INSERT INTO
    site_as_tile(parent_tile_type_pkey, tile_type_pkey, site_pkey)
VALUES
    (?, ?, ?);""", (tile.tile_type_pkey, tile.sites[0].tile_type_pkey,
                    tile.sites[0].site_pkey))
                site_as_tile_pkey = write_cur.lastrowid
            else:
                site_as_tile_pkey, parent_tile_type_pkey = result
                assert parent_tile_type_pkey == tile.tile_type_pkey

            # Mark that this tile is split by setting the site_as_tile_pkey.
            write_cur.execute(
                """
INSERT INTO tile(phy_tile_pkey, tile_type_pkey, site_as_tile_pkey, grid_x, grid_y) VALUES (
        ?, ?, ?, ?, ?)""", (tile.phy_tile_pkeys[0], tile.tile_type_pkey,
                            site_as_tile_pkey, grid_x, grid_y))
        else:
            write_cur.execute(
                """
INSERT INTO tile(phy_tile_pkey, tile_type_pkey, grid_x, grid_y) VALUES (
        ?, ?, ?, ?)""",
                (tile.phy_tile_pkeys[0], tile.tile_type_pkey, grid_x, grid_y))

        tile_pkey = write_cur.lastrowid

        # Build the phy_tile <-> tile map.
        for phy_tile_pkey in tile.phy_tile_pkeys:
            write_cur.execute(
                """
INSERT INTO tile_map(tile_pkey, phy_tile_pkey) VALUES (?, ?)
                """, (tile_pkey, phy_tile_pkey))

        # First assign all wires at the root_phy_tile_pkeys to this tile_pkey.
        # This ensures all wires, (including wires without sites) have a home.
        for root_phy_tile_pkey in tile.root_phy_tile_pkeys:
            write_cur.execute(
                """
UPDATE
    wire
SET
    tile_pkey = ?
WHERE
    phy_tile_pkey = ?
    ;""", (tile_pkey, root_phy_tile_pkey))

    write_cur.execute(
        "CREATE INDEX tile_location_index ON tile(grid_x, grid_y);")
    write_cur.execute("CREATE INDEX tile_to_phy_map ON tile_map(tile_pkey);")
    write_cur.execute(
        "CREATE INDEX phy_to_tile_map ON tile_map(phy_tile_pkey);")
    write_cur.execute("""COMMIT TRANSACTION;""")

    write_cur.execute("""BEGIN EXCLUSIVE TRANSACTION;""")

    # At this point all wires have a tile_pkey that corrisponds to the old root
    # tile.  Wires belonging to sites need to be reassigned to their respective
    # tiles.
    for (grid_x, grid_y), tile in new_grid.items():
        cur2.execute("SELECT pkey FROM tile WHERE grid_x = ? AND grid_y = ?;",
                     (grid_x, grid_y))
        tile_pkey = cur2.fetchone()[0]

        for site in tile.sites:
            cur2.execute("SELECT tile_type_pkey FROM phy_tile WHERE pkey = ?;",
                         (site.phy_tile_pkey, ))
            tile_type_pkey = cur2.fetchone()[0]

            # Find all wires that belong to the new tile location.
            for wire_pkey, wire_in_tile_pkey in cur2.execute(
                    """
WITH wires(wire_pkey, wire_in_tile_pkey) AS (
    SELECT
        pkey, wire_in_tile_pkey
    FROM
        wire
    WHERE
        phy_tile_pkey = ?
)
SELECT
    wires.wire_pkey, wires.wire_in_tile_pkey
FROM
    wires
INNER JOIN
    wire_in_tile
ON
    wire_in_tile.pkey = wires.wire_in_tile_pkey
WHERE
    wire_in_tile.site_pkey = ?
    ;""", (site.phy_tile_pkey, site.site_pkey)):
                # Move the wire to the new tile_pkey.
                write_cur.execute(
                    """
UPDATE
    wire
SET
    tile_pkey = ?
WHERE
    pkey = ?;""", (
                        tile_pkey,
                        wire_pkey,
                    ))

                # Wires connected to the site via a pip require traversing the
                # pip.
                other_wire_in_tile_pkey = traverse_pip(conn, wire_in_tile_pkey)
                if other_wire_in_tile_pkey is not None:
                    # A wire was found connected to the site via pip, reassign
                    # tile_pkey.
                    write_cur.execute(
                        """
UPDATE
    wire
SET
    tile_pkey = ?
WHERE
    phy_tile_pkey = ?
AND
    wire_in_tile_pkey = ?
    ;""", (tile_pkey, site.phy_tile_pkey, other_wire_in_tile_pkey))

    # Now that final wire <-> tile assignments are made, create the index.
    write_cur.execute(
        "CREATE INDEX tile_wire_index ON wire(wire_in_tile_pkey, tile_pkey);")
    write_cur.execute("""COMMIT TRANSACTION;""")