VPR-6.0

vpr/SRC/route/route_breadth_first.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 "mst.h"
00006 #include "route_export.h"
00007 #include "route_common.h"
00008 #include "route_breadth_first.h"
00009 
00010 
00011 /********************* Subroutines local to this module *********************/
00012 
00013 static boolean breadth_first_route_net(int inet,
00014                                        float bend_cost);
00015 
00016 static void breadth_first_expand_trace_segment(struct s_trace *start_ptr,
00017                                                int
00018                                                remaining_connections_to_sink);
00019 
00020 static void breadth_first_expand_neighbours(int inode,
00021                                             float pcost,
00022                                             int inet,
00023                                             float bend_cost);
00024 
00025 static void breadth_first_add_source_to_heap(int inet);
00026 
00027 
00028 /************************ Subroutine definitions ****************************/
00029 
00030 /** Iterated maze router ala Pathfinder Negotiated Congestion algorithm,  
00031  * (FPGA 95 p. 111).  Returns TRUE if it can route this FPGA, FALSE if   
00032  * it can't.                                                             
00033  */
00034 boolean
00035 try_breadth_first_route(struct s_router_opts router_opts,
00036                         t_ivec ** clb_opins_used_locally,
00037                         int width_fac)
00038 {
00039 
00040     float pres_fac;
00041     boolean success, is_routable, rip_up_local_opins;
00042     int itry, inet;
00043 
00044 /* Usually the first iteration uses a very small (or 0) pres_fac to find  *
00045  * the shortest path and get a congestion map.  For fast compiles, I set  *
00046  * pres_fac high even for the first iteration.                            */
00047 
00048     pres_fac = router_opts.first_iter_pres_fac;
00049 
00050     for(itry = 1; itry <= router_opts.max_router_iterations; itry++)
00051         {
00052 
00053             for(inet = 0; inet < num_nets; inet++)
00054                 {
00055                     if(clb_net[inet].is_global == FALSE)
00056                         {       /* Skip global nets. */
00057 
00058                             pathfinder_update_one_cost(trace_head[inet], -1,
00059                                                        pres_fac);
00060 
00061                             is_routable =
00062                                 breadth_first_route_net(inet,
00063                                                         router_opts.
00064                                                         bend_cost);
00065 
00066                             /* Impossible to route? (disconnected rr_graph) */
00067 
00068                             if(!is_routable)
00069                                 {
00070                                     printf("Routing failed.\n");
00071                                     return (FALSE);
00072                                 }
00073 
00074                             pathfinder_update_one_cost(trace_head[inet], 1,
00075                                                        pres_fac);
00076 
00077                         }
00078                 }
00079 
00080 
00081             /* Make sure any CLB OPINs used up by subblocks being hooked directly     *
00082              * to them are reserved for that purpose.                                 */
00083 
00084             if(itry == 1)
00085                 rip_up_local_opins = FALSE;
00086             else
00087                 rip_up_local_opins = TRUE;
00088 
00089             reserve_locally_used_opins(pres_fac, rip_up_local_opins,
00090                                        clb_opins_used_locally);
00091 
00092             success = feasible_routing();
00093             if(success)
00094                 {
00095                     printf
00096                         ("Successfully routed after %d routing iterations.\n",
00097                          itry);
00098                     return (TRUE);
00099                 }
00100 
00101             if(itry == 1)
00102                         pres_fac = router_opts.initial_pres_fac;
00103             else
00104                         pres_fac *= router_opts.pres_fac_mult;
00105 
00106                 pres_fac = min (pres_fac, HUGE_FLOAT / 1e5);
00107 
00108             pathfinder_update_cost(pres_fac, router_opts.acc_fac);
00109         }
00110 
00111     printf("Routing failed.\n");
00112     return (FALSE);
00113 }
00114 
00115 /** Uses a maze routing (Dijkstra's) algorithm to route a net.  The net       
00116  * begins at the net output, and expands outward until it hits a target      
00117  * pin.  The algorithm is then restarted with the entire first wire segment  
00118  * included as part of the source this time.  For an n-pin net, the maze     
00119  * router is invoked n-1 times to complete all the connections.  Inet is     
00120  * the index of the net to be routed.  Bends are penalized by bend_cost      
00121  * (which is typically zero for detailed routing and nonzero only for global 
00122  * routing), since global routes with lots of bends are tougher to detailed  
00123  * route (using a detailed router like SEGA).                                
00124  * If this routine finds that a net *cannot* be connected (due to a complete 
00125  * lack of potential paths, rather than congestion), it returns FALSE, as    
00126  * routing is impossible on this architecture.  Otherwise it returns TRUE.   
00127  */
00128 static boolean
00129 breadth_first_route_net(int inet,
00130                         float bend_cost)
00131 {
00132 
00133     int i, inode, prev_node, remaining_connections_to_sink;
00134     float pcost, new_pcost;
00135     struct s_heap *current;
00136     struct s_trace *tptr;
00137 
00138     free_traceback(inet);
00139     breadth_first_add_source_to_heap(inet);
00140     mark_ends(inet);
00141 
00142     tptr = NULL;
00143     remaining_connections_to_sink = 0;
00144 
00145     for(i = 1; i <= clb_net[inet].num_sinks; i++)
00146         {                       /* Need n-1 wires to connect n pins */
00147             breadth_first_expand_trace_segment(tptr,
00148                                                remaining_connections_to_sink);
00149             current = get_heap_head();
00150 
00151             if(current == NULL)
00152                 {               /* Infeasible routing.  No possible path for net. */
00153                     reset_path_costs(); /* Clean up before leaving. */
00154                     return (FALSE);
00155                 }
00156 
00157             inode = current->index;
00158 
00159             while(rr_node_route_inf[inode].target_flag == 0)
00160                 {
00161                     pcost = rr_node_route_inf[inode].path_cost;
00162                     new_pcost = current->cost;
00163                     if(pcost > new_pcost)
00164                         {       /* New path is lowest cost. */
00165                             rr_node_route_inf[inode].path_cost = new_pcost;
00166                             prev_node = current->u.prev_node;
00167                             rr_node_route_inf[inode].prev_node = prev_node;
00168                             rr_node_route_inf[inode].prev_edge =
00169                                 current->prev_edge;
00170 
00171                             if(pcost > 0.99 * HUGE_FLOAT)       /* First time touched. */
00172                                 add_to_mod_list(&rr_node_route_inf[inode].
00173                                                 path_cost);
00174 
00175                             breadth_first_expand_neighbours(inode, new_pcost,
00176                                                             inet, bend_cost);
00177                         }
00178 
00179                     free_heap_data(current);
00180                     current = get_heap_head();
00181 
00182                     if(current == NULL)
00183                         {       /* Impossible routing. No path for net. */
00184                             reset_path_costs();
00185                             return (FALSE);
00186                         }
00187 
00188                     inode = current->index;
00189                 }
00190 
00191             rr_node_route_inf[inode].target_flag--;     /* Connected to this SINK. */
00192             remaining_connections_to_sink =
00193                 rr_node_route_inf[inode].target_flag;
00194             tptr = update_traceback(current, inet);
00195             free_heap_data(current);
00196         }
00197 
00198     empty_heap();
00199     reset_path_costs();
00200     return (TRUE);
00201 }
00202 
00203 /** Adds all the rr_nodes in the traceback segment starting at tptr (and     
00204  * continuing to the end of the traceback) to the heap with a cost of zero. 
00205  * This allows expansion to begin from the existing wiring.  The            
00206  * remaining_connections_to_sink value is 0 if the route segment ending     
00207  * at this location is the last one to connect to the SINK ending the route 
00208  * segment.  This is the usual case.  If it is not the last connection this 
00209  * net must make to this SINK, I have a hack to ensure the next connection  
00210  * to this SINK goes through a different IPIN.  Without this hack, the      
00211  * router would always put all the connections from this net to this SINK   
00212  * through the same IPIN.  With LUTs or cluster-based logic blocks, you     
00213  * should never have a net connecting to two logically-equivalent pins on   
00214  * the same logic block, so the hack will never execute.  If your logic     
00215  * block is an and-gate, however, nets might connect to two and-inputs on   
00216  * the same logic block, and since the and-inputs are logically-equivalent, 
00217  * this means two connections to the same SINK.                             
00218  */
00219 static void
00220 breadth_first_expand_trace_segment(struct s_trace *start_ptr,
00221                                    int remaining_connections_to_sink)
00222 {
00223 
00224     struct s_trace *tptr, *next_ptr;
00225     int inode, sink_node, last_ipin_node;
00226 
00227     tptr = start_ptr;
00228 
00229     if(remaining_connections_to_sink == 0)
00230         {                       /* Usual case. */
00231             while(tptr != NULL)
00232                 {
00233                     node_to_heap(tptr->index, 0., NO_PREVIOUS, NO_PREVIOUS,
00234                                  OPEN, OPEN);
00235                     tptr = tptr->next;
00236                 }
00237         }
00238 
00239     else
00240         {                       /* This case never executes for most logic blocks. */
00241 
00242 /* Weird case.  Lots of hacks. The cleanest way to do this would be to empty *
00243  * the heap, update the congestion due to the partially-completed route, put *
00244  * the whole route so far (excluding IPINs and SINKs) on the heap with cost  *
00245  * 0., and expand till you hit the next SINK.  That would be slow, so I      *
00246  * do some hacks to enable incremental wavefront expansion instead.          */
00247 
00248             if(tptr == NULL)
00249                 return;         /* No route yet */
00250 
00251             next_ptr = tptr->next;
00252             last_ipin_node = OPEN;      /* Stops compiler from complaining. */
00253 
00254 /* Can't put last SINK on heap with NO_PREVIOUS, etc, since that won't let  *
00255  * us reach it again.  Instead, leave the last traceback element (SINK) off *
00256  * the heap.                                                                */
00257 
00258             while(next_ptr != NULL)
00259                 {
00260                     inode = tptr->index;
00261                     node_to_heap(inode, 0., NO_PREVIOUS, NO_PREVIOUS, OPEN,
00262                                  OPEN);
00263 
00264                     if(rr_node[inode].type == IPIN)
00265                         last_ipin_node = inode;
00266 
00267                     tptr = next_ptr;
00268                     next_ptr = tptr->next;
00269                 }
00270 
00271 /* This will stop the IPIN node used to get to this SINK from being         *
00272  * reexpanded for the remainder of this net's routing.  This will make us   *
00273  * hook up more IPINs to this SINK (which is what we want).  If IPIN        *
00274  * doglegs are allowed in the graph, we won't be able to use this IPIN to   *
00275  * do a dogleg, since it won't be re-expanded.  Shouldn't be a big problem. */
00276 
00277             rr_node_route_inf[last_ipin_node].path_cost = -HUGE_FLOAT;
00278 
00279 /* Also need to mark the SINK as having high cost, so another connection can *
00280  * be made to it.                                                            */
00281 
00282             sink_node = tptr->index;
00283             rr_node_route_inf[sink_node].path_cost = HUGE_FLOAT;
00284 
00285 /* Finally, I need to remove any pending connections to this SINK via the    *
00286  * IPIN I just used (since they would result in congestion).  Scan through   *
00287  * the heap to do this.                                                      */
00288 
00289             invalidate_heap_entries(sink_node, last_ipin_node);
00290         }
00291 }
00292 
00293 /** Puts all the rr_nodes adjacent to inode on the heap.  rr_nodes outside   
00294  * the expanded bounding box specified in route_bb are not added to the     
00295  * heap.  pcost is the path_cost to get to inode.                           
00296  */
00297 static void
00298 breadth_first_expand_neighbours(int inode,
00299                                 float pcost,
00300                                 int inet,
00301                                 float bend_cost)
00302 {
00303 
00304     int iconn, to_node, num_edges;
00305     t_rr_type from_type, to_type;
00306     float tot_cost;
00307 
00308     num_edges = rr_node[inode].num_edges;
00309     for(iconn = 0; iconn < num_edges; iconn++)
00310         {
00311             to_node = rr_node[inode].edges[iconn];
00312 
00313             if(rr_node[to_node].xhigh < route_bb[inet].xmin ||
00314                rr_node[to_node].xlow > route_bb[inet].xmax ||
00315                rr_node[to_node].yhigh < route_bb[inet].ymin ||
00316                rr_node[to_node].ylow > route_bb[inet].ymax)
00317                 continue;       /* Node is outside (expanded) bounding box. */
00318 
00319             tot_cost = pcost + get_rr_cong_cost(to_node);
00320 
00321             if(bend_cost != 0.)
00322                 {
00323                     from_type = rr_node[inode].type;
00324                     to_type = rr_node[to_node].type;
00325                     if((from_type == CHANX && to_type == CHANY) ||
00326                        (from_type == CHANY && to_type == CHANX))
00327                         tot_cost += bend_cost;
00328                 }
00329 
00330             node_to_heap(to_node, tot_cost, inode, iconn, OPEN, OPEN);
00331         }
00332 }
00333 
00334 
00335 /** Adds the SOURCE of this net to the heap.  Used to start a net's routing. */
00336 static void
00337 breadth_first_add_source_to_heap(int inet)
00338 {
00339     int inode;
00340     float cost;
00341 
00342     inode = net_rr_terminals[inet][0];  /* SOURCE */
00343     cost = get_rr_cong_cost(inode);
00344 
00345     node_to_heap(inode, cost, NO_PREVIOUS, NO_PREVIOUS, OPEN, OPEN);
00346 }