]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - sim/mips/interp.c
sim: mips: fix build w/out dv-sockser
[thirdparty/binutils-gdb.git] / sim / mips / interp.c
index 0c587e0a17da2866b3abe3b4d1186238761df9e8..93bbc5c846c0d8367cfb9d75518dbd49113ae4ae 100644 (file)
@@ -22,12 +22,8 @@ code on the hardware.
 
 */
 
-/* The TRACE manifests enable the provision of extra features. If they
-   are not defined then a simpler (quicker) simulator is constructed
-   without the required run-time checks, etc. */
-#if 1 /* 0 to allow user build selection, 1 to force inclusion */
-#define TRACE (1)
-#endif
+/* This must come before any other includes.  */
+#include "defs.h"
 
 #include "bfd.h"
 #include "sim-main.h"
@@ -38,40 +34,25 @@ code on the hardware.
 
 #include "itable.h"
 
-
-#include "config.h"
-
 #include <stdio.h>
 #include <stdarg.h>
 #include <ansidecl.h>
 #include <ctype.h>
 #include <limits.h>
 #include <math.h>
-#ifdef HAVE_STDLIB_H
 #include <stdlib.h>
-#endif
-#ifdef HAVE_STRING_H
 #include <string.h>
-#else
-#ifdef HAVE_STRINGS_H
-#include <strings.h>
-#endif
-#endif
 
 #include "getopt.h"
 #include "libiberty.h"
 #include "bfd.h"
-#include "callback.h"   /* GDB simulator callback interface */
-#include "remote-sim.h" /* GDB simulator interface */
+#include "elf-bfd.h"
+#include "sim/callback.h"   /* GDB simulator callback interface */
+#include "sim/sim.h" /* GDB simulator interface */
+#include "sim-syscall.h"   /* Simulator system call support */
 
-#include "sysdep.h"
-
-#ifndef PARAMS
-#define PARAMS(x) 
-#endif
-
-char* pr_addr PARAMS ((SIM_ADDR addr));
-char* pr_uword64 PARAMS ((uword64 addr));
+char* pr_addr (SIM_ADDR addr);
+char* pr_uword64 (uword64 addr);
 
 
 /* Within interp.c we refer to the sim_state and sim_cpu directly. */
@@ -83,7 +64,7 @@ char* pr_uword64 PARAMS ((uword64 addr));
    trap is required. NOTE: Care must be taken, since this value may be
    used in later revisions of the MIPS ISA. */
 
-#define RSVD_INSTRUCTION           (0x00000005)
+#define RSVD_INSTRUCTION           (0x00000039)
 #define RSVD_INSTRUCTION_MASK      (0xFC00003F)
 
 #define RSVD_INSTRUCTION_ARG_SHIFT 6
@@ -99,7 +80,7 @@ char* pr_uword64 PARAMS ((uword64 addr));
 /*-- GDB simulator interface ------------------------------------------------*/
 /*---------------------------------------------------------------------------*/
 
-static void ColdReset PARAMS((SIM_DESC sd));
+static void ColdReset (SIM_DESC sd);
 
 /*---------------------------------------------------------------------------*/
 
@@ -131,6 +112,9 @@ static void ColdReset PARAMS((SIM_DESC sd));
 
 /* Note that the monitor code essentially assumes this layout of memory.
    If you change these, change the monitor code, too.  */
+/* FIXME Currently addresses are truncated to 32-bits, see
+   mips/sim-main.c:address_translation(). If that changes, then these
+   values will need to be extended, and tested for more carefully. */
 #define K0BASE  (0x80000000)
 #define K0SIZE  (0x20000000)
 #define K1BASE  (0xA0000000)
@@ -155,15 +139,16 @@ static SIM_ADDR lsipmon_monitor_base = 0xBFC00200;
 
 static SIM_RC sim_firmware_command (SIM_DESC sd, char* arg);
 
+#define MEM_SIZE (8 << 20)     /* 8 MBytes */
 
-#define MEM_SIZE (2 << 20)
 
-
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
 static char *tracefile = "trace.din"; /* default filename for trace log */
 FILE *tracefh = NULL;
-static void open_trace PARAMS((SIM_DESC sd));
-#endif /* TRACE */
+static void open_trace (SIM_DESC sd);
+#else
+#define open_trace(sd)
+#endif
 
 static const char * get_insn_name (sim_cpu *, int);
 
@@ -177,23 +162,21 @@ enum {
   OPTION_DINERO_TRACE = OPTION_START,
   OPTION_DINERO_FILE,
   OPTION_FIRMWARE,
+  OPTION_INFO_MEMORY,
   OPTION_BOARD
 };
 
+static int display_mem_info = 0;
 
 static SIM_RC
-mips_option_handler (sd, cpu, opt, arg, is_command)
-     SIM_DESC sd;
-     sim_cpu *cpu;
-     int opt;
-     char *arg;
-     int is_command;
+mips_option_handler (SIM_DESC sd, sim_cpu *cpu, int opt, char *arg,
+                     int is_command)
 {
   int cpu_nr;
   switch (opt)
     {
     case OPTION_DINERO_TRACE: /* ??? */
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
       /* Eventually the simTRACE flag could be treated as a toggle, to
         allow external control of the program points being traced
         (i.e. only from main onwards, excluding the run-time setup,
@@ -218,15 +201,15 @@ mips_option_handler (sd, cpu, opt, arg, is_command)
            }
        }
       return SIM_RC_OK;
-#else /* !TRACE */
+#else /* !WITH_TRACE_ANY_P */
       fprintf(stderr,"\
 Simulator constructed without dinero tracing support (for performance).\n\
-Re-compile simulator with \"-DTRACE\" to enable this option.\n");
+Re-compile simulator with \"-DWITH_TRACE_ANY_P\" to enable this option.\n");
       return SIM_RC_FAIL;
-#endif /* !TRACE */
+#endif /* !WITH_TRACE_ANY_P */
 
     case OPTION_DINERO_FILE:
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
       if (optarg != NULL) {
        char *tmp;
        tmp = (char *)malloc(strlen(optarg) + 1);
@@ -241,7 +224,7 @@ Re-compile simulator with \"-DTRACE\" to enable this option.\n");
          sim_io_printf(sd,"Placing trace information into file \"%s\"\n",tracefile);
        }
       }
-#endif /* TRACE */
+#endif /* WITH_TRACE_ANY_P */
       return SIM_RC_OK;
 
     case OPTION_FIRMWARE:
@@ -256,6 +239,10 @@ Re-compile simulator with \"-DTRACE\" to enable this option.\n");
          }
        return SIM_RC_OK;
       }
+
+    case OPTION_INFO_MEMORY:
+      display_mem_info = 1;
+      break;
     }
   
   return SIM_RC_OK;
@@ -287,6 +274,20 @@ static const OPTION mips_options[] =
 
     , "Customize simulation for a particular board.", mips_option_handler },
 
+  /* These next two options have the same names as ones found in the
+     memory_options[] array in common/sim-memopt.c.  This is because
+     the intention is to provide an alternative handler for those two
+     options.  We need an alternative handler because the memory
+     regions are not set up until after the command line arguments
+     have been parsed, and so we cannot display the memory info whilst
+     processing the command line.  There is a hack in sim_open to
+     remove these handlers when we want the real --memory-info option
+     to work.  */
+  { { "info-memory", no_argument, NULL, OPTION_INFO_MEMORY },
+    '\0', NULL, "List configured memory regions", mips_option_handler },
+  { { "memory-info", no_argument, NULL, OPTION_INFO_MEMORY },
+    '\0', NULL, NULL, mips_option_handler },
+  
   { {NULL, no_argument, NULL, 0}, '\0', NULL, NULL, NULL }
 };
 
@@ -297,7 +298,7 @@ void
 interrupt_event (SIM_DESC sd, void *data)
 {
   sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
-  address_word cia = CIA_GET (cpu);
+  address_word cia = CPU_PC_GET (cpu);
   if (SR & status_IE)
     {
       interrupt_pending = 0;
@@ -322,21 +323,39 @@ static void device_init(SIM_DESC sd) {
 /*-- GDB simulator interface ------------------------------------------------*/
 /*---------------------------------------------------------------------------*/
 
+static sim_cia
+mips_pc_get (sim_cpu *cpu)
+{
+  return PC;
+}
+
+static void
+mips_pc_set (sim_cpu *cpu, sim_cia pc)
+{
+  PC = pc;
+}
+
+static int mips_reg_fetch (SIM_CPU *, int, unsigned char *, int);
+static int mips_reg_store (SIM_CPU *, int, unsigned char *, int);
+
 SIM_DESC
-sim_open (kind, cb, abfd, argv)
-     SIM_OPEN_KIND kind;
-     host_callback *cb;
-     struct _bfd *abfd;
-     char **argv;
+sim_open (SIM_OPEN_KIND kind, host_callback *cb,
+         struct bfd *abfd, char * const *argv)
 {
-  SIM_DESC sd = sim_state_alloc (kind, cb);
-  sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
+  int i;
+  SIM_DESC sd = sim_state_alloc_extra (kind, cb,
+                                      sizeof (struct mips_sim_state));
+  sim_cpu *cpu;
 
   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, 1) != SIM_RC_OK)
+    return 0;
+
+  cpu = STATE_CPU (sd, 0); /* FIXME */
+
   /* FIXME: watchpoints code shouldn't need this */
-  STATE_WATCHPOINTS (sd)->pc = &(PC);
-  STATE_WATCHPOINTS (sd)->sizeof_pc = sizeof (PC);
   STATE_WATCHPOINTS (sd)->interrupt_handler = interrupt_event;
 
   /* Initialize the mechanism for doing insn profiling.  */
@@ -350,9 +369,7 @@ sim_open (kind, cb, abfd, argv)
   sim_add_option_table (sd, NULL, mips_options);
 
 
-  /* getopt will print the error message so we just have to exit if this fails.
-     FIXME: Hmmm...  in the case of gdb we need getopt to call
-     print_filtered.  */
+  /* The parser will print an error message for us, so we silently return.  */
   if (sim_parse_args (sd, argv) != SIM_RC_OK)
     {
       /* Uninstall the modules to avoid memory leaks,
@@ -365,17 +382,67 @@ sim_open (kind, cb, abfd, argv)
   if (board == NULL)
     {
       /* Allocate core managed memory */
-      
+      sim_memopt *entry, *match = NULL;
+      address_word mem_size = 0;
+      int mapped = 0;
 
       /* For compatibility with the old code - under this (at level one)
         are the kernel spaces K0 & K1.  Both of these map to a single
         smaller sub region */
       sim_do_command(sd," memory region 0x7fff8000,0x8000") ; /* MTZ- 32 k stack */
-      sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx%%0x%lx,0x%0x",
-                      K1BASE, K0SIZE,
-                      MEM_SIZE, /* actual size */
-                      K0BASE);
-      
+
+      /* Look for largest memory region defined on command-line at
+        phys address 0. */
+      for (entry = STATE_MEMOPT (sd); entry != NULL; entry = entry->next)
+       {
+         /* If we find an entry at address 0, then we will end up
+            allocating a new buffer in the "memory alias" command
+            below. The region at address 0 will be deleted. */
+         address_word size = (entry->modulo != 0
+                              ? entry->modulo : entry->nr_bytes);
+         if (entry->addr == 0
+             && (!match || entry->level < match->level))
+           match = entry;
+         else if (entry->addr == K0BASE || entry->addr == K1BASE)
+           mapped = 1;
+         else
+           {
+             sim_memopt *alias;
+             for (alias = entry->alias; alias != NULL; alias = alias->next)
+               {
+                 if (alias->addr == 0
+                     && (!match || entry->level < match->level))
+                   match = entry;
+                 else if (alias->addr == K0BASE || alias->addr == K1BASE)
+                   mapped = 1;
+               }
+           }
+       }
+
+      if (!mapped)
+       {
+         if (match)
+           {
+             /* Get existing memory region size. */
+             mem_size = (match->modulo != 0
+                         ? match->modulo : match->nr_bytes);
+             /* Delete old region. */
+             sim_do_commandf (sd, "memory delete %d:0x%lx@%d",
+                              match->space, match->addr, match->level);
+           }         
+         else if (mem_size == 0)
+           mem_size = MEM_SIZE;
+         /* Limit to KSEG1 size (512MB) */
+         if (mem_size > K1SIZE)
+           mem_size = K1SIZE;
+         /* memory alias K1BASE@1,K1SIZE%MEMSIZE,K0BASE */
+         sim_do_commandf (sd, "memory alias 0x%lx@1,0x%lx%%0x%lx,0x%0x",
+                          K1BASE, K1SIZE, (long)mem_size, K0BASE);
+         if (WITH_TARGET_WORD_BITSIZE == 64)
+           sim_do_commandf (sd, "memory alias 0x%x,0x%" PRIxTW ",0x%" PRIxTA,
+                            (K0BASE), mem_size, EXTENDED(K0BASE));
+       }
+
       device_init(sd);
     }
   else if (board != NULL
@@ -476,8 +543,12 @@ sim_open (kind, cb, abfd, argv)
       {
        /* FIXME: poking at dv-sockser internals, use tcp backend if
         --sockser_addr option was given.*/
+#ifdef HAVE_DV_SOCKSER
        extern char* sockser_addr;
-       if(sockser_addr == NULL)
+#else
+# define sockser_addr NULL
+#endif
+       if (sockser_addr == NULL)
          sim_hw_parse (sd, "/tx3904sio@0xfffff300/backend stdio");
        else
          sim_hw_parse (sd, "/tx3904sio@0xfffff300/backend tcp");
@@ -534,6 +605,31 @@ sim_open (kind, cb, abfd, argv)
     }
 #endif
 
+  if (display_mem_info)
+    {
+      struct option_list * ol;
+      struct option_list * prev;
+
+      /* This is a hack.  We want to execute the real --memory-info command
+        line switch which is handled in common/sim-memopts.c, not the
+        override we have defined in this file.  So we remove the
+        mips_options array from the state options list.  This is safe
+         because we have now processed all of the command line.  */
+      for (ol = STATE_OPTIONS (sd), prev = NULL;
+          ol != NULL;
+          prev = ol, ol = ol->next)
+       if (ol->options == mips_options)
+         break;
+
+      SIM_ASSERT (ol != NULL);
+
+      if (prev == NULL)
+       STATE_OPTIONS (sd) = ol->next;
+      else
+       prev->next = ol->next;
+
+      sim_do_commandf (sd, "memory-info");
+    }
 
   /* check for/establish the a reference program image */
   if (sim_analyze_program (sd,
@@ -575,7 +671,7 @@ sim_open (kind, cb, abfd, argv)
       {
        if (rn < 32)
          cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
-       else if ((rn >= FGRIDX) && (rn < (FGRIDX + NR_FGR)))
+       else if ((rn >= FGR_BASE) && (rn < (FGR_BASE + NR_FGR)))
          cpu->register_widths[rn] = WITH_TARGET_FLOATING_POINT_BITSIZE;
        else if ((rn >= 33) && (rn <= 37))
          cpu->register_widths[rn] = WITH_TARGET_WORD_BITSIZE;
@@ -591,10 +687,8 @@ sim_open (kind, cb, abfd, argv)
 
   }
 
-#if defined(TRACE)
   if (STATE & simTRACE)
     open_trace(sd);
-#endif /* TRACE */
 
   /*
   sim_io_eprintf (sd, "idt@%x pmon@%x lsipmon@%x\n", 
@@ -609,11 +703,16 @@ sim_open (kind, cb, abfd, argv)
   if (idt_monitor_base != 0)
     {
       unsigned loop;
-      unsigned idt_monitor_size = 1 << 11;
+      address_word idt_monitor_size = 1 << 11;
 
       /* the default monitor region */
-      sim_do_commandf (sd, "memory region 0x%x,0x%x",
-                      idt_monitor_base, idt_monitor_size);
+      if (WITH_TARGET_WORD_BITSIZE == 64)
+       sim_do_commandf (sd, "memory alias 0x%x,0x%" PRIxTW ",0x%" PRIxTA,
+                        idt_monitor_base, idt_monitor_size,
+                        EXTENDED (idt_monitor_base));
+      else
+       sim_do_commandf (sd, "memory region 0x%x,0x%x",
+                        idt_monitor_base, idt_monitor_size);
 
       /* Entry into the IDT monitor is via fixed address vectors, and
         not using machine instructions. To avoid clashing with use of
@@ -626,7 +725,7 @@ sim_open (kind, cb, abfd, argv)
                             (((loop >> 2) & RSVD_INSTRUCTION_ARG_MASK)
                              << RSVD_INSTRUCTION_ARG_SHIFT));
          H2T (insn);
-         sim_write (sd, vaddr, (char *)&insn, sizeof (insn));
+         sim_write (sd, vaddr, (unsigned char *)&insn, sizeof (insn));
        }
     }
 
@@ -674,13 +773,13 @@ sim_open (kind, cb, abfd, argv)
        if (pmon_monitor_base != 0)
          {
            address_word vaddr = (pmon_monitor_base + (loop * 4));
-           sim_write (sd, vaddr, (char *)&value, sizeof (value));
+           sim_write (sd, vaddr, (unsigned char *)&value, sizeof (value));
          }
 
        if (lsipmon_monitor_base != 0)
          {
            address_word vaddr = (lsipmon_monitor_base + (loop * 4));
-           sim_write (sd, vaddr, (char *)&value, sizeof (value));
+           sim_write (sd, vaddr, (unsigned char *)&value, sizeof (value));
          }
       }
 
@@ -695,25 +794,33 @@ sim_open (kind, cb, abfd, argv)
                             HALT_INSTRUCTION /* BREAK */ };
       H2T (halt[0]);
       H2T (halt[1]);
-      sim_write (sd, 0x80000000, (char *) halt, sizeof (halt));
-      sim_write (sd, 0x80000180, (char *) halt, sizeof (halt));
-      sim_write (sd, 0x80000200, (char *) halt, sizeof (halt));
+      sim_write (sd, 0x80000000, (unsigned char *) halt, sizeof (halt));
+      sim_write (sd, 0x80000180, (unsigned char *) halt, sizeof (halt));
+      sim_write (sd, 0x80000200, (unsigned char *) halt, sizeof (halt));
       /* XXX: Write here unconditionally? */
-      sim_write (sd, 0xBFC00200, (char *) halt, sizeof (halt));
-      sim_write (sd, 0xBFC00380, (char *) halt, sizeof (halt));
-      sim_write (sd, 0xBFC00400, (char *) halt, sizeof (halt));
+      sim_write (sd, 0xBFC00200, (unsigned char *) halt, sizeof (halt));
+      sim_write (sd, 0xBFC00380, (unsigned char *) halt, sizeof (halt));
+      sim_write (sd, 0xBFC00400, (unsigned char *) halt, sizeof (halt));
     }
   }
 
+  /* CPU specific initialization.  */
+  for (i = 0; i < MAX_NR_PROCESSORS; ++i)
+    {
+      SIM_CPU *cpu = STATE_CPU (sd, i);
 
+      CPU_REG_FETCH (cpu) = mips_reg_fetch;
+      CPU_REG_STORE (cpu) = mips_reg_store;
+      CPU_PC_FETCH (cpu) = mips_pc_get;
+      CPU_PC_STORE (cpu) = mips_pc_set;
+    }
 
   return sd;
 }
 
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
 static void
-open_trace(sd)
-     SIM_DESC sd;
+open_trace (SIM_DESC sd)
 {
   tracefh = fopen(tracefile,"wb+");
   if (tracefh == NULL)
@@ -722,7 +829,7 @@ open_trace(sd)
       tracefh = stderr;
   }
 }
-#endif /* TRACE */
+#endif
 
 /* Return name of an insn, used by insn profiling.  */
 static const char *
@@ -732,110 +839,20 @@ get_insn_name (sim_cpu *cpu, int i)
 }
 
 void
-sim_close (sd, quitting)
-     SIM_DESC sd;
-     int quitting;
+mips_sim_close (SIM_DESC sd, int quitting)
 {
-#ifdef DEBUG
-  printf("DBG: sim_close: entered (quitting = %d)\n",quitting);
-#endif
-
-
-  /* "quitting" is non-zero if we cannot hang on errors */
-
-  /* shut down modules */
-  sim_module_uninstall (sd);
-
-  /* Ensure that any resources allocated through the callback
-     mechanism are released: */
-  sim_io_shutdown (sd);
-
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
   if (tracefh != NULL && tracefh != stderr)
    fclose(tracefh);
   tracefh = NULL;
-#endif /* TRACE */
-
-  /* FIXME - free SD */
-
-  return;
-}
-
-
-int
-sim_write (sd,addr,buffer,size)
-     SIM_DESC sd;
-     SIM_ADDR addr;
-     unsigned char *buffer;
-     int size;
-{
-  int index;
-  sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
-
-  /* Return the number of bytes written, or zero if error. */
-#ifdef DEBUG
-  sim_io_printf(sd,"sim_write(0x%s,buffer,%d);\n",pr_addr(addr),size);
 #endif
-
-  /* We use raw read and write routines, since we do not want to count
-     the GDB memory accesses in our statistics gathering. */
-
-  for (index = 0; index < size; index++)
-    {
-      address_word vaddr = (address_word)addr + index;
-      address_word paddr;
-      int cca;
-      if (!address_translation (SD, CPU, NULL_CIA, vaddr, isDATA, isSTORE, &paddr, &cca, isRAW))
-       break;
-      if (sim_core_write_buffer (SD, CPU, read_map, buffer + index, paddr, 1) != 1)
-       break;
-    }
-
-  return(index);
 }
 
-int
-sim_read (sd,addr,buffer,size)
-     SIM_DESC sd;
-     SIM_ADDR addr;
-     unsigned char *buffer;
-     int size;
+static int
+mips_reg_store (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
 {
-  int index;
-  sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
-
-  /* Return the number of bytes read, or zero if error. */
-#ifdef DEBUG
-  sim_io_printf(sd,"sim_read(0x%s,buffer,%d);\n",pr_addr(addr),size);
-#endif /* DEBUG */
-
-  for (index = 0; (index < size); index++)
-    {
-      address_word vaddr = (address_word)addr + index;
-      address_word paddr;
-      int cca;
-      if (!address_translation (SD, CPU, NULL_CIA, vaddr, isDATA, isLOAD, &paddr, &cca, isRAW))
-       break;
-      if (sim_core_read_buffer (SD, CPU, read_map, buffer + index, paddr, 1) != 1)
-       break;
-    }
-
-  return(index);
-}
-
-int
-sim_store_register (sd,rn,memory,length)
-     SIM_DESC sd;
-     int rn;
-     unsigned char *memory;
-     int length;
-{
-  sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
   /* NOTE: gdb (the client) stores registers in target byte order
      while the simulator uses host byte order */
-#ifdef DEBUG
-  sim_io_printf(sd,"sim_store_register(%d,*memory=0x%s);\n",rn,pr_addr(*((SIM_ADDR *)memory)));
-#endif /* DEBUG */
 
   /* Unfortunately this suffers from the same problem as the register
      numbering one. We need to know what the width of each logical
@@ -843,33 +860,39 @@ sim_store_register (sd,rn,memory,length)
 
   if (cpu->register_widths[rn] == 0)
     {
-      sim_io_eprintf(sd,"Invalid register width for %d (register store ignored)\n",rn);
+      sim_io_eprintf (CPU_STATE (cpu), "Invalid register width for %d (register store ignored)\n", rn);
       return 0;
     }
 
-
-
-  if (rn >= FGRIDX && rn < FGRIDX + NR_FGR)
+  if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
     {
-      cpu->fpr_state[rn - FGRIDX] = fmt_uninterpreted;
+      cpu->fpr_state[rn - FGR_BASE] = fmt_uninterpreted;
       if (cpu->register_widths[rn] == 32)
        {
          if (length == 8)
            {
-             cpu->fgr[rn - FGRIDX] = 
+             cpu->fgr[rn - FGR_BASE] = 
                (unsigned32) T2H_8 (*(unsigned64*)memory);
              return 8;
            }
          else
            {
-             cpu->fgr[rn - FGRIDX] = T2H_4 (*(unsigned32*)memory);
+             cpu->fgr[rn - FGR_BASE] = T2H_4 (*(unsigned32*)memory);
              return 4;
            }
        }
       else
        {
-         cpu->fgr[rn - FGRIDX] = T2H_8 (*(unsigned64*)memory);
-         return 8;
+          if (length == 8)
+           {
+             cpu->fgr[rn - FGR_BASE] = T2H_8 (*(unsigned64*)memory);
+             return 8;
+           }
+         else
+           {
+             cpu->fgr[rn - FGR_BASE] = T2H_4 (*(unsigned32*)memory);
+             return 4;
+           }
        }
     }
 
@@ -889,58 +912,62 @@ sim_store_register (sd,rn,memory,length)
     }
   else
     {
-      cpu->registers[rn] = T2H_8 (*(unsigned64*)memory);
-      return 8;
+      if (length == 8)
+       {
+         cpu->registers[rn] = T2H_8 (*(unsigned64*)memory);
+         return 8;
+       }
+      else
+       {
+         cpu->registers[rn] = (signed32) T2H_4(*(unsigned32*)memory);
+         return 4;
+       }
     }
 
   return 0;
 }
 
-int
-sim_fetch_register (sd,rn,memory,length)
-     SIM_DESC sd;
-     int rn;
-     unsigned char *memory;
-     int length;
+static int
+mips_reg_fetch (SIM_CPU *cpu, int rn, unsigned char *memory, int length)
 {
-  sim_cpu *cpu = STATE_CPU (sd, 0); /* FIXME */
   /* NOTE: gdb (the client) stores registers in target byte order
      while the simulator uses host byte order */
-#ifdef DEBUG
-#if 0  /* FIXME: doesn't compile */
-  sim_io_printf(sd,"sim_fetch_register(%d=0x%s,mem) : place simulator registers into memory\n",rn,pr_addr(registers[rn]));
-#endif
-#endif /* DEBUG */
 
   if (cpu->register_widths[rn] == 0)
     {
-      sim_io_eprintf (sd, "Invalid register width for %d (register fetch ignored)\n",rn);
+      sim_io_eprintf (CPU_STATE (cpu), "Invalid register width for %d (register fetch ignored)\n", rn);
       return 0;
     }
 
-
-
   /* Any floating point register */
-  if (rn >= FGRIDX && rn < FGRIDX + NR_FGR)
+  if (rn >= FGR_BASE && rn < FGR_BASE + NR_FGR)
     {
       if (cpu->register_widths[rn] == 32)
        {
          if (length == 8)
            {
              *(unsigned64*)memory =
-               H2T_8 ((unsigned32) (cpu->fgr[rn - FGRIDX]));
+               H2T_8 ((unsigned32) (cpu->fgr[rn - FGR_BASE]));
              return 8;
            }
          else
            {
-             *(unsigned32*)memory = H2T_4 (cpu->fgr[rn - FGRIDX]);
+             *(unsigned32*)memory = H2T_4 (cpu->fgr[rn - FGR_BASE]);
              return 4;
            }
        }
       else
        {
-         *(unsigned64*)memory = H2T_8 (cpu->fgr[rn - FGRIDX]);
-         return 8;
+         if (length == 8)
+           {
+             *(unsigned64*)memory = H2T_8 (cpu->fgr[rn - FGR_BASE]);
+             return 8;
+           }
+         else
+           {
+             *(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->fgr[rn - FGR_BASE]));
+             return 4;
+           }
        }
     }
 
@@ -960,20 +987,25 @@ sim_fetch_register (sd,rn,memory,length)
     }
   else
     {
-      *(unsigned64*)memory = H2T_8 ((unsigned64)(cpu->registers[rn]));
-      return 8;
+      if (length == 8)
+       {
+         *(unsigned64*)memory =
+           H2T_8 ((unsigned64) (cpu->registers[rn]));
+         return 8;
+       }
+      else
+       {
+         *(unsigned32*)memory = H2T_4 ((unsigned32)(cpu->registers[rn]));
+         return 4;
+       }
     }
 
   return 0;
 }
 
-
 SIM_RC
-sim_create_inferior (sd, abfd, argv,env)
-     SIM_DESC sd;
-     struct _bfd *abfd;
-     char **argv;
-     char **env;
+sim_create_inferior (SIM_DESC sd, struct bfd *abfd,
+                    char * const *argv, char * const *env)
 {
 
 #ifdef DEBUG
@@ -992,7 +1024,16 @@ sim_create_inferior (sd, abfd, argv,env)
       for (cpu_nr = 0; cpu_nr < sim_engine_nr_cpus (sd); cpu_nr++)
        {
          sim_cpu *cpu = STATE_CPU (sd, cpu_nr);
-         CIA_SET (cpu, (unsigned64) bfd_get_start_address (abfd));
+         sim_cia pc = bfd_get_start_address (abfd);
+
+         /* The 64-bit BFD sign-extends MIPS addresses to model
+            32-bit compatibility segments with 64-bit addressing.
+            These addresses work as is on 64-bit targets but
+            can be truncated for 32-bit targets.  */
+         if (WITH_TARGET_WORD_BITSIZE == 32)
+           pc = (unsigned32) pc;
+
+         CPU_PC_SET (cpu, pc);
        }
     }
 
@@ -1013,16 +1054,6 @@ sim_create_inferior (sd, abfd, argv,env)
   return SIM_RC_OK;
 }
 
-void
-sim_do_command (sd,cmd)
-     SIM_DESC sd;
-     char *cmd;
-{
-  if (sim_args_command (sd, cmd) != SIM_RC_OK)
-    sim_io_printf (sd, "Error: \"%s\" is not a valid MIPS simulator command.\n",
-                  cmd);
-}
-
 /*---------------------------------------------------------------------------*/
 /*-- Private simulator support interface ------------------------------------*/
 /*---------------------------------------------------------------------------*/
@@ -1034,11 +1065,11 @@ fetch_str (SIM_DESC sd,
 {
   char *buf;
   int nr = 0;
-  char null;
+  unsigned char null;
   while (sim_read (sd, addr + nr, &null, 1) == 1 && null != 0)
     nr++;
   buf = NZALLOC (char, nr + 1);
-  sim_read (sd, addr, buf, nr);
+  sim_read (sd, addr, (unsigned char *)buf, nr);
   return buf;
 }
 
@@ -1077,7 +1108,10 @@ sim_firmware_command (SIM_DESC sd, char *arg)
          }
       }
     else
-      address_present = 0;
+      {
+       address_present = 0;
+       address = -1; /* Dummy value.  */
+      }
   }
 
   if (! strncmp (arg, "idt", 3))
@@ -1125,6 +1159,23 @@ Recognized firmware names are: `idt', `pmon', `lsipmon', and `none'.\n",
   return SIM_RC_OK;
 }
 
+/* stat structures from MIPS32/64.  */
+static const char stat32_map[] =
+"st_dev,2:st_ino,2:st_mode,4:st_nlink,2:st_uid,2:st_gid,2"
+":st_rdev,2:st_size,4:st_atime,4:st_spare1,4:st_mtime,4:st_spare2,4"
+":st_ctime,4:st_spare3,4:st_blksize,4:st_blocks,4:st_spare4,8";
+
+static const char stat64_map[] =
+"st_dev,2:st_ino,2:st_mode,4:st_nlink,2:st_uid,2:st_gid,2"
+":st_rdev,2:st_size,8:st_atime,8:st_spare1,8:st_mtime,8:st_spare2,8"
+":st_ctime,8:st_spare3,8:st_blksize,8:st_blocks,8:st_spare4,16";
+
+/* Map for calls using the host struct stat.  */
+static const CB_TARGET_DEFS_MAP CB_stat_map[] =
+{
+  { "stat", CB_SYS_stat, 15 },
+  { 0, -1, -1 }
+};
 
 
 /* Simple monitor interface (currently setup for the IDT and PMON monitors) */
@@ -1145,7 +1196,7 @@ sim_monitor (SIM_DESC sd,
 
   /* The following callback functions are available, however the
      monitor we are simulating does not make use of them: get_errno,
-     isatty, lseek, rename, system, time and unlink */
+     isatty, rename, system and time.  */
   switch (reason)
     {
 
@@ -1153,7 +1204,7 @@ sim_monitor (SIM_DESC sd,
       {
        char *path = fetch_str (sd, A0);
        V0 = sim_io_open (sd, path, (int)A1);
-       zfree (path);
+       free (path);
        break;
       }
 
@@ -1163,8 +1214,8 @@ sim_monitor (SIM_DESC sd,
        int nr = A2;
        char *buf = zalloc (nr);
        V0 = sim_io_read (sd, fd, buf, nr);
-       sim_write (sd, A1, buf, nr);
-       zfree (buf);
+       sim_write (sd, A1, (unsigned char *)buf, nr);
+       free (buf);
       }
       break;
 
@@ -1173,9 +1224,13 @@ sim_monitor (SIM_DESC sd,
        int fd = A0;
        int nr = A2;
        char *buf = zalloc (nr);
-       sim_read (sd, A1, buf, nr);
+       sim_read (sd, A1, (unsigned char *)buf, nr);
        V0 = sim_io_write (sd, fd, buf, nr);
-       zfree (buf);
+       if (fd == 1)
+           sim_io_flush_stdout (sd);
+       else if (fd == 2)
+           sim_io_flush_stderr (sd);
+       free (buf);
        break;
       }
 
@@ -1215,6 +1270,56 @@ sim_monitor (SIM_DESC sd,
        break;
       }
 
+    case 13: /* int unlink(const char *path) */
+      {
+       char *path = fetch_str (sd, A0);
+       V0 = sim_io_unlink (sd, path);
+       free (path);
+       break;
+      }
+
+    case 14: /* int lseek(int fd, int offset, int whence) */
+      {
+       V0 = sim_io_lseek (sd, A0, A1, A2);
+       break;
+      }
+
+    case 15: /* int stat(const char *path, struct stat *buf); */
+      {
+       /* As long as the infrastructure doesn't cache anything
+          related to the stat mapping, this trick gets us a dual
+          "struct stat"-type mapping in the least error-prone way.  */
+       host_callback *cb = STATE_CALLBACK (sd);
+       const char *saved_map = cb->stat_map;
+       CB_TARGET_DEFS_MAP *saved_syscall_map = cb->syscall_map;
+       bfd *prog_bfd = STATE_PROG_BFD (sd);
+       int is_elf32bit = (elf_elfheader(prog_bfd)->e_ident[EI_CLASS] ==
+                          ELFCLASS32);
+       static CB_SYSCALL s;
+       CB_SYSCALL_INIT (&s);
+       s.func = 15;
+       /* Mask out the sign extension part for 64-bit targets because the
+          MIPS simulator's memory model is still 32-bit.  */
+       s.arg1 = A0 & 0xFFFFFFFF;
+       s.arg2 = A1 & 0xFFFFFFFF;
+       s.p1 = (PTR) sd;
+       s.p2 = (PTR) cpu;
+       s.read_mem = sim_syscall_read_mem;
+       s.write_mem = sim_syscall_write_mem;
+
+       cb->syscall_map = (CB_TARGET_DEFS_MAP *) CB_stat_map;
+       cb->stat_map = is_elf32bit ? stat32_map : stat64_map;
+
+       if (cb_syscall (cb, &s) != CB_RC_OK)
+         sim_engine_halt (sd, cpu, NULL, mips_pc_get (cpu),
+                          sim_stopped, SIM_SIGILL);
+
+       V0 = s.result;
+       cb->stat_map = saved_map;
+       cb->syscall_map = saved_syscall_map;
+       break;
+      }
+
     case 17: /* void _exit() */
       {
        sim_io_eprintf (sd, "sim_monitor(17): _exit(int reason) to be coded\n");
@@ -1223,7 +1328,7 @@ sim_monitor (SIM_DESC sd,
        break;
       }
 
-    case 28 : /* PMON flush_cache */
+    case 28: /* PMON flush_cache */
       break;
 
     case 55: /* void get_mem_info(unsigned int *ptr) */
@@ -1232,17 +1337,48 @@ sim_monitor (SIM_DESC sd,
       /*      [A0 + 4] = instruction cache size */
       /*      [A0 + 8] = data cache size */
       {
-       unsigned_4 value = MEM_SIZE /* FIXME STATE_MEM_SIZE (sd) */;
+       unsigned_4 value;
        unsigned_4 zero = 0;
+       address_word mem_size;
+       sim_memopt *entry, *match = NULL;
+
+       /* Search for memory region mapped to KSEG0 or KSEG1. */
+       for (entry = STATE_MEMOPT (sd); 
+            entry != NULL;
+            entry = entry->next)
+         {
+           if ((entry->addr == K0BASE || entry->addr == K1BASE)
+               && (!match || entry->level < match->level))
+             match = entry;
+           else
+             {
+               sim_memopt *alias;
+               for (alias = entry->alias; 
+                    alias != NULL;
+                    alias = alias->next)
+                 if ((alias->addr == K0BASE || alias->addr == K1BASE)
+                     && (!match || entry->level < match->level))
+                   match = entry;
+             }
+         }
+
+       /* Get region size, limit to KSEG1 size (512MB). */
+       SIM_ASSERT (match != NULL);
+       mem_size = (match->modulo != 0
+                   ? match->modulo : match->nr_bytes);
+       if (mem_size > K1SIZE)
+         mem_size = K1SIZE;
+
+       value = mem_size;
        H2T (value);
-       sim_write (sd, A0 + 0, (char *)&value, 4);
-       sim_write (sd, A0 + 4, (char *)&zero, 4);
-       sim_write (sd, A0 + 8, (char *)&zero, 4);
-       /* sim_io_eprintf (sd, "sim: get_mem_info() depreciated\n"); */
+       sim_write (sd, A0 + 0, (unsigned char *)&value, 4);
+       sim_write (sd, A0 + 4, (unsigned char *)&zero, 4);
+       sim_write (sd, A0 + 8, (unsigned char *)&zero, 4);
+       /* sim_io_eprintf (sd, "sim: get_mem_info() deprecated\n"); */
        break;
       }
     
-    case 158 : /* PMON printf */
+    case 158: /* PMON printf */
       /* in:  A0 = pointer to format string */
       /*      A1 = optional argument 1 */
       /*      A2 = optional argument 2 */
@@ -1251,7 +1387,7 @@ sim_monitor (SIM_DESC sd,
       /* The following is based on the PMON printf source */
       {
        address_word s = A0;
-       char c;
+       unsigned char c;
        signed_word *ap = &A1; /* 1st argument */
         /* This isn't the quickest way, since we call the host print
            routine for every character almost. But it does avoid
@@ -1308,7 +1444,7 @@ sim_monitor (SIM_DESC sd,
                    if ((int)*ap != 0)
                      {
                        address_word p = *ap++;
-                       char ch;
+                       unsigned char ch;
                        while (sim_read (sd, p++, &ch, 1) == 1 && ch != '\0')
                          sim_io_printf(sd, "%c", ch);
                      }
@@ -1373,26 +1509,21 @@ store_word (SIM_DESC sd,
            uword64 vaddr,
            signed_word val)
 {
-  address_word paddr;
-  int uncached;
+  address_word paddr = vaddr;
 
   if ((vaddr & 3) != 0)
     SignalExceptionAddressStore ();
   else
     {
-      if (AddressTranslation (vaddr, isDATA, isSTORE, &paddr, &uncached,
-                             isTARGET, isREAL))
-       {
-         const uword64 mask = 7;
-         uword64 memval;
-         unsigned int byte;
-
-         paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
-         byte = (vaddr & mask) ^ (BigEndianCPU << 2);
-         memval = ((uword64) val) << (8 * byte);
-         StoreMemory (uncached, AccessLength_WORD, memval, 0, paddr, vaddr,
-                      isREAL);
-       }
+      const uword64 mask = 7;
+      uword64 memval;
+      unsigned int byte;
+
+      paddr = (paddr & ~mask) | ((paddr & mask) ^ (ReverseEndian << 2));
+      byte = (vaddr & mask) ^ (BigEndianCPU << 2);
+      memval = ((uword64) val) << (8 * byte);
+      StoreMemory (AccessLength_WORD, memval, 0, paddr, vaddr,
+                  isREAL);
     }
 }
 
@@ -1410,24 +1541,18 @@ load_word (SIM_DESC sd,
     }
   else
     {
-      address_word paddr;
-      int uncached;
-
-      if (AddressTranslation (vaddr, isDATA, isLOAD, &paddr, &uncached,
-                             isTARGET, isREAL))
-       {
-         const uword64 mask = 0x7;
-         const unsigned int reverse = ReverseEndian ? 1 : 0;
-         const unsigned int bigend = BigEndianCPU ? 1 : 0;
-         uword64 memval;
-         unsigned int byte;
-
-         paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2));
-         LoadMemory (&memval,NULL,uncached, AccessLength_WORD, paddr, vaddr,
-                              isDATA, isREAL);
-         byte = (vaddr & mask) ^ (bigend << 2);
-         return EXTEND32 (memval >> (8 * byte));
-       }
+      address_word paddr = vaddr;
+      const uword64 mask = 0x7;
+      const unsigned int reverse = ReverseEndian ? 1 : 0;
+      const unsigned int bigend = BigEndianCPU ? 1 : 0;
+      uword64 memval;
+      unsigned int byte;
+
+      paddr = (paddr & ~mask) | ((paddr & mask) ^ (reverse << 2));
+      LoadMemory (&memval, NULL, AccessLength_WORD, paddr, vaddr, isDATA,
+                 isREAL);
+      byte = (vaddr & mask) ^ (bigend << 2);
+      return EXTEND32 (memval >> (8 * byte));
     }
 
   return 0;
@@ -1528,16 +1653,16 @@ mips16_entry (SIM_DESC sd,
 
 /*-- trace support ----------------------------------------------------------*/
 
-/* The TRACE support is provided (if required) in the memory accessing
+/* The trace support is provided (if required) in the memory accessing
    routines. Since we are also providing the architecture specific
    features, the architecture simulation code can also deal with
-   notifying the TRACE world of cache flushes, etc. Similarly we do
+   notifying the trace world of cache flushes, etc. Similarly we do
    not need to provide profiling support in the simulator engine,
    since we can sample in the instruction fetch control loop. By
-   defining the TRACE manifest, we add tracing as a run-time
+   defining the trace manifest, we add tracing as a run-time
    option. */
 
-#if defined(TRACE)
+#if WITH_TRACE_ANY_P
 /* Tracing by default produces "din" format (as required by
    dineroIII). Each line of such a trace file *MUST* have a din label
    and address field. The rest of the line is ignored, so comments can
@@ -1601,7 +1726,7 @@ dotrace (SIM_DESC sd,
 
   return;
 }
-#endif /* TRACE */
+#endif /* WITH_TRACE_ANY_P */
 
 /*---------------------------------------------------------------------------*/
 /*-- simulator engine -------------------------------------------------------*/
@@ -1638,6 +1763,20 @@ ColdReset (SIM_DESC sd)
            FPR_STATE[rn] = fmt_uninterpreted;
        }
       
+      /* Initialise the Config0 register. */
+      C0_CONFIG = 0x80000000           /* Config1 present */
+       | 2;                            /* KSEG0 uncached */
+      if (WITH_TARGET_WORD_BITSIZE == 64)
+       {
+         /* FIXME Currently mips/sim-main.c:address_translation()
+            truncates all addresses to 32-bits. */
+         if (0 && WITH_TARGET_ADDRESS_BITSIZE == 64)
+           C0_CONFIG |= (2 << 13);     /* MIPS64, 64-bit addresses */
+         else
+           C0_CONFIG |= (1 << 13);     /* MIPS64, 32-bit addresses */
+       }
+      if (BigEndianMem)
+       C0_CONFIG |= 0x00008000;        /* Big Endian */
     }
 }
 
@@ -1671,7 +1810,7 @@ signal_exception (SIM_DESC sd,
 
   switch (exception) {
 
-    case DebugBreakPoint :
+    case DebugBreakPoint:
       if (! (Debug & Debug_DM))
         {
           if (INDELAYSLOT())
@@ -1694,7 +1833,7 @@ signal_exception (SIM_DESC sd,
         }
       break;
 
-    case ReservedInstruction :
+    case ReservedInstruction:
      {
        va_list ap;
        unsigned int instruction;
@@ -1845,7 +1984,7 @@ signal_exception (SIM_DESC sd,
         sim_engine_halt (SD, CPU, NULL, PC,
                          sim_stopped, SIM_SIGTRAP);
 
-       default : /* Unknown internal exception */
+       default: /* Unknown internal exception */
         PC = EPC;
         sim_engine_halt (SD, CPU, NULL, PC,
                          sim_stopped, SIM_SIGABRT);
@@ -1921,8 +2060,7 @@ cop_lw (SIM_DESC sd,
 #ifdef DEBUG
          printf("DBG: COP_LW: memword = 0x%08X (uword64)memword = 0x%s\n",memword,pr_addr(memword));
 #endif
-         StoreFPR(coproc_reg,fmt_word,(uword64)memword);
-         FPR_STATE[coproc_reg] = fmt_uninterpreted;
+         StoreFPR(coproc_reg,fmt_uninterpreted_32,(uword64)memword);
          break;
        }
 
@@ -1953,7 +2091,7 @@ cop_ld (SIM_DESC sd,
     case 1:
       if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
        {
-         StoreFPR(coproc_reg,fmt_uninterpreted,memword);
+         StoreFPR(coproc_reg,fmt_uninterpreted_64,memword);
          break;
        }
 
@@ -1984,11 +2122,7 @@ cop_sw (SIM_DESC sd,
     case 1:
       if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
        {
-         FP_formats hold;
-         hold = FPR_STATE[coproc_reg];
-         FPR_STATE[coproc_reg] = fmt_word;
-         value = (unsigned int)ValueFPR(coproc_reg,fmt_uninterpreted);
-         FPR_STATE[coproc_reg] = hold;
+         value = (unsigned int)ValueFPR(coproc_reg,fmt_uninterpreted_32);
          break;
        }
 
@@ -2015,7 +2149,7 @@ cop_sd (SIM_DESC sd,
     case 1:
       if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
        {
-         value = ValueFPR(coproc_reg,fmt_uninterpreted);
+         value = ValueFPR(coproc_reg,fmt_uninterpreted_64);
          break;
        }
 
@@ -2036,18 +2170,17 @@ void
 decode_coproc (SIM_DESC sd,
               sim_cpu *cpu,
               address_word cia,
-              unsigned int instruction)
+              unsigned int instruction,
+              int coprocnum,
+              CP0_operation op,
+              int rt,
+              int rd,
+              int sel)
 {
-  int coprocnum = ((instruction >> 26) & 3);
-
   switch (coprocnum)
     {
     case 0: /* standard CPU control and cache registers */
       {
-        int code = ((instruction >> 21) & 0x1F);
-       int rt = ((instruction >> 16) & 0x1F);
-       int rd = ((instruction >> 11) & 0x1F);
-       int tail = instruction & 0x3ff;
         /* R4000 Users Manual (second edition) lists the following CP0
            instructions:
                                                                   CODE><-RT><RD-><--TAIL--->
@@ -2062,15 +2195,10 @@ decode_coproc (SIM_DESC sd,
           CACHE   Cache operation                 (VR4100 = 101111bbbbbpppppiiiiiiiiiiiiiiii)
           ERET    Exception return                (VR4100 = 01000010000000000000000000011000)
           */
-        if (((code == 0x00) || (code == 0x04)      /* MFC0  /  MTC0  */        
-            || (code == 0x01) || (code == 0x05))  /* DMFC0 / DMTC0  */        
-           && tail == 0)
+       if (((op == cp0_mfc0) || (op == cp0_mtc0)      /* MFC0  /  MTC0  */
+            || (op == cp0_dmfc0) || (op == cp0_dmtc0))  /* DMFC0 / DMTC0  */
+           && sel == 0)
          {
-           /* Clear double/single coprocessor move bit. */
-           code &= ~1;
-
-           /* M[TF]C0 (32 bits) | DM[TF]C0 (64 bits) */
-           
            switch (rd)  /* NOTEs: Standard CP0 registers */
              {
                /* 0 = Index               R4000   VR4100  VR4300 */
@@ -2098,29 +2226,29 @@ decode_coproc (SIM_DESC sd,
 
              case 8:
                /* 8 = BadVAddr            R4000   VR4100  VR4300 */
-               if (code == 0x00)
-                 GPR[rt] = COP0_BADVADDR;
+               if (op == cp0_mfc0 || op == cp0_dmfc0)
+                 GPR[rt] = (signed_word) (signed_address) COP0_BADVADDR;
                else
                  COP0_BADVADDR = GPR[rt];
                break;
 
 #endif /* SUBTARGET_R3900 */
              case 12:
-               if (code == 0x00)
+               if (op == cp0_mfc0 || op == cp0_dmfc0)
                  GPR[rt] = SR;
                else
                  SR = GPR[rt];
                break;
                /* 13 = Cause              R4000   VR4100  VR4300 */
              case 13:
-               if (code == 0x00)
+               if (op == cp0_mfc0 || op == cp0_dmfc0)
                  GPR[rt] = CAUSE;
                else
                  CAUSE = GPR[rt];
                break;
                /* 14 = EPC                R4000   VR4100  VR4300 */
              case 14:
-               if (code == 0x00)
+               if (op == cp0_mfc0 || op == cp0_dmfc0)
                  GPR[rt] = (signed_word) (signed_address) EPC;
                else
                  EPC = GPR[rt];
@@ -2129,7 +2257,7 @@ decode_coproc (SIM_DESC sd,
 #ifdef SUBTARGET_R3900
                 /* 16 = Debug */
               case 16:
-                if (code == 0x00)
+                if (op == cp0_mfc0 || op == cp0_dmfc0)
                   GPR[rt] = Debug;
                 else
                   Debug = GPR[rt];
@@ -2137,16 +2265,17 @@ decode_coproc (SIM_DESC sd,
 #else
                /* 16 = Config             R4000   VR4100  VR4300 */
               case 16:
-                if (code == 0x00)
-                  GPR[rt] = C0_CONFIG;
-                else
-                  C0_CONFIG = GPR[rt];
+               if (op == cp0_mfc0 || op == cp0_dmfc0)
+                 GPR[rt] = C0_CONFIG;
+               else
+                 /* only bottom three bits are writable */
+                 C0_CONFIG = (C0_CONFIG & ~0x7) | (GPR[rt] & 0x7);
                 break;
 #endif
 #ifdef SUBTARGET_R3900
                 /* 17 = Debug */
               case 17:
-                if (code == 0x00)
+                if (op == cp0_mfc0 || op == cp0_dmfc0)
                   GPR[rt] = DEPC;
                 else
                   DEPC = GPR[rt];
@@ -2169,7 +2298,7 @@ decode_coproc (SIM_DESC sd,
                GPR[rt] = 0xDEADC0DE; /* CPR[0,rd] */
                /* CPR[0,rd] = GPR[rt]; */
              default:
-               if (code == 0x00)
+               if (op == cp0_mfc0 || op == cp0_dmfc0)
                  GPR[rt] = (signed_word) (signed32) COP0_GPR[rd];
                else
                  COP0_GPR[rd] = GPR[rt];
@@ -2181,7 +2310,41 @@ decode_coproc (SIM_DESC sd,
 #endif
              }
          }
-       else if (code == 0x10 && (tail & 0x3f) == 0x18)
+       else if ((op == cp0_mfc0 || op == cp0_dmfc0)
+                && rd == 16)
+         {
+           /* [D]MFC0 RT,C0_CONFIG,SEL */
+           signed32 cfg = 0;
+           switch (sel)
+             {
+             case 0:
+               cfg = C0_CONFIG;
+               break;
+             case 1:
+               /* MIPS32 r/o Config1: 
+                  Config2 present */
+               cfg = 0x80000000;
+               /* MIPS16 implemented. 
+                  XXX How to check configuration? */
+               cfg |= 0x0000004;
+               if (CURRENT_FLOATING_POINT == HARD_FLOATING_POINT)
+                 /* MDMX & FPU implemented */
+                 cfg |= 0x00000021;
+               break;
+             case 2:
+               /* MIPS32 r/o Config2: 
+                  Config3 present. */
+               cfg = 0x80000000;
+               break;
+             case 3:
+               /* MIPS32 r/o Config3: 
+                  SmartMIPS implemented. */
+               cfg = 0x00000002;
+               break;
+             }
+           GPR[rt] = cfg;
+         }
+       else if (op == cp0_eret && sel == 0x18)
          {
            /* ERET */
            if (SR & status_ERL)
@@ -2197,7 +2360,7 @@ decode_coproc (SIM_DESC sd,
                SR &= ~status_EXL;
              }
          }
-        else if (code == 0x10 && (tail & 0x3f) == 0x10)
+        else if (op == cp0_rfe && sel == 0x10)
           {
             /* RFE */
 #ifdef SUBTARGET_R3900
@@ -2209,7 +2372,7 @@ decode_coproc (SIM_DESC sd,
            /* TODO: CACHE register */
 #endif /* SUBTARGET_R3900 */
           }
-        else if (code == 0x10 && (tail & 0x3f) == 0x1F)
+        else if (op == cp0_deret && sel == 0x1F)
           {
             /* DERET */
             Debug &= ~Debug_DM;
@@ -2268,8 +2431,7 @@ get_cell (void)
 static int thirty_two = 32;    
 
 char* 
-pr_addr(addr)
-  SIM_ADDR addr;
+pr_addr (SIM_ADDR addr)
 {
   char *paddr_str=get_cell();
   switch (sizeof(addr))
@@ -2291,8 +2453,7 @@ pr_addr(addr)
 }
 
 char* 
-pr_uword64(addr)
-  uword64 addr;
+pr_uword64 (uword64 addr)
 {
   char *paddr_str=get_cell();
   sprintf(paddr_str,"%08lx%08lx",