1061 lines
31 KiB
C
1061 lines
31 KiB
C
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <assert.h>
|
|
#include "util.h"
|
|
#include "hash.h"
|
|
#include "vpr_types.h"
|
|
#include "OptionTokens.h"
|
|
#include "ReadOptions.h"
|
|
#include "read_settings.h"
|
|
#include "globals.h"
|
|
|
|
static boolean EchoEnabled;
|
|
|
|
static boolean Generate_PostSynthesis_Netlist;
|
|
|
|
static boolean *echoFileEnabled = NULL;
|
|
static char **echoFileNames = NULL;
|
|
|
|
static char **outputFileNames = NULL;
|
|
|
|
/******** Function prototypes ********/
|
|
|
|
static char **ReadBaseToken(INP char **Args, OUTP enum e_OptionBaseToken *Token);
|
|
static void Error(INP const char *Token);
|
|
static char **ProcessOption(INP char **Args, INOUTP t_options * Options);
|
|
static void MergeOptions(INOUTP t_options * dest, INP t_options * src, int id);
|
|
static char **ReadFloat(INP char **Args, OUTP float *Val);
|
|
static char **ReadInt(INP char **Args, OUTP int *Val);
|
|
static char **ReadOnOff(INP char **Args, OUTP boolean * Val);
|
|
static char **ReadClusterSeed(INP char **Args, OUTP enum e_cluster_seed *Type);
|
|
static char **ReadFixPins(INP char **Args, OUTP char **PinFile);
|
|
static char **ReadPlaceAlgorithm(INP char **Args,
|
|
OUTP enum e_place_algorithm *Algo);
|
|
static char **ReadRouterAlgorithm(INP char **Args,
|
|
OUTP enum e_router_algorithm *Algo);
|
|
static char **ReadPackerAlgorithm(INP char **Args,
|
|
OUTP enum e_packer_algorithm *Algo);
|
|
static char **ReadBaseCostType(INP char **Args,
|
|
OUTP enum e_base_cost_type *BaseCostType);
|
|
static char **ReadRouteType(INP char **Args, OUTP enum e_route_type *Type);
|
|
static char **ReadString(INP char **Args, OUTP char **Val);
|
|
|
|
/******** Globally Accessible Function ********/
|
|
/* Determines whether timing analysis should be on or off.
|
|
Unless otherwise specified, always default to timing.
|
|
*/
|
|
boolean IsTimingEnabled(INP t_options *Options) {
|
|
/* First priority to the '--timing_analysis' flag */
|
|
if (Options->Count[OT_TIMING_ANALYSIS]) {
|
|
return Options->TimingAnalysis;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/* Determines whether file echo should be on or off.
|
|
Unless otherwise specified, always default to on.
|
|
*/
|
|
boolean IsEchoEnabled(INP t_options *Options) {
|
|
/* First priority to the '--echo_file' flag */
|
|
if (Options->Count[OT_CREATE_ECHO_FILE]) {
|
|
return Options->CreateEchoFile;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
boolean getEchoEnabled(void) {
|
|
return EchoEnabled;
|
|
}
|
|
|
|
void setEchoEnabled(boolean echo_enabled) {
|
|
/* enable echo outputs */
|
|
EchoEnabled = echo_enabled;
|
|
if(echoFileEnabled == NULL) {
|
|
/* initialize default echo options */
|
|
alloc_and_load_echo_file_info();
|
|
}
|
|
}
|
|
|
|
boolean GetPostSynthesisOption(void){
|
|
return Generate_PostSynthesis_Netlist;
|
|
}
|
|
|
|
void SetPostSynthesisOption(boolean post_synthesis_enabled){
|
|
Generate_PostSynthesis_Netlist = post_synthesis_enabled;
|
|
}
|
|
|
|
boolean IsPostSynthesisEnabled(INP t_options *Options) {
|
|
/* First priority to the '--generate_postsynthesis_netlist' flag */
|
|
if (Options->Count[OT_GENERATE_POST_SYNTHESIS_NETLIST]) {
|
|
return Options->Generate_Post_Synthesis_Netlist;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
void setAllEchoFileEnabled(boolean value) {
|
|
int i;
|
|
for(i = 0; i < (int) E_ECHO_END_TOKEN; i++) {
|
|
echoFileEnabled[i] = value;
|
|
}
|
|
}
|
|
|
|
void setEchoFileEnabled(enum e_echo_files echo_option, boolean value) {
|
|
echoFileEnabled[(int)echo_option] = value;
|
|
}
|
|
|
|
void setEchoFileName(enum e_echo_files echo_option, const char *name) {
|
|
if(echoFileNames[(int)echo_option] != NULL) {
|
|
free(echoFileNames[(int)echo_option]);
|
|
}
|
|
echoFileNames[(int)echo_option] = my_strdup(name);
|
|
}
|
|
|
|
boolean isEchoFileEnabled(enum e_echo_files echo_option) {
|
|
if(echoFileEnabled == NULL) {
|
|
return FALSE;
|
|
} else {
|
|
return echoFileEnabled[(int)echo_option];
|
|
}
|
|
}
|
|
char *getEchoFileName(enum e_echo_files echo_option) {
|
|
return echoFileNames[(int)echo_option];
|
|
}
|
|
|
|
void alloc_and_load_echo_file_info() {
|
|
echoFileEnabled = (boolean*)my_calloc((int) E_ECHO_END_TOKEN, sizeof(boolean));
|
|
echoFileNames = (char**)my_calloc((int) E_ECHO_END_TOKEN, sizeof(char*));
|
|
|
|
setAllEchoFileEnabled(TRUE);
|
|
|
|
setEchoFileName(E_ECHO_INITIAL_CLB_PLACEMENT, "initial_clb_placement.echo");
|
|
setEchoFileName(E_ECHO_INITIAL_PLACEMENT_TIMING_GRAPH, "initial_placement_timing_graph.echo");
|
|
setEchoFileName(E_ECHO_INITIAL_PLACEMENT_SLACK, "initial_placement_slack.echo");
|
|
setEchoFileName(E_ECHO_INITIAL_PLACEMENT_CRITICALITY, "initial_placement_criticality.echo");
|
|
setEchoFileName(E_ECHO_END_CLB_PLACEMENT, "end_clb_placement.echo");
|
|
setEchoFileName(E_ECHO_PLACEMENT_SINK_DELAYS, "placement_sink_delays.echo");
|
|
setEchoFileName(E_ECHO_FINAL_PLACEMENT_TIMING_GRAPH, "final_placement_timing_graph.echo");
|
|
setEchoFileName(E_ECHO_FINAL_PLACEMENT_SLACK, "final_placement_slack.echo");
|
|
setEchoFileName(E_ECHO_FINAL_PLACEMENT_CRITICALITY, "final_placement_criticality.echo");
|
|
setEchoFileName(E_ECHO_PLACEMENT_CRIT_PATH, "placement_crit_path.echo");
|
|
setEchoFileName(E_ECHO_PB_GRAPH, "pb_graph.echo");
|
|
setEchoFileName(E_ECHO_ARCH, "arch.echo");
|
|
setEchoFileName(E_ECHO_PLACEMENT_CRITICAL_PATH, "placement_critical_path.echo");
|
|
setEchoFileName(E_ECHO_PLACEMENT_LOWER_BOUND_SINK_DELAYS, "placement_lower_bound_sink_delays.echo");
|
|
setEchoFileName(E_ECHO_PLACEMENT_LOGIC_SINK_DELAYS, "placement_logic_sink_delays.echo");
|
|
setEchoFileName(E_ECHO_ROUTING_SINK_DELAYS, "routing_sink_delays.echo");
|
|
setEchoFileName(E_ECHO_POST_FLOW_TIMING_GRAPH, "post_flow_timing_graph.blif");
|
|
setEchoFileName(E_ECHO_POST_PACK_NETLIST, "post_pack_netlist.blif");
|
|
setEchoFileName(E_ECHO_BLIF_INPUT, "blif_input.echo");
|
|
setEchoFileName(E_ECHO_NET_DELAY, "net_delay.echo");
|
|
setEchoFileName(E_ECHO_TIMING_GRAPH, "timing_graph.echo");
|
|
setEchoFileName(E_ECHO_LUT_REMAPPING, "lut_remapping.echo");
|
|
setEchoFileName(E_ECHO_PRE_PACKING_TIMING_GRAPH, "pre_packing_timing_graph.echo");
|
|
setEchoFileName(E_ECHO_PRE_PACKING_TIMING_GRAPH_AS_BLIF, "pre_packing_timing_graph_as_blif.blif");
|
|
setEchoFileName(E_ECHO_CLUSTERING_TIMING_INFO, "clustering_timing_info.echo");
|
|
setEchoFileName(E_ECHO_PRE_PACKING_SLACK, "pre_packing_slack.echo");
|
|
setEchoFileName(E_ECHO_PRE_PACKING_CRITICALITY, "pre_packing_criticality.echo");
|
|
setEchoFileName(E_ECHO_CLUSTERING_BLOCK_CRITICALITIES, "clustering_block_criticalities.echo");
|
|
setEchoFileName(E_ECHO_PRE_PACKING_MOLECULES_AND_PATTERNS, "pre_packing_molecules_and_patterns.echo");
|
|
setEchoFileName(E_ECHO_MEM, "mem.echo");
|
|
setEchoFileName(E_ECHO_RR_GRAPH, "rr_graph.echo");
|
|
setEchoFileName(E_ECHO_TIMING_CONSTRAINTS, "timing_constraints.echo");
|
|
setEchoFileName(E_ECHO_CRITICAL_PATH, "critical_path.echo");
|
|
setEchoFileName(E_ECHO_SLACK, "slack.echo");
|
|
setEchoFileName(E_ECHO_CRITICALITY, "criticality.echo");
|
|
setEchoFileName(E_ECHO_COMPLETE_NET_TRACE, "complete_net_trace.echo");
|
|
setEchoFileName(E_ECHO_SEG_DETAILS, "seg_details.txt");
|
|
}
|
|
|
|
void free_echo_file_info() {
|
|
int i;
|
|
if(echoFileEnabled != NULL) {
|
|
for(i = 0; i < (int) E_ECHO_END_TOKEN; i++) {
|
|
if(echoFileNames[i] != NULL) {
|
|
free(echoFileNames[i]);
|
|
}
|
|
}
|
|
free(echoFileNames);
|
|
free(echoFileEnabled);
|
|
echoFileNames = NULL;
|
|
echoFileEnabled = NULL;
|
|
}
|
|
}
|
|
|
|
void setOutputFileName(enum e_output_files ename, const char *name, const char *default_name) {
|
|
if(outputFileNames == NULL) {
|
|
alloc_and_load_output_file_names(default_name);
|
|
}
|
|
if(outputFileNames[(int)ename] != NULL) {
|
|
free(outputFileNames[(int)ename]);
|
|
}
|
|
outputFileNames[(int)ename] = my_strdup(name);
|
|
}
|
|
|
|
char *getOutputFileName(enum e_output_files ename) {
|
|
return outputFileNames[(int)ename];
|
|
}
|
|
|
|
void alloc_and_load_output_file_names(const char *default_name) {
|
|
char *name;
|
|
|
|
if(outputFileNames == NULL) {
|
|
|
|
outputFileNames = (char**)my_calloc((int)E_FILE_END_TOKEN, sizeof(char*));
|
|
|
|
name = (char*)my_malloc((strlen(default_name) + 40) * sizeof(char));
|
|
sprintf(name, "%s.critical_path.out", default_name);
|
|
setOutputFileName(E_CRIT_PATH_FILE, name, default_name);
|
|
|
|
sprintf(name, "%s.slack.out", default_name);
|
|
setOutputFileName(E_SLACK_FILE, name, default_name);
|
|
|
|
sprintf(name, "%s.criticality.out", default_name);
|
|
setOutputFileName(E_CRITICALITY_FILE, name, default_name);
|
|
|
|
free(name);
|
|
}
|
|
}
|
|
|
|
void free_output_file_names() {
|
|
int i;
|
|
if(outputFileNames != NULL) {
|
|
for(i = 0; i < (int)E_FILE_END_TOKEN; i++) {
|
|
if(outputFileNames[i] != NULL) {
|
|
free(outputFileNames[i]);
|
|
outputFileNames[i] = NULL;
|
|
}
|
|
}
|
|
free(outputFileNames);
|
|
outputFileNames = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******** Subroutine implementations ********/
|
|
|
|
void ReadOptions(INP int argc, INP char **argv, OUTP t_options * Options) {
|
|
char **Args, **head;
|
|
int offset;
|
|
|
|
/* 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 = ProcessOption(Args, Options);
|
|
} else if (strncmp("-", *Args, 1) == 0) {
|
|
*Args += 1; /* Skip the prefix */
|
|
Args = ProcessOption(Args, Options);
|
|
} else if (NULL == Options->ArchFile) {
|
|
Options->ArchFile = my_strdup(*Args);
|
|
vpr_printf(TIO_MESSAGE_INFO, "Architecture file: %s\n", Options->ArchFile);
|
|
++Args;
|
|
} else if (NULL == Options->CircuitName) {
|
|
Options->CircuitName = my_strdup(*Args);
|
|
/*if the user entered the circuit name with the .blif extension, remove it now*/
|
|
offset = strlen(Options->CircuitName) - 5;
|
|
if (offset > 0 && !strcmp(Options->CircuitName + offset, ".blif")) {
|
|
Options->CircuitName[offset] = '\0';
|
|
}
|
|
vpr_printf(TIO_MESSAGE_INFO, "Circuit name: %s.blif\n", Options->CircuitName);
|
|
vpr_printf(TIO_MESSAGE_INFO, "\n");
|
|
++Args;
|
|
} else {
|
|
/* Not an option and arch and net already specified so fail */
|
|
Error(*Args);
|
|
}
|
|
|
|
if (Options->Count[OT_SETTINGS_FILE] != Options->read_settings)
|
|
{
|
|
int tmp_argc = 0;
|
|
char **tmp_argv = NULL;
|
|
t_options SettingsFileOptions;
|
|
|
|
tmp_argc = read_settings_file(Options->SettingsFile, &tmp_argv);
|
|
|
|
ReadOptions(tmp_argc, tmp_argv, &SettingsFileOptions);
|
|
|
|
MergeOptions(Options, &SettingsFileOptions, Options->Count[OT_SETTINGS_FILE]);
|
|
|
|
Options->read_settings = Options->Count[OT_SETTINGS_FILE];
|
|
|
|
/* clean up local data structures */
|
|
free(tmp_argv);
|
|
}
|
|
}
|
|
free(head);
|
|
}
|
|
|
|
static char **
|
|
ProcessOption(INP char **Args, INOUTP t_options * Options) {
|
|
enum e_OptionBaseToken Token;
|
|
char **PrevArgs;
|
|
|
|
PrevArgs = Args;
|
|
Args = ReadBaseToken(Args, &Token);
|
|
|
|
if (Token < OT_BASE_UNKNOWN) {
|
|
/* If this was previously set by a lower priority source
|
|
* (ie. a settings file), reset the provenance and the
|
|
* count */
|
|
if (Options->Provenance[Token])
|
|
{
|
|
Options->Provenance[Token] = 0;
|
|
Options->Count[Token] = 1;
|
|
}
|
|
else
|
|
++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);
|
|
case OT_SDC_FILE:
|
|
return ReadString(Args, &Options->SDCFile);
|
|
case OT_SETTINGS_FILE:
|
|
return ReadString(Args, &Options->SettingsFile);
|
|
/* 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->out_file_prefix);
|
|
case OT_CREATE_ECHO_FILE:
|
|
return ReadOnOff(Args, &Options->CreateEchoFile);
|
|
case OT_GENERATE_POST_SYNTHESIS_NETLIST:
|
|
|
|
return ReadOnOff(Args, &Options->Generate_Post_Synthesis_Netlist);
|
|
/* 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);
|
|
|
|
/* 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_CHAN_WIDTH:
|
|
return ReadInt(Args, &Options->PlaceChanWidth);
|
|
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);
|
|
|
|
/* Power options */
|
|
case OT_POWER:
|
|
return Args;
|
|
case OT_ACTIVITY_FILE:
|
|
return ReadString(Args, &Options->ActFile);
|
|
case OT_POWER_OUT_FILE:
|
|
return ReadString(Args, &Options->PowerFile);
|
|
case OT_CMOS_TECH_BEHAVIOR_FILE:
|
|
return ReadString(Args, &Options->CmosTechFile);
|
|
|
|
/* Xifan Tang: FPGA X2P Options*/
|
|
case OT_FPGA_X2P_RENAME_ILLEGAL_PORT:
|
|
return Args;
|
|
case OT_FPGA_X2P_SIGNAL_DENSITY_WEIGHT:
|
|
return ReadFloat(Args, &Options->fpga_spice_signal_density_weight);
|
|
case OT_FPGA_X2P_SIM_WINDOW_SIZE:
|
|
return ReadFloat(Args, &Options->fpga_spice_sim_window_size);
|
|
case OT_FPGA_X2P_COMPACT_ROUTING_HIERARCHY:
|
|
/* use a compact routing hierarchy in SPICE/Verilog generation */
|
|
return Args;
|
|
case OT_FPGA_X2P_OUTPUT_SB_XML:
|
|
/* Read the file prefix to output SB XML files */
|
|
return ReadString(Args, &Options->sb_xml_dir);
|
|
/* Xifan TANG: FPGA SPICE Model Options*/
|
|
case OT_FPGA_SPICE:
|
|
return Args;
|
|
case OT_FPGA_SPICE_DIR:
|
|
return ReadString(Args, &Options->spice_dir);
|
|
case OT_FPGA_SPICE_PRINT_TOP_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_PB_MUX_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_CB_MUX_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_SB_MUX_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_CB_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_SB_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_GRID_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_LUT_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_HARDLOGIC_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PRINT_IO_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_SPICE_LEAKAGE_ONLY:
|
|
return Args;
|
|
case OT_FPGA_SPICE_PARASITIC_NET_ESTIMATION:
|
|
return ReadOnOff(Args, &Options->fpga_spice_parasitic_net_estimation);
|
|
case OT_FPGA_SPICE_TESTBENCH_LOAD_EXTRACTION:
|
|
return ReadOnOff(Args, &Options->fpga_spice_testbench_load_extraction);
|
|
case OT_FPGA_SPICE_SIM_MT_NUM:
|
|
return ReadInt(Args, &Options->fpga_spice_sim_mt_num);
|
|
case OT_FPGA_SPICE_SIMULATOR_PATH:
|
|
return ReadString(Args, &Options->fpga_spice_simulator_path);
|
|
/* Xifan TANG: Synthesizable Verilog */
|
|
case OT_FPGA_VERILOG_SYN:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_DIR:
|
|
return ReadString(Args, &Options->fpga_syn_verilog_dir);
|
|
case OT_FPGA_VERILOG_SYN_PRINT_TOP_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_PRINT_AUTOCHECK_TOP_TESTBENCH:
|
|
return ReadString(Args, &Options->fpga_verilog_reference_benchmark_file);
|
|
case OT_FPGA_VERILOG_SYN_PRINT_INPUT_BLIF_TESTBENCH:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_PRINT_FORMAL_VERIFICATION_TOP_NETLIST:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_INCLUDE_TIMING:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_INCLUDE_SIGNAL_INIT:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_INCLUDE_ICARUS_SIMULATOR:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_PRINT_MODELSIM_AUTODECK:
|
|
return ReadString(Args, &Options->fpga_verilog_modelsim_ini_path);
|
|
case OT_FPGA_VERILOG_SYN_PRINT_USER_DEFINED_TEMPLATE:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_PRINT_REPORT_TIMING_TCL:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_REPORT_TIMING_RPT_PATH:
|
|
return ReadString(Args, &Options->fpga_verilog_report_timing_path);
|
|
case OT_FPGA_VERILOG_SYN_PRINT_SDC_PNR:
|
|
return Args;
|
|
case OT_FPGA_VERILOG_SYN_PRINT_SDC_ANALYSIS:
|
|
return Args;
|
|
/* Xifan TANG: Bitstream generator */
|
|
case OT_FPGA_BITSTREAM_GENERATOR:
|
|
return Args;
|
|
case OT_FPGA_BITSTREAM_OUTPUT_FILE:
|
|
return ReadString(Args, &Options->fpga_bitstream_file);
|
|
/* mrFPGA: Xifan TANG */
|
|
case OT_SHOW_SRAM:
|
|
case OT_SHOW_PASS_TRANS:
|
|
return Args;
|
|
/* Xifan TANG: CLB_PIN_REMAP */
|
|
case OT_PACK_CLB_PIN_REMAP:
|
|
case OT_PLACE_CLB_PIN_REMAP:
|
|
return Args;
|
|
|
|
default:
|
|
vpr_printf(TIO_MESSAGE_ERROR, "Unexpected option '%s' on command line.\n", *PrevArgs);
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Map options set in the source t_options to a target t_options
|
|
* structure. Existing values in the destination have priority
|
|
* and will not be overwritten
|
|
*/
|
|
static void MergeOptions(INOUTP t_options * dest, INP t_options * src, int id)
|
|
{
|
|
int Token;
|
|
|
|
for (Token = 0; Token < OT_BASE_UNKNOWN; Token++)
|
|
{
|
|
/* Don't override values already set in the
|
|
* target destination. Also do not process
|
|
* Tokens that are not present in the source.
|
|
*/
|
|
if ((dest->Count[Token] || (!src->Count[Token])))
|
|
continue;
|
|
|
|
dest->Count[Token] = src->Count[Token];
|
|
dest->Provenance[Token] = id;
|
|
|
|
switch (Token) {
|
|
/* File naming options */
|
|
case OT_BLIF_FILE:
|
|
dest->BlifFile = src->BlifFile;
|
|
break;
|
|
case OT_NET_FILE:
|
|
dest->NetFile = src->NetFile;
|
|
break;
|
|
case OT_PLACE_FILE:
|
|
dest->PlaceFile = src->PlaceFile;
|
|
break;
|
|
case OT_ROUTE_FILE:
|
|
dest->RouteFile = src->RouteFile;
|
|
break;
|
|
case OT_SETTINGS_FILE:
|
|
dest->SettingsFile = src->SettingsFile;
|
|
break;
|
|
case OT_SDC_FILE:
|
|
dest->SDCFile = src->SDCFile;
|
|
break;
|
|
/* General Options */
|
|
case OT_NODISP:
|
|
break;
|
|
case OT_AUTO:
|
|
dest->GraphPause = src->GraphPause;
|
|
break;
|
|
case OT_PACK:
|
|
case OT_ROUTE:
|
|
case OT_PLACE:
|
|
break;
|
|
case OT_TIMING_ANALYZE_ONLY_WITH_NET_DELAY:
|
|
dest->constant_net_delay = src->constant_net_delay;
|
|
break;
|
|
case OT_FAST:
|
|
case OT_FULL_STATS:
|
|
break;
|
|
case OT_TIMING_ANALYSIS:
|
|
dest->TimingAnalysis = src->TimingAnalysis;
|
|
break;
|
|
case OT_OUTFILE_PREFIX:
|
|
dest->out_file_prefix = src->out_file_prefix;
|
|
break;
|
|
case OT_CREATE_ECHO_FILE:
|
|
dest->CreateEchoFile = src->CreateEchoFile;
|
|
break;
|
|
|
|
/* Clustering Options */
|
|
case OT_GLOBAL_CLOCKS:
|
|
dest->global_clocks = src->global_clocks;
|
|
break;
|
|
case OT_HILL_CLIMBING_FLAG:
|
|
dest->hill_climbing_flag = src->hill_climbing_flag;
|
|
break;
|
|
case OT_SWEEP_HANGING_NETS_AND_INPUTS:
|
|
dest->sweep_hanging_nets_and_inputs = src->sweep_hanging_nets_and_inputs;
|
|
break;
|
|
case OT_TIMING_DRIVEN_CLUSTERING:
|
|
dest->timing_driven = src->timing_driven;
|
|
break;
|
|
case OT_CLUSTER_SEED:
|
|
dest->cluster_seed_type = src->cluster_seed_type;
|
|
break;
|
|
case OT_ALPHA_CLUSTERING:
|
|
dest->alpha = src->alpha;
|
|
break;
|
|
case OT_BETA_CLUSTERING:
|
|
dest->beta = src->beta;
|
|
break;
|
|
case OT_RECOMPUTE_TIMING_AFTER:
|
|
dest->recompute_timing_after = src->recompute_timing_after;
|
|
break;
|
|
case OT_CLUSTER_BLOCK_DELAY:
|
|
dest->block_delay = src->block_delay;
|
|
break;
|
|
case OT_ALLOW_UNRELATED_CLUSTERING:
|
|
dest->allow_unrelated_clustering = src->allow_unrelated_clustering;
|
|
break;
|
|
case OT_ALLOW_EARLY_EXIT:
|
|
dest->allow_early_exit = src->allow_early_exit;
|
|
break;
|
|
case OT_INTRA_CLUSTER_NET_DELAY:
|
|
dest->intra_cluster_net_delay = src->intra_cluster_net_delay;
|
|
break;
|
|
case OT_INTER_CLUSTER_NET_DELAY:
|
|
dest->inter_cluster_net_delay = src->inter_cluster_net_delay;
|
|
break;
|
|
case OT_CONNECTION_DRIVEN_CLUSTERING:
|
|
dest->connection_driven = src->connection_driven;
|
|
break;
|
|
case OT_SKIP_CLUSTERING:
|
|
break;
|
|
case OT_PACKER_ALGORITHM:
|
|
dest->packer_algorithm = src->packer_algorithm;
|
|
break;
|
|
|
|
/* Placer Options */
|
|
case OT_PLACE_ALGORITHM:
|
|
dest->PlaceAlgorithm = src->PlaceAlgorithm;
|
|
break;
|
|
case OT_INIT_T:
|
|
dest->PlaceInitT = src->PlaceInitT;
|
|
break;
|
|
case OT_EXIT_T:
|
|
dest->PlaceExitT = src->PlaceExitT;
|
|
break;
|
|
case OT_ALPHA_T:
|
|
dest->PlaceAlphaT = src->PlaceAlphaT;
|
|
break;
|
|
case OT_INNER_NUM:
|
|
dest->PlaceInnerNum = src->PlaceInnerNum;
|
|
break;
|
|
case OT_SEED:
|
|
dest->Seed = src->Seed;
|
|
break;
|
|
case OT_PLACE_COST_EXP:
|
|
dest->place_cost_exp = src->place_cost_exp;
|
|
break;
|
|
case OT_PLACE_CHAN_WIDTH:
|
|
dest->PlaceChanWidth = src->PlaceChanWidth;
|
|
break;
|
|
case OT_FIX_PINS:
|
|
dest->PinFile = src->PinFile;
|
|
break;
|
|
case OT_ENABLE_TIMING_COMPUTATIONS:
|
|
dest->ShowPlaceTiming = src->ShowPlaceTiming;
|
|
break;
|
|
case OT_BLOCK_DIST:
|
|
dest->block_dist = src->block_dist;
|
|
break;
|
|
|
|
/* Placement Options Valid Only for Timing-Driven Placement */
|
|
case OT_TIMING_TRADEOFF:
|
|
dest->PlaceTimingTradeoff = src->PlaceTimingTradeoff;
|
|
break;
|
|
case OT_RECOMPUTE_CRIT_ITER:
|
|
dest->RecomputeCritIter = src->RecomputeCritIter;
|
|
break;
|
|
case OT_INNER_LOOP_RECOMPUTE_DIVIDER:
|
|
dest->inner_loop_recompute_divider = src->inner_loop_recompute_divider;
|
|
break;
|
|
case OT_TD_PLACE_EXP_FIRST:
|
|
dest->place_exp_first = src->place_exp_first;
|
|
break;
|
|
case OT_TD_PLACE_EXP_LAST:
|
|
dest->place_exp_last = src->place_exp_last;
|
|
break;
|
|
|
|
/* Router Options */
|
|
case OT_MAX_ROUTER_ITERATIONS:
|
|
dest->max_router_iterations = src->max_router_iterations;
|
|
break;
|
|
case OT_BB_FACTOR:
|
|
dest->bb_factor = src->bb_factor;
|
|
break;
|
|
case OT_INITIAL_PRES_FAC:
|
|
dest->initial_pres_fac = src->initial_pres_fac;
|
|
break;
|
|
case OT_PRES_FAC_MULT:
|
|
dest->pres_fac_mult = src->pres_fac_mult;
|
|
break;
|
|
case OT_ACC_FAC:
|
|
dest->acc_fac = src->acc_fac;
|
|
break;
|
|
case OT_FIRST_ITER_PRES_FAC:
|
|
dest->first_iter_pres_fac = src->first_iter_pres_fac;
|
|
break;
|
|
case OT_BEND_COST:
|
|
dest->bend_cost = src->bend_cost;
|
|
break;
|
|
case OT_ROUTE_TYPE:
|
|
dest->RouteType = src->RouteType;
|
|
break;
|
|
case OT_VERIFY_BINARY_SEARCH:
|
|
break;
|
|
case OT_ROUTE_CHAN_WIDTH:
|
|
dest->RouteChanWidth = src->RouteChanWidth;
|
|
break;
|
|
case OT_ROUTER_ALGORITHM:
|
|
dest->RouterAlgorithm = src->RouterAlgorithm;
|
|
break;
|
|
case OT_BASE_COST_TYPE:
|
|
dest->base_cost_type = src->base_cost_type;
|
|
break;
|
|
|
|
/* Routing options valid only for timing-driven routing */
|
|
case OT_ASTAR_FAC:
|
|
dest->astar_fac = src->astar_fac;
|
|
break;
|
|
case OT_MAX_CRITICALITY:
|
|
dest->max_criticality = src->max_criticality;
|
|
break;
|
|
case OT_CRITICALITY_EXP:
|
|
dest->criticality_exp = src->criticality_exp;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
static char **
|
|
ReadBaseToken(INP char **Args, OUTP enum e_OptionBaseToken *Token) {
|
|
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 = (enum e_OptionBaseToken) Cur->Enum;
|
|
return ++Args;
|
|
}
|
|
++Cur;
|
|
}
|
|
|
|
*Token = OT_BASE_UNKNOWN;
|
|
return ++Args;
|
|
}
|
|
|
|
static char **
|
|
ReadToken(INP char **Args, OUTP enum e_OptionArgToken *Token) {
|
|
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 = (enum e_OptionArgToken)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) {
|
|
vpr_printf(TIO_MESSAGE_ERROR, "Unexpected token '%s' on command line.\n", Token);
|
|
} else {
|
|
vpr_printf(TIO_MESSAGE_ERROR, "Missing token at end of command line.\n");
|
|
}
|
|
exit(1);
|
|
}
|
|
|
|
static char **
|
|
ReadClusterSeed(INP char **Args, OUTP enum e_cluster_seed *Type) {
|
|
enum e_OptionArgToken Token;
|
|
char **PrevArgs;
|
|
|
|
PrevArgs = Args;
|
|
Args = ReadToken(Args, &Token);
|
|
switch (Token) {
|
|
case OT_TIMING:
|
|
*Type = VPACK_TIMING;
|
|
break;
|
|
case OT_MAX_INPUTS:
|
|
*Type = VPACK_MAX_INPUTS;
|
|
break;
|
|
default:
|
|
Error(*PrevArgs);
|
|
}
|
|
|
|
return Args;
|
|
}
|
|
|
|
static char **
|
|
ReadPackerAlgorithm(INP char **Args, OUTP enum e_packer_algorithm *Algo) {
|
|
enum e_OptionArgToken Token;
|
|
char **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 char **
|
|
ReadRouterAlgorithm(INP char **Args, OUTP enum e_router_algorithm *Algo) {
|
|
enum e_OptionArgToken Token;
|
|
char **PrevArgs;
|
|
|
|
PrevArgs = Args;
|
|
Args = ReadToken(Args, &Token);
|
|
switch (Token) {
|
|
case OT_BREADTH_FIRST:
|
|
*Algo = BREADTH_FIRST;
|
|
break;
|
|
case OT_NO_TIMING:
|
|
*Algo = NO_TIMING;
|
|
break;
|
|
case OT_TIMING_DRIVEN:
|
|
*Algo = TIMING_DRIVEN;
|
|
break;
|
|
default:
|
|
Error(*PrevArgs);
|
|
}
|
|
|
|
return Args;
|
|
}
|
|
|
|
static char **
|
|
ReadBaseCostType(INP char **Args, OUTP enum e_base_cost_type *BaseCostType) {
|
|
enum e_OptionArgToken Token;
|
|
char **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 char **
|
|
ReadRouteType(INP char **Args, OUTP enum e_route_type *Type) {
|
|
enum e_OptionArgToken Token;
|
|
char **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 char **
|
|
ReadPlaceAlgorithm(INP char **Args, OUTP enum e_place_algorithm *Algo) {
|
|
enum e_OptionArgToken Token;
|
|
char **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 char **
|
|
ReadFixPins(INP char **Args, OUTP char **PinFile) {
|
|
enum e_OptionArgToken Token;
|
|
int Len;
|
|
char **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 char **
|
|
ReadOnOff(INP char **Args, OUTP boolean * Val) {
|
|
enum e_OptionArgToken Token;
|
|
char **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 char **
|
|
ReadInt(INP char **Args, OUTP int *Val) {
|
|
if (NULL == *Args)
|
|
Error(*Args);
|
|
if ((**Args > '9') || (**Args < '0'))
|
|
Error(*Args);
|
|
|
|
*Val = atoi(*Args);
|
|
|
|
return ++Args;
|
|
}
|
|
|
|
static char **
|
|
ReadFloat(INP char ** Args, OUTP float *Val) {
|
|
if (NULL == *Args) {
|
|
Error(*Args);
|
|
}
|
|
|
|
if ((**Args != '-') && (**Args != '.')
|
|
&& ((**Args > '9') || (**Args < '0'))) {
|
|
Error(*Args);
|
|
}
|
|
|
|
*Val = atof(*Args);
|
|
|
|
return ++Args;
|
|
}
|
|
|
|
static char **
|
|
ReadString(INP char **Args, OUTP char **Val) {
|
|
if (NULL == *Args) {
|
|
Error(*Args);
|
|
}
|
|
|
|
*Val = my_strdup(*Args);
|
|
|
|
return ++Args;
|
|
}
|
|
|
|
|