void free_route_structs(t_ivec ** fb_opins_used_locally) { /* Frees the temporary storage needed only during the routing. The * * final routing result is not freed. */ int i; free(heap + 1); free(route_bb); heap = NULL; /* Defensive coding: crash hard if I use these. */ route_bb = NULL; for(i = 0; i < num_blocks; i++) { free_ivec_vector(fb_opins_used_locally[i], 0, block[i].type->num_class - 1); } free(fb_opins_used_locally); /* NB: Should use my chunk_malloc for tptr, hptr, and mod_ptr structures. * * I could free everything except the tptrs at the end then. */ }
void free_saved_routing(struct s_trace **best_routing, t_ivec ** saved_clb_opins_used_locally) { /* Frees the data structures needed to save a routing. */ int i; free(best_routing); for(i = 0; i < num_blocks; i++) { free_ivec_vector(saved_clb_opins_used_locally[i], 0, block[i].type->num_class - 1); } free(saved_clb_opins_used_locally); }
static void free_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 i; free_rr_graph(); free_rr_node_route_structs(); free_route_structs(); free_trace_structs(); free_timing_driven_route_structs(pin_criticality, sink_order, rt_node_of_sink); 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; } }
void build_rr_graph (enum e_route_type route_type, struct s_det_routing_arch det_routing_arch, struct s_segment_inf *segment_inf, t_timing_inf timing_inf) { /* Builds the routing resource graph needed for routing. Does all the * * necessary allocation and initialization. If route_type is DETAILED * * then the routing graph built is for detailed routing, otherwise it is * * for GLOBAL routing. */ int nodes_per_clb, nodes_per_pad, nodes_per_chan; int **rr_node_indices; int Fc_output, Fc_input, Fc_pad; int **pads_to_tracks; struct s_ivec **tracks_to_clb_ipin, *tracks_to_pads; /* [0..pins_per_clb-1][0..3][0..Fc_output-1]. List of tracks this pin * * connects to. Second index is the side number (see pr.h). If a pin * * is not an output or input, respectively, or doesn't connect to * * anything on this side, the [ipin][iside][0] element is OPEN. */ int ***clb_opin_to_tracks, ***clb_ipin_to_tracks; t_seg_details *seg_details_x, *seg_details_y; /* [0 .. nodes_per_chan-1] */ nodes_per_clb = num_class + pins_per_clb; nodes_per_pad = 4 * io_rat; /* SOURCE, SINK, OPIN, and IPIN */ if (route_type == GLOBAL) { nodes_per_chan = 1; } else { nodes_per_chan = chan_width_x[0]; } seg_details_x = alloc_and_load_seg_details (nodes_per_chan, segment_inf, det_routing_arch.num_segment, nx); seg_details_y = alloc_and_load_seg_details (nodes_per_chan, segment_inf, det_routing_arch.num_segment, ny); #ifdef DEBUG dump_seg_details (seg_details_x, nodes_per_chan, "x.echo"); dump_seg_details (seg_details_y, nodes_per_chan, "y.echo"); #endif /* To set up the routing graph I need to choose an order for the rr_indices. * * For each (i,j) slot in the FPGA, the index order is [source+sink]/pins/ * * chanx/chany. The dummy source and sink are ordered by class number or pad * * number; the pins are ordered by pin number or pad number, and the channel * * segments are ordered by track number. Track 1 is closest to the "owning" * * block; i.e. it is towards the left of y-chans and the bottom of x-chans. * * * * The maximize cache effectiveness, I put all the rr_nodes associated with * * a block together (this includes the "owned" channel segments). I start * * at (0,0) (empty), go to (1,0), (2,0) ... (0,1) and so on. */ /* NB: Allocates data structures for fast index computations -- more than * * just rr_node_indices are allocated by this routine. */ rr_node_indices = alloc_and_load_rr_node_indices (nodes_per_clb, nodes_per_pad, nodes_per_chan, seg_details_x, seg_details_y); num_rr_nodes = rr_node_indices[nx+1][ny+1]; if (det_routing_arch.Fc_type == ABSOLUTE) { Fc_output = min (det_routing_arch.Fc_output, nodes_per_chan); Fc_input = min (det_routing_arch.Fc_input, nodes_per_chan); Fc_pad = min (det_routing_arch.Fc_pad, nodes_per_chan); } else { /* FRACTIONAL */ Fc_output = nint (nodes_per_chan * det_routing_arch.Fc_output); Fc_output = max (1, Fc_output); Fc_input = nint (nodes_per_chan * det_routing_arch.Fc_input); Fc_input = max (1, Fc_input); Fc_pad = nint (nodes_per_chan * det_routing_arch.Fc_pad); Fc_pad = max (1, Fc_pad); } alloc_and_load_switch_block_conn (nodes_per_chan, det_routing_arch.switch_block_type); clb_opin_to_tracks = alloc_and_load_clb_pin_to_tracks (DRIVER, nodes_per_chan, Fc_output); clb_ipin_to_tracks = alloc_and_load_clb_pin_to_tracks (RECEIVER, nodes_per_chan, Fc_input); tracks_to_clb_ipin = alloc_and_load_tracks_to_clb_ipin (nodes_per_chan, Fc_input, clb_ipin_to_tracks); pads_to_tracks = alloc_and_load_pads_to_tracks (nodes_per_chan, Fc_pad); tracks_to_pads = alloc_and_load_tracks_to_pads (pads_to_tracks, nodes_per_chan, Fc_pad); rr_edge_done = (boolean *) my_calloc (num_rr_nodes, sizeof (boolean)); alloc_and_load_rr_graph (rr_node_indices, clb_opin_to_tracks, tracks_to_clb_ipin, pads_to_tracks, tracks_to_pads, Fc_output, Fc_input, Fc_pad, nodes_per_chan, route_type, det_routing_arch, seg_details_x, seg_details_y); free (rr_edge_done); free_rr_node_indices (rr_node_indices); free_matrix3 (clb_opin_to_tracks, 0, pins_per_clb-1, 0, 3, 0, sizeof(int)); free_matrix3 (clb_ipin_to_tracks, 0, pins_per_clb-1, 0, 3, 0, sizeof(int)); free_ivec_matrix (tracks_to_clb_ipin, 0, nodes_per_chan-1, 0, 3); free_ivec_vector (tracks_to_pads, 0, nodes_per_chan-1); free_matrix (pads_to_tracks, 0, io_rat-1, 0, sizeof(int)); free_switch_block_conn (nodes_per_chan); free_edge_list_hard (&free_edge_list_head); save_segment_type_and_length_info (seg_details_x, nodes_per_chan, seg_details_y, nodes_per_chan); free_seg_details (seg_details_x, nodes_per_chan); free_seg_details (seg_details_y, nodes_per_chan); add_rr_graph_C_from_switches (timing_inf.ipin_cblock_C); /* dump_rr_graph ("rr_graph.echo"); */ check_rr_graph (route_type, det_routing_arch.num_switch); }
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);*/ }