Refactored net_delay and route_tree_timing code
diff --git a/vpr/src/draw/draw.cpp b/vpr/src/draw/draw.cpp
index 4a2afdc..8e108d3 100644
--- a/vpr/src/draw/draw.cpp
+++ b/vpr/src/draw/draw.cpp
@@ -3240,7 +3240,7 @@
std::reverse(rr_nodes_on_path.begin(), rr_nodes_on_path.end());
if (allocated_route_tree_structs) {
- free_route_tree_timing_structs(); //Clean-up
+ free_route_tree_timing_structs();
}
return rr_nodes_on_path;
}
diff --git a/vpr/src/route/route_timing.cpp b/vpr/src/route/route_timing.cpp
index 8ec3ea5..80d5962 100644
--- a/vpr/src/route/route_timing.cpp
+++ b/vpr/src/route/route_timing.cpp
@@ -841,6 +841,7 @@
free(sink_order + 1);
// coverity[offset_free : Intentional]
free(rt_node_of_sink + 1);
+
free_route_tree_timing_structs();
}
diff --git a/vpr/src/route/route_tree_timing.cpp b/vpr/src/route/route_tree_timing.cpp
index 52d1de3..0cb14b9 100644
--- a/vpr/src/route/route_tree_timing.cpp
+++ b/vpr/src/route/route_tree_timing.cpp
@@ -21,11 +21,7 @@
* about the partial routing during timing-driven routing, so the routines
* in this module are used to keep a tree representation of the partial
* routing during timing-driven routing. This allows rapid incremental
- * timing analysis. The net_delay module does timing analysis in one step
- * (not incrementally as pieces of the routing are added). I could probably
- * one day remove a lot of net_delay.c and call the corresponding routines
- * here, but it's useful to have a from-scratch delay calculator to check
- * the results of this one. */
+ * timing analysis. */
/********************** Variables local to this module ***********************/
@@ -612,6 +608,7 @@
if (!rr_node_to_rt_node.empty()) {
rr_node_to_rt_node.at(rt_node->inode) = nullptr;
}
+
free_rt_node(rt_node);
}
@@ -690,7 +687,13 @@
while (trace) { //Each branch
trace = traceback_to_route_tree_branch(trace, rr_node_to_rt);
}
+ // Due to the recursive nature of traceback_to_route_tree_branch,
+ // the source node is not properly configured.
+ // Here, for the source we set the parent node and switch to be
+ // nullptr and OPEN respectively.
+ rr_node_to_rt[head->index]->parent_node = nullptr;
+ rr_node_to_rt[head->index]->parent_switch = OPEN;
return rr_node_to_rt[head->index];
}
diff --git a/vpr/src/timing/net_delay.cpp b/vpr/src/timing/net_delay.cpp
index 6045ea7..3fa6fb2 100644
--- a/vpr/src/timing/net_delay.cpp
+++ b/vpr/src/timing/net_delay.cpp
@@ -9,87 +9,37 @@
#include "globals.h"
#include "net_delay.h"
-/***************** Types and defines local to this module ********************/
-struct t_rc_node;
+#include "route_tree_timing.h"
-/* Linked list listing the children of an rc_node. *
- * child: Pointer to an rc_node (child of the current node). *
- * iswitch: Index of the switch type used to connect to the child node. *
- * next: Pointer to the next linked_rc_edge in the linked list (allows *
- * you to get the next child of the current rc_node). */
-struct t_linked_rc_edge {
- t_rc_node* child;
- short iswitch;
- t_linked_rc_edge* next;
-};
+/* This module keeps track of the time delays for signals to arrive at *
+ * each pin in every net after timing-driven routing is complete. It *
+ * achieves this by first constructing the skeleton route tree *
+ * from the traceback. Next, to obtain the completed route tree, it *
+ * calls functions to calculate the resistance, capacitance, and time *
+ * delays associated with each node. Then, it recursively traverses *
+ * the tree, copying the time delay from each node into the *
+ * net_delay data structure. Essentially, the delays are calculated *
+ * by building the completed route tree from scratch, and is used *
+ * to check against the time delays computed incrementally during *
+ * timing-driven routing. */
-/* Structure describing one node in an RC tree (used to get net delays). *
- * u.child_list: Pointer to a linked list of linked_rc_edge. Each one of *
- * the linked list entries gives a child of this node. *
- * u.next: Used only when this node is on the free list. Gives the next *
- * node on the free list. *
- * inode: index (ID) of the rr_node that corresponds to this rc_node. *
- * C_downstream: Total downstream capacitance from this rc_node. That is, *
- * the total C of the subtree rooted at the current node, *
- * including the C of the current node. *
- * Tdel: Time delay for the signal to get from the net source to this node. *
- * Includes the time to go through this node. */
-struct t_rc_node {
- union {
- t_linked_rc_edge* child_list;
- t_rc_node* next;
- } u;
- int inode;
- float C_downstream;
- float Tdel;
-};
+/********************** Variables local to this module ***********************/
-/* Linked list of pointers to rc_nodes. *
- * rc_node: Pointer to an rc_node. *
- * next: Next list element. */
-struct t_linked_rc_ptr {
- t_rc_node* rc_node;
- t_linked_rc_ptr* next;
-};
+/* Unordered map below stores the pair whose key is the index of the rr_node *
+ * that corresponds to the rt_node, and whose value is the time delay *
+ * associated with that node. The map will be used to store delays while *
+ * traversing the nodes of the route tree in load_one_net_delay_recurr. */
+
+static std::unordered_map<int, float> inode_to_Tdel_map;
/*********************** Subroutines local to this module ********************/
-static t_rc_node* alloc_and_load_rc_tree(ClusterNetId net_id,
- t_rc_node** rc_node_free_list_ptr,
- t_linked_rc_edge** rc_edge_free_list_ptr,
- t_linked_rc_ptr* rr_node_to_rc_node);
+static void load_one_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id);
-static void add_to_rc_tree(t_rc_node* parent_rc, t_rc_node* child_rc, short iswitch, int inode, t_linked_rc_edge** rc_edge_free_list_ptr);
-
-static t_rc_node* alloc_rc_node(t_rc_node** rc_node_free_list_ptr);
-
-static void free_rc_node(t_rc_node* rc_node,
- t_rc_node** rc_node_free_list_ptr);
-
-static t_linked_rc_edge* alloc_linked_rc_edge(t_linked_rc_edge** rc_edge_free_list_ptr);
-
-static void free_linked_rc_edge(t_linked_rc_edge* rc_edge,
- t_linked_rc_edge** rc_edge_free_list_ptr);
-
-static float load_rc_tree_C(t_rc_node* rc_node);
-
-static void load_rc_tree_T(t_rc_node* rc_node, float T_arrival);
-
-static void load_one_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id, t_linked_rc_ptr* rr_node_to_rc_node);
+static void load_one_net_delay_recurr(t_rt_node* node, ClusterNetId net_id);
static void load_one_constant_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id, float delay_value);
-static void free_rc_tree(t_rc_node* rc_root,
- t_rc_node** rc_node_free_list_ptr,
- t_linked_rc_edge** rc_edge_free_list_ptr);
-
-static void reset_rr_node_to_rc_node(t_linked_rc_ptr* rr_node_to_rc_node,
- ClusterNetId net_id);
-
-static void free_rc_node_free_list(t_rc_node* rc_node_free_list);
-
-static void free_rc_edge_free_list(t_linked_rc_edge* rc_edge_free_list);
-
/*************************** Subroutine definitions **************************/
/* Allocates space for the net_delay data structure *
@@ -118,399 +68,76 @@
void free_net_delay(vtr::vector<ClusterNetId, float*>& net_delay,
vtr::t_chunk* chunk_list_ptr) {
- /* Frees the net_delay structure. Assumes it was chunk allocated. */
-
net_delay.clear();
vtr::free_chunk_memory(chunk_list_ptr);
}
void load_net_delay_from_routing(vtr::vector<ClusterNetId, float*>& net_delay) {
/* This routine loads net_delay[0..nets.size()-1][1..num_pins-1]. Each entry *
- * is the Elmore delay from the net source to the appropriate sink. Both *
- * the rr_graph and the routing traceback must be completely constructed *
- * before this routine is called, and the net_delay array must have been *
- * allocated. */
- auto& device_ctx = g_vpr_ctx.device();
+ * is the Elmore delay from the net source to the appropriate sink. Both *
+ * the rr_graph and the routing traceback must be completely constructed *
+ * before this routine is called, and the net_delay array must have been *
+ * allocated. */
auto& cluster_ctx = g_vpr_ctx.clustering();
- t_rc_node *rc_node_free_list, *rc_root;
- t_linked_rc_edge* rc_edge_free_list;
- t_linked_rc_ptr* rr_node_to_rc_node; /* [0..device_ctx.rr_nodes.size()-1] */
-
- rr_node_to_rc_node = (t_linked_rc_ptr*)vtr::calloc(device_ctx.rr_nodes.size(),
- sizeof(t_linked_rc_ptr));
-
- rc_node_free_list = nullptr;
- rc_edge_free_list = nullptr;
-
for (auto net_id : cluster_ctx.clb_nlist.nets()) {
if (cluster_ctx.clb_nlist.net_is_ignored(net_id)) {
load_one_constant_net_delay(net_delay, net_id, 0.);
} else {
- rc_root = alloc_and_load_rc_tree(net_id, &rc_node_free_list,
- &rc_edge_free_list, rr_node_to_rc_node);
- load_rc_tree_C(rc_root);
- load_rc_tree_T(rc_root, 0.);
- load_one_net_delay(net_delay, net_id, rr_node_to_rc_node);
- free_rc_tree(rc_root, &rc_node_free_list, &rc_edge_free_list);
- reset_rr_node_to_rc_node(rr_node_to_rc_node, net_id);
+ load_one_net_delay(net_delay, net_id);
}
}
-
- free_rc_node_free_list(rc_node_free_list);
- free_rc_edge_free_list(rc_edge_free_list);
- free(rr_node_to_rc_node);
}
-static t_rc_node*
-alloc_and_load_rc_tree(ClusterNetId net_id, t_rc_node** rc_node_free_list_ptr, t_linked_rc_edge** rc_edge_free_list_ptr, t_linked_rc_ptr* rr_node_to_rc_node) {
- /* Builds a tree describing the routing of net inet. Allocates all the data *
- * and inserts all the connections in the tree. */
-
- t_rc_node *curr_rc, *prev_rc, *root_rc;
- t_trace* tptr;
- int inode;
- short iswitch;
- t_linked_rc_ptr* linked_rc_ptr;
+static void load_one_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id) {
+ /* This routine loads delay values for one net in *
+ * net_delay[net_id][1..num_pins-1]. First, from the traceback, it *
+ * constructs the route tree and computes its values for R, C, and Tdel. *
+ * Next, it walks the route tree recursively, storing the time delays for *
+ * each node into the map inode_to_Tdel. Then, while looping through the *
+ * net_delay array we search for the inode corresponding to the pin *
+ * identifiers, and correspondingly update the entry in net_delay. *
+ * Finally, it frees the route tree and clears the inode_to_Tdel_map *
+ * associated with that net. */
auto& route_ctx = g_vpr_ctx.routing();
- root_rc = alloc_rc_node(rc_node_free_list_ptr);
- tptr = route_ctx.trace[net_id].head;
-
- if (tptr == nullptr) {
+ if (route_ctx.trace[net_id].head == nullptr) {
VPR_FATAL_ERROR(VPR_ERROR_TIMING,
- "in alloc_and_load_rc_tree: Traceback for net %lu does not exist.\n", size_t(net_id));
+ "in load_one_net_delay: Traceback for net %lu does not exist.\n", size_t(net_id));
}
- inode = tptr->index;
- iswitch = tptr->iswitch;
- root_rc->inode = inode;
- root_rc->u.child_list = nullptr;
- rr_node_to_rc_node[inode].rc_node = root_rc;
-
- prev_rc = root_rc;
- tptr = tptr->next;
-
- while (tptr != nullptr) {
- inode = tptr->index;
-
- /* Is this node a "stitch-in" point to part of the existing routing or a *
- * new piece of routing along the current routing "arm?" */
-
- if (rr_node_to_rc_node[inode].rc_node == nullptr) { /* Part of current "arm" */
- curr_rc = alloc_rc_node(rc_node_free_list_ptr);
- add_to_rc_tree(prev_rc, curr_rc, iswitch, inode, rc_edge_free_list_ptr);
- rr_node_to_rc_node[inode].rc_node = curr_rc;
- prev_rc = curr_rc;
-
- } else if (iswitch == OPEN) { /* Connection to old stuff. */
-
- prev_rc = rr_node_to_rc_node[inode].rc_node;
-
- } else { /* SINK that this net has connected to more than once. */
-
- /* I can connect to a SINK node more than once in some weird architectures. *
- * That means the routing isn't really a tree -- there is reconvergent *
- * fanout from two or more IPINs into one SINK. I convert this structure *
- * into a true RC tree on the fly by creating a new rc_node each time I hit *
- * the same sink. This means I need to keep a linked list of the rc_nodes *
- * associated with the rr_node (inode) associated with that SINK. */
-
- curr_rc = alloc_rc_node(rc_node_free_list_ptr);
- add_to_rc_tree(prev_rc, curr_rc, iswitch, inode, rc_edge_free_list_ptr);
-
- linked_rc_ptr = (t_linked_rc_ptr*)vtr::malloc(sizeof(t_linked_rc_ptr));
- linked_rc_ptr->next = rr_node_to_rc_node[inode].next;
- rr_node_to_rc_node[inode].next = linked_rc_ptr;
- linked_rc_ptr->rc_node = curr_rc;
-
- prev_rc = curr_rc;
- }
- iswitch = tptr->iswitch;
- tptr = tptr->next;
- }
-
- return (root_rc);
-}
-
-static void add_to_rc_tree(t_rc_node* parent_rc, t_rc_node* child_rc, short iswitch, int inode, t_linked_rc_edge** rc_edge_free_list_ptr) {
- /* Adds child_rc to the child list of parent_rc, and sets the switch between *
- * them to iswitch. This routine also intitializes the child_rc properly *
- * and sets its node value to inode. */
-
- t_linked_rc_edge* linked_rc_edge;
-
- linked_rc_edge = alloc_linked_rc_edge(rc_edge_free_list_ptr);
-
- linked_rc_edge->next = parent_rc->u.child_list;
- parent_rc->u.child_list = linked_rc_edge;
-
- linked_rc_edge->child = child_rc;
- linked_rc_edge->iswitch = iswitch;
-
- child_rc->u.child_list = nullptr;
- child_rc->inode = inode;
-}
-
-static t_rc_node*
-alloc_rc_node(t_rc_node** rc_node_free_list_ptr) {
- /* Allocates a new rc_node, from the free list if possible, from the free *
- * store otherwise. */
-
- t_rc_node* rc_node;
-
- rc_node = *rc_node_free_list_ptr;
-
- if (rc_node != nullptr) {
- *rc_node_free_list_ptr = rc_node->u.next;
- } else {
- rc_node = (t_rc_node*)vtr::malloc(sizeof(t_rc_node));
- }
-
- return (rc_node);
-}
-
-static void free_rc_node(t_rc_node* rc_node,
- t_rc_node** rc_node_free_list_ptr) {
- /* Adds rc_node to the proper free list. */
-
- rc_node->u.next = *rc_node_free_list_ptr;
- *rc_node_free_list_ptr = rc_node;
-}
-
-static t_linked_rc_edge*
-alloc_linked_rc_edge(t_linked_rc_edge** rc_edge_free_list_ptr) {
- /* Allocates a new linked_rc_edge, from the free list if possible, from the *
- * free store otherwise. */
-
- t_linked_rc_edge* linked_rc_edge;
-
- linked_rc_edge = *rc_edge_free_list_ptr;
-
- if (linked_rc_edge != nullptr) {
- *rc_edge_free_list_ptr = linked_rc_edge->next;
- } else {
- linked_rc_edge = (t_linked_rc_edge*)vtr::malloc(sizeof(t_linked_rc_edge));
- }
-
- return (linked_rc_edge);
-}
-
-static void free_linked_rc_edge(t_linked_rc_edge* rc_edge,
- t_linked_rc_edge** rc_edge_free_list_ptr) {
- /* Adds the rc_edge to the rc_edge free list. */
-
- rc_edge->next = *rc_edge_free_list_ptr;
- *rc_edge_free_list_ptr = rc_edge;
-}
-
-static float load_rc_tree_C(t_rc_node* rc_node) {
- /* Does a post-order traversal of the rc tree to load each node's *
- * C_downstream with the proper sum of all the downstream capacitances. *
- * This routine calls itself recursively to perform the traversal. */
-
- t_linked_rc_edge* linked_rc_edge;
- t_rc_node* child_node;
- int inode;
- short iswitch;
- float C, C_downstream;
-
- auto& device_ctx = g_vpr_ctx.device();
-
- linked_rc_edge = rc_node->u.child_list;
- inode = rc_node->inode;
- C = device_ctx.rr_nodes[inode].C();
-
- while (linked_rc_edge != nullptr) { /* For all children */
- iswitch = linked_rc_edge->iswitch;
- child_node = linked_rc_edge->child;
- C_downstream = load_rc_tree_C(child_node);
-
- if (!device_ctx.rr_switch_inf[iswitch].buffered())
- C += C_downstream;
-
- linked_rc_edge = linked_rc_edge->next;
- }
-
- rc_node->C_downstream = C;
- return (C);
-}
-
-static void load_rc_tree_T(t_rc_node* rc_node, float T_arrival) {
- /* This routine does a pre-order depth-first traversal of the rc tree to *
- * compute the Tdel to each node in the rc tree. The T_arrival is the time *
- * at which the signal hits the input to this node. This routine calls *
- * itself recursively to perform the traversal. */
-
- float Tdel, Rmetal, Tchild;
- t_linked_rc_edge* linked_rc_edge;
- t_rc_node* child_node;
- short iswitch;
- int inode;
-
- auto& device_ctx = g_vpr_ctx.device();
-
- Tdel = T_arrival;
- inode = rc_node->inode;
- Rmetal = device_ctx.rr_nodes[inode].R();
-
- /* NB: device_ctx.rr_nodes[inode].C gives the capacitance of this node, while *
- * rc_node->C_downstream gives the unbuffered downstream capacitance rooted *
- * at this node, including the C of the node itself. I want to multiply *
- * the C of this node by 0.5 Rmetal, since it's a distributed RC line. *
- * Hence 0.5 Rmetal * Cnode is a pessimistic estimate of delay (i.e. end to *
- * end). For the downstream capacitance rooted at this node (not including *
- * the capacitance of the node itself), I assume it is, on average, *
- * connected halfway along the line, so I also multiply by 0.5 Rmetal. To *
- * be totally pessimistic I would multiply the downstream part of the *
- * capacitance by Rmetal. Play with this equation if you like. */
-
- /* Rmetal is distributed so x0.5 */
- Tdel += 0.5 * rc_node->C_downstream * Rmetal;
- rc_node->Tdel = Tdel;
-
- /* Now expand the children of this node to load their Tdel values. */
-
- linked_rc_edge = rc_node->u.child_list;
-
- while (linked_rc_edge != nullptr) { /* For all children */
- iswitch = linked_rc_edge->iswitch;
- child_node = linked_rc_edge->child;
-
- Tchild = Tdel + device_ctx.rr_switch_inf[iswitch].R * child_node->C_downstream;
- Tchild += device_ctx.rr_switch_inf[iswitch].Tdel; /* Intrinsic switch delay. */
- load_rc_tree_T(child_node, Tchild);
-
- linked_rc_edge = linked_rc_edge->next;
- }
-}
-
-/* Loads the net delay array for net inet. The rc tree for that net must *
- * have already been completely built and loaded. */
-static void load_one_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id, t_linked_rc_ptr* rr_node_to_rc_node) {
- unsigned int ipin, inode;
- float Tmax;
- t_rc_node* rc_node;
- t_linked_rc_ptr *linked_rc_ptr, *next_ptr;
-
auto& cluster_ctx = g_vpr_ctx.clustering();
- auto& route_ctx = g_vpr_ctx.routing();
+ int inode;
- for (ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ipin++) {
- inode = route_ctx.net_rr_terminals[net_id][ipin];
- linked_rc_ptr = rr_node_to_rc_node[inode].next;
- rc_node = rr_node_to_rc_node[inode].rc_node;
- Tmax = rc_node->Tdel;
+ t_rt_node* rt_root = traceback_to_route_tree(net_id); // obtain the root of the tree constructed from the traceback
+ load_new_subtree_R_upstream(rt_root); // load in the resistance values for the route tree
+ load_new_subtree_C_downstream(rt_root); // load in the capacitance values for the route tree
+ load_route_tree_Tdel(rt_root, 0.); // load the time delay values for the route tree
+ load_one_net_delay_recurr(rt_root, net_id); // recursively traverse the tree and load entries into the inode_to_Tdel map
- /* If below only executes when one net connects several times to the *
- * same SINK. In this case, I can't tell which net pin each connection *
- * to this SINK corresponds to (I can just choose arbitrarily). To make *
- * sure the timing behaviour converges, I pessimistically set the delay *
- * for all of the connections to this SINK by this net to be the max. of *
- * the delays from this net to this SINK. NB: This code only occurs *
- * when a net connect more than once to the same pin class on the same *
- * logic block. Only a weird architecture would allow this. */
+ for (unsigned int ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ipin++) {
+ inode = route_ctx.net_rr_terminals[net_id][ipin]; // look for the index of the rr node that corresponds to the sink that was used to route a certain connection.
+ net_delay[net_id][ipin] = inode_to_Tdel_map.find(inode)->second; // search for the value of Tdel in the inode map and load into net_delay
+ }
+ free_route_tree(rt_root); // free the route tree
+ inode_to_Tdel_map.clear(); // clear the map
+}
- if (linked_rc_ptr != nullptr) {
- /* The first time I hit a multiply-used SINK, I choose the largest delay *
- * from this net to this SINK and use it for every connection to this *
- * SINK by this net. */
+static void load_one_net_delay_recurr(t_rt_node* node, ClusterNetId net_id) {
+ /* This routine recursively traverses the route tree, and copies the Tdel of the node into the map. */
- do {
- rc_node = linked_rc_ptr->rc_node;
- if (rc_node->Tdel > Tmax) {
- Tmax = rc_node->Tdel;
- rr_node_to_rc_node[inode].rc_node = rc_node;
- }
- next_ptr = linked_rc_ptr->next;
- free(linked_rc_ptr);
- linked_rc_ptr = next_ptr;
- } while (linked_rc_ptr != nullptr); /* End do while */
+ inode_to_Tdel_map[node->inode] = node->Tdel; // add to the map, process current node
- rr_node_to_rc_node[inode].next = nullptr;
- }
- /* End of if multiply-used SINK */
- net_delay[net_id][ipin] = Tmax;
+ for (t_linked_rt_edge* edge = node->u.child_list; edge != nullptr; edge = edge->next) { // process children
+ load_one_net_delay_recurr(edge->child, net_id);
}
}
static void load_one_constant_net_delay(vtr::vector<ClusterNetId, float*>& net_delay, ClusterNetId net_id, float delay_value) {
/* Sets each entry of the net_delay array for net inet to delay_value. */
- unsigned int ipin;
auto& cluster_ctx = g_vpr_ctx.clustering();
- for (ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ipin++)
+ for (unsigned int ipin = 1; ipin < cluster_ctx.clb_nlist.net_pins(net_id).size(); ipin++)
net_delay[net_id][ipin] = delay_value;
}
-
-static void free_rc_tree(t_rc_node* rc_root,
- t_rc_node** rc_node_free_list_ptr,
- t_linked_rc_edge** rc_edge_free_list_ptr) {
- /* Puts the rc tree pointed to by rc_root back on the free list. Depth- *
- * first post-order traversal via recursion. */
-
- t_rc_node *rc_node, *child_node;
- t_linked_rc_edge *rc_edge, *next_edge;
-
- rc_node = rc_root;
- rc_edge = rc_node->u.child_list;
-
- while (rc_edge != nullptr) { /* For all children */
- child_node = rc_edge->child;
- free_rc_tree(child_node, rc_node_free_list_ptr, rc_edge_free_list_ptr);
- next_edge = rc_edge->next;
- free_linked_rc_edge(rc_edge, rc_edge_free_list_ptr);
- rc_edge = next_edge;
- }
-
- free_rc_node(rc_node, rc_node_free_list_ptr);
-}
-
-static void reset_rr_node_to_rc_node(t_linked_rc_ptr* rr_node_to_rc_node, ClusterNetId net_id) {
- /* Resets the rr_node_to_rc_node mapping entries that were set during *
- * construction of the RC tree for net inet. Any extra linked list entries *
- * added to deal with a SINK being connected to multiple times have already *
- * been freed by load_one_net_delay. */
-
- t_trace* tptr;
- int inode;
-
- auto& route_ctx = g_vpr_ctx.routing();
-
- tptr = route_ctx.trace[net_id].head;
-
- while (tptr != nullptr) {
- inode = tptr->index;
- rr_node_to_rc_node[inode].rc_node = nullptr;
- tptr = tptr->next;
- }
-}
-
-static void free_rc_node_free_list(t_rc_node* rc_node_free_list) {
- /* Really frees (i.e. calls free()) all the rc_nodes on the free list. */
-
- t_rc_node *rc_node, *next_node;
-
- rc_node = rc_node_free_list;
-
- while (rc_node != nullptr) {
- next_node = rc_node->u.next;
- free(rc_node);
- rc_node = next_node;
- }
-}
-
-static void free_rc_edge_free_list(t_linked_rc_edge* rc_edge_free_list) {
- /* Really frees (i.e. calls free()) all the rc_edges on the free list. */
-
- t_linked_rc_edge *rc_edge, *next_edge;
-
- rc_edge = rc_edge_free_list;
-
- while (rc_edge != nullptr) {
- next_edge = rc_edge->next;
- free(rc_edge);
- rc_edge = next_edge;
- }
-}