VPR-6.0
|
00001 #include <stdio.h> 00002 #include <assert.h> 00003 #include <sys/types.h> 00004 #include <time.h> 00005 00006 #include "heapsort.h" 00007 #include "util.h" 00008 #include "vpr_types.h" 00009 #include "globals.h" 00010 #include "mst.h" 00011 #include "route_export.h" 00012 #include "route_common.h" 00013 #include "route_directed_search.h" 00014 #include "stats.h" 00015 #include "draw.h" 00016 00017 00018 /********************* Subroutines local to this module *********************/ 00019 00020 static boolean directed_search_route_net(int inet, 00021 float pres_fac, 00022 float astar_fac, 00023 float bend_cost, 00024 t_mst_edge ** mst); 00025 00026 static int directed_search_expand_trace_segment(struct s_trace *start_ptr, 00027 int target_node, 00028 float astar_fac, 00029 int inet, 00030 int remaining_connections_to_sink); 00031 00032 static void directed_search_expand_neighbours(struct s_heap *current, 00033 int inet, 00034 float bend_cost, 00035 int target_node, 00036 int highfanout_rlim, 00037 float astar_fac); 00038 00039 static void directed_search_add_source_to_heap(int inet, 00040 int target_node, 00041 float astar_fac); 00042 00043 static float get_directed_search_expected_cost(int inode, 00044 int target_node); 00045 00046 static int get_expected_segs_to_target(int inode, 00047 int target_node, 00048 int *num_segs_ortho_dir_ptr); 00049 00050 /************************ Subroutine definitions ****************************/ 00051 00052 /** Iterated maze router ala Pathfinder Negotiated Congestion algorithm, 00053 * (FPGA 95 p. 111). Returns TRUE if it can route this FPGA, FALSE if 00054 * it can't. 00055 */ 00056 boolean 00057 try_directed_search_route(struct s_router_opts router_opts, 00058 t_ivec ** clb_opins_used_locally, 00059 int width_fac, 00060 t_mst_edge ** mst) 00061 { 00062 00063 float pres_fac; 00064 boolean success, is_routable, rip_up_local_opins; 00065 int itry, inet, i; 00066 clock_t begin, end; 00067 00068 int bends; 00069 int wirelength, total_wirelength, available_wirelength; 00070 int segments; 00071 00072 float *sinks; 00073 int *net_index; 00074 00075 sinks = my_malloc(sizeof(float) * num_nets); 00076 net_index = my_malloc(sizeof(int) * num_nets); 00077 for(i = 0; i < num_nets; i++) { 00078 sinks[i] = clb_net[i].num_sinks; 00079 net_index[i] = i; 00080 } 00081 heapsort(net_index, sinks, num_nets, 1); 00082 00083 /* char msg[100]; */ 00084 00085 begin = clock(); 00086 00087 /* mst not built as good as it should, ideally, just have it after placement once only 00088 however, rr_node numbers changed when the channel width changes so forced to do it here */ 00089 if(mst) 00090 { 00091 for(inet = 0; inet < num_nets; inet++) 00092 { 00093 free(mst[inet]); 00094 mst[inet] = get_mst_of_net(inet); 00095 } 00096 } 00097 00098 end = clock(); 00099 #ifdef CLOCKS_PER_SEC 00100 printf("mst took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); 00101 #else 00102 printf("mst took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); 00103 #endif 00104 00105 00106 /* Usually the first iteration uses a very small (or 0) pres_fac to find * 00107 * the shortest path and get a congestion map. For fast compiles, I set * 00108 * pres_fac high even for the first iteration. */ 00109 00110 pres_fac = router_opts.first_iter_pres_fac; 00111 00112 for(itry = 1; itry <= router_opts.max_router_iterations; itry++) 00113 { 00114 begin = clock(); 00115 00116 printf("routing iteration %d\n", itry); 00117 for(i = 0; i < num_nets; i++) 00118 { 00119 inet = net_index[i]; 00120 if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0) 00121 { /* Skip global nets and empty nets (empty nets are already reserved using reserve_locally_used_opins). */ 00122 is_routable = 00123 directed_search_route_net(inet, pres_fac, 00124 router_opts. 00125 astar_fac, 00126 router_opts. 00127 bend_cost, mst); 00128 00129 /* Impossible to route? (disconnected rr_graph) */ 00130 00131 if(!is_routable) 00132 { 00133 printf("Routing failed.\n"); 00134 free(net_index); 00135 free(sinks); 00136 return (FALSE); 00137 } 00138 00139 } 00140 } 00141 end = clock(); 00142 #ifdef CLOCKS_PER_SEC 00143 printf("routing iteration took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); 00144 #else 00145 printf("routing iteration took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); 00146 #endif 00147 fflush(stdout); 00148 00149 if(itry == 1) { 00150 /* Early exit code for cases where it is obvious that a successful route will not be found 00151 Heuristic: If total wirelength used in first routing iteration is X% of total available wirelength, exit 00152 */ 00153 total_wirelength = 0; 00154 available_wirelength = 0; 00155 00156 for(i = 0; i < num_rr_nodes; i++) { 00157 if(rr_node[i].type == CHANX || rr_node[i].type == CHANY) 00158 { 00159 available_wirelength += 1 + rr_node[i].xhigh - rr_node[i].xlow + 00160 rr_node[i].yhigh - rr_node[i].ylow; 00161 } 00162 } 00163 00164 for(inet = 0; inet < num_nets; inet++) 00165 { 00166 if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0) 00167 { /* Globals don't count. */ 00168 get_num_bends_and_length(inet, &bends, &wirelength, 00169 &segments); 00170 00171 total_wirelength += wirelength; 00172 } 00173 } 00174 printf("wirelength after first iteration %d, total available wirelength %d, ratio %g\n", total_wirelength, available_wirelength, (float)(total_wirelength)/(float)(available_wirelength)); 00175 if((float)(total_wirelength)/(float)(available_wirelength) > FIRST_ITER_WIRELENTH_LIMIT) { 00176 printf("Wirelength usage ratio exceeds limit of %g, fail routing\n", FIRST_ITER_WIRELENTH_LIMIT); 00177 free(net_index); 00178 free(sinks); 00179 return FALSE; 00180 } 00181 } 00182 00183 00184 /* Make sure any CLB OPINs used up by subblocks being hooked directly * 00185 * to them are reserved for that purpose. */ 00186 00187 if(itry == 1) 00188 rip_up_local_opins = FALSE; 00189 else 00190 rip_up_local_opins = TRUE; 00191 00192 reserve_locally_used_opins(pres_fac, rip_up_local_opins, 00193 clb_opins_used_locally); 00194 00195 success = feasible_routing(); 00196 if(success) 00197 { 00198 printf 00199 ("Successfully routed after %d routing iterations by Directed Search.\n", 00200 itry); 00201 free(net_index); 00202 free(sinks); 00203 return (TRUE); 00204 } 00205 #if 0 00206 else 00207 { 00208 sprintf(msg, 00209 "After iteration %d routing failed (A*) with a channel width factor of %d and Fc_int of %d, Fs_int of %d.", 00210 itry, width_fac, Fc_int, Fs_int); 00211 init_draw_coords(pins_per_clb); 00212 update_screen(MAJOR, msg, ROUTING, FALSE); 00213 } 00214 #endif 00215 00216 00217 if(itry == 1) 00218 { 00219 pres_fac = router_opts.initial_pres_fac; 00220 pathfinder_update_cost(pres_fac, 0.); /* Acc_fac=0 for first iter. */ 00221 } 00222 else 00223 { 00224 pres_fac *= router_opts.pres_fac_mult; 00225 pathfinder_update_cost(pres_fac, router_opts.acc_fac); 00226 } 00227 00228 } 00229 00230 printf("Routing failed.\n"); 00231 free(sinks); 00232 free(net_index); 00233 00234 return (FALSE); 00235 } 00236 00237 00238 /** Uses a maze routing (Dijkstra's) algorithm to route a net. The net 00239 * begins at the net output, and expands outward until it hits a target 00240 * pin. The algorithm is then restarted with the entire first wire segment 00241 * included as part of the source this time. For an n-pin net, the maze 00242 * router is invoked n-1 times to complete all the connections. Inet is 00243 * the index of the net to be routed. Bends are penalized by bend_cost 00244 * (which is typically zero for detailed routing and nonzero only for global 00245 * routing), since global routes with lots of bends are tougher to detailed 00246 * route (using a detailed router like SEGA). 00247 * If this routine finds that a net *cannot* be connected (due to a complete 00248 * lack of potential paths, rather than congestion), it returns FALSE, as 00249 * routing is impossible on this architecture. Otherwise it returns TRUE. 00250 */ 00251 /** WMF: This is the directed search (A-star) version of maze router. */ 00252 static boolean 00253 directed_search_route_net(int inet, 00254 float pres_fac, 00255 float astar_fac, 00256 float bend_cost, 00257 t_mst_edge ** mst) 00258 { 00259 00260 int inode, remaining_connections_to_sink; 00261 int itarget, target_pin, target_node; 00262 struct s_heap *current; 00263 struct s_trace *new_route_start_tptr; 00264 float old_tcost, new_tcost, old_back_cost, new_back_cost; 00265 int highfanout_rlim; 00266 00267 assert(mst); 00268 00269 /* Rip-up any old routing. */ 00270 /* WMF: For the 1st router iteration trace_head[inet] is NULL, as it is 00271 * my_calloc'ed in alloc_route_structs() so the following does nothing. 00272 * However, for subsequent iterations, trace_head[inet] contains the previous 00273 * ieration's routing for this net. */ 00274 pathfinder_update_one_cost(trace_head[inet], -1, pres_fac); 00275 free_traceback(inet); /* kills trace, and set the trace head and tail to NULL */ 00276 00277 /* adding the SOURCE node to the heap with correct total cost */ 00278 target_pin = mst[inet][0].to_node; 00279 target_node = net_rr_terminals[inet][target_pin]; 00280 directed_search_add_source_to_heap(inet, target_node, astar_fac); 00281 00282 mark_ends(inet); 00283 00284 remaining_connections_to_sink = 0; 00285 00286 for(itarget = 0; itarget < clb_net[inet].num_sinks; itarget++) 00287 { 00288 target_pin = mst[inet][itarget].to_node; 00289 target_node = net_rr_terminals[inet][target_pin]; 00290 00291 /* printf ("Target #%d, pin number %d, target_node: %d.\n", 00292 * itarget, target_pin, target_node); */ 00293 00294 /* WMF: since the heap has been emptied, need to restart the wavefront 00295 * from the current partial routing, starting at the trace_head (SOURCE) 00296 * Note: in the 1st iteration, there is no trace (no routing at all for this net) 00297 * i.e. trace_head[inet] == NULL (found in free_traceback() in route_common.c, 00298 * which is called before the routing of any net), 00299 * so this routine does nothing, but the heap does have the SOURCE node due 00300 * to directed_search_add_source_to_heap (inet) before the loop */ 00301 highfanout_rlim = directed_search_expand_trace_segment(trace_head[inet], 00302 target_node, astar_fac, inet, 00303 remaining_connections_to_sink); 00304 00305 current = get_heap_head(); 00306 00307 if(current == NULL) 00308 { /* Infeasible routing. No possible path for net. */ 00309 reset_path_costs(); /* Clean up before leaving. */ 00310 return (FALSE); 00311 } 00312 00313 inode = current->index; 00314 00315 while(inode != target_node) 00316 { 00317 old_tcost = rr_node_route_inf[inode].path_cost; 00318 new_tcost = current->cost; 00319 00320 /* WMF: not needed if Vaughn initialized rr_node_route_inf[inode].backward_path_cost 00321 * to HUGE_FLOAT along with rr_node_route_inf[inode].path_cost */ 00322 if(old_tcost > 0.99 * HUGE_FLOAT) /* First time touched. */ 00323 old_back_cost = HUGE_FLOAT; 00324 else 00325 old_back_cost = 00326 rr_node_route_inf[inode].backward_path_cost; 00327 00328 new_back_cost = current->backward_path_cost; 00329 00330 /* I only re-expand a node if both the "known" backward cost is lower * 00331 * in the new expansion (this is necessary to prevent loops from * 00332 * forming in the routing and causing havoc) *and* the expected total * 00333 * cost to the sink is lower than the old value. Different R_upstream * 00334 * values could make a path with lower back_path_cost less desirable * 00335 * than one with higher cost. Test whether or not I should disallow * 00336 * re-expansion based on a higher total cost. */ 00337 00338 /* updating the maze (Dijktra's min dist algorithm) if found "shorter" path */ 00339 if(old_tcost > new_tcost && old_back_cost > new_back_cost) 00340 { 00341 /* if (old_tcost > new_tcost) { */ 00342 rr_node_route_inf[inode].prev_node = 00343 current->u.prev_node; 00344 rr_node_route_inf[inode].prev_edge = 00345 current->prev_edge; 00346 rr_node_route_inf[inode].path_cost = new_tcost; 00347 rr_node_route_inf[inode].backward_path_cost = 00348 new_back_cost; 00349 00350 if(old_tcost > 0.99 * HUGE_FLOAT) /* First time touched. */ 00351 add_to_mod_list(&rr_node_route_inf[inode]. 00352 path_cost); 00353 00354 directed_search_expand_neighbours(current, inet, 00355 bend_cost, 00356 target_node, 00357 highfanout_rlim, 00358 astar_fac); 00359 } 00360 00361 free_heap_data(current); 00362 current = get_heap_head(); 00363 00364 if(current == NULL) 00365 { /* Impossible routing. No path for net. */ 00366 printf("Failed to route net %s #%d pin %d num_sinks %d highfanout_rlim %d\n", clb_net[inet].name, inet, itarget, clb_net[inet].num_sinks, highfanout_rlim); 00367 reset_path_costs(); 00368 return (FALSE); 00369 } 00370 00371 inode = current->index; 00372 } 00373 00374 rr_node_route_inf[inode].target_flag--; /* Connected to this SINK. */ 00375 remaining_connections_to_sink = 00376 rr_node_route_inf[inode].target_flag; 00377 00378 /* keep info on the current routing of this net */ 00379 new_route_start_tptr = update_traceback(current, inet); 00380 00381 free_heap_data(current); 00382 /* update the congestion costs of rr_nodes due to the routing to this sink 00383 * so only those nodes used in the partial routing of this sink and not 00384 * of the entire net (remember we're in a loop for this net over its sinks) */ 00385 pathfinder_update_one_cost(new_route_start_tptr, 1, pres_fac); 00386 00387 /* WMF: MUST empty heap and recalculate all total costs, because 00388 * for the next sink, the target destination is changed, so the expected 00389 * cost calculation is changed also, meaning all the nodes on the heap have 00390 * "stale" total costs (costs based on last sink). */ 00391 empty_heap(); 00392 reset_path_costs(); 00393 } 00394 00395 return (TRUE); 00396 } 00397 00398 /** Adds all the rr_nodes in the entire traceback from SOURCE to all SINKS 00399 * routed so far (partial routing). 00400 * This allows expansion to begin from the existing wiring. The 00401 * remaining_connections_to_sink value is 0 if the route segment ending 00402 * at this location is the last one to connect to the SINK ending the route 00403 * segment. This is the usual case. If it is not the last connection this 00404 * net must make to this SINK, I have a hack to ensure the next connection 00405 * to this SINK goes through a different IPIN. Without this hack, the 00406 * router would always put all the connections from this net to this SINK 00407 * through the same IPIN. With LUTs or cluster-based logic blocks, you 00408 * should never have a net connecting to two logically-equivalent pins on 00409 * the same logic block, so the hack will never execute. If your logic 00410 * block is an and-gate, however, nets might connect to two and-inputs on 00411 * the same logic block, and since the and-inputs are logically-equivalent, 00412 * this means two connections to the same SINK. 00413 * 00414 * For high-fanout nets, return the radius of the expansion bin, 00415 * undefined otherwise 00416 */ 00417 static int 00418 directed_search_expand_trace_segment(struct s_trace *start_ptr, 00419 int target_node, 00420 float astar_fac, 00421 int inet, 00422 int remaining_connections_to_sink) 00423 { 00424 00425 struct s_trace *tptr; 00426 int inode, backward_path_cost, tot_cost; 00427 int target_x, target_y; 00428 int rlim, area; 00429 boolean success; 00430 00431 target_x = rr_node[target_node].xhigh; 00432 target_y = rr_node[target_node].yhigh; 00433 00434 area = (route_bb[inet].xmax - route_bb[inet].xmin) * (route_bb[inet].ymax - route_bb[inet].ymin); 00435 if(area <= 0) { 00436 area = 1; 00437 } 00438 00439 if(clb_net[inet].num_sinks < HIGH_FANOUT_NET_LIM) { 00440 rlim = 1; 00441 } else { 00442 rlim = ceil(sqrt((float)area / (float)clb_net[inet].num_sinks)); 00443 if(start_ptr == NULL) { 00444 /* For first node, route normally since there is nothing in the current traceback path */ 00445 rlim = max(nx + 2, ny + 2); 00446 } 00447 } 00448 success = FALSE; 00449 /* determine quickly a feasible bin radius to route sink for high fanout nets 00450 this is necessary to prevent super long runtimes for high fanout nets; in best case, a reduction in complexity from O(N^2logN) to O(NlogN) (Swartz fast router) 00451 */ 00452 while(success == FALSE && start_ptr != NULL) { 00453 tptr = start_ptr; 00454 while(tptr != NULL && success == FALSE) 00455 { 00456 inode = tptr->index; 00457 if(!(rr_node[inode].type == IPIN || rr_node[inode].type == SINK)) { 00458 if( clb_net[inet].num_sinks < HIGH_FANOUT_NET_LIM || 00459 (rr_node[inode].xlow <= target_x + rlim && 00460 rr_node[inode].xhigh >= target_x - rlim && 00461 rr_node[inode].ylow <= target_y + rlim && 00462 rr_node[inode].yhigh >= target_y - rlim)) { 00463 success = TRUE; 00464 } 00465 } 00466 tptr = tptr->next; 00467 } 00468 00469 if(success == FALSE) { 00470 if(rlim > max(nx + 2, ny + 2)) { 00471 printf(ERRTAG "VPR internal error, net %s has paths that are not found in traceback\n", clb_net[inet].name); 00472 exit(1); 00473 } 00474 /* if sink not in bin, increase bin size until fit */ 00475 rlim *= 2; 00476 } else { 00477 /* Sometimes might just catch a wire in the end segment, need to give it some channel space to explore */ 00478 rlim += 4; 00479 } 00480 } 00481 00482 if(remaining_connections_to_sink == 0) 00483 { /* Usual case. */ 00484 tptr = start_ptr; 00485 while(tptr != NULL) 00486 { 00487 /* WMF: partial routing is added to the heap with path cost of 0, because 00488 * new extension to the next sink can start at any point on current partial 00489 * routing. However, for directed search the total cost must be made to favor 00490 * the points of current partial routing that are NEAR the next sink (target sink) */ 00491 00492 /* WMF: IPINs and SINKs should be excluded from the heap in this 00493 * since they NEVER connect TO any rr_node (no to_edges), but since they have 00494 * no to_edges, it's ok (ROUTE_THROUGHS are disabled). To clarify, see 00495 * rr_graph.c to find out rr_node[inode].num_edges = 0 for SINKs and 00496 * rr_node[inode].num_edges = 1 for INPINs */ 00497 00498 inode = tptr->index; 00499 if(! 00500 (rr_node[inode].type == IPIN 00501 || rr_node[inode].type == SINK)) 00502 { 00503 if( clb_net[inet].num_sinks < HIGH_FANOUT_NET_LIM || 00504 (rr_node[inode].xlow <= target_x + rlim && 00505 rr_node[inode].xhigh >= target_x - rlim && 00506 rr_node[inode].ylow <= target_y + rlim && 00507 rr_node[inode].yhigh >= target_y - rlim)) { 00508 backward_path_cost = 0; 00509 tot_cost = 00510 backward_path_cost + 00511 astar_fac * 00512 get_directed_search_expected_cost(inode, 00513 target_node); 00514 node_to_heap(inode, tot_cost, NO_PREVIOUS, 00515 NO_PREVIOUS, backward_path_cost, 00516 OPEN); 00517 } 00518 } 00519 00520 tptr = tptr->next; 00521 } 00522 } 00523 else 00524 { /* This case never executes for most logic blocks. */ 00525 printf("Warning: Multiple connections from net to the same sink. " 00526 "This should not happen for LUT/Cluster based logic blocks. Aborting.\n"); 00527 exit(1); 00528 } 00529 return rlim; 00530 } 00531 00532 /** Puts all the rr_nodes adjacent to current on the heap. rr_nodes outside 00533 * the expanded bounding box specified in route_bb are not added to the 00534 * heap. back_cost is the path_cost to get to inode. total cost i.e. 00535 * tot_cost is path_cost + (expected_cost to target sink) 00536 */ 00537 static void 00538 directed_search_expand_neighbours(struct s_heap *current, 00539 int inet, 00540 float bend_cost, 00541 int target_node, 00542 int highfanout_rlim, 00543 float astar_fac) 00544 { 00545 00546 int iconn, to_node, num_edges, inode, target_x, target_y; 00547 t_rr_type from_type, to_type; 00548 float new_tot_cost, old_back_pcost, new_back_pcost; 00549 00550 inode = current->index; 00551 old_back_pcost = current->backward_path_cost; 00552 num_edges = rr_node[inode].num_edges; 00553 00554 target_x = rr_node[target_node].xhigh; 00555 target_y = rr_node[target_node].yhigh; 00556 00557 for(iconn = 0; iconn < num_edges; iconn++) 00558 { 00559 to_node = rr_node[inode].edges[iconn]; 00560 00561 if(rr_node[to_node].xhigh < route_bb[inet].xmin || 00562 rr_node[to_node].xlow > route_bb[inet].xmax || 00563 rr_node[to_node].yhigh < route_bb[inet].ymin || 00564 rr_node[to_node].ylow > route_bb[inet].ymax) 00565 continue; /* Node is outside (expanded) bounding box. */ 00566 00567 if(clb_net[inet].num_sinks >= HIGH_FANOUT_NET_LIM) { 00568 if(rr_node[to_node].xhigh < target_x - highfanout_rlim || 00569 rr_node[to_node].xlow > target_x + highfanout_rlim || 00570 rr_node[to_node].yhigh < target_y - highfanout_rlim || 00571 rr_node[to_node].ylow > target_y + highfanout_rlim) 00572 continue; /* Node is outside high fanout bin. */ 00573 } 00574 00575 /* Prune away IPINs that lead to blocks other than the target one. Avoids * 00576 * the issue of how to cost them properly so they don't get expanded before * 00577 * more promising routes, but makes route-throughs (via CLBs) impossible. * 00578 * Change this if you want to investigate route-throughs. */ 00579 00580 to_type = rr_node[to_node].type; 00581 if(to_type == IPIN && (rr_node[to_node].xhigh != target_x || 00582 rr_node[to_node].yhigh != target_y)) 00583 continue; 00584 00585 /* new_back_pcost stores the "known" part of the cost to this node -- the * 00586 * congestion cost of all the routing resources back to the existing route * 00587 * new_tot_cost 00588 * is this "known" backward cost + an expected cost to get to the target. */ 00589 00590 new_back_pcost = old_back_pcost + get_rr_cong_cost(to_node); 00591 00592 if(bend_cost != 0.) 00593 { 00594 from_type = rr_node[inode].type; 00595 to_type = rr_node[to_node].type; 00596 if((from_type == CHANX && to_type == CHANY) || 00597 (from_type == CHANY && to_type == CHANX)) 00598 new_back_pcost += bend_cost; 00599 } 00600 00601 /* Calculate the new total cost = path cost + astar_fac * remaining distance to target */ 00602 new_tot_cost = new_back_pcost + astar_fac * 00603 get_directed_search_expected_cost(to_node, target_node); 00604 00605 node_to_heap(to_node, new_tot_cost, inode, iconn, new_back_pcost, 00606 OPEN); 00607 } 00608 } 00609 00610 00611 /** Adds the SOURCE of this net to the heap. Used to start a net's routing. */ 00612 static void 00613 directed_search_add_source_to_heap(int inet, 00614 int target_node, 00615 float astar_fac) 00616 { 00617 int inode; 00618 float back_cost, tot_cost; 00619 00620 inode = net_rr_terminals[inet][0]; /* SOURCE */ 00621 back_cost = 0.0 + get_rr_cong_cost(inode); 00622 00623 /* setting the total cost to 0 because it's the only element on the heap */ 00624 if(!is_empty_heap()) 00625 { 00626 printf 00627 ("Error: Wrong Assumption: in directed_search_add_source_to_heap " 00628 "the heap is not empty. Need to properly calculate source node's cost.\n"); 00629 exit(1); 00630 } 00631 00632 /* WMF: path cost is 0. could use tot_cost = 0 to save some computation time, but 00633 * for consistency, I chose to do the expected cost calculation. */ 00634 tot_cost = 00635 back_cost + astar_fac * get_directed_search_expected_cost(inode, 00636 target_node); 00637 node_to_heap(inode, tot_cost, NO_PREVIOUS, NO_PREVIOUS, back_cost, OPEN); 00638 00639 } 00640 00641 /** Determines the expected cost (due to resouce cost i.e. distance) to reach 00642 * the target node from inode. It doesn't include the cost of inode -- 00643 * that's already in the "known" path_cost. 00644 */ 00645 static float 00646 get_directed_search_expected_cost(int inode, 00647 int target_node) 00648 { 00649 00650 t_rr_type rr_type; 00651 int cost_index, ortho_cost_index, num_segs_same_dir, num_segs_ortho_dir; 00652 float cong_cost; 00653 00654 rr_type = rr_node[inode].type; 00655 00656 if(rr_type == CHANX || rr_type == CHANY) 00657 { 00658 num_segs_same_dir = 00659 get_expected_segs_to_target(inode, target_node, 00660 &num_segs_ortho_dir); 00661 cost_index = rr_node[inode].cost_index; 00662 ortho_cost_index = rr_indexed_data[cost_index].ortho_cost_index; 00663 00664 cong_cost = 00665 num_segs_same_dir * rr_indexed_data[cost_index].base_cost + 00666 num_segs_ortho_dir * 00667 rr_indexed_data[ortho_cost_index].base_cost; 00668 cong_cost += 00669 rr_indexed_data[IPIN_COST_INDEX].base_cost + 00670 rr_indexed_data[SINK_COST_INDEX].base_cost; 00671 00672 return (cong_cost); 00673 } 00674 00675 else if(rr_type == IPIN) 00676 { /* Change if you're allowing route-throughs */ 00677 return (rr_indexed_data[SINK_COST_INDEX].base_cost); 00678 } 00679 00680 else 00681 { /* Change this if you want to investigate route-throughs */ 00682 return (0.); 00683 } 00684 } 00685 00686 00687 /** Macro used below to ensure that fractions are rounded up, but floating 00688 * point values very close to an integer are rounded to that integer. 00689 */ 00690 #define ROUND_UP(x) (ceil (x - 0.001)) 00691 00692 /** Returns the number of segments the same type as inode that will be needed 00693 * to reach target_node (not including inode) in each direction (the same 00694 * direction (horizontal or vertical) as inode and the orthogonal direction). 00695 */ 00696 static int 00697 get_expected_segs_to_target(int inode, 00698 int target_node, 00699 int *num_segs_ortho_dir_ptr) 00700 { 00701 t_rr_type rr_type; 00702 int target_x, target_y, num_segs_same_dir, cost_index, ortho_cost_index; 00703 int no_need_to_pass_by_clb; 00704 float inv_length, ortho_inv_length, ylow, yhigh, xlow, xhigh; 00705 00706 target_x = rr_node[target_node].xlow; 00707 target_y = rr_node[target_node].ylow; 00708 cost_index = rr_node[inode].cost_index; 00709 inv_length = rr_indexed_data[cost_index].inv_length; 00710 ortho_cost_index = rr_indexed_data[cost_index].ortho_cost_index; 00711 ortho_inv_length = rr_indexed_data[ortho_cost_index].inv_length; 00712 rr_type = rr_node[inode].type; 00713 00714 if(rr_type == CHANX) 00715 { 00716 ylow = rr_node[inode].ylow; 00717 xhigh = rr_node[inode].xhigh; 00718 xlow = rr_node[inode].xlow; 00719 00720 /* Count vertical (orthogonal to inode) segs first. */ 00721 00722 if(ylow > target_y) 00723 { /* Coming from a row above target? */ 00724 *num_segs_ortho_dir_ptr = 00725 ROUND_UP((ylow - target_y + 1.) * ortho_inv_length); 00726 no_need_to_pass_by_clb = 1; 00727 } 00728 else if(ylow < target_y - 1) 00729 { /* Below the CLB bottom? */ 00730 *num_segs_ortho_dir_ptr = ROUND_UP((target_y - ylow) * 00731 ortho_inv_length); 00732 no_need_to_pass_by_clb = 1; 00733 } 00734 else 00735 { /* In a row that passes by target CLB */ 00736 *num_segs_ortho_dir_ptr = 0; 00737 no_need_to_pass_by_clb = 0; 00738 } 00739 00740 /* Now count horizontal (same dir. as inode) segs. */ 00741 00742 if(xlow > target_x + no_need_to_pass_by_clb) 00743 { 00744 num_segs_same_dir = 00745 ROUND_UP((xlow - no_need_to_pass_by_clb - 00746 target_x) * inv_length); 00747 } 00748 else if(xhigh < target_x - no_need_to_pass_by_clb) 00749 { 00750 num_segs_same_dir = 00751 ROUND_UP((target_x - no_need_to_pass_by_clb - 00752 xhigh) * inv_length); 00753 } 00754 else 00755 { 00756 num_segs_same_dir = 0; 00757 } 00758 } 00759 00760 else 00761 { /* inode is a CHANY */ 00762 ylow = rr_node[inode].ylow; 00763 yhigh = rr_node[inode].yhigh; 00764 xlow = rr_node[inode].xlow; 00765 00766 /* Count horizontal (orthogonal to inode) segs first. */ 00767 00768 if(xlow > target_x) 00769 { /* Coming from a column right of target? */ 00770 *num_segs_ortho_dir_ptr = 00771 ROUND_UP((xlow - target_x + 1.) * ortho_inv_length); 00772 no_need_to_pass_by_clb = 1; 00773 } 00774 else if(xlow < target_x - 1) 00775 { /* Left of and not adjacent to the CLB? */ 00776 *num_segs_ortho_dir_ptr = ROUND_UP((target_x - xlow) * 00777 ortho_inv_length); 00778 no_need_to_pass_by_clb = 1; 00779 } 00780 else 00781 { /* In a column that passes by target CLB */ 00782 *num_segs_ortho_dir_ptr = 0; 00783 no_need_to_pass_by_clb = 0; 00784 } 00785 00786 /* Now count vertical (same dir. as inode) segs. */ 00787 00788 if(ylow > target_y + no_need_to_pass_by_clb) 00789 { 00790 num_segs_same_dir = 00791 ROUND_UP((ylow - no_need_to_pass_by_clb - 00792 target_y) * inv_length); 00793 } 00794 else if(yhigh < target_y - no_need_to_pass_by_clb) 00795 { 00796 num_segs_same_dir = 00797 ROUND_UP((target_y - no_need_to_pass_by_clb - 00798 yhigh) * inv_length); 00799 } 00800 else 00801 { 00802 num_segs_same_dir = 0; 00803 } 00804 } 00805 00806 return (num_segs_same_dir); 00807 }