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:
parent
540502f96d
commit
7e794212d9
131
csrc/emulator.cc
131
csrc/emulator.cc
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user