void reserve_locally_used_opins (float pres_fac, boolean rip_up_local_opins, t_ivec **clb_opins_used_locally) { /* If some subblock outputs are hooked directly to CLB outputs, then * * some CLB outputs are occupied if their associated subblock is used * * locally, even though the inter-CLB netlist does not say those outputs * * have to connect to anything. This is important when you have * * logically equivalent outputs. Code below makes sure any CLB outputs * * that are used by being directly hooked to subblocks get properly * * reserved. */ int iblk, num_local_opin, inode, from_node, iconn, num_edges, to_node; int iclass, ipin; float cost; struct s_heap *heap_head_ptr; if (rip_up_local_opins) { for (iblk=0;iblk<num_blocks;iblk++) { for (iclass=0;iclass<num_class;iclass++) { num_local_opin = clb_opins_used_locally[iblk][iclass].nelem; /* Always 0 for pads and for RECEIVER (IPIN) classes */ for (ipin=0;ipin<num_local_opin;ipin++) { inode = clb_opins_used_locally[iblk][iclass].list[ipin]; adjust_one_rr_occ_and_pcost (inode, -1, pres_fac); } } } } for (iblk=0;iblk<num_blocks;iblk++) { for (iclass=0;iclass<num_class;iclass++) { num_local_opin = clb_opins_used_locally[iblk][iclass].nelem; /* Always 0 for pads and for RECEIVER (IPIN) classes */ if (num_local_opin != 0) { /* Have to reserve (use) some OPINs */ from_node = rr_clb_source[iblk][iclass]; num_edges = rr_node[from_node].num_edges; for (iconn=0;iconn<num_edges;iconn++) { to_node = rr_node[from_node].edges[iconn]; cost = get_rr_cong_cost (to_node); node_to_heap (to_node, cost, OPEN, OPEN, 0., 0.); } for (ipin=0;ipin<num_local_opin;ipin++) { heap_head_ptr = get_heap_head (); inode = heap_head_ptr->index; adjust_one_rr_occ_and_pcost (inode, 1, pres_fac); clb_opins_used_locally[iblk][iclass].list[ipin] = inode; free_heap_data (heap_head_ptr); } empty_heap (); } } } }
/** * Adapted from breadth_first_route_net() */ boolean inc_breadth_first_route_net(int inet, float bend_cost, struct s_trace **old_trace_tail, int old_num_nets, struct s_router_opts *router_opts) { /* Uses a maze routing (Dijkstra's) algorithm to route a net. The net * * begins at the net output, and expands outward until it hits a target * * pin. The algorithm is then restarted with the entire first wire segment * * included as part of the source this time. For an n-pin net, the maze * * router is invoked n-1 times to complete all the connections. Inet is * * the index of the net to be routed. Bends are penalized by bend_cost * * (which is typically zero for detailed routing and nonzero only for global * * routing), since global routes with lots of bends are tougher to detailed * * route (using a detailed router like SEGA). * * If this routine finds that a net *cannot* be connected (due to a complete * * lack of potential paths, rather than congestion), it returns FALSE, as * * routing is impossible on this architecture. Otherwise it returns TRUE. */ int inode, prev_node, remaining_connections_to_sink; int itarget, target_inode, target_iblk; int max_mdist; float pcost, new_pcost; struct s_heap *current; struct s_trace *tptr; /* Rip up incremental trace only */ inc_free_traceback(inet, old_trace_tail); inode = net_rr_terminals[inet][0]; /* EH: Extract the assigned TB target */ itarget = clb_net[inet].num_sinks; target_inode = net_rr_terminals[inet][itarget+1]; assert(target_inode != OPEN); target_iblk = clb_net[inet].node_block[itarget+1]; /* If LE symmetry enabled, and inet was local, add all CLB_OPINs * from other local nets onto heap too */ if (router_opts->inc_le_symmetry && inet >= old_num_nets) { int num_sources, *sources; int i; boolean found = FALSE; num_sources = inc_local_OPINs(inet, old_num_nets, &sources); for (i = 0; i < num_sources; i++) { inc_breadth_first_add_inode_to_heap(sources[i]); if (sources[i] == inode) found = TRUE; } assert(found == TRUE); free(sources); } else { breadth_first_add_source_to_heap(inet); } /*mark_ends(inet); */ tptr = trace_head[inet]; remaining_connections_to_sink = 0; max_mdist = 0; /* for(i = 1; i <= clb_net[inet].num_sinks; i++) */ { /* Need n-1 wires to connect n pins */ breadth_first_expand_trace_segment(tptr, remaining_connections_to_sink); current = get_heap_head(); if(current == NULL) { /* Infeasible routing. No possible path for net. */ reset_path_costs(); /* Clean up before leaving. */ return (FALSE); } inode = current->index; /*while(rr_node_route_inf[inode].target_flag == 0)*/ while(rr_node_route_inf[inode].target_flag != target_iblk) { /*max_mdist = max(max_mdist, inc_traceback_len(current));*/ pcost = rr_node_route_inf[inode].path_cost; new_pcost = current->cost; if(pcost > new_pcost) { /* New path is lowest cost. */ rr_node_route_inf[inode].path_cost = new_pcost; prev_node = current->u.prev_node; rr_node_route_inf[inode].prev_node = prev_node; rr_node_route_inf[inode].prev_edge = current->prev_edge; if(pcost > 0.99 * HUGE_POSITIVE_FLOAT) /* First time touched. */ add_to_mod_list(&rr_node_route_inf[inode]. path_cost); inc_breadth_first_expand_neighbours(inode, new_pcost, inet, bend_cost); } free_heap_data(current); current = get_heap_head(); if(current == NULL) { /* Impossible routing. No path for net. */ fprintf(stdout, "\ninet %d (vnet %d) failed", inet, clb_to_vpack_net_mapping[inet]); empty_heap(); reset_path_costs(); return (FALSE); } inode = current->index; } /*rr_node_route_inf[inode].target_flag--;*/ /* Connected to this SINK. */ remaining_connections_to_sink = rr_node_route_inf[inode].target_flag; tptr = update_traceback(current, inet); free_heap_data(current); } /*printf("max_mdist = %d\n", max_mdist);*/ empty_heap(); reset_path_costs(); return (TRUE); }
static boolean breadth_first_route_net (int inet, float bend_cost) { /* Uses a maze routing (Dijkstra's) algorithm to route a net. The net * * begins at the net output, and expands outward until it hits a target * * pin. The algorithm is then restarted with the entire first wire segment * * included as part of the source this time. For an n-pin net, the maze * * router is invoked n-1 times to complete all the connections. Inet is * * the index of the net to be routed. Bends are penalized by bend_cost * * (which is typically zero for detailed routing and nonzero only for global * * routing), since global routes with lots of bends are tougher to detailed * * route (using a detailed router like SEGA). * * If this routine finds that a net *cannot* be connected (due to a complete * * lack of potential paths, rather than congestion), it returns FALSE, as * * routing is impossible on this architecture. Otherwise it returns TRUE. */ int i, inode, prev_node, remaining_connections_to_sink; float pcost, new_pcost; struct s_heap *current; struct s_trace *tptr; free_traceback (inet); breadth_first_add_source_to_heap (inet); mark_ends (inet); tptr = NULL; remaining_connections_to_sink = 0; for (i=1;i<net[inet].num_pins;i++) { /* Need n-1 wires to connect n pins */ breadth_first_expand_trace_segment (tptr, remaining_connections_to_sink); current = get_heap_head(); if (current == NULL) { /* Infeasible routing. No possible path for net. */ reset_path_costs (); /* Clean up before leaving. */ return (FALSE); } inode = current->index; while (rr_node_route_inf[inode].target_flag == 0) { pcost = rr_node_route_inf[inode].path_cost; new_pcost = current->cost; if (pcost > new_pcost) { /* New path is lowest cost. */ rr_node_route_inf[inode].path_cost = new_pcost; prev_node = current->u.prev_node; rr_node_route_inf[inode].prev_node = prev_node; rr_node_route_inf[inode].prev_edge = current->prev_edge; if (pcost > 0.99 * HUGE_FLOAT) /* First time touched. */ add_to_mod_list (&rr_node_route_inf[inode].path_cost); breadth_first_expand_neighbours (inode, new_pcost, inet, bend_cost); } free_heap_data (current); current = get_heap_head (); if (current == NULL) { /* Impossible routing. No path for net. */ reset_path_costs (); return (FALSE); } inode = current->index; } rr_node_route_inf[inode].target_flag--; /* Connected to this SINK. */ remaining_connections_to_sink = rr_node_route_inf[inode].target_flag; tptr = update_traceback (current, inet); free_heap_data (current); } empty_heap (); reset_path_costs (); return (TRUE); }
static boolean directed_search_route_net(int inet, float pres_fac, float astar_fac, float bend_cost, t_mst_edge ** mst) { /* Uses a maze routing (Dijkstra's) algorithm to route a net. The net * * begins at the net output, and expands outward until it hits a target * * pin. The algorithm is then restarted with the entire first wire segment * * included as part of the source this time. For an n-pin net, the maze * * router is invoked n-1 times to complete all the connections. Inet is * * the index of the net to be routed. Bends are penalized by bend_cost * * (which is typically zero for detailed routing and nonzero only for global * * routing), since global routes with lots of bends are tougher to detailed * * route (using a detailed router like SEGA). * * If this routine finds that a net *cannot* be connected (due to a complete * * lack of potential paths, rather than congestion), it returns FALSE, as * * routing is impossible on this architecture. Otherwise it returns TRUE. */ /* WMF: This is the directed search (A-star) version of maze router. */ int inode, remaining_connections_to_sink; int itarget, target_pin, target_node; struct s_heap *current; struct s_trace *new_route_start_tptr; float old_tcost, new_tcost, old_back_cost, new_back_cost; int highfanout_rlim; assert(mst); /* Rip-up any old routing. */ /* WMF: For the 1st router iteration trace_head[inet] is NULL, as it is * my_calloc'ed in alloc_route_structs() so the following does nothing. * However, for subsequent iterations, trace_head[inet] contains the previous * ieration's routing for this net. */ pathfinder_update_one_cost(trace_head[inet], -1, pres_fac); free_traceback(inet); /* kills trace, and set the trace head and tail to NULL */ /* adding the SOURCE node to the heap with correct total cost */ target_pin = mst[inet][0].to_node; target_node = net_rr_terminals[inet][target_pin]; directed_search_add_source_to_heap(inet, target_node, astar_fac); mark_ends(inet); remaining_connections_to_sink = 0; for(itarget = 0; itarget < clb_net[inet].num_sinks; itarget++) { target_pin = mst[inet][itarget].to_node; target_node = net_rr_terminals[inet][target_pin]; /* printf ("Target #%d, pin number %d, target_node: %d.\n", * itarget, target_pin, target_node); */ /* WMF: since the heap has been emptied, need to restart the wavefront * from the current partial routing, starting at the trace_head (SOURCE) * Note: in the 1st iteration, there is no trace (no routing at all for this net) * i.e. trace_head[inet] == NULL (found in free_traceback() in route_common.c, * which is called before the routing of any net), * so this routine does nothing, but the heap does have the SOURCE node due * to directed_search_add_source_to_heap (inet) before the loop */ highfanout_rlim = directed_search_expand_trace_segment(trace_head[inet], target_node, astar_fac, inet, remaining_connections_to_sink); current = get_heap_head(); if(current == NULL) { /* Infeasible routing. No possible path for net. */ reset_path_costs(); /* Clean up before leaving. */ return (FALSE); } inode = current->index; while(inode != target_node) { old_tcost = rr_node_route_inf[inode].path_cost; new_tcost = current->cost; /* WMF: not needed if Vaughn initialized rr_node_route_inf[inode].backward_path_cost * to HUGE_FLOAT along with rr_node_route_inf[inode].path_cost */ if(old_tcost > 0.99 * HUGE_FLOAT) /* First time touched. */ old_back_cost = HUGE_FLOAT; else old_back_cost = rr_node_route_inf[inode].backward_path_cost; new_back_cost = current->backward_path_cost; /* I only re-expand a node if both the "known" backward cost is lower * * in the new expansion (this is necessary to prevent loops from * * forming in the routing and causing havoc) *and* the expected total * * cost to the sink is lower than the old value. Different R_upstream * * values could make a path with lower back_path_cost less desirable * * than one with higher cost. Test whether or not I should disallow * * re-expansion based on a higher total cost. */ /* updating the maze (Dijktra's min dist algorithm) if found "shorter" path */ if(old_tcost > new_tcost && old_back_cost > new_back_cost) { /* if (old_tcost > new_tcost) { */ rr_node_route_inf[inode].prev_node = current->u.prev_node; rr_node_route_inf[inode].prev_edge = current->prev_edge; rr_node_route_inf[inode].path_cost = new_tcost; rr_node_route_inf[inode].backward_path_cost = new_back_cost; if(old_tcost > 0.99 * HUGE_FLOAT) /* First time touched. */ add_to_mod_list(&rr_node_route_inf[inode]. path_cost); directed_search_expand_neighbours(current, inet, bend_cost, target_node, highfanout_rlim, astar_fac); } free_heap_data(current); current = get_heap_head(); if(current == NULL) { /* Impossible routing. No path for net. */ 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); reset_path_costs(); return (FALSE); } inode = current->index; } rr_node_route_inf[inode].target_flag--; /* Connected to this SINK. */ remaining_connections_to_sink = rr_node_route_inf[inode].target_flag; /* keep info on the current routing of this net */ new_route_start_tptr = update_traceback(current, inet); free_heap_data(current); /* update the congestion costs of rr_nodes due to the routing to this sink * so only those nodes used in the partial routing of this sink and not * of the entire net (remember we're in a loop for this net over its sinks) */ pathfinder_update_one_cost(new_route_start_tptr, 1, pres_fac); /* WMF: MUST empty heap and recalculate all total costs, because * for the next sink, the target destination is changed, so the expected * cost calculation is changed also, meaning all the nodes on the heap have * "stale" total costs (costs based on last sink). */ empty_heap(); reset_path_costs(); } return (TRUE); }