|
| 1 | +/* Standard header files required go first */ |
| 2 | +#include <map> |
| 3 | + |
| 4 | +/* EXTERNAL library header files go second*/ |
| 5 | +#include "vtr_assert.h" |
| 6 | +#include "vtr_time.h" |
| 7 | + |
| 8 | +/* VPR header files go then */ |
| 9 | +#include "vpr_types.h" |
| 10 | +#include "rr_graph_obj.h" |
| 11 | +#include "check_rr_graph_obj.h" |
| 12 | +#include "create_rr_graph.h" |
| 13 | + |
| 14 | +/* Finally we include global variables */ |
| 15 | +#include "globals.h" |
| 16 | + |
| 17 | +/******************************************************************** |
| 18 | + * TODO: remove when this conversion (from traditional to new data structure) |
| 19 | + * is no longer needed |
| 20 | + * This function will convert an existing rr_graph in device_ctx to the RRGraph |
| 21 | + *object |
| 22 | + * This function is used to test our RRGraph if it is acceptable in downstream |
| 23 | + *routers |
| 24 | + ********************************************************************/ |
| 25 | +void convert_rr_graph(std::vector<t_segment_inf>& vpr_segments) { |
| 26 | + vtr::ScopedStartFinishTimer timer("Build routing resource graph object"); |
| 27 | + |
| 28 | + /* IMPORTANT: to build clock tree, |
| 29 | + * vpr added segments to the original arch segments |
| 30 | + * This is why to use vpr_segments as an inputs!!! |
| 31 | + */ |
| 32 | + auto& device_ctx = g_vpr_ctx.mutable_device(); |
| 33 | + |
| 34 | + /* make sure we have a clean empty rr_graph */ |
| 35 | + device_ctx.rr_graph.clear(); |
| 36 | + |
| 37 | + /* The number of switches are in general small, |
| 38 | + * reserve switches may not bring significant memory efficiency |
| 39 | + * So, we just use create_switch to push_back each time |
| 40 | + */ |
| 41 | + device_ctx.rr_graph.reserve_switches(device_ctx.rr_switch_inf.size()); |
| 42 | + // Create the switches |
| 43 | + for (size_t iswitch = 0; iswitch < device_ctx.rr_switch_inf.size(); ++iswitch) { |
| 44 | + device_ctx.rr_graph.create_switch(device_ctx.rr_switch_inf[iswitch]); |
| 45 | + } |
| 46 | + |
| 47 | + /* The number of segments are in general small, reserve segments may not bring |
| 48 | + * significant memory efficiency */ |
| 49 | + device_ctx.rr_graph.reserve_segments(vpr_segments.size()); |
| 50 | + // Create the segments |
| 51 | + for (size_t iseg = 0; iseg < vpr_segments.size(); ++iseg) { |
| 52 | + device_ctx.rr_graph.create_segment(vpr_segments[iseg]); |
| 53 | + } |
| 54 | + |
| 55 | + /* Reserve list of nodes to be memory efficient */ |
| 56 | + device_ctx.rr_graph.reserve_nodes(device_ctx.rr_nodes.size()); |
| 57 | + |
| 58 | + // Create the nodes |
| 59 | + std::map<int, RRNodeId> old_to_new_rr_node; |
| 60 | + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { |
| 61 | + auto& node = device_ctx.rr_nodes[inode]; |
| 62 | + RRNodeId rr_node = device_ctx.rr_graph.create_node(node.type()); |
| 63 | + |
| 64 | + device_ctx.rr_graph.set_node_xlow(rr_node, node.xlow()); |
| 65 | + device_ctx.rr_graph.set_node_ylow(rr_node, node.ylow()); |
| 66 | + device_ctx.rr_graph.set_node_xhigh(rr_node, node.xhigh()); |
| 67 | + device_ctx.rr_graph.set_node_yhigh(rr_node, node.yhigh()); |
| 68 | + |
| 69 | + device_ctx.rr_graph.set_node_capacity(rr_node, node.capacity()); |
| 70 | + |
| 71 | + device_ctx.rr_graph.set_node_ptc_num(rr_node, node.ptc_num()); |
| 72 | + |
| 73 | + device_ctx.rr_graph.set_node_cost_index(rr_node, node.cost_index()); |
| 74 | + |
| 75 | + if (CHANX == node.type() || CHANY == node.type()) { |
| 76 | + device_ctx.rr_graph.set_node_direction(rr_node, node.direction()); |
| 77 | + } |
| 78 | + if (IPIN == node.type() || OPIN == node.type()) { |
| 79 | + device_ctx.rr_graph.set_node_side(rr_node, node.side()); |
| 80 | + } |
| 81 | + device_ctx.rr_graph.set_node_R(rr_node, node.R()); |
| 82 | + device_ctx.rr_graph.set_node_C(rr_node, node.C()); |
| 83 | + |
| 84 | + /* Set up segment id */ |
| 85 | + short irc_data = node.cost_index(); |
| 86 | + short iseg = device_ctx.rr_indexed_data[irc_data].seg_index; |
| 87 | + device_ctx.rr_graph.set_node_segment(rr_node, RRSegmentId(iseg)); |
| 88 | + |
| 89 | + VTR_ASSERT(!old_to_new_rr_node.count(inode)); |
| 90 | + old_to_new_rr_node[inode] = rr_node; |
| 91 | + } |
| 92 | + |
| 93 | + /* Reserve list of edges to be memory efficient */ |
| 94 | + { |
| 95 | + int num_edges_to_reserve = 0; |
| 96 | + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { |
| 97 | + const auto& node = device_ctx.rr_nodes[inode]; |
| 98 | + num_edges_to_reserve += node.num_edges(); |
| 99 | + } |
| 100 | + device_ctx.rr_graph.reserve_edges(num_edges_to_reserve); |
| 101 | + } |
| 102 | + |
| 103 | + // Create the edges |
| 104 | + std::map<std::pair<int, int>, RREdgeId> old_to_new_rr_edge; // Key: |
| 105 | + // {inode,iedge} |
| 106 | + for (size_t inode = 0; inode < device_ctx.rr_nodes.size(); ++inode) { |
| 107 | + const auto& node = device_ctx.rr_nodes[inode]; |
| 108 | + for (int iedge = 0; iedge < node.num_edges(); ++iedge) { |
| 109 | + int isink_node = node.edge_sink_node(iedge); |
| 110 | + int iswitch = node.edge_switch(iedge); |
| 111 | + |
| 112 | + VTR_ASSERT(old_to_new_rr_node.count(inode)); |
| 113 | + VTR_ASSERT(old_to_new_rr_node.count(isink_node)); |
| 114 | + |
| 115 | + RREdgeId rr_edge = device_ctx.rr_graph.create_edge(old_to_new_rr_node[inode], |
| 116 | + old_to_new_rr_node[isink_node], |
| 117 | + RRSwitchId(iswitch)); |
| 118 | + |
| 119 | + auto key = std::make_pair(inode, iedge); |
| 120 | + VTR_ASSERT(!old_to_new_rr_edge.count(key)); |
| 121 | + old_to_new_rr_edge[key] = rr_edge; |
| 122 | + } |
| 123 | + } |
| 124 | + |
| 125 | + /* Partition edges to be two class: configurable (1st part) and |
| 126 | + * non-configurable (2nd part) |
| 127 | + * See how the router will use the edges and determine the strategy |
| 128 | + * if we want to partition the edges first or depends on the routing needs |
| 129 | + */ |
| 130 | + device_ctx.rr_graph.partition_edges(); |
| 131 | + |
| 132 | + /* Essential check for rr_graph, build look-up and */ |
| 133 | + if (false == device_ctx.rr_graph.validate()) { |
| 134 | + /* Error out if built-in validator of rr_graph fails */ |
| 135 | + vpr_throw(VPR_ERROR_ROUTE, |
| 136 | + __FILE__, |
| 137 | + __LINE__, |
| 138 | + "Fundamental errors occurred when validating rr_graph object!\n"); |
| 139 | + } |
| 140 | + |
| 141 | + /* Error out if advanced checker of rr_graph fails */ |
| 142 | + if (false == check_rr_graph(device_ctx.rr_graph)) { |
| 143 | + vpr_throw(VPR_ERROR_ROUTE, |
| 144 | + __FILE__, |
| 145 | + __LINE__, |
| 146 | + "Advanced checking rr_graph object fails! Routing may still work " |
| 147 | + "but not smooth\n"); |
| 148 | + } |
| 149 | +} |
0 commit comments