def create_tracks_from_points(name, graph, unique_pos, short, grid_width,
                              grid_height):
    xs, ys = points.decompose_points_into_tracks(
        unique_pos,
        grid_width,
        grid_height,
        right_only=True,
    )
    tracks_list, track_connections = tracks.make_tracks(
        xs, ys, unique_pos, grid_width, grid_height)
    tracks_model = tracks.Tracks(tracks_list, track_connections)
    nodes = []
    for idx, track in enumerate(tracks_list):
        nodes.append(
            graph.add_track(
                track=track,
                segment_id=graph.segments[0].id,
                capacity=1,
                name="{}{}".format(name, idx),
            ))

    for aidx, bidx in track_connections:
        graph.add_edge(
            src_node=nodes[aidx],
            sink_node=nodes[bidx],
            switch_id=short,
        )
        graph.add_edge(
            src_node=nodes[bidx],
            sink_node=nodes[aidx],
            switch_id=short,
        )

    return nodes, tracks_model
def form_tracks(conn):
    c = conn.cursor()

    c.execute('SELECT count(pkey) FROM node WHERE classification == ?;',
              (NodeClassification.CHANNEL.value, ))
    num_nodes = c.fetchone()[0]

    tracks_to_insert = []
    with progressbar.ProgressBar(max_value=num_nodes) as bar:
        bar.update(0)
        c2 = conn.cursor()
        for idx, (node, ) in enumerate(
                c.execute(
                    """
SELECT pkey FROM node WHERE classification == ?;
""", (NodeClassification.CHANNEL.value, ))):
            bar.update(idx)

            unique_pos = set()
            for wire_pkey, grid_x, grid_y in c2.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, )):
                unique_pos.add((grid_x, grid_y))

            xs, ys = points.decompose_points_into_tracks(unique_pos)
            tracks_list, track_connections = tracks.make_tracks(
                xs, ys, unique_pos)
            tracks_model = tracks.Tracks(tracks_list, track_connections)

            tracks_to_insert.append(
                [node, tracks_list, track_connections, tracks_model])

    insert_tracks(conn, tracks_to_insert)
def get_track_model(conn, track_pkey):
    assert track_pkey is not None

    track_list = []
    track_nodes = []
    c2 = conn.cursor()
    graph_node_pkey = {}
    for idx, (pkey, graph_node_type, x_low, x_high, y_low,
              y_high) in enumerate(
                  c2.execute(
                      """
    SELECT pkey, graph_node_type, x_low, x_high, y_low, y_high
        FROM graph_node WHERE track_pkey = ?""", (track_pkey, ))):
        node_type = graph2.NodeType(graph_node_type)
        if node_type == graph2.NodeType.CHANX:
            direction = 'X'
        elif node_type == graph2.NodeType.CHANY:
            direction = 'Y'

        graph_node_pkey[pkey] = idx
        track_nodes.append(pkey)
        track_list.append(
            tracks.Track(direction=direction,
                         x_low=x_low,
                         x_high=x_high,
                         y_low=y_low,
                         y_high=y_high))

    track_connections = set()
    for src_graph_node_pkey, dest_graph_node_pkey in c2.execute(
            """
    SELECT src_graph_node_pkey, dest_graph_node_pkey
        FROM graph_edge WHERE track_pkey = ?""", (track_pkey, )):

        src_idx = graph_node_pkey[src_graph_node_pkey]
        dest_idx = graph_node_pkey[dest_graph_node_pkey]

        track_connections.add(tuple(sorted((src_idx, dest_idx))))

    tracks_model = tracks.Tracks(track_list, list(track_connections))

    return tracks_model, track_nodes
Пример #4
0
    def form_tracks(self, grid):
        connected_tiles = set()
        for tile, wire in self.node:
            connected_tiles.add(grid.loc_of_tilename(tile))

        unique_pos = set()
        for tile, wire in self.node:
            loc = grid.loc_of_tilename(tile)
            unique_pos.add((loc.grid_x, loc.grid_y))

        xs, ys = points.decompose_points_into_tracks(unique_pos)

        self.tracks, self.track_connections = tracks.make_tracks(
            xs, ys, unique_pos)
        self.wire_connections = {}
        self.tracks_model = tracks.Tracks(self.tracks, self.track_connections)
        for tile, wire in self.node:
            loc = grid.loc_of_tilename(tile)
            connections = list(
                self.tracks_model.get_tracks_for_wire_at_coord(
                    (loc.grid_x, loc.grid_y)))
            assert len(connections) > 0
            self.wire_connections[(tile, wire)] = connections[0][0]
Пример #5
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument(
            '--db_root', required=True, help='Project X-Ray Database')
    parser.add_argument(
            '--read_rr_graph', required=True, help='Input rr_graph file')
    parser.add_argument(
            '--write_rr_graph', required=True, help='Output rr_graph file')
    parser.add_argument(
            '--channels', required=True, help='Channel definitions from prjxray_form_channels')
    parser.add_argument(
            '--synth_tiles', help='If using an ROI, synthetic tile defintion from prjxray-arch-import')

    args = parser.parse_args()

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

    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

    # Convert input rr graph into graph2.Graph object.
    input_rr_graph = read_xml_file(args.read_rr_graph)

    xml_graph = xml_graph2.Graph(
            input_rr_graph,
            progressbar=progressbar.progressbar)

    graph = xml_graph.graph

    tool_version = input_rr_graph.getroot().attrib['tool_version']
    tool_comment = input_rr_graph.getroot().attrib['tool_comment']

    delayless_switch = graph.get_delayless_switch_id()

    print('{} reading channels definitions.'.format(now()))
    with open(args.channels) as f:
        channels = json.load(f)

    segment_id = graph.get_segment_id_from_name('dummy')

    track_wire_map = {}

    print('{} add nodes for all channels.'.format(now()))
    used_channels = 0
    for idx, channel in progressbar.progressbar(enumerate(channels['channels'])):
        # Don't use dead channels if using an ROI.
        # Consider a channel alive if at least 1 wire in the node is part of a
        # live tile.
        if use_roi:
            alive = False
            for tile, wire in channel['wires']:
                loc = grid.loc_of_tilename(tile)
                if roi.tile_in_roi(loc) or tile in synth_tiles['tiles']:
                    alive = True
                    break

            if not alive:
                continue

        used_channels += 1
        nodes = []
        track_list = []
        for idx2, track_dict in enumerate(channel['tracks']):
            if track_dict['direction'] == 'X':
                track_dict['x_low'] = max(track_dict['x_low'], 1)
            elif track_dict['direction'] == 'Y':
                track_dict['y_low'] = max(track_dict['y_low'], 1)
            track = tracks.Track(**track_dict)
            track_list.append(track)

            nodes.append(graph.add_track(track=track, segment_id=segment_id, name='track_{}_{}'.format(idx, idx2)))

        for a_idx, b_idx in channel['track_connections']:
            graph.add_edge(nodes[a_idx], nodes[b_idx], delayless_switch, 'track_{}_to_{}'.format(a_idx, b_idx))
            graph.add_edge(nodes[b_idx], nodes[a_idx], delayless_switch, 'track_{}_to_{}'.format(b_idx, a_idx))

        tracks_model = tracks.Tracks(track_list, channel['track_connections'])

        for tile, wire in channel['wires']:
            track_wire_map[(tile, wire)] = (tracks_model, nodes)

    print('original {} final {}'.format(len(channels['channels']), used_channels))

    routing_switch = graph.get_switch_id('routing')

    pip_map = {}

    edges_with_mux = {}
    for idx, edge_with_mux in progressbar.progressbar(enumerate(channels['edges_with_mux'])):
        if edge_with_mux['pip'] not in edges_with_mux:
            edges_with_mux[edge_with_mux['pip']] = {}

        assert len(edge_with_mux['source_node']) == 1
        edges_with_mux[edge_with_mux['pip']][tuple(edge_with_mux['source_node'][0])] = edge_with_mux['destination_node']

    # Set of (src, sink, switch_id) tuples that pip edges have been sent to
    # VPR.  VPR cannot handle duplicate paths with the same switch id.
    pip_set = set()
    print('{} Adding edges'.format(now()))
    for loc in progressbar.progressbar(grid.tile_locations()):
        gridinfo = grid.gridinfo_at_loc(loc)
        tile_name = grid.tilename_at_loc(loc)

        if use_roi:
            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']:
                    tracks_model, track_nodes = track_wire_map[(tile_name, pin['wire'])]

                    option = list(tracks_model.get_tracks_for_wire_at_coord(loc))
                    assert len(option) > 0

                    if pin['port_type'] == 'input':
                        tile_type = 'BLK_SY-OUTPAD'
                        wire = 'outpad'
                    elif pin['port_type'] == 'output':
                        tile_type = 'BLK_SY-INPAD'
                        wire = 'inpad'
                    else:
                        assert False, pin

                    track_node = track_nodes[option[0][0]]
                    pin_name = graph.create_pin_name_from_tile_type_and_pin(
                            tile_type,
                            wire)

                    pin_node = graph.get_nodes_for_pin(loc, pin_name)

                    if pin['port_type'] == 'input':
                        graph.add_edge(
                                src_node=track_node,
                                sink_node=pin_node[0][0],
                                switch_id=routing_switch,
                                name='synth_{}_{}'.format(tile_name, pin['wire']),
                        )
                    elif pin['port_type'] == 'output':
                        graph.add_edge(
                                src_node=pin_node[0][0],
                                sink_node=track_node,
                                switch_id=routing_switch,
                                name='synth_{}_{}'.format(tile_name, pin['wire']),
                        )
                    else:
                        assert False, pin
            else:
                # Not a synth node, check if in ROI.
                if 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

            if not pip.is_directional:
                # TODO: Handle bidirectional pips?
                continue

            edge_node = make_connection(graph, track_wire_map, loc, tile_name, gridinfo.tile_type,
                            pip, routing_switch, edges_with_mux, grid, pip_set)

            if edge_node is not None:
                pip_map[(tile_name, pip.name)] = edge_node

    print('{} Writing node mapping.'.format(now()))
    node_mapping = {
            'pips': [],
            'tracks': []
        }

    for (tile, pip_name), edge in pip_map.items():
        node_mapping['pips'].append({
                'tile': tile,
                'pip': pip_name,
                'edge': edge
        })

    for (tile, wire), (_, nodes) in track_wire_map.items():
        node_mapping['tracks'].append({
                'tile': tile,
                'wire': wire,
                'nodes': nodes,
        })

    with open('node_mapping.pickle', 'wb') as f:
        pickle.dump(node_mapping, f)

    print('{} Create channels and serializing.'.format(now()))
    pool = multiprocessing.Pool(10)
    serialized_rr_graph = xml_graph.serialize_to_xml(
            tool_version=tool_version,
            tool_comment=tool_comment,
            pad_segment=segment_id,
            pool=pool,
    )

    print('{} Writing to disk.'.format(now()))
    with open(args.write_rr_graph, "wb") as f:
        f.write(serialized_rr_graph)
    print('{} Done.'.format(now()))
Пример #6
0
def create_track(node, unique_pos):
    xs, ys = points.decompose_points_into_tracks(unique_pos)
    tracks_list, track_connections = tracks.make_tracks(xs, ys, unique_pos)
    tracks_model = tracks.Tracks(tracks_list, track_connections)

    return [node, tracks_list, track_connections, tracks_model]
Пример #7
0
def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--db_root',
                        help='Project X-Ray Database',
                        required=True)
    parser.add_argument('--channels',
                        help='Input JSON defining channel assignments',
                        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)
    grid = db.grid()

    edge_assignments = {}

    wires_in_tile_types = set()

    for tile_type in db.get_tile_types():
        type_obj = db.get_tile_type(tile_type)

        for wire in type_obj.get_wires():
            wires_in_tile_types.add((tile_type, wire))

        for site in type_obj.get_sites():
            for site_pin in site.site_pins:
                if site_pin.wire is None:
                    continue

                key = (tile_type, site_pin.wire)
                assert key not in edge_assignments, key
                edge_assignments[key] = []

    print('{} Reading channel data'.format(datetime.datetime.now()))
    with open(args.channels) as f:
        channels = json.load(f)
    print('{} Done reading channel data'.format(datetime.datetime.now()))

    direct_connections = set()

    # 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).
    for edge_with_mux in progressbar.progressbar(channels['edges_with_mux']):
        source_tile = None
        source_tile_type = None
        source_wire = None
        destination_tile = None
        destination_tile_type = None
        destination_wire = None

        for tile, wire in edge_with_mux['source_node']:
            tileinfo = grid.gridinfo_at_tilename(tile)
            tile_type = db.get_tile_type(tileinfo.tile_type)
            wire_info = tile_type.get_wire_info(wire)

            if len(wire_info.sites) == 1:
                assert source_tile is None, (tile, wire, source_tile)
                source_tile = tile
                source_tile_type = tileinfo.tile_type
                source_wire = wire

        for tile, wire in edge_with_mux['destination_node']:
            tileinfo = grid.gridinfo_at_tilename(tile)
            tile_type = db.get_tile_type(tileinfo.tile_type)
            wire_info = tile_type.get_wire_info(wire)

            if len(wire_info.sites) == 1:
                assert destination_tile is None, (tile, wire, destination_tile,
                                                  wire_info)
                destination_tile = tile
                destination_tile_type = tileinfo.tile_type
                destination_wire = wire

        assert source_tile is not None
        assert destination_tile is not None

        source_loc = grid.loc_of_tilename(source_tile)
        destination_loc = grid.loc_of_tilename(destination_tile)

        assert source_loc.grid_x == destination_loc.grid_x or source_loc.grid_y == destination_loc.grid_y, (
            source_tile, destination_tile, edge_with_mux['pip'])

        direct_connections.add(
            DirectConnection(
                from_pin='{}.{}'.format(source_tile_type, source_wire),
                to_pin='{}.{}'.format(destination_tile_type, destination_wire),
                switch_name='routing',
                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, ))

    wires_not_in_channels = {}
    for node in progressbar.progressbar(channels['node_not_in_channels']):
        reason = node['classification']

        for tile, wire in node['wires']:
            tileinfo = grid.gridinfo_at_tilename(tile)
            key = (tileinfo.tile_type, wire)

            # Sometimes nodes in particular tile instances are disconnected,
            # disregard classification changes if this is the case.
            if reason != '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, 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.
    for channel in progressbar.progressbar(channels['channels']):
        track_list = []
        for track in channel['tracks']:
            track_list.append(tracks.Track(**track))

        tracks_model = tracks.Tracks(track_list, channel['track_connections'])
        channel_nodes.append(tracks_model)

        for tile, wire in channel['wires']:
            tileinfo = grid.gridinfo_at_tilename(tile)
            key = (tileinfo.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)

            channel_wires_to_tracks[(tile, wire)] = tracks_model

    # Make sure all wires appear to have been assigned.
    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.
    for node in progressbar.progressbar(channels['node_not_in_channels']):
        reason = node['classification']

        assert reason != 'EDGE_WITH_SHORT'

        if reason == 'NULL':
            for tile, wire in node['wires']:
                tileinfo = grid.gridinfo_at_tilename(tile)
                tile_type = db.get_tile_type(tileinfo.tile_type)
                null_tile_wires.add((tileinfo.tile_type, wire))

        if reason == 'EDGES_TO_CHANNEL':

            num_sites = 0

            for tile, wire in node['wires']:
                tileinfo = grid.gridinfo_at_tilename(tile)
                loc = grid.loc_of_tilename(tile)
                tile_type = db.get_tile_type(tileinfo.tile_type)

                wire_info = tile_type.get_wire_info(wire)
                num_sites += len(wire_info.sites)
                for pip in wire_info.pips:
                    other_wire = prjxray.tile.get_other_wire_from_pip(
                        tile_type.get_pip_by_name(pip), wire)

                    key = (tile, other_wire)
                    if key in channel_wires_to_tracks:
                        tracks_model = channel_wires_to_tracks[key]

                        if len(wire_info.sites) > 0:
                            available_pins = set(
                                pin_dir for _, pin_dir in tracks_model.
                                get_tracks_for_wire_at_coord((loc.grid_x,
                                                              loc.grid_y)))
                            edge_assignments[(tileinfo.tile_type,
                                              wire)].append(available_pins)

    final_edge_assignments = {}
    for (tile_type, wire), available_pins in progressbar.progressbar(
            edge_assignments.items()):
        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[(tile_type,
                                    wire)] = [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[(tile_type, wire)] = [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[(tile_type, wire)] = pins

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

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

    pin_directions = {}
    for (tile_type, wire), pins in final_edge_assignments.items():
        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)