def main():
    parser = argparse.ArgumentParser(description=__doc__)

    parser.add_argument(
        '--connection_db', required=True, help="xc7 connection database."
    )
    parser.add_argument(
        '--route_file', required=True, help="VPR route output file."
    )
    parser.add_argument(
        '--rr_graph', required=True, help="Real or virt xc7 graph"
    )

    args = parser.parse_args()

    xml_graph = xml_graph2.Graph(
        read_xml_file(args.rr_graph), need_edges=False
    )
    graph = xml_graph.graph

    conn = sqlite3.connect(args.connection_db)

    with open(args.route_file) as f:
        net_list = create_net_list(conn, graph, f)
        print(json.dumps([net._asdict() for net in net_list], indent=2))
def rebuild_graph(fn, fn_out, rcw=6, verbose=False):
    """
    Add rcw tracks spanning full channel to both X and Y channels
    Connect all of those to all the adjacent pins
    Fully connect tracks at intersections
    For intersections this means we actually have two edges per intersection
    since source and sink must be specified
    """

    print('Importing input g')
    xml_graph = xml_graph2.Graph(
        fn,
        output_file_name=fn_out,
    )

    graph = xml_graph.graph

    grid_width = max(p.x for p in graph.grid) + 1
    grid_height = max(p.y for p in graph.grid) + 1

    mux = graph.get_switch_id('mux')

    try:
        short = graph.get_switch_id('short')
    except KeyError:
        short = xml_graph.add_switch(
            graph2.Switch(
                id=None,
                name='short',
                type=graph2.SwitchType.SHORT,
                timing=None,
                sizing=graph2.SwitchSizing(
                    mux_trans_size=0,
                    buf_size=0,
                ),
            )
        )

    create_tracks(graph, grid_width, grid_height, rcw, verbose=verbose)
    create_global_constant_tracks(graph, mux, short, grid_width, grid_height)
    connect_blocks_to_tracks(graph, grid_width, grid_height, rcw, switch=mux)
    connect_tracks_to_tracks(graph, switch=mux, verbose=verbose)
    print("Completed rebuild")

    xml_graph.root_attrib["tool_version"] = "dev"
    xml_graph.root_attrib["tool_comment"] = "Generated from black magic"

    channels_obj = graph.create_channels(pad_segment=graph.segments[0].id)

    xml_graph.serialize_to_xml(
        channels_obj=channels_obj,
        connection_box_obj=None,
        nodes_obj=graph.nodes,
        edges_obj=graph.edges
    )
Exemplo n.º 3
0
def load_net_list(conn, rr_graph_file, route_file):
    xml_graph = xml_graph2.Graph(read_xml_file(rr_graph_file),
                                 build_pin_edges=False)
    graph = xml_graph.graph

    net_map = {}
    with open(route_file) as f:
        for net in create_net_list(conn, graph, f):
            net_map[net.wire_pkey] = net.name

    return net_map
Exemplo n.º 4
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('--write_rr_node_map',
                        required=True,
                        help='Output map of graph_node_pkey to rr inode file')
    parser.add_argument('--connection_database',
                        help='Database of fabric connectivity',
                        required=True)
    parser.add_argument(
        '--synth_tiles',
        help=
        'If using an ROI, synthetic tile defintion from prjxray-arch-import')
    parser.add_argument(
        '--graph_limit',
        help='Limit grid to specified dimensions in x_min,y_min,x_max,y_max',
    )

    args = parser.parse_args()

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

    synth_tiles = None
    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()))
    elif args.graph_limit:
        use_roi = True
        x_min, y_min, x_max, y_max = map(int, args.graph_limit.split(','))
        roi = Roi(
            db=db,
            x1=x_min,
            y1=y_min,
            x2=x_max,
            y2=y_max,
        )
    else:
        use_roi = False
        roi = None
        synth_tiles = None

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

    if synth_tiles is None:
        synth_tiles = find_constant_network(input_rr_graph)

    xml_graph = xml_graph2.Graph(
        input_rr_graph,
        progressbar=progressbar_utils.progressbar,
        output_file_name=args.write_rr_graph,
    )

    graph = xml_graph.graph

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

    with DatabaseCache(args.connection_database, True) as conn:
        cur = conn.cursor()
        for name, internal_capacitance, drive_resistance, intrinsic_delay, \
                switch_type in cur.execute("""
SELECT
    name,
    internal_capacitance,
    drive_resistance,
    intrinsic_delay,
    switch_type
FROM
    switch;"""):
            # Add back missing switchs, which were unused in arch xml, and so
            # were not  emitted in rrgraph XML.
            #
            # TODO: This can be removed once
            # https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/354
            # is fixed.

            try:
                graph.get_switch_id(name)
                continue
            except KeyError:
                xml_graph.add_switch(
                    graph2.Switch(
                        id=None,
                        name=name,
                        type=graph2.SwitchType[switch_type.upper()],
                        timing=graph2.SwitchTiming(
                            r=drive_resistance,
                            c_in=0.0,
                            c_out=0.0,
                            c_internal=internal_capacitance,
                            t_del=intrinsic_delay,
                        ),
                        sizing=graph2.SwitchSizing(
                            mux_trans_size=0,
                            buf_size=0,
                        ),
                    ))

        # Mapping of graph_node.pkey to rr node id.
        node_mapping = {}

        print('{} Creating connection box list'.format(now()))
        connection_box_map = create_connection_boxes(conn, graph)

        # Match site pins rr nodes with graph_node's in the connection_database.
        print('{} Importing graph nodes'.format(now()))
        import_graph_nodes(conn, graph, node_mapping, connection_box_map)

        # Walk all track graph nodes and add them.
        print('{} Creating tracks'.format(now()))
        segment_id = graph.get_segment_id_from_name('dummy')
        create_track_rr_graph(conn, graph, node_mapping, use_roi, roi,
                              synth_tiles, segment_id)

        # 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.
        if use_roi:
            print('{} Adding synthetic edges'.format(now()))
            add_synthetic_edges(conn, graph, node_mapping, grid, synth_tiles)

        print('{} Creating channels.'.format(now()))
        channels_obj = create_channels(conn)

        x_dim, y_dim = phy_grid_dims(conn)
        connection_box_obj = graph.create_connection_box_object(x_dim=x_dim,
                                                                y_dim=y_dim)

        print('{} Serializing to disk.'.format(now()))
        with xml_graph:
            xml_graph.start_serialize_to_xml(
                tool_version=tool_version,
                tool_comment=tool_comment,
                channels_obj=channels_obj,
                connection_box_obj=connection_box_obj,
            )

            xml_graph.serialize_nodes(yield_nodes(xml_graph.graph.nodes))
            xml_graph.serialize_edges(
                import_graph_edges(conn, graph, node_mapping))

        print('{} Writing node map.'.format(now()))
        with open(args.write_rr_node_map, 'wb') as f:
            pickle.dump(node_mapping, f)
        print('{} Done writing node map.'.format(now()))
Exemplo n.º 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()))
Exemplo n.º 6
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,
    )
Exemplo n.º 7
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('--connection_database',
                        help='Database of fabric connectivity',
                        required=True)
    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,
        output_file_name=args.write_rr_graph,
    )

    graph = xml_graph.graph

    # Add back short switch, which is unused in arch xml, so is not emitted in
    # rrgraph XML.
    #
    # TODO: This can be removed once
    # https://github.com/verilog-to-routing/vtr-verilog-to-routing/issues/354
    # is fixed.
    try:
        short = graph.get_switch_id('short')
    except KeyError:
        short = xml_graph.add_switch(
            graph2.Switch(
                id=None,
                name='short',
                type=graph2.SwitchType.SHORT,
                timing=None,
                sizing=graph2.SwitchSizing(
                    mux_trans_size=0,
                    buf_size=0,
                ),
            ))

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

    with DatabaseCache(args.connection_database, True) as conn:

        # Mapping of graph_node.pkey to rr node id.
        node_mapping = {}

        # Match site pins rr nodes with graph_node's in the connection_database.
        print('{} Importing graph nodes'.format(now()))
        import_graph_nodes(conn, graph, node_mapping)

        # Walk all track graph nodes and add them.
        print('{} Creating tracks'.format(now()))
        segment_id = graph.get_segment_id_from_name('dummy')
        create_track_rr_graph(conn, graph, node_mapping, use_roi, roi,
                              synth_tiles, segment_id)

        # 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.
        if use_roi:
            print('{} Adding synthetic edges'.format(now()))
            add_synthetic_edges(conn, graph, node_mapping, grid, synth_tiles)

        print('{} Creating channels.'.format(now()))
        channels_obj = create_channels(conn)

        print('{} Serializing to disk.'.format(now()))
        with xml_graph:
            xml_graph.start_serialize_to_xml(
                tool_version=tool_version,
                tool_comment=tool_comment,
                channels_obj=channels_obj,
            )

            xml_graph.serialize_nodes(yield_nodes(xml_graph.graph.nodes))
            xml_graph.serialize_edges(
                import_graph_edges(conn, graph, node_mapping))