1
0

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 <getopt.h>.

Closes #484.
This commit is contained in:
Schuyler Eldridge 2016-12-13 17:29:57 -05:00 committed by Henry Cook
parent 540502f96d
commit 7e794212d9

View File

@ -12,6 +12,7 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h>
extern dtm_t* dtm; extern dtm_t* dtm;
static uint64_t trace_count = 0; static uint64_t trace_count = 0;
@ -33,33 +34,123 @@ extern "C" int vpi_get_vlog_info(void* arg)
return 0; 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) int main(int argc, char** argv)
{ {
unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid(); unsigned random_seed = (unsigned)time(NULL) ^ (unsigned)getpid();
uint64_t max_cycles = -1; uint64_t max_cycles = -1;
uint64_t start = 0;
int ret = 0; int ret = 0;
FILE *vcdfile = NULL;
bool print_cycles = false; bool print_cycles = false;
#if VM_TRACE
FILE * vcdfile = NULL;
uint64_t start = 0;
#endif
for (int i = 1; i < argc; i++) std::vector<std::string> to_dtm;
{ while (1) {
std::string arg = argv[i]; static struct option long_options[] = {
if (arg.substr(0, 2) == "-v") { {"cycle-count", no_argument, 0, 'c' },
const char* filename = argv[i]+2; {"help", no_argument, 0, 'h' },
vcdfile = strcmp(filename, "-") == 0 ? stdout : fopen(filename, "w"); {"max-cycles", required_argument, 0, 'm' },
if (!vcdfile) {"seed", required_argument, 0, 's' },
abort(); {"verbose", no_argument, 0, 'V' },
} else if (arg.substr(0, 2) == "-s") #if VM_TRACE
random_seed = atoi(argv[i]+2); {"vcd", required_argument, 0, 'v' },
else if (arg == "+verbose") {"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; verbose = true;
else if (arg.substr(0, 12) == "+max-cycles=") else if (arg.substr(0, 12) == "+max-cycles=")
max_cycles = atoll(argv[i]+12); max_cycles = atoll(optarg+12);
#if VM_TRACE
else if (arg.substr(0, 7) == "+start=") else if (arg.substr(0, 7) == "+start=")
start = atoll(argv[i]+7); start = atoll(optarg+7);
#endif
else if (arg.substr(0, 12) == "+cycle-count") else if (arg.substr(0, 12) == "+cycle-count")
print_cycles = true; 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) if (verbose)
@ -81,7 +172,7 @@ int main(int argc, char** argv)
} }
#endif #endif
dtm = new dtm_t(std::vector<std::string>(argv + 1, argv + argc)); dtm = new dtm_t(to_dtm);
signal(SIGTERM, handle_sigterm); signal(SIGTERM, handle_sigterm);
@ -117,10 +208,9 @@ int main(int argc, char** argv)
#if VM_TRACE #if VM_TRACE
if (tfp) if (tfp)
tfp->close(); tfp->close();
#endif
if (vcdfile) if (vcdfile)
fclose(vcdfile); fclose(vcdfile);
#endif
if (dtm->exit_code()) if (dtm->exit_code())
{ {
@ -137,8 +227,7 @@ int main(int argc, char** argv)
fprintf(stderr, "Completed after %ld cycles\n", trace_count); fprintf(stderr, "Completed after %ld cycles\n", trace_count);
} }
delete dtm; if (dtm) delete dtm;
delete tile; if (tile) delete tile;
return ret; return ret;
} }