vpr: Add initial route tree stub check to check_route
diff --git a/vpr/src/route/check_route.cpp b/vpr/src/route/check_route.cpp
index 821ce50..f08d3d6 100755
--- a/vpr/src/route/check_route.cpp
+++ b/vpr/src/route/check_route.cpp
@@ -14,6 +14,8 @@
#include "rr_graph.h"
#include "check_rr_graph.h"
#include "read_xml_arch_file.h"
+#include "route_tree_type.h"
+#include "route_tree_timing.h"
struct t_node_edge {
t_node_edge(int fnode, int tnode) {
@@ -51,6 +53,11 @@
static void expand_non_configurable(int inode, std::set<t_node_edge>& edge_set);
static bool check_non_configurable_edges(ClusterNetId net, const t_non_configurable_rr_sets& non_configurable_rr_sets);
+
+void check_net_for_stubs(ClusterNetId net);
+std::vector<t_rt_node*> find_route_tree_stubs(t_rt_node* rt_root);
+bool find_route_tree_stubs_recurr(t_rt_node* rt_root, std::vector<t_rt_node*>& stubs);
+
/************************ Subroutine definitions ****************************/
void check_route(enum e_route_type route_type) {
@@ -180,6 +187,8 @@
check_non_configurable_edges(net_id, non_configurable_rr_sets);
+ check_net_for_stubs(net_id);
+
reset_flags(net_id, connected_to_route);
} /* End for each net */
@@ -880,3 +889,77 @@
return true;
}
+
+//Cheks 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.
+//The only exception are stubs required by non-configurable switches (e.g. shorts).
+//
+//We treat any configurable stubs as an error.
+void check_net_for_stubs(ClusterNetId net) {
+ auto& route_ctx = g_vpr_ctx.mutable_routing();
+
+ t_rt_node* rt_root = traceback_to_route_tree(net);
+
+ auto stubs = find_route_tree_stubs(rt_root);
+
+ if (!stubs.empty()) {
+ auto& cluster_ctx = g_vpr_ctx.clustering();
+ std::string msg = vtr::string_fmt("Route tree for net '%s' (#%zu) contains stub branches rooted at:\n",
+ cluster_ctx.clb_nlist.net_name(net).c_str(), size_t(net));
+ for (t_rt_node* stub_root : stubs) {
+ msg += vtr::string_fmt(" %s\n", describe_rr_node(stub_root->inode).c_str());
+ }
+
+ VPR_THROW(VPR_ERROR_ROUTE, msg.c_str());
+ }
+
+ free_route_tree(rt_root);
+}
+
+//Returns the set of stub roots for a given route tree
+std::vector<t_rt_node*> find_route_tree_stubs(t_rt_node* rt_root) {
+ std::vector<t_rt_node*> stubs;
+ find_route_tree_stubs_recurr(rt_root, stubs);
+ return stubs;
+}
+
+//Returns true if rt_root is a configurable stub.
+//If any of rt_root's children are stubs they are added to 'stubs' since they are stub roots
+//
+//A stub is defined as a branch of the route tree which does not connect to a SINK, but has
+//configurable edges (and hence should have been trimmed).
+bool find_route_tree_stubs_recurr(t_rt_node* rt_root, std::vector<t_rt_node*>& stubs) {
+ auto& device_ctx = g_vpr_ctx.device();
+
+ if (rt_root->u.child_list == nullptr) {
+ //If a leaf of the route tree is not a SINK, then it is a stub
+ if (device_ctx.rr_nodes[rt_root->inode].type() != SINK) {
+ return true; //It is the current root of this stub
+ } else {
+ return false;
+ }
+ } else {
+ //If any of the children are not stubs, neither is the current node
+ bool is_stub = true;
+ std::vector<t_rt_node*> child_stubs;
+ for (t_linked_rt_edge* edge = rt_root->u.child_list; edge != nullptr; edge = edge->next) {
+ bool child_is_stub = find_route_tree_stubs_recurr(edge->child, stubs);
+ bool driver_switch_configurable = device_ctx.rr_switch_inf[edge->iswitch].configurable();
+
+ if (child_is_stub && driver_switch_configurable) {
+ child_stubs.push_back(edge->child);
+ } else {
+ is_stub = false;
+ }
+ }
+
+ if (is_stub) {
+ return true; //All children were stubs, so is the current node
+ } else {
+ //This node is not a stub, so add any child stubs as stub roots
+ stubs.insert(stubs.end(), child_stubs.begin(), child_stubs.end());
+ return false;
+ }
+ }
+}