| /* |
| Permission is hereby granted, free of charge, to any person |
| obtaining a copy of this software and associated documentation |
| files (the "Software"), to deal in the Software without |
| restriction, including without limitation the rights to use, |
| copy, modify, merge, publish, distribute, sublicense, and/or sell |
| copies of the Software, and to permit persons to whom the |
| Software is furnished to do so, subject to the following |
| conditions: |
| |
| The above copyright notice and this permission notice shall be |
| included in all copies or substantial portions of the Software. |
| |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
| EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
| OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
| NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
| HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
| OTHER DEALINGS IN THE SOFTWARE. |
| */ |
| #include <stdlib.h> |
| #include <stdio.h> |
| #include <string.h> |
| #include <sstream> |
| #include <vector> |
| |
| #include "vtr_error.h" |
| #include "vtr_time.h" |
| #include "odin_ii.h" |
| |
| #include "argparse.hpp" |
| |
| #include "arch_util.h" |
| |
| #include "odin_globals.h" |
| #include "odin_types.h" |
| #include "netlist_utils.h" |
| #include "arch_types.h" |
| #include "parse_making_ast.h" |
| #include "netlist_create_from_ast.h" |
| #include "ast_util.h" |
| #include "read_xml_config_file.h" |
| #include "read_xml_arch_file.h" |
| #include "partial_map.h" |
| #include "multipliers.h" |
| #include "netlist_check.h" |
| #include "read_blif.h" |
| #include "output_blif.h" |
| #include "netlist_cleanup.h" |
| |
| #include "hard_blocks.h" |
| #include "memories.h" |
| #include "simulate_blif.h" |
| |
| #include "netlist_visualizer.h" |
| #include "adders.h" |
| #include "subtractions.h" |
| #include "vtr_util.h" |
| #include "vtr_path.h" |
| #include "vtr_memory.h" |
| |
| |
| #define DEFAULT_OUTPUT "." |
| |
| int current_parse_file = -1; |
| t_arch Arch; |
| global_args_t global_args; |
| std::vector<t_physical_tile_type> physical_tile_types; |
| std::vector<t_logical_block_type> logical_block_types; |
| int block_tag = -1; |
| ids default_net_type = WIRE; |
| |
| enum ODIN_ERROR_CODE |
| { |
| SUCCESS, |
| ERROR_INITIALIZATION, |
| ERROR_PARSE_CONFIG, |
| ERROR_PARSE_ARGS, |
| ERROR_PARSE_ARCH, |
| ERROR_SYNTHESIS, |
| ERROR_PARSE_BLIF, |
| |
| }; |
| |
| static ODIN_ERROR_CODE synthesize_verilog() |
| { |
| double elaboration_time = wall_time(); |
| |
| printf("--------------------------------------------------------------------\n"); |
| printf("High-level synthesis Begin\n"); |
| /* Perform any initialization routines here */ |
| find_hard_multipliers(); |
| find_hard_adders(); |
| //find_hard_adders_for_sub(); |
| register_hard_blocks(); |
| |
| module_names_to_idx = sc_new_string_cache(); |
| |
| /* parse to abstract syntax tree */ |
| printf("Parser starting - we'll create an abstract syntax tree. Note this tree can be viewed using Grap Viz (see documentation)\n"); |
| init_parser(); |
| parse_to_ast(); |
| /** |
| * Note that the entry point for ast optimzations is done per module with the |
| * function void next_parsed_verilog_file(ast_node_t *file_items_list) |
| */ |
| |
| /* after the ast is made potentially do tagging for downstream links to verilog */ |
| if (global_args.high_level_block.provenance() == argparse::Provenance::SPECIFIED) |
| add_tag_data(); |
| |
| /** |
| * Now that we have a parse tree (abstract syntax tree [ast]) of |
| * the Verilog we want to make into a netlist. |
| */ |
| printf("Converting AST into a Netlist. Note this netlist can be viewed using GraphViz (see documentation)\n"); |
| create_netlist(); |
| |
| // Can't levelize yet since the large muxes can look like combinational loops when they're not |
| check_netlist(verilog_netlist); |
| |
| //START ################# NETLIST OPTIMIZATION ############################ |
| |
| /* point for all netlist optimizations. */ |
| printf("Performing Optimizations of the Netlist\n"); |
| if(hard_multipliers) |
| { |
| /* Perform a splitting of the multipliers for hard block mults */ |
| reduce_operations(verilog_netlist, MULTIPLY); |
| iterate_multipliers(verilog_netlist); |
| clean_multipliers(); |
| } |
| |
| if (sp_memory_list || dp_memory_list) |
| { |
| /* Perform a splitting of any hard block memories */ |
| iterate_memories(verilog_netlist); |
| free_memory_lists(); |
| } |
| |
| if(hard_adders) |
| { |
| /* Perform a splitting of the adders for hard block add */ |
| reduce_operations(verilog_netlist, ADD); |
| iterate_adders(verilog_netlist); |
| clean_adders(); |
| |
| /* Perform a splitting of the adders for hard block sub */ |
| reduce_operations(verilog_netlist, MINUS); |
| iterate_adders_for_sub(verilog_netlist); |
| clean_adders_for_sub(); |
| } |
| |
| //END ################# NETLIST OPTIMIZATION ############################ |
| |
| if (configuration.output_netlist_graphs ) |
| graphVizOutputNetlist(configuration.debug_output_path, "optimized", 1, verilog_netlist); /* Path is where we are */ |
| |
| /* point where we convert netlist to FPGA or other hardware target compatible format */ |
| printf("Performing Partial Map to target device\n"); |
| partial_map_top(verilog_netlist); |
| |
| /* Find any unused logic in the netlist and remove it */ |
| remove_unused_logic(verilog_netlist); |
| |
| /** |
| * point for outputs. This includes soft and hard mapping all structures to the |
| * target format. Some of these could be considred optimizations |
| */ |
| printf("Outputting the netlist to the specified output format\n"); |
| |
| output_blif(global_args.output_file.value().c_str(), verilog_netlist); |
| |
| module_names_to_idx = sc_free_string_cache(module_names_to_idx); |
| |
| cleanup_parser(); |
| |
| elaboration_time = wall_time() - elaboration_time; |
| |
| printf("Successful High-level synthesis by Odin\n\tBlif file available at %s\n\tRan in ",global_args.output_file.value().c_str()); |
| print_time(elaboration_time); |
| printf("\n"); |
| printf("--------------------------------------------------------------------\n"); |
| |
| report_mult_distribution(); |
| report_add_distribution(); |
| report_sub_distribution(); |
| deregister_hard_blocks(); |
| |
| //cleanup netlist |
| free_netlist(verilog_netlist); |
| |
| return SUCCESS; |
| } |
| |
| netlist_t *start_odin_ii(int argc,char **argv) |
| { |
| |
| try |
| { |
| /* Some initialization */ |
| one_string = vtr::strdup(ONE_VCC_CNS); |
| zero_string = vtr::strdup(ZERO_GND_ZERO); |
| pad_string = vtr::strdup(ZERO_PAD_ZERO); |
| |
| printf("--------------------------------------------------------------------\n"); |
| printf("Welcome to ODIN II version 0.1 - the better High level synthesis tools++ targetting FPGAs (mainly VPR)\n"); |
| printf("Email: jamieson.peter@gmail.com and ken@unb.ca for support issues\n\n"); |
| } |
| catch(vtr::VtrError& vtr_error) |
| { |
| printf("Odin failed to initialize %s with exit code%d\n", vtr_error.what(), ERROR_INITIALIZATION); |
| exit(ERROR_INITIALIZATION); |
| } |
| |
| try |
| { |
| /* Set up the global arguments to their default. */ |
| set_default_config(); |
| |
| /* get the command line options */ |
| get_options(argc, argv); |
| |
| create_directory(configuration.debug_output_path); |
| |
| } |
| catch(vtr::VtrError& vtr_error) |
| { |
| printf("Odin Failed Reading The command line arguments %s with exit code%d\n", vtr_error.what(), ERROR_PARSE_ARGS); |
| exit(ERROR_PARSE_ARGS); |
| } |
| catch(argparse::ArgParseError& arg_error) |
| { |
| printf("Odin Failed Reading The command line arguments %s with exit code%d\n", arg_error.what(), ERROR_PARSE_ARGS); |
| exit(ERROR_PARSE_ARGS); |
| } |
| |
| /* read the confirguration file .. get options presets the config values just in case theyr'e not read in with config file */ |
| if (global_args.config_file.provenance() == argparse::Provenance::SPECIFIED) |
| { |
| printf("Reading Configuration file\n"); |
| try |
| { |
| read_config_file(global_args.config_file.value().c_str()); |
| } |
| catch(vtr::VtrError& vtr_error) |
| { |
| printf("Odin Failed Reading Configuration file %s with exit code%d\n", vtr_error.what(), ERROR_PARSE_CONFIG); |
| exit(ERROR_PARSE_CONFIG); |
| } |
| } |
| |
| /* read the FPGA architecture file */ |
| if (global_args.arch_file.provenance() == argparse::Provenance::SPECIFIED) |
| { |
| printf("Reading FPGA Architecture file\n"); |
| try |
| { |
| XmlReadArch(global_args.arch_file.value().c_str(), false, &Arch, physical_tile_types, logical_block_types); |
| } |
| catch(vtr::VtrError& vtr_error) |
| { |
| printf("Odin Failed to load architecture file: %s with exit code%d\n", vtr_error.what(), ERROR_PARSE_ARCH); |
| exit(ERROR_PARSE_ARCH); |
| } |
| } |
| |
| /* do High level Synthesis */ |
| if (global_args.blif_file.provenance() != argparse::Provenance::SPECIFIED) |
| { |
| ODIN_ERROR_CODE error_code = synthesize_verilog(); |
| if(error_code) |
| { |
| printf("Odin Failed to parse Verilog with exit status: %d\n", error_code); |
| exit(error_code); |
| } |
| } |
| |
| /************************************************************* |
| * begin simulation section |
| */ |
| netlist_t *odin_netlist = NULL; |
| |
| if(global_args.blif_file.provenance() == argparse::Provenance::SPECIFIED |
| || global_args.interactive_simulation |
| || global_args.sim_num_test_vectors |
| || global_args.sim_vector_input_file.provenance() == argparse::Provenance::SPECIFIED) |
| { |
| // if we started with a verilog file read the output that was made since |
| // the simulator can only simulate blifs |
| if(global_args.blif_file.provenance() != argparse::Provenance::SPECIFIED) |
| { |
| configuration.list_of_file_names = { global_args.output_file }; |
| current_parse_file =0; |
| } |
| |
| try |
| { |
| odin_netlist = read_blif(); |
| } |
| catch(vtr::VtrError& vtr_error) |
| { |
| printf("Odin Failed to load blif file: %s with exit code:%d \n", vtr_error.what(), ERROR_PARSE_BLIF); |
| exit(ERROR_PARSE_BLIF); |
| } |
| } |
| |
| /* Simulate netlist */ |
| if(odin_netlist && !global_args.interactive_simulation |
| && (global_args.sim_num_test_vectors || (global_args.sim_vector_input_file.provenance() == argparse::Provenance::SPECIFIED) )) |
| { |
| printf("Netlist Simulation Begin\n"); |
| create_directory(global_args.sim_directory); |
| |
| simulate_netlist(odin_netlist); |
| } |
| |
| printf("--------------------------------------------------------------------\n"); |
| printf("Odin ran with exit status: %d\n", SUCCESS); |
| return odin_netlist; |
| } |
| |
| int terminate_odin_ii(netlist_t *odin_netlist) |
| { |
| |
| free_netlist(odin_netlist); |
| |
| //Clean-up |
| free_arch(&Arch); |
| free_type_descriptors(logical_block_types); |
| free_type_descriptors(physical_tile_types); |
| |
| return 0; |
| } |
| |
| struct ParseInitRegState { |
| int from_str(std::string str) |
| { |
| if (str == "0") return 0; |
| else if (str == "1") return 1; |
| else if (str == "X") return -1; |
| std::stringstream msg; |
| msg << "Invalid conversion from '" << str << "' (expected one of: " << argparse::join(default_choices(), ", ") << ")"; |
| throw argparse::ArgParseConversionError(msg.str()); |
| } |
| |
| std::string to_str(int val) |
| { |
| if (val == 0) return "0"; |
| else if (val == 1) return "1"; |
| else if (val == -1) return "X"; |
| std::stringstream msg; |
| msg << "Invalid conversion from " << val; |
| throw argparse::ArgParseConversionError(msg.str()); |
| } |
| |
| std::vector<std::string> default_choices() |
| { |
| return {"0", "1", "X"}; |
| } |
| }; |
| |
| /*--------------------------------------------------------------------------------------------- |
| * (function: get_options) |
| *-------------------------------------------------------------------------*/ |
| void get_options(int argc, char** argv) { |
| |
| auto parser = argparse::ArgumentParser(argv[0]); |
| |
| global_args.program_name = parser.prog(); |
| |
| auto& input_grp = parser.add_argument_group("input files"); |
| |
| input_grp.add_argument(global_args.config_file, "-c") |
| .help("Configuration file") |
| .metavar("XML_CONFIGURATION_FILE") |
| ; |
| |
| input_grp.add_argument(global_args.verilog_files, "-V") |
| .help("list of Verilog HDL file") |
| .nargs('+') |
| .metavar("VERILOG_FILE") |
| ; |
| |
| input_grp.add_argument(global_args.blif_file, "-b") |
| .help("BLIF file") |
| .metavar("BLIF_FILE") |
| ; |
| |
| auto& output_grp = parser.add_argument_group("output files"); |
| |
| output_grp.add_argument(global_args.output_file, "-o") |
| .help("Output file path") |
| .default_value("default_out.blif") |
| .metavar("OUTPUT_FILE_PATH") |
| ; |
| |
| auto& other_grp = parser.add_argument_group("other options"); |
| |
| other_grp.add_argument(global_args.show_help, "-h") |
| .help("Display this help message") |
| .action(argparse::Action::HELP) |
| ; |
| |
| other_grp.add_argument(global_args.arch_file, "-a") |
| .help("VTR FPGA architecture description file (XML)") |
| .metavar("ARCHITECTURE_FILE") |
| ; |
| |
| other_grp.add_argument(global_args.permissive, "--permissive") |
| .help("Turn possible_error_messages into warning_messages ... unexpected behaviour may occur") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_grp.add_argument(global_args.write_netlist_as_dot, "-G") |
| .help("Output netlist graph in graphviz .dot format") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_grp.add_argument(global_args.write_ast_as_dot, "-A") |
| .help("Output AST graph in graphviz .dot format") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_grp.add_argument(global_args.all_warnings, "-W") |
| .help("Print all warnings (can be substantial)") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_grp.add_argument(global_args.adder_def, "--adder_type") |
| .help("DEPRECATED") |
| .default_value("N/A") |
| .metavar("N/A") |
| ; |
| |
| other_grp.add_argument(global_args.adder_cin_global, "--adder_cin_global") |
| .help("Defines if the first cin of an adder/subtractor is connected to a global gnd/vdd instead of a dummy adder generating a gnd/vdd.") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_grp.add_argument(global_args.top_level_module_name, "--top_module") |
| .help("Allow to overwrite the top level module that odin would use") |
| .metavar("TOP_LEVEL_MODULE_NAME") |
| ; |
| |
| auto& rand_sim_grp = parser.add_argument_group("random simulation options"); |
| |
| rand_sim_grp.add_argument(global_args.sim_num_test_vectors, "-g") |
| .help("Number of random test vectors to generate") |
| .metavar("NUM_VECTORS") |
| ; |
| |
| rand_sim_grp.add_argument(global_args.sim_min_coverage, "--coverage") |
| .help("using the g argument we will simulate in blocks until a certain coverage is attained") |
| .metavar("MIN_COVERAGE") |
| ; |
| |
| rand_sim_grp.add_argument(global_args.sim_achieve_best, "--best_coverage") |
| .help("using the g argument we will simulate in blocks until best coverage is attained") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| rand_sim_grp.add_argument(global_args.sim_random_seed, "-r") |
| .help("Random seed") |
| .default_value("0") |
| .metavar("SEED") |
| ; |
| |
| rand_sim_grp.add_argument(global_args.sim_hold_low, "-L") |
| .help("list of primary inputs to hold high at cycle 0, and low for all subsequent cycles") |
| .nargs('+') |
| .metavar("PRIMARY_INPUTS") |
| ; |
| |
| rand_sim_grp.add_argument(global_args.sim_hold_high, "-H") |
| .help("list of primary inputs to hold low at cycle 0, and high for all subsequent cycles") |
| .nargs('+') |
| .metavar("PRIMARY_INPUTS") |
| ; |
| |
| |
| auto& vec_sim_grp = parser.add_argument_group("vector simulation options"); |
| |
| vec_sim_grp.add_argument(global_args.sim_vector_input_file, "-t") |
| .help("File of predefined input vectors to simulate") |
| .metavar("INPUT_VECTOR_FILE") |
| ; |
| |
| vec_sim_grp.add_argument(global_args.sim_vector_output_file, "-T") |
| .help("File of predefined output vectors to check against simulation") |
| .metavar("OUTPUT_VECTOR_FILE") |
| ; |
| |
| auto& other_sim_grp = parser.add_argument_group("other simulation options"); |
| |
| other_sim_grp.add_argument(global_args.parralelized_simulation, "-j") |
| .help("Number of threads allowed for simulator to use") |
| .default_value("1") |
| .metavar("PARALEL NODE COUNT") |
| ; |
| |
| other_sim_grp.add_argument(global_args.parralelized_simulation_in_batch, "--batch") |
| .help("DEPRECATED") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| .metavar("BATCH FLAG") |
| ; |
| |
| other_sim_grp.add_argument(global_args.sim_directory, "-sim_dir") |
| .help("Directory output for simulation") |
| .default_value(DEFAULT_OUTPUT) |
| .metavar("SIMULATION_DIRECTORY") |
| ; |
| |
| other_sim_grp.add_argument(global_args.sim_generate_three_valued_logic, "-3") |
| .help("Generate three valued logic, instead of binary") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_sim_grp.add_argument(global_args.interactive_simulation, "--interractive_simulation") |
| .help("prevent Odin from freeing element so that application leveraging the simulator can use the nodes") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_sim_grp.add_argument<int,ParseInitRegState>(global_args.sim_initial_value, "-U") |
| .help("Default initial register state") |
| .default_value("X") |
| .metavar("INIT_REG_STATE") |
| ; |
| |
| other_sim_grp.add_argument(global_args.sim_output_both_edges, "-E") |
| .help("Output after both edges of the clock (This is by default)") |
| .default_value("true") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_sim_grp.add_argument(global_args.sim_output_both_edges, "-R") |
| .help("DEPRECATED Output after rising edges of the clock only (Default after both edges)") |
| .default_value("true") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_sim_grp.add_argument(global_args.read_mif_input, "--read_mif") |
| .help("look for a mif file to read") |
| .default_value("false") |
| .action(argparse::Action::STORE_TRUE) |
| ; |
| |
| other_sim_grp.add_argument(global_args.sim_additional_pins, "-p") |
| .help("list of additional pins/nodes to monitor during simulation.\n" |
| "Eg: \"-p input~0 input~1\" monitors pin 0 and 1 of input, \n" |
| " or \"-p input\" monitors all pins of input as a single port. \n" |
| " or \"-p input~\" monitors all pins of input as separate ports. (split) \n" |
| "- Note: Non-existent pins are ignored. \n" |
| "- Matching is done via strstr so general strings will match \n" |
| " all similar pins and nodes.\n" |
| " (Eg: FF_NODE will create a single port with all flipflops) \n") |
| .nargs('+') |
| .metavar("PINS_TO_MONITOR") |
| ; |
| |
| parser.parse_args(argc, argv); |
| |
| //Check required options |
| if(!only_one_is_true({ |
| global_args.config_file.provenance() == argparse::Provenance::SPECIFIED, //have a config file |
| global_args.blif_file.provenance() == argparse::Provenance::SPECIFIED, //have a blif file |
| global_args.verilog_files.value().size() > 0 //have a verilog input list |
| })){ |
| parser.print_usage(); |
| error_message(ARG_ERROR,0,-1, "%s", "Must include only one of either:\n\ta config file(-c)\n\ta blif file(-b)\n\ta verilog file(-V)\n"); |
| } |
| |
| //adjust thread count |
| int thread_requested = global_args.parralelized_simulation; |
| int max_thread = std::thread::hardware_concurrency(); |
| |
| global_args.parralelized_simulation.set( |
| std::max(1, std::min( thread_requested, std::min( (CONCURENCY_LIMIT-1) , max_thread ))) |
| ,argparse::Provenance::SPECIFIED |
| ); |
| |
| //Allow some config values to be overriden from command line |
| if (!global_args.verilog_files.value().empty()) |
| { |
| //parse comma separated list of verilog files |
| configuration.list_of_file_names = global_args.verilog_files.value(); |
| } |
| else if(global_args.blif_file.provenance() == argparse::Provenance::SPECIFIED) |
| { |
| configuration.list_of_file_names = { std::string(global_args.blif_file) }; |
| } |
| |
| if (global_args.arch_file.provenance() == argparse::Provenance::SPECIFIED) { |
| configuration.arch_file = global_args.arch_file; |
| } |
| |
| if (global_args.write_netlist_as_dot.provenance() == argparse::Provenance::SPECIFIED) { |
| configuration.output_netlist_graphs = global_args.write_netlist_as_dot; |
| } |
| |
| if (global_args.write_ast_as_dot.provenance() == argparse::Provenance::SPECIFIED) { |
| configuration.output_ast_graphs = global_args.write_ast_as_dot; |
| } |
| |
| if (global_args.adder_cin_global.provenance() == argparse::Provenance::SPECIFIED) { |
| configuration.adder_cin_global = global_args.adder_cin_global; |
| } |
| |
| if(global_args.sim_directory.value() == DEFAULT_OUTPUT) |
| { |
| global_args.sim_directory.set(configuration.debug_output_path, argparse::Provenance::SPECIFIED); |
| } |
| |
| if(configuration.debug_output_path == DEFAULT_OUTPUT) |
| { |
| configuration.debug_output_path = global_args.sim_directory; |
| } |
| |
| if(global_args.permissive.value()) |
| { |
| warning_message(ARG_ERROR,-1,-1, "%s", "Permissive flag is ON. Undefined behaviour may occur\n"); |
| } |
| } |
| |
| /*--------------------------------------------------------------------------- |
| * (function: set_default_options) |
| *-------------------------------------------------------------------------*/ |
| void set_default_config() |
| { |
| /* Set up the global configuration. */ |
| configuration.output_type = std::string("blif"); |
| configuration.output_ast_graphs = 0; |
| configuration.output_netlist_graphs = 0; |
| configuration.print_parse_tokens = 0; |
| configuration.output_preproc_source = 0; // TODO: unused |
| configuration.debug_output_path = std::string(DEFAULT_OUTPUT); |
| configuration.arch_file = ""; |
| |
| configuration.fixed_hard_multiplier = 0; |
| configuration.split_hard_multiplier = 0; |
| |
| configuration.split_memory_width = 0; |
| configuration.split_memory_depth = 0; |
| |
| configuration.adder_cin_global = false; |
| |
| /* |
| * Soft logic cutoffs. If a memory or a memory resulting from a split |
| * has a width AND depth below these, it will be converted to soft logic. |
| */ |
| configuration.soft_logic_memory_width_threshold = 0; |
| configuration.soft_logic_memory_depth_threshold = 0; |
| } |