From 7e794212d9f696de618d25dc38f3f585a48813ab Mon Sep 17 00:00:00 2001 From: Schuyler Eldridge Date: Tue, 13 Dec 2016 17:29:57 -0500 Subject: [PATCH] Cleanup emulator.cc, use getopt, add help text (#487) This changes the emulator to conform to POSIX-style options (e.g., short/'-' and long/'--') while preserving legacy option parsing (i.e., '+'). Options are read from the user until the first non-option (either POSIX or legacy) is encountered. This and everything following is assumed to be the binary and any arguments the user wants to run on the emulator. All non-options are passed directly to the DTM. This allows for the same option to be passed, safely, to both the emulator and the binary, e.g., "+verbose". This introduces a dependency on . Closes #484. --- csrc/emulator.cc | 141 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 115 insertions(+), 26 deletions(-) diff --git a/csrc/emulator.cc b/csrc/emulator.cc index c1837188..bc586f48 100644 --- a/csrc/emulator.cc +++ b/csrc/emulator.cc @@ -12,6 +12,7 @@ #include #include #include +#include extern dtm_t* dtm; static uint64_t trace_count = 0; @@ -33,33 +34,123 @@ extern "C" int vpi_get_vlog_info(void* arg) return 0; } +static void usage(const char * program_name) { + printf("Usage: %s [OPTION]... BINARY [BINARY ARGS]\n", program_name); + fputs("\ +Run a BINARY on the Rocket Chip emulator.\n\ +\n\ +Mandatory arguments to long options are mandatory for short options too.\n\ + -c, --cycle-count print the cycle count before exiting\n\ + +cycle-count\n\ + -h, --help display this help and exit\n\ + -m, --max-cycles=CYCLES kill the emulation after CYCLES\n\ + +max-cycles=CYCLES\n\ + -s, --seed=SEED use random number seed SEED\n\ + -V, --verbose enable all Chisel printfs\n\ + +verbose\n\ +", stdout); +#if VM_TRACE + fputs("\ + -v, --vcd=FILE, write vcd trace to FILE (or '-' for stdout)\n\ + -x, --start=CYCLE start VCD tracing at CYCLE\n\ + +start\n\ +", stdout); +#else + fputs("\ +VCD options (e.g., -v, +start) require a debug-enabled emulator.\n\ +Try `make debug`.\n\ +", stdout); +#endif +} + int main(int argc, char** argv) { unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); uint64_t max_cycles = -1; - uint64_t start = 0; int ret = 0; - FILE *vcdfile = NULL; bool print_cycles = false; +#if VM_TRACE + FILE * vcdfile = NULL; + uint64_t start = 0; +#endif - for (int i = 1; i < argc; i++) - { - std::string arg = argv[i]; - if (arg.substr(0, 2) == "-v") { - const char* filename = argv[i]+2; - vcdfile = strcmp(filename, "-") == 0 ? stdout : fopen(filename, "w"); - if (!vcdfile) - abort(); - } else if (arg.substr(0, 2) == "-s") - random_seed = atoi(argv[i]+2); - else if (arg == "+verbose") - verbose = true; - else if (arg.substr(0, 12) == "+max-cycles=") - max_cycles = atoll(argv[i]+12); - else if (arg.substr(0, 7) == "+start=") - start = atoll(argv[i]+7); - else if (arg.substr(0, 12) == "+cycle-count") - print_cycles = true; + std::vector to_dtm; + while (1) { + static struct option long_options[] = { + {"cycle-count", no_argument, 0, 'c' }, + {"help", no_argument, 0, 'h' }, + {"max-cycles", required_argument, 0, 'm' }, + {"seed", required_argument, 0, 's' }, + {"verbose", no_argument, 0, 'V' }, +#if VM_TRACE + {"vcd", required_argument, 0, 'v' }, + {"start", required_argument, 0, 'x' }, +#endif + {0, 0, 0, 0} + }; + int option_index = 0; +#if VM_TRACE + int c = getopt_long(argc, argv, "-chm:s:v:Vx:", long_options, &option_index); +#else + int c = getopt_long(argc, argv, "-chm:s:V", long_options, &option_index); +#endif + if (c == -1) break; + switch (c) { + // Process "normal" options with '--' long options or '-' short options + case '?': usage(argv[0]); return 1; + case 'c': print_cycles = true; break; + case 'h': usage(argv[0]); return 0; + case 'm': max_cycles = atoll(optarg); break; + case 's': random_seed = atoi(optarg); break; + case 'V': verbose = true; break; +#if VM_TRACE + case 'v': { + vcdfile = strcmp(optarg, "-") == 0 ? stdout : fopen(optarg, "w"); + if (!vcdfile) { + std::cerr << "Unable to open " << optarg << " for VCD write\n"; + return 1; + } + break; + } + case 'x': start = atoll(optarg); break; +#endif + // Processing of legacy '+' options and recognition of when + // we've hit the binary. The binary is expected to be a + // non-option and not start with '-' or '+'. + case 1: { + if (optarg[0] != '+') { + to_dtm.push_back(optarg); + goto done_processing; + } + std::string arg = optarg; + if (arg == "+verbose") + verbose = true; + else if (arg.substr(0, 12) == "+max-cycles=") + max_cycles = atoll(optarg+12); +#if VM_TRACE + else if (arg.substr(0, 7) == "+start=") + start = atoll(optarg+7); +#endif + else if (arg.substr(0, 12) == "+cycle-count") + print_cycles = true; + else { + fprintf(stderr, "%s: unrecognized option '%s'\n", argv[0], optarg); + usage(argv[0]); + return 1; + } + break; + } + } + } + +done_processing: + if (optind < argc) + while (optind < argc) + to_dtm.push_back(argv[optind++]); + if (!to_dtm.size()) { + std::cerr << "No binary specified for emulator\n"; + usage(argv[0]); + return 1; } if (verbose) @@ -81,7 +172,7 @@ int main(int argc, char** argv) } #endif - dtm = new dtm_t(std::vector(argv + 1, argv + argc)); + dtm = new dtm_t(to_dtm); signal(SIGTERM, handle_sigterm); @@ -117,10 +208,9 @@ int main(int argc, char** argv) #if VM_TRACE if (tfp) tfp->close(); -#endif - if (vcdfile) fclose(vcdfile); +#endif if (dtm->exit_code()) { @@ -137,8 +227,7 @@ int main(int argc, char** argv) fprintf(stderr, "Completed after %ld cycles\n", trace_count); } - delete dtm; - delete tile; - + if (dtm) delete dtm; + if (tile) delete tile; return ret; }