static void alloc_routing_structs(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_subblock_data subblock_data) { int bb_factor; /*calls routines that set up routing resource graph and associated structures*/ /*must set up dummy blocks for the first pass through*/ assign_locations(CLB, 1, 1, CLB, nx, ny); clb_opins_used_locally = alloc_route_structs(subblock_data); free_rr_graph(); build_rr_graph(router_opts.route_type, det_routing_arch, segment_inf, timing_inf, router_opts.base_cost_type); alloc_and_load_rr_node_route_structs(); alloc_timing_driven_route_structs(&pin_criticality, &sink_order, &rt_node_of_sink); bb_factor = nx + ny; /*set it to a huge value*/ init_route_structs(bb_factor); }
static void alloc_routing_structs(struct s_router_opts router_opts, struct s_det_routing_arch det_routing_arch, t_segment_inf * segment_inf, t_timing_inf timing_inf) { int bb_factor; int warnings; t_graph_type graph_type; /*calls routines that set up routing resource graph and associated structures */ /*must set up dummy blocks for the first pass through to setup locally used opins */ /* Only one block per tile */ assign_locations(FILL_TYPE, 1, 1, 0, FILL_TYPE, nx, ny, 0); clb_opins_used_locally = alloc_route_structs(); free_rr_graph(); if(router_opts.route_type == GLOBAL) { graph_type = GRAPH_GLOBAL; } else { graph_type = (det_routing_arch.directionality == BI_DIRECTIONAL ? GRAPH_BIDIR : GRAPH_UNIDIR); } build_rr_graph(graph_type, num_types, dummy_type_descriptors, nx, ny, grid, chan_width_x[0], NULL, det_routing_arch.switch_block_type, det_routing_arch.Fs, det_routing_arch.num_segment, det_routing_arch.num_switch, segment_inf, det_routing_arch.global_route_switch, det_routing_arch.delayless_switch, timing_inf, det_routing_arch.wire_to_ipin_switch, router_opts.base_cost_type, &warnings); alloc_and_load_rr_node_route_structs(); alloc_timing_driven_route_structs(&pin_criticality, &sink_order, &rt_node_of_sink); bb_factor = nx + ny; /*set it to a huge value */ init_route_structs(bb_factor); }
static int binary_search_place_and_route(struct s_placer_opts placer_opts, char *place_file, char *net_file, char *arch_file, char *route_file, boolean full_stats, boolean verify_binary_search, 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, t_mst_edge ** mst, t_model *models) { /* This routine performs a binary search to find the minimum number of * * tracks per channel required to successfully route a circuit, and returns * * that minimum width_fac. */ struct s_trace **best_routing; /* Saves the best routing found so far. */ int current, low, high, final; int max_pins_per_clb, i; boolean success, prev_success, prev2_success, Fc_clipped = FALSE; char msg[BUFSIZE]; float **net_delay, **net_slack; struct s_linked_vptr *net_delay_chunk_list_head; int try_w_limit; t_ivec **clb_opins_used_locally, **saved_clb_opins_used_locally; /* [0..num_blocks-1][0..num_class-1] */ int attempt_count; int udsd_multiplier; int warnings; t_graph_type graph_type; /* Allocate the major routing structures. */ if(router_opts.route_type == GLOBAL) { graph_type = GRAPH_GLOBAL; } else { graph_type = (det_routing_arch.directionality == BI_DIRECTIONAL ? GRAPH_BIDIR : GRAPH_UNIDIR); } max_pins_per_clb = 0; for(i = 0; i < num_types; i++) { max_pins_per_clb = max(max_pins_per_clb, type_descriptors[i].num_pins); } clb_opins_used_locally = alloc_route_structs(); best_routing = alloc_saved_routing(clb_opins_used_locally, &saved_clb_opins_used_locally); 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; } /* UDSD by AY Start */ if(det_routing_arch.directionality == BI_DIRECTIONAL) udsd_multiplier = 1; else udsd_multiplier = 2; /* UDSD by AY End */ if(router_opts.fixed_channel_width != NO_FIXED_CHANNEL_WIDTH) { current = router_opts.fixed_channel_width + 5 * udsd_multiplier; low = router_opts.fixed_channel_width - 1 * udsd_multiplier; } else { current = max_pins_per_clb + max_pins_per_clb % 2; /* Binary search part */ low = -1; } /* Constraints must be checked to not break rr_graph generator */ if(det_routing_arch.directionality == UNI_DIRECTIONAL) { if(current % 2 != 0) { printf ("Error: pack_place_and_route.c: tried odd chan width (%d) for udsd architecture\n", current); exit(1); } } else { if(det_routing_arch.Fs % 3) { printf("Fs must be three in bidirectional mode\n"); exit(1); } } high = -1; final = -1;
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; } }
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, t_direct_inf *directs, int num_directs) { /* This routine controls the overall placement and routing of a circuit. */ char msg[BUFSIZE]; int width_fac, i; boolean success, Fc_clipped; float **net_delay = NULL; t_slack * slacks = NULL; t_chunk net_delay_ch = {NULL, 0, NULL}; /*struct s_linked_vptr *net_delay_chunk_list_head;*/ t_ivec **clb_opins_used_locally = NULL; /* [0..num_blocks-1][0..num_class-1] */ 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, directs, num_directs); print_place(place_file, net_file, arch_file); end = clock(); #ifdef CLOCKS_PER_SEC vpr_printf(TIO_MESSAGE_INFO, "Placement took %g seconds.\n", (float)(end - begin) / CLOCKS_PER_SEC); #else vpr_printf(TIO_MESSAGE_INFO, "Placement took %g seconds.\n", (float)(end - begin) / CLK_PER_SEC); #endif } begin = clock(); post_place_sync(num_blocks, block); fflush(stdout); if (!router_opts.doRouting) return; 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) { g_solution_inf.channel_width = 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, models, directs, num_directs); } else { g_solution_inf.channel_width = width_fac; if (det_routing_arch.directionality == UNI_DIRECTIONAL) { if (width_fac % 2 != 0) { vpr_printf(TIO_MESSAGE_ERROR, "in 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(); slacks = alloc_and_load_timing_graph(timing_inf); net_delay = alloc_net_delay(&net_delay_ch, clb_net, num_nets); success = try_route(width_fac, router_opts, det_routing_arch, segment_inf, timing_inf, net_delay, slacks, chan_width_dist, clb_opins_used_locally, &Fc_clipped, directs, num_directs); if (Fc_clipped) { vpr_printf(TIO_MESSAGE_WARNING, "Fc_output was too high and was clipped to full (maximum) connectivity.\n"); } if (success == FALSE) { vpr_printf(TIO_MESSAGE_INFO, "Circuit is unrouteable with a channel width factor of %d.\n", width_fac); vpr_printf(TIO_MESSAGE_INFO, "\n"); 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(); vpr_printf(TIO_MESSAGE_INFO, "Circuit successfully routed with a channel width factor of %d.\n", width_fac); vpr_printf(TIO_MESSAGE_INFO, "\n"); 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_delay, slacks); print_route(route_file); if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_ROUTING_SINK_DELAYS)) { print_sink_delays(getEchoFileName(E_ECHO_ROUTING_SINK_DELAYS)); } 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(slacks->slack); if (getEchoEnabled() && isEchoFileEnabled(E_ECHO_POST_FLOW_TIMING_GRAPH)) { print_timing_graph_as_blif (getEchoFileName(E_ECHO_POST_FLOW_TIMING_GRAPH), models); } free_timing_graph(slacks); assert(net_delay); free_net_delay(net_delay, &net_delay_ch); } fflush(stdout); } if (clb_opins_used_locally != NULL) { for (i = 0; i < num_blocks; i++) { free_ivec_vector(clb_opins_used_locally[i], 0, block[i].type->num_class - 1); } free(clb_opins_used_locally); clb_opins_used_locally = NULL; } if(GetPostSynthesisOption()) { verilog_writer(); } end = clock(); #ifdef CLOCKS_PER_SEC vpr_printf(TIO_MESSAGE_INFO, "Routing took %g seconds.\n", (float) (end - begin) / CLOCKS_PER_SEC); #else vpr_printf(TIO_MESSAGE_INFO, "Routing took %g seconds.\n", (float)(end - begin) / CLK_PER_SEC); #endif /*WMF: cleaning up memory usage */ /* if (g_heap_free_head) free(g_heap_free_head); if (g_trace_free_head) free(g_trace_free_head); if (g_linked_f_pointer_free_head) free(g_linked_f_pointer_free_head);*/ }