diff mbox

[PATCH/RFC] sim: simarch: new runtime framework for target settings (for --enable-targets=all)

Message ID 1451903563-6188-1-git-send-email-vapier@gentoo.org
State RFC
Delegated to: Mike Frysinger
Headers show

Commit Message

Mike Frysinger Jan. 4, 2016, 10:32 a.m. UTC
This takes a page from gdbarch's framework and brings it to the sim.
Rather than setting up defaults via configure flags or having every
port provide specific symbol names (e.g. sim_xxx), they define and
register a simarch structure.  The core code then matches that when
it loads and uses that for defaults/further callbacks.

This doesn't get us complete arch independence yet as we need to:
 - redo the build system
 - invert sim_state definition (e.g. STATE_ARCH_DATA)
 - invert sim_cpu definition (e.g. CPU_ARCH_DATA)

But this gets us much closer and should allow for further unwinding.
This isn't ready just yet for merging -- posting as RFC before I get
too much further down this rabbit hole.
---
 sim/bfin/configure        |  21 +----
 sim/bfin/configure.ac     |   3 +-
 sim/bfin/interp.c         | 163 ++++++++++------------------------
 sim/bfin/proc_list.def    |   3 +-
 sim/bfin/sim-main.h       |   3 +
 sim/common/Make-common.in |   3 +
 sim/common/sim-base.h     |   8 +-
 sim/common/sim-config.c   |   9 +-
 sim/common/sim-inferior.c |  64 ++++++++++++++
 sim/common/sim-model.c    | 216 +++++++++++++++++++++++++++++-----------------
 sim/common/sim-model.h    |  13 ++-
 sim/common/sim-open.c     |  95 ++++++++++++++++++++
 sim/common/sim-resume.c   |   5 +-
 sim/common/sim-simarch.c  | 120 ++++++++++++++++++++++++++
 sim/common/sim-simarch.h  |  58 +++++++++++++
 15 files changed, 549 insertions(+), 235 deletions(-)
 create mode 100644 sim/common/sim-inferior.c
 create mode 100644 sim/common/sim-open.c
 create mode 100644 sim/common/sim-simarch.c
 create mode 100644 sim/common/sim-simarch.h

Comments

Pedro Alves Jan. 4, 2016, 12:32 p.m. UTC | #1
On 01/04/2016 10:32 AM, Mike Frysinger wrote:
> This takes a page from gdbarch's framework and brings it to the sim.
> Rather than setting up defaults via configure flags or having every
> port provide specific symbol names (e.g. sim_xxx), they define and
> register a simarch structure.  The core code then matches that when
> it loads and uses that for defaults/further callbacks.
> 
> This doesn't get us complete arch independence yet as we need to:
>  - redo the build system
>  - invert sim_state definition (e.g. STATE_ARCH_DATA)
>  - invert sim_cpu definition (e.g. CPU_ARCH_DATA)
> 
> But this gets us much closer and should allow for further unwinding.
> This isn't ready just yet for merging -- posting as RFC before I get
> too much further down this rabbit hole.

I'm not very familiar with the sim's internals, but this sounds like
a great step forward to me.  Thanks for doing all of this.

Thanks,
Pedro Alves
diff mbox

Patch

diff --git a/sim/bfin/configure b/sim/bfin/configure
index ae49198..10079c6 100755
--- a/sim/bfin/configure
+++ b/sim/bfin/configure
@@ -765,7 +765,6 @@  with_pkgversion
 with_bugurl
 enable_sim_endian
 enable_sim_alignment
-enable_sim_default_model
 enable_sim_environment
 enable_sim_inline
 enable_werror
@@ -1427,8 +1426,6 @@  Optional Features:
   --enable-sim-alignment=align
                           Specify strict, nonstrict or forced alignment of
                           memory accesses
-  --enable-sim-default-model=model
-                          Specify default model to simulate
   --enable-sim-environment=environment
                           Specify mixed, user, virtual or operating
                           environment
@@ -13132,7 +13129,7 @@  sim_link_links="${sim_link_links} targ-vals.def"
 
 
 
-wire_endian="LITTLE"
+wire_endian=""
 default_endian=""
 # Check whether --enable-sim-endian was given.
 if test "${enable_sim_endian+set}" = set; then :
@@ -13223,22 +13220,6 @@  fi
 fi
 
 
-default_sim_default_model="bf537"
-# Check whether --enable-sim-default-model was given.
-if test "${enable_sim_default_model+set}" = set; then :
-  enableval=$enable_sim_default_model; case "${enableval}" in
-  yes|no) as_fn_error "\"Missing argument to --enable-sim-default-model\"" "$LINENO" 5;;
-  *)	sim_default_model="-DWITH_DEFAULT_MODEL='\"${enableval}\"'";;
-esac
-if test x"$silent" != x"yes" && test x"$sim_default_model" != x""; then
-  echo "Setting default model = $sim_default_model" 6>&1
-fi
-else
-  sim_default_model="-DWITH_DEFAULT_MODEL='\"${default_sim_default_model}\"'"
-fi
-
-
-
 # Check whether --enable-sim-environment was given.
 if test "${enable_sim_environment+set}" = set; then :
   enableval=$enable_sim_environment; case "${enableval}" in
diff --git a/sim/bfin/configure.ac b/sim/bfin/configure.ac
index f0f7396..32598fb 100644
--- a/sim/bfin/configure.ac
+++ b/sim/bfin/configure.ac
@@ -5,9 +5,8 @@  sinclude(../common/acinclude.m4)
 
 SIM_AC_COMMON
 
-SIM_AC_OPTION_ENDIAN(LITTLE)
+SIM_AC_OPTION_ENDIAN
 SIM_AC_OPTION_ALIGNMENT(STRICT_ALIGNMENT,STRICT_ALIGNMENT)
-SIM_AC_OPTION_DEFAULT_MODEL(bf537)
 SIM_AC_OPTION_ENVIRONMENT
 SIM_AC_OPTION_INLINE
 SIM_AC_OPTION_WARNINGS
diff --git a/sim/bfin/interp.c b/sim/bfin/interp.c
index ad86500..effcdff 100644
--- a/sim/bfin/interp.c
+++ b/sim/bfin/interp.c
@@ -657,8 +657,8 @@  step_once (SIM_CPU *cpu)
   return oldpc;
 }
 
-void
-sim_engine_run (SIM_DESC sd,
+static void
+bfin_engine_run (SIM_DESC sd,
 		int next_cpu_nr, /* ignore  */
 		int nr_cpus, /* ignore  */
 		int siggnal) /* ignore  */
@@ -681,22 +681,11 @@  sim_engine_run (SIM_DESC sd,
     }
 }
 
-/* Cover function of sim_state_free to free the cpu buffers as well.  */
-
 static void
-free_state (SIM_DESC sd)
+bfin_cpu_init (SIM_CPU *cpu)
 {
-  if (STATE_MODULES (sd) != NULL)
-    sim_module_uninstall (sd);
-  sim_cpu_free_all (sd);
-  sim_state_free (sd);
-}
-
-/* Create an instance of the simulator.  */
+  SIM_DESC sd = CPU_STATE (cpu);
 
-static void
-bfin_initialize_cpu (SIM_DESC sd, SIM_CPU *cpu)
-{
   memset (&cpu->state, 0, sizeof (cpu->state));
 
   PROFILE_TOTAL_INSN_COUNT (CPU_PROFILE_DATA (cpu)) = 0;
@@ -712,56 +701,20 @@  bfin_initialize_cpu (SIM_DESC sd, SIM_CPU *cpu)
   SET_SYSCFGREG (0x30);
 }
 
-SIM_DESC
-sim_open (SIM_OPEN_KIND kind, host_callback *callback,
-	  struct bfd *abfd, char **argv)
+static void
+bfin_state_init (SIM_DESC sd)
 {
   char c;
-  int i;
-  SIM_DESC sd = sim_state_alloc (kind, callback);
-
-  /* The cpu data is kept in a separately allocated chunk of memory.  */
-  if (sim_cpu_alloc_all (sd, 1, /*cgen_cpu_max_extra_bytes ()*/0) != SIM_RC_OK)
-    {
-      free_state (sd);
-      return 0;
-    }
 
-  {
-    /* XXX: Only first core gets profiled ?  */
-    SIM_CPU *cpu = STATE_CPU (sd, 0);
-    STATE_WATCHPOINTS (sd)->pc = &PCREG;
-    STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PCREG);
-  }
-
-  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
-    {
-      free_state (sd);
-      return 0;
-    }
+  /* XXX: Only first core gets profiled ?  */
+  SIM_CPU *cpu = STATE_CPU (sd, 0);
+  STATE_WATCHPOINTS (sd)->pc = &PCREG;
+  STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PCREG);
 
   /* XXX: Default to the Virtual environment.  */
   if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT)
     STATE_ENVIRONMENT (sd) = VIRTUAL_ENVIRONMENT;
 
-  /* These options override any module options.
-     Obviously ambiguity should be avoided, however the caller may wish to
-     augment the meaning of an option.  */
-#define e_sim_add_option_table(sd, options) \
-  do { \
-    extern const OPTION options[]; \
-    sim_add_option_table (sd, NULL, options); \
-  } while (0)
-  e_sim_add_option_table (sd, bfin_mmu_options);
-  e_sim_add_option_table (sd, bfin_mach_options);
-
-  /* The parser will print an error message for us, so we silently return.  */
-  if (sim_parse_args (sd, argv) != SIM_RC_OK)
-    {
-      free_state (sd);
-      return 0;
-    }
-
   /* Allocate external memory if none specified by user.
      Use address 4 here in case the user wanted address 0 unmapped.  */
   if (sim_core_read_buffer (sd, NULL, read_map, &c, 4, 1) == 0)
@@ -770,38 +723,6 @@  sim_open (SIM_OPEN_KIND kind, host_callback *callback,
       sim_do_commandf (sd, "memory-size 0x%lx", BFIN_DEFAULT_MEM_SIZE);
       sim_write (sd, 0, (void *)&emuexcpt, 2);
     }
-
-  /* Check for/establish the a reference program image.  */
-  if (sim_analyze_program (sd,
-			   (STATE_PROG_ARGV (sd) != NULL
-			    ? *STATE_PROG_ARGV (sd)
-			    : NULL), abfd) != SIM_RC_OK)
-    {
-      free_state (sd);
-      return 0;
-    }
-
-  /* Establish any remaining configuration options.  */
-  if (sim_config (sd) != SIM_RC_OK)
-    {
-      free_state (sd);
-      return 0;
-    }
-
-  if (sim_post_argv_init (sd) != SIM_RC_OK)
-    {
-      free_state (sd);
-      return 0;
-    }
-
-  /* CPU specific initialization.  */
-  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
-    {
-      SIM_CPU *cpu = STATE_CPU (sd, i);
-      bfin_initialize_cpu (sd, cpu);
-    }
-
-  return sd;
 }
 
 /* Some utils don't like having a NULL environ.  */
@@ -962,7 +883,7 @@  bfin_fdpic_load (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd, bu32 *sp,
 }
 
 static void
-bfin_user_init (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd,
+bfin_user_init (SIM_DESC sd, struct bfd *abfd,
 		const char * const *argv, const char * const *env)
 {
   /* XXX: Missing host -> target endian ...  */
@@ -998,6 +919,9 @@  bfin_user_init (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd,
 
   host_callback *cb = STATE_CALLBACK (sd);
 
+  /* We only set up the first CPU.  The others are left unlocked.  */
+  SIM_CPU *cpu = STATE_CPU (sd, 0);
+
   elf_addrs[0] = elf_addrs[4] = bfd_get_start_address (abfd);
   elf_addrs[1] = elf_addrs[2] = elf_addrs[3] = elf_addrs[5] = 0;
 
@@ -1145,8 +1069,10 @@  bfin_user_init (SIM_DESC sd, SIM_CPU *cpu, struct bfd *abfd,
 }
 
 static void
-bfin_os_init (SIM_DESC sd, SIM_CPU *cpu, const char * const *argv)
+bfin_os_init (SIM_DESC sd, const char * const *argv)
 {
+  /* We only set up the first CPU.  The others are left unlocked.  */
+  SIM_CPU *cpu = STATE_CPU (sd, 0);
   /* Pass the command line via a string in R0 like Linux expects.  */
   int i;
   bu8 byte;
@@ -1172,7 +1098,7 @@  bfin_os_init (SIM_DESC sd, SIM_CPU *cpu, const char * const *argv)
 }
 
 static void
-bfin_virtual_init (SIM_DESC sd, SIM_CPU *cpu)
+bfin_virtual_init (SIM_DESC sd)
 {
   host_callback *cb = STATE_CALLBACK (sd);
 
@@ -1180,42 +1106,41 @@  bfin_virtual_init (SIM_DESC sd, SIM_CPU *cpu)
   stat_map_64 = NULL;
 }
 
-SIM_RC
-sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
-		     char **argv, char **env)
+static void
+bfin_inferior_init (SIM_DESC sd, struct bfd *abfd,
+		    const char * const *argv, const char * const *envp)
 {
-  SIM_CPU *cpu = STATE_CPU (sd, 0);
-  SIM_ADDR addr;
-
-  /* Set the PC.  */
-  if (abfd != NULL)
-    addr = bfd_get_start_address (abfd);
-  else
-    addr = 0;
-  sim_pc_set (cpu, addr);
-
-  /* Standalone mode (i.e. `run`) will take care of the argv for us in
-     sim_open() -> sim_parse_args().  But in debug mode (i.e. 'target sim'
-     with `gdb`), we need to handle it because the user can change the
-     argv on the fly via gdb's 'run'.  */
-  if (STATE_PROG_ARGV (sd) != argv)
-    {
-      freeargv (STATE_PROG_ARGV (sd));
-      STATE_PROG_ARGV (sd) = dupargv (argv);
-    }
-
   switch (STATE_ENVIRONMENT (sd))
     {
     case USER_ENVIRONMENT:
-      bfin_user_init (sd, cpu, abfd, (void *)argv, (void *)env);
+      bfin_user_init (sd, abfd, (void *)argv, (void *)envp);
       break;
     case OPERATING_ENVIRONMENT:
-      bfin_os_init (sd, cpu, (void *)argv);
+      bfin_os_init (sd, (void *)argv);
       break;
     default:
-      bfin_virtual_init (sd, cpu);
+      bfin_virtual_init (sd);
       break;
     }
+}
+
+static const simarch bfin_simarch =
+{
+  .engine_run = bfin_engine_run,
+  .state_init = bfin_state_init,
+  .cpu_init = bfin_cpu_init,
+  .inferior_init = bfin_inferior_init,
+  .default_environment = VIRTUAL_ENVIRONMENT,
+  .default_endian = BFD_ENDIAN_LITTLE,
+  .default_alignment = STRICT_ALIGNMENT,
+  .default_model = "bf537",
+  .machs = sim_machs,
+};
+
+extern SIM_SIMARCH_REGISTER_FN sim_simarch_register_bfin;
 
-  return SIM_RC_OK;
+SIM_RC
+sim_simarch_register_bfin (void)
+{
+  return sim_simarch_register (bfd_arch_bfin, &bfin_simarch);
 }
diff --git a/sim/bfin/proc_list.def b/sim/bfin/proc_list.def
index 1fe73ff..a9bb67d 100644
--- a/sim/bfin/proc_list.def
+++ b/sim/bfin/proc_list.def
@@ -18,8 +18,6 @@ 
    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
-/* First entry is the default model.  */
-P(537)
 P(504)
 P(506)
 P(512)
@@ -38,6 +36,7 @@  P(533)
 P(534)
 /*P(535)*/
 P(536)
+P(537)
 P(538)
 P(539)
 P(542)
diff --git a/sim/bfin/sim-main.h b/sim/bfin/sim-main.h
index 8804a71..65587d3 100644
--- a/sim/bfin/sim-main.h
+++ b/sim/bfin/sim-main.h
@@ -21,6 +21,9 @@ 
 #ifndef _BFIN_MAIN_SIM_H_
 #define _BFIN_MAIN_SIM_H_
 
+/* We want to use the new simarch logic.  */
+#define WITH_SIMARCH 1
+
 #include "sim-basics.h"
 #include "sim-signal.h"
 
diff --git a/sim/common/Make-common.in b/sim/common/Make-common.in
index 6fdf10f..1ec468d 100644
--- a/sim/common/Make-common.in
+++ b/sim/common/Make-common.in
@@ -185,17 +185,20 @@  SIM_NEW_COMMON_OBJS = \
 	sim-fpu.o \
 	sim-hload.o \
 	sim-hrw.o \
+	sim-inferior.o \
 	sim-io.o \
 	sim-info.o \
 	sim-load.o \
 	sim-memopt.o \
 	sim-model.o \
 	sim-module.o \
+	sim-open.o \
 	sim-options.o \
 	sim-profile.o \
 	sim-reason.o \
 	sim-reg.o \
 	sim-signal.o \
+	sim-simarch.o \
 	sim-stop.o \
 	sim-syscall.o \
 	sim-trace.o \
diff --git a/sim/common/sim-base.h b/sim/common/sim-base.h
index 350b352..9d51dbf 100644
--- a/sim/common/sim-base.h
+++ b/sim/common/sim-base.h
@@ -78,6 +78,7 @@  typedef struct _sim_cpu sim_cpu;
 
 #include "sim-module.h"
 
+#include "sim-simarch.h"
 #include "sim-trace.h"
 #include "sim-core.h"
 #include "sim-events.h"
@@ -113,6 +114,10 @@  typedef struct {
   struct host_callback_struct *callback;
 #define STATE_CALLBACK(sd) ((sd)->base.callback)
 
+  /* Target specific data.  */
+  const simarch *simarch;
+#define STATE_SIMARCH(sd) ((sd)->base.simarch)
+
   /* The type of simulation environment (user/operating).  */
   enum sim_environment environment;
 #define STATE_ENVIRONMENT(sd) ((sd)->base.environment)
@@ -147,8 +152,7 @@  typedef struct {
   const char *target;
 #define STATE_TARGET(sd) ((sd)->base.target)
 
-  /* In standalone simulator, this is the program's arguments passed
-     on the command line.  */
+  /* The program's arguments passed on the command line.  */
   char **prog_argv;
 #define STATE_PROG_ARGV(sd) ((sd)->base.prog_argv)
 
diff --git a/sim/common/sim-config.c b/sim/common/sim-config.c
index d9036e1..60c6efc 100644
--- a/sim/common/sim-config.c
+++ b/sim/common/sim-config.c
@@ -169,6 +169,8 @@  sim_config (SIM_DESC sd)
     current_target_byte_order = WITH_TARGET_BYTE_ORDER;
   if (current_target_byte_order == BFD_ENDIAN_UNKNOWN)
     current_target_byte_order = WITH_DEFAULT_TARGET_BYTE_ORDER;
+  if (current_target_byte_order == BFD_ENDIAN_UNKNOWN && WITH_SIMARCH)
+    current_target_byte_order = STATE_SIMARCH (sd)->default_endian;
 
   /* verify the target byte order */
   if (CURRENT_TARGET_BYTE_ORDER == BFD_ENDIAN_UNKNOWN)
@@ -237,8 +239,9 @@  sim_config (SIM_DESC sd)
     }
 #endif
   if (STATE_ENVIRONMENT (sd) == ALL_ENVIRONMENT)
-    STATE_ENVIRONMENT (sd) = DEFAULT_ENVIRONMENT;
-
+    STATE_ENVIRONMENT (sd) =
+      WITH_SIMARCH ? STATE_SIMARCH (sd)->default_environment
+		   : DEFAULT_ENVIRONMENT;
 
   /* set the alignment */
 #if (WITH_TREE_PROPERTIES)
@@ -252,6 +255,8 @@  sim_config (SIM_DESC sd)
     current_alignment = WITH_ALIGNMENT;
   if (current_alignment == 0)
     current_alignment = WITH_DEFAULT_ALIGNMENT;
+  if (current_alignment == 0 && WITH_SIMARCH)
+    current_alignment = STATE_SIMARCH (sd)->default_alignment;
 
   /* verify the alignment */
   if (CURRENT_ALIGNMENT == 0)
diff --git a/sim/common/sim-inferior.c b/sim/common/sim-inferior.c
new file mode 100644
index 0000000..d9f601c
--- /dev/null
+++ b/sim/common/sim-inferior.c
@@ -0,0 +1,64 @@ 
+/* Miscellaneous simulator utilities.
+
+   Copyright (C) 2005-2015 Free Software Foundation, Inc.
+   Contributed by Analog Devices, Inc. and Stephane Carrez.
+
+   This file is part of simulators.
+
+   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 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "sim-main.h"
+#include "gdb/remote-sim.h"
+
+#if WITH_SIMARCH
+
+SIM_RC
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
+		     char **argv, char **envp)
+{
+  size_t i;
+  sim_cia pc;
+  const simarch *simarch;
+
+  /* Set the PC.  */
+  if (abfd != NULL)
+    pc = bfd_get_start_address (abfd);
+  else
+    pc = 0;
+
+  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+    {
+      SIM_CPU *cpu = STATE_CPU (sd, i);
+
+      sim_pc_set (cpu, pc);
+    }
+
+  /* Standalone mode (i.e. `run`) will take care of the argv for us in
+     sim_open() -> sim_parse_args().  But in debug mode (i.e. 'target sim'
+     with `gdb`), we need to handle it because the user can change the
+     argv on the fly via gdb's 'run'.  */
+  if (STATE_PROG_ARGV (sd) != argv)
+    {
+      freeargv (STATE_PROG_ARGV (sd));
+      STATE_PROG_ARGV (sd) = dupargv (argv);
+    }
+
+  simarch = STATE_SIMARCH (sd);
+  if (simarch->inferior_init)
+    simarch->inferior_init (sd, abfd, (void *)argv, (void *)envp);
+
+  return SIM_RC_OK;
+}
+
+#endif
diff --git a/sim/common/sim-model.c b/sim/common/sim-model.c
index 80c2d6c..84e140a 100644
--- a/sim/common/sim-model.c
+++ b/sim/common/sim-model.c
@@ -25,79 +25,39 @@  along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 #include "sim-assert.h"
 #include "bfd.h"
 
-static void model_set (sim_cpu *, const SIM_MODEL *);
+#define MODEL_ACTION_LIST (void *)-1
 
-static DECLARE_OPTION_HANDLER (model_option_handler);
+/* Find where the list of models are maintained.  */
 
-static MODULE_INIT_FN sim_model_init;
-
-enum {
-  OPTION_MODEL = OPTION_START,
-  OPTION_MODEL_INFO,
-};
-
-static const OPTION model_options[] = {
-  { {"model", required_argument, NULL, OPTION_MODEL},
-      '\0', "MODEL", "Specify model to simulate",
-      model_option_handler, NULL },
-
-  { {"model-info", no_argument, NULL, OPTION_MODEL_INFO},
-      '\0', NULL, "List selectable models",
-      model_option_handler, NULL },
-  { {"info-model", no_argument, NULL, OPTION_MODEL_INFO},
-      '\0', NULL, NULL,
-      model_option_handler, NULL },
-
-  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
-};
-
-static SIM_RC
-model_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
-		      char *arg, int is_command)
+static const SIM_MACH **
+sim_model_machs (SIM_DESC sd)
 {
-  switch (opt)
-    {
-    case OPTION_MODEL :
-      {
-	const SIM_MODEL *model = sim_model_lookup (arg);
-	if (! model)
-	  {
-	    sim_io_eprintf (sd, "unknown model `%s'\n", arg);
-	    return SIM_RC_FAIL;
-	  }
-	sim_model_set (sd, cpu, model);
-	break;
-      }
-
-    case OPTION_MODEL_INFO :
-      {
-	const SIM_MACH **machp;
-	const SIM_MODEL *model;
-	for (machp = & sim_machs[0]; *machp != NULL; ++machp)
-	  {
-	    sim_io_printf (sd, "Models for architecture `%s':\n",
-			   MACH_NAME (*machp));
-	    for (model = MACH_MODELS (*machp); MODEL_NAME (model) != NULL;
-		 ++model)
-	      sim_io_printf (sd, " %s", MODEL_NAME (model));
-	    sim_io_printf (sd, "\n");
-	  }
-	break;
-      }
-    }
-
-  return SIM_RC_OK;
+#if WITH_SIMARCH
+  return STATE_SIMARCH (sd)->machs;
+#else
+# if !WITH_MODEL_P
+  /* Set up basic model support.  This is a stub for ports that do not define
+     models.  See sim-model.h for more details.  */
+  static const SIM_MACH *sim_machs[] = { NULL };
+# endif
+  return &sim_machs[0];
+#endif
 }
 
-SIM_RC
-sim_model_install (SIM_DESC sd)
+static void
+model_list (SIM_DESC sd)
 {
-  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
-
-  sim_add_option_table (sd, NULL, model_options);
-  sim_module_add_init_fn (sd, sim_model_init);
+  const SIM_MACH **machp;
+  const SIM_MODEL *model;
 
-  return SIM_RC_OK;
+  for (machp = sim_model_machs (sd); *machp != NULL; ++machp)
+    {
+      sim_io_printf (sd, "Models for architecture `%s':\n",
+		     MACH_NAME (*machp));
+      for (model = MACH_MODELS (*machp); MODEL_NAME (model) != NULL; ++model)
+	sim_io_printf (sd, " %s", MODEL_NAME (model));
+      sim_io_printf (sd, "\n");
+    }
 }
 
 /* Subroutine of sim_model_set to set the model for one cpu.  */
@@ -135,12 +95,12 @@  sim_model_set (SIM_DESC sd, sim_cpu *cpu, const SIM_MODEL *model)
    Result is pointer to MODEL entry or NULL if not found.  */
 
 const SIM_MODEL *
-sim_model_lookup (const char *name)
+sim_model_lookup (SIM_DESC sd, const char *name)
 {
   const SIM_MACH **machp;
   const SIM_MODEL *model;
 
-  for (machp = & sim_machs[0]; *machp != NULL; ++machp)
+  for (machp = sim_model_machs (sd); *machp != NULL; ++machp)
     {
       for (model = MACH_MODELS (*machp); MODEL_NAME (model) != NULL; ++model)
 	{
@@ -151,15 +111,30 @@  sim_model_lookup (const char *name)
   return NULL;
 }
 
+static SIM_RC
+model_set_name (SIM_DESC sd, sim_cpu *cpu, const char *name)
+{
+  const SIM_MODEL *model = sim_model_lookup (sd, name);
+
+  if (model == NULL)
+    {
+      sim_io_eprintf (sd, "unknown model `%s'\n", name);
+      return SIM_RC_FAIL;
+    }
+
+  sim_model_set (sd, cpu, model);
+  return SIM_RC_OK;
+}
+
 /* Look up machine named NAME.
    Result is pointer to MACH entry or NULL if not found.  */
 
 const SIM_MACH *
-sim_mach_lookup (const char *name)
+sim_mach_lookup (SIM_DESC sd, const char *name)
 {
   const SIM_MACH **machp;
 
-  for (machp = & sim_machs[0]; *machp != NULL; ++machp)
+  for (machp = sim_model_machs (sd); *machp != NULL; ++machp)
     {
       if (strcmp (MACH_NAME (*machp), name) == 0)
 	return *machp;
@@ -171,11 +146,11 @@  sim_mach_lookup (const char *name)
    Result is pointer to MACH entry or NULL if not found.  */
 
 const SIM_MACH *
-sim_mach_lookup_bfd_name (const char *name)
+sim_mach_lookup_bfd_name (SIM_DESC sd, const char *name)
 {
   const SIM_MACH **machp;
 
-  for (machp = & sim_machs[0]; *machp != NULL; ++machp)
+  for (machp = sim_model_machs (sd); *machp != NULL; ++machp)
     {
       if (strcmp (MACH_BFD_NAME (*machp), name) == 0)
 	return *machp;
@@ -202,11 +177,26 @@  sim_model_init (SIM_DESC sd)
   /* ??? At present this only supports homogeneous multiprocessors.  */
   cpu = STATE_CPU (sd, 0);
 
+  /* Process any actions requested by the command line.  */
+  if (CPU_MODEL_DATA (cpu) == MODEL_ACTION_LIST)
+    model_list (sd);
+  else if (CPU_MODEL_DATA (cpu) != NULL)
+    {
+      const char *model_name = CPU_MODEL_DATA (cpu);
+
+      if (model_set_name (sd, cpu, model_name) != SIM_RC_OK)
+	return SIM_RC_FAIL;
+    }
+  CPU_MODEL_DATA (cpu) = NULL;
+
   if (! STATE_ARCHITECTURE (sd)
       && ! CPU_MACH (cpu))
     {
+#if WITH_SIMARCH
+# define WITH_DEFAULT_MODEL STATE_SIMARCH (sd)->default_model
+#endif
       /* Set the default model.  */
-      const SIM_MODEL *model = sim_model_lookup (WITH_DEFAULT_MODEL);
+      const SIM_MODEL *model = sim_model_lookup (sd, WITH_DEFAULT_MODEL);
       SIM_ASSERT (model != NULL);
       sim_model_set (sd, NULL, model);
     }
@@ -227,7 +217,7 @@  sim_model_init (SIM_DESC sd)
     {
       /* Use the default model for the selected machine.
 	 The default model is the first one in the list.  */
-      const SIM_MACH *mach = sim_mach_lookup_bfd_name (STATE_ARCHITECTURE (sd)->printable_name);
+      const SIM_MACH *mach = sim_mach_lookup_bfd_name (sd, STATE_ARCHITECTURE (sd)->printable_name);
 
       if (mach == NULL)
 	{
@@ -245,11 +235,77 @@  sim_model_init (SIM_DESC sd)
   return SIM_RC_OK;
 }
 
-#if !WITH_MODEL_P
-/* Set up basic model support.  This is a stub for ports that do not define
-   models.  See sim-model.h for more details.  */
-const SIM_MACH *sim_machs[] =
+/* We need to delay actions from option parsing to the init phase.
+   This way we can load the simarch properly which provides models.  */
+static void
+model_queue_action (SIM_DESC sd, sim_cpu *cpu, void *act)
 {
-  NULL
+  if (cpu == NULL)
+    {
+      size_t c;
+
+      for (c = 0; c < MAX_NR_PROCESSORS; ++c)
+	{
+	  cpu = STATE_CPU (sd, c);
+	  if (cpu)
+	    CPU_MODEL_DATA (cpu) = act;
+	}
+    }
+  else
+    CPU_MODEL_DATA (cpu) = act;
+}
+
+enum {
+  OPTION_MODEL = OPTION_START,
+  OPTION_MODEL_INFO,
 };
-#endif
+
+static SIM_RC
+model_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt,
+		      char *arg, int is_command)
+{
+  switch (opt)
+    {
+    case OPTION_MODEL :
+      if (STATE_SIMARCH (sd))
+	return model_set_name (sd, cpu, arg);
+      else
+	model_queue_action (sd, cpu, arg);
+      break;
+
+    case OPTION_MODEL_INFO :
+      if (STATE_SIMARCH (sd))
+	model_list (sd);
+      else
+	model_queue_action (sd, cpu, MODEL_ACTION_LIST);
+      break;
+    }
+
+  return SIM_RC_OK;
+}
+
+static const OPTION model_options[] = {
+  { {"model", required_argument, NULL, OPTION_MODEL},
+      '\0', "MODEL", "Specify model to simulate",
+      model_option_handler, NULL },
+
+  { {"model-info", no_argument, NULL, OPTION_MODEL_INFO},
+      '\0', NULL, "List selectable models",
+      model_option_handler, NULL },
+  { {"info-model", no_argument, NULL, OPTION_MODEL_INFO},
+      '\0', NULL, NULL,
+      model_option_handler, NULL },
+
+  { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL, NULL }
+};
+
+SIM_RC
+sim_model_install (SIM_DESC sd)
+{
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  sim_add_option_table (sd, NULL, model_options);
+  sim_module_add_init_fn (sd, sim_model_init);
+
+  return SIM_RC_OK;
+}
diff --git a/sim/common/sim-model.h b/sim/common/sim-model.h
index 534e720..939f83f 100644
--- a/sim/common/sim-model.h
+++ b/sim/common/sim-model.h
@@ -47,9 +47,8 @@  typedef struct {
 #define MAX_UNITS 1
 #endif
 
-#ifndef WITH_DEFAULT_MODEL
+#if !defined(WITH_DEFAULT_MODEL) && !WITH_SIMARCH
 /* Just a stub for ports that do not define models.  */
-enum mach_attr { _MACH_NONE };
 # define WITH_DEFAULT_MODEL NULL
 # define WITH_MODEL_P 0
 #else
@@ -86,13 +85,13 @@  typedef struct {
 
 /* A machine variant.  */
 
-typedef struct {
+typedef struct sim_mach {
   const char *name;
 #define MACH_NAME(m) ((m)->name)
   /* This is the argument to bfd_scan_arch.  */
   const char *bfd_name;
 #define MACH_BFD_NAME(m) ((m)->bfd_name)
-  enum mach_attr num;
+  int num;
 #define MACH_NUM(m) ((m)->num)
 
   int word_bitsize;
@@ -147,8 +146,8 @@  extern MODULE_INSTALL_FN sim_model_install;
 
 /* Support routines.  */
 extern void sim_model_set (SIM_DESC sd_, sim_cpu *cpu_, const SIM_MODEL *model_);
-extern const SIM_MODEL *sim_model_lookup (const char *name_);
-extern const SIM_MACH *sim_mach_lookup (const char *name_);
-extern const SIM_MACH *sim_mach_lookup_bfd_name (const char *bfd_name_);
+extern const SIM_MODEL *sim_model_lookup (SIM_DESC, const char *name_);
+extern const SIM_MACH *sim_mach_lookup (SIM_DESC, const char *name_);
+extern const SIM_MACH *sim_mach_lookup_bfd_name (SIM_DESC, const char *bfd_name_);
 
 #endif /* SIM_MODEL_H */
diff --git a/sim/common/sim-open.c b/sim/common/sim-open.c
new file mode 100644
index 0000000..73d2401
--- /dev/null
+++ b/sim/common/sim-open.c
@@ -0,0 +1,95 @@ 
+/* Create a fully initialized simulator instance.
+
+   Copyright (C) 2005-2016 Free Software Foundation, Inc.
+   Contributed by Analog Devices, Inc.
+
+   This file is part of simulators.
+
+   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 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "sim-main.h"
+#include "gdb/remote-sim.h"
+
+#if WITH_SIMARCH
+
+#ifndef CGEN_ARCH
+# define cgen_cpu_max_extra_bytes() 0
+# define cgen_init(sd)
+#endif
+
+SIM_DESC
+sim_open (SIM_OPEN_KIND kind, host_callback *cb, struct bfd *abfd, char **argv)
+{
+  SIM_DESC sd = sim_state_alloc (kind, cb);
+  const simarch *simarch;
+  SIM_ASSERT (STATE_MAGIC (sd) == SIM_MAGIC_NUMBER);
+
+  /* The cpu data is kept in a separately allocated chunk of memory.  */
+  if (sim_cpu_alloc_all (sd, MAX_NR_PROCESSORS, cgen_cpu_max_extra_bytes ())
+      != SIM_RC_OK)
+    goto error_cpu_alloc;
+
+  if (sim_pre_argv_init (sd, argv[0]) != SIM_RC_OK)
+    goto error_argv_init;
+
+  /* The parser will print an error message for us, so we silently return.  */
+  if (sim_parse_args (sd, argv) != SIM_RC_OK)
+    goto error;
+
+  /* Check for/establish the reference program image.  */
+  if (sim_analyze_program (sd, (STATE_PROG_ARGV (sd) != NULL
+				? *STATE_PROG_ARGV (sd) : NULL),
+			   abfd) != SIM_RC_OK)
+    goto error;
+
+  /* With an appropriate prog bfd loaded, try to detect the right sim.  */
+  if (sim_simarch_lookup (sd) != SIM_RC_OK)
+    goto error;
+  simarch = STATE_SIMARCH (sd);
+
+  /* Establish any remaining configuration options.  */
+  if (sim_config (sd) != SIM_RC_OK)
+    goto error;
+
+  if (sim_post_argv_init (sd) != SIM_RC_OK)
+    goto error;
+
+  /* Port specific state finalization.  */
+  if (simarch->state_init)
+    simarch->state_init (sd);
+
+  /* Initialize various cgen things not done by common framework.  */
+  cgen_init (sd);
+
+  /* CPU specific initialization.  */
+  if (simarch->cpu_init)
+    {
+      size_t i;
+
+      for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+	simarch->cpu_init (STATE_CPU (sd, i));
+    }
+
+  return sd;
+
+ error:
+  sim_module_uninstall (sd);
+ error_argv_init:
+  sim_cpu_free_all (sd);
+ error_cpu_alloc:
+  sim_state_free (sd);
+  return NULL;
+}
+
+#endif
diff --git a/sim/common/sim-resume.c b/sim/common/sim-resume.c
index e9ec9c9..40ccb4d 100644
--- a/sim/common/sim-resume.c
+++ b/sim/common/sim-resume.c
@@ -86,7 +86,10 @@  sim_resume (SIM_DESC sd,
       }
 #endif
 
-      sim_engine_run (sd, next_cpu_nr, nr_cpus, sig_to_deliver);
+      if (WITH_SIMARCH)
+	STATE_SIMARCH (sd)->engine_run (sd, next_cpu_nr, nr_cpus, sig_to_deliver);
+      else
+	sim_engine_run (sd, next_cpu_nr, nr_cpus, sig_to_deliver);
     }
   engine->jmpbuf = NULL;
 
diff --git a/sim/common/sim-simarch.c b/sim/common/sim-simarch.c
new file mode 100644
index 0000000..d51a583
--- /dev/null
+++ b/sim/common/sim-simarch.c
@@ -0,0 +1,120 @@ 
+/* Simulator arch ops for support multiple targets in a single build.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Mike Frysinger.
+
+   This file is part of simulators.
+
+   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 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, see <http://www.gnu.org/licenses/>.  */
+
+#include "sim-main.h"
+
+/* Keep a registry of the architectures known by the sim.  */
+
+struct simarch_registration
+{
+  const struct bfd_arch_info *bfd_arch_info;
+  const struct simarch *simarch;
+};
+
+static size_t registered_count;
+static struct simarch_registration **simarch_registery;
+
+SIM_RC
+sim_simarch_register (enum bfd_architecture bfd_architecture,
+		      const struct simarch *simarch)
+{
+  size_t i;
+  struct simarch_registration *reg;
+  const struct bfd_arch_info *bfd_arch_info;
+
+  bfd_arch_info = bfd_lookup_arch (bfd_architecture, 0);
+  if (bfd_arch_info == NULL)
+    return SIM_RC_FAIL;
+
+  i = registered_count++;
+  simarch_registery = XRESIZEVEC (struct simarch_registration *,
+				  simarch_registery, registered_count);
+  reg = simarch_registery[i] = xmalloc (sizeof (*reg));
+  reg->bfd_arch_info = bfd_arch_info;
+  reg->simarch = simarch;
+
+
+  return SIM_RC_OK;
+}
+
+static const struct simarch *
+simarch_lookup (const struct bfd_arch_info *architecture)
+{
+  struct simarch_registration *reg;
+  size_t i;
+
+  for (i = 0; i < registered_count; ++i)
+    {
+      reg = simarch_registery[i];
+      if (architecture == reg->bfd_arch_info)
+	return reg->simarch;
+    }
+
+  return NULL;
+}
+
+SIM_RC
+sim_simarch_lookup (SIM_DESC sd)
+{
+  const struct simarch *simarch = NULL;
+  const struct bfd_arch_info *architecture;
+  struct bfd *abfd;
+  const char **list, **lp;
+
+extern SIM_SIMARCH_REGISTER_FN sim_simarch_register_bfin;
+sim_simarch_register_bfin ();
+
+  /* The prog bfd has been set, use it.  */
+  abfd = STATE_PROG_BFD (sd);
+  if (abfd != NULL)
+    {
+      simarch = simarch_lookup (bfd_get_arch_info (abfd));
+      goto done;
+    }
+
+  /* If the state arch has been set, use it.  */
+  architecture = STATE_ARCHITECTURE (sd);
+  if (architecture != NULL)
+    {
+      simarch = simarch_lookup (STATE_ARCHITECTURE (sd));
+      goto done;
+    }
+
+  /* Scan all available bfds and blindly use the first one that matches.  */
+  list = bfd_arch_list ();
+  if (list != NULL)
+    {
+      for (lp = list; *lp != NULL; lp++)
+	{
+	  architecture = bfd_scan_arch (*lp);
+	  if (architecture == NULL)
+	    continue;
+
+	  simarch = simarch_lookup (architecture);
+	  if (simarch)
+	    break;
+	}
+      free (list);
+    }
+
+ done:
+  STATE_SIMARCH (sd) = simarch;
+  return simarch ? SIM_RC_OK : SIM_RC_FAIL;
+}
diff --git a/sim/common/sim-simarch.h b/sim/common/sim-simarch.h
new file mode 100644
index 0000000..d0de77e
--- /dev/null
+++ b/sim/common/sim-simarch.h
@@ -0,0 +1,58 @@ 
+/* Simulator arch ops for support multiple targets in a single build.
+
+   Copyright (C) 2016 Free Software Foundation, Inc.
+   Contributed by Mike Frysinger.
+
+   This file is part of simulators.
+
+   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 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, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef SIM_SIMARCH_H
+#define SIM_SIMARCH_H
+
+/* Not all targets have been converted yet.  */
+#ifndef WITH_SIMARCH
+#define WITH_SIMARCH 0
+#endif
+
+typedef SIM_RC (SIM_SIMARCH_REGISTER_FN) (void);
+
+struct sim_mach;
+
+typedef struct simarch
+{
+  /* Runtime callbacks.  */
+  void (*engine_run) (SIM_DESC, int, int, int);
+
+  /* Init callbacks.  */
+  void (*state_init) (SIM_DESC);
+  void (*cpu_init) (SIM_CPU *);
+  void (*inferior_init) (SIM_DESC, struct bfd *,
+			 const char * const *argv, const char * const *envp);
+
+  /* Arch settings.  */
+  enum sim_environment default_environment;
+  enum bfd_endian default_endian;
+  enum sim_alignments default_alignment;
+
+  const char *default_model;
+  const struct sim_mach **machs;
+} simarch;
+
+SIM_RC sim_simarch_register (enum bfd_architecture bfd_architecture,
+			     const simarch *simarch);
+
+SIM_RC sim_simarch_lookup (SIM_DESC);
+
+#endif /* SIM_SIMARCH_H */