* Makefile.in (SIM_OBJS): Add sim-load.o.
authorDavid Edelsohn <dje.gcc@gmail.com>
Thu, 17 Apr 1997 10:54:07 +0000 (10:54 +0000)
committerDavid Edelsohn <dje.gcc@gmail.com>
Thu, 17 Apr 1997 10:54:07 +0000 (10:54 +0000)
* interp.c (sim_kind, myname): New static locals.
(sim_open): Set sim_kind, myname.  Ignore -E arg.
(sim_load): Return SIM_RC.  New arg abfd.  Call sim_load_file to
load file into simulator.  Set start address from bfd.
(sim_create_inferior): Return SIM_RC.  Delete arg start_address.

sim/v850/ChangeLog
sim/v850/interp.c

index 79e55930b8a0b7bd52b36c8db425f2f0fdaa79c8..72d507d49e09e0471621da96935d7717aa3d2c4f 100644 (file)
@@ -1,3 +1,12 @@
+Thu Apr 17 03:53:18 1997  Doug Evans  <dje@canuck.cygnus.com>
+
+       * Makefile.in (SIM_OBJS): Add sim-load.o.
+       * interp.c (sim_kind, myname): New static locals.
+       (sim_open): Set sim_kind, myname.  Ignore -E arg.
+       (sim_load): Return SIM_RC.  New arg abfd.  Call sim_load_file to
+       load file into simulator.  Set start address from bfd.
+       (sim_create_inferior): Return SIM_RC.  Delete arg start_address.
+
 Wed Apr 16 19:53:55 1997  Andrew Cagney  <cagney@b1.cygnus.com>
 
        * simops.c (OP_10007E0): Only provide system calls SYS_execv,
index 77b7c6658c1a2451656692478a0549824d3e933c..d1aa8ebdd3b6acda18f9c9b959d1d0d69ddfcd46 100644 (file)
@@ -1,11 +1,61 @@
 #include <signal.h>
 #include "sysdep.h"
 #include "bfd.h"
-#include "remote-sim.h"
-#include "callback.h"
 
 #include "v850_sim.h"
 
+enum interrupt_type
+{
+  int_none,
+  int_reset,
+  int_nmi,
+  int_intov1,
+  int_intp10,
+  int_intp11,
+  int_intp12,
+  int_intp13,
+  int_intcm4,
+  num_int_types
+};
+
+enum interrupt_cond_type
+{
+  int_cond_none,
+  int_cond_pc,
+  int_cond_time
+};
+
+struct interrupt_generator
+{
+  enum interrupt_type type;
+  enum interrupt_cond_type cond_type;
+  int number;
+  int address;
+  int time;
+  int enabled;
+  struct interrupt_generator *next;
+};
+
+char *interrupt_names[] = {
+  "",
+  "reset",
+  "nmi",
+  "intov1",
+  "intp10",
+  "intp11",
+  "intp12",
+  "intp13",
+  "intcm4",
+  NULL
+};
+
+struct interrupt_generator *intgen_list;
+
+/* True if a non-maskable (such as NMI or reset) interrupt generator
+   is present.  */
+
+static int have_nm_generator;
+
 #ifndef INLINE
 #ifdef __GNUC__
 #define INLINE inline
 #endif
 #endif
 
-#define MEM_SIZE 18    /* V850 memory size is 18 bits XXX */
+/* These default values correspond to expected usage for the chip.  */
+
+SIM_ADDR rom_size = 0x8000;
+SIM_ADDR low_end = 0x200000;
+SIM_ADDR high_start = 0xffe000;
+
+SIM_ADDR high_base;
 
 host_callback *v850_callback;
+
 int v850_debug;
 
+static SIM_OPEN_KIND sim_kind;
+static char *myname;
 
 uint32 OP[4];
 
@@ -35,6 +94,7 @@ static void do_format_9_10 PARAMS ((uint32));
 static void init_system PARAMS ((void));
 
 #define MAX_HASH  63
+
 struct hash_entry
 {
   struct hash_entry *next;
@@ -55,12 +115,15 @@ hash(insn)
       || (insn & 0x0700) == 0x0600
       || (insn & 0x0780) == 0x0700)
     return (insn & 0x07e0) >> 5;
+
   if ((insn & 0x0700) == 0x0300
       || (insn & 0x0700) == 0x0400
       || (insn & 0x0700) == 0x0500)
     return (insn & 0x0780) >> 7;
+
   if ((insn & 0x07c0) == 0x0780)
     return (insn & 0x07c0) >> 6;
+
   return (insn & 0x07e0) >> 5;
 }
 
@@ -76,7 +139,7 @@ lookup_hash (ins)
     {
       if (h->next == NULL)
        {
-         (*v850_callback->printf_filtered) (v850_callback, "ERROR looking up hash for %x\n", ins);
+         (*v850_callback->printf_filtered) (v850_callback, "ERROR looking up hash for 0x%x, PC=0x%x\n", ins, PC);
          exit(1);
        }
       h = h->next;
@@ -84,6 +147,9 @@ lookup_hash (ins)
   return (h);
 }
 
+/* FIXME These would more efficient to use than load_mem/store_mem,
+   but need to be changed to use the memory map.  */
+
 uint8
 get_byte (x)
      uint8 *x;
@@ -138,6 +204,92 @@ put_word (addr, data)
   a[3] = (data >> 24) & 0xff;
 }
 
+uint8 *
+map (addr)
+     SIM_ADDR addr;
+{
+  uint8 *p;
+
+  /* Mask down to 24 bits. */
+  addr &= 0xffffff;
+
+  if (addr < low_end)
+    {
+      /* "Mirror" the addresses below 1MB. */
+      if (addr < 0x100000)
+       addr &= (rom_size - 1);
+      else
+       addr += (rom_size - 0x100000);
+      return (uint8 *) (addr + State.mem);
+    }
+  else if (addr >= high_start)
+    {
+      /* If in the peripheral I/O region, mirror 1K region across 4K,
+        and similarly if in the internal RAM region.  */
+      if (addr >= 0xfff000)
+       addr &= 0xfff3ff;
+      else if (addr >= 0xffe000)
+       addr &= 0xffe3ff;
+      return (uint8 *) (addr - high_start + high_base + State.mem);
+    }
+  else
+    {
+      /* Signal a memory error. */
+      State.exception = SIGSEGV;
+      /* Point to a location not in main memory - renders invalid
+        addresses harmless until we get back to main insn loop. */
+      return (uint8 *) &(State.dummy_mem);
+    }
+}
+
+uint32
+load_mem (addr, len)
+     SIM_ADDR addr;
+     int len;
+{
+  uint8 *p = map (addr);
+
+  switch (len)
+    {
+    case 1:
+      return p[0];
+    case 2:
+      return p[1] << 8 | p[0];
+    case 4:
+      return p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
+    default:
+      abort ();
+    }
+}
+
+void
+store_mem (addr, len, data)
+     SIM_ADDR addr;
+     int len;
+     uint32 data;
+{
+  uint8 *p = map (addr);
+
+  switch (len)
+    {
+    case 1:
+      p[0] = data;
+      return;
+    case 2:
+      p[0] = data;
+      p[1] = data >> 8;
+      return;
+    case 4:
+      p[0] = data;
+      p[1] = data >> 8;
+      p[2] = data >> 16;
+      p[3] = data >> 24;
+      return;
+    default:
+      abort ();
+    }
+}
+
 static void
 do_format_1_2 (insn)
      uint32 insn;
@@ -241,19 +393,82 @@ sim_size (power)
      int power;
 
 {
+  int totsize;
+
   if (State.mem)
+    free (State.mem);
+
+  totsize = rom_size + (low_end - 0x100000) + (0x1000000 - high_start);
+
+  high_base = rom_size + (low_end - 0x100000);
+
+  State.mem = (uint8 *) calloc (1, totsize);
+  if (!State.mem)
     {
-      free (State.mem);
+      (*v850_callback->printf_filtered) (v850_callback, "Allocation of main memory failed.\n");
+      exit (1);
     }
+}
 
-  State.mem = (uint8 *)calloc(1,1<<MEM_SIZE);
-  if (!State.mem)
+void
+sim_set_memory_map (spec)
+     char *spec;
+{
+  char *reststr, *nreststr;
+  SIM_ADDR new_low_end, new_high_start;
+
+  new_low_end = low_end;
+  new_high_start = high_start;
+  if (! strncmp (spec, "hole=", 5))
     {
-      (*v850_callback->printf_filtered) (v850_callback, "Memory allocation failed.\n");
-      exit(1);
+      new_low_end = sim_parse_number (spec + 5, &reststr);
+      if (new_low_end < 0x100000)
+       {
+         (*v850_callback->printf_filtered) (v850_callback,
+                                            "Low end must be at least 0x100000\n");
+         return;
+       }
+      if (*reststr == ',')
+       {
+         ++reststr;
+         new_high_start = sim_parse_number (reststr, &nreststr);
+         /* FIXME Check high_start also */
+       }
+      (*v850_callback->printf_filtered) (v850_callback,
+                                        "Hole goes from 0x%x to 0x%x\n",
+                                        new_low_end, new_high_start);
+    }
+  else
+    {
+      (*v850_callback->printf_filtered) (v850_callback, "Invalid specification for memory map, must be `hole=<m>[,<n>]'\n");
+    }
+
+  if (new_low_end != low_end || new_high_start != high_start)
+    {
+      low_end = new_low_end;
+      high_start = new_high_start;
+      if (State.mem)
+       {
+         (*v850_callback->printf_filtered) (v850_callback, "Reconfiguring memory (old contents will be lost)\n");
+         sim_size (1);
+       }
     }
 }
 
+/* Parse a number in hex, octal, or decimal form.  */
+
+int
+sim_parse_number (str, rest)
+     char *str, **rest;
+{
+  if (str[0] == '0' && str[1] == 'x')
+    return strtol (str, rest, 16);
+  else if (str[0] == '0')
+    return strtol (str, rest, 16);
+  else
+    return strtol (str, rest, 10);
+}
+
 static void
 init_system ()
 {
@@ -262,35 +477,45 @@ init_system ()
 }
 
 int
-sim_write (addr, buffer, size)
+sim_write (sd, addr, buffer, size)
+     SIM_DESC sd;
      SIM_ADDR addr;
      unsigned char *buffer;
      int size;
 {
   int i;
+
   init_system ();
 
   for (i = 0; i < size; i++)
-    {
-      State.mem[i+addr] = buffer[i]; 
-    }
+    store_mem (addr + i, 1, buffer[i]);
+
   return size;
 }
 
-void
-sim_open (args)
-     char *args;
+SIM_DESC
+sim_open (kind,argv)
+     SIM_OPEN_KIND kind;
+     char **argv;
 {
   struct simops *s;
   struct hash_entry *h;
-  if (args != NULL)
+  char **p;
+
+  sim_kind = kind;
+  myname = argv[0];
+
+  for (p = argv + 1; *p; ++p)
     {
+      if (strcmp (*p, "-E") == 0)
+       ++p; /* ignore endian spec */
+      else
 #ifdef DEBUG
-      if (strcmp (args, "-t") == 0)
+      if (strcmp (*p, "-t") == 0)
        v850_debug = DEBUG;
       else
 #endif
-       (*v850_callback->printf_filtered) (v850_callback, "ERROR: unsupported option(s): %s\n",args);
+       (*v850_callback->printf_filtered) (v850_callback, "ERROR: unsupported option(s): %s\n",*p);
     }
 
   /* put all the opcodes in the hash table */
@@ -304,18 +529,22 @@ sim_open (args)
 
       if (h->ops)
        {
-         h->next = calloc(1,sizeof(struct hash_entry));
+         h->next = (struct hash_entry *) calloc(1,sizeof(struct hash_entry));
          h = h->next;
        }
       h->ops = s;
       h->mask = s->mask;
       h->opcode = s->opcode;
     }
+
+  /* fudge our descriptor for now */
+  return (SIM_DESC) 1;
 }
 
 
 void
-sim_close (quitting)
+sim_close (sd, quitting)
+     SIM_DESC sd;
      int quitting;
 {
   /* nothing to do */
@@ -335,111 +564,229 @@ sim_set_profile_size (n)
   (*v850_callback->printf_filtered) (v850_callback, "sim_set_profile_size %d\n", n);
 }
 
+time_t start_time;
+
+static void do_interrupt PARAMS ((enum interrupt_type));
+
 void
-sim_resume (step, siggnal)
+sim_resume (sd, step, siggnal)
+     SIM_DESC sd;
      int step, siggnal;
 {
   uint32 inst, opcode;
   reg_t oldpc;
+  struct interrupt_generator *intgen;
+  time_t now;
 
-  PC = State.sregs[0];
+  if (step)
+    State.exception = SIGTRAP;
+  else
+    State.exception = 0;
 
- if (step)
-   State.exception = SIGTRAP;
- else
-   State.exception = 0;
- do
-   {
-     inst = RLW (PC);
-     oldpc = PC;
-     opcode = (inst & 0x07e0) >> 5;
-     if ((opcode & 0x30) == 0
-        || (opcode & 0x38) == 0x10)
-       {
-        do_format_1_2 (inst & 0xffff);
-        PC += 2;
-       }
-     else if ((opcode & 0x3C) == 0x18
-             || (opcode & 0x3C) == 0x1C
-             || (opcode & 0x3C) == 0x20
-             || (opcode & 0x3C) == 0x24
-             || (opcode & 0x3C) == 0x28)
-       {
-        do_format_4 (inst & 0xffff);
-        PC += 2;
-       }
-     else if ((opcode & 0x3C) == 0x2C)
-       {
-        do_format_3 (inst & 0xffff);
-        /* No PC update, it's done in the instruction.  */
-       }
-     else if ((opcode & 0x38) == 0x30)
-       {
-        do_format_6 (inst);
-        PC += 4;
-       }
-     else if ((opcode & 0x3C) == 0x38)
-       {
-        do_format_7 (inst);
-        PC += 4;
-       }
-     else if ((opcode & 0x3E) == 0x3C)
-       {
-        do_format_5 (inst);
-        /* No PC update, it's done in the instruction.  */
-       }
-     else if ((opcode & 0x3F) == 0x3E)
-       {
-        do_format_8 (inst);
-        PC += 4;
-       }
-     else
-       {
-        do_format_9_10 (inst);
-        PC += 4;
-       }
-   } 
- while (!State.exception);
-
-  State.sregs[0] = PC;
+  time (&start_time);
+
+  do
+    {
+      /* Fetch the current instruction.  */
+      inst = RLW (PC);
+      oldpc = PC;
+      opcode = (inst & 0x07e0) >> 5;
+
+      /* Decode the opcode field. */
+      if ((opcode & 0x30) == 0
+         || (opcode & 0x38) == 0x10)
+       {
+         do_format_1_2 (inst & 0xffff);
+         PC += 2;
+       }
+      else if ((opcode & 0x3C) == 0x18
+              || (opcode & 0x3C) == 0x1C
+              || (opcode & 0x3C) == 0x20
+              || (opcode & 0x3C) == 0x24
+              || (opcode & 0x3C) == 0x28)
+       {
+         do_format_4 (inst & 0xffff);
+         PC += 2;
+       }
+      else if ((opcode & 0x3C) == 0x2C)
+       {
+         do_format_3 (inst & 0xffff);
+         /* No PC update, it's done in the instruction.  */
+       }
+      else if ((opcode & 0x38) == 0x30)
+       {
+         do_format_6 (inst);
+         PC += 4;
+       }
+      else if ((opcode & 0x3C) == 0x38)
+       {
+         do_format_7 (inst);
+         PC += 4;
+       }
+      else if ((opcode & 0x3E) == 0x3C)
+       {
+         do_format_5 (inst);
+         /* No PC update, it's done in the instruction.  */
+       }
+      else if ((opcode & 0x3F) == 0x3E)
+       {
+         do_format_8 (inst);
+         PC += 4;
+       }
+      else
+       {
+         do_format_9_10 (inst);
+         PC += 4;
+       }
+
+      /* Check for and handle pending interrupts.  */
+      if (intgen_list && (have_nm_generator || !(PSW & PSW_ID)))
+       {
+         intgen = NULL;
+         for (intgen = intgen_list; intgen != NULL; intgen = intgen->next)
+           {
+             if (intgen->cond_type == int_cond_pc
+                 && oldpc == intgen->address
+                 && intgen->enabled)
+               {
+                 break;
+               }
+             else if (intgen->cond_type == int_cond_time
+                      && intgen->enabled)
+               {
+                 time (&now);
+                 if (((long) now - (long) start_time) > intgen->time)
+                   {
+                     intgen->enabled = 0;
+                     break;
+                   }
+               }
+           }
+         if (intgen)
+           do_interrupt (intgen->type);
+       }
+      else if (State.pending_nmi)
+       {
+         State.pending_nmi = 0;
+         do_interrupt (int_nmi);
+       }
+    }
+  while (!State.exception);
+}
+
+static void
+do_interrupt (inttype)
+     enum interrupt_type inttype;
+{
+  /* Disable further interrupts.  */
+  PSW |= PSW_ID;
+  /* Indicate that we're doing interrupt not exception processing.  */
+  PSW &= ~PSW_EP;
+  if (inttype == int_reset)
+    {
+      PC = 0;
+      PSW = 0x20;
+      ECR = 0;
+      /* (Might be useful to init other regs with random values.) */
+    }
+  else if (inttype == int_nmi)
+    {
+      if (PSW & PSW_NP)
+       {
+         /* We're already working on an NMI, so this one must wait
+            around until the previous one is done.  The processor
+            ignores subsequent NMIs, so we don't need to count them.  */
+         State.pending_nmi = 1;
+       }
+      else
+       {
+         FEPC = PC;
+         FEPSW = PSW;
+         /* Set the FECC part of the ECR. */
+         ECR &= 0x0000ffff;
+         ECR |= 0x10;
+         PSW |= PSW_NP;
+         PC = 0x10;
+       }
+    }
+  else
+    {
+      EIPC = PC;
+      EIPSW = PSW;
+      /* Clear the EICC part of the ECR, will set below. */
+      ECR &= 0xffff0000;
+      switch (inttype)
+       {
+       case int_intov1:
+         PC = 0x80;
+         ECR |= 0x80;
+         break;
+       case int_intp10:
+         PC = 0x90;
+         ECR |= 0x90;
+         break;
+       case int_intp11:
+         PC = 0xa0;
+         ECR |= 0xa0;
+         break;
+       case int_intp12:
+         PC = 0xb0;
+         ECR |= 0xb0;
+         break;
+       case int_intp13:
+         PC = 0xc0;
+         ECR |= 0xc0;
+         break;
+       case int_intcm4:
+         PC = 0xd0;
+         ECR |= 0xd0;
+         break;
+       default:
+         /* Should never be possible.  */
+         abort ();
+         break;
+       }
+    }
 }
 
 int
-sim_trace ()
+sim_trace (sd)
+     SIM_DESC sd;
 {
 #ifdef DEBUG
   v850_debug = DEBUG;
 #endif
-  sim_resume (0, 0);
+  sim_resume (sd, 0, 0);
   return 1;
 }
 
 void
-sim_info (verbose)
+sim_info (sd, verbose)
+     SIM_DESC sd;
      int verbose;
 {
   (*v850_callback->printf_filtered) (v850_callback, "sim_info\n");
 }
 
-void
-sim_create_inferior (start_address, argv, env)
-     SIM_ADDR start_address;
+SIM_RC
+sim_create_inferior (sd, argv, env)
+     SIM_DESC sd;
      char **argv;
      char **env;
 {
-  PC = start_address;
+  return SIM_RC_OK;
 }
 
-
 void
-sim_kill ()
+sim_kill (sd)
+     SIM_DESC sd;
 {
   /* nothing to do */
 }
 
 void
-sim_set_callbacks(p)
+sim_set_callbacks (sd, p)
+     SIM_DESC sd;
      host_callback *p;
 {
   v850_callback = p;
@@ -448,21 +795,28 @@ sim_set_callbacks(p)
 /* All the code for exiting, signals, etc needs to be revamped.
 
    This is enough to get c-torture limping though.  */
+
 void
-sim_stop_reason (reason, sigrc)
+sim_stop_reason (sd, reason, sigrc)
+     SIM_DESC sd;
      enum sim_stop *reason;
      int *sigrc;
 {
-
-  *reason = sim_stopped;
-  if (State.exception == SIGQUIT)
-    *sigrc = 0;
+  if (State.exception == SIG_V850_EXIT)
+    {
+      *reason = sim_exited;
+      *sigrc = State.regs[7];
+    }
   else
-    *sigrc = State.exception;
+    {
+      *reason = sim_stopped;
+      *sigrc = State.exception;
+    }
 }
 
 void
-sim_fetch_register (rn, memory)
+sim_fetch_register (sd, rn, memory)
+     SIM_DESC sd;
      int rn;
      unsigned char *memory;
 {
@@ -470,7 +824,8 @@ sim_fetch_register (rn, memory)
 }
  
 void
-sim_store_register (rn, memory)
+sim_store_register (sd, rn, memory)
+     SIM_DESC sd;
      int rn;
      unsigned char *memory;
 {
@@ -478,31 +833,205 @@ sim_store_register (rn, memory)
 }
 
 int
-sim_read (addr, buffer, size)
+sim_read (sd, addr, buffer, size)
+     SIM_DESC sd;
      SIM_ADDR addr;
      unsigned char *buffer;
      int size;
 {
   int i;
   for (i = 0; i < size; i++)
-    {
-      buffer[i] = State.mem[addr + i];
-    }
+    buffer[i] = load_mem (addr + i, 1);
+
   return size;
 } 
 
+int current_intgen_number = 1;
+
 void
-sim_do_command (cmd)
+sim_set_interrupt (spec)
+     char *spec;
+{
+  int i, num;
+  char **argv;
+  struct interrupt_generator *intgen, *tmpgen;
+  extern char **buildargv ();
+
+  argv = buildargv (spec);
+
+  if (*argv && ! strcmp (*argv, "add"))
+    {
+      /* Create a new interrupt generator object.  */
+      intgen = (struct interrupt_generator *)
+       malloc (sizeof(struct interrupt_generator));
+      intgen->type = int_none;
+      intgen->cond_type = int_cond_none;
+      intgen->address = 0;
+      intgen->time = 0;
+      intgen->enabled = 0;
+      ++argv;
+      /* Match on interrupt type name.  */
+      for (i = 0; i < num_int_types; ++i)
+       {
+         if (*argv && ! strcmp (*argv, interrupt_names[i]))
+           {
+             intgen->type = i;
+             break;
+           }
+       }
+      if (intgen->type == int_none)
+       {
+         (*v850_callback->printf_filtered) (v850_callback, "Interrupt type unknown; known types are\n");
+         for (i = 0; i < num_int_types; ++i)
+           {
+             (*v850_callback->printf_filtered) (v850_callback, " %s", interrupt_names[i]);
+           }
+         (*v850_callback->printf_filtered) (v850_callback, "\n");
+         free (intgen);
+         return;
+       }
+      ++argv;
+      intgen->address = 0;
+      intgen->time = 0;
+      if (*argv && ! strcmp (*argv, "pc"))
+       {
+         intgen->cond_type = int_cond_pc;
+         ++argv;
+         intgen->address = sim_parse_number (*argv, NULL);
+       }
+      else if (*argv && ! strcmp (*argv, "time"))
+       {
+         intgen->cond_type = int_cond_time;
+         ++argv;
+         intgen->time = sim_parse_number (*argv, NULL);
+       }
+      else
+       {
+         (*v850_callback->printf_filtered) (v850_callback, "Condition type must be `pc' or `time'.\n");
+         free (intgen);
+         return;
+       }
+      /* We now have a valid interrupt generator.  Number it and add
+        to the list of generators.  */
+      intgen->number = current_intgen_number++;
+      intgen->enabled = 1;
+      intgen->next = intgen_list;
+      intgen_list = intgen;
+      (*v850_callback->printf_filtered) (v850_callback, "Interrupt generator %d (NMI) at pc=0x%x, time=%d.\n", intgen_list->number, intgen_list->address, intgen_list->time);
+    }
+  else if (*argv && !strcmp (*argv, "remove"))
+    {
+      ++argv;
+      num = sim_parse_number (*argv, NULL);
+      tmpgen = NULL;
+      if (intgen_list)
+       {
+         if (intgen_list->number == num)
+           {
+             tmpgen = intgen_list;
+             intgen_list = intgen_list->next;
+           }
+         else
+           {
+             for (intgen = intgen_list; intgen != NULL; intgen = intgen->next)
+               {
+                 if (intgen->next != NULL && intgen->next->number == num)
+                   {
+                     tmpgen = intgen->next;
+                     intgen->next = intgen->next->next;
+                     break;
+                   }
+               }
+           }
+         if (tmpgen)
+           free (tmpgen);
+         else
+           (*v850_callback->printf_filtered) (v850_callback,
+                                              "No interrupt generator numbered %d, ignoring.\n", num);
+       }
+    }
+  else if (*argv && !strcmp (*argv, "info"))
+    {
+      if (intgen_list)
+       {
+         for (intgen = intgen_list; intgen != NULL; intgen = intgen->next)
+           (*v850_callback->printf_filtered) (v850_callback,
+                                              "Interrupt generator %d (%s) at pc=0x%x/time=%d%s.\n",
+                                              intgen->number,
+                                              interrupt_names[intgen->type],
+                                              intgen->address,
+                                              intgen->time,
+                                              (intgen->enabled ? "" : " (disabled)"));
+       }
+      else
+       {
+         (*v850_callback->printf_filtered) (v850_callback, "No interrupt generators defined.\n"); 
+       }
+
+    }
+  else
+    {
+      (*v850_callback->printf_filtered) (v850_callback,
+                                        "Invalid interrupt command, must be one of `add', `remove', or `info'.\n");
+    }
+  /* Cache the presence of a non-maskable generator.  */
+  have_nm_generator = 0;
+  for (intgen = intgen_list; intgen != NULL; intgen = intgen->next)
+    {
+      if (intgen->type == int_nmi || intgen->type == int_reset)
+       {
+         have_nm_generator = 1;
+         break;
+       }
+    }
+}
+
+void
+sim_do_command (sd, cmd)
+     SIM_DESC sd;
      char *cmd;
-{ 
-  (*v850_callback->printf_filtered) (v850_callback, "sim_do_command: %s\n", cmd);
+{
+  char *mm_cmd = "memory-map";
+  char *int_cmd = "interrupt";
+
+  if (! strncmp (cmd, mm_cmd, strlen (mm_cmd))
+      && strchr ("     ", cmd[strlen(mm_cmd)]))
+    sim_set_memory_map (cmd + strlen(mm_cmd) + 1);
+
+  else if (! strncmp (cmd, int_cmd, strlen (int_cmd))
+      && strchr ("     ", cmd[strlen(int_cmd)]))
+    sim_set_interrupt (cmd + strlen(int_cmd) + 1);
+
+  else if (! strcmp (cmd, "help"))
+    {
+      (*v850_callback->printf_filtered) (v850_callback, "V850 simulator commands:\n\n");
+      (*v850_callback->printf_filtered) (v850_callback, "interrupt add <inttype> { pc | time } <value> -- Set up an interrupt generator\n");
+      (*v850_callback->printf_filtered) (v850_callback, "interrupt remove <n> -- Remove an existing interrupt generator\n");
+      (*v850_callback->printf_filtered) (v850_callback, "interrupt info -- List all the interrupt generators\n");
+      (*v850_callback->printf_filtered) (v850_callback, "memory-map hole=<m>,<n> -- Set the memory map to have a hole between <m> and <n>\n");
+      (*v850_callback->printf_filtered) (v850_callback, "\n");
+    }
+  else
+    (*v850_callback->printf_filtered) (v850_callback, "\"%s\" is not a valid V850 simulator command.\n",
+                                      cmd);
 }
 
-int
-sim_load (prog, from_tty)
+SIM_RC
+sim_load (sd, prog, abfd, from_tty)
+     SIM_DESC sd;
      char *prog;
+     bfd *abfd;
      int from_tty;
 {
-  /* Return nonzero so GDB will handle it.  */
-  return 1;
+  extern bfd *sim_load_file (); /* ??? Don't know where this should live.  */
+  bfd *prog_bfd;
+
+  prog_bfd = sim_load_file (sd, myname, v850_callback, prog, abfd,
+                           sim_kind == SIM_OPEN_DEBUG);
+  if (prog_bfd == NULL)
+    return SIM_RC_FAIL;
+  PC = bfd_get_start_address (prog_bfd);
+  if (abfd == NULL)
+    bfd_close (prog_bfd);
+  return SIM_RC_OK;
 }