| #include <assert.h> | |
| #include <stdio.h> | |
| #include <sys/types.h> | |
| #include <time.h> | |
| #include "util.h" | |
| #include "vpr_types.h" | |
| #include "vpr_utils.h" | |
| #include "globals.h" | |
| #include "place_and_route.h" | |
| #include "mst.h" | |
| #include "place.h" | |
| #include "read_place.h" | |
| #include "route_export.h" | |
| #include "draw.h" | |
| #include "stats.h" | |
| #include "check_route.h" | |
| #include "rr_graph.h" | |
| #include "path_delay.h" | |
| #include "net_delay.h" | |
| #include "timing_place.h" | |
| #include "read_xml_arch_file.h" | |
| /******************* Subroutines local to this module ************************/ | |
| 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); | |
| static float comp_width(t_chan * chan, | |
| float x, | |
| float separation); | |
| void post_place_sync(INP int num_blocks, | |
| INOUTP const struct s_block block_list[]); | |
| void free_pb_data(t_pb *pb); | |
| /************************* Subroutine Definitions ****************************/ | |
| 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; | |
| } | |
| } | |
| 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; | |
| try_w_limit = 0; | |
| attempt_count = 0; | |
| while(final == -1) | |
| { | |
| printf("low, high, current %d %d %d\n", low, high, current); | |
| fflush(stdout); | |
| /* Check if the channel width is huge to avoid overflow. Assume the * | |
| * circuit is unroutable with the current router options if we're * | |
| * going to overflow. */ | |
| if(router_opts.fixed_channel_width != NO_FIXED_CHANNEL_WIDTH) | |
| { | |
| if(current > router_opts.fixed_channel_width * 4) | |
| { | |
| printf | |
| ("This circuit appears to be unroutable with the current " | |
| "router options. Last failed at %d\n", low); | |
| printf("Aborting routing procedure.\n"); | |
| exit(1); | |
| } | |
| } | |
| else | |
| { | |
| if(current > 1000) | |
| { | |
| printf | |
| ("This circuit requires a channel width above 1000, probably isn't going to route.\n"); | |
| printf("Aborting routing procedure.\n"); | |
| exit(1); | |
| } | |
| } | |
| if((current * 3) < det_routing_arch.Fs) | |
| { | |
| printf | |
| ("width factor is now below specified Fs. Stop search.\n"); | |
| final = high; | |
| break; | |
| } | |
| if(placer_opts.place_freq == PLACE_ALWAYS) | |
| { | |
| placer_opts.place_chan_width = current; | |
| try_place(placer_opts, annealing_sched, chan_width_dist, | |
| router_opts, det_routing_arch, segment_inf, | |
| timing_inf, &mst); | |
| } | |
| success = | |
| try_route(current, router_opts, det_routing_arch, segment_inf, | |
| timing_inf, net_slack, net_delay, chan_width_dist, | |
| clb_opins_used_locally, mst, &Fc_clipped); | |
| attempt_count++; | |
| fflush(stdout); | |
| #if 1 | |
| if(success && (Fc_clipped == FALSE)) | |
| { | |
| #else | |
| if(success | |
| && (Fc_clipped == FALSE | |
| || det_routing_arch.Fc_type == FRACTIONAL)) | |
| { | |
| #endif | |
| if(current == high) { | |
| /* Can't go any lower */ | |
| final = current; | |
| } | |
| high = current; | |
| /* If Fc_output is too high, set to full connectivity but warn the user */ | |
| if(Fc_clipped) | |
| { | |
| printf | |
| ("Warning: Fc_output was too high and was clipped to full (maximum) connectivity.\n"); | |
| } | |
| /* If we're re-placing constantly, save placement in case it is best. */ | |
| #if 0 | |
| if(placer_opts.place_freq == PLACE_ALWAYS) | |
| { | |
| print_place(place_file, net_file, arch_file); | |
| } | |
| #endif | |
| /* Save routing in case it is best. */ | |
| save_routing(best_routing, clb_opins_used_locally, | |
| saved_clb_opins_used_locally); | |
| if((high - low) <= 1 * udsd_multiplier) | |
| final = high; | |
| if(low != -1) | |
| { | |
| current = (high + low) / 2; | |
| } | |
| else | |
| { | |
| current = high / 2; /* haven't found lower bound yet */ | |
| } | |
| } | |
| else | |
| { /* last route not successful */ | |
| if(success && Fc_clipped) | |
| { | |
| printf | |
| ("Routing rejected, Fc_output was too high.\n"); | |
| success = FALSE; | |
| } | |
| low = current; | |
| if(high != -1) | |
| { | |
| if((high - low) <= 1 * udsd_multiplier) | |
| final = high; | |
| current = (high + low) / 2; | |
| } | |
| else | |
| { | |
| if(router_opts.fixed_channel_width != | |
| NO_FIXED_CHANNEL_WIDTH) | |
| { | |
| /* FOR Wneed = f(Fs) search */ | |
| if(low < | |
| router_opts.fixed_channel_width + 30) | |
| { | |
| current = | |
| low + 5 * udsd_multiplier; | |
| } | |
| else | |
| { | |
| printf | |
| ("Aborting: Wneed = f(Fs) search found exceedingly large Wneed (at least %d)\n", | |
| low); | |
| exit(1); | |
| } | |
| } | |
| else | |
| { | |
| current = low * 2; /* Haven't found upper bound yet */ | |
| } | |
| } | |
| } | |
| current = current + current % udsd_multiplier; | |
| } | |
| /* The binary search above occassionally does not find the minimum * | |
| * routeable channel width. Sometimes a circuit that will not route * | |
| * in 19 channels will route in 18, due to router flukiness. If * | |
| * verify_binary_search is set, the code below will ensure that FPGAs * | |
| * with channel widths of final-2 and final-3 wil not route * | |
| * successfully. If one does route successfully, the router keeps * | |
| * trying smaller channel widths until two in a row (e.g. 8 and 9) * | |
| * fail. */ | |
| if(verify_binary_search) | |
| { | |
| printf | |
| ("\nVerifying that binary search found min. channel width ...\n"); | |
| prev_success = TRUE; /* Actually final - 1 failed, but this makes router */ | |
| /* try final-2 and final-3 even if both fail: safer */ | |
| prev2_success = TRUE; | |
| current = final - 2; | |
| while(prev2_success || prev_success) | |
| { | |
| if((router_opts.fixed_channel_width != | |
| NO_FIXED_CHANNEL_WIDTH) | |
| && (current < router_opts.fixed_channel_width)) | |
| { | |
| break; | |
| } | |
| fflush(stdout); | |
| if(current < 1) | |
| break; | |
| if(placer_opts.place_freq == PLACE_ALWAYS) | |
| { | |
| placer_opts.place_chan_width = current; | |
| try_place(placer_opts, annealing_sched, | |
| chan_width_dist, router_opts, | |
| det_routing_arch, segment_inf, | |
| timing_inf, &mst); | |
| } | |
| success = | |
| try_route(current, router_opts, det_routing_arch, | |
| segment_inf, timing_inf, net_slack, | |
| net_delay, chan_width_dist, | |
| clb_opins_used_locally, mst, &Fc_clipped); | |
| if(success && Fc_clipped == FALSE) | |
| { | |
| final = current; | |
| save_routing(best_routing, clb_opins_used_locally, | |
| saved_clb_opins_used_locally); | |
| if(placer_opts.place_freq == PLACE_ALWAYS) | |
| { | |
| print_place(place_file, net_file, | |
| arch_file); | |
| } | |
| } | |
| prev2_success = prev_success; | |
| prev_success = success; | |
| current--; | |
| if(det_routing_arch.directionality == UNI_DIRECTIONAL) { | |
| current--; /* width must be even */ | |
| } | |
| } | |
| } | |
| /* End binary search verification. */ | |
| /* Restore the best placement (if necessary), the best routing, and * | |
| * * the best channel widths for final drawing and statistics output. */ | |
| init_chan(final, chan_width_dist); | |
| #if 0 | |
| if(placer_opts.place_freq == PLACE_ALWAYS) | |
| { | |
| printf("Reading best placement back in.\n"); | |
| placer_opts.place_chan_width = final; | |
| read_place(place_file, net_file, arch_file, placer_opts, | |
| router_opts, chan_width_dist, det_routing_arch, | |
| segment_inf, timing_inf, &mst); | |
| } | |
| #endif | |
| free_rr_graph(); | |
| build_rr_graph(graph_type, | |
| num_types, 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); | |
| restore_routing(best_routing, clb_opins_used_locally, | |
| saved_clb_opins_used_locally); | |
| check_route(router_opts.route_type, det_routing_arch.num_switch, | |
| clb_opins_used_locally); | |
| get_serial_num(); | |
| if(Fc_clipped) | |
| { | |
| printf | |
| ("Warning: Best routing Fc_output too high, clipped to full (maximum) connectivity.\n"); | |
| } | |
| printf("Best routing used a channel width factor of %d.\n\n", final); | |
| routing_stats(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 */ | |
| init_draw_coords(max_pins_per_clb); | |
| sprintf(msg, "Routing succeeded with a channel width factor of %d.", | |
| final); | |
| update_screen(MAJOR, msg, ROUTING, timing_inf.timing_analysis_enabled); | |
| if(timing_inf.timing_analysis_enabled) | |
| { | |
| #ifdef CREATE_ECHO_FILES | |
| print_timing_graph_as_blif("post_flow_timing_graph.blif", models); | |
| #endif | |
| free_timing_graph(net_slack); | |
| free_net_delay(net_delay, &net_delay_chunk_list_head); | |
| } | |
| free_route_structs(clb_opins_used_locally); | |
| free_saved_routing(best_routing, saved_clb_opins_used_locally); | |
| fflush(stdout); | |
| return (final); | |
| } | |
| void | |
| init_chan(int cfactor, | |
| t_chan_width_dist chan_width_dist) | |
| { | |
| /* Assigns widths to channels (in tracks). Minimum one track * | |
| * per channel. io channels are io_rat * maximum in interior * | |
| * tracks wide. The channel distributions read from the architecture * | |
| * file are scaled by cfactor. */ | |
| float x, separation, chan_width_io; | |
| int nio, i; | |
| t_chan chan_x_dist, chan_y_dist; | |
| chan_width_io = chan_width_dist.chan_width_io; | |
| chan_x_dist = chan_width_dist.chan_x_dist; | |
| chan_y_dist = chan_width_dist.chan_y_dist; | |
| /* io channel widths */ | |
| nio = (int)floor(cfactor * chan_width_io + 0.5); | |
| if(nio == 0) | |
| nio = 1; /* No zero width channels */ | |
| chan_width_x[0] = chan_width_x[ny] = nio; | |
| chan_width_y[0] = chan_width_y[nx] = nio; | |
| if(ny > 1) | |
| { | |
| separation = 1. / (ny - 2.); /* Norm. distance between two channels. */ | |
| x = 0.; /* This avoids div by zero if ny = 2. */ | |
| chan_width_x[1] = (int)floor(cfactor * comp_width(&chan_x_dist, x, | |
| separation) + | |
| 0.5); | |
| /* No zero width channels */ | |
| chan_width_x[1] = max(chan_width_x[1], 1); | |
| for(i = 1; i < ny - 1; i++) | |
| { | |
| x = (float)i / ((float)(ny - 2.)); | |
| chan_width_x[i + 1] = | |
| (int)floor(cfactor * | |
| comp_width(&chan_x_dist, x, | |
| separation) + 0.5); | |
| chan_width_x[i + 1] = max(chan_width_x[i + 1], 1); | |
| } | |
| } | |
| if(nx > 1) | |
| { | |
| separation = 1. / (nx - 2.); /* Norm. distance between two channels. */ | |
| x = 0.; /* Avoids div by zero if nx = 2. */ | |
| chan_width_y[1] = (int)floor(cfactor * comp_width(&chan_y_dist, x, | |
| separation) + | |
| 0.5); | |
| chan_width_y[1] = max(chan_width_y[1], 1); | |
| for(i = 1; i < nx - 1; i++) | |
| { | |
| x = (float)i / ((float)(nx - 2.)); | |
| chan_width_y[i + 1] = | |
| (int)floor(cfactor * | |
| comp_width(&chan_y_dist, x, | |
| separation) + 0.5); | |
| chan_width_y[i + 1] = max(chan_width_y[i + 1], 1); | |
| } | |
| } | |
| #ifdef VERBOSE | |
| printf("\nchan_width_x:\n"); | |
| for(i = 0; i <= ny; i++) | |
| printf("%d ", chan_width_x[i]); | |
| printf("\n\nchan_width_y:\n"); | |
| for(i = 0; i <= nx; i++) | |
| printf("%d ", chan_width_y[i]); | |
| printf("\n\n"); | |
| #endif | |
| } | |
| static float | |
| comp_width(t_chan * chan, | |
| float x, | |
| float separation) | |
| { | |
| /* Return the relative channel density. *chan points to a channel * | |
| * functional description data structure, and x is the distance * | |
| * (between 0 and 1) we are across the chip. separation is the * | |
| * distance between two channels, in the 0 to 1 coordinate system. */ | |
| float val; | |
| switch (chan->type) | |
| { | |
| case UNIFORM: | |
| val = chan->peak; | |
| break; | |
| case GAUSSIAN: | |
| val = (x - chan->xpeak) * (x - chan->xpeak) / (2 * chan->width * | |
| chan->width); | |
| val = chan->peak * exp(-val); | |
| val += chan->dc; | |
| break; | |
| case PULSE: | |
| val = (float)fabs((double)(x - chan->xpeak)); | |
| if(val > chan->width / 2.) | |
| { | |
| val = 0; | |
| } | |
| else | |
| { | |
| val = chan->peak; | |
| } | |
| val += chan->dc; | |
| break; | |
| case DELTA: | |
| val = x - chan->xpeak; | |
| if(val > -separation / 2. && val <= separation / 2.) | |
| val = chan->peak; | |
| else | |
| val = 0.; | |
| val += chan->dc; | |
| break; | |
| default: | |
| printf("Error in comp_width: Unknown channel type %d.\n", | |
| chan->type); | |
| exit(1); | |
| break; | |
| } | |
| return (val); | |
| } | |
| /* After placement, logical pins for blocks, and nets must be updated to correspond with physical pins of type */ | |
| /* This function should only be called once */ | |
| void | |
| post_place_sync(INP int num_blocks, | |
| INOUTP const struct s_block block_list[]) | |
| { | |
| int iblk, j, k, inet; | |
| t_type_ptr type; | |
| int max_num_block_pins; | |
| /* Go through each block */ | |
| for(iblk = 0; iblk < num_blocks; ++iblk) | |
| { | |
| type = block[iblk].type; | |
| assert(type->num_pins % type->capacity == 0); | |
| max_num_block_pins = type->num_pins / type->capacity; | |
| /* Logical location and physical location is offset by z * max_num_block_pins */ | |
| /* Sync blocks and nets */ | |
| for(j = 0; j < max_num_block_pins; j++) | |
| { | |
| inet = block[iblk].nets[j]; | |
| if(inet != OPEN && block[iblk].z > 0) | |
| { | |
| assert(block[iblk]. | |
| nets[j + | |
| block[iblk].z * max_num_block_pins] == | |
| OPEN); | |
| block[iblk].nets[j + | |
| block[iblk].z * | |
| max_num_block_pins] = | |
| block[iblk].nets[j]; | |
| block[iblk].nets[j] = OPEN; | |
| for(k = 0; k <= clb_net[inet].num_sinks; k++) | |
| { | |
| if(clb_net[inet].node_block[k] == iblk) | |
| { | |
| assert(clb_net[inet]. | |
| node_block_pin[k] == j); | |
| clb_net[inet].node_block_pin[k] = | |
| j + | |
| block[iblk].z * | |
| max_num_block_pins; | |
| break; | |
| } | |
| } | |
| assert(k <= clb_net[inet].num_sinks); | |
| } | |
| } | |
| } | |
| } | |
| void | |
| free_pb_data(t_pb *pb) | |
| { | |
| int i, j; | |
| const t_pb_type *pb_type; | |
| t_rr_node *temp; | |
| if(pb == NULL || pb->name == NULL) { | |
| return; | |
| } | |
| pb_type = pb->pb_graph_node->pb_type; | |
| /* free existing rr graph for pb */ | |
| if(pb->rr_graph) { | |
| temp = rr_node; | |
| rr_node = pb->rr_graph; | |
| num_rr_nodes = pb->pb_graph_node->total_pb_pins; | |
| free_rr_graph(); | |
| rr_node = temp; | |
| } | |
| if(pb_type->num_modes > 0) { | |
| /* Free children of pb */ | |
| for(i = 0; i < pb_type->modes[pb->mode].num_pb_type_children; i++) { | |
| for(j = 0; j < pb_type->modes[pb->mode].pb_type_children[i].num_pb; j++) { | |
| if(pb->child_pbs[i]) { | |
| free_pb_data(&pb->child_pbs[i][j]); | |
| } | |
| } | |
| } | |
| } | |
| /* Frees all the pb data structures. */ | |
| if(pb->name) { | |
| free(pb->name); | |
| if(pb->child_pbs) { | |
| free(pb->child_pbs); | |
| } | |
| } | |
| } |