diff --git a/vpr/src/base/vpr_types.h b/vpr/src/base/vpr_types.h index e33c1ac004e..1fc5fe60317 100644 --- a/vpr/src/base/vpr_types.h +++ b/vpr/src/base/vpr_types.h @@ -1641,7 +1641,7 @@ typedef t_routing_status t_atom_net_routing_status; /** Edge between two RRNodes */ struct t_node_edge { - t_node_edge(RRNodeId fnode, RRNodeId tnode) + t_node_edge(RRNodeId fnode, RRNodeId tnode) noexcept : from_node(fnode) , to_node(tnode) {} @@ -1654,10 +1654,18 @@ struct t_node_edge { } }; -///@brief Non-configurably connected nodes and edges in the RR graph +/** + * @brief Groups of non-configurably connected nodes and edges in the RR graph. + * @note Each group is represented by a node set and an edge set, stored at the same index. + * + * For example, in an architecture with L-shaped wires formed by an x- and y-directed segment + * connected by an electrical short, each L-shaped wire corresponds to a new group. The group's + * index provides access to its node set (containing two RRNodeIds) and edge set (containing two + * directed edge in opposite directions). + */ struct t_non_configurable_rr_sets { - std::set> node_sets; - std::set> edge_sets; + std::vector> node_sets; + std::vector> edge_sets; }; ///@brief Power estimation options @@ -1669,11 +1677,11 @@ struct t_power_opts { * @param max= Maximum channel width between x_max and y_max. * @param x_min= Minimum channel width of horizontal channels. Initialized when init_chan() is invoked in rr_graph2.cpp * @param y_min= Same as above but for vertical channels. - * @param x_max= Maximum channel width of horiozntal channels. Initialized when init_chan() is invoked in rr_graph2.cpp + * @param x_max= Maximum channel width of horizontal channels. Initialized when init_chan() is invoked in rr_graph2.cpp * @param y_max= Same as above but for vertical channels. * @param x_list= Stores the channel width of all horizontal channels and thus goes from [0..grid.height()] * (imagine a 2D Cartesian grid with horizontal lines starting at every grid point on a line parallel to the y-axis) - * @param y_list= Stores the channel width of all verical channels and thus goes from [0..grid.width()] + * @param y_list= Stores the channel width of all vertical channels and thus goes from [0..grid.width()] * (imagine a 2D Cartesian grid with vertical lines starting at every grid point on a line parallel to the x-axis) */ diff --git a/vpr/src/route/check_route.cpp b/vpr/src/route/check_route.cpp index fd239d39b52..a8bc1f98126 100644 --- a/vpr/src/route/check_route.cpp +++ b/vpr/src/route/check_route.cpp @@ -1,4 +1,5 @@ -#include + +#include "check_route.h" #include "route_common.h" #include "vtr_assert.h" @@ -11,7 +12,7 @@ #include "globals.h" #include "route_export.h" -#include "check_route.h" + #include "rr_graph.h" #include "check_rr_graph.h" #include "read_xml_arch_file.h" @@ -39,11 +40,32 @@ static void check_locally_used_clb_opins(const t_clb_opins_used& clb_opins_used_ enum e_route_type route_type, bool is_flat); +/** + * Checks that all non-configurable edges are in a legal configuration. + * @param net_list The netlist whose routing is to be checked. + * @param is_flat True if flat routing is enabled; otherwise false. + */ static void check_all_non_configurable_edges(const Netlist<>& net_list, bool is_flat); + +/** + * @brief Checks that the specified routing is legal with respect to non-configurable edges. + * For routing to be valid, if any non-configurable edge is used, all nodes in the same set + * and the required connecting edges in the set must also be used. + * + * @param net_list A reference to the netlist. + * @param net The net id for which the check is done. + * @param non_configurable_rr_sets Node and edge sets that constitute non-configurable RR sets. + * @param rrnode_set_id Specifies which RR sets each RR node is part of. These indices can be used to + * access elements of node_sets and edge_sets in non_configurable_rr_sets. + * @param is_flat Indicates whether flat routing is enabled. + * @return True if check is done successfully; otherwise false. + */ static bool check_non_configurable_edges(const Netlist<>& net_list, ParentNetId net, const t_non_configurable_rr_sets& non_configurable_rr_sets, + const vtr::vector& rrnode_set_id, bool is_flat); + static void check_net_for_stubs(const Netlist<>& net_list, ParentNetId net, bool is_flat); @@ -65,13 +87,9 @@ void check_route(const Netlist<>& net_list, return; } - int max_pins; - unsigned int ipin; - bool valid, connects; - - auto& device_ctx = g_vpr_ctx.device(); + const auto& device_ctx = g_vpr_ctx.device(); const auto& rr_graph = device_ctx.rr_graph; - auto& route_ctx = g_vpr_ctx.routing(); + const auto& route_ctx = g_vpr_ctx.routing(); const size_t num_switches = rr_graph.num_rr_switches(); @@ -83,7 +101,7 @@ void check_route(const Netlist<>& net_list, * is a successful routing, but I want to double check it here. */ recompute_occupancy_from_scratch(net_list, is_flat); - valid = feasible_routing(); + const bool valid = feasible_routing(); if (valid == false) { VPR_ERROR(VPR_ERROR_ROUTE, "Error in check_route -- routing resources are overused.\n"); @@ -95,7 +113,7 @@ void check_route(const Netlist<>& net_list, is_flat); } - max_pins = 0; + int max_pins = 0; for (auto net_id : net_list.nets()) max_pins = std::max(max_pins, (int)net_list.net_pins(net_id).size()); @@ -129,7 +147,7 @@ void check_route(const Netlist<>& net_list, check_switch(rt_node, num_switches); if (rt_node.parent()) { - connects = check_adjacent(rt_node.parent()->inode, rt_node.inode, is_flat); + bool connects = check_adjacent(rt_node.parent()->inode, rt_node.inode, is_flat); if (!connects) { VPR_ERROR(VPR_ERROR_ROUTE, "in check_route: found non-adjacent segments in traceback while checking net %d:\n" @@ -154,7 +172,7 @@ void check_route(const Netlist<>& net_list, num_sinks, net_list.net_sinks(net_id).size()); } - for (ipin = 0; ipin < net_list.net_pins(net_id).size(); ipin++) { + for (size_t ipin = 0; ipin < net_list.net_pins(net_id).size(); ipin++) { if (pin_done[ipin] == false) { VPR_FATAL_ERROR(VPR_ERROR_ROUTE, "in check_route: net %zu does not connect to pin %d.\n", size_t(net_id), ipin); @@ -194,7 +212,7 @@ static void check_sink(const Netlist<>& net_list, inode, net_list.net_name(net_id).c_str(), size_t(net_id)); } - VTR_ASSERT(!pin_done[net_pin_index]); /* Should not have found a routed cnnection to it before */ + VTR_ASSERT(!pin_done[net_pin_index]); /* Should not have found a routed connection to it before */ pin_done[net_pin_index] = true; } @@ -595,43 +613,71 @@ static void check_node_and_range(RRNodeId inode, is_flat); } -//Checks that all non-configurable edges are in a legal configuration -//This check is slow, so it has been moved out of check_route() static void check_all_non_configurable_edges(const Netlist<>& net_list, bool is_flat) { + const auto& rr_graph = g_vpr_ctx.device().rr_graph; + vtr::ScopedStartFinishTimer timer("Checking to ensure non-configurable edges are legal"); - auto non_configurable_rr_sets = identify_non_configurable_rr_sets(); + const t_non_configurable_rr_sets non_configurable_rr_sets = identify_non_configurable_rr_sets(); + + // Specifies which RR set each node is part of. + vtr::vector rrnode_set_ids(rr_graph.num_nodes(), -1); + + const size_t num_non_cfg_rr_sets = non_configurable_rr_sets.node_sets.size(); + + // Populate rrnode_set_ids + for (size_t non_cfg_rr_set_id = 0; non_cfg_rr_set_id < num_non_cfg_rr_sets; non_cfg_rr_set_id++) { + const std::set& node_set = non_configurable_rr_sets.node_sets[non_cfg_rr_set_id]; + for (const RRNodeId node_id : node_set) { + VTR_ASSERT_SAFE(rrnode_set_ids[node_id] == -1); + rrnode_set_ids[node_id] = (int)non_cfg_rr_set_id; + } + } for (auto net_id : net_list.nets()) { check_non_configurable_edges(net_list, net_id, non_configurable_rr_sets, + rrnode_set_ids, is_flat); } } -// Checks that the specified routing is legal with respect to non-configurable edges -// -//For routing to be legal if *any* non-configurable edge is used, so must *all* -//other non-configurable edges in the same set static bool check_non_configurable_edges(const Netlist<>& net_list, ParentNetId net, const t_non_configurable_rr_sets& non_configurable_rr_sets, + const vtr::vector& rrnode_set_id, bool is_flat) { const auto& device_ctx = g_vpr_ctx.device(); - auto& route_ctx = g_vpr_ctx.mutable_routing(); + const auto& route_ctx = g_vpr_ctx.routing(); if (!route_ctx.route_trees[net]) // no routing return true; - // Collect all the edges used by this net's routing + // Collect all the nodes, edges, and non-configurable RR set ids used by this net's routing std::set routing_edges; std::set routing_nodes; - for (auto& rt_node : route_ctx.route_trees[net].value().all_nodes()) { + std::set routing_non_configurable_rr_set_ids; + for (const RouteTreeNode& rt_node : route_ctx.route_trees[net].value().all_nodes()) { routing_nodes.insert(rt_node.inode); if (!rt_node.parent()) continue; t_node_edge edge = {rt_node.parent()->inode, rt_node.inode}; routing_edges.insert(edge); + + if (rrnode_set_id[rt_node.inode] >= 0) { // The node belongs to a non-configurable RR set + routing_non_configurable_rr_set_ids.insert(rrnode_set_id[rt_node.inode]); + } + } + + // Copy used non-configurable RR sets + // This is done to check legality only for used non-configurable RR sets. If a non-configurable RR set + // is not used by a net's routing, it cannot violate the requirements of using that non-configurable RR set. + t_non_configurable_rr_sets used_non_configurable_rr_sets; + used_non_configurable_rr_sets.node_sets.reserve(routing_non_configurable_rr_set_ids.size()); + used_non_configurable_rr_sets.edge_sets.reserve(routing_non_configurable_rr_set_ids.size()); + for (const int set_idx : routing_non_configurable_rr_set_ids) { + used_non_configurable_rr_sets.node_sets.emplace_back(non_configurable_rr_sets.node_sets[set_idx]); + used_non_configurable_rr_sets.edge_sets.emplace_back(non_configurable_rr_sets.edge_sets[set_idx]); } //We need to perform two types of checks: @@ -640,13 +686,13 @@ static bool check_non_configurable_edges(const Netlist<>& net_list, // 2) That all (required) non-configurable edges are used // //We need to check (2) in addition to (1) to ensure that (1) did not pass - //because the nodes 'happend' to be connected together by configurable + //because the nodes 'happened' to be connected together by configurable //routing (to be legal, by definition, they must be connected by //non-configurable routing). - //Check that all nodes in each non-configurable set are full included if any element + //Check that all nodes in each non-configurable set are fully included if any element //within a set is used by the routing - for (const auto& rr_nodes : non_configurable_rr_sets.node_sets) { + for (const auto& rr_nodes : used_non_configurable_rr_sets.node_sets) { //Compute the intersection of the routing and current non-configurable nodes set std::vector intersection; std::set_intersection(routing_nodes.begin(), routing_nodes.end(), @@ -668,7 +714,7 @@ static bool check_non_configurable_edges(const Netlist<>& net_list, routing_nodes.begin(), routing_nodes.end(), std::back_inserter(difference)); - VTR_ASSERT(difference.size() > 0); + VTR_ASSERT(!difference.empty()); std::string msg = vtr::string_fmt( "Illegal routing for net '%s' (#%zu) some " "required non-configurably connected nodes are missing:\n", @@ -685,7 +731,7 @@ static bool check_non_configurable_edges(const Netlist<>& net_list, //Check that any sets of non-configurable RR graph edges are fully included //in the routing, if any of a set's edges are used - for (const auto& rr_edges : non_configurable_rr_sets.edge_sets) { + for (const auto& rr_edges : used_non_configurable_rr_sets.edge_sets) { //Compute the intersection of the routing and current non-configurable edge set std::vector intersection; std::set_intersection(routing_edges.begin(), routing_edges.end(), @@ -698,7 +744,7 @@ static bool check_non_configurable_edges(const Netlist<>& net_list, //Since at least one non-configurable edge is used, to be legal //the full set of non-configurably connected edges must be used. // - //This is somewhat complicted by the fact that non-configurable edges + //This is somewhat complicated by the fact that non-configurable edges //are sometimes bi-directional (e.g. electrical shorts) and so appear //in rr_edges twice (once forward, once backward). Only one of the //paired edges need appear to be correct. @@ -791,9 +837,9 @@ class StubFinder { std::set stub_nodes_; }; -//Cheks for stubs in a net's routing. +//Checks for stubs in a net's routing. // -//Stubs (routing branches which don't connect to SINKs) serve no purpose, and only chew up wiring unecessarily. +//Stubs (routing branches which don't connect to SINKs) serve no purpose, and only chew up wiring unnecessarily. //The only exception are stubs required by non-configurable switches (e.g. shorts). // //We treat any configurable stubs as an error. diff --git a/vpr/src/route/edge_groups.cpp b/vpr/src/route/edge_groups.cpp index 6b63f7d8823..6ca1e36692a 100644 --- a/vpr/src/route/edge_groups.cpp +++ b/vpr/src/route/edge_groups.cpp @@ -52,14 +52,14 @@ t_non_configurable_rr_sets EdgeGroups::output_sets() { std::set edge_set; std::set node_set(nodes.begin(), nodes.end()); - for (const auto& src : node_set) { - for (const auto& dest : graph_[src].edges) { - edge_set.emplace(t_node_edge(src, dest)); + for (const RRNodeId src : node_set) { + for (const RRNodeId dest : graph_[src].edges) { + edge_set.emplace(src, dest); } } - sets.node_sets.emplace(std::move(node_set)); - sets.edge_sets.emplace(std::move(edge_set)); + sets.node_sets.emplace_back(std::move(node_set)); + sets.edge_sets.emplace_back(std::move(edge_set)); } return sets; diff --git a/vpr/test/test_edge_groups.cpp b/vpr/test/test_edge_groups.cpp index 80bfea5e133..e8b83741afa 100644 --- a/vpr/test/test_edge_groups.cpp +++ b/vpr/test/test_edge_groups.cpp @@ -19,12 +19,12 @@ TEST_CASE("edge_groups_create_sets", "[vpr]") { // Build chains from the given connected sets int max_node_id = 0; std::vector> edges; - for (auto set : connected_sets) { + for (const auto& set : connected_sets) { int last = *set.cbegin(); std::for_each(std::next(set.cbegin()), set.cend(), [&](int node) { - edges.push_back(std::make_pair(last, node)); + edges.emplace_back(last, node); last = node; max_node_id = std::max(max_node_id, node); }); @@ -36,7 +36,7 @@ TEST_CASE("edge_groups_create_sets", "[vpr]") { // Initialize nodes to [0, 1, ..., max_node_id] std::iota(nodes.begin(), nodes.end(), 0); - // Create a Mersenne Twister psuedo-random number generator with seed 1 + // Create a Mersenne Twister pseudo-random number generator with seed 1 std::mt19937 g(1); // Run the test many times, the PRNG will give differently shuffled inputs @@ -66,12 +66,12 @@ TEST_CASE("edge_groups_create_sets", "[vpr]") { t_non_configurable_rr_sets sets = groups.output_sets(); // Check for the expected sets - for (auto set : connected_sets) { + for (const auto& set : connected_sets) { std::set random_set; for (auto elem : set) { random_set.insert(RRNodeId(random_nodes[elem])); } - REQUIRE(sets.node_sets.find(random_set) != sets.node_sets.end()); + REQUIRE(std::find(sets.node_sets.begin(), sets.node_sets.end(), random_set) != sets.node_sets.end()); } } }