diff --git a/libs/librrgraph/src/base/check_rr_graph.cpp b/libs/librrgraph/src/base/check_rr_graph.cpp index d774fe4c7e..dbea0e20ba 100644 --- a/libs/librrgraph/src/base/check_rr_graph.cpp +++ b/libs/librrgraph/src/base/check_rr_graph.cpp @@ -58,13 +58,13 @@ void check_rr_graph(const RRGraphView& rr_graph, route_type = e_route_type::GLOBAL; } - auto total_edges_to_node = std::vector(rr_graph.num_nodes()); - auto switch_types_from_current_to_node = std::vector(rr_graph.num_nodes()); + std::vector total_edges_to_node(rr_graph.num_nodes()); + std::vector switch_types_from_current_to_node(rr_graph.num_nodes()); const int num_rr_switches = rr_graph.num_rr_switches(); std::vector> edges; - for (const RRNodeId& rr_node : rr_graph.nodes()) { + for (const RRNodeId rr_node : rr_graph.nodes()) { size_t inode = (size_t)rr_node; rr_graph.validate_node(rr_node); @@ -83,7 +83,7 @@ void check_rr_graph(const RRGraphView& rr_graph, check_rr_node(rr_graph, rr_indexed_data, grid, chan_width, route_type, inode, is_flat); - /* Check all the connectivity (edges, etc.) information. */ + // Check all the connectivity (edges, etc.) information. edges.resize(0); edges.reserve(num_edges); @@ -329,14 +329,9 @@ void check_rr_node(const RRGraphView& rr_graph, const enum e_route_type route_type, const int inode, bool is_flat) { - /* This routine checks that the rr_node is inside the grid and has a valid - * pin number, etc. - */ - //Make sure over-flow doesn't happen VTR_ASSERT(inode >= 0); - int nodes_per_chan, tracks_per_node; - float C, R; + int tracks_per_node; RRNodeId rr_node = RRNodeId(inode); e_rr_type rr_type = rr_graph.node_type(rr_node); @@ -437,6 +432,14 @@ void check_rr_node(const RRGraphView& rr_graph, } break; + case e_rr_type::CHANZ: + if (xhigh != xlow || yhigh != ylow || xhigh > int(grid.width()) - 2 || ylow < 1 || yhigh > int(grid.height()) - 2) { + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, + "Error in check_rr_node: CHANZ out of range for endpoints (%d,%d) and (%d,%d)\n", xlow, ylow, xhigh, yhigh); + } + // TODO: handle global routing case + break; + default: VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "in check_rr_node: Unexpected segment type: %d\n", rr_type); @@ -481,20 +484,9 @@ void check_rr_node(const RRGraphView& rr_graph, case e_rr_type::CHANX: case e_rr_type::CHANY: if (route_type == e_route_type::DETAILED) { - nodes_per_chan = chan_width.max; tracks_per_node = 1; } else { - nodes_per_chan = 1; - tracks_per_node = ((rr_type == e_rr_type::CHANX) ? chan_width.x_list[ylow] : chan_width.y_list[xlow]); - } - - //if a chanx/chany has length 0, it means it is used to connect different dice together - //hence, the ptc number can be larger than nodes_per_chan - if(xlow != xhigh || ylow != yhigh) { - if (ptc_num >= nodes_per_chan) { - VPR_ERROR(VPR_ERROR_ROUTE, - "in check_rr_node: inode %d (type %d) has a ptc_num of %d.\n", inode, rr_type, ptc_num); - } + tracks_per_node = (rr_type == e_rr_type::CHANX) ? chan_width.x_list[ylow] : chan_width.y_list[xlow]; } if (capacity != tracks_per_node) { @@ -503,14 +495,18 @@ void check_rr_node(const RRGraphView& rr_graph, } break; + case e_rr_type::CHANZ: + // TODO: do checks for CHANZ type + break; + default: VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "in check_rr_node: Unexpected segment type: %d\n", rr_type); } - /* Check that the capacitance and resistance are reasonable. */ - C = rr_graph.node_C(rr_node); - R = rr_graph.node_R(rr_node); + // Check that the capacitance and resistance are reasonable. + float C = rr_graph.node_C(rr_node); + float R = rr_graph.node_R(rr_node); if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) { if (C < 0. || R < 0.) { diff --git a/libs/librrgraph/src/base/check_rr_graph.h b/libs/librrgraph/src/base/check_rr_graph.h index 828438faab..4ace55ba0f 100644 --- a/libs/librrgraph/src/base/check_rr_graph.h +++ b/libs/librrgraph/src/base/check_rr_graph.h @@ -12,6 +12,27 @@ void check_rr_graph(const RRGraphView& rr_graph, const e_graph_type graph_type, bool is_flat); +/** + * @brief Validates the internal consistency of a single RR node in the routing resource graph. + * + * This function performs a series of checks on the specified RR node to ensure it conforms + * to architectural and routing constraints. It verifies: + * - That the node's bounding box is valid and within the device grid bounds. + * - That the node's PTC number, capacity, and cost index are within legal limits. + * - That IPINs, OPINs, SOURCEs, and SINKs correspond to valid physical locations and types. + * - That CHANX, CHANY, and CHANZ nodes have legal coordinate bounds and track indices. + * - That electrical characteristics (resistance and capacitance) are appropriate for the node type. + * + * Errors or inconsistencies will cause fatal errors or logged messages, depending on severity. + * + * @param rr_graph The read-only view of the routing resource graph. + * @param rr_indexed_data Indexed data for RR node cost metrics. + * @param grid The device grid. + * @param chan_width The channel widths for different channels + * @param route_type The routing type (GLOBAL or DETAILED). + * @param inode The index of the RR node to be checked. + * @param is_flat Flag indicating if flat routing is enabled. + */ void check_rr_node(const RRGraphView& rr_graph, const vtr::vector& rr_indexed_data, const DeviceGrid& grid, diff --git a/libs/librrgraph/src/base/rr_graph_builder.cpp b/libs/librrgraph/src/base/rr_graph_builder.cpp index 173914241d..a2ebdb0c0d 100644 --- a/libs/librrgraph/src/base/rr_graph_builder.cpp +++ b/libs/librrgraph/src/base/rr_graph_builder.cpp @@ -33,6 +33,7 @@ void RRGraphBuilder::add_node_to_all_locs(RRNodeId node) { switch (node_type) { case e_rr_type::SOURCE: case e_rr_type::SINK: + case e_rr_type::CHANZ: case e_rr_type::CHANY: case e_rr_type::CHANX: node_lookup_.add_node(node, node_layer, ix, iy, node_type, node_ptc_num, TOTAL_2D_SIDES[0]); diff --git a/libs/librrgraph/src/base/rr_graph_storage.cpp b/libs/librrgraph/src/base/rr_graph_storage.cpp index 7225f1892b..4466eb5903 100644 --- a/libs/librrgraph/src/base/rr_graph_storage.cpp +++ b/libs/librrgraph/src/base/rr_graph_storage.cpp @@ -646,8 +646,8 @@ void t_rr_graph_storage::set_node_pin_num(RRNodeId id, int new_pin_num) { } void t_rr_graph_storage::set_node_track_num(RRNodeId id, int new_track_num) { - if (node_type(id) != e_rr_type::CHANX && node_type(id) != e_rr_type::CHANY) { - VTR_LOG_ERROR("Attempted to set RR node 'track_num' for non-CHANX/CHANY type '%s'", node_type_string(id)); + if (node_type(id) != e_rr_type::CHANX && node_type(id) != e_rr_type::CHANY && node_type(id) != e_rr_type::CHANZ) { + VTR_LOG_ERROR("Attempted to set RR node 'track_num' for non-CHANX/CHANY/CHANZ type '%s'", node_type_string(id)); } node_ptc_[id].ptc_.track_num = new_track_num; } @@ -663,10 +663,9 @@ int t_rr_graph_storage::node_ptc_num(RRNodeId id) const { return node_ptc_[id].ptc_.pin_num; } -static int get_node_pin_num( - vtr::array_view_id node_storage, - vtr::array_view_id node_ptc, - RRNodeId id) { +static int get_node_pin_num(vtr::array_view_id node_storage, + vtr::array_view_id node_ptc, + RRNodeId id) { e_rr_type node_type = node_storage[id].type_; if (node_type != e_rr_type::IPIN && node_type != e_rr_type::OPIN) { VTR_LOG_ERROR("Attempted to access RR node 'pin_num' for non-IPIN/OPIN type '%s'", rr_node_typename[node_type]); @@ -674,21 +673,19 @@ static int get_node_pin_num( return node_ptc[id].ptc_.pin_num; } -static int get_node_track_num( - vtr::array_view_id node_storage, - vtr::array_view_id node_ptc, - RRNodeId id) { +static int get_node_track_num(vtr::array_view_id node_storage, + vtr::array_view_id node_ptc, + RRNodeId id) { e_rr_type node_type = node_storage[id].type_; - if (node_type != e_rr_type::CHANX && node_type != e_rr_type::CHANY) { - VTR_LOG_ERROR("Attempted to access RR node 'track_num' for non-CHANX/CHANY type '%s'", rr_node_typename[node_type]); + if (node_type != e_rr_type::CHANX && node_type != e_rr_type::CHANY && node_type != e_rr_type::CHANZ) { + VTR_LOG_ERROR("Attempted to access RR node 'track_num' for non-CHANX/CHANY/CHANZ type '%s'", rr_node_typename[node_type]); } return node_ptc[id].ptc_.track_num; } -static int get_node_class_num( - vtr::array_view_id node_storage, - vtr::array_view_id node_ptc, - RRNodeId id) { +static int get_node_class_num(vtr::array_view_id node_storage, + vtr::array_view_id node_ptc, + RRNodeId id) { e_rr_type node_type = node_storage[id].type_; if (node_type != e_rr_type::SOURCE && node_type != e_rr_type::SINK) { VTR_LOG_ERROR("Attempted to access RR node 'class_num' for non-SOURCE/SINK type '%s'", rr_node_typename[node_type]); @@ -760,7 +757,7 @@ void t_rr_graph_storage::set_node_capacity(RRNodeId id, short new_capacity) { } void t_rr_graph_storage::set_node_direction(RRNodeId id, Direction new_direction) { - if (node_type(id) != e_rr_type::CHANX && node_type(id) != e_rr_type::CHANY) { + if (node_type(id) != e_rr_type::CHANX && node_type(id) != e_rr_type::CHANY && node_type(id) != e_rr_type::CHANZ) { VTR_LOG_ERROR("Attempted to set RR node 'direction' for non-channel type '%s'", node_type_string(id)); } node_storage_[id].dir_side_.direction = new_direction; diff --git a/libs/librrgraph/src/base/rr_graph_utils.cpp b/libs/librrgraph/src/base/rr_graph_utils.cpp index a728ed0459..c244ef5c4e 100644 --- a/libs/librrgraph/src/base/rr_graph_utils.cpp +++ b/libs/librrgraph/src/base/rr_graph_utils.cpp @@ -54,19 +54,18 @@ static void rr_walk_cluster_recursive(const RRGraphView& rr_graph, } std::vector find_rr_graph_switches(const RRGraph& rr_graph, - const RRNodeId& from_node, - const RRNodeId& to_node) { + RRNodeId from_node, + RRNodeId to_node) { std::vector switches; std::vector edges = rr_graph.find_edges(from_node, to_node); - if (true == edges.empty()) { + if (edges.empty()) { /* edge is open, we return an empty vector of switches */ return switches; } - /* Reach here, edge list is not empty, find switch id one by one - * and update the switch list - */ - for (auto edge : edges) { + // Reach here, edge list is not empty, find switch id one by one + // and update the switch list + for (RREdgeId edge : edges) { switches.push_back(rr_graph.edge_switch(edge)); } @@ -82,10 +81,8 @@ int seg_index_of_cblock(const RRGraphView& rr_graph, e_rr_type from_rr_type, int } int seg_index_of_sblock(const RRGraphView& rr_graph, int from_node, int to_node) { - e_rr_type from_rr_type, to_rr_type; - - from_rr_type = rr_graph.node_type(RRNodeId(from_node)); - to_rr_type = rr_graph.node_type(RRNodeId(to_node)); + e_rr_type from_rr_type = rr_graph.node_type(RRNodeId(from_node)); + e_rr_type to_rr_type = rr_graph.node_type(RRNodeId(to_node)); if (from_rr_type == e_rr_type::CHANX) { if (to_rr_type == e_rr_type::CHANY) { @@ -135,7 +132,7 @@ vtr::vector> get_fan_in_list(const RRGraphView& node_fan_in_list.resize(rr_graph.num_nodes(), std::vector(0)); node_fan_in_list.shrink_to_fit(); - //Walk the graph and increment fanin on all dwnstream nodes + // Walk the graph and increment fanin on all downstream nodes rr_graph.rr_nodes().for_each_edge( [&](RREdgeId edge, RRNodeId src, RRNodeId sink) -> void { (void) src; @@ -238,7 +235,7 @@ void rr_set_sink_locs(const RRGraphView& rr_graph, RRGraphBuilder& rr_graph_buil bool inter_layer_connections_limited_to_opin(const RRGraphView& rr_graph) { bool limited_to_opin = true; - for (const auto& from_node : rr_graph.nodes()) { + for (const RRNodeId from_node : rr_graph.nodes()) { for (t_edge_size edge : rr_graph.edges(from_node)) { RRNodeId to_node = rr_graph.edge_sink_node(from_node, edge); int from_layer = rr_graph.node_layer(from_node); diff --git a/libs/librrgraph/src/base/rr_graph_utils.h b/libs/librrgraph/src/base/rr_graph_utils.h index b6bb43f625..73e6c54a08 100644 --- a/libs/librrgraph/src/base/rr_graph_utils.h +++ b/libs/librrgraph/src/base/rr_graph_utils.h @@ -51,8 +51,8 @@ struct t_cluster_pin_chain { * @return A vector of switch IDs */ std::vector find_rr_graph_switches(const RRGraph& rr_graph, - const RRNodeId& from_node, - const RRNodeId& to_node); + RRNodeId from_node, + RRNodeId to_node); /** * @brief This function generates and returns a vector indexed by RRNodeId containing a vector of fan-in edges for each node. diff --git a/libs/librrgraph/src/base/rr_graph_view.h b/libs/librrgraph/src/base/rr_graph_view.h index 0fe36d8cef..f77a69167f 100644 --- a/libs/librrgraph/src/base/rr_graph_view.h +++ b/libs/librrgraph/src/base/rr_graph_view.h @@ -236,13 +236,19 @@ class RRGraphView { } /** @brief Return the length (number of grid tile units spanned by the wire, including the endpoints) of a specified node. - * @note node_length() only applies to CHANX or CHANY and is always a positive number + * @note node_length() only applies to CHANX or CHANY or CHANZ and is always a positive number */ inline int node_length(RRNodeId node) const { - VTR_ASSERT(node_type(node) == e_rr_type::CHANX || node_type(node) == e_rr_type::CHANY); + VTR_ASSERT(node_type(node) == e_rr_type::CHANX || node_type(node) == e_rr_type::CHANY || node_type(node) == e_rr_type::CHANZ); + + if (node_type(node) == e_rr_type::CHANZ) { + return 1; + } + if (node_direction(node) == Direction::NONE) { return 0; //length zero wire } + int length = 1 + node_xhigh(node) - node_xlow(node) + node_yhigh(node) - node_ylow(node); VTR_ASSERT_SAFE(length > 0); return length; @@ -257,7 +263,8 @@ class RRGraphView { } /** @brief Check if two routing resource nodes are adjacent (must be a CHANX and a CHANY). - * @note This function performs error checking by determining whether two nodes are physically adjacent based on their geometry. It does not verify the routing edges to confirm if a connection is feasible within the current routing graph. + * @note This function performs error checking by determining whether two nodes are physically adjacent based on their geometry. + * It does not verify the routing edges to confirm if a connection is feasible within the current routing graph. */ inline bool nodes_are_adjacent(RRNodeId chanx_node, RRNodeId chany_node) const { VTR_ASSERT(node_type(chanx_node) == e_rr_type::CHANX && node_type(chany_node) == e_rr_type::CHANY); @@ -332,7 +339,7 @@ class RRGraphView { start_x = " (" + std::to_string(node_xhigh(node)) + ","; start_y = std::to_string(node_yhigh(node)) + ","; start_layer_str = std::to_string(node_layer_num) + ")"; - } else if (node_type(node) == e_rr_type::CHANX || node_type(node) == e_rr_type::CHANY) { //for channels, we would like to describe the component with segment specific information + } else if (node_type(node) == e_rr_type::CHANX || node_type(node) == e_rr_type::CHANY || node_type(node) == e_rr_type::CHANZ) { //for channels, we would like to describe the component with segment specific information RRIndexedDataId cost_index = node_cost_index(node); int seg_index = rr_indexed_data_[cost_index].seg_index; coordinate_string += rr_segments(RRSegmentId(seg_index)).name; //Write the segment name diff --git a/libs/librrgraph/src/base/rr_node_types.h b/libs/librrgraph/src/base/rr_node_types.h index 31c4e38e14..15f35314ad 100644 --- a/libs/librrgraph/src/base/rr_node_types.h +++ b/libs/librrgraph/src/base/rr_node_types.h @@ -29,18 +29,22 @@ enum class e_rr_type : unsigned char { OPIN, /// RR_TYPES = {{e_rr_type::SOURCE, e_rr_type::SINK, e_rr_type::IPIN, - e_rr_type::OPIN, e_rr_type::CHANX, e_rr_type::CHANY}}; +constexpr std::array RR_TYPES = {{e_rr_type::SOURCE, e_rr_type::SINK, + e_rr_type::IPIN, e_rr_type::OPIN, + e_rr_type::CHANX, e_rr_type::CHANY, e_rr_type::CHANZ}}; /** * @brief Lookup for the string representation of the given node type. This is useful * for logging the type of an RR node. */ -constexpr vtr::array rr_node_typename {"SOURCE", "SINK", "IPIN", "OPIN", "CHANX", "CHANY"}; +constexpr vtr::array rr_node_typename {"SOURCE", "SINK", + "IPIN", "OPIN", + "CHANX", "CHANY", "CHANZ"}; /** * @enum Direction diff --git a/libs/librrgraph/src/base/rr_spatial_lookup.cpp b/libs/librrgraph/src/base/rr_spatial_lookup.cpp index 3b53404e6f..7ea9dd3c81 100644 --- a/libs/librrgraph/src/base/rr_spatial_lookup.cpp +++ b/libs/librrgraph/src/base/rr_spatial_lookup.cpp @@ -149,9 +149,9 @@ std::vector RRSpatialLookup::find_channel_nodes(int layer, int x, int y, e_rr_type type) const { - /* Pre-check: node type should be routing tracks! */ - if (type != e_rr_type::CHANX && type != e_rr_type::CHANY) { - return std::vector(); + // Pre-check: node type should be routing tracks. + if (type != e_rr_type::CHANX && type != e_rr_type::CHANY && type != e_rr_type::CHANZ) { + return {}; } return find_nodes(layer, x, y, type); @@ -167,7 +167,7 @@ std::vector RRSpatialLookup::find_nodes_at_all_sides(int layer, /* TODO: Consider to access the raw data like find_node() rather than calling find_node() many times, which hurts runtime */ if (rr_type == e_rr_type::IPIN || rr_type == e_rr_type::OPIN) { indices.reserve(NUM_2D_SIDES); - //For pins, we need to look at all the sides of the current grid tile + // For pins, we need to look at all the sides of the current grid tile for (e_side side : TOTAL_2D_SIDES) { RRNodeId rr_node_index = find_node(layer, x, y, rr_type, ptc, side); if (rr_node_index) { @@ -176,7 +176,7 @@ std::vector RRSpatialLookup::find_nodes_at_all_sides(int layer, } indices.shrink_to_fit(); } else { - //Sides do not affect non-pins so there should only be one per ptc + // Sides do not affect non-pins so there should only be one per ptc RRNodeId rr_node_index = find_node(layer, x, y, rr_type, ptc); if (rr_node_index) { indices.push_back(rr_node_index); @@ -196,7 +196,7 @@ std::vector RRSpatialLookup::find_grid_nodes_at_all_sides(int layer, } std::vector nodes; - /* Reserve space to avoid memory fragmentation */ + // Reserve space to avoid memory fragmentation size_t num_nodes = 0; for (e_side node_side : TOTAL_2D_SIDES) { num_nodes += find_nodes(layer,x, y, rr_type, node_side).size(); diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h index bd7ff06819..2f760f64dc 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcxx.py /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: dcf32619cae0c49d168a2575bdb00896 + * Cmdline: uxsdcxx/uxsdcxx.py /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: 5d51b89242fe6e463629ac43a72e4606 */ #include @@ -1611,7 +1611,7 @@ template constexpr const char *lookup_switch_type[] = {"UXSD_INVALID", "mux", "tristate", "pass_gate", "short", "buffer"}; constexpr const char *lookup_segment_res_type[] = {"UXSD_INVALID", "GENERAL", "GCLK"}; constexpr const char *lookup_pin_type[] = {"UXSD_INVALID", "OPEN", "OUTPUT", "INPUT"}; -constexpr const char *lookup_node_type[] = {"UXSD_INVALID", "CHANX", "CHANY", "SOURCE", "SINK", "OPIN", "IPIN"}; +constexpr const char *lookup_node_type[] = {"UXSD_INVALID", "CHANX", "CHANY", "CHANZ", "SOURCE", "SINK", "OPIN", "IPIN"}; constexpr const char *lookup_node_direction[] = {"UXSD_INVALID", "INC_DIR", "DEC_DIR", "BI_DIR", "NONE"}; constexpr const char *lookup_node_clk_res_type[] = {"UXSD_INVALID", "VIRTUAL_SINK"}; constexpr const char *lookup_loc_side[] = {"UXSD_INVALID", "LEFT", "RIGHT", "TOP", "BOTTOM", "RIGHT_LEFT", "RIGHT_BOTTOM", "RIGHT_BOTTOM_LEFT", "TOP_RIGHT", "TOP_BOTTOM", "TOP_LEFT", "TOP_RIGHT_BOTTOM", "TOP_RIGHT_LEFT", "TOP_BOTTOM_LEFT", "TOP_RIGHT_BOTTOM_LEFT", "BOTTOM_LEFT"}; @@ -1814,6 +1814,9 @@ inline enum_node_type lex_enum_node_type(const char *in, bool throw_on_invalid, case onechar('Y', 0, 8): return enum_node_type::CHANY; break; + case onechar('Z', 0, 8): + return enum_node_type::CHANZ; + break; default: break; } break; diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h index 0b0b50ab8f..9fb505d137 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_capnp.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcap.py /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: dcf32619cae0c49d168a2575bdb00896 + * Cmdline: uxsdcxx/uxsdcap.py /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: 5d51b89242fe6e463629ac43a72e4606 */ #include @@ -220,6 +220,8 @@ inline enum_node_type conv_enum_node_type(ucap::NodeType e, const std::function< return enum_node_type::CHANX; case ucap::NodeType::CHANY: return enum_node_type::CHANY; + case ucap::NodeType::CHANZ: + return enum_node_type::CHANZ; case ucap::NodeType::SOURCE: return enum_node_type::SOURCE; case ucap::NodeType::SINK: @@ -242,6 +244,8 @@ inline ucap::NodeType conv_to_enum_node_type(enum_node_type e) { return ucap::NodeType::CHANX; case enum_node_type::CHANY: return ucap::NodeType::CHANY; + case enum_node_type::CHANZ: + return ucap::NodeType::CHANZ; case enum_node_type::SOURCE: return ucap::NodeType::SOURCE; case enum_node_type::SINK: diff --git a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h index 70a2aae0d0..425f1e706c 100644 --- a/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h +++ b/libs/librrgraph/src/io/gen/rr_graph_uxsdcxx_interface.h @@ -4,9 +4,9 @@ * https://github.com/duck2/uxsdcxx * Modify only if your build process doesn't involve regenerating this file. * - * Cmdline: uxsdcxx/uxsdcxx.py /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * Input file: /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd - * md5sum of input file: dcf32619cae0c49d168a2575bdb00896 + * Cmdline: uxsdcxx/uxsdcxx.py /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd + * Input file: /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd + * md5sum of input file: 5d51b89242fe6e463629ac43a72e4606 */ #include @@ -27,7 +27,7 @@ enum class enum_segment_res_type {UXSD_INVALID = 0, GENERAL, GCLK}; enum class enum_pin_type {UXSD_INVALID = 0, OPEN, OUTPUT, INPUT}; -enum class enum_node_type {UXSD_INVALID = 0, CHANX, CHANY, SOURCE, SINK, OPIN, IPIN}; +enum class enum_node_type {UXSD_INVALID = 0, CHANX, CHANY, CHANZ, SOURCE, SINK, OPIN, IPIN}; enum class enum_node_direction {UXSD_INVALID = 0, INC_DIR, DEC_DIR, BI_DIR, NONE}; diff --git a/libs/librrgraph/src/io/rr_graph.xsd b/libs/librrgraph/src/io/rr_graph.xsd index a958fc35ab..c6b214fd63 100644 --- a/libs/librrgraph/src/io/rr_graph.xsd +++ b/libs/librrgraph/src/io/rr_graph.xsd @@ -229,6 +229,7 @@ + diff --git a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h index 2f23c13d77..9ca8279f47 100644 --- a/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h +++ b/libs/librrgraph/src/io/rr_graph_uxsdcxx_serializer.h @@ -824,6 +824,11 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { int seg_ind_y = find_segment_index_along_axis(segment_id, Y_AXIS); rr_graph_builder_->set_node_cost_index(node_id, RRIndexedDataId(CHANX_COST_INDEX_START + segment_inf_x_.size() + seg_ind_y)); seg_index_[rr_graph.node_cost_index(node.id())] = segment_id; + } else if (rr_graph.node_type(node.id()) == e_rr_type::CHANZ) { + // TODO: Don't use CHANX info + int seg_ind_z = find_segment_index_along_axis(segment_id, X_AXIS); + rr_graph_builder_->set_node_cost_index(node_id, RRIndexedDataId(CHANX_COST_INDEX_START + seg_ind_z)); + seg_index_[rr_graph.node_cost_index(node.id())] = segment_id; } return inode; } @@ -881,9 +886,10 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { switch (rr_graph.node_type(node.id())) { case e_rr_type::CHANX: - break; case e_rr_type::CHANY: + case e_rr_type::CHANZ: break; + case e_rr_type::SOURCE: rr_graph_builder_->set_node_cost_index(node_id, RRIndexedDataId(SOURCE_COST_INDEX)); break; @@ -949,7 +955,7 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { inline void set_node_direction(uxsd::enum_node_direction direction, int& inode) final { const auto& rr_graph = (*rr_graph_); - auto node = (*rr_nodes_)[inode]; + const t_rr_node& node = (*rr_nodes_)[inode]; RRNodeId node_id = node.id(); if (direction == uxsd::enum_node_direction::UXSD_INVALID) { @@ -958,13 +964,18 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { "inode %d is type %d, which requires a direction, but no direction was supplied.", inode, rr_graph.node_type(node.id())); } + + // TODO: when CHANZ nodes have a direction, we should handle them + } else { rr_graph_builder_->set_node_direction(node_id, from_uxsd_node_direction(direction)); } } inline uxsd::enum_node_direction get_node_direction(const t_rr_node& node) final { const auto& rr_graph = (*rr_graph_); - if (rr_graph.node_type(node.id()) == e_rr_type::CHANX || rr_graph.node_type(node.id()) == e_rr_type::CHANY) { + if (rr_graph.node_type(node.id()) == e_rr_type::CHANX + || rr_graph.node_type(node.id()) == e_rr_type::CHANY + || rr_graph.node_type(node.id()) == e_rr_type::CHANZ) { return to_uxsd_node_direction(rr_graph.node_direction(node.id())); } else { return uxsd::enum_node_direction::UXSD_INVALID; @@ -1996,6 +2007,8 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { return e_rr_type::CHANX; case uxsd::enum_node_type::CHANY: return e_rr_type::CHANY; + case uxsd::enum_node_type::CHANZ: + return e_rr_type::CHANZ; case uxsd::enum_node_type::SOURCE: return e_rr_type::SOURCE; case uxsd::enum_node_type::SINK: @@ -2016,6 +2029,8 @@ class RrGraphSerializer final : public uxsd::RrGraphBase { return uxsd::enum_node_type::CHANX; case e_rr_type::CHANY: return uxsd::enum_node_type::CHANY; + case e_rr_type::CHANZ: + return uxsd::enum_node_type::CHANZ; case e_rr_type::SOURCE: return uxsd::enum_node_type::SOURCE; case e_rr_type::SINK: diff --git a/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp b/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp index 001c03fe89..9c68e2eb45 100644 --- a/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp +++ b/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.cpp @@ -1,22 +1,19 @@ +#include "alloc_and_load_rr_indexed_data.h" + #include /* Needed only for sqrt call (remove if sqrt removed) */ #include #include #include #include -#include "alloc_and_load_rr_indexed_data.h" - #include "arch_types.h" #include "vtr_assert.h" #include "vtr_log.h" #include "vtr_math.h" #include "vpr_error.h" - #include "rr_graph_utils.h" - #include "rr_graph_cost.h" - #include "histogram.h" /******************* Subroutines local to this module ************************/ @@ -60,8 +57,6 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, enum e_base_cost_type base_cost_type, const bool echo_enabled, const char* echo_file_name) { - int length, i, index; - (void)segment_inf; int total_num_segment = segment_inf_x.size() + segment_inf_y.size(); /*CHAX & CHANY segment lsit sizes may differ. but if we're using uniform channels, they @@ -75,7 +70,7 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, * * other than base_cost are invalid. Mark invalid fields as OPEN for safety. */ constexpr float nan = std::numeric_limits::quiet_NaN(); - for (i = SOURCE_COST_INDEX; i <= IPIN_COST_INDEX; i++) { + for (int i = SOURCE_COST_INDEX; i <= IPIN_COST_INDEX; i++) { rr_indexed_data[RRIndexedDataId(i)].ortho_cost_index = OPEN; rr_indexed_data[RRIndexedDataId(i)].seg_index = OPEN; rr_indexed_data[RRIndexedDataId(i)].inv_length = nan; @@ -87,9 +82,7 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, //TODO: SM: IPIN t_linear assumes wire_to_ipin_switch which corresponds to within die switch connection rr_indexed_data[RRIndexedDataId(IPIN_COST_INDEX)].T_linear = rr_graph.rr_switch_inf(RRSwitchId(wire_to_ipin_switch)).Tdel; - std::vector ortho_costs; - - ortho_costs = find_ortho_cost_index(rr_graph, segment_inf_x, segment_inf_y, X_AXIS); + std::vector ortho_costs = find_ortho_cost_index(rr_graph, segment_inf_x, segment_inf_y, X_AXIS); /* AA: The code below should replace find_ortho_cost_index call once we deprecate the CLASSIC lookahead as it is the only lookahead * that actively uses the orthogonal cost indices. To avoid complicated dependencies with the rr_graph reader, regardless of the lookahead, @@ -106,10 +99,11 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, /* X-directed segments*/ for (size_t iseg = 0; iseg < segment_inf_x.size(); ++iseg) { - index = iseg + CHANX_COST_INDEX_START; + int index = iseg + CHANX_COST_INDEX_START; rr_indexed_data[RRIndexedDataId(index)].ortho_cost_index = ortho_costs[iseg]; + int length; if (segment_inf_x[iseg].longline) length = grid.width(); else @@ -124,9 +118,10 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, /* Y-directed segments*/ for (size_t iseg = segment_inf_x.size(); iseg < ortho_costs.size(); ++iseg) { - index = iseg + CHANX_COST_INDEX_START; + int index = iseg + CHANX_COST_INDEX_START; rr_indexed_data[RRIndexedDataId(index)].ortho_cost_index = ortho_costs[iseg]; + int length; if (segment_inf_x[iseg - segment_inf_x.size()].longline) length = grid.width(); else @@ -153,20 +148,17 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, /* AA: We use a normalized product of frequency and length to find the segment that is most likely * to connect to in the perpendicular axis. Note that the size of segment_inf_x & segment_inf_y is not - * the same necessarly. The result vector will contain the indices in segment_inf_perp + * the same necessarily. The result vector will contain the indices in segment_inf_perp * of the most likely perp segments for each segment at index i in segment_inf_parallel. * * Note: We use the seg_index field of t_segment_inf to store the segment index - * in the **unified** t_segment_inf vector. We will temporarly use this field in + * in the **unified** t_segment_inf vector. We will temporarily use this field in * a copy passed to the function to store the index w.r.t the parallel axis segment list.*/ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, - const std::vector segment_inf_x, - const std::vector segment_inf_y, + const std::vector& segment_inf_x, + const std::vector& segment_inf_y, e_parallel_axis parallel_axis) { - auto segment_inf_parallel = parallel_axis == X_AXIS ? segment_inf_x : segment_inf_y; - auto segment_inf_perp = parallel_axis == X_AXIS ? segment_inf_y : segment_inf_x; - size_t num_segments = segment_inf_x.size() + segment_inf_y.size(); std::vector> dest_nodes_count; @@ -184,8 +176,8 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, std::vector ortho_cost_indices(dest_nodes_count.size(), 0); - //Go through all rr_Nodes. Look at the ones with CHAN type. Count all outgoing edges to CHAN typed nodes from each CHAN type node. - for (const RRNodeId& rr_node : rr_graph.nodes()) { + // Go through all rr_Nodes. Look at the ones with CHAN type. Count all outgoing edges to CHAN typed nodes from each CHAN type node. + for (const RRNodeId rr_node : rr_graph.nodes()) { for (size_t iedge = 0; iedge < rr_graph.num_edges(rr_node); ++iedge) { RRNodeId to_node = rr_graph.edge_sink_node(rr_node, iedge); e_rr_type from_node_type = rr_graph.node_type(rr_node); @@ -194,7 +186,7 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, size_t from_node_cost_index = (size_t)rr_graph.node_cost_index(rr_node); size_t to_node_cost_index = (size_t)rr_graph.node_cost_index(to_node); - //if the type is smaller than start index, means destination is not a CHAN type node. + // if the type is smaller than start index, means destination is not a CHAN type node. if ((from_node_type == e_rr_type::CHANX && to_node_type == e_rr_type::CHANY) || (from_node_type == e_rr_type::CHANY && to_node_type == e_rr_type::CHANX)) { if (to_node_type == e_rr_type::CHANY) { @@ -227,7 +219,8 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, /*Update seg_index */ #ifdef FREQ_LENGTH_ORTHO_COSTS - + const std::vector& segment_inf_parallel = parallel_axis == X_AXIS ? segment_inf_x : segment_inf_y; + const std::vector& segment_inf_perp = parallel_axis == X_AXIS ? segment_inf_y : segment_inf_x; for (int i = 0; i < (int)segment_inf_perp.size(); ++i) segment_inf_perp[i].seg_index = i; @@ -326,6 +319,9 @@ std::vector find_ortho_cost_index(const RRGraphView& rr_graph, # endif return ortho_costs_indices; + +#else + (void)parallel_axis; #endif } @@ -427,10 +423,10 @@ static void load_rr_indexed_data_base_costs(const RRGraphView& rr_graph, static std::vector count_rr_segment_types(const RRGraphView& rr_graph, const vtr::vector& rr_indexed_data) { std::vector rr_segment_type_counts; - for (const RRNodeId& id : rr_graph.nodes()) { + for (const RRNodeId id : rr_graph.nodes()) { if (rr_graph.node_type(id) != e_rr_type::CHANX && rr_graph.node_type(id) != e_rr_type::CHANY) continue; - auto cost_index = rr_graph.node_cost_index(id); + RRIndexedDataId cost_index = rr_graph.node_cost_index(id); int seg_index = rr_indexed_data[cost_index].seg_index; @@ -498,7 +494,7 @@ static float get_delay_normalization_fac(const vtr::vector& rr_indexed_data) { - auto fan_in_list = get_fan_in_list(rr_graph); + vtr::vector> fan_in_list = get_fan_in_list(rr_graph); vtr::vector num_nodes_of_index(rr_indexed_data.size(), 0); vtr::vector> C_total(rr_indexed_data.size()); @@ -523,7 +519,7 @@ static void load_rr_indexed_data_T_values(const RRGraphView& rr_graph, * The median of R and C values for each cost index is assigned to the indexed * data. */ - for (const RRNodeId& rr_id : rr_graph.nodes()) { + for (const RRNodeId rr_id : rr_graph.nodes()) { e_rr_type rr_type = rr_graph.node_type(rr_id); if (rr_type != e_rr_type::CHANX && rr_type != e_rr_type::CHANY) { diff --git a/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.h b/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.h index a70946dc56..578c0e1302 100644 --- a/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.h +++ b/libs/librrgraph/src/utils/alloc_and_load_rr_indexed_data.h @@ -17,6 +17,6 @@ void alloc_and_load_rr_indexed_data(const RRGraphView& rr_graph, const char* echo_file_name); std::vector find_ortho_cost_index(const RRGraphView& rr_graph, - const std::vector segment_inf_x, - const std::vector segment_inf_y, + const std::vector& segment_inf_x, + const std::vector& segment_inf_y, e_parallel_axis parallel_axis); diff --git a/libs/librrgraph/src/utils/describe_rr_node.cpp b/libs/librrgraph/src/utils/describe_rr_node.cpp index 3c00748f6d..1f026d39a9 100644 --- a/libs/librrgraph/src/utils/describe_rr_node.cpp +++ b/libs/librrgraph/src/utils/describe_rr_node.cpp @@ -10,9 +10,10 @@ std::string describe_rr_node(const RRGraphView& rr_graph, RRNodeId inode, bool is_flat) { + const e_rr_type node_type = rr_graph.node_type(inode); std::string msg = vtr::string_fmt("RR node: %d", inode); - if (rr_graph.node_type(inode) == e_rr_type::CHANX || rr_graph.node_type(inode) == e_rr_type::CHANY) { - auto cost_index = rr_graph.node_cost_index(inode); + if (node_type == e_rr_type::CHANX || node_type == e_rr_type::CHANY || node_type == e_rr_type::CHANZ) { + RRIndexedDataId cost_index = rr_graph.node_cost_index(inode); int seg_index = rr_indexed_data[cost_index].seg_index; std::string rr_node_direction_string = rr_graph.node_direction_string(inode); @@ -26,10 +27,10 @@ std::string describe_rr_node(const RRGraphView& rr_graph, rr_graph.node_track_num(inode), seg_index); } - } else if (rr_graph.node_type(inode) == e_rr_type::IPIN || rr_graph.node_type(inode) == e_rr_type::OPIN) { - auto type = grid.get_physical_type({rr_graph.node_xlow(inode), - rr_graph.node_ylow(inode), - rr_graph.node_layer(inode)}); + } else if (node_type == e_rr_type::IPIN || node_type == e_rr_type::OPIN) { + t_physical_tile_type_ptr type = grid.get_physical_type({rr_graph.node_xlow(inode), + rr_graph.node_ylow(inode), + rr_graph.node_layer(inode)}); std::string pin_name = block_type_pin_index_to_name(type, rr_graph.node_pin_num(inode), is_flat); @@ -37,7 +38,7 @@ std::string describe_rr_node(const RRGraphView& rr_graph, rr_graph.node_pin_num(inode), pin_name.c_str()); } else { - VTR_ASSERT(rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK); + VTR_ASSERT(node_type == e_rr_type::SOURCE || node_type == e_rr_type::SINK); msg += vtr::string_fmt(" class: %d", rr_graph.node_class_num(inode)); } diff --git a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp index e0976620c8..192f4e331c 100644 --- a/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp +++ b/libs/libvtrcapnproto/gen/rr_graph_uxsdcxx.capnp @@ -2,11 +2,11 @@ # https://github.com/duck2/uxsdcxx # Modify only if your build process doesn't involve regenerating this file. # -# Cmdline: uxsdcxx/uxsdcap.py /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd -# Input file: /home/smahmoudi/vtr-verilog-to-routing/libs/librrgraph/src/io/rr_graph.xsd -# md5sum of input file: dcf32619cae0c49d168a2575bdb00896 +# Cmdline: uxsdcxx/uxsdcap.py /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd +# Input file: /home/soheil/vpr_repos/libs/librrgraph/src/io/rr_graph.xsd +# md5sum of input file: 5d51b89242fe6e463629ac43a72e4606 -@0xbc43d9d3589ccc58; +@0x8fe58c48975cfaf0; using Cxx = import "/capnp/c++.capnp"; $Cxx.namespace("ucap"); @@ -36,10 +36,11 @@ enum NodeType { uxsdInvalid @0; chanx @1; chany @2; - source @3; - sink @4; - opin @5; - ipin @6; + chanz @3; + source @4; + sink @5; + opin @6; + ipin @7; } enum NodeDirection { diff --git a/vpr/src/base/read_route.cpp b/vpr/src/base/read_route.cpp index 28c15debac..f6fbf93d9b 100644 --- a/vpr/src/base/read_route.cpp +++ b/vpr/src/base/read_route.cpp @@ -563,9 +563,9 @@ void print_route(const Netlist<>& net_list, auto& route_ctx = g_vpr_ctx.mutable_routing(); if (route_ctx.route_trees.empty()) - return; //Only if routing exists + return; // Only if routing exists - for (auto net_id : net_list.nets()) { + for (ParentNetId net_id : net_list.nets()) { if (!net_list.net_is_ignored(net_id)) { fprintf(fp, "\n\nNet %zu (%s)\n\n", size_t(net_id), net_list.net_name(net_id).c_str()); if (net_list.net_sinks(net_id).size() == false) { @@ -587,8 +587,8 @@ void print_route(const Netlist<>& net_list, fprintf(fp, "Node:\t%zu\t%6s (%d,%d,%d) ", size_t(inode), rr_graph.node_type_string(inode), ilow, jlow, layer_num); - if ((ilow != rr_graph.node_xhigh(inode)) - || (jlow != rr_graph.node_yhigh(inode))) + if (ilow != rr_graph.node_xhigh(inode) + || jlow != rr_graph.node_yhigh(inode)) fprintf(fp, "to (%d,%d,%d) ", rr_graph.node_xhigh(inode), rr_graph.node_yhigh(inode), layer_num); @@ -600,13 +600,14 @@ void print_route(const Netlist<>& net_list, if (physical_tile->is_io()) { fprintf(fp, " Pad: "); - } else { /* IO Pad. */ + } else { // IO Pad fprintf(fp, " Pin: "); } break; case e_rr_type::CHANX: case e_rr_type::CHANY: + case e_rr_type::CHANZ: fprintf(fp, " Track: "); break; @@ -614,7 +615,7 @@ void print_route(const Netlist<>& net_list, case e_rr_type::SINK: if (physical_tile->is_io()) { fprintf(fp, " Pad: "); - } else { /* IO Pad. */ + } else { // IO Pad fprintf(fp, " Class: "); } break; diff --git a/vpr/src/place/net_cost_handler.cpp b/vpr/src/place/net_cost_handler.cpp index cdc9e756f2..6282a3e872 100644 --- a/vpr/src/place/net_cost_handler.cpp +++ b/vpr/src/place/net_cost_handler.cpp @@ -20,8 +20,6 @@ * To get a delay estimation of a connection (from a source to a sink), first, dx and dy between these two points should be calculated, * and these two numbers are the indices to access this 2D array. By default, the placement delay model is created by iterating over the router lookahead * to get the minimum cost for each dx and dy. - * - * @date July 12, 2024 */ #include "net_cost_handler.h" diff --git a/vpr/src/route/check_route.cpp b/vpr/src/route/check_route.cpp index fa159289e2..85ca86d0a9 100644 --- a/vpr/src/route/check_route.cpp +++ b/vpr/src/route/check_route.cpp @@ -33,8 +33,22 @@ static void check_sink(const Netlist<>& net_list, bool* pin_done); static void check_switch(const RouteTreeNode& rt_node, size_t num_switch); + +/** + * @brief Checks if two RR nodes are physically adjacent and legally connected. + * + * Verifies whether `to_node` is reachable from `from_node` based on spatial proximity and RR node types. + * + * Special cases: + * - Direct OPIN to IPIN connections are allowed even if not physically adjacent (e.g., carry chains). + * - In flat routing, intra-cluster OPIN/IPIN connections are allowed. + * + * @param from_node The source RR node. + * @param to_node The destination RR node. + * @param is_flat Whether routing is flat (affects intra-cluster pin checks). + * @return true if nodes are legally adjacent, false otherwise. + */ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat); -static int chanx_chany_adjacent(RRNodeId chanx_node, RRNodeId chany_node); static void check_locally_used_clb_opins(const t_clb_opins_used& clb_opins_used_locally, enum e_route_type route_type, @@ -70,6 +84,12 @@ static void check_net_for_stubs(const Netlist<>& net_list, ParentNetId net, bool is_flat); +/** + * @brief Returns true if the given CHANX or CHANY node is adjacent to the given CHANZ node. + * @note Only performs geometric adjacency check; does not validate routing connectivity. + */ +static bool chanxy_chanz_adjacent(RRNodeId chanxy_node, RRNodeId chanz_node); + /************************ Subroutine definitions ****************************/ void check_route(const Netlist<>& net_list, @@ -140,7 +160,7 @@ void check_route(const Netlist<>& net_list, /* Check the rest of the net */ size_t num_sinks = 0; - for (auto& rt_node : route_ctx.route_trees[net_id].value().all_nodes()) { + for (const RouteTreeNode& rt_node : route_ctx.route_trees[net_id].value().all_nodes()) { RRNodeId inode = rt_node.inode; int net_pin_index = rt_node.net_pin_index; check_node_and_range(inode, route_type, is_flat); @@ -274,17 +294,10 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { * Special case: direct OPIN to IPIN connections need not be adjacent. These * represent specially-crafted connections such as carry-chains or more advanced * blocks where adjacency is overridden by the architect */ - - int from_layer, from_xlow, from_ylow, to_layer, to_xlow, to_ylow, from_ptc, to_ptc, iclass; - int num_adj, to_xhigh, to_yhigh, from_xhigh, from_yhigh; - bool reached; - e_rr_type from_type, to_type; - t_physical_tile_type_ptr from_grid_type, to_grid_type; - auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - reached = false; + bool reached = false; for (t_edge_size iconn = 0; iconn < rr_graph.num_edges(RRNodeId(from_node)); iconn++) { if (size_t(rr_graph.edge_sink_node(from_node, iconn)) == size_t(to_node)) { @@ -293,31 +306,32 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { } } - if (!reached) - return (false); + if (!reached) { + return false; + } /* Now we know the rr graph says these two nodes are adjacent. Double * * check that this makes sense, to verify the rr graph. */ VTR_ASSERT(reached); - num_adj = 0; + int num_adj = 0; auto from_rr = RRNodeId(from_node); auto to_rr = RRNodeId(to_node); - from_type = rr_graph.node_type(from_rr); - from_layer = rr_graph.node_layer(from_rr); - from_xlow = rr_graph.node_xlow(from_rr); - from_ylow = rr_graph.node_ylow(from_rr); - from_xhigh = rr_graph.node_xhigh(from_rr); - from_yhigh = rr_graph.node_yhigh(from_rr); - from_ptc = rr_graph.node_ptc_num(from_rr); - to_type = rr_graph.node_type(to_rr); - to_layer = rr_graph.node_layer(to_rr); - to_xlow = rr_graph.node_xlow(to_rr); - to_ylow = rr_graph.node_ylow(to_rr); - to_xhigh = rr_graph.node_xhigh(to_rr); - to_yhigh = rr_graph.node_yhigh(to_rr); - to_ptc = rr_graph.node_ptc_num(to_rr); + e_rr_type from_type = rr_graph.node_type(from_rr); + int from_layer = rr_graph.node_layer(from_rr); + int from_xlow = rr_graph.node_xlow(from_rr); + int from_ylow = rr_graph.node_ylow(from_rr); + int from_xhigh = rr_graph.node_xhigh(from_rr); + int from_yhigh = rr_graph.node_yhigh(from_rr); + int from_ptc = rr_graph.node_ptc_num(from_rr); + e_rr_type to_type = rr_graph.node_type(to_rr); + int to_layer = rr_graph.node_layer(to_rr); + int to_xlow = rr_graph.node_xlow(to_rr); + int to_ylow = rr_graph.node_ylow(to_rr); + int to_xhigh = rr_graph.node_xhigh(to_rr); + int to_yhigh = rr_graph.node_yhigh(to_rr); + int to_ptc = rr_graph.node_ptc_num(to_rr); // If to_node is a SINK, it could be anywhere within its containing device grid tile, and it is reasonable for // any input pins or within-cluster pins to reach it. Hence, treat its size as that of its containing tile. @@ -330,6 +344,8 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { to_yhigh = tile_bb.ymax(); } + t_physical_tile_type_ptr from_grid_type, to_grid_type; + // Layer numbers are should not be more than one layer apart for connected nodes VTR_ASSERT(abs(from_layer - to_layer) <= 1); switch (from_type) { @@ -337,15 +353,12 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { VTR_ASSERT(to_type == e_rr_type::OPIN); //The OPIN should be contained within the bounding box of it's connected source - if (from_xlow <= to_xlow - && from_ylow <= to_ylow - && from_xhigh >= to_xhigh - && from_yhigh >= to_yhigh) { + if (from_xlow <= to_xlow && from_ylow <= to_ylow && from_xhigh >= to_xhigh && from_yhigh >= to_yhigh) { from_grid_type = device_ctx.grid.get_physical_type({from_xlow, from_ylow, from_layer}); to_grid_type = device_ctx.grid.get_physical_type({to_xlow, to_ylow, to_layer}); VTR_ASSERT(from_grid_type == to_grid_type); - iclass = get_class_num_from_pin_physical_num(to_grid_type, to_ptc); + int iclass = get_class_num_from_pin_physical_num(to_grid_type, to_ptc); if (iclass == from_ptc) num_adj++; } @@ -386,7 +399,7 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { from_grid_type = device_ctx.grid.get_physical_type({from_xlow, from_ylow, from_layer}); to_grid_type = device_ctx.grid.get_physical_type({to_xlow, to_ylow, to_layer}); VTR_ASSERT(from_grid_type == to_grid_type); - iclass = get_class_num_from_pin_physical_num(from_grid_type, from_ptc); + int iclass = get_class_num_from_pin_physical_num(from_grid_type, from_ptc); if (iclass == to_ptc) num_adj++; } @@ -431,7 +444,9 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { /* UDSD Modification by WMF End */ } } else if (to_type == e_rr_type::CHANY) { - num_adj += chanx_chany_adjacent(from_node, to_node); + num_adj += rr_graph.nodes_are_adjacent(from_node, to_node); + } else if (to_type == e_rr_type::CHANZ) { + num_adj += chanxy_chanz_adjacent(from_node, to_node); } else { VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "in check_adjacent: %d and %d are not adjacent", from_node, to_node); @@ -463,14 +478,34 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { /* UDSD Modification by WMF End */ } } else if (to_type == e_rr_type::CHANX) { - num_adj += chanx_chany_adjacent(to_node, from_node); + num_adj += rr_graph.nodes_are_adjacent(to_node, from_node); + } else if (to_type == e_rr_type::CHANZ) { + num_adj += chanxy_chanz_adjacent(from_node, to_node); + } else { + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, + "in check_adjacent: %d and %d are not adjacent", from_node, to_node); + } + break; + + case e_rr_type::CHANZ: + if (to_type == e_rr_type::CHANX || to_type == e_rr_type::CHANY) { + num_adj += chanxy_chanz_adjacent(to_node, from_node); + } else if (to_type == e_rr_type::CHANZ) { + if (from_xlow == to_xlow && from_xhigh == to_xhigh && from_ylow == to_ylow && from_yhigh == to_yhigh && std::abs(from_layer - to_layer) == 1) { + num_adj++; + } } else { + std::cout << describe_rr_node(device_ctx.rr_graph, device_ctx.grid, device_ctx.rr_indexed_data, from_node, is_flat) << std::endl; + std::cout << describe_rr_node(device_ctx.rr_graph, device_ctx.grid, device_ctx.rr_indexed_data, to_node, is_flat) << std::endl; + VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "in check_adjacent: %d and %d are not adjacent", from_node, to_node); } break; default: + VPR_ERROR(VPR_ERROR_ROUTE, + "in check_adjacent: Unknown RR type.\n"); break; } @@ -484,20 +519,6 @@ static bool check_adjacent(RRNodeId from_node, RRNodeId to_node, bool is_flat) { return false; //Should not reach here once thrown } -static int chanx_chany_adjacent(RRNodeId chanx_node, RRNodeId chany_node) { - /* Returns 1 if the specified CHANX and CHANY nodes are adjacent, 0 * - * otherwise. */ - - auto& device_ctx = g_vpr_ctx.device(); - const auto& rr_graph = device_ctx.rr_graph; - - if (rr_graph.nodes_are_adjacent(chanx_node, chany_node)) { - return (1); - } else { - return (0); - } -} - void recompute_occupancy_from_scratch(const Netlist<>& net_list, bool is_flat) { /* * This routine updates the occ field in the route_ctx.rr_node_route_inf structure @@ -866,6 +887,30 @@ void check_net_for_stubs(const Netlist<>& net_list, } } +static bool chanxy_chanz_adjacent(RRNodeId chanxy_node, RRNodeId chanz_node) { + const RRGraphView& rr_graph = g_vpr_ctx.device().rr_graph; + VTR_ASSERT(rr_graph.node_type(chanz_node) == e_rr_type::CHANZ); + e_rr_type chanxy_node_type = rr_graph.node_type(chanxy_node); + VTR_ASSERT(chanxy_node_type == e_rr_type::CHANX || chanxy_node_type == e_rr_type::CHANY); + + int chanz_x = rr_graph.node_xlow(chanz_node); + int chanz_y = rr_graph.node_ylow(chanz_node); + VTR_ASSERT_SAFE(chanz_x == rr_graph.node_xhigh(chanz_node)); + VTR_ASSERT_SAFE(chanz_y == rr_graph.node_yhigh(chanz_node)); + + if (chanxy_node_type == e_rr_type::CHANX) { + // CHANX runs horizontally, so y must match and x must overlap + return chanz_y == rr_graph.node_ylow(chanxy_node) + && chanz_x >= rr_graph.node_xlow(chanxy_node) - 1 + && chanz_x <= rr_graph.node_xhigh(chanxy_node) + 1; + } else { + // CHANY runs vertically, so x must match and y must overlap + return chanz_x == rr_graph.node_xlow(chanxy_node) + && chanz_y >= rr_graph.node_ylow(chanxy_node) - 1 + && chanz_y <= rr_graph.node_yhigh(chanxy_node) + 1; + } +} + bool StubFinder::CheckNet(ParentNetId net) { auto& route_ctx = g_vpr_ctx.mutable_routing(); stub_nodes_.clear(); diff --git a/vpr/src/route/router_lookahead/router_lookahead_map.cpp b/vpr/src/route/router_lookahead/router_lookahead_map.cpp index 2f49b43961..539be31e37 100644 --- a/vpr/src/route/router_lookahead/router_lookahead_map.cpp +++ b/vpr/src/route/router_lookahead/router_lookahead_map.cpp @@ -175,13 +175,14 @@ float MapLookahead::get_expected_cost(RRNodeId current_node, RRNodeId target_nod if (is_flat_) { return get_expected_cost_flat_router(current_node, target_node, params, R_upstream); } else { - if (from_rr_type == e_rr_type::CHANX || from_rr_type == e_rr_type::CHANY || from_rr_type == e_rr_type::SOURCE || from_rr_type == e_rr_type::OPIN) { + if (from_rr_type == e_rr_type::CHANX || from_rr_type == e_rr_type::CHANY || from_rr_type == e_rr_type::CHANZ + || from_rr_type == e_rr_type::SOURCE || from_rr_type == e_rr_type::OPIN) { // Get the total cost using the combined delay and congestion costs auto [delay_cost, cong_cost] = get_expected_delay_and_cong(current_node, target_node, params, R_upstream); return delay_cost + cong_cost; - } else if (from_rr_type == e_rr_type::IPIN) { /* Change if you're allowing route-throughs */ + } else if (from_rr_type == e_rr_type::IPIN) { // Change if you're allowing route-throughs return (device_ctx.rr_indexed_data[RRIndexedDataId(SINK_COST_INDEX)].base_cost); - } else { /* Change this if you want to investigate route-throughs */ + } else { // Change this if you want to investigate route-throughs return (0.); } } diff --git a/vpr/src/route/rr_graph_generation/rr_graph.cpp b/vpr/src/route/rr_graph_generation/rr_graph.cpp index b116816210..c67a1b4163 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph.cpp @@ -256,15 +256,6 @@ static void add_pins_rr_graph(RRGraphBuilder& rr_graph_builder, * the delay of these edges is not necessarily zero. If the primitive block which a SINK/SRC belongs to is a combinational block, the delay of * the edge is equal to the pin delay. This is done in order to make the router lookahead aware of the different IPIN delays. In this way, more critical * nets are routed to the pins with less delay. - * @param rr_graph_builder - * @param arch_sw_inf_map - * @param class_num_vec - * @param layer - * @param i - * @param j - * @param rr_edges_to_create - * @param delayless_switch - * @param physical_type_ptr */ static void connect_tile_src_sink_to_pins(RRGraphBuilder& rr_graph_builder, std::map& arch_sw_inf_map, @@ -436,17 +427,6 @@ static void add_pb_edges(RRGraphBuilder& rr_graph_builder, /** * Edges going in/out of collapse nodes are not added by the normal routine. This function add those edges - * @param rr_graph_builder - * @param rr_edges_to_create - * @param physical_type - * @param logical_block - * @param cluster_pins - * @param nodes_to_collapse - * @param R_minW_nmos - * @param R_minW_pmos - * @param layer - * @param i - * @param j * @return Number of the collapsed nodes */ static int add_edges_for_collapsed_nodes(RRGraphBuilder& rr_graph_builder, @@ -462,23 +442,7 @@ static int add_edges_for_collapsed_nodes(RRGraphBuilder& rr_graph_builder, int j, bool load_rr_graph); /** - * @note This function is used to add the fan-in edges of the given chain node to the chain's sink with the modified delay - * @param rr_graph_builder - * @param rr_edges_to_create - * @param num_collapsed_pins - * @param physical_type - * @param logical_block - * @param nodes_to_collapse - * @param cluster_pins - * @param chain_pins - * @param R_minW_nmos - * @param R_minW_pmos - * @param chain_idx - * @param node_idx - * @param sink_pin_num - * @param layer - * @param i - * @param j + * @brief This function is used to add the fan-in edges of the given chain node to the chain's sink with the modified delay */ static void add_chain_node_fan_in_edges(RRGraphBuilder& rr_graph_builder, t_rr_edge_info_set& rr_edges_to_create, @@ -498,14 +462,7 @@ static void add_chain_node_fan_in_edges(RRGraphBuilder& rr_graph_builder, bool load_rr_graph); /** - * @note Return the minimum delay to the chain's sink since a pin outside of the chain may have connections to multiple pins inside the chain. - * @param physical_type - * @param logical_block - * @param cluster_pins - * @param chain_pins - * @param pin_physical_num - * @param chain_sink_pin - * @return + * @brief Return the minimum delay to the chain's sink since a pin outside of the chain may have connections to multiple pins inside the chain. */ static float get_min_delay_to_chain(t_physical_tile_type_ptr physical_type, t_logical_block_type_ptr logical_block, @@ -611,26 +568,12 @@ static RRNodeId pick_best_direct_connect_target_rr_node(const RRGraphView& rr_gr RRNodeId from_rr, const std::vector& candidate_rr_nodes); -/** - * - * @param cluster_pins - * @param physical_type - * @param logical_block - * @param is_flat - * @return A structure containing - */ static t_cluster_pin_chain get_cluster_directly_connected_nodes(const std::vector& cluster_pins, t_physical_tile_type_ptr physical_type, t_logical_block_type_ptr logical_block, bool is_flat); /** - * - * @param physical_type - * @param logical_block - * @param pins_in_cluster - * @param pin_physical_num - * @param is_flat * @return A chain of nodes starting from pin_physcical_num. All of the pins in this chain has a fan-out of 1 */ static std::vector get_directly_connected_nodes(t_physical_tile_type_ptr physical_type, @@ -661,11 +604,6 @@ static int get_chain_idx(const std::vector& pin_idx_vec, const std::vector< /** * If pin chain is a part of a chain already added to all_chains, add the new parts to the corresponding chain. Otherwise, add pin_chain as a new chain to all_chains. - * @param pin_chain - * @param chain_idx - * @param pin_index_vec - * @param all_chains - * @param is_new_chain */ static void add_pin_chain(const std::vector& pin_chain, int chain_idx, @@ -945,27 +883,27 @@ static void add_intra_tile_edges_rr_graph(RRGraphBuilder& rr_graph_builder, int layer, int i, int j) { - auto pin_num_vec = get_flat_tile_pins(physical_tile); + std::vector pin_num_vec = get_flat_tile_pins(physical_tile); for (int pin_physical_num : pin_num_vec) { if (is_pin_on_tile(physical_tile, pin_physical_num)) { continue; } - auto pin_rr_node_id = get_pin_rr_node_id(rr_graph_builder.node_lookup(), - physical_tile, - layer, - i, - j, - pin_physical_num); + RRNodeId pin_rr_node_id = get_pin_rr_node_id(rr_graph_builder.node_lookup(), + physical_tile, + layer, + i, + j, + pin_physical_num); VTR_ASSERT(pin_rr_node_id != RRNodeId::INVALID()); - auto logical_block = get_logical_block_from_pin_physical_num(physical_tile, pin_physical_num); - auto driving_pins = get_physical_pin_src_pins(physical_tile, logical_block, pin_physical_num); - for (auto driving_pin : driving_pins) { - auto driving_pin_node_id = get_pin_rr_node_id(rr_graph_builder.node_lookup(), - physical_tile, - layer, - i, - j, - driving_pin); + t_logical_block_type_ptr logical_block = get_logical_block_from_pin_physical_num(physical_tile, pin_physical_num); + std::vector driving_pins = get_physical_pin_src_pins(physical_tile, logical_block, pin_physical_num); + for (int driving_pin : driving_pins) { + RRNodeId driving_pin_node_id = get_pin_rr_node_id(rr_graph_builder.node_lookup(), + physical_tile, + layer, + i, + j, + driving_pin); VTR_ASSERT(driving_pin_node_id != RRNodeId::INVALID()); int sw_idx = get_edge_sw_arch_idx(physical_tile, @@ -980,12 +918,10 @@ static void add_intra_tile_edges_rr_graph(RRGraphBuilder& rr_graph_builder, } void print_rr_graph_stats() { - auto& device_ctx = g_vpr_ctx.device(); - - const auto& rr_graph = device_ctx.rr_graph; + const auto& rr_graph = g_vpr_ctx.device().rr_graph; size_t num_rr_edges = 0; - for (auto& rr_node : rr_graph.rr_nodes()) { + for (const t_rr_node& rr_node : rr_graph.rr_nodes()) { num_rr_edges += rr_graph.edges(rr_node.id()).size(); } @@ -1339,7 +1275,7 @@ static void build_rr_graph(e_graph_type graph_type, // Keep how many nodes each switchblock requires for each x,y location vtr::NdMatrix extra_nodes_per_switchblock = get_number_track_to_track_inter_die_conn(sb_conn_map, custom_3d_sb_fanin_fanout, device_ctx.rr_graph_builder); // Allocate new nodes in each switchblocks - alloc_and_load_inter_die_rr_node_indices(device_ctx.rr_graph_builder, nodes_per_chan, grid, extra_nodes_per_switchblock, &num_rr_nodes); + alloc_and_load_inter_die_rr_node_indices(device_ctx.rr_graph_builder, grid, extra_nodes_per_switchblock, &num_rr_nodes); device_ctx.rr_graph_builder.resize_nodes(num_rr_nodes); } @@ -3136,7 +3072,7 @@ static void build_rr_chan(RRGraphBuilder& rr_graph_builder, const auto& device_ctx = g_vpr_ctx.device(); auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); - //Initally assumes CHANX + // Initially assumes CHANX int seg_coord = x_coord; //The absolute coordinate of this segment within the channel int chan_coord = y_coord; //The absolute coordinate of this channel within the device int seg_dimension = device_ctx.grid.width() - 2; //-2 for no perim channels @@ -3310,42 +3246,41 @@ static void build_inter_die_custom_sb_rr_chan(RRGraphBuilder& rr_graph_builder, auto& mutable_device_ctx = g_vpr_ctx.mutable_device(); const t_chan_seg_details* seg_details = chan_details_x[x_coord][y_coord].data(); - /* 3D connections within the switch blocks use some extra length-0 CHANX node to allow a single 3D connection to be driven - * by multiple tracks in the source layer, and drives multiple tracks in the destination layer. - * These nodes have already been added to RRGraph builder, this function will go through all added nodes - * with specific location (layer, x_coord, y_coord) and sets their attributes. - * - * The extra length-0 nodes have the following attributes to make them distinguishable form normal chanx wires (e.g., length-4): - * 1) type: CHANX (could have used either CHANX or CHANY, we used CHANX) - * 2) ptc_num: [max_chan_width : max_chan_width + num_of_3d_connections - 1] - * 3) length: 0 - * 4) xhigh=xlow, yhigh=ylow - * 5) directionality: NONE (neither incremental nor decremental in 2D space) - */ + // 3D connections within the switch blocks use some CHANZ nodes to allow a single 3D connection to be driven + // by multiple tracks in the source layer, and drives multiple tracks in the destination layer. + // These nodes have already been added to RRGraph builder, this function will go through all added nodes + // with specific location (layer, x_coord, y_coord) and sets their attributes. + + // These nodes have the following attributes: + // 1) type: CHANZ + // 2) ptc_num: [0:num_of_3d_connections - 1] + // 3) xhigh=xlow, yhigh=ylow + // 4) directionality: NONE (neither incremental nor decremental in 2D space) + const int start_track = nodes_per_chan.max; - int offset = 0; - while (true) { // Going through allocated nodes until no nodes are found within the RRGraph builder - RRNodeId node = rr_graph_builder.node_lookup().find_node(layer, x_coord, y_coord, e_rr_type::CHANX, start_track + offset); - if (node) { - rr_graph_builder.set_node_layer(node, layer); - rr_graph_builder.set_node_coordinates(node, x_coord, y_coord, x_coord, y_coord); - rr_graph_builder.set_node_cost_index(node, RRIndexedDataId( - const_index_offset + seg_details[start_track - 1].index())); - rr_graph_builder.set_node_capacity(node, 1); /* GLOBAL routing handled elsewhere */ - float R = 0; - float C = 0; - rr_graph_builder.set_node_rc_index(node, NodeRCIndex( - find_create_rr_rc_data(R, C, mutable_device_ctx.rr_rc_data))); - - rr_graph_builder.set_node_type(node, e_rr_type::CHANX); - rr_graph_builder.set_node_track_num(node, start_track + offset); - rr_graph_builder.set_node_direction(node, Direction::NONE); - - offset++; - } else { + // Go through allocated nodes until no nodes are found within the RRGraph builder + for (int track_num = 0; /*no condition*/; track_num++) { + // Try to find a node with the current track_num + RRNodeId node = rr_graph_builder.node_lookup().find_node(layer, x_coord, y_coord, e_rr_type::CHANZ, track_num); + + // If the track can't be found, it means we have already processed all tracks + if (!node.is_valid()) { break; } + + rr_graph_builder.set_node_layer(node, layer); + rr_graph_builder.set_node_coordinates(node, x_coord, y_coord, x_coord, y_coord); + // TODO: the index doesn't make any sense. We need to an RRIndexedDataId for CHANZ nodes + rr_graph_builder.set_node_cost_index(node, RRIndexedDataId(const_index_offset + seg_details[start_track - 1].index())); + rr_graph_builder.set_node_capacity(node, 1); // GLOBAL routing handled elsewhere + float R = 0; + float C = 0; + rr_graph_builder.set_node_rc_index(node, NodeRCIndex(find_create_rr_rc_data(R, C, mutable_device_ctx.rr_rc_data))); + + rr_graph_builder.set_node_type(node, e_rr_type::CHANZ); + rr_graph_builder.set_node_track_num(node, track_num); + rr_graph_builder.set_node_direction(node, Direction::NONE); } } diff --git a/vpr/src/route/rr_graph_generation/rr_graph2.cpp b/vpr/src/route/rr_graph_generation/rr_graph2.cpp index 7cef8d589a..a8b65050a9 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph2.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph2.cpp @@ -64,7 +64,6 @@ static int get_unidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, * @param tile_x x-coordinate of the switch block * @param tile_y y-coordinate of the switch block * @param layer layer-coordinate of the switch block - * @param max_chan_width number of available tracks within the channel * @param from_side switch block connection source side * @param from_wire switch block connection source wire index (ptc_num) within the channel * @param from_rr_node switch block connection source wire RRNode index @@ -81,7 +80,6 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, const int tile_x, const int tile_y, const int layer, - const int max_chan_width, const e_side from_side, const int from_wire, RRNodeId from_rr_node, @@ -103,7 +101,6 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, * * @param rr_graph_builder RRGraphBuilder data structure which allows data modification on a routing resource graph * @param layer the channel segment layer-coordinate - * @param max_chan_width number of tracks per channel * @param from_track source track index (ptc_num) within the channel * @param to_chan destination coordinate (x or y) based on chan type * @param to_seg destination segment coordinate (x or y) based on chan type @@ -120,7 +117,6 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, const int layer, - const int max_chan_width, const int from_track, const int to_chan, const int to_seg, @@ -1371,7 +1367,7 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, if (sb_seg < end_sb_seg) { if (custom_switch_block) { if (Direction::DEC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { - num_conn += get_track_to_chan_seg(rr_graph_builder, layer, max_chan_width, from_track, to_chan, to_seg, + num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, to_type, from_side_a, to_side, switch_override, custom_3d_sb_fanin_fanout, delayless_switch, *sb_conn_map, num_of_3d_conns_custom_SB, from_rr_node, rr_edges_to_create, des_3d_rr_edges_to_create); @@ -1409,7 +1405,7 @@ int get_track_to_tracks(RRGraphBuilder& rr_graph_builder, if (sb_seg > start_sb_seg) { if (custom_switch_block) { if (Direction::INC == from_seg_details[from_track].direction() || BI_DIRECTIONAL == directionality) { - num_conn += get_track_to_chan_seg(rr_graph_builder, layer, max_chan_width, from_track, to_chan, to_seg, + num_conn += get_track_to_chan_seg(rr_graph_builder, layer, from_track, to_chan, to_seg, to_type, from_side_b, to_side, switch_override, custom_3d_sb_fanin_fanout, delayless_switch, *sb_conn_map, num_of_3d_conns_custom_SB, from_rr_node, rr_edges_to_create, des_3d_rr_edges_to_create); @@ -1515,7 +1511,6 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, const int tile_x, const int tile_y, const int layer, - const int max_chan_width, const e_side from_side, const int from_wire, RRNodeId from_rr_node, @@ -1585,20 +1580,20 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, } // In order to connect two tracks in different layers, we need to follow these three steps: - // 1) connect "from_tracks" to extra "chanx" node in the same switch blocks - // 2) connect extra "chanx" node located in from_layer to another extra "chanx" node located in to_layer - // 3) connect "chanx" node located in to_layer to "to_track" + // 1) connect "from_tracks" to CHANZ node in the same switch block + // 2) connect CHANZ node located in from_layer to another CHANZ node located in to_layer + // 3) connect CHANZ node located in to_layer to "to_track" // +-------------+ +-------------+ +--------------+ +--------------+ - // | from_wire | -----> | extra_chanx | ------> | extra_chanx | ------> | to_wire | + // | from_wire | -----> | CHANZ node | ------> | CHANZ node | ------> | to_wire | // | (src_layer) | | (src_layer) | | (dest_layer) | | (dest_layer) | // +-------------+ +-------------+ +--------------+ +--------------+ - int offset = num_of_3d_conns_custom_SB[tile_x][tile_y] / custom_3d_sb_fanin_fanout; - RRNodeId track_to_chanx_node = rr_graph_builder.node_lookup().find_node(layer, tile_x, tile_y, e_rr_type::CHANX, max_chan_width + offset); - RRNodeId diff_layer_chanx_node = rr_graph_builder.node_lookup().find_node(to_layer, tile_x, tile_y, e_rr_type::CHANX, max_chan_width + offset); - RRNodeId chanx_to_track_node = rr_graph_builder.node_lookup().find_node(to_layer, to_x, to_y, to_chan_type, to_wire); + const int chanz_track_num = num_of_3d_conns_custom_SB[tile_x][tile_y] / custom_3d_sb_fanin_fanout; + RRNodeId src_chanz_node = rr_graph_builder.node_lookup().find_node(layer, tile_x, tile_y, e_rr_type::CHANZ, chanz_track_num); + RRNodeId sink_chanz_node = rr_graph_builder.node_lookup().find_node(to_layer, tile_x, tile_y, e_rr_type::CHANZ, chanz_track_num); + RRNodeId sink_track_node = rr_graph_builder.node_lookup().find_node(to_layer, to_x, to_y, to_chan_type, to_wire); - if (!track_to_chanx_node || !diff_layer_chanx_node || !chanx_to_track_node) { + if (!src_chanz_node || !sink_chanz_node || !sink_track_node) { continue; } @@ -1608,17 +1603,17 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, } // Add edge between source node at from layer to intermediate node - rr_edges_to_create.emplace_back(from_rr_node, track_to_chanx_node, delayless_switch, false); + rr_edges_to_create.emplace_back(from_rr_node, src_chanz_node, delayless_switch, false); ++edge_count; // Add edge between intermediate node to destination node at to layer // might add the same edge more than once, but redundant edges will be removed before updating the RR graph - des_3d_rr_edges_to_create.emplace_back(diff_layer_chanx_node, chanx_to_track_node, src_switch_betwen_layers, false); + des_3d_rr_edges_to_create.emplace_back(sink_chanz_node, sink_track_node, src_switch_betwen_layers, false); ++edge_count; // We only add the following edge between intermediate nodes once for the first 3D connection for each pair of intermediate nodes if (num_of_3d_conns_custom_SB[tile_x][tile_y] % custom_3d_sb_fanin_fanout == 0) { - rr_edges_to_create.emplace_back(track_to_chanx_node, diff_layer_chanx_node, delayless_switch, false); + rr_edges_to_create.emplace_back(src_chanz_node, sink_chanz_node, delayless_switch, false); ++edge_count; } @@ -1630,7 +1625,6 @@ static void get_switchblocks_edges(RRGraphBuilder& rr_graph_builder, static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, const int layer, - const int max_chan_width, const int from_wire, const int to_chan, const int to_seg, @@ -1669,7 +1663,6 @@ static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, tile_x, tile_y, layer, - max_chan_width, from_side, from_wire, from_rr_node, @@ -1692,7 +1685,6 @@ static int get_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, tile_x, tile_y, layer, - max_chan_width, from_side, from_wire, from_rr_node, @@ -1733,7 +1725,7 @@ static int get_unidir_track_to_chan_seg(RRGraphBuilder& rr_graph_builder, int num_labels = 0; std::vector mux_labels; - /* x, y coords for get_rr_node lookups */ + // x, y coords for get_rr_node lookups int to_x = (e_rr_type::CHANX == to_type ? to_seg : to_chan); int to_y = (e_rr_type::CHANX == to_type ? to_chan : to_seg); int sb_x = (e_rr_type::CHANX == to_type ? to_sb : to_chan); diff --git a/vpr/src/route/rr_graph_generation/rr_graph_area.cpp b/vpr/src/route/rr_graph_generation/rr_graph_area.cpp index 784125a437..ec76b5f803 100644 --- a/vpr/src/route/rr_graph_generation/rr_graph_area.cpp +++ b/vpr/src/route/rr_graph_generation/rr_graph_area.cpp @@ -33,7 +33,10 @@ static void count_unidir_routing_transistors(std::vector& segment const float trans_sram_bit, bool is_flat); -static float get_cblock_trans(int* num_inputs_to_cblock, int wire_to_ipin_switch, int max_inputs_to_cblock, float trans_sram_bit); +static float get_cblock_trans(vtr::vector& num_inputs_to_cblock, + int wire_to_ipin_switch, + int max_inputs_to_cblock, + float trans_sram_bit); static float* alloc_and_load_unsharable_switch_trans(int num_switch, float trans_sram_bit, @@ -108,9 +111,7 @@ void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, fl auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - int* num_inputs_to_cblock; /* [0..device_ctx.rr_nodes.size()-1], but all entries not */ - - /* corresponding to IPINs will be 0. */ + vtr::vector num_inputs_to_cblock(rr_graph.num_nodes(), 0); // entries not corresponding to IPINs will be 0 bool* cblock_counted; /* [0..max(device_ctx.grid.width(),device_ctx.grid.height())] -- 0th element unused. */ float* shared_buffer_trans; /* [0..max(device_ctx.grid.width(),device_ctx.grid.height())] */ @@ -145,16 +146,11 @@ void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, fl * wiring C plus the fanout. */ if (INCLUDE_TRACK_BUFFERS) { - trans_track_to_cblock_buf = trans_per_buf(R_minW_nmos / 4., R_minW_nmos, - R_minW_pmos); + trans_track_to_cblock_buf = trans_per_buf(R_minW_nmos / 4., R_minW_nmos, R_minW_pmos); } else { trans_track_to_cblock_buf = 0; } - num_inputs_to_cblock = new int[rr_graph.num_nodes()]; - for (size_t cb = 0; cb < rr_graph.num_nodes(); cb++) - num_inputs_to_cblock[cb] = 0; - maxlen = std::max(device_ctx.grid.width(), device_ctx.grid.height()); cblock_counted = new bool[maxlen]; shared_buffer_trans = new float[maxlen]; @@ -169,7 +165,7 @@ void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, fl sharable_switch_trans = alloc_and_load_sharable_switch_trans(num_switch, R_minW_nmos, R_minW_pmos); - for (const RRNodeId& from_rr_node : device_ctx.rr_graph.nodes()) { + for (const RRNodeId from_rr_node : device_ctx.rr_graph.nodes()) { size_t from_node = (size_t)from_rr_node; from_rr_type = rr_graph.node_type(from_rr_node); @@ -210,9 +206,8 @@ void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, fl break; case e_rr_type::IPIN: - num_inputs_to_cblock[size_t(to_node)]++; - max_inputs_to_cblock = std::max(max_inputs_to_cblock, - num_inputs_to_cblock[size_t(to_node)]); + num_inputs_to_cblock[to_node]++; + max_inputs_to_cblock = std::max(max_inputs_to_cblock, num_inputs_to_cblock[to_node]); iseg = seg_index_of_cblock(rr_graph, from_rr_type, size_t(to_node)); @@ -293,8 +288,6 @@ void count_bidir_routing_transistors(int num_switch, int wire_to_ipin_switch, fl input_cblock_trans = get_cblock_trans(num_inputs_to_cblock, wire_to_ipin_switch, max_inputs_to_cblock, trans_sram_bit); - delete[] num_inputs_to_cblock; - ntrans_sharing += input_cblock_trans; ntrans_no_sharing += input_cblock_trans; @@ -316,18 +309,15 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - bool* cblock_counted; /* [0..max(device_ctx.grid.width(),device_ctx.grid.height())] -- 0th element unused. */ - int* num_inputs_to_cblock; /* [0..device_ctx.rr_nodes.size()-1], but all entries not */ - - /* corresponding to IPINs will be 0. */ + bool* cblock_counted; /* [0..max(device_ctx.grid.width(),device_ctx.grid.height())] -- 0th element unused. */ + vtr::vector num_inputs_to_cblock(rr_graph.num_nodes(), 0); // entries not corresponding to IPINs will be 0 e_rr_type from_rr_type, to_rr_type; int i, j, iseg, iedge, num_edges, maxlen; int max_inputs_to_cblock; float input_cblock_trans; - /* August 2014: - * In a unidirectional architecture all the fanin to a wire segment comes from + /* In a unidirectional architecture all the fanin to a wire segment comes from * a single mux. We should count this mux only once as we look at the outgoing * switches of all rr nodes. Thus we keep track of which muxes we have already * counted via the variable below. */ @@ -361,17 +351,13 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* trans_track_to_cblock_buf = 0; } - num_inputs_to_cblock = new int[rr_graph.num_nodes()]; - for (size_t c = 0; c < rr_graph.num_nodes(); c++) - num_inputs_to_cblock[c] = 0; - maxlen = std::max(device_ctx.grid.width(), device_ctx.grid.height()); cblock_counted = new bool[maxlen]; for (auto k = 0; k < maxlen; k++) cblock_counted[k] = 0; ntrans = 0; - for (const RRNodeId& from_rr_node : device_ctx.rr_graph.nodes()) { + for (const RRNodeId from_rr_node : device_ctx.rr_graph.nodes()) { size_t from_node = size_t(from_rr_node); from_rr_type = rr_graph.node_type(from_rr_node); @@ -395,7 +381,7 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* case e_rr_type::CHANY: if (!chan_node_switch_done[size_t(to_node)]) { int switch_index = rr_graph.edge_switch(RRNodeId(from_node), iedge); - auto switch_type = rr_graph.rr_switch_inf(RRSwitchId(switch_index)).type(); + SwitchType switch_type = rr_graph.rr_switch_inf(RRSwitchId(switch_index)).type(); int fan_in = rr_graph.node_fan_in(to_node); @@ -411,7 +397,7 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* * the rr switches were created from the arch switches */ ntrans += rr_graph.rr_switch_inf(RRSwitchId(switch_index)).buf_size; } else if (switch_type == SwitchType::SHORT) { - ntrans += 0.; //Electrical shorts contribute no transisitor area + ntrans += 0.; //Electrical shorts contribute no transistor area } else if (switch_type == SwitchType::BUFFER) { if (fan_in != 1) { std::string msg = vtr::string_fmt( @@ -434,9 +420,8 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* break; case e_rr_type::IPIN: - num_inputs_to_cblock[size_t(to_node)]++; - max_inputs_to_cblock = std::max(max_inputs_to_cblock, - num_inputs_to_cblock[size_t(to_node)]); + num_inputs_to_cblock[to_node]++; + max_inputs_to_cblock = std::max(max_inputs_to_cblock, num_inputs_to_cblock[to_node]); iseg = seg_index_of_cblock(rr_graph, from_rr_type, size_t(to_node)); if (cblock_counted[iseg] == false) { @@ -448,6 +433,10 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* case e_rr_type::SINK: break; //ignore virtual sinks + case e_rr_type::CHANZ: + // TODO: handle chanz + break; + default: VPR_ERROR(VPR_ERROR_ROUTE, "in count_routing_transistors:\n" @@ -470,9 +459,14 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* cblock_counted[j] = false; } break; + case e_rr_type::OPIN: break; + case e_rr_type::CHANZ: + // TODO: handle chanz + break; + default: break; @@ -485,7 +479,6 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* max_inputs_to_cblock, trans_sram_bit); delete[] cblock_counted; - delete[] num_inputs_to_cblock; ntrans += input_cblock_trans; @@ -494,7 +487,10 @@ void count_unidir_routing_transistors(std::vector& /*segment_inf* VTR_LOG("\tTotal routing area: %#g, per logic tile: %#g\n", ntrans, ntrans / (float)(device_ctx.grid.get_num_layers() * device_ctx.grid.width() * device_ctx.grid.height())); } -static float get_cblock_trans(int* num_inputs_to_cblock, int wire_to_ipin_switch, int max_inputs_to_cblock, float trans_sram_bit) { +static float get_cblock_trans(vtr::vector& num_inputs_to_cblock, + int wire_to_ipin_switch, + int max_inputs_to_cblock, + float trans_sram_bit) { /* Computes the transistors in the input connection block multiplexers and * * the buffers from connection block outputs to the logic block input pins. * * For speed, I precompute the number of transistors in the multiplexers of * @@ -522,8 +518,8 @@ static float get_cblock_trans(int* num_inputs_to_cblock, int wire_to_ipin_switch trans_count = 0.; - for (const RRNodeId& rr_id : device_ctx.rr_graph.nodes()) { - num_inputs = num_inputs_to_cblock[(size_t)rr_id]; + for (const RRNodeId rr_id : device_ctx.rr_graph.nodes()) { + num_inputs = num_inputs_to_cblock[rr_id]; trans_count += trans_per_cblock[num_inputs]; } diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp index eeac71308b..24b4afb145 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.cpp +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.cpp @@ -325,16 +325,15 @@ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, } void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const t_chan_width& nodes_per_chan, const DeviceGrid& grid, const vtr::NdMatrix& extra_nodes_per_switchblock, int* index) { - // In case of multi-die FPGAs, we add extra nodes (could have used either CHANX or CHANY; we chose to use all CHANX) to + // In case of multi-die FPGAs, we add extra nodes of type CHANZ to // support inter-die communication coming from switch blocks (connection between two tracks in different layers) // The extra nodes have the following attribute: - // 1) type = CHANX - // 2) length = 0 (xhigh = xlow, yhigh = ylow) - // 3) ptc = [max_chanx_width:max_chanx_width+number_of_connection-1] + // 1) type = CHANZ + // 2) xhigh == xlow, yhigh == ylow + // 3) ptc = [0:number_of_connection-1] // 4) direction = NONE const auto& device_ctx = g_vpr_ctx.device(); @@ -346,7 +345,7 @@ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, for (size_t y = 0; y < grid.height() - 1; ++y) { for (size_t x = 1; x < grid.width() - 1; ++x) { - // count how many track-to-track connection go from current layer to other layers + // how many track-to-track connection go from current layer to other layers int conn_count = extra_nodes_per_switchblock[x][y]; // skip if no connection is required @@ -355,13 +354,13 @@ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, } // reserve extra nodes for inter-die track-to-track connection - rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANX, conn_count + nodes_per_chan.max); + rr_graph_builder.node_lookup().reserve_nodes(layer, x, y, e_rr_type::CHANZ, conn_count); for (int rr_node_offset = 0; rr_node_offset < conn_count; rr_node_offset++) { - RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset); + RRNodeId inode = rr_graph_builder.node_lookup().find_node(layer, x, y, e_rr_type::CHANZ, rr_node_offset); if (!inode) { inode = RRNodeId(*index); ++(*index); - rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANX, nodes_per_chan.max + rr_node_offset); + rr_graph_builder.node_lookup().add_node(inode, layer, x, y, e_rr_type::CHANZ, rr_node_offset); } } } @@ -467,7 +466,7 @@ bool verify_rr_node_indices(const DeviceGrid& grid, for (e_rr_type rr_type : RR_TYPES) { // Get the list of nodes at a specific location (x, y) std::vector nodes_from_lookup; - if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY) { + if (rr_type == e_rr_type::CHANX || rr_type == e_rr_type::CHANY || rr_type == e_rr_type::CHANZ) { nodes_from_lookup = rr_graph.node_lookup().find_channel_nodes(l, x, y, rr_type); } else { nodes_from_lookup = rr_graph.node_lookup().find_grid_nodes_at_all_sides(l, x, y, rr_type); @@ -516,6 +515,24 @@ bool verify_rr_node_indices(const DeviceGrid& grid, y, describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); } + } else if (rr_graph.node_type(inode) == e_rr_type::CHANZ) { + VTR_ASSERT_MSG(rr_graph.node_xlow(inode) == rr_graph.node_xhigh(inode), "CHANZ should move only along layers"); + VTR_ASSERT_MSG(rr_graph.node_ylow(inode) == rr_graph.node_yhigh(inode), "CHANZ should move only along layers"); + + if (x != rr_graph.node_xlow(inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node x position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s", + rr_graph.node_xlow(inode), + x, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + + if (y != rr_graph.node_ylow(inode)) { + VPR_ERROR(VPR_ERROR_ROUTE, "RR node y position does not agree between rr_nodes (%d) and rr_node_indices (%d): %s", + rr_graph.node_xlow(inode), + y, + describe_rr_node(rr_graph, grid, rr_indexed_data, inode, is_flat).c_str()); + } + } else if (rr_graph.node_type(inode) == e_rr_type::SOURCE || rr_graph.node_type(inode) == e_rr_type::SINK) { // Sources have co-ordinates covering the entire block they are in, but not sinks if (!rr_graph.x_in_node_range(x, inode)) { diff --git a/vpr/src/route/rr_graph_generation/rr_node_indices.h b/vpr/src/route/rr_graph_generation/rr_node_indices.h index 76373c1cc7..03c123ffa2 100644 --- a/vpr/src/route/rr_graph_generation/rr_node_indices.h +++ b/vpr/src/route/rr_graph_generation/rr_node_indices.h @@ -39,7 +39,6 @@ void alloc_and_load_rr_node_indices(RRGraphBuilder& rr_graph_builder, * @param index Pointer to the global RR node index counter; incremented as new RR nodes are assigned. */ void alloc_and_load_inter_die_rr_node_indices(RRGraphBuilder& rr_graph_builder, - const t_chan_width& nodes_per_chan, const DeviceGrid& grid, const vtr::NdMatrix& extra_nodes_per_switchblock, int* index);