/*- * Copyright (c) 2012,2013 Joseph Koshy * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include #include #include #include #include #include #include #include #include #include "_elftc.h" ELFTC_VCSID("$Id: isa.c 2934 2013-03-30 01:40:49Z jkoshy $"); /* * Option handling. */ enum isa_mode { ISA_MODE_DECODE, ISA_MODE_ENCODE, ISA_MODE_QUERY }; enum isa_submode { ISA_SUBMODE_GENERATE_TESTS, ISA_SUBMODE_LIST_INSTRUCTIONS }; #define ISA_OPT_DRY_RUN 0x0001 #define ISA_OPT_NO_WARNINGS 0x0002 #define ISA_OPT_VERBOSE 0x0004 /* Record a option. */ struct isa_option { const char *isa_option; SLIST_ENTRY(isa_option) isa_next; }; struct isa_config { unsigned int isa_flags; enum isa_mode isa_mode; enum isa_submode isa_submode; int isa_ntests; int isa_seed; const char *isa_arch; const char *isa_input; const char *isa_output; const char *isa_prefix; SLIST_HEAD(,isa_option) isa_cpus; SLIST_HEAD(,isa_option) isa_specs; }; #define ISA_MAX_LONG_OPTION_LENGTH 64 static struct option isa_long_options[] = { { "arch", required_argument, NULL, 'a' }, { "cpu", required_argument, NULL, 'c' }, { "decode", no_argument, NULL, 'D' }, { "dry-run", no_argument, NULL, 'n' }, { "encode", no_argument, NULL, 'E' }, { "help", no_argument, NULL, 'h' }, { "input", required_argument, NULL, 'i' }, { "list-instructions", no_argument, NULL, 'L' }, { "ntests", required_argument, NULL, 'N' }, { "output", required_argument, NULL, 'o' }, { "prefix", required_argument, NULL, 'p' }, { "query", no_argument, NULL, 'Q' }, { "quiet", no_argument, NULL, 'q' }, { "random-seed", required_argument, NULL, 'R' }, { "spec", required_argument, NULL, 's' }, { "test", no_argument, NULL, 'T' }, { "verbose", no_argument, NULL, 'v' }, { "version", no_argument, NULL, 'V' }, { NULL, 0, NULL, 0 } }; static const char *isa_usage_message = "\ usage: %s [options] [command] [specfiles]...\n\ Process an instruction set specification.\n\ \n\ Supported values for 'command' are:\n\ decode Build an instruction stream decoder.\n\ encode Build an instruction stream encoder.\n\ query (default) Retrieve information about an instruction set.\n\ \n\ Supported global options are:\n\ -a ARCH | --arch ARCH Process instruction specifications for ARCH.\n\ -c CPU | --cpu CPU Process instruction specifications for CPU.\n\ -n | --dry-run Exit after checking inputs for errors.\n\ -s FILE | --spec FILE Read instruction specifications from FILE.\n\ -q | --quiet Suppress warning messages.\n\ -v | --verbose Be verbose.\n\ -V | --version Display a version identifier and exit.\n\ \n\ Supported options for command 'decode' are:\n\ -i FILE | --input FILE Read source to be expanded from FILE.\n\ -o FILE | --output FILE Write generated output to FILE.\n\ \n\ Supported options for command 'encode' are:\n\ -o FILE | --output FILE Write generated output to FILE.\n\ -p STR | --prefix STR Use STR as a prefix for generated symbols.\n\ \n\ Supported options for command 'query' are:\n\ -L | --list-instructions Generate a list of all known instructions.\n\ -N NUM | --ntests NUM Specify the number of test sequences generated.\n\ -R N | --random-seed N Use N as the random number generator seed.\n\ -T | --test Generate test sequences.\n\ "; void isa_usage(int iserror, const char *message, ...) { FILE *channel; va_list ap; channel = iserror ? stderr : stdout; if (message) { va_start(ap, message); (void) vfprintf(channel, message, ap); va_end(ap); } (void) fprintf(channel, isa_usage_message, ELFTC_GETPROGNAME()); exit(iserror != 0); } void isa_unimplemented(int option, int option_index, struct option *options_table) { char msgbuf[ISA_MAX_LONG_OPTION_LENGTH]; if (option_index >= 0) (void) snprintf(msgbuf, sizeof(msgbuf), "\"--%s\"", options_table[option_index].name); else (void) snprintf(msgbuf, sizeof(msgbuf), "'-%c'", option); errx(1, "ERROR: option %s is unimplemented.", msgbuf); } struct isa_option * isa_make_option(const char *arg) { struct isa_option *isa_opt; if ((isa_opt = malloc(sizeof(*isa_opt))) == NULL) return (NULL); isa_opt->isa_option = optarg; return (isa_opt); } int main(int argc, char **argv) { int option, option_index; struct isa_option *isa_opt; struct isa_config config; (void) memset(&config, 0, sizeof(config)); config.isa_mode = ISA_MODE_QUERY; config.isa_arch = config.isa_input = config.isa_output = config.isa_prefix = NULL; SLIST_INIT(&config.isa_cpus); SLIST_INIT(&config.isa_specs); for (option_index = -1; (option = getopt_long(argc, argv, "a:c:hi:no:p:qs:vDELN:QR:TV", isa_long_options, &option_index)) != -1; option_index = -1) { switch (option) { case 'h': isa_usage(0, NULL); break; case 'V': (void) printf("%s (%s)\n", ELFTC_GETPROGNAME(), elftc_version()); exit(0); break; case 'a': config.isa_arch = optarg; break; case 'c': if ((isa_opt = isa_make_option(optarg)) == NULL) goto error; SLIST_INSERT_HEAD(&config.isa_cpus, isa_opt, isa_next); break; case 'i': config.isa_input = optarg; break; case 'n': config.isa_flags |= ISA_OPT_DRY_RUN; break; case 'o': config.isa_output = optarg; break; case 'p': config.isa_prefix = optarg; break; case 'q': config.isa_flags |= ISA_OPT_NO_WARNINGS; break; case 's': if ((isa_opt = isa_make_option(optarg)) == NULL) goto error; SLIST_INSERT_HEAD(&config.isa_specs, isa_opt, isa_next); break; case 'v': config.isa_flags |= ISA_OPT_VERBOSE; break; case 'D': config.isa_mode = ISA_MODE_DECODE; break; case 'E': config.isa_mode = ISA_MODE_ENCODE; break; case 'L': config.isa_submode = ISA_SUBMODE_LIST_INSTRUCTIONS; break; case 'N': config.isa_ntests = atoi(optarg); break; case 'Q': config.isa_mode = ISA_MODE_QUERY; break; case 'R': config.isa_seed = atoi(optarg); break; case 'T': config.isa_submode = ISA_SUBMODE_GENERATE_TESTS; break; default: isa_usage(1, "\n"); break; } } /* * Create the canonical list of specification files to * be processed. */ for (;optind < argc; optind++) { if ((isa_opt = isa_make_option(argv[optind])) == NULL) goto error; SLIST_INSERT_HEAD(&config.isa_specs, isa_opt, isa_next); } exit(0); error: err(1, "ERROR: Invocation failed"); }