/* * Command-line option parsing */ #include "vriscv.h" #define OPTION_SEPARATOR "-" uint64_t memory_size = 512 * 1024 * 1024; char* file_path; bool gdbstub = false; bool trace = false; static void print_usage(); static void print_help(); static void print_version(); static int parse_long_option(char* str, char* argq); void parse_options(int argc, char** argv) { for(int i = 1; i < argc; i++) { // Start option parsing for argument 'i' if(argv[i][0] != *OPTION_SEPARATOR) continue; // Check for long options if(argv[i][1] == *OPTION_SEPARATOR) { i += parse_long_option(argv[i] + 2, argv[i + 1]); continue; } // Parse short options int k = 1; while(argv[i][k]) { switch(argv[i][k]) { case 'h': case '?': { print_help(); exit(0); } case 'v': { print_version(); exit(0); } case 'm': { // First try to convert next chars into int (ex. -m512) char* end; memory_size = strtol(&argv[i][k + 1], &end, 10); if(*end != '\0' || end == &argv[i][k + 1]) { if(argv[i][k + 1]) { fprintf(stderr, "Error: Option -m needs an argument, but you used -m in a group of options without an integer next to it\n"); exit(EXIT_FAILURE); } // Try to parse next arg as integer if(argc <= i + 1) { fprintf(stderr, "Error: Option " OPTION_SEPARATOR "m needs an argument\n"); exit(EXIT_FAILURE); } memory_size = strtol(argv[i + 1], &end, 10); if(*end != '\0') { fprintf(stderr, "Error: Invalid argument '%s' for option " OPTION_SEPARATOR "m\n", argv[i + 1]); exit(EXIT_FAILURE); } else { i++; k = strlen(argv[i]) - 1; } } else k += (end - &argv[i][k + 1]); if(memory_size <= 0) { fprintf(stderr, "Error: Memory size needs to be > 0\n"); exit(EXIT_FAILURE); } if(memory_size > 4096) { fprintf(stderr, "Error: Cannot address more than 4 GiB of memory on 32-bits !\n"); exit(EXIT_FAILURE); } memory_size *= 1024 * 1024; break; } case 's': { gdbstub = true; break; } case 't': { trace = true; break; } default: { fprintf(stderr, "Error: Unknown short option -%c\n", argv[i][k]); exit(EXIT_FAILURE); } } k++; } } if(argc <= 1) { print_usage(); exit(EXIT_FAILURE); } else file_path = argv[argc - 1]; } static int parse_long_option(char* str, char* argq) { if(strcmp(str, "help") == 0) { print_help(); exit(0); } else if(strcmp(str, "version") == 0) { print_version(); exit(0); } else if(strcmp(str, "memory") == 0) { if(argq == NULL) { fprintf(stderr, "Error: No argument given for option " OPTION_SEPARATOR "-memory\n"); exit(EXIT_FAILURE); } // Convert argument to integer char* end; memory_size = strtol(argq, &end, 10); if(*end != '\0') { fprintf(stderr, "Error: Invalid argument '%s' for option " OPTION_SEPARATOR "-memory\n", argq); exit(EXIT_FAILURE); } if(memory_size > 4096) { fprintf(stderr, "Error: Cannot address more than 4 GiB of memory on 32-bits !\n"); exit(EXIT_FAILURE); } memory_size *= 1024 * 1024; return 1; } else if(strcmp(str, "gdb-stub") == 0) { gdbstub = true; return 0; } else if(strcmp(str, "trace") == 0) { trace = true; return 0; } else { fprintf(stderr, "Error: Unknown long option " OPTION_SEPARATOR OPTION_SEPARATOR "%s\n", str); exit(EXIT_FAILURE); } } static void print_usage() { printf("Usage: %s [options] \n", CURRENT_NAME); } static void print_help() { print_usage(); printf("Options:\n"); printf(" " OPTION_SEPARATOR "h, " OPTION_SEPARATOR "?, --help\t\tPrint this help message\n"); printf(" " OPTION_SEPARATOR "v, --version\t\t\tPrint version information\n"); printf(" " OPTION_SEPARATOR "m, --memory\t\t\tSet the simulated memory size, in MiB (max 4096)\n"); printf(" " OPTION_SEPARATOR "t, --trace\t\t\tTrace executed instructions in stdout\n"); printf(" " OPTION_SEPARATOR "s, --gdb-stub\t\tLaunch a gdb stub server (remote gdb debugging)\n"); } static void print_version() { printf("%s (%s) version %s\n", CURRENT_NAME, NAME, VERSION); }