]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/common/sim-options.c
Update years in copyright notice for the GDB files.
[thirdparty/binutils-gdb.git] / sim / common / sim-options.c
index 94342e4a66b44c0b6e3cf446ae59ca1482b9e38a..73f84fb3dec02fdfd4d3927afa24282a47609751 100644 (file)
@@ -1,22 +1,21 @@
 /* Simulator option handling.
-   Copyright (C) 1996, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1996-2013 Free Software Foundation, Inc.
    Contributed by Cygnus Support.
 
 This file is part of GDB, the GNU debugger.
 
 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
+the Free Software Foundation; either version 3 of the License, or
+(at your option) any later version.
 
 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
-You should have received a copy of the GNU General Public License along
-with this program; if not, write to the Free Software Foundation, Inc.,
-59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "sim-main.h"
 #ifdef HAVE_STRING_H
@@ -31,7 +30,6 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #endif
 #include <ctype.h>
 #include "libiberty.h"
-#include "../libiberty/alloca-conf.h"
 #include "sim-options.h"
 #include "sim-io.h"
 #include "sim-assert.h"
@@ -43,9 +41,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
    This is intended to be called by modules in their `install' handler.  */
 
 SIM_RC
-sim_add_option_table (sd, table)
-     SIM_DESC sd;
-     const OPTION *table;
+sim_add_option_table (SIM_DESC sd, sim_cpu *cpu, const OPTION *table)
 {
   struct option_list *ol = ((struct option_list *)
                            xmalloc (sizeof (struct option_list)));
@@ -53,9 +49,19 @@ sim_add_option_table (sd, table)
   /* Note: The list is constructed in the reverse order we're called so
      later calls will override earlier ones (in case that ever happens).
      This is the intended behaviour.  */
-  ol->next = STATE_OPTIONS (sd);
-  ol->options = table;
-  STATE_OPTIONS (sd) = ol;
+
+  if (cpu)
+    {
+      ol->next = CPU_OPTIONS (cpu);
+      ol->options = table;
+      CPU_OPTIONS (cpu) = ol;
+    }
+  else
+    {
+      ol->next = STATE_OPTIONS (sd);
+      ol->options = table;
+      STATE_OPTIONS (sd) = ol;
+    }
 
   return SIM_RC_OK;
 }
@@ -83,25 +89,56 @@ static DECLARE_OPTION_HANDLER (standard_option_handler);
    If you decide to conditionally compile them out as well, delete this
    comment and add a comment saying that that is the rule.  */
 
-#define OPTION_DEBUG_INSN      (OPTION_START + 0)
-#define OPTION_DEBUG_FILE      (OPTION_START + 1)
-#define OPTION_DO_COMMAND      (OPTION_START + 2)
-#define OPTION_ARCHITECTURE     (OPTION_START + 3)
-#define OPTION_TARGET           (OPTION_START + 4)
+typedef enum {
+  OPTION_DEBUG_INSN = OPTION_START,
+  OPTION_DEBUG_FILE,
+  OPTION_DO_COMMAND,
+  OPTION_ARCHITECTURE,
+  OPTION_TARGET,
+  OPTION_ARCHITECTURE_INFO,
+  OPTION_ENVIRONMENT,
+  OPTION_ALIGNMENT,
+  OPTION_VERBOSE,
+  OPTION_ENDIAN,
+  OPTION_DEBUG,
+#ifdef SIM_HAVE_FLATMEM
+  OPTION_MEM_SIZE,
+#endif
+  OPTION_HELP,
+#ifdef SIM_H8300 /* FIXME: Should be movable to h8300 dir.  */
+  OPTION_H8300H,
+  OPTION_H8300S,
+  OPTION_H8300SX,
+#endif
+  OPTION_LOAD_LMA,
+  OPTION_LOAD_VMA,
+  OPTION_SYSROOT
+} STANDARD_OPTIONS;
 
 static const OPTION standard_options[] =
 {
-  { {"verbose", no_argument, NULL, 'v'},
+  { {"verbose", no_argument, NULL, OPTION_VERBOSE},
       'v', NULL, "Verbose output",
-      standard_option_handler },
+      standard_option_handler, NULL },
 
-#if defined (SIM_HAVE_BIENDIAN) /* ??? && WITH_TARGET_BYTE_ORDER == 0 */
-  { {"endian", required_argument, NULL, 'E'},
+  { {"endian", required_argument, NULL, OPTION_ENDIAN},
       'E', "big|little", "Set endianness",
+      standard_option_handler, NULL },
+
+#ifdef SIM_HAVE_ENVIRONMENT
+  /* This option isn't supported unless all choices are supported in keeping
+     with the goal of not printing in --help output things the simulator can't
+     do [as opposed to things that just haven't been configured in].  */
+  { {"environment", required_argument, NULL, OPTION_ENVIRONMENT},
+      '\0', "user|virtual|operating", "Set running environment",
       standard_option_handler },
 #endif
 
-  { {"debug", no_argument, NULL, 'D'},
+  { {"alignment", required_argument, NULL, OPTION_ALIGNMENT},
+      '\0', "strict|nonstrict|forced", "Set memory access alignment",
+      standard_option_handler },
+
+  { {"debug", no_argument, NULL, OPTION_DEBUG},
       'D', NULL, "Print debugging messages",
       standard_option_handler },
   { {"debug-insn", no_argument, NULL, OPTION_DEBUG_INSN},
@@ -112,53 +149,79 @@ static const OPTION standard_options[] =
       standard_option_handler },
 
 #ifdef SIM_H8300 /* FIXME: Should be movable to h8300 dir.  */
-  { {"h8300h", no_argument, NULL, 'h'},
-      'h', NULL, "Indicate the CPU is h8/300h or h8/300s",
+  { {"h8300h", no_argument, NULL, OPTION_H8300H},
+      'h', NULL, "Indicate the CPU is H8/300H",
+      standard_option_handler },
+  { {"h8300s", no_argument, NULL, OPTION_H8300S},
+      'S', NULL, "Indicate the CPU is H8S",
+      standard_option_handler },
+  { {"h8300sx", no_argument, NULL, OPTION_H8300SX},
+      'x', NULL, "Indicate the CPU is H8SX",
       standard_option_handler },
 #endif
 
 #ifdef SIM_HAVE_FLATMEM
-  { {"mem-size", required_argument, NULL, 'm'},
-      'm', "MEMORY SIZE", "Specify memory size",
-      standard_option_handler },
+  { {"mem-size", required_argument, NULL, OPTION_MEM_SIZE},
+     'm', "<size>[in bytes, Kb (k suffix), Mb (m suffix) or Gb (g suffix)]",
+     "Specify memory size", standard_option_handler },
 #endif
 
   { {"do-command", required_argument, NULL, OPTION_DO_COMMAND},
       '\0', "COMMAND", ""/*undocumented*/,
       standard_option_handler },
 
-  { {"help", no_argument, NULL, 'H'},
+  { {"help", no_argument, NULL, OPTION_HELP},
       'H', NULL, "Print help information",
       standard_option_handler },
 
   { {"architecture", required_argument, NULL, OPTION_ARCHITECTURE},
       '\0', "MACHINE", "Specify the architecture to use",
       standard_option_handler },
+  { {"architecture-info", no_argument, NULL, OPTION_ARCHITECTURE_INFO},
+      '\0', NULL, "List supported architectures",
+      standard_option_handler },
+  { {"info-architecture", no_argument, NULL, OPTION_ARCHITECTURE_INFO},
+      '\0', NULL, NULL,
+      standard_option_handler },
 
   { {"target", required_argument, NULL, OPTION_TARGET},
       '\0', "BFDNAME", "Specify the object-code format for the object files",
       standard_option_handler },
 
-  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
+#ifdef SIM_HANDLES_LMA
+  { {"load-lma", no_argument, NULL, OPTION_LOAD_LMA},
+      '\0', NULL,
+#if SIM_HANDLES_LMA
+    "Use VMA or LMA addresses when loading image (default LMA)",
+#else
+    "Use VMA or LMA addresses when loading image (default VMA)",
+#endif
+      standard_option_handler, "load-{lma,vma}" },
+  { {"load-vma", no_argument, NULL, OPTION_LOAD_VMA},
+      '\0', NULL, "", standard_option_handler,  "" },
+#endif
+
+  { {"sysroot", required_argument, NULL, OPTION_SYSROOT},
+      '\0', "SYSROOT",
+    "Root for system calls with absolute file-names and cwd at start",
+      standard_option_handler, NULL },
+
+  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
 };
 
 static SIM_RC
-standard_option_handler (sd, opt, arg, is_command)
-     SIM_DESC sd;
-     int opt;
-     char *arg;
-     int is_command;
+standard_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
+                        char *arg, int is_command)
 {
   int i,n;
 
-  switch (opt)
+  switch ((STANDARD_OPTIONS) opt)
     {
-    case 'v' :
+    case OPTION_VERBOSE:
       STATE_VERBOSE_P (sd) = 1;
       break;
 
-#ifdef SIM_HAVE_BIENDIAN
-    case 'E' :
+    case OPTION_ENDIAN:
       if (strcmp (arg, "big") == 0)
        {
          if (WITH_TARGET_BYTE_ORDER == LITTLE_ENDIAN)
@@ -185,9 +248,80 @@ standard_option_handler (sd, opt, arg, is_command)
          return SIM_RC_FAIL;
        }
       break;
-#endif
 
-    case 'D' :
+    case OPTION_ENVIRONMENT:
+      if (strcmp (arg, "user") == 0)
+       STATE_ENVIRONMENT (sd) = USER_ENVIRONMENT;
+      else if (strcmp (arg, "virtual") == 0)
+       STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT;
+      else if (strcmp (arg, "operating") == 0)
+       STATE_ENVIRONMENT (sd) = OPERATING_ENVIRONMENT;
+      else
+       {
+         sim_io_eprintf (sd, "Invalid environment specification `%s'\n", arg);
+         return SIM_RC_FAIL;
+       }
+      if (WITH_ENVIRONMENT != ALL_ENVIRONMENT
+         && WITH_ENVIRONMENT != STATE_ENVIRONMENT (sd))
+       {
+         const char *type;
+         switch (WITH_ENVIRONMENT)
+           {
+           case USER_ENVIRONMENT: type = "user"; break;
+           case VIRTUAL_ENVIRONMENT: type = "virtual"; break;
+           case OPERATING_ENVIRONMENT: type = "operating"; break;
+           }
+         sim_io_eprintf (sd, "Simulator compiled for the %s environment only.\n",
+                         type);
+         return SIM_RC_FAIL;
+       }
+      break;
+
+    case OPTION_ALIGNMENT:
+      if (strcmp (arg, "strict") == 0)
+       {
+         if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == STRICT_ALIGNMENT)
+           {
+             current_alignment = STRICT_ALIGNMENT;
+             break;
+           }
+       }
+      else if (strcmp (arg, "nonstrict") == 0)
+       {
+         if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == NONSTRICT_ALIGNMENT)
+           {
+             current_alignment = NONSTRICT_ALIGNMENT;
+             break;
+           }
+       }
+      else if (strcmp (arg, "forced") == 0)
+       {
+         if (WITH_ALIGNMENT == 0 || WITH_ALIGNMENT == FORCED_ALIGNMENT)
+           {
+             current_alignment = FORCED_ALIGNMENT;
+             break;
+           }
+       }
+      else
+       {
+         sim_io_eprintf (sd, "Invalid alignment specification `%s'\n", arg);
+         return SIM_RC_FAIL;
+       }
+      switch (WITH_ALIGNMENT)
+       {
+       case STRICT_ALIGNMENT:
+         sim_io_eprintf (sd, "Simulator compiled for strict alignment only.\n");
+         break;
+       case NONSTRICT_ALIGNMENT:
+         sim_io_eprintf (sd, "Simulator compiled for nonstrict alignment only.\n");
+         break;
+       case FORCED_ALIGNMENT:
+         sim_io_eprintf (sd, "Simulator compiled for forced alignment only.\n");
+         break;
+       }
+      return SIM_RC_FAIL;
+
+    case OPTION_DEBUG:
       if (! WITH_DEBUG)
        sim_io_eprintf (sd, "Debugging not compiled in, `-D' ignored\n");
       else
@@ -226,15 +360,35 @@ standard_option_handler (sd, opt, arg, is_command)
       break;
 
 #ifdef SIM_H8300 /* FIXME: Can be moved to h8300 dir.  */
-    case 'h' :
-      set_h8300h (1);
+    case OPTION_H8300H:
+      set_h8300h (bfd_mach_h8300h);
+      break;
+    case OPTION_H8300S:
+      set_h8300h (bfd_mach_h8300s);
+      break;
+    case OPTION_H8300SX:
+      set_h8300h (bfd_mach_h8300sx);
       break;
 #endif
 
 #ifdef SIM_HAVE_FLATMEM
-    case 'm':
+    case OPTION_MEM_SIZE:
       {
-       unsigned long ul = strtol (arg, NULL, 0);
+       char * endp;
+       unsigned long ul = strtol (arg, &endp, 0);
+
+       switch (* endp)
+         {
+         case 'k': case 'K': size <<= 10; break;
+         case 'm': case 'M': size <<= 20; break;
+         case 'g': case 'G': size <<= 30; break;
+         case ' ': case '\0': case '\t':  break;
+         default:
+           if (ul > 0)
+             sim_io_eprintf (sd, "Ignoring strange character at end of memory size: %c\n", * endp);
+           break;
+         }
+
        /* 16384: some minimal amount */
        if (! isdigit (arg[0]) || ul < 16384)
          {
@@ -262,18 +416,56 @@ standard_option_handler (sd, opt, arg, is_command)
        break;
       }
 
+    case OPTION_ARCHITECTURE_INFO:
+      {
+       const char **list = bfd_arch_list ();
+       const char **lp;
+       if (list == NULL)
+         abort ();
+       sim_io_printf (sd, "Possible architectures:");
+       for (lp = list; *lp != NULL; lp++)
+         sim_io_printf (sd, " %s", *lp);
+       sim_io_printf (sd, "\n");
+       free (list);
+       break;
+      }
+
     case OPTION_TARGET:
       {
        STATE_TARGET (sd) = xstrdup (arg);
        break;
       }
 
-    case 'H':
+    case OPTION_LOAD_LMA:
+      {
+       STATE_LOAD_AT_LMA_P (sd) = 1;
+       break;
+      }
+
+    case OPTION_LOAD_VMA:
+      {
+       STATE_LOAD_AT_LMA_P (sd) = 0;
+       break;
+      }
+
+    case OPTION_HELP:
       sim_print_help (sd, is_command);
       if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
        exit (0);
       /* FIXME: 'twould be nice to do something similar if gdb.  */
       break;
+
+    case OPTION_SYSROOT:
+      /* Don't leak memory in the odd event that there's lots of
+        --sysroot=... options.  We treat "" specially since this
+        is the statically initialized value and cannot free it.  */
+      if (simulator_sysroot[0] != '\0')
+       free (simulator_sysroot);
+      if (arg[0] != '\0')
+       simulator_sysroot = xstrdup (arg);
+      else
+       simulator_sysroot = "";
+      break;
     }
 
   return SIM_RC_OK;
@@ -285,8 +477,11 @@ SIM_RC
 standard_install (SIM_DESC sd)
 {
   SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
-  if (sim_add_option_table (sd, standard_options) != SIM_RC_OK)
+  if (sim_add_option_table (sd, NULL, standard_options) != SIM_RC_OK)
     return SIM_RC_FAIL;
+#ifdef SIM_HANDLES_LMA
+  STATE_LOAD_AT_LMA_P (sd) = SIM_HANDLES_LMA;
+#endif
   return SIM_RC_OK;
 }
 
@@ -297,16 +492,15 @@ standard_install (SIM_DESC sd)
 #define ARG_HASH(a) ((256 * (unsigned char) a[0] + (unsigned char) a[1]) % ARG_HASH_SIZE)
 
 static int
-dup_arg_p (arg)
-     char *arg;
+dup_arg_p (const char *arg)
 {
   int hash;
-  static char **arg_table = NULL;
+  static const char **arg_table = NULL;
 
   if (arg == NULL)
     {
       if (arg_table == NULL)
-       arg_table = (char **) xmalloc (ARG_HASH_SIZE * sizeof (char *));
+       arg_table = (const char **) xmalloc (ARG_HASH_SIZE * sizeof (char *));
       memset (arg_table, 0, ARG_HASH_SIZE * sizeof (char *));
       return 0;
     }
@@ -324,24 +518,24 @@ dup_arg_p (arg)
   arg_table[hash] = arg;
   return 0;
 }
-     
+
 /* Called by sim_open to parse the arguments.  */
 
 SIM_RC
-sim_parse_args (sd, argv)
-     SIM_DESC sd;
-     char **argv;
+sim_parse_args (SIM_DESC sd, char **argv)
 {
-  int i, argc, num_opts;
+  int c, i, argc, num_opts;
   char *p, *short_options;
   /* The `val' option struct entry is dynamically assigned for options that
      only come in the long form.  ORIG_VAL is used to get the original value
      back.  */
-  unsigned char *orig_val;
+  int *orig_val;
   struct option *lp, *long_options;
   const struct option_list *ol;
   const OPTION *opt;
   OPTION_HANDLER **handlers;
+  sim_cpu **opt_cpu;
+  SIM_RC result = SIM_RC_OK;
 
   /* Count the number of arguments.  */
   for (argc = 0; argv[argc] != NULL; ++argc)
@@ -350,28 +544,34 @@ sim_parse_args (sd, argv)
   /* Count the number of options.  */
   num_opts = 0;
   for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next)
-    for (opt = ol->options; opt->opt.name != NULL; ++opt)
+    for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
       ++num_opts;
+  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+    for (ol = CPU_OPTIONS (STATE_CPU (sd, i)); ol != NULL; ol = ol->next)
+      for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
+       ++num_opts;
 
   /* Initialize duplicate argument checker.  */
   (void) dup_arg_p (NULL);
 
   /* Build the option table for getopt.  */
-  long_options = (struct option *) alloca ((num_opts + 1) * sizeof (struct option));
+
+  long_options = NZALLOC (struct option, num_opts + 1);
   lp = long_options;
-  short_options = (char *) alloca (num_opts * 3 + 1);
+  short_options = NZALLOC (char, num_opts * 3 + 1);
   p = short_options;
-#if 0 /* ??? necessary anymore? */
-  /* Set '+' as first char so argument permutation isn't done.  This is done
-     to workaround a problem with invoking getopt_long in run.c.: optind gets
-     decremented when the program name is reached.  */
+  handlers = NZALLOC (OPTION_HANDLER *, OPTION_START + num_opts);
+  orig_val = NZALLOC (int, OPTION_START + num_opts);
+  opt_cpu = NZALLOC (sim_cpu *, OPTION_START + num_opts);
+
+  /* Set '+' as first char so argument permutation isn't done.  This
+     is done to stop getopt_long returning options that appear after
+     the target program.  Such options should be passed unchanged into
+     the program image. */
   *p++ = '+';
-#endif
-  handlers = (OPTION_HANDLER **) alloca (256 * sizeof (OPTION_HANDLER *));
-  memset (handlers, 0, 256 * sizeof (OPTION_HANDLER *));
-  orig_val = (unsigned char *) alloca (256);
+
   for (i = OPTION_START, ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next)
-    for (opt = ol->options; opt->opt.name != NULL; ++opt)
+    for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
       {
        if (dup_arg_p (opt->opt.name))
          continue;
@@ -382,21 +582,72 @@ sim_parse_args (sd, argv)
              *p++ = ':';
            else if (opt->opt.has_arg == optional_argument)
              { *p++ = ':'; *p++ = ':'; }
+           handlers[(unsigned char) opt->shortopt] = opt->handler;
+           if (opt->opt.val != 0)
+             orig_val[(unsigned char) opt->shortopt] = opt->opt.val;
+           else
+             orig_val[(unsigned char) opt->shortopt] = opt->shortopt;
+         }
+       if (opt->opt.name != NULL)
+         {
+           *lp = opt->opt;
+           /* Dynamically assign `val' numbers for long options. */
+           lp->val = i++;
+           handlers[lp->val] = opt->handler;
+           orig_val[lp->val] = opt->opt.val;
+           opt_cpu[lp->val] = NULL;
+           ++lp;
          }
-       *lp = opt->opt;
-       /* Dynamically assign `val' numbers for long options that don't have
-          a short option equivalent.  */
-       if (OPTION_LONG_ONLY_P (opt->opt.val))
-         lp->val = i++;
-       handlers[(unsigned char) lp->val] = opt->handler;
-       orig_val[(unsigned char) lp->val] = opt->opt.val;
-       ++lp;
       }
+
+  for (c = 0; c < MAX_NR_PROCESSORS; ++c)
+    {
+      sim_cpu *cpu = STATE_CPU (sd, c);
+      for (ol = CPU_OPTIONS (cpu); ol != NULL; ol = ol->next)
+       for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
+         {
+#if 0 /* Each option is prepended with --<cpuname>- so this greatly cuts down
+        on the need for dup_arg_p checking.  Maybe in the future it'll be
+        needed so this is just commented out, and not deleted.  */
+           if (dup_arg_p (opt->opt.name))
+             continue;
+#endif
+           /* Don't allow short versions of cpu specific options for now.  */
+           if (opt->shortopt != 0)
+             {
+               sim_io_eprintf (sd, "internal error, short cpu specific option");
+               result = SIM_RC_FAIL;
+               break;
+             }
+           if (opt->opt.name != NULL)
+             {
+               char *name;
+               *lp = opt->opt;
+               /* Prepend --<cpuname>- to the option.  */
+               if (asprintf (&name, "%s-%s", CPU_NAME (cpu), lp->name) < 0)
+                 {
+                   sim_io_eprintf (sd, "internal error, out of memory");
+                   result = SIM_RC_FAIL;
+                   break;
+                 }
+               lp->name = name;
+               /* Dynamically assign `val' numbers for long options. */
+               lp->val = i++;
+               handlers[lp->val] = opt->handler;
+               orig_val[lp->val] = opt->opt.val;
+               opt_cpu[lp->val] = cpu;
+               ++lp;
+             }
+         }
+    }
+
+  /* Terminate the short and long option lists.  */
   *p = 0;
   lp->name = NULL;
 
   /* Ensure getopt is initialized.  */
   optind = 0;
+
   while (1)
     {
       int longind, optc;
@@ -405,44 +656,41 @@ sim_parse_args (sd, argv)
       if (optc == -1)
        {
          if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
-           STATE_PROG_ARGV (sd) = sim_copy_argv (argv + optind);
+           STATE_PROG_ARGV (sd) = dupargv (argv + optind);
          break;
        }
       if (optc == '?')
-       return SIM_RC_FAIL;
+       {
+         result = SIM_RC_FAIL;
+         break;
+       }
 
-      if ((*handlers[optc]) (sd, orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL)
-       return SIM_RC_FAIL;
+      if ((*handlers[optc]) (sd, opt_cpu[optc], orig_val[optc], optarg, 0/*!is_command*/) == SIM_RC_FAIL)
+       {
+         result = SIM_RC_FAIL;
+         break;
+       }
     }
 
-  return SIM_RC_OK;
+  free (long_options);
+  free (short_options);
+  free (handlers);
+  free (opt_cpu);
+  free (orig_val);
+  return result;
 }
 
-/* Print help messages for the options.  */
+/* Utility of sim_print_help to print a list of option tables.  */
 
-void
-sim_print_help (sd, is_command)
-     SIM_DESC sd;
-     int is_command;
+static void
+print_help (SIM_DESC sd, sim_cpu *cpu, const struct option_list *ol, int is_command)
 {
-  const struct option_list *ol;
   const OPTION *opt;
 
-  if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
-    sim_io_printf (sd, "Usage: %s [options] program [program args]\n",
-                  STATE_MY_NAME (sd));
-
-  /* Initialize duplicate argument checker.  */
-  (void) dup_arg_p (NULL);
-
-  if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
-    sim_io_printf (sd, "Options:\n");
-  else
-    sim_io_printf (sd, "Commands:\n");
-
-  for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next)
-    for (opt = ol->options; opt->opt.name != NULL; ++opt)
+  for ( ; ol != NULL; ol = ol->next)
+    for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
       {
+       const int indent = 30;
        int comma, len;
        const OPTION *o;
 
@@ -460,6 +708,7 @@ sim_print_help (sd, is_command)
        comma = 0;
        len = 2;
 
+       /* list any short options (aliases) for the current OPT */
        if (!is_command)
          {
            o = opt;
@@ -486,22 +735,26 @@ sim_print_help (sd, is_command)
                  }
                ++o;
              }
-           while (o->opt.name != NULL && o->doc == NULL);
+           while (OPTION_VALID_P (o) && o->doc == NULL);
          }
-       
+
+       /* list any long options (aliases) for the current OPT */
        o = opt;
        do
          {
            const char *name;
+           const char *cpu_prefix = cpu ? CPU_NAME (cpu) : NULL;
            if (o->doc_name != NULL)
              name = o->doc_name;
            else
              name = o->opt.name;
            if (name != NULL)
              {
-               sim_io_printf (sd, "%s%s%s",
+               sim_io_printf (sd, "%s%s%s%s%s",
                               comma ? ", " : "",
                               is_command ? "" : "--",
+                              cpu ? cpu_prefix : "",
+                              cpu ? "-" : "",
                               name);
                len += ((comma ? 2 : 0)
                        + (is_command ? 0 : 2)
@@ -510,7 +763,7 @@ sim_print_help (sd, is_command)
                  {
                    if (o->opt.has_arg == optional_argument)
                      {
-                       sim_io_printf (sd, " [%s]", o->arg);
+                       sim_io_printf (sd, "[=%s]", o->arg);
                        len += 2 + strlen (o->arg) + 1;
                      }
                    else
@@ -523,21 +776,74 @@ sim_print_help (sd, is_command)
              }
            ++o;
          }
-       while (o->opt.name != NULL && o->doc == NULL);
+       while (OPTION_VALID_P (o) && o->doc == NULL);
 
-       if (len >= 30)
+       if (len >= indent)
          {
-           sim_io_printf (sd, "\n");
-           len = 0;
+           sim_io_printf (sd, "\n%*s", indent, "");
          }
+       else
+         sim_io_printf (sd, "%*s", indent - len, "");
 
-       for (; len < 30; len++)
-         sim_io_printf (sd, " ");
-
-       sim_io_printf (sd, "%s\n", opt->doc);
+       /* print the description, word wrap long lines */
+       {
+         const char *chp = opt->doc;
+         unsigned doc_width = 80 - indent;
+         while (strlen (chp) >= doc_width) /* some slack */
+           {
+             const char *end = chp + doc_width - 1;
+             while (end > chp && !isspace (*end))
+               end --;
+             if (end == chp)
+               end = chp + doc_width - 1;
+             /* The cast should be ok - its distances between to
+                 points in a string.  */
+             sim_io_printf (sd, "%.*s\n%*s", (int) (end - chp), chp, indent,
+                            "");
+             chp = end;
+             while (isspace (*chp) && *chp != '\0')
+               chp++;
+           }
+         sim_io_printf (sd, "%s\n", chp);
+       }
       }
+}
 
+/* Print help messages for the options.  */
+
+void
+sim_print_help (SIM_DESC sd, int is_command)
+{
+  if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
+    sim_io_printf (sd, "Usage: %s [options] program [program args]\n",
+                  STATE_MY_NAME (sd));
+
+  /* Initialize duplicate argument checker.  */
+  (void) dup_arg_p (NULL);
+
+  if (STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE)
+    sim_io_printf (sd, "Options:\n");
+  else
+    sim_io_printf (sd, "Commands:\n");
+
+  print_help (sd, NULL, STATE_OPTIONS (sd), is_command);
   sim_io_printf (sd, "\n");
+
+  /* Print cpu-specific options.  */
+  {
+    int i;
+
+    for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+      {
+       sim_cpu *cpu = STATE_CPU (sd, i);
+       if (CPU_OPTIONS (cpu) == NULL)
+         continue;
+       sim_io_printf (sd, "CPU %s specific options:\n", CPU_NAME (cpu));
+       print_help (sd, cpu, CPU_OPTIONS (cpu), is_command);
+       sim_io_printf (sd, "\n");
+      }
+  }
+
   sim_io_printf (sd, "Note: Depending on the simulator configuration some %ss\n",
                 STATE_OPEN_KIND (sd) == SIM_OPEN_STANDALONE ? "option" : "command");
   sim_io_printf (sd, "      may not be applicable\n");
@@ -550,18 +856,127 @@ sim_print_help (sd, is_command)
     }
 }
 
+/* Utility of sim_args_command to find the closest match for a command.
+   Commands that have "-" in them can be specified as separate words.
+   e.g. sim memory-region 0x800000,0x4000
+   or   sim memory region 0x800000,0x4000
+   If CPU is non-null, use its option table list, otherwise use the main one.
+   *PARGI is where to start looking in ARGV.  It is updated to point past
+   the found option.  */
+
+static const OPTION *
+find_match (SIM_DESC sd, sim_cpu *cpu, char *argv[], int *pargi)
+{
+  const struct option_list *ol;
+  const OPTION *opt;
+  /* most recent option match */
+  const OPTION *matching_opt = NULL;
+  int matching_argi = -1;
+
+  if (cpu)
+    ol = CPU_OPTIONS (cpu);
+  else
+    ol = STATE_OPTIONS (sd);
+
+  /* Skip passed elements specified by *PARGI.  */
+  argv += *pargi;
+
+  for ( ; ol != NULL; ol = ol->next)
+    for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
+      {
+       int argi = 0;
+       const char *name = opt->opt.name;
+       if (name == NULL)
+         continue;
+       while (argv [argi] != NULL
+              && strncmp (name, argv [argi], strlen (argv [argi])) == 0)
+         {
+           name = &name [strlen (argv[argi])];
+           if (name [0] == '-')
+             {
+               /* leading match ...<a-b-c>-d-e-f - continue search */
+               name ++; /* skip `-' */
+               argi ++;
+               continue;
+             }
+           else if (name [0] == '\0')
+             {
+               /* exact match ...<a-b-c-d-e-f> - better than before? */
+               if (argi > matching_argi)
+                 {
+                   matching_argi = argi;
+                   matching_opt = opt;
+                 }
+               break;
+             }
+           else
+             break;
+         }
+      }
+
+  *pargi = matching_argi;
+  return matching_opt;
+}
+
+static char **
+complete_option_list (char **ret, size_t *cnt, const struct option_list *ol,
+                     char *text, char *word)
+{
+  const OPTION *opt = NULL;
+  int argi;
+  size_t len = strlen (word);
 
+  for ( ; ol != NULL; ol = ol->next)
+    for (opt = ol->options; OPTION_VALID_P (opt); ++opt)
+      {
+       const char *name = opt->opt.name;
+
+       /* A long option to match against?  */
+       if (!name)
+         continue;
 
+       /* Does this option actually match?  */
+       if (strncmp (name, word, len))
+         continue;
+
+       ret = xrealloc (ret, ++*cnt * sizeof (ret[0]));
+       ret[*cnt - 2] = xstrdup (name);
+      }
+
+  return ret;
+}
+
+/* All leading text is stored in @text, while the current word being
+   completed is stored in @word.  Trailing text of @word is not.  */
+
+char **
+sim_complete_command (SIM_DESC sd, char *text, char *word)
+{
+  char **ret = NULL;
+  size_t cnt = 1;
+  sim_cpu *cpu;
+
+  /* Only complete first word for now.  */
+  if (text != word)
+    return ret;
+
+  cpu = STATE_CPU (sd, 0);
+  if (cpu)
+    ret = complete_option_list (ret, &cnt, CPU_OPTIONS (cpu), text, word);
+  ret = complete_option_list (ret, &cnt, STATE_OPTIONS (sd), text, word);
+
+  if (ret)
+    ret[cnt - 1] = NULL;
+  return ret;
+}
 
 SIM_RC
-sim_args_command (sd, cmd)
-     SIM_DESC sd;
-     char *cmd;
+sim_args_command (SIM_DESC sd, char *cmd)
 {
   /* something to do? */
   if (cmd == NULL)
-    return SIM_RC_OK; /* FIXME - perhaphs help would be better */
-  
+    return SIM_RC_OK; /* FIXME - perhaps help would be better */
+
   if (cmd [0] == '-')
     {
       /* user specified -<opt> ... form? */
@@ -572,50 +987,53 @@ sim_args_command (sd, cmd)
     }
   else
     {
-      /* user specified <opt> form? */
-      const struct option_list *ol;
-      const OPTION *opt;
       char **argv = buildargv (cmd);
-      /* most recent option match */
       const OPTION *matching_opt = NULL;
-      int matching_argi = -1;
-      if (argv [0] != NULL)
-       for (ol = STATE_OPTIONS (sd); ol != NULL; ol = ol->next)
-         for (opt = ol->options; opt->opt.name != NULL; ++opt)
-           {
-             int argi = 0;
-             const char *name = opt->opt.name;
-             while (strncmp (name, argv [argi], strlen (argv [argi])) == 0)
-               {
-                 name = &name [strlen (argv[argi])];
-                 if (name [0] == '-')
-                   {
-                     /* leading match ...<a-b-c>-d-e-f - continue search */
-                     name ++; /* skip `-' */
-                     argi ++;
-                     continue;
-                   }
-                 else if (name [0] == '\0')
-                   {
-                     /* exact match ...<a-b-c-d-e-f> - better than before? */
-                     if (argi > matching_argi)
-                       {
-                         matching_argi = argi;
-                         matching_opt = opt;
-                       }
-                     break;
-                   }
-                 else
-                   break;
-               }
-           }
+      int matching_argi;
+      sim_cpu *cpu;
+
+      if (argv [0] == NULL)
+       return SIM_RC_OK; /* FIXME - perhaps help would be better */
+
+      /* First check for a cpu selector.  */
+      {
+       char *cpu_name = xstrdup (argv[0]);
+       char *hyphen = strchr (cpu_name, '-');
+       if (hyphen)
+         *hyphen = 0;
+       cpu = sim_cpu_lookup (sd, cpu_name);
+       if (cpu)
+         {
+           /* If <cpuname>-<command>, point argv[0] at <command>.  */
+           if (hyphen)
+             {
+               matching_argi = 0;
+               argv[0] += hyphen - cpu_name + 1;
+             }
+           else
+             matching_argi = 1;
+           matching_opt = find_match (sd, cpu, argv, &matching_argi);
+           /* If hyphen found restore argv[0].  */
+           if (hyphen)
+             argv[0] -= hyphen - cpu_name + 1;
+         }
+       free (cpu_name);
+      }
+
+      /* If that failed, try the main table.  */
+      if (matching_opt == NULL)
+       {
+         matching_argi = 0;
+         matching_opt = find_match (sd, NULL, argv, &matching_argi);
+       }
+
       if (matching_opt != NULL)
        {
          switch (matching_opt->opt.has_arg)
            {
            case no_argument:
              if (argv [matching_argi + 1] == NULL)
-               matching_opt->handler (sd, matching_opt->opt.val,
+               matching_opt->handler (sd, cpu, matching_opt->opt.val,
                                       NULL, 1/*is_command*/);
              else
                sim_io_eprintf (sd, "Command `%s' takes no arguments\n",
@@ -623,10 +1041,10 @@ sim_args_command (sd, cmd)
              break;
            case optional_argument:
              if (argv [matching_argi + 1] == NULL)
-               matching_opt->handler (sd, matching_opt->opt.val,
+               matching_opt->handler (sd, cpu, matching_opt->opt.val,
                                       NULL, 1/*is_command*/);
              else if (argv [matching_argi + 2] == NULL)
-               matching_opt->handler (sd, matching_opt->opt.val,
+               matching_opt->handler (sd, cpu, matching_opt->opt.val,
                                       argv [matching_argi + 1], 1/*is_command*/);
              else
                sim_io_eprintf (sd, "Command `%s' requires no more than one argument\n",
@@ -637,16 +1055,19 @@ sim_args_command (sd, cmd)
                sim_io_eprintf (sd, "Command `%s' requires an argument\n",
                                matching_opt->opt.name);
              else if (argv [matching_argi + 2] == NULL)
-               matching_opt->handler (sd, matching_opt->opt.val,
+               matching_opt->handler (sd, cpu, matching_opt->opt.val,
                                       argv [matching_argi + 1], 1/*is_command*/);
              else
                sim_io_eprintf (sd, "Command `%s' requires only one argument\n",
                                matching_opt->opt.name);
            }
+         freeargv (argv);
          return SIM_RC_OK;
        }
+
+      freeargv (argv);
     }
-      
+
   /* didn't find anything that remotly matched */
   return SIM_RC_FAIL;
 }