VPR-6.0

vpr/SRC/route/route_directed_search.c

Go to the documentation of this file.
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 }