VPR-6.0

vpr/SRC/route/route_tree_timing.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include "util.h"
00003 #include "vpr_types.h"
00004 #include "globals.h"
00005 #include "route_common.h"
00006 #include "route_tree_timing.h"
00007 
00008 /**
00009  * @file
00010  *
00011  * This module keeps track of the partial routing tree for timing-driven     
00012  * routing.  The normal traceback structure doesn't provide enough info      
00013  * about the partial routing during timing-driven routing, so the routines   
00014  * in this module are used to keep a tree representation of the partial      
00015  * routing during timing-driven routing.  This allows rapid incremental      
00016  * timing analysis.  The net_delay module does timing analysis in one step   
00017  * (not incrementally as pieces of the routing are added).  I could probably 
00018  * one day remove a lot of net_delay.c and call the corresponding routines   
00019  * here, but it's useful to have a from-scratch delay calculator to check    
00020  * the results of this one.                                                  
00021  */
00022 
00023 
00024 /********************** Variables local to this module ***********************/
00025 
00026 /** Array below allows mapping from any rr_node to any rt_node currently in   
00027  * the rt_tree.                                                              
00028  */
00029 static t_rt_node **rr_node_to_rt_node = NULL;   /**< [0..num_rr_nodes-1] */
00030 
00031 /**@{*/
00032 /** Frees lists for fast addition and deletion of nodes and edges. */
00033 static t_rt_node *rt_node_free_list = NULL;
00034 static t_linked_rt_edge *rt_edge_free_list = NULL;
00035 /**@}*/
00036 
00037 
00038 /********************** Subroutines local to this module *********************/
00039 
00040 static t_rt_node *alloc_rt_node(void);
00041 
00042 static void free_rt_node(t_rt_node * rt_node);
00043 
00044 static t_linked_rt_edge *alloc_linked_rt_edge(void);
00045 
00046 static void free_linked_rt_edge(t_linked_rt_edge * rt_edge);
00047 
00048 static t_rt_node *add_path_to_route_tree(struct s_heap *hptr,
00049                                          t_rt_node ** sink_rt_node_ptr);
00050 
00051 static void load_new_path_R_upstream(t_rt_node * start_of_new_path_rt_node);
00052 
00053 static t_rt_node *update_unbuffered_ancestors_C_downstream(t_rt_node
00054                                                            *
00055                                                            start_of_new_path_rt_node);
00056 
00057 static void load_rt_subtree_Tdel(t_rt_node * subtree_rt_root,
00058                                  float Tarrival);
00059 
00060 
00061 
00062 /************************** Subroutine definitions ***************************/
00063 
00064 /** Allocates any structures needed to build the routing trees. */
00065 void
00066 alloc_route_tree_timing_structs(void)
00067 {
00068     if(rr_node_to_rt_node != NULL || rt_node_free_list != NULL ||
00069        rt_node_free_list != NULL)
00070         {
00071             printf("Error in alloc_route_tree_timing_structs: old structures "
00072                    "already exist.\n");
00073             exit(1);
00074         }
00075 
00076     rr_node_to_rt_node = (t_rt_node **) my_malloc(num_rr_nodes *
00077                                                   sizeof(t_rt_node *));
00078 }
00079 
00080 /** Frees the structures needed to build routing trees, and really frees      
00081  * (i.e. calls free) all the data on the free lists.                         
00082  */
00083 void
00084 free_route_tree_timing_structs(void)
00085 {
00086     t_rt_node *rt_node, *next_node;
00087     t_linked_rt_edge *rt_edge, *next_edge;
00088 
00089     free(rr_node_to_rt_node);
00090     rr_node_to_rt_node = NULL;
00091 
00092     rt_node = rt_node_free_list;
00093 
00094     while(rt_node != NULL)
00095         {
00096             next_node = rt_node->u.next;
00097             free(rt_node);
00098             rt_node = next_node;
00099         }
00100 
00101     rt_node_free_list = NULL;
00102 
00103     rt_edge = rt_edge_free_list;
00104 
00105     while(rt_edge != NULL)
00106         {
00107             next_edge = rt_edge->next;
00108             free(rt_edge);
00109             rt_edge = next_edge;
00110         }
00111 
00112     rt_edge_free_list = NULL;
00113 }
00114 
00115 /** Allocates a new rt_node, from the free list if possible, from the free   
00116  * store otherwise.                                                         
00117  */
00118 static t_rt_node *
00119 alloc_rt_node(void)
00120 {
00121     t_rt_node *rt_node;
00122 
00123     rt_node = rt_node_free_list;
00124 
00125     if(rt_node != NULL)
00126         {
00127             rt_node_free_list = rt_node->u.next;
00128         }
00129     else
00130         {
00131             rt_node = (t_rt_node *) my_malloc(sizeof(t_rt_node));
00132         }
00133 
00134     return (rt_node);
00135 }
00136 
00137 
00138 /** Adds rt_node to the proper free list.          */
00139 static void
00140 free_rt_node(t_rt_node * rt_node)
00141 {
00142     rt_node->u.next = rt_node_free_list;
00143     rt_node_free_list = rt_node;
00144 }
00145 
00146 /** Allocates a new linked_rt_edge, from the free list if possible, from the  
00147  * free store otherwise.                                                     
00148  */
00149 static t_linked_rt_edge *
00150 alloc_linked_rt_edge(void)
00151 {
00152     t_linked_rt_edge *linked_rt_edge;
00153 
00154     linked_rt_edge = rt_edge_free_list;
00155 
00156     if(linked_rt_edge != NULL)
00157         {
00158             rt_edge_free_list = linked_rt_edge->next;
00159         }
00160     else
00161         {
00162             linked_rt_edge = (t_linked_rt_edge *) my_malloc(sizeof
00163                                                             (t_linked_rt_edge));
00164         }
00165 
00166     return (linked_rt_edge);
00167 }
00168 
00169 
00170 /** Adds the rt_edge to the rt_edge free list.                       */
00171 static void
00172 free_linked_rt_edge(t_linked_rt_edge * rt_edge)
00173 {
00174     rt_edge->next = rt_edge_free_list;
00175     rt_edge_free_list = rt_edge;
00176 }
00177 
00178 /** Initializes the routing tree to just the net source, and returns the root 
00179  * node of the rt_tree (which is just the net source).                       
00180  */
00181 t_rt_node *
00182 init_route_tree_to_source(int inet)
00183 {
00184     t_rt_node *rt_root;
00185     int inode;
00186 
00187     rt_root = alloc_rt_node();
00188     rt_root->u.child_list = NULL;
00189     rt_root->parent_node = NULL;
00190     rt_root->parent_switch = OPEN;
00191     rt_root->re_expand = TRUE;
00192 
00193     inode = net_rr_terminals[inet][0];  /* Net source */
00194 
00195     rt_root->inode = inode;
00196     rt_root->C_downstream = rr_node[inode].C;
00197     rt_root->R_upstream = rr_node[inode].R;
00198     rt_root->Tdel = 0.5 * rr_node[inode].R * rr_node[inode].C;
00199     rr_node_to_rt_node[inode] = rt_root;
00200 
00201     return (rt_root);
00202 }
00203 
00204 /** Adds the most recently finished wire segment to the routing tree, and    
00205  * updates the Tdel, etc. numbers for the rest of the routing tree.  hptr   
00206  * is the heap pointer of the SINK that was reached.  This routine returns  
00207  * a pointer to the rt_node of the SINK that it adds to the routing.        
00208  */
00209 t_rt_node *
00210 update_route_tree(struct s_heap * hptr)
00211 {
00212 
00213     t_rt_node *start_of_new_path_rt_node, *sink_rt_node;
00214     t_rt_node *unbuffered_subtree_rt_root, *subtree_parent_rt_node;
00215     float Tdel_start;
00216     short iswitch;
00217 
00218     start_of_new_path_rt_node = add_path_to_route_tree(hptr, &sink_rt_node);
00219     load_new_path_R_upstream(start_of_new_path_rt_node);
00220     unbuffered_subtree_rt_root =
00221         update_unbuffered_ancestors_C_downstream(start_of_new_path_rt_node);
00222 
00223     subtree_parent_rt_node = unbuffered_subtree_rt_root->parent_node;
00224 
00225     if(subtree_parent_rt_node != NULL)
00226         {                       /* Parent exists. */
00227             Tdel_start = subtree_parent_rt_node->Tdel;
00228             iswitch = unbuffered_subtree_rt_root->parent_switch;
00229             Tdel_start += switch_inf[iswitch].R *
00230                 unbuffered_subtree_rt_root->C_downstream;
00231             Tdel_start += switch_inf[iswitch].Tdel;
00232         }
00233     else
00234         {                       /* Subtree starts at SOURCE */
00235             Tdel_start = 0.;
00236         }
00237 
00238     load_rt_subtree_Tdel(unbuffered_subtree_rt_root, Tdel_start);
00239 
00240     return (sink_rt_node);
00241 }
00242 
00243 /** Adds the most recent wire segment, ending at the SINK indicated by hptr, 
00244  * to the routing tree.  It returns the first (most upstream) new rt_node,  
00245  * and (via a pointer) the rt_node of the new SINK.                         
00246  */
00247 static t_rt_node *
00248 add_path_to_route_tree(struct s_heap *hptr,
00249                        t_rt_node ** sink_rt_node_ptr)
00250 {
00251     int inode, remaining_connections_to_sink;
00252     short iedge, iswitch;
00253     float C_downstream;
00254     t_rt_node *rt_node, *downstream_rt_node, *sink_rt_node;
00255     t_linked_rt_edge *linked_rt_edge;
00256 
00257 
00258     inode = hptr->index;
00259 
00260 #ifdef DEBUG
00261     if(rr_node[inode].type != SINK)
00262         {
00263             printf
00264                 ("Error in add_path_to_route_tree.  Expected type = SINK (%d).\n",
00265                  SINK);
00266             printf("Got type = %d.", rr_node[inode].type);
00267             exit(1);
00268         }
00269 #endif
00270 
00271     remaining_connections_to_sink = rr_node_route_inf[inode].target_flag;
00272     sink_rt_node = alloc_rt_node();
00273     sink_rt_node->u.child_list = NULL;
00274     sink_rt_node->inode = inode;
00275     C_downstream = rr_node[inode].C;
00276     sink_rt_node->C_downstream = C_downstream;
00277     rr_node_to_rt_node[inode] = sink_rt_node;
00278 
00279 /* In the code below I'm marking SINKs and IPINs as not to be re-expanded.  *
00280  * Undefine NO_ROUTE_THROUGHS if you want route-throughs or ipin doglegs.   *
00281  * It makes the code more efficient (though not vastly) to prune this way   *
00282  * when there aren't route-throughs or ipin doglegs.                        */
00283 
00284 #define NO_ROUTE_THROUGHS 1     /* Can't route through unused CLB outputs */
00285 
00286 #ifdef NO_ROUTE_THROUGHS
00287     sink_rt_node->re_expand = FALSE;
00288 #else
00289     if(remaining_connections_to_sink == 0)
00290         {                       /* Usual case */
00291             sink_rt_node->re_expand = TRUE;
00292         }
00293 
00294     /* Weird case.  This net connects several times to the same SINK.  Thus I   *
00295      * can't re_expand this node as part of the partial routing for subsequent  *
00296      * connections, since I need to reach it again via another path.            */
00297 
00298     else
00299         {
00300             sink_rt_node->re_expand = FALSE;
00301         }
00302 #endif
00303 
00304 
00305 /* Now do it's predecessor. */
00306 
00307     downstream_rt_node = sink_rt_node;
00308     inode = hptr->u.prev_node;
00309     iedge = hptr->prev_edge;
00310     iswitch = rr_node[inode].switches[iedge];
00311 
00312 /* For all "new" nodes in the path */
00313 
00314     while(rr_node_route_inf[inode].prev_node != NO_PREVIOUS)
00315         {
00316             linked_rt_edge = alloc_linked_rt_edge();
00317             linked_rt_edge->child = downstream_rt_node;
00318             linked_rt_edge->iswitch = iswitch;
00319             linked_rt_edge->next = NULL;
00320 
00321             rt_node = alloc_rt_node();
00322             downstream_rt_node->parent_node = rt_node;
00323             downstream_rt_node->parent_switch = iswitch;
00324 
00325             rt_node->u.child_list = linked_rt_edge;
00326             rt_node->inode = inode;
00327 
00328             if(switch_inf[iswitch].buffered == FALSE)
00329                 C_downstream += rr_node[inode].C;
00330             else
00331                 C_downstream = rr_node[inode].C;
00332 
00333             rt_node->C_downstream = C_downstream;
00334             rr_node_to_rt_node[inode] = rt_node;
00335 
00336 #ifdef NO_ROUTE_THROUGHS
00337             if(rr_node[inode].type == IPIN)
00338                 rt_node->re_expand = FALSE;
00339             else
00340                 rt_node->re_expand = TRUE;
00341 
00342 #else
00343             if(remaining_connections_to_sink == 0)
00344                 {               /* Normal case */
00345                     rt_node->re_expand = TRUE;
00346                 }
00347             else
00348                 {               /* This is the IPIN before a multiply-connected SINK */
00349                     rt_node->re_expand = FALSE;
00350 
00351                     /* Reset flag so wire segments get reused */
00352 
00353                     remaining_connections_to_sink = 0;
00354                 }
00355 #endif
00356 
00357             downstream_rt_node = rt_node;
00358             iedge = rr_node_route_inf[inode].prev_edge;
00359             inode = rr_node_route_inf[inode].prev_node;
00360             iswitch = rr_node[inode].switches[iedge];
00361         }
00362 
00363 /* Inode is the join point to the old routing */
00364 
00365     rt_node = rr_node_to_rt_node[inode];
00366 
00367     linked_rt_edge = alloc_linked_rt_edge();
00368     linked_rt_edge->child = downstream_rt_node;
00369     linked_rt_edge->iswitch = iswitch;
00370     linked_rt_edge->next = rt_node->u.child_list;
00371     rt_node->u.child_list = linked_rt_edge;
00372 
00373     downstream_rt_node->parent_node = rt_node;
00374     downstream_rt_node->parent_switch = iswitch;
00375 
00376     *sink_rt_node_ptr = sink_rt_node;
00377     return (downstream_rt_node);
00378 }
00379 
00380 /** Sets the R_upstream values of all the nodes in the new path to the       
00381  * correct value.                                                           
00382  */
00383 static void
00384 load_new_path_R_upstream(t_rt_node * start_of_new_path_rt_node)
00385 {
00386 
00387     float R_upstream;
00388     int inode;
00389     short iswitch;
00390     t_rt_node *rt_node, *parent_rt_node;
00391     t_linked_rt_edge *linked_rt_edge;
00392 
00393     rt_node = start_of_new_path_rt_node;
00394     iswitch = rt_node->parent_switch;
00395     inode = rt_node->inode;
00396     parent_rt_node = rt_node->parent_node;
00397 
00398     R_upstream = switch_inf[iswitch].R + rr_node[inode].R;
00399 
00400     if(switch_inf[iswitch].buffered == FALSE)
00401         R_upstream += parent_rt_node->R_upstream;
00402 
00403     rt_node->R_upstream = R_upstream;
00404 
00405 /* Note:  the traversal below makes use of the fact that this new path      *
00406  * really is a path (not a tree with branches) to do a traversal without    *
00407  * recursion, etc.                                                          */
00408 
00409     linked_rt_edge = rt_node->u.child_list;
00410 
00411     while(linked_rt_edge != NULL)
00412         {                       /* While SINK not reached. */
00413 
00414 #ifdef DEBUG
00415             if(linked_rt_edge->next != NULL)
00416                 {
00417                     printf
00418                         ("Error in load_new_path_R_upstream: new routing addition is\n"
00419                          "a tree (not a path).\n");
00420                     exit(1);
00421                 }
00422 #endif
00423 
00424             rt_node = linked_rt_edge->child;
00425             iswitch = linked_rt_edge->iswitch;
00426             inode = rt_node->inode;
00427 
00428             if(switch_inf[iswitch].buffered)
00429                 R_upstream = switch_inf[iswitch].R + rr_node[inode].R;
00430             else
00431                 R_upstream += switch_inf[iswitch].R + rr_node[inode].R;
00432 
00433             rt_node->R_upstream = R_upstream;
00434             linked_rt_edge = rt_node->u.child_list;
00435         }
00436 }
00437 
00438 /** Updates the C_downstream values for the ancestors of the new path.  Once 
00439  * a buffered switch is found amongst the ancestors, no more ancestors are  
00440  * affected.  Returns the root of the "unbuffered subtree" whose Tdel       
00441  * values are affected by the new path's addition.                          
00442  */
00443 static t_rt_node *
00444 update_unbuffered_ancestors_C_downstream(t_rt_node
00445                                          * start_of_new_path_rt_node)
00446 {
00447 
00448     t_rt_node *rt_node, *parent_rt_node;
00449     short iswitch;
00450     float C_downstream_addition;
00451 
00452     rt_node = start_of_new_path_rt_node;
00453     C_downstream_addition = rt_node->C_downstream;
00454     parent_rt_node = rt_node->parent_node;
00455     iswitch = rt_node->parent_switch;
00456 
00457     while(parent_rt_node != NULL && switch_inf[iswitch].buffered == FALSE)
00458         {
00459             rt_node = parent_rt_node;
00460             rt_node->C_downstream += C_downstream_addition;
00461             parent_rt_node = rt_node->parent_node;
00462             iswitch = rt_node->parent_switch;
00463         }
00464 
00465     return (rt_node);
00466 }
00467 
00468 /** Updates the Tdel values of the subtree rooted at subtree_rt_root by      
00469  * by calling itself recursively.  The C_downstream values of all the nodes 
00470  * must be correct before this routine is called.  Tarrival is the time at  
00471  * at which the signal arrives at this node's *input*.                      
00472  */
00473 static void
00474 load_rt_subtree_Tdel(t_rt_node * subtree_rt_root,
00475                      float Tarrival)
00476 {
00477     int inode;
00478     short iswitch;
00479     t_rt_node *child_node;
00480     t_linked_rt_edge *linked_rt_edge;
00481     float Tdel, Tchild;
00482 
00483     inode = subtree_rt_root->inode;
00484 
00485 /* Assuming the downstream connections are, on average, connected halfway    *
00486  * along a wire segment's length.  See discussion in net_delay.c if you want *
00487  * to change this.                                                           */
00488 
00489     Tdel = Tarrival + 0.5 * subtree_rt_root->C_downstream * rr_node[inode].R;
00490     subtree_rt_root->Tdel = Tdel;
00491 
00492 /* Now expand the children of this node to load their Tdel values (depth-   *
00493  * first pre-order traversal).                                              */
00494 
00495     linked_rt_edge = subtree_rt_root->u.child_list;
00496 
00497     while(linked_rt_edge != NULL)
00498         {
00499             iswitch = linked_rt_edge->iswitch;
00500             child_node = linked_rt_edge->child;
00501 
00502             Tchild = Tdel + switch_inf[iswitch].R * child_node->C_downstream;
00503             Tchild += switch_inf[iswitch].Tdel; /* Intrinsic switch delay. */
00504             load_rt_subtree_Tdel(child_node, Tchild);
00505 
00506             linked_rt_edge = linked_rt_edge->next;
00507         }
00508 }
00509 
00510 /** Puts the rt_nodes and edges in the tree rooted at rt_node back on the    
00511  * free lists.  Recursive, depth-first post-order traversal.                
00512  */
00513 void
00514 free_route_tree(t_rt_node * rt_node)
00515 {
00516 
00517     t_rt_node *child_node;
00518     t_linked_rt_edge *rt_edge, *next_edge;
00519 
00520     rt_edge = rt_node->u.child_list;
00521 
00522     while(rt_edge != NULL)
00523         {                       /* For all children */
00524             child_node = rt_edge->child;
00525             free_route_tree(child_node);
00526             next_edge = rt_edge->next;
00527             free_linked_rt_edge(rt_edge);
00528             rt_edge = next_edge;
00529         }
00530 
00531     free_rt_node(rt_node);
00532 }
00533 
00534 /** Goes through all the sinks of this net and copies their delay values from
00535  * the route_tree to the net_delay array.                                    
00536  */
00537 void
00538 update_net_delays_from_route_tree(float *net_delay,
00539                                   t_rt_node ** rt_node_of_sink,
00540                                   int inet)
00541 {
00542 
00543     int isink;
00544     t_rt_node *sink_rt_node;
00545 
00546     for(isink = 1; isink <= clb_net[inet].num_sinks; isink++)
00547         {
00548             sink_rt_node = rt_node_of_sink[isink];
00549             net_delay[isink] = sink_rt_node->Tdel;
00550         }
00551 }