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); }
void place_and_route(enum e_operation operation, struct s_placer_opts placer_opts, char *place_file, char *net_file, char *arch_file, char *route_file, struct s_annealing_sched annealing_sched, struct s_router_opts router_opts, struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf, t_timing_inf timing_inf, t_chan_width_dist chan_width_dist, struct s_model *models) { /* This routine controls the overall placement and routing of a circuit. */ char msg[BUFSIZE]; int width_fac, inet, i; boolean success, Fc_clipped; float **net_delay, **net_slack; struct s_linked_vptr *net_delay_chunk_list_head; t_ivec **clb_opins_used_locally; /* [0..num_blocks-1][0..num_class-1] */ t_mst_edge **mst = NULL; /* Make sure mst is never undefined */ int max_pins_per_clb; clock_t begin, end; Fc_clipped = FALSE; max_pins_per_clb = 0; for(i = 0; i < num_types; i++) { if(type_descriptors[i].num_pins > max_pins_per_clb) { max_pins_per_clb = type_descriptors[i].num_pins; } } if(placer_opts.place_freq == PLACE_NEVER) { /* Read the placement from a file */ read_place(place_file, net_file, arch_file, nx, ny, num_blocks, block); sync_grid_to_blocks(num_blocks, block, nx, ny, grid); } else { assert((PLACE_ONCE == placer_opts.place_freq) || (PLACE_ALWAYS == placer_opts.place_freq)); begin = clock(); try_place(placer_opts, annealing_sched, chan_width_dist, router_opts, det_routing_arch, segment_inf, timing_inf, &mst); print_place(place_file, net_file, arch_file); end = clock(); #ifdef CLOCKS_PER_SEC printf("Placement took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); #else printf("Placement took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); #endif } begin = clock(); post_place_sync(num_blocks, block); fflush(stdout); /* reset mst */ if(mst) { for(inet = 0; inet < num_nets; inet++) { if(mst[inet]) { free(mst[inet]); } } free(mst); } mst = NULL; if(!router_opts.doRouting) return; mst = (t_mst_edge **) my_malloc(sizeof(t_mst_edge *) * num_nets); for(inet = 0; inet < num_nets; inet++) { mst[inet] = get_mst_of_net(inet); } width_fac = router_opts.fixed_channel_width; /* If channel width not fixed, use binary search to find min W */ if(NO_FIXED_CHANNEL_WIDTH == width_fac) { binary_search_place_and_route(placer_opts, place_file, net_file, arch_file, route_file, router_opts.full_stats, router_opts.verify_binary_search, annealing_sched, router_opts, det_routing_arch, segment_inf, timing_inf, chan_width_dist, mst, models); } else { if(det_routing_arch.directionality == UNI_DIRECTIONAL) { if(width_fac % 2 != 0) { printf ("Error: pack_place_and_route.c: given odd chan width (%d) for udsd architecture\n", width_fac); exit(1); } } /* Other constraints can be left to rr_graph to check since this is one pass routing */ /* Allocate the major routing structures. */ clb_opins_used_locally = alloc_route_structs(); if(timing_inf.timing_analysis_enabled) { net_slack = alloc_and_load_timing_graph(timing_inf); net_delay = alloc_net_delay(&net_delay_chunk_list_head, clb_net, num_nets); } else { net_delay = NULL; /* Defensive coding. */ net_slack = NULL; } success = try_route(width_fac, router_opts, det_routing_arch, segment_inf, timing_inf, net_slack, net_delay, chan_width_dist, clb_opins_used_locally, mst, &Fc_clipped); if(Fc_clipped) { printf ("Warning: Fc_output was too high and was clipped to full (maximum) connectivity.\n"); } if(success == FALSE) { printf ("Circuit is unrouteable with a channel width factor of %d\n\n", width_fac); sprintf(msg, "Routing failed with a channel width factor of %d. ILLEGAL routing shown.", width_fac); } else { check_route(router_opts.route_type, det_routing_arch.num_switch, clb_opins_used_locally); get_serial_num(); printf ("Circuit successfully routed with a channel width factor of %d.\n\n", width_fac); routing_stats(router_opts.full_stats, router_opts.route_type, det_routing_arch.num_switch, segment_inf, det_routing_arch.num_segment, det_routing_arch.R_minW_nmos, det_routing_arch.R_minW_pmos, det_routing_arch.directionality, timing_inf.timing_analysis_enabled, net_slack, net_delay); print_route(route_file); #ifdef CREATE_ECHO_FILES /*print_sink_delays("routing_sink_delays.echo"); */ #endif /* CREATE_ECHO_FILES */ sprintf(msg, "Routing succeeded with a channel width factor of %d.\n\n", width_fac); } init_draw_coords(max_pins_per_clb); update_screen(MAJOR, msg, ROUTING, timing_inf.timing_analysis_enabled); if(timing_inf.timing_analysis_enabled) { assert(net_slack); #ifdef CREATE_ECHO_FILES print_timing_graph_as_blif("post_flow_timing_graph.blif", models); #endif free_timing_graph(net_slack); assert(net_delay); free_net_delay(net_delay, &net_delay_chunk_list_head); } free_route_structs(clb_opins_used_locally); fflush(stdout); } end = clock(); #ifdef CLOCKS_PER_SEC printf("Routing took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); #else printf("Routing took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); #endif /*WMF: cleaning up memory usage */ if(mst) { for(inet = 0; inet < num_nets; inet++) { if(!mst[inet]) { printf("no mst for net %s #%d\n", clb_net[inet].name, inet); } assert(mst[inet]); free(mst[inet]); } free(mst); mst = NULL; } }
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); }