| #include <stdio.h> | |
| #include <string.h> | |
| #include <assert.h> | |
| #include <time.h> | |
| #include "util.h" | |
| #include "vpr_types.h" | |
| #include "globals.h" | |
| #include "graphics.h" | |
| #include "read_netlist.h" | |
| #include "check_netlist.h" | |
| #include "print_netlist.h" | |
| #include "draw.h" | |
| #include "place_and_route.h" | |
| #include "pack.h" | |
| #include "SetupGrid.h" | |
| #include "stats.h" | |
| #include "path_delay.h" | |
| #include "OptionTokens.h" | |
| #include "ReadOptions.h" | |
| #include "read_xml_arch_file.h" | |
| #include "SetupVPR.h" | |
| #include "rr_graph.h" | |
| #include "pb_type_graph.h" | |
| /******** Global variables ********/ | |
| int Fs_seed = -1; | |
| int W_seed = -1; | |
| int binary_search = -1; | |
| float grid_logic_tile_area = 0; | |
| float ipin_mux_trans_size = 0; | |
| /* t-vpack globals begin */ | |
| int num_logical_nets = 0, num_logical_blocks = 0, num_saved_logical_blocks = 0, num_saved_logical_nets = 0, num_subckts = 0; | |
| int num_p_inputs = 0, num_p_outputs = 0, num_luts = 0, num_latches = 0; | |
| struct s_net *vpack_net = NULL, *saved_logical_nets = NULL; | |
| struct s_logical_block *logical_block = NULL, *saved_logical_blocks = NULL; | |
| struct s_subckt *subckt = NULL; | |
| char *blif_circuit_name = NULL; | |
| /* t-vpack globals end */ | |
| /******** Netlist to be mapped stuff ********/ | |
| int num_nets = 0; | |
| struct s_net *clb_net = NULL; | |
| int num_blocks = 0; | |
| struct s_block *block = NULL; | |
| int num_ff = 0; | |
| int num_const_gen = 0; | |
| int *clb_to_vpack_net_mapping = NULL; /* [0..num_clb_nets - 1] */ | |
| int *vpack_to_clb_net_mapping = NULL; /* [0..num_vpack_nets - 1] */ | |
| /* This identifies the t_type_ptr of an IO block */ | |
| int num_types = 0; | |
| struct s_type_descriptor *type_descriptors = NULL; | |
| t_type_ptr IO_TYPE = NULL; | |
| t_type_ptr EMPTY_TYPE = NULL; | |
| t_type_ptr FILL_TYPE = NULL; | |
| /******** Physical architecture stuff ********/ | |
| int nx = 0; | |
| int ny = 0; | |
| /* TRUE if this is a global clb pin -- an input pin to which the netlist can * | |
| * connect global signals, but which does not connect into the normal * | |
| * routing via muxes etc. Marking pins like this (only clocks in my work) * | |
| * stops them from screwing up the input switch pattern in the rr_graph * | |
| * generator and from creating extra switches that the area model would * | |
| * count. */ | |
| int *chan_width_x = NULL; /* [0..ny] */ | |
| int *chan_width_y = NULL; /* [0..nx] */ | |
| struct s_grid_tile **grid = NULL; /* [0..(nx+1)][0..(ny+1)] Physical block list */ | |
| /******** Structures defining the routing ********/ | |
| /* Linked list start pointers. Define the routing. */ | |
| struct s_trace **trace_head = NULL; /* [0..(num_nets-1)] */ | |
| struct s_trace **trace_tail = NULL; /* [0..(num_nets-1)] */ | |
| /******** Structures defining the FPGA routing architecture ********/ | |
| int num_rr_nodes = 0; | |
| t_rr_node *rr_node = NULL; /* [0..(num_rr_nodes-1)] */ | |
| t_ivec ***rr_node_indices = NULL; | |
| int num_rr_indexed_data = 0; | |
| t_rr_indexed_data *rr_indexed_data = NULL; /* [0..(num_rr_indexed_data-1)] */ | |
| /* Gives the rr_node indices of net terminals. */ | |
| int **net_rr_terminals = NULL; /* [0..num_nets-1][0..num_pins-1] */ | |
| /* Gives information about all the switch types * | |
| * (part of routing architecture, but loaded in read_arch.c */ | |
| struct s_switch_inf *switch_inf = NULL; /* [0..(det_routing_arch.num_switch-1)] */ | |
| /* Stores the SOURCE and SINK nodes of all CLBs (not valid for pads). */ | |
| int **rr_blk_source = NULL; /* [0..(num_blocks-1)][0..(num_class-1)] */ | |
| /* primiary inputs removed from circuit */ | |
| struct s_linked_vptr *circuit_p_io_removed = NULL; | |
| /********** Structures representing timing graph information */ | |
| t_tnode *tnode = NULL; /* [0..num_tnodes - 1] */ | |
| int num_tnodes = 0; /* Number of nodes (pins) in the timing graph */ | |
| float pb_max_internal_delay = UNDEFINED; /* biggest internal delay of physical block */ | |
| const t_pb_type *pbtype_max_internal_delay = NULL; /* physical block type with highest internal delay */ | |
| /********************** Subroutines local to this module ********************/ | |
| static void PrintUsage(); | |
| static void PrintTitle(); | |
| static void freeArch(t_arch* Arch); | |
| static void freeOptions(t_options *options); | |
| static void InitArch(INP t_arch Arch); | |
| static void free_pb_type(t_pb_type *pb_type); | |
| static void free_complex_block_types(); | |
| /************************* Subroutine definitions ***************************/ | |
| /** | |
| * VPR program | |
| * Generate FPGA architecture given architecture description | |
| * Pack, place, and route circuit into FPGA architecture | |
| * Electrical timing analysis on results | |
| * | |
| * Overall steps | |
| * 1. Initialization | |
| * 2. Pack | |
| * 3. Place-and-route and timing analysis | |
| */ | |
| int | |
| main(int argc, | |
| char **argv) | |
| { | |
| t_options Options; | |
| t_arch Arch; | |
| t_model *user_models, *library_models; | |
| enum e_operation Operation; | |
| struct s_file_name_opts FileNameOpts; | |
| struct s_packer_opts PackerOpts; | |
| struct s_placer_opts PlacerOpts; | |
| struct s_annealing_sched AnnealSched; | |
| struct s_router_opts RouterOpts; | |
| struct s_det_routing_arch RoutingArch; | |
| t_segment_inf *Segments; | |
| t_timing_inf Timing; | |
| boolean ShowGraphics; | |
| boolean TimingEnabled; | |
| int GraphPause; | |
| clock_t begin, end; | |
| /* Print title message */ | |
| PrintTitle(); | |
| /* Print usage message if no args */ | |
| if(argc < 2) | |
| { | |
| PrintUsage(); | |
| exit(1); | |
| } | |
| /* Read in available inputs */ | |
| ReadOptions(argc, argv, &Options); | |
| /* Determine whether timing is on or off */ | |
| TimingEnabled = IsTimingEnabled(Options); | |
| /* Use inputs to configure VPR */ | |
| memset(&Arch, 0, sizeof(t_arch)); | |
| SetupVPR(Options, TimingEnabled, &FileNameOpts, &Arch, &Operation, &user_models, | |
| &library_models, &PackerOpts, &PlacerOpts, | |
| &AnnealSched, &RouterOpts, &RoutingArch, &Segments, | |
| &Timing, &ShowGraphics, &GraphPause); | |
| /* Check inputs are reasonable */ | |
| CheckOptions(Options, TimingEnabled); | |
| CheckArch(Arch, TimingEnabled); | |
| /* Verify settings don't conflict or otherwise not make sense */ | |
| CheckSetup(Operation, PlacerOpts, AnnealSched, RouterOpts, | |
| RoutingArch, Segments, Timing, Arch.Chans); | |
| fflush(stdout); | |
| /* Packing stage */ | |
| if(PackerOpts.doPacking) { | |
| begin = clock(); | |
| try_pack(&PackerOpts, &Arch, user_models, library_models); | |
| end = clock(); | |
| #ifdef CLOCKS_PER_SEC | |
| printf("Packing took %g seconds\n", (float)(end - begin) / CLOCKS_PER_SEC); | |
| #else | |
| printf("Packing took %g seconds\n", (float)(end - begin) / CLK_PER_SEC); | |
| #endif | |
| /* Free logical blocks and nets */ | |
| if(logical_block != NULL) { | |
| free_logical_blocks(); | |
| free_logical_nets(); | |
| } | |
| if(!PlacerOpts.doPlacement && !RouterOpts.doRouting) { | |
| return 0; | |
| } | |
| } | |
| /* Packing stage complete */ | |
| fflush(stdout); | |
| /* Read in netlist file for placement and routing */ | |
| if(FileNameOpts.NetFile) | |
| { | |
| read_netlist(FileNameOpts.NetFile, &Arch, &num_blocks, &block, &num_nets, &clb_net); | |
| /* This is done so that all blocks have subblocks and can be treated the same */ | |
| check_netlist(); | |
| } | |
| /* Output the current settings to console. */ | |
| ShowSetup(Options, Arch, TimingEnabled, Operation, FileNameOpts, PlacerOpts, | |
| AnnealSched, RouterOpts, RoutingArch, Segments, Timing); | |
| if(Operation == TIMING_ANALYSIS_ONLY) { | |
| do_constant_net_delay_timing_analysis( | |
| Timing, Options.constant_net_delay); | |
| return 0; | |
| } | |
| InitArch(Arch); | |
| fflush(stdout); | |
| /* Startup X graphics */ | |
| set_graphics_state(ShowGraphics, GraphPause, RouterOpts.route_type); | |
| if(ShowGraphics) | |
| { | |
| init_graphics("VPR: Versatile Place and Route for FPGAs"); | |
| alloc_draw_structs(); | |
| } | |
| /* Do placement and routing */ | |
| place_and_route(Operation, PlacerOpts, FileNameOpts.PlaceFile, | |
| FileNameOpts.NetFile, FileNameOpts.ArchFile, FileNameOpts.RouteFile, | |
| AnnealSched, RouterOpts, RoutingArch, | |
| Segments, Timing, Arch.Chans, Arch.models); | |
| fflush(stdout); | |
| /* Close down X Display */ | |
| if(ShowGraphics) | |
| close_graphics(); | |
| /* free data structures */ | |
| freeOptions(&Options); | |
| /* Free logical blocks and nets */ | |
| if(logical_block != NULL) { | |
| free_logical_blocks(); | |
| free_logical_nets(); | |
| } | |
| freeArch(&Arch); | |
| free_complex_block_types(); | |
| /* Return 0 to single success to scripts */ | |
| return 0; | |
| } | |
| /* Outputs usage message */ | |
| static void | |
| PrintUsage() | |
| { | |
| puts("Usage: vpr fpga_architecture.xml circuit_name [Options ...]"); | |
| puts(""); | |
| puts("General Options: [--nodisp] [--auto <int>] [--pack]"); | |
| puts("\t[--place] [--route] [--timing_analyze_only_with_net_delay <float>]"); | |
| puts("\t[--fast] [--full_stats] [--timing_analysis on | off] [--outfile_prefix <string>]"); | |
| puts("\t[--blif_file <string>][--net_file <string>][--place_file <string>][--route_file <string>]"); | |
| puts(""); | |
| puts("Packer Options:"); | |
| /* puts("\t[-global_clocks on|off]"); | |
| puts("\t[-hill_climbing on|off]"); | |
| puts("\t[-sweep_hanging_nets_and_inputs on|off]"); */ | |
| puts("\t[--timing_driven_clustering on|off]"); | |
| puts("\t[--cluster_seed_type timing|max_inputs] [--alpha_clustering <float>] [--beta_clustering <float>]"); | |
| /* puts("\t[-recompute_timing_after <int>] [-cluster_block_delay <float>]"); */ | |
| puts("\t[--allow_unrelated_clustering on|off]"); | |
| /* puts("\t[-allow_early_exit on|off]"); | |
| puts("\t[-intra_cluster_net_delay <float>] "); | |
| puts("\t[-inter_cluster_net_delay <float>] "); */ | |
| puts("\t[--connection_driven_clustering on|off] "); | |
| /* puts("\t[-packer_algorithm greedy|brute_force]"); | |
| puts("\t[-hack_no_legal_frac_lut]"); | |
| puts("\t[-hack_safe_latch]"); */ | |
| puts(""); | |
| puts("Placer Options:"); | |
| puts("\t[--place_algorithm bounding_box | net_timing_driven | path_timing_driven]"); | |
| puts("\t[--init_t <float>] [--exit_t <float>]"); | |
| puts("\t[--alpha_t <float>] [--inner_num <float>] [--seed <int>]"); | |
| puts("\t[--place_cost_exp <float>] [--place_cost_type linear | nonlinear]"); | |
| puts("\t[--place_chan_width <int>] [--num_regions <int>] "); | |
| puts("\t[--fix_pins random | <file.pads>]"); | |
| puts("\t[--enable_timing_computations on | off]"); | |
| puts("\t[--block_dist <int>]"); | |
| puts(""); | |
| puts("Placement Options Valid Only for Timing-Driven Placement:"); | |
| puts("\t[--timing_tradeoff <float>]"); | |
| puts("\t[--recompute_crit_iter <int>]"); | |
| puts("\t[--inner_loop_recompute_divider <int>]"); | |
| puts("\t[--td_place_exp_first <float>]"); | |
| puts("\t[--td_place_exp_last <float>]"); | |
| puts(""); | |
| puts("Router Options: [-max_router_iterations <int>] [-bb_factor <int>]"); | |
| puts("\t[--initial_pres_fac <float>] [--pres_fac_mult <float>]"); | |
| puts("\t[--acc_fac <float>] [--first_iter_pres_fac <float>]"); | |
| puts("\t[--bend_cost <float>] [--route_type global | detailed]"); | |
| puts("\t[--verify_binary_search] [--route_chan_width <int>]"); | |
| puts("\t[--router_algorithm breadth_first | timing_driven | directed_search]"); | |
| puts("\t[--base_cost_type intrinsic_delay | delay_normalized | demand_only]"); | |
| puts(""); | |
| puts("Routing options valid only for timing-driven routing:"); | |
| puts("\t[--astar_fac <float>] [--max_criticality <float>]"); | |
| puts("\t[--criticality_exp <float>]"); | |
| puts(""); | |
| } | |
| static void | |
| PrintTitle() | |
| { | |
| puts(""); | |
| puts("VPR FPGA Placement and Routing."); | |
| puts("Version: Version " VPR_VERSION); | |
| puts("Compiled: " __DATE__ "."); | |
| puts("Original VPR by V. Betz."); | |
| puts("Timing-driven placement enhancements by A. Marquardt."); | |
| puts("Single-drivers enhancements by Andy Ye with additions by."); | |
| puts("Mark Fang, Jason Luu, Ted Campbell"); | |
| puts("Heterogeneous stucture support by Jason Luu and Ted Campbell."); | |
| puts("T-VPack clustering integration by Jason Luu."); | |
| puts("Area-driven AAPack added by Jason Luu."); | |
| puts("This is free open source code under MIT license."); | |
| puts(""); | |
| } | |
| static void freeArch(t_arch* Arch) | |
| { | |
| int i; | |
| t_model *model, *prev; | |
| t_model_ports *port, *prev_port; | |
| struct s_linked_vptr *vptr, *vptr_prev; | |
| for(i = 0; i < Arch->num_switches; i++) { | |
| if(Arch->Switches->name != NULL) { | |
| free(Arch->Switches[i].name); | |
| } | |
| } | |
| free(Arch->Switches); | |
| for(i = 0; i < Arch->num_segments; i++) { | |
| if(Arch->Segments->cb != NULL) { | |
| free(Arch->Segments[i].cb); | |
| } | |
| if(Arch->Segments->sb != NULL) { | |
| free(Arch->Segments[i].sb); | |
| } | |
| } | |
| free(Arch->Segments); | |
| model = Arch->models; | |
| while(model) { | |
| port = model->inputs; | |
| while(port) { | |
| prev_port = port; | |
| port = port->next; | |
| free(prev_port->name); | |
| free(prev_port); | |
| } | |
| port = model->outputs; | |
| while(port) { | |
| prev_port = port; | |
| port = port->next; | |
| free(prev_port->name); | |
| free(prev_port); | |
| } | |
| vptr = model->pb_types; | |
| while(vptr) { | |
| vptr_prev = vptr; | |
| vptr = vptr->next; | |
| free(vptr_prev); | |
| } | |
| prev = model; | |
| model = model->next; | |
| if(prev->instances) | |
| free(prev->instances); | |
| free(prev->name); | |
| free(prev); | |
| } | |
| for(i = 0; i < 4; i++) { | |
| vptr = Arch->model_library[i].pb_types; | |
| while(vptr) { | |
| vptr_prev = vptr; | |
| vptr = vptr->next; | |
| free(vptr_prev); | |
| } | |
| } | |
| free(Arch->model_library[0].name); | |
| free(Arch->model_library[0].outputs->name); | |
| free(Arch->model_library[0].outputs); | |
| free(Arch->model_library[1].inputs->name); | |
| free(Arch->model_library[1].inputs); | |
| free(Arch->model_library[1].name); | |
| free(Arch->model_library[2].name); | |
| free(Arch->model_library[2].inputs[0].name); | |
| free(Arch->model_library[2].inputs[1].name); | |
| free(Arch->model_library[2].inputs); | |
| free(Arch->model_library[2].outputs->name); | |
| free(Arch->model_library[2].outputs); | |
| free(Arch->model_library[3].name); | |
| free(Arch->model_library[3].inputs->name); | |
| free(Arch->model_library[3].inputs); | |
| free(Arch->model_library[3].outputs->name); | |
| free(Arch->model_library[3].outputs); | |
| free(Arch->model_library); | |
| } | |
| static void free_complex_block_types() { | |
| int i, j, k, m; | |
| free_all_pb_graph_nodes(); | |
| for(i = 0; i < num_types; i++) { | |
| if(&type_descriptors[i] == EMPTY_TYPE) { | |
| continue; | |
| } | |
| free(type_descriptors[i].name); | |
| for(j = 0; j < type_descriptors[i].height; j++) { | |
| for(k = 0; k < 4; k ++) { | |
| for(m = 0; m < type_descriptors[i].num_pin_loc_assignments[j][k]; m++) { | |
| if(type_descriptors[i].pin_loc_assignments[j][k][m]) | |
| free(type_descriptors[i].pin_loc_assignments[j][k][m]); | |
| } | |
| free(type_descriptors[i].pinloc[j][k]); | |
| free(type_descriptors[i].pin_loc_assignments[j][k]); | |
| } | |
| free(type_descriptors[i].pinloc[j]); | |
| free(type_descriptors[i].pin_loc_assignments[j]); | |
| free(type_descriptors[i].num_pin_loc_assignments[j]); | |
| } | |
| free(type_descriptors[i].pinloc); | |
| free(type_descriptors[i].pin_loc_assignments); | |
| free(type_descriptors[i].num_pin_loc_assignments); | |
| free(type_descriptors[i].pin_height); | |
| free_pb_type(type_descriptors[i].pb_type); | |
| free(type_descriptors[i].pb_type); | |
| } | |
| } | |
| static void free_pb_type(t_pb_type *pb_type) { | |
| int i, j, k, m; | |
| struct s_linked_vptr *vptr, *prev; | |
| free(pb_type->name); | |
| if(pb_type->blif_model) | |
| free(pb_type->blif_model); | |
| for(i = 0; i < pb_type->num_modes; i++) { | |
| for(j = 0; j < pb_type->modes[i].num_pb_type_children; j++) { | |
| free_pb_type(&pb_type->modes[i].pb_type_children[j]); | |
| } | |
| free(pb_type->modes[i].pb_type_children); | |
| free(pb_type->modes[i].name); | |
| for(j = 0; j < pb_type->modes[i].num_interconnect; j++) { | |
| free(pb_type->modes[i].interconnect[j].input_string); | |
| free(pb_type->modes[i].interconnect[j].output_string); | |
| free(pb_type->modes[i].interconnect[j].name); | |
| for(k = 0; k < pb_type->modes[i].interconnect[j].num_annotations; k++) { | |
| if(pb_type->modes[i].interconnect[j].annotations[k].clock) | |
| free(pb_type->modes[i].interconnect[j].annotations[k].clock); | |
| if(pb_type->modes[i].interconnect[j].annotations[k].input_pins) { | |
| free(pb_type->modes[i].interconnect[j].annotations[k].input_pins); | |
| } | |
| if(pb_type->modes[i].interconnect[j].annotations[k].output_pins) { | |
| free(pb_type->modes[i].interconnect[j].annotations[k].output_pins); | |
| } | |
| for(m = 0; m < pb_type->modes[i].interconnect[j].annotations[k].num_value_prop_pairs; m++) { | |
| free(pb_type->modes[i].interconnect[j].annotations[k].value[m]); | |
| } | |
| free(pb_type->modes[i].interconnect[j].annotations[k].prop); | |
| free(pb_type->modes[i].interconnect[j].annotations[k].value); | |
| } | |
| free(pb_type->modes[i].interconnect[j].annotations); | |
| } | |
| if(pb_type->modes[i].interconnect) | |
| free(pb_type->modes[i].interconnect); | |
| } | |
| if(pb_type->modes) | |
| free(pb_type->modes); | |
| for(i = 0; i < pb_type->num_annotations; i++) { | |
| for(j = 0; j < pb_type->annotations[i].num_value_prop_pairs; j++) { | |
| free(pb_type->annotations[i].value[j]); | |
| } | |
| free(pb_type->annotations[i].value); | |
| free(pb_type->annotations[i].prop); | |
| if(pb_type->annotations[i].input_pins) { | |
| free(pb_type->annotations[i].input_pins); | |
| } | |
| if(pb_type->annotations[i].output_pins) { | |
| free(pb_type->annotations[i].output_pins); | |
| } | |
| if(pb_type->annotations[i].clock) { | |
| free(pb_type->annotations[i].clock); | |
| } | |
| } | |
| if(pb_type->num_annotations > 0) { | |
| free(pb_type->annotations); | |
| } | |
| vptr = pb_type->models_contained; | |
| while(vptr) { | |
| prev = vptr; | |
| vptr = vptr->next; | |
| free(prev); | |
| } | |
| for(i = 0; i < pb_type->num_ports; i++) { | |
| free(pb_type->ports[i].name); | |
| if(pb_type->ports[i].port_class) { | |
| free(pb_type->ports[i].port_class); | |
| } | |
| } | |
| free(pb_type->ports); | |
| } | |
| /* This is a modification of the init_arch function to use Arch as param. | |
| * Sets globals: nx, ny | |
| * Allocs globals: chan_width_x, chan_width_y, grid | |
| * Depends on num_clbs, pins_per_clb */ | |
| static void | |
| InitArch(INP t_arch Arch) | |
| { | |
| int *num_instances_type, *num_blocks_type; | |
| int i; | |
| int current, high, low; | |
| boolean fit; | |
| current = nint(sqrt(num_blocks)); /* current is the value of the smaller side of the FPGA */ | |
| low = 1; | |
| high = -1; | |
| num_instances_type = my_calloc(num_types, sizeof(int)); | |
| num_blocks_type = my_calloc(num_types, sizeof(int)); | |
| for(i = 0; i < num_blocks; i++) | |
| { | |
| num_blocks_type[block[i].type->index]++; | |
| } | |
| if(Arch.clb_grid.IsAuto) | |
| { | |
| /* Auto-size FPGA, perform a binary search */ | |
| while(high == -1 || low < high) | |
| { | |
| /* Generate grid */ | |
| if(Arch.clb_grid.Aspect >= 1.0) | |
| { | |
| ny = current; | |
| nx = nint(current * Arch.clb_grid.Aspect); | |
| } | |
| else | |
| { | |
| nx = current; | |
| ny = nint(current / Arch.clb_grid.Aspect); | |
| } | |
| #if DEBUG | |
| printf("Auto-sizing FPGA, try x = %d y = %d\n", nx, ny); | |
| #endif | |
| alloc_and_load_grid(num_instances_type); | |
| freeGrid(); | |
| /* Test if netlist fits in grid */ | |
| fit = TRUE; | |
| for(i = 0; i < num_types; i++) | |
| { | |
| if(num_blocks_type[i] > num_instances_type[i]) | |
| { | |
| fit = FALSE; | |
| break; | |
| } | |
| } | |
| /* get next value */ | |
| if(!fit) | |
| { | |
| /* increase size of max */ | |
| if(high == -1) | |
| { | |
| current = current * 2; | |
| if(current > MAX_SHORT) | |
| { | |
| printf(ERRTAG | |
| "FPGA required is too large for current architecture settings\n"); | |
| exit(1); | |
| } | |
| } | |
| else | |
| { | |
| if(low == current) | |
| current++; | |
| low = current; | |
| current = low + ((high - low) / 2); | |
| } | |
| } | |
| else | |
| { | |
| high = current; | |
| current = low + ((high - low) / 2); | |
| } | |
| } | |
| /* Generate grid */ | |
| if(Arch.clb_grid.Aspect >= 1.0) | |
| { | |
| ny = current; | |
| nx = nint(current * Arch.clb_grid.Aspect); | |
| } | |
| else | |
| { | |
| nx = current; | |
| ny = nint(current / Arch.clb_grid.Aspect); | |
| } | |
| alloc_and_load_grid(num_instances_type); | |
| printf("FPGA auto-sized to, x = %d y = %d\n", nx, ny); | |
| } | |
| else | |
| { | |
| nx = Arch.clb_grid.W; | |
| ny = Arch.clb_grid.H; | |
| alloc_and_load_grid(num_instances_type); | |
| } | |
| printf("The circuit will be mapped into a %d x %d array of clbs.\n", | |
| nx, ny); | |
| /* Test if netlist fits in grid */ | |
| fit = TRUE; | |
| for(i = 0; i < num_types; i++) | |
| { | |
| if(num_blocks_type[i] > num_instances_type[i]) | |
| { | |
| fit = FALSE; | |
| break; | |
| } | |
| } | |
| if(!fit) | |
| { | |
| printf(ERRTAG "Not enough physical locations for type %s, " | |
| "number of blocks is %d but number of locations is %d\n", | |
| type_descriptors[i].name, num_blocks_type[i], num_instances_type[i]); | |
| exit(1); | |
| } | |
| printf("\nResource Usage:\n"); | |
| for(i = 0; i < num_types; i++) | |
| { | |
| printf("Netlist %d\tblocks of type %s\n", | |
| num_blocks_type[i], type_descriptors[i].name); | |
| printf("Architecture %d\tblocks of type %s\n", | |
| num_instances_type[i], type_descriptors[i].name); | |
| } | |
| printf("\n"); | |
| chan_width_x = (int *)my_malloc((ny + 1) * sizeof(int)); | |
| chan_width_y = (int *)my_malloc((nx + 1) * sizeof(int)); | |
| free(num_blocks_type); | |
| free(num_instances_type); | |
| } | |
| static void freeOptions(t_options *options) { | |
| free(options->ArchFile); | |
| free(options->CircuitName); | |
| if(options->BlifFile) | |
| free(options->BlifFile); | |
| if(options->NetFile) | |
| free(options->NetFile); | |
| if(options->PlaceFile) | |
| free(options->PlaceFile); | |
| if(options->RouteFile) | |
| free(options->RouteFile); | |
| if(options->OutFilePrefix) | |
| free(options->OutFilePrefix); | |
| if(options->PinFile) | |
| free(options->PinFile); | |
| } | |