| #include "argparse.hpp" |
| #include "argparse_util.hpp" |
| |
| using argparse::ArgValue; |
| using argparse::ConvertedValue; |
| |
| #define TEST |
| |
| struct Args { |
| ArgValue<std::string> architecture_file; |
| ArgValue<std::string> circuit; |
| |
| ArgValue<bool> disp; |
| ArgValue<bool> auto_value; |
| |
| ArgValue<bool> pack; |
| ArgValue<bool> place; |
| ArgValue<bool> route; |
| |
| ArgValue<bool> show_help; |
| ArgValue<bool> timing_analysis; |
| ArgValue<const char*> slack_definition; |
| ArgValue<bool> echo_files; |
| ArgValue<bool> verify_file_digests; |
| ArgValue<unsigned> num_workers; |
| |
| ArgValue<std::string> blif_file; |
| ArgValue<std::string> net_file; |
| ArgValue<std::string> place_file; |
| ArgValue<std::string> route_file; |
| ArgValue<std::string> sdc_file; |
| ArgValue<std::string> outfile_prefix; |
| |
| ArgValue<bool> absorb_buffer_luts; |
| ArgValue<bool> sweep_dangling_primary_ios; |
| ArgValue<bool> sweep_dangling_nets; |
| ArgValue<bool> sweep_dangling_blocks; |
| ArgValue<bool> sweep_constant_primary_outputs; |
| |
| ArgValue<bool> connection_driven_clustering; |
| ArgValue<bool> allow_unrelated_clustering; |
| ArgValue<float> alpha_clustering; |
| ArgValue<float> beta_clustering; |
| ArgValue<bool> timing_driven_clustering; |
| ArgValue<std::string> cluster_seed_type; |
| |
| ArgValue<size_t> seed; |
| ArgValue<bool> enable_timing_computations; |
| ArgValue<float> inner_num; |
| ArgValue<float> init_t; |
| ArgValue<float> exit_t; |
| ArgValue<float> alpha_t; |
| ArgValue<std::string> fix_pins; |
| ArgValue<std::string> place_algorithm; |
| ArgValue<size_t> place_chan_width; |
| |
| ArgValue<float> timing_tradeoff; |
| ArgValue<int> recompute_crit_iter; |
| ArgValue<int> inner_loop_recompute_divider; |
| ArgValue<float> td_place_exp_first; |
| ArgValue<float> td_place_exp_last; |
| |
| ArgValue<int> max_router_iterations; |
| ArgValue<float> first_iter_pres_fac; |
| ArgValue<float> initial_pres_fac; |
| ArgValue<float> pres_fac_mult; |
| ArgValue<float> acc_fac; |
| ArgValue<int> bb_factor; |
| ArgValue<std::string> base_cost_type; |
| ArgValue<float> bend_cost; |
| ArgValue<std::string> route_type; |
| ArgValue<size_t> route_chan_width; |
| ArgValue<size_t> min_route_chan_width_hint; |
| ArgValue<bool> verify_binary_search; |
| ArgValue<std::string> router_algorithm; |
| ArgValue<int> min_incremental_reroute_fanout; |
| |
| ArgValue<float> astar_fac; |
| ArgValue<float> max_criticality; |
| ArgValue<float> criticality_exp; |
| ArgValue<std::string> routing_failure_predictor; |
| |
| ArgValue<bool> power; |
| ArgValue<std::string> tech_properties_file; |
| ArgValue<std::string> activity_file; |
| |
| ArgValue<bool> full_stats; |
| ArgValue<bool> gen_post_synthesis_netlist; |
| |
| ArgValue<std::vector<float>> one_or_more; |
| ArgValue<std::vector<float>> zero_or_more; |
| }; |
| |
| bool expect_pass(argparse::ArgumentParser& parser, std::vector<std::string> cmd_line); |
| bool expect_fail(argparse::ArgumentParser& parser, std::vector<std::string> cmd_line); |
| |
| struct OnOff { |
| ConvertedValue<bool> from_str(std::string str) { |
| ConvertedValue<bool> converted_value; |
| |
| if (str == "on") converted_value.set_value(true); |
| else if (str == "off") converted_value.set_value(false); |
| else converted_value.set_error("Invalid argument value"); |
| return converted_value; |
| } |
| |
| ConvertedValue<std::string> to_str(bool val) { |
| ConvertedValue<std::string> converted_value; |
| if (val) converted_value.set_value("on"); |
| else converted_value.set_value("off"); |
| return converted_value; |
| } |
| |
| std::vector<std::string> default_choices() { |
| return {"on", "off"}; |
| } |
| }; |
| |
| int main( |
| int |
| #ifndef TEST |
| argc |
| #endif |
| , const char** argv) { |
| Args args; |
| |
| auto parser = argparse::ArgumentParser(argv[0], "Test parser for libargparse"); |
| parser.epilog("This is the epilog"); |
| |
| auto& pos_grp = parser.add_argument_group("positional arguments"); |
| pos_grp.add_argument(args.architecture_file, "architecture") |
| .help("FPGA Architecture description file (XML)"); |
| pos_grp.add_argument(args.circuit, "circuit") |
| .help("Circuit file (or circuit name if --blif_file specified)"); |
| |
| auto& stage_grp = parser.add_argument_group("stage options"); |
| stage_grp.add_argument<bool,OnOff>(args.pack, "--pack") |
| .help("Run packing") |
| .action(argparse::Action::STORE_TRUE) |
| .default_value("off"); |
| stage_grp.add_argument<bool,OnOff>(args.place, "--place") |
| .help("Run placement") |
| .action(argparse::Action::STORE_TRUE) |
| .default_value("off"); |
| stage_grp.add_argument<bool,OnOff>(args.route, "--route") |
| .help("Run routing") |
| .action(argparse::Action::STORE_TRUE) |
| .default_value("off"); |
| stage_grp.add_argument<bool,OnOff>(args.route, "--analysis") |
| .help("Run analysis") |
| .action(argparse::Action::STORE_TRUE) |
| .required(true) |
| .default_value("off"); |
| |
| stage_grp.epilog("If none of the stage options are specified, all stages are run.\n" |
| "Analysis is always run after routing."); |
| |
| auto& gfx_grp = parser.add_argument_group("graphics options"); |
| gfx_grp.add_argument<bool,OnOff>(args.disp, "--disp") |
| .help("Enable or disable interactive graphics") |
| .default_value("off"); |
| gfx_grp.add_argument(args.auto_value, "--auto") |
| .help("Controls how often VPR pauses for interactive" |
| " graphics (requiring Proceed to be clicked)." |
| " Higher values pause less frequently") |
| .default_value("1") |
| .choices({"0", "1", "2"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& gen_grp = parser.add_argument_group("general options"); |
| gen_grp.add_argument(args.show_help, "--help", "-h") |
| .help("Show this help message then exit") |
| .action(argparse::Action::HELP); |
| gen_grp.add_argument<bool,OnOff>(args.timing_analysis, "--timing_analysis") |
| .help("Controls whether timing analysis (and timing driven optimizations) are enabled.") |
| .default_value("on") ; |
| gen_grp.add_argument(args.slack_definition, "--slack_definition") |
| .help("Sets the slack definition used by the classic timing analyyzer") |
| .default_value("R") |
| .choices({"R", "I", "S", "G", "C", "N"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| gen_grp.add_argument<bool,OnOff>(args.echo_files, "--echo_file") |
| .help("Generate echo files of key internal data structures." |
| " Useful for debugging VPR, and typically end in .echo") |
| .default_value("off") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| gen_grp.add_argument<bool,OnOff>(args.verify_file_digests, "--verify_file_digests") |
| .help("Verify that files loaded by VPR (e.g. architecture, netlist," |
| " previous packing/placement/routing) are consistent") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| gen_grp.add_argument(args.num_workers, "--num_workers", "-j") |
| .help("Number of parallel workers") |
| .default_value("1") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& file_grp = parser.add_argument_group("filename options"); |
| file_grp.add_argument(args.blif_file, "--blif_file") |
| .help("Path to technology mapped circuit in BLIF format") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| file_grp.add_argument(args.net_file, "--net_file") |
| .help("Path to packed netlist file") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| file_grp.add_argument(args.place_file, "--place_file") |
| .help("Path to placement file") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| file_grp.add_argument(args.route_file, "--route_file") |
| .help("Path to routing file") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| file_grp.add_argument(args.sdc_file, "--sdc_file") |
| .help("Path to timing constraints file in SDC format") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| file_grp.add_argument(args.outfile_prefix, "--outfile_prefix") |
| .help("Prefix for output files") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| |
| auto& netlist_grp = parser.add_argument_group("netlist options"); |
| netlist_grp.add_argument<bool,OnOff>(args.absorb_buffer_luts, "--absorb_buffer_luts") |
| .help("Controls whether LUTS programmed as buffers are absorbed by downstream logic") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_primary_ios, "--sweep_dangling_primary_ios") |
| .help("Controls whether dangling primary inputs and outputs are removed from the netlist") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_nets, "--sweep_dangling_nets") |
| .help("Controls whether dangling nets are removed from the netlist") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| netlist_grp.add_argument<bool,OnOff>(args.sweep_dangling_blocks, "--sweep_dangling_blocks") |
| .help("Controls whether dangling blocks are removed from the netlist") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| netlist_grp.add_argument<bool,OnOff>(args.sweep_constant_primary_outputs, "--sweep_constant_primary_outputs") |
| .help("Controls whether primary outputs driven by constant values are removed from the netlist") |
| .default_value("off") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& pack_grp = parser.add_argument_group("packing options"); |
| pack_grp.add_argument<bool,OnOff>(args.connection_driven_clustering, "--connection_driven_clustering") |
| .help("Controls whether or not packing prioritizes the absorption of nets with fewer" |
| " connections into a complex logic block over nets with more connections") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| pack_grp.add_argument<bool,OnOff>(args.allow_unrelated_clustering, "--allow_unrelated_clustering") |
| .help("Controls whether or not primitives with no attraction to the current cluster" |
| " can be packed into it") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| pack_grp.add_argument(args.alpha_clustering, "--alpha_clustering") |
| .help("Parameter that weights the optimization of timing vs area. 0.0 focuses solely on" |
| " area, 1.0 solely on timing.") |
| .default_value("0.75") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| pack_grp.add_argument(args.beta_clustering, "--beta_clustering") |
| .help("Parameter that weights the absorption of small nets vs signal sharing." |
| " 0.0 focuses solely on sharing, 1.0 solely on small net absoprtion." |
| " Only meaningful if --connection_driven_clustering=on") |
| .default_value("0.9") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| pack_grp.add_argument<bool,OnOff>(args.timing_driven_clustering, "--timing_driven_clustering") |
| .help("Controls whether custering optimizes for timing") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| pack_grp.add_argument(args.cluster_seed_type, "--cluster_seed_type") |
| .help("Controls how primitives are chosen as seeds." |
| " (Default: blend if timing driven, max_inputs otherwise)") |
| .choices({"blend", "timing", "max_inputs"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& place_grp = parser.add_argument_group("placement options"); |
| place_grp.add_argument(args.seed, "--seed") |
| .help("Placement random number generator seed") |
| .default_value("1") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument<bool,OnOff>(args.enable_timing_computations, "--enable_timing_computations") |
| .help("Displays delay statistics even if placement is not timing driven") |
| .default_value("on") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument(args.inner_num, "--inner_num") |
| .help("Controls number of moves per temperature: inner_num * num_blocks ^ (4/3)") |
| .default_value("10.0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument(args.init_t, "--init_t") |
| .help("Initial temperature for manual annealing schedule") |
| .default_value("100.0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument(args.exit_t, "--exit_t") |
| .help("Temperature at which annealing which terminate for manual annealing schedule") |
| .default_value("0.01") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument(args.alpha_t, "--alpha_t") |
| .help("Temperature scaling factor for manual annealing schedule." |
| " Old temperature is multiplied by alpha_t") |
| .default_value("0.01") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument(args.fix_pins, "--fix_pins") |
| .help("Fixes I/O pad locations during placement." |
| " Can be 'random' for a random initial assignment," |
| " 'off' to allow the place to optimize pad locations," |
| " or a file specifying the pad locations.") |
| .default_value("off") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument(args.place_algorithm, "--place_algorithm") |
| .help("Controls which placement algorithm is used") |
| .default_value("path_timing_driven") |
| .choices({"bounding_box", "path_timing_driven"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_grp.add_argument(args.place_chan_width, "--place_chan_width") |
| .help("Sets the assumed channel width during placement") |
| .default_value("100") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& place_timing_grp = parser.add_argument_group("timing-driven placement options"); |
| place_timing_grp.add_argument(args.timing_tradeoff, "--timing_tradeoff") |
| .help("Trade-off control between delay and wirelength during placement." |
| " 0.0 focuses completely on wirelength, 1.0 completely on timing") |
| .default_value("0.5") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_timing_grp.add_argument(args.recompute_crit_iter, "--recompute_crit_iter") |
| .help("Controls how many temperature updates occur between timing analysis during placement") |
| .default_value("1") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_timing_grp.add_argument(args.inner_loop_recompute_divider, "--inner_loop_recompute_divider") |
| .help("Controls how many timing analysies are perform per temperature during placement") |
| .default_value("0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_timing_grp.add_argument(args.td_place_exp_first, "--td_place_exp_first") |
| .help("Controls how critical a connection is as a function of slack at the start of placement." |
| " A value of zero treats all connections as equally critical (regardless of slack)." |
| " Values larger than 1.0 cause low slack connections to be treated more critically." |
| " The value increases to --td_place_exp_last during placement.") |
| .default_value("1.0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| place_timing_grp.add_argument(args.td_place_exp_last, "--td_place_exp_last") |
| .help("Controls how critical a connection is as a function of slack at the end of placement.") |
| .default_value("8.0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& route_grp = parser.add_argument_group("routing options"); |
| route_grp.add_argument(args.max_router_iterations, "--max_route_iterations") |
| .help("Maximum number of Pathfinder-based routing iterations before the circuit is" |
| " declared unroutable at a given channel width") |
| .default_value("50") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.initial_pres_fac, "--first_iter_pres_fac") |
| .help("Sets the present overuse factor for the first routing iteration") |
| .default_value("0.0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.initial_pres_fac, "--initial_pres_fac") |
| .help("Sets the present overuse factor for the second routing iteration") |
| .default_value("0.5") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.pres_fac_mult, "--pres_fac_mult") |
| .help("Sets the growth factor by which the present overuse penalty factor is" |
| " multiplied after each routing iteration") |
| .default_value("1.3") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.acc_fac, "--acc_fac") |
| .help("Specifies the accumulated overuse factor (historical congestion cost factor)") |
| .default_value("1.0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.bb_factor, "--bb_factor") |
| .help("Sets the distance (in channels) outside a connection's bounding box which can be explored") |
| .default_value("3") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.base_cost_type, "--base_cost_type") |
| .help("Sets the basic cost of routing resource nodes:\n" |
| " * demand_only: based on expected demand of node type\n" |
| " * delay_normalized: like demand_only but normalized to magnitude of typical routing resource delay\n" |
| "(Default: demand_only for bread-first router, delay_normalized for timing-driven router)") |
| .choices({"demand_only", "delay_normalized"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.bend_cost, "--bend_cost") |
| .help("The cost of a bend. (Default: 1.0 for global routing, 0.0 for detailed routing)") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.route_type, "--route_type") |
| .help("Specifies whether global, or combined global and detailed routing is performed.") |
| .choices({"global", "detailed"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.route_chan_width, "--route_chan_width") |
| .help("Specifies a fixed channel width to route at.") |
| .metavar("CHANNEL_WIDTH"); |
| route_grp.add_argument(args.min_route_chan_width_hint, "--min_route_chan_width_hint") |
| .help("Hint to the router what the minimum routable channel width is." |
| " Good hints can speed-up determining the minimum channel width.") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument<bool,OnOff>(args.verify_binary_search, "--verify_binary_search") |
| .help("Force the router to verify the minimum channel width by routing at" |
| " consecutively lower channel widths until two consecutive failures are observed.") |
| .default_value("off") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.router_algorithm, "--router_algorithm") |
| .help("Specifies the router algorithm to use.\n" |
| " * breadth_first: focuses solely on routability\n" |
| " * timing driven: focuses on routability and circuit speed\n") |
| .default_value("timing_driven") |
| .choices({"breadth_first", "timing_driven"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_grp.add_argument(args.min_incremental_reroute_fanout, "--min_incremental_reroute_fanout") |
| .help("The net fanout thershold above which nets will be re-routed incrementally.") |
| .default_value("64") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& route_timing_grp = parser.add_argument_group("timing-driven routing options"); |
| route_timing_grp.add_argument(args.astar_fac, "--astar_fac") |
| .help("How aggressive the directed search used by the timing-driven router is." |
| " Values between 1 and 2 are resonable; higher values trade some quality for reduced run-time") |
| .default_value("1.2") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_timing_grp.add_argument(args.max_criticality, "--max_criticality") |
| .help("Sets the maximum fraction of routing cost derived from delay (vs routability) for any net." |
| " 0.0 means no attention is paid to delay, 1.0 means nets on the critical path ignore congestion") |
| .default_value("0.99") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_timing_grp.add_argument(args.criticality_exp, "--criticality_exp") |
| .help("Controls the delay-routability trade-off for nets as a function of slack." |
| " 0.0 implies all nets treated equally regardless of slack." |
| " At large values (>> 1) only nets on the critical path will consider delay.") |
| .default_value("1.0") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| route_timing_grp.add_argument(args.routing_failure_predictor, "--routing_failure_predictor") |
| .help("Controls how aggressively the router will predict a routing as unsuccessful" |
| " and give up early. This can significantly reducing the run-time required" |
| " to find the minimum channel width).\n" |
| " * safe: Only abort when it is extremely unlikely a routing will succeed\n" |
| " * aggressive: Further reduce run-time by giving up earlier. This may increase the reported minimum channel width\n" |
| " * off: Only abort when the maximum number of iterations is reached\n") |
| .default_value("safe") |
| .choices({"safe", "aggressive", "off"}) |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& analysis_grp = parser.add_argument_group("analysis options"); |
| |
| analysis_grp.add_argument<bool,OnOff>(args.full_stats, "--full_stats") |
| .help("Print extra statistics about the circuit and it's routing (useful for wireability analysis)") |
| .default_value("off") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| analysis_grp.add_argument<bool,OnOff>(args.gen_post_synthesis_netlist, "--gen_post_synthesis_netlist") |
| .help("Generates the post-synthesis netlist (in BLIF and Verilog) along with delay information (in SDF)." |
| " Used for post-implementation simulation and verification") |
| .default_value("off") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& power_grp = parser.add_argument_group("power analysis options"); |
| power_grp.add_argument<bool,OnOff>(args.power, "--power") |
| .help("Enable power estimation") |
| .action(argparse::Action::STORE_TRUE) |
| .default_value("off") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| power_grp.add_argument(args.tech_properties_file, "--tech_properties_file") |
| .help("XML file containing CMOS technology properties (see documentation).") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| power_grp.add_argument(args.activity_file, "--activity_file") |
| .help("Signal activities file for all nets (see documentation).") |
| .show_in(argparse::ShowIn::HELP_ONLY); |
| |
| auto& test_grp = parser.add_argument_group("test options"); |
| |
| test_grp.add_argument(args.one_or_more, "--one_or_more") |
| .nargs('+'); |
| test_grp.add_argument(args.zero_or_more, "--zero_or_more") |
| .nargs('*'); |
| |
| #ifndef TEST |
| auto specified_args = parser.parse_args(argc, argv); |
| for(auto& arg : specified_args) { |
| std::cout << "Group: " << arg->group_name() << " Specified argument: " << arg->long_option(); |
| auto short_opt = arg->short_option(); |
| if (!short_opt.empty()) { |
| std::cout << "/" << short_opt; |
| } |
| std::cout << "\n"; |
| } |
| return 0; |
| #else |
| parser.print_help(); |
| std::cout << "\n"; |
| |
| std::vector<std::vector<std::string>> pass_cases = { |
| {"my_arch1.xml", "my_circuit1.blif", "--analysis"}, |
| {"my_arch2.xml", "my_circuit2.blif", "--analysis", "--pack"}, |
| {"my_arch3.xml", "my_circuit3.blif", "--analysis", "--timing_analysis", "on"}, |
| {"my_arch4.xml", "my_circuit4.blif", "--analysis", "--route_chan_width", "300"}, |
| {"my_arch5.xml", "my_circuit5.blif", "--analysis", "--criticality_exp", "2"}, //Float from integer |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--criticality_exp", "2.0"}, //Float |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j", "3"}, |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j3"}, //No-space for single letter arg |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j 3"}, //Space in short arg (but one string) |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j3", "--analysis"}, //Space in short arg (but one string) |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "3.24"}, //Single value argument |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "3.24", "10", "29"}, //Multiple values |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more"}, //No values |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "234"}, //One values |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "234", "254", "1.23"}, //Multiple values |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "234", "254", "1.23", "--one_or_more", "284"}, //* followed by + |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--zero_or_more", "--one_or_more", "284"}, //* followed by + |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "284", "--zero_or_more", }, //+ followed by * |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more", "284", "--zero_or_more", "798"}, //+ followed by * |
| {"my_arch6.xml", "--analysis", "--one_or_more", "3.24", "10", "29", "my_circuit6.blif"}, //positional after nargs='+' |
| {"my_arch6.xml", "--analysis", "--one_or_more", "3.24", "10", "29", "my_circuit6.blif"}, //positional after nargs='+' |
| {"my_arch6.xml", "--analysis", "--zero_or_more", "3.24", "10", "29", "my_circuit6.blif"}, //positional after nargs='*' |
| }; |
| |
| int num_failed = 0; |
| for(const auto& cmd_line : pass_cases) { |
| bool pass = expect_pass(parser, cmd_line); |
| |
| if(!pass) { |
| std::cout << " Failed to parse: '" << argparse::join(cmd_line, " ") << "'" << std::endl; |
| ++num_failed; |
| } |
| } |
| |
| std::vector<std::vector<std::string>> fail_cases = { |
| {"--analysis"}, //Missing positional |
| {"my_arch7.xml", "--analysis"}, //Missing positional |
| {"my_arch8.xml", "my_circuit8.blif", "--analysis", "extra"}, //Extra positional |
| {"my_arch9.xml", "my_circuit9.blif", "--analysis", "--route_chan_width"}, //Missing value to option |
| {"my_arch10.xml", "my_circuit10.blif", "--analysis", "--route_chan_width", "off"}, //Wrong option value type |
| {"my_arch11.xml", "my_circuit11.blif", "--analysis", "--disp", "132"}, //Wrong option value |
| {"my_arch12.xml", "my_circuit12.blif", "--analysis", "--route_chan_width", "300", "5"}, //Extra option value |
| {"my_arch13.xml", "my_circuit13.blif", "--analysis", "--pack", "on"}, //Extra option value to toggle option |
| {"my_arch14.xml", "my_circuit14.blif", "--analysis", "--route_chan_width", "300.5"}, //Type mismatch: float->int |
| {"my_arch15.xml", "my_circuit15.blif", "--analysis", "--criticality_exp", "on"}, //Wrong value type for float |
| {"my_arch16.xml", "my_circuit16.blif", "--analysis", "--slack_definition", "Z"}, //Valid type, but wrong choice |
| {"my_arch17.xml", "my_circuit17.blif"}, //Missing required |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "-j", "3.4"}, //Float when expected unsigned |
| {"my_arch6.xml", "my_circuit6.blif", "--analysis", "--one_or_more"}, //Expected at least one argument |
| }; |
| |
| for(const auto& cmd_line : fail_cases) { |
| bool pass = expect_fail(parser, cmd_line); |
| |
| if(!pass) { |
| std::cout << " Parsed successfully when expected failure: '" << argparse::join(cmd_line, " ") << "'" << std::endl; |
| ++num_failed; |
| } |
| } |
| |
| if (num_failed != 0) { |
| std::cout << "\n"; |
| std::cout << "FAILED: " << num_failed << " test(s)!" << "\n"; |
| } |
| |
| return num_failed; |
| #endif |
| } |
| |
| bool expect_pass(argparse::ArgumentParser& parser, std::vector<std::string> cmd_line) { |
| try { |
| parser.parse_args_throw(cmd_line); |
| } catch(const argparse::ArgParseHelp&) { |
| parser.reset_destinations(); |
| std::cout << "[PASS] Parsed help OK" << std::endl; |
| return true; |
| } catch(const argparse::ArgParseError& err) { |
| std::cout << "[FAIL] " << err.what() << std::endl; |
| parser.reset_destinations(); |
| return false; |
| } |
| std::cout << "[PASS] Parsed OK" << std::endl; |
| parser.reset_destinations(); |
| return true; |
| } |
| |
| bool expect_fail(argparse::ArgumentParser& parser, std::vector<std::string> cmd_line) { |
| try { |
| parser.parse_args_throw(cmd_line); |
| } catch(const argparse::ArgParseError& err) { |
| std::cout << "[PASS] " << err.what() << std::endl; |
| parser.reset_destinations(); |
| return true; |
| } |
| std::cout << "[FAIL] Parsed OK when expected fail" << std::endl; |
| parser.reset_destinations(); |
| return false; |
| } |