VPR-6.0
|
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 }