| #include <stdio.h> | |
| #include <string.h> | |
| #include <assert.h> | |
| #include "util.h" | |
| #include "vpr_types.h" | |
| #include "OptionTokens.h" | |
| #include "ReadOptions.h" | |
| /******** Function prototypes ********/ | |
| static const char *const *ReadBaseToken(INP const char *const *Args, | |
| OUTP enum e_OptionBaseToken *Token); | |
| static void Error(INP const char *Token); | |
| static void ErrorOption(INP const char *Option); | |
| static const char *const *ProcessOption(INP const char *const *Args, | |
| INOUTP t_options * Options); | |
| static const char *const *ReadFloat(INP const char *const *Args, | |
| OUTP float *Val); | |
| static const char *const *ReadInt(INP const char *const *Args, | |
| OUTP int *Val); | |
| static const char *const *ReadOnOff(INP const char *const *Args, | |
| OUTP boolean * Val); | |
| static const char *const *ReadClusterSeed(INP const char *const *Args, | |
| OUTP enum e_cluster_seed *Type); | |
| static const char *const *ReadFixPins(INP const char *const *Args, | |
| OUTP char **PinFile); | |
| static const char *const *ReadPlaceAlgorithm(INP const char *const *Args, | |
| OUTP enum e_place_algorithm | |
| *Algo); | |
| static const char *const *ReadPlaceCostType(INP const char *const *Args, | |
| OUTP enum place_c_types *Type); | |
| static const char *const *ReadRouterAlgorithm(INP const char *const *Args, | |
| OUTP enum e_router_algorithm | |
| *Algo); | |
| static const char *const *ReadPackerAlgorithm(INP const char *const *Args, | |
| OUTP enum e_packer_algorithm | |
| *Algo); | |
| static const char *const *ReadBaseCostType(INP const char *const *Args, | |
| OUTP enum e_base_cost_type *BaseCostType); | |
| static const char *const *ReadRouteType(INP const char *const *Args, | |
| OUTP enum e_route_type *Type); | |
| static const char *const *ReadString(INP const char *const *Args, | |
| OUTP char **Val); | |
| /******** Subroutine implementations ********/ | |
| void | |
| ReadOptions(INP int argc, | |
| INP char **argv, | |
| OUTP t_options * Options) | |
| { | |
| char **Args, **head; | |
| /* Clear values and pointers to zero */ | |
| memset(Options, 0, sizeof(t_options)); | |
| /* Alloc a new pointer list for args with a NULL at end. | |
| * This makes parsing the same as for archfile for consistency. | |
| * Skips the first arg as it is the program image path */ | |
| --argc; | |
| ++argv; | |
| head = Args = (char **)my_malloc(sizeof(char *) * (argc + 1)); | |
| memcpy(Args, argv, (sizeof(char *) * argc)); | |
| Args[argc] = NULL; | |
| /* Go through the command line args. If they have hyphens they are | |
| * options. Otherwise assume they are part of the four mandatory | |
| * arguments */ | |
| while(*Args) | |
| { | |
| if(strncmp("--", *Args, 2) == 0) | |
| { | |
| *Args += 2; /* Skip the prefix */ | |
| Args = | |
| (char **)ProcessOption((const char *const *)Args, | |
| Options); | |
| } | |
| else if(strncmp("-", *Args, 1) == 0) | |
| { | |
| *Args += 1; /* Skip the prefix */ | |
| Args = | |
| (char **)ProcessOption((const char *const *)Args, | |
| Options); | |
| } | |
| else if(NULL == Options->ArchFile) | |
| { | |
| Options->ArchFile = my_strdup(*Args); | |
| ++Args; | |
| } | |
| else if(NULL == Options->CircuitName) | |
| { | |
| Options->CircuitName = my_strdup(*Args); | |
| ++Args; | |
| } | |
| else | |
| { | |
| /* Not an option and arch and net already specified so fail */ | |
| Error(*Args); | |
| } | |
| } | |
| free(head); | |
| } | |
| static const char *const * | |
| ProcessOption(INP const char *const *Args, | |
| INOUTP t_options * Options) | |
| { | |
| enum e_OptionBaseToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadBaseToken(Args, &Token); | |
| if(Token < OT_BASE_UNKNOWN) | |
| { | |
| ++Options->Count[Token]; | |
| } | |
| switch (Token) | |
| { | |
| /* File naming options */ | |
| case OT_BLIF_FILE: | |
| return ReadString(Args, &Options->BlifFile); | |
| case OT_NET_FILE: | |
| return ReadString(Args, &Options->NetFile); | |
| case OT_PLACE_FILE: | |
| return ReadString(Args, &Options->PlaceFile); | |
| case OT_ROUTE_FILE: | |
| return ReadString(Args, &Options->RouteFile); | |
| /* General Options */ | |
| case OT_NODISP: | |
| return Args; | |
| case OT_AUTO: | |
| return ReadInt(Args, &Options->GraphPause); | |
| case OT_PACK: | |
| case OT_ROUTE: | |
| case OT_PLACE: | |
| return Args; | |
| case OT_TIMING_ANALYZE_ONLY_WITH_NET_DELAY: | |
| return ReadFloat(Args, &Options->constant_net_delay); | |
| case OT_FAST: | |
| case OT_FULL_STATS: | |
| return Args; | |
| case OT_TIMING_ANALYSIS: | |
| return ReadOnOff(Args, &Options->TimingAnalysis); | |
| case OT_OUTFILE_PREFIX: | |
| return ReadString(Args, &Options->OutFilePrefix); | |
| /* Clustering Options */ | |
| case OT_GLOBAL_CLOCKS: | |
| return ReadOnOff(Args, &Options->global_clocks); | |
| case OT_HILL_CLIMBING_FLAG: | |
| return ReadOnOff(Args, &Options->hill_climbing_flag); | |
| case OT_SWEEP_HANGING_NETS_AND_INPUTS: | |
| return ReadOnOff(Args, &Options->sweep_hanging_nets_and_inputs); | |
| case OT_TIMING_DRIVEN_CLUSTERING: | |
| return ReadOnOff(Args, &Options->timing_driven); | |
| case OT_CLUSTER_SEED: | |
| return ReadClusterSeed(Args, &Options->cluster_seed_type); | |
| case OT_ALPHA_CLUSTERING: | |
| return ReadFloat(Args, &Options->alpha); | |
| case OT_BETA_CLUSTERING: | |
| return ReadFloat(Args, &Options->beta); | |
| case OT_RECOMPUTE_TIMING_AFTER: | |
| return ReadInt(Args, &Options->recompute_timing_after); | |
| case OT_CLUSTER_BLOCK_DELAY: | |
| return ReadFloat(Args, &Options->block_delay); | |
| case OT_ALLOW_UNRELATED_CLUSTERING: | |
| return ReadOnOff(Args, &Options->allow_unrelated_clustering); | |
| case OT_ALLOW_EARLY_EXIT: | |
| return ReadOnOff(Args, &Options->allow_early_exit); | |
| case OT_INTRA_CLUSTER_NET_DELAY: | |
| return ReadFloat(Args, &Options->intra_cluster_net_delay); | |
| case OT_INTER_CLUSTER_NET_DELAY: | |
| return ReadFloat(Args, &Options->inter_cluster_net_delay); | |
| case OT_CONNECTION_DRIVEN_CLUSTERING: | |
| return ReadOnOff(Args, &Options->connection_driven); | |
| case OT_SKIP_CLUSTERING: | |
| return Args; | |
| case OT_PACKER_ALGORITHM: | |
| return ReadPackerAlgorithm(Args, &Options->packer_algorithm); | |
| case OT_HACK_NO_LEGAL_FRAC_LUT: | |
| return Args; | |
| case OT_HACK_SAFE_LATCH: | |
| return Args; | |
| /* Placer Options */ | |
| case OT_PLACE_ALGORITHM: | |
| return ReadPlaceAlgorithm(Args, &Options->PlaceAlgorithm); | |
| case OT_INIT_T: | |
| return ReadFloat(Args, &Options->PlaceInitT); | |
| case OT_EXIT_T: | |
| return ReadFloat(Args, &Options->PlaceExitT); | |
| case OT_ALPHA_T: | |
| return ReadFloat(Args, &Options->PlaceAlphaT); | |
| case OT_INNER_NUM: | |
| return ReadFloat(Args, &Options->PlaceInnerNum); | |
| case OT_SEED: | |
| return ReadInt(Args, &Options->Seed); | |
| case OT_PLACE_COST_EXP: | |
| return ReadFloat(Args, &Options->place_cost_exp); | |
| case OT_PLACE_COST_TYPE: | |
| return ReadPlaceCostType(Args, &Options->PlaceCostType); | |
| case OT_PLACE_CHAN_WIDTH: | |
| return ReadInt(Args, &Options->PlaceChanWidth); | |
| case OT_NUM_REGIONS: | |
| return ReadInt(Args, &Options->PlaceNonlinearRegions); | |
| case OT_FIX_PINS: | |
| return ReadFixPins(Args, &Options->PinFile); | |
| case OT_ENABLE_TIMING_COMPUTATIONS: | |
| return ReadOnOff(Args, &Options->ShowPlaceTiming); | |
| case OT_BLOCK_DIST: | |
| return ReadInt(Args, &Options->block_dist); | |
| /* Placement Options Valid Only for Timing-Driven Placement */ | |
| case OT_TIMING_TRADEOFF: | |
| return ReadFloat(Args, &Options->PlaceTimingTradeoff); | |
| case OT_RECOMPUTE_CRIT_ITER: | |
| return ReadInt(Args, &Options->RecomputeCritIter); | |
| case OT_INNER_LOOP_RECOMPUTE_DIVIDER: | |
| return ReadInt(Args, &Options->inner_loop_recompute_divider); | |
| case OT_TD_PLACE_EXP_FIRST: | |
| return ReadFloat(Args, &Options->place_exp_first); | |
| case OT_TD_PLACE_EXP_LAST: | |
| return ReadFloat(Args, &Options->place_exp_last); | |
| /* Router Options */ | |
| case OT_MAX_ROUTER_ITERATIONS: | |
| return ReadInt(Args, &Options->max_router_iterations); | |
| case OT_BB_FACTOR: | |
| return ReadInt(Args, &Options->bb_factor); | |
| case OT_INITIAL_PRES_FAC: | |
| return ReadFloat(Args, &Options->initial_pres_fac); | |
| case OT_PRES_FAC_MULT: | |
| return ReadFloat(Args, &Options->pres_fac_mult); | |
| case OT_ACC_FAC: | |
| return ReadFloat(Args, &Options->acc_fac); | |
| case OT_FIRST_ITER_PRES_FAC: | |
| return ReadFloat(Args, &Options->first_iter_pres_fac); | |
| case OT_BEND_COST: | |
| return ReadFloat(Args, &Options->bend_cost); | |
| case OT_ROUTE_TYPE: | |
| return ReadRouteType(Args, &Options->RouteType); | |
| case OT_VERIFY_BINARY_SEARCH: | |
| return Args; | |
| case OT_ROUTE_CHAN_WIDTH: | |
| return ReadInt(Args, &Options->RouteChanWidth); | |
| case OT_ROUTER_ALGORITHM: | |
| return ReadRouterAlgorithm(Args, &Options->RouterAlgorithm); | |
| case OT_BASE_COST_TYPE: | |
| return ReadBaseCostType(Args, &Options->base_cost_type); | |
| /* Routing options valid only for timing-driven routing */ | |
| case OT_ASTAR_FAC: | |
| return ReadFloat(Args, &Options->astar_fac); | |
| case OT_MAX_CRITICALITY: | |
| return ReadFloat(Args, &Options->max_criticality); | |
| case OT_CRITICALITY_EXP: | |
| return ReadFloat(Args, &Options->criticality_exp); | |
| default: | |
| ErrorOption(*PrevArgs); | |
| } | |
| return NULL; | |
| } | |
| static const char *const * | |
| ReadBaseToken(INP const char *const *Args, | |
| OUTP enum e_OptionBaseToken *Token) | |
| { | |
| const struct s_TokenPair *Cur; | |
| /* Empty string is end of tokens marker */ | |
| if(NULL == *Args) | |
| Error(*Args); | |
| /* Linear search for the pair */ | |
| Cur = OptionBaseTokenList; | |
| while(Cur->Str) | |
| { | |
| if(strcmp(*Args, Cur->Str) == 0) | |
| { | |
| *Token = Cur->Enum; | |
| return ++Args; | |
| } | |
| ++Cur; | |
| } | |
| *Token = OT_BASE_UNKNOWN; | |
| return ++Args; | |
| } | |
| static const char *const * | |
| ReadToken(INP const char *const *Args, | |
| OUTP enum e_OptionArgToken *Token) | |
| { | |
| const struct s_TokenPair *Cur; | |
| /* Empty string is end of tokens marker */ | |
| if(NULL == *Args) | |
| Error(*Args); | |
| /* Linear search for the pair */ | |
| Cur = OptionArgTokenList; | |
| while(Cur->Str) | |
| { | |
| if(strcmp(*Args, Cur->Str) == 0) | |
| { | |
| *Token = Cur->Enum; | |
| return ++Args; | |
| } | |
| ++Cur; | |
| } | |
| *Token = OT_ARG_UNKNOWN; | |
| return ++Args; | |
| } | |
| /* Called for parse errors. Spits out a message and then exits program. */ | |
| static void | |
| Error(INP const char *Token) | |
| { | |
| if(Token) | |
| { | |
| printf(ERRTAG "Unexpected token '%s' on command line\n", Token); | |
| } | |
| else | |
| { | |
| printf(ERRTAG "Missing token at end of command line\n"); | |
| } | |
| exit(1); | |
| } | |
| static void | |
| ErrorOption(INP const char *Option) | |
| { | |
| printf(ERRTAG "Unexpected option '%s' on command line\n", Option); | |
| exit(1); | |
| } | |
| static const char *const * | |
| ReadClusterSeed(INP const char *const *Args, | |
| OUTP enum e_cluster_seed *Type) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_TIMING: | |
| *Type = VPACK_TIMING; | |
| break; | |
| case OT_MAX_INPUTS: | |
| *Type = NONLINEAR_CONG; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadPackerAlgorithm(INP const char *const *Args, | |
| OUTP enum e_packer_algorithm *Algo) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_GREEDY: | |
| *Algo = PACK_GREEDY; | |
| break; | |
| case OT_BRUTE_FORCE: | |
| *Algo = PACK_BRUTE_FORCE; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadRouterAlgorithm(INP const char *const *Args, | |
| OUTP enum e_router_algorithm *Algo) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_BREADTH_FIRST: | |
| *Algo = BREADTH_FIRST; | |
| break; | |
| case OT_DIRECTED_SEARCH: | |
| *Algo = DIRECTED_SEARCH; | |
| break; | |
| case OT_TIMING_DRIVEN: | |
| *Algo = TIMING_DRIVEN; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadBaseCostType(INP const char *const *Args, | |
| OUTP enum e_base_cost_type *BaseCostType) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_INTRINSIC_DELAY: | |
| *BaseCostType = INTRINSIC_DELAY; | |
| break; | |
| case OT_DELAY_NORMALIZED: | |
| *BaseCostType = DELAY_NORMALIZED; | |
| break; | |
| case OT_DEMAND_ONLY: | |
| *BaseCostType = DEMAND_ONLY; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadRouteType(INP const char *const *Args, | |
| OUTP enum e_route_type *Type) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_GLOBAL: | |
| *Type = GLOBAL; | |
| break; | |
| case OT_DETAILED: | |
| *Type = DETAILED; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadPlaceCostType(INP const char *const *Args, | |
| OUTP enum place_c_types *Type) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_LINEAR: | |
| *Type = LINEAR_CONG; | |
| break; | |
| case OT_NONLINEAR: | |
| *Type = NONLINEAR_CONG; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadPlaceAlgorithm(INP const char *const *Args, | |
| OUTP enum e_place_algorithm *Algo) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_BOUNDING_BOX: | |
| *Algo = BOUNDING_BOX_PLACE; | |
| break; | |
| case OT_NET_TIMING_DRIVEN: | |
| *Algo = NET_TIMING_DRIVEN_PLACE; | |
| break; | |
| case OT_PATH_TIMING_DRIVEN: | |
| *Algo = PATH_TIMING_DRIVEN_PLACE; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadFixPins(INP const char *const *Args, | |
| OUTP char **PinFile) | |
| { | |
| enum e_OptionArgToken Token; | |
| int Len; | |
| const char *const *PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| if(OT_RANDOM != Token) | |
| { | |
| Len = 1 + strlen(*PrevArgs); | |
| *PinFile = (char *)my_malloc(Len * sizeof(char)); | |
| memcpy(*PinFile, *PrevArgs, Len); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadOnOff(INP const char *const *Args, | |
| OUTP boolean * Val) | |
| { | |
| enum e_OptionArgToken Token; | |
| const char *const *PrevArgs; | |
| PrevArgs = Args; | |
| Args = ReadToken(Args, &Token); | |
| switch (Token) | |
| { | |
| case OT_ON: | |
| *Val = TRUE; | |
| break; | |
| case OT_OFF: | |
| *Val = FALSE; | |
| break; | |
| default: | |
| Error(*PrevArgs); | |
| } | |
| return Args; | |
| } | |
| static const char *const * | |
| ReadInt(INP const char *const *Args, | |
| OUTP int *Val) | |
| { | |
| if(NULL == *Args) | |
| Error(*Args); | |
| if((**Args > '9') || (**Args < '0')) | |
| Error(*Args); | |
| *Val = atoi(*Args); | |
| return ++Args; | |
| } | |
| static const char *const * | |
| ReadFloat(INP const char *const *Args, | |
| OUTP float *Val) | |
| { | |
| if(NULL == *Args) | |
| { | |
| Error(*Args); | |
| } | |
| if((**Args != '-') && | |
| (**Args != '.') && ((**Args > '9') || (**Args < '0'))) | |
| { | |
| Error(*Args); | |
| } | |
| *Val = atof(*Args); | |
| return ++Args; | |
| } | |
| static const char *const * | |
| ReadString(INP const char *const *Args, | |
| OUTP char **Val) | |
| { | |
| if(NULL == *Args) | |
| { | |
| Error(*Args); | |
| } | |
| *Val = my_strdup(*Args); | |
| return ++Args; | |
| } |