summaryrefslogtreecommitdiff
path: root/isa/isa.c
diff options
context:
space:
mode:
Diffstat (limited to 'isa/isa.c')
-rw-r--r--isa/isa.c286
1 files changed, 286 insertions, 0 deletions
diff --git a/isa/isa.c b/isa/isa.c
new file mode 100644
index 000000000000..ada1ad05949c
--- /dev/null
+++ b/isa/isa.c
@@ -0,0 +1,286 @@
+/*-
+ * 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 <sys/queue.h>
+
+#include <err.h>
+#include <getopt.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libelftc.h>
+
+#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");
+}
+