boolean try_breadth_first_route (struct s_router_opts router_opts, t_ivec **clb_opins_used_locally) { /* Iterated maze router ala Pathfinder Negotiated Congestion algorithm, * * (FPGA 95 p. 111). Returns TRUE if it can route this FPGA, FALSE if * * it can't. */ float pres_fac; boolean success, is_routable, rip_up_local_opins; int itry, inet; /* Usually the first iteration uses a very small (or 0) pres_fac to find * * the shortest path and get a congestion map. For fast compiles, I set * * pres_fac high even for the first iteration. */ pres_fac = router_opts.first_iter_pres_fac; for (itry=1;itry<=router_opts.max_router_iterations;itry++) { for (inet=0;inet<num_nets;inet++) { /* Added by Wei */ if (is_folding) { if (current_stage != num_stage) { if ((inet<num_net_per_stage[current_stage-1].begin)||(inet>=num_net_per_stage[current_stage].begin)) continue; } else { if (inet<num_net_per_stage[current_stage-1].begin) continue; } } printf("The net is %d\n",inet); if (is_global[inet] == FALSE) { /* Skip global nets. */ pathfinder_update_one_cost (trace_head[inet], -1, pres_fac); is_routable = breadth_first_route_net (inet, router_opts.bend_cost); /* Impossible to route? (disconnected rr_graph) */ if (!is_routable) { printf ("Routing failed.\n"); return (FALSE); } pathfinder_update_one_cost (trace_head[inet], 1, pres_fac); } } /* Make sure any CLB OPINs used up by subblocks being hooked directly * * to them are reserved for that purpose. */ if (itry == 1) rip_up_local_opins = FALSE; else rip_up_local_opins = TRUE; reserve_locally_used_opins (pres_fac, rip_up_local_opins, clb_opins_used_locally); success = feasible_routing (); if (success) { printf("Successfully routed after %d routing iterations.\n", itry); return (TRUE); } if (itry == 1) pres_fac = router_opts.initial_pres_fac; else pres_fac *= router_opts.pres_fac_mult; pathfinder_update_cost (pres_fac, router_opts.acc_fac); } printf ("Routing failed.\n"); return (FALSE); }
void check_route(enum e_route_type route_type, int num_switch, t_ivec ** clb_opins_used_locally) { /* This routine checks that a routing: (1) Describes a properly * * connected path for each net, (2) this path connects all the * * pins spanned by that net, and (3) that no routing resources are * * oversubscribed (the occupancy of everything is recomputed from * * scratch). */ int inet, ipin, max_pins, inode, prev_node; boolean valid, connects; boolean * connected_to_route; /* [0 .. num_rr_nodes-1] */ struct s_trace *tptr; boolean * pin_done; vpr_printf(TIO_MESSAGE_INFO, "\n"); vpr_printf(TIO_MESSAGE_INFO, "Checking to ensure routing is legal...\n"); /* Recompute the occupancy from scratch and check for overuse of routing * * resources. This was already checked in order to determine that this * * is a successful routing, but I want to double check it here. */ recompute_occupancy_from_scratch(clb_opins_used_locally); valid = feasible_routing(); if (valid == FALSE) { vpr_printf(TIO_MESSAGE_ERROR, "Error in check_route -- routing resources are overused.\n"); exit(1); } check_locally_used_clb_opins(clb_opins_used_locally, route_type); connected_to_route = (boolean *) my_calloc(num_rr_nodes, sizeof(boolean)); max_pins = 0; for (inet = 0; inet < num_nets; inet++) max_pins = std::max(max_pins, (clb_net[inet].num_sinks + 1)); pin_done = (boolean *) my_malloc(max_pins * sizeof(boolean)); /* Now check that all nets are indeed connected. */ for (inet = 0; inet < num_nets; inet++) { if (clb_net[inet].is_global || clb_net[inet].num_sinks == 0) /* Skip global nets. */ continue; for (ipin = 0; ipin < (clb_net[inet].num_sinks + 1); ipin++) pin_done[ipin] = FALSE; /* Check the SOURCE of the net. */ tptr = trace_head[inet]; if (tptr == NULL) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d has no routing.\n", inet); exit(1); } inode = tptr->index; check_node_and_range(inode, route_type); check_switch(tptr, num_switch); connected_to_route[inode] = TRUE; /* Mark as in path. */ check_source(inode, inet); pin_done[0] = TRUE; prev_node = inode; tptr = tptr->next; /* Check the rest of the net */ while (tptr != NULL) { inode = tptr->index; check_node_and_range(inode, route_type); check_switch(tptr, num_switch); if (rr_node[prev_node].type == SINK) { if (connected_to_route[inode] == FALSE) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: node %d does not link into existing routing for net %d.\n", inode, inet); exit(1); } } else { connects = check_adjacent(prev_node, inode); if (!connects) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: found non-adjacent segments in traceback while checking net %d.\n", inet); exit(1); } if (connected_to_route[inode] && rr_node[inode].type != SINK) { /* Note: Can get multiple connections to the same logically-equivalent * * SINK in some logic blocks. */ vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d routing is not a tree.\n", inet); exit(1); } connected_to_route[inode] = TRUE; /* Mark as in path. */ if (rr_node[inode].type == SINK) check_sink(inode, inet, pin_done); } /* End of prev_node type != SINK */ prev_node = inode; tptr = tptr->next; } /* End while */ if (rr_node[prev_node].type != SINK) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d does not end with a SINK.\n", inet); exit(1); } for (ipin = 0; ipin < (clb_net[inet].num_sinks + 1); ipin++) { if (pin_done[ipin] == FALSE) { vpr_printf(TIO_MESSAGE_ERROR, "in check_route: net %d does not connect to pin %d.\n", inet, ipin); exit(1); } } reset_flags(inet, connected_to_route); } /* End for each net */ free(pin_done); free(connected_to_route); vpr_printf(TIO_MESSAGE_INFO, "Completed routing consistency check successfully.\n"); vpr_printf(TIO_MESSAGE_INFO, "\n"); }
boolean try_directed_search_route(struct s_router_opts router_opts, t_ivec ** fb_opins_used_locally, int width_fac, t_mst_edge ** mst) { /* Iterated maze router ala Pathfinder Negotiated Congestion algorithm, * * (FPGA 95 p. 111). Returns TRUE if it can route this FPGA, FALSE if * * it can't. */ float pres_fac; boolean success, is_routable, rip_up_local_opins; int itry, inet; /* char msg[100]; */ /* mst not built as good as it should, ideally, just have it after placement once only however, rr_node numbers changed when the channel width changes so forced to do it here */ if(mst) { for(inet = 0; inet < num_nets; inet++) { free(mst[inet]); mst[inet] = get_mst_of_net(inet); } } /* Usually the first iteration uses a very small (or 0) pres_fac to find * * the shortest path and get a congestion map. For fast compiles, I set * * pres_fac high even for the first iteration. */ pres_fac = router_opts.first_iter_pres_fac; for(itry = 1; itry <= router_opts.max_router_iterations; itry++) { for(inet = 0; inet < num_nets; inet++) { if(net[inet].is_global == FALSE) { /* Skip global nets. */ is_routable = directed_search_route_net(inet, pres_fac, router_opts. astar_fac, router_opts. bend_cost, mst); /* Impossible to route? (disconnected rr_graph) */ if(!is_routable) { printf("Routing failed.\n"); return (FALSE); } } } /* Make sure any FB OPINs used up by subblocks being hooked directly * * to them are reserved for that purpose. */ if(itry == 1) rip_up_local_opins = FALSE; else rip_up_local_opins = TRUE; reserve_locally_used_opins(pres_fac, rip_up_local_opins, fb_opins_used_locally); success = feasible_routing(); if(success) { printf ("Successfully routed after %d routing iterations by Directed Search.\n", itry); return (TRUE); } #if 0 else { sprintf(msg, "After iteration %d routing failed (A*) with a channel width factor of %d and Fc_int of %d, Fs_int of %d.", itry, width_fac, Fc_int, Fs_int); init_draw_coords(pins_per_clb); update_screen(MAJOR, msg, ROUTING, FALSE); } #endif if(itry == 1) { pres_fac = router_opts.initial_pres_fac; pathfinder_update_cost(pres_fac, 0.); /* Acc_fac=0 for first iter. */ } else { pres_fac *= router_opts.pres_fac_mult; pathfinder_update_cost(pres_fac, router_opts.acc_fac); } } printf("Routing failed.\n"); return (FALSE); }
boolean try_directed_search_route(struct s_router_opts router_opts, t_ivec ** clb_opins_used_locally, int width_fac, t_mst_edge ** mst) { /* Iterated maze router ala Pathfinder Negotiated Congestion algorithm, * * (FPGA 95 p. 111). Returns TRUE if it can route this FPGA, FALSE if * * it can't. */ float pres_fac; boolean success, is_routable, rip_up_local_opins; int itry, inet, i; clock_t begin, end; int bends; int wirelength, total_wirelength, available_wirelength; int segments; float *sinks; int *net_index; sinks = my_malloc(sizeof(float) * num_nets); net_index = my_malloc(sizeof(int) * num_nets); for(i = 0; i < num_nets; i++) { sinks[i] = clb_net[i].num_sinks; net_index[i] = i; } heapsort(net_index, sinks, num_nets, 1); /* char msg[100]; */ begin = clock(); /* mst not built as good as it should, ideally, just have it after placement once only however, rr_node numbers changed when the channel width changes so forced to do it here */ if(mst) { for(inet = 0; inet < num_nets; inet++) { free(mst[inet]); mst[inet] = get_mst_of_net(inet); } } end = clock(); #ifdef CLOCKS_PER_SEC printf("mst took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); #else printf("mst took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); #endif /* Usually the first iteration uses a very small (or 0) pres_fac to find * * the shortest path and get a congestion map. For fast compiles, I set * * pres_fac high even for the first iteration. */ pres_fac = router_opts.first_iter_pres_fac; for(itry = 1; itry <= router_opts.max_router_iterations; itry++) { begin = clock(); printf("routing iteration %d\n", itry); for(i = 0; i < num_nets; i++) { inet = net_index[i]; if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0) { /* Skip global nets and empty nets (empty nets are already reserved using reserve_locally_used_opins). */ is_routable = directed_search_route_net(inet, pres_fac, router_opts. astar_fac, router_opts. bend_cost, mst); /* Impossible to route? (disconnected rr_graph) */ if(!is_routable) { printf("Routing failed.\n"); free(net_index); free(sinks); return (FALSE); } } } end = clock(); #ifdef CLOCKS_PER_SEC printf("routing iteration took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); #else printf("routing iteration took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); #endif fflush(stdout); if(itry == 1) { /* Early exit code for cases where it is obvious that a successful route will not be found Heuristic: If total wirelength used in first routing iteration is X% of total available wirelength, exit */ total_wirelength = 0; available_wirelength = 0; for(i = 0; i < num_rr_nodes; i++) { if(rr_node[i].type == CHANX || rr_node[i].type == CHANY) { available_wirelength += 1 + rr_node[i].xhigh - rr_node[i].xlow + rr_node[i].yhigh - rr_node[i].ylow; } } for(inet = 0; inet < num_nets; inet++) { if(clb_net[inet].is_global == FALSE && clb_net[inet].num_sinks != 0) { /* Globals don't count. */ get_num_bends_and_length(inet, &bends, &wirelength, &segments); total_wirelength += wirelength; } } printf("wirelength after first iteration %d, total available wirelength %d, ratio %g\n", total_wirelength, available_wirelength, (float)(total_wirelength)/(float)(available_wirelength)); if((float)(total_wirelength)/(float)(available_wirelength) > FIRST_ITER_WIRELENTH_LIMIT) { printf("Wirelength usage ratio exceeds limit of %g, fail routing\n", FIRST_ITER_WIRELENTH_LIMIT); free(net_index); free(sinks); return FALSE; } } /* Make sure any CLB OPINs used up by subblocks being hooked directly * * to them are reserved for that purpose. */ if(itry == 1) rip_up_local_opins = FALSE; else rip_up_local_opins = TRUE; reserve_locally_used_opins(pres_fac, rip_up_local_opins, clb_opins_used_locally); success = feasible_routing(); if(success) { printf ("Successfully routed after %d routing iterations by Directed Search.\n", itry); free(net_index); free(sinks); return (TRUE); } #if 0 else { sprintf(msg, "After iteration %d routing failed (A*) with a channel width factor of %d and Fc_int of %d, Fs_int of %d.", itry, width_fac, Fc_int, Fs_int); init_draw_coords(pins_per_clb); update_screen(MAJOR, msg, ROUTING, FALSE); } #endif if(itry == 1) { pres_fac = router_opts.initial_pres_fac; pathfinder_update_cost(pres_fac, 0.); /* Acc_fac=0 for first iter. */ } else { pres_fac *= router_opts.pres_fac_mult; pathfinder_update_cost(pres_fac, router_opts.acc_fac); } } printf("Routing failed.\n"); free(sinks); free(net_index); return (FALSE); }
boolean try_breadth_first_route(struct s_router_opts router_opts, t_ivec ** clb_opins_used_locally, int width_fac) { /* Iterated maze router ala Pathfinder Negotiated Congestion algorithm, * * (FPGA 95 p. 111). Returns TRUE if it can route this FPGA, FALSE if * * it can't. */ float pres_fac; boolean success, is_routable, rip_up_local_opins; int itry, inet; /* Usually the first iteration uses a very small (or 0) pres_fac to find * * the shortest path and get a congestion map. For fast compiles, I set * * pres_fac high even for the first iteration. */ pres_fac = router_opts.first_iter_pres_fac; for (itry = 1; itry <= router_opts.max_router_iterations; itry++) { for (inet = 0; inet < num_nets; inet++) { if (clb_net[inet].is_global == FALSE) { /* Skip global nets. */ pathfinder_update_one_cost(trace_head[inet], -1, pres_fac); is_routable = breadth_first_route_net(inet, router_opts.bend_cost); /* Impossible to route? (disconnected rr_graph) */ if (!is_routable) { vpr_printf(TIO_MESSAGE_INFO, "Routing failed.\n"); return (FALSE); } pathfinder_update_one_cost(trace_head[inet], 1, pres_fac); } } /* Make sure any CLB OPINs used up by subblocks being hooked directly * * to them are reserved for that purpose. */ if (itry == 1) rip_up_local_opins = FALSE; else rip_up_local_opins = TRUE; reserve_locally_used_opins(pres_fac, rip_up_local_opins, clb_opins_used_locally); success = feasible_routing(); if (success) { vpr_printf(TIO_MESSAGE_INFO, "Successfully routed after %d routing iterations.\n", itry); return (TRUE); } if (itry == 1) pres_fac = router_opts.initial_pres_fac; else pres_fac *= router_opts.pres_fac_mult; pres_fac = std::min(pres_fac, static_cast<float>(HUGE_POSITIVE_FLOAT / 1e5)); pathfinder_update_cost(pres_fac, router_opts.acc_fac); } vpr_printf(TIO_MESSAGE_INFO, "Routing failed.\n"); return (FALSE); }