2007-11-19 Markus Deuling <deuling@de.ibm.com>
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 493f01150655d1b2f2def08a2c74a7259fe34670..6df6c616b6b081ce7c3aba9a96e95c89e0f90def 100644 (file)
@@ -11,7 +11,7 @@
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   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,
@@ -20,9 +20,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor,
-   Boston, MA 02110-1301, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "defs.h"
 #include "gdb_string.h"
@@ -167,6 +165,9 @@ static int mips_debug = 0;
 #define PROPERTY_GP32 "internal: transfers-32bit-registers"
 #define PROPERTY_GP64 "internal: transfers-64bit-registers"
 
+struct target_desc *mips_tdesc_gp32;
+struct target_desc *mips_tdesc_gp64;
+
 /* MIPS specific per-architecture information */
 struct gdbarch_tdep
 {
@@ -198,38 +199,6 @@ struct gdbarch_tdep
   int register_size;
 };
 
-static int
-n32n64_floatformat_always_valid (const struct floatformat *fmt,
-                                 const void *from)
-{
-  return 1;
-}
-
-/* FIXME: brobecker/2004-08-08: Long Double values are 128 bit long.
-   They are implemented as a pair of 64bit doubles where the high
-   part holds the result of the operation rounded to double, and
-   the low double holds the difference between the exact result and
-   the rounded result.  So "high" + "low" contains the result with
-   added precision.  Unfortunately, the floatformat structure used
-   by GDB is not powerful enough to describe this format.  As a temporary
-   measure, we define a 128bit floatformat that only uses the high part.
-   We lose a bit of precision but that's probably the best we can do
-   for now with the current infrastructure.  */
-
-static const struct floatformat floatformat_n32n64_long_double_big =
-{
-  floatformat_big, 128, 0, 1, 11, 1023, 2047, 12, 52,
-  floatformat_intbit_no,
-  "floatformat_n32n64_long_double_big",
-  n32n64_floatformat_always_valid
-};
-
-static const struct floatformat *floatformats_n32n64_long[BFD_ENDIAN_UNKNOWN] =
-{
-  &floatformat_n32n64_long_double_big,
-  &floatformat_n32n64_long_double_big
-};
-
 const struct mips_regnum *
 mips_regnum (struct gdbarch *gdbarch)
 {
@@ -266,36 +235,6 @@ unmake_mips16_addr (CORE_ADDR addr)
   return ((addr) & ~(CORE_ADDR) 1);
 }
 
-/* Return the contents of register REGNUM as a signed integer.  */
-
-static LONGEST
-read_signed_register (int regnum)
-{
-  LONGEST val;
-  regcache_cooked_read_signed (current_regcache, regnum, &val);
-  return val;
-}
-
-static LONGEST
-read_signed_register_pid (int regnum, ptid_t ptid)
-{
-  ptid_t save_ptid;
-  LONGEST retval;
-
-  if (ptid_equal (ptid, inferior_ptid))
-    return read_signed_register (regnum);
-
-  save_ptid = inferior_ptid;
-
-  inferior_ptid = ptid;
-
-  retval = read_signed_register (regnum);
-
-  inferior_ptid = save_ptid;
-
-  return retval;
-}
-
 /* Return the MIPS ABI associated with GDBARCH.  */
 enum mips_abi
 mips_abi (struct gdbarch *gdbarch)
@@ -372,18 +311,20 @@ msymbol_is_special (struct minimal_symbol *msym)
    things accordingly.  */
 
 static void
-mips_xfer_register (struct regcache *regcache, int reg_num, int length,
+mips_xfer_register (struct gdbarch *gdbarch, struct regcache *regcache,
+                   int reg_num, int length,
                    enum bfd_endian endian, gdb_byte *in,
                    const gdb_byte *out, int buf_offset)
 {
   int reg_offset = 0;
-  gdb_assert (reg_num >= gdbarch_num_regs (current_gdbarch));
+
+  gdb_assert (reg_num >= gdbarch_num_regs (gdbarch));
   /* Need to transfer the left or right part of the register, based on
      the targets byte order.  */
   switch (endian)
     {
     case BFD_ENDIAN_BIG:
-      reg_offset = register_size (current_gdbarch, reg_num) - length;
+      reg_offset = register_size (gdbarch, reg_num) - length;
       break;
     case BFD_ENDIAN_LITTLE:
       reg_offset = 0;
@@ -427,12 +368,12 @@ mips_xfer_register (struct regcache *regcache, int reg_num, int length,
    physical 64-bit registers, but should treat them as 32-bit registers.  */
 
 static int
-mips2_fp_compat (void)
+mips2_fp_compat (struct frame_info *frame)
 {
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not
      meaningful.  */
-  if (register_size (current_gdbarch, mips_regnum (current_gdbarch)->fp0) ==
-      4)
+  if (register_size (gdbarch, mips_regnum (gdbarch)->fp0) == 4)
     return 0;
 
 #if 0
@@ -441,7 +382,7 @@ mips2_fp_compat (void)
   /* Otherwise check the FR bit in the status register - it controls
      the FP compatiblity mode.  If it is clear we are in compatibility
      mode.  */
-  if ((read_register (MIPS_PS_REGNUM) & ST0_FR) == 0)
+  if ((get_frame_register_unsigned (frame, MIPS_PS_REGNUM) & ST0_FR) == 0)
     return 1;
 #endif
 
@@ -520,9 +461,9 @@ static const char *mips_irix_reg_names[NUM_MIPS_PROCESSOR_REGS] = {
 
 /* Return the name of the register corresponding to REGNO.  */
 static const char *
-mips_register_name (int regno)
+mips_register_name (struct gdbarch *gdbarch, int regno)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   /* GPR names for all ABIs other than n32/n64.  */
   static char *mips_gpr_names[] = {
     "zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
@@ -539,12 +480,12 @@ mips_register_name (int regno)
     "t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
   };
 
-  enum mips_abi abi = mips_abi (current_gdbarch);
+  enum mips_abi abi = mips_abi (gdbarch);
 
   /* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers, 
      but then don't make the raw register names visible.  */
-  int rawnum = regno % gdbarch_num_regs (current_gdbarch);
-  if (regno < gdbarch_num_regs (current_gdbarch))
+  int rawnum = regno % gdbarch_num_regs (gdbarch);
+  if (regno < gdbarch_num_regs (gdbarch))
     return "";
 
   /* The MIPS integer registers are always mapped from 0 to 31.  The
@@ -557,9 +498,9 @@ mips_register_name (int regno)
       else
        return mips_gpr_names[rawnum];
     }
-  else if (tdesc_has_registers (gdbarch_target_desc (current_gdbarch)))
-    return tdesc_register_name (rawnum);
-  else if (32 <= rawnum && rawnum < gdbarch_num_regs (current_gdbarch))
+  else if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+    return tdesc_register_name (gdbarch, rawnum);
+  else if (32 <= rawnum && rawnum < gdbarch_num_regs (gdbarch))
     {
       gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS);
       return tdep->mips_processor_reg_names[rawnum - 32];
@@ -578,17 +519,17 @@ mips_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
   int vector_p;
   int float_p;
   int raw_p;
-  int rawnum = regnum % gdbarch_num_regs (current_gdbarch);
-  int pseudo = regnum / gdbarch_num_regs (current_gdbarch);
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int pseudo = regnum / gdbarch_num_regs (gdbarch);
   if (reggroup == all_reggroup)
     return pseudo;
   vector_p = TYPE_VECTOR (register_type (gdbarch, regnum));
   float_p = TYPE_CODE (register_type (gdbarch, regnum)) == TYPE_CODE_FLT;
   /* FIXME: cagney/2003-04-13: Can't yet use gdbarch_num_regs
      (gdbarch), as not all architectures are multi-arch.  */
-  raw_p = rawnum < gdbarch_num_regs (current_gdbarch);
-  if (gdbarch_register_name (current_gdbarch, regnum) == NULL
-      || gdbarch_register_name (current_gdbarch, regnum)[0] == '\0')
+  raw_p = rawnum < gdbarch_num_regs (gdbarch);
+  if (gdbarch_register_name (gdbarch, regnum) == NULL
+      || gdbarch_register_name (gdbarch, regnum)[0] == '\0')
     return 0;
   if (reggroup == float_reggroup)
     return float_p && pseudo;
@@ -644,16 +585,16 @@ static void
 mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
                           int cookednum, gdb_byte *buf)
 {
-  int rawnum = cookednum % gdbarch_num_regs (current_gdbarch);
-  gdb_assert (cookednum >= gdbarch_num_regs (current_gdbarch)
-             && cookednum < 2 * gdbarch_num_regs (current_gdbarch));
+  int rawnum = cookednum % gdbarch_num_regs (gdbarch);
+  gdb_assert (cookednum >= gdbarch_num_regs (gdbarch)
+             && cookednum < 2 * gdbarch_num_regs (gdbarch));
   if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
     regcache_raw_read (regcache, rawnum, buf);
   else if (register_size (gdbarch, rawnum) >
           register_size (gdbarch, cookednum))
     {
       if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
-         || gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
+         || gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
        regcache_raw_read_part (regcache, rawnum, 0, 4, buf);
       else
        regcache_raw_read_part (regcache, rawnum, 4, 4, buf);
@@ -667,16 +608,16 @@ mips_pseudo_register_write (struct gdbarch *gdbarch,
                            struct regcache *regcache, int cookednum,
                            const gdb_byte *buf)
 {
-  int rawnum = cookednum % gdbarch_num_regs (current_gdbarch);
-  gdb_assert (cookednum >= gdbarch_num_regs (current_gdbarch)
-             && cookednum < 2 * gdbarch_num_regs (current_gdbarch));
+  int rawnum = cookednum % gdbarch_num_regs (gdbarch);
+  gdb_assert (cookednum >= gdbarch_num_regs (gdbarch)
+             && cookednum < 2 * gdbarch_num_regs (gdbarch));
   if (register_size (gdbarch, rawnum) == register_size (gdbarch, cookednum))
     regcache_raw_write (regcache, rawnum, buf);
   else if (register_size (gdbarch, rawnum) >
           register_size (gdbarch, cookednum))
     {
       if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
-         || gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
+         || gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
        regcache_raw_write_part (regcache, rawnum, 0, 4, buf);
       else
        regcache_raw_write_part (regcache, rawnum, 4, 4, buf);
@@ -719,14 +660,14 @@ set_mips64_transfers_32bit_regs (char *args, int from_tty,
 /* Convert to/from a register and the corresponding memory value.  */
 
 static int
-mips_convert_register_p (int regnum, struct type *type)
-{
-  return (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
-         && register_size (current_gdbarch, regnum) == 4
-         && (regnum % gdbarch_num_regs (current_gdbarch))
-               >= mips_regnum (current_gdbarch)->fp0
-         && (regnum % gdbarch_num_regs (current_gdbarch))
-               < mips_regnum (current_gdbarch)->fp0 + 32
+mips_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type)
+{
+  return (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
+         && register_size (gdbarch, regnum) == 4
+         && (regnum % gdbarch_num_regs (gdbarch))
+               >= mips_regnum (gdbarch)->fp0
+         && (regnum % gdbarch_num_regs (gdbarch))
+               < mips_regnum (gdbarch)->fp0 + 32
          && TYPE_CODE (type) == TYPE_CODE_FLT && TYPE_LENGTH (type) == 8);
 }
 
@@ -752,11 +693,10 @@ mips_value_to_register (struct frame_info *frame, int regnum,
 static struct type *
 mips_register_type (struct gdbarch *gdbarch, int regnum)
 {
-  gdb_assert (regnum >= 0 && regnum < 2 * gdbarch_num_regs (current_gdbarch));
-  if ((regnum % gdbarch_num_regs (current_gdbarch))
-       >= mips_regnum (current_gdbarch)->fp0
-      && (regnum % gdbarch_num_regs (current_gdbarch))
-       < mips_regnum (current_gdbarch)->fp0 + 32)
+  gdb_assert (regnum >= 0 && regnum < 2 * gdbarch_num_regs (gdbarch));
+  if ((regnum % gdbarch_num_regs (gdbarch)) >= mips_regnum (gdbarch)->fp0
+      && (regnum % gdbarch_num_regs (gdbarch))
+        < mips_regnum (gdbarch)->fp0 + 32)
     {
       /* The floating-point registers raw, or cooked, always match
          mips_isa_regsize(), and also map 1:1, byte for byte.  */
@@ -765,7 +705,7 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
       else
        return builtin_type_ieee_double;
     }
-  else if (regnum < gdbarch_num_regs (current_gdbarch))
+  else if (regnum < gdbarch_num_regs (gdbarch))
     {
       /* The raw or ISA registers.  These are all sized according to
         the ISA regsize.  */
@@ -778,10 +718,9 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
     {
       /* The cooked or ABI registers.  These are sized according to
         the ABI (with a few complications).  */
-      if (regnum >= (gdbarch_num_regs (current_gdbarch)
-                    + mips_regnum (current_gdbarch)->fp_control_status)
-         && regnum <= gdbarch_num_regs (current_gdbarch)
-                      + MIPS_LAST_EMBED_REGNUM)
+      if (regnum >= (gdbarch_num_regs (gdbarch)
+                    + mips_regnum (gdbarch)->fp_control_status)
+         && regnum <= gdbarch_num_regs (gdbarch) + MIPS_LAST_EMBED_REGNUM)
        /* The pseudo/cooked view of the embedded registers is always
           32-bit.  The raw view is handled below.  */
        return builtin_type_int32;
@@ -926,25 +865,26 @@ mips_pc_is_mips16 (CORE_ADDR memaddr)
    all registers should be sign extended for simplicity? */
 
 static CORE_ADDR
-mips_read_pc (ptid_t ptid)
+mips_read_pc (struct regcache *regcache)
 {
-  return read_signed_register_pid (mips_regnum (current_gdbarch)->pc, ptid);
+  ULONGEST pc;
+  int regnum = mips_regnum (get_regcache_arch (regcache))->pc;
+  regcache_cooked_read_signed (regcache, regnum, &pc);
+  return pc;
 }
 
 static CORE_ADDR
 mips_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  return frame_unwind_register_signed (next_frame,
-                                      gdbarch_num_regs (current_gdbarch)
-                                      + mips_regnum (gdbarch)->pc);
+  return frame_unwind_register_signed
+          (next_frame, gdbarch_num_regs (gdbarch) + mips_regnum (gdbarch)->pc);
 }
 
 static CORE_ADDR
 mips_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
-  return frame_unwind_register_signed (next_frame,
-                                      gdbarch_num_regs (current_gdbarch)
-                                      + MIPS_SP_REGNUM);
+  return frame_unwind_register_signed
+          (next_frame, gdbarch_num_regs (gdbarch) + MIPS_SP_REGNUM);
 }
 
 /* Assuming NEXT_FRAME->prev is a dummy, return the frame ID of that
@@ -957,15 +897,16 @@ mips_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   return frame_id_build
           (frame_unwind_register_signed (next_frame,
-                                         gdbarch_num_regs (current_gdbarch)
+                                         gdbarch_num_regs (gdbarch)
                                          + MIPS_SP_REGNUM),
                                          frame_pc_unwind (next_frame));
 }
 
 static void
-mips_write_pc (CORE_ADDR pc, ptid_t ptid)
+mips_write_pc (struct regcache *regcache, CORE_ADDR pc)
 {
-  write_register_pid (mips_regnum (current_gdbarch)->pc, pc, ptid);
+  int regnum = mips_regnum (get_regcache_arch (regcache))->pc;
+  regcache_cooked_write_unsigned (regcache, regnum, pc);
 }
 
 /* Fetch and return instruction from the specified location.  If the PC
@@ -1017,7 +958,7 @@ mips32_relative_offset (ULONGEST inst)
 /* Determine where to set a single step breakpoint while considering
    branch prediction.  */
 static CORE_ADDR
-mips32_next_pc (CORE_ADDR pc)
+mips32_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
   unsigned long inst;
   int op;
@@ -1036,7 +977,7 @@ mips32_next_pc (CORE_ADDR pc)
              goto neq_branch;
            case 2:             /* BLEZL */
              goto less_branch;
-           case 3:             /* BGTZ */
+           case 3:             /* BGTZL */
              goto greater_branch;
            default:
              pc += 4;
@@ -1048,8 +989,9 @@ mips32_next_pc (CORE_ADDR pc)
          int tf = itype_rt (inst) & 0x01;
          int cnum = itype_rt (inst) >> 2;
          int fcrcs =
-           read_signed_register (mips_regnum (current_gdbarch)->
-                                 fp_control_status);
+           get_frame_register_signed (frame,
+                                      mips_regnum (get_frame_arch (frame))->
+                                               fp_control_status);
          int cond = ((fcrcs >> 24) & 0x0e) | ((fcrcs >> 23) & 0x01);
 
          if (((cond >> cnum) & 0x01) == tf)
@@ -1073,7 +1015,7 @@ mips32_next_pc (CORE_ADDR pc)
            case 8:             /* JR */
            case 9:             /* JALR */
              /* Set PC to that address */
-             pc = read_signed_register (rtype_rs (inst));
+             pc = get_frame_register_signed (frame, rtype_rs (inst));
              break;
            default:
              pc += 4;
@@ -1090,7 +1032,7 @@ mips32_next_pc (CORE_ADDR pc)
              case 16:          /* BLTZAL */
              case 18:          /* BLTZALL */
              less_branch:
-               if (read_signed_register (itype_rs (inst)) < 0)
+               if (get_frame_register_signed (frame, itype_rs (inst)) < 0)
                  pc += mips32_relative_offset (inst) + 4;
                else
                  pc += 8;      /* after the delay slot */
@@ -1099,7 +1041,7 @@ mips32_next_pc (CORE_ADDR pc)
              case 3:           /* BGEZL */
              case 17:          /* BGEZAL */
              case 19:          /* BGEZALL */
-               if (read_signed_register (itype_rs (inst)) >= 0)
+               if (get_frame_register_signed (frame, itype_rs (inst)) >= 0)
                  pc += mips32_relative_offset (inst) + 4;
                else
                  pc += 8;      /* after the delay slot */
@@ -1129,22 +1071,22 @@ mips32_next_pc (CORE_ADDR pc)
          break;                /* The new PC will be alternate mode */
        case 4:         /* BEQ, BEQL */
        equal_branch:
-         if (read_signed_register (itype_rs (inst)) ==
-             read_signed_register (itype_rt (inst)))
+         if (get_frame_register_signed (frame, itype_rs (inst)) ==
+             get_frame_register_signed (frame, itype_rt (inst)))
            pc += mips32_relative_offset (inst) + 4;
          else
            pc += 8;
          break;
        case 5:         /* BNE, BNEL */
        neq_branch:
-         if (read_signed_register (itype_rs (inst)) !=
-             read_signed_register (itype_rt (inst)))
+         if (get_frame_register_signed (frame, itype_rs (inst)) !=
+             get_frame_register_signed (frame, itype_rt (inst)))
            pc += mips32_relative_offset (inst) + 4;
          else
            pc += 8;
          break;
        case 6:         /* BLEZ, BLEZL */
-         if (read_signed_register (itype_rs (inst)) <= 0)
+         if (get_frame_register_signed (frame, itype_rs (inst)) <= 0)
            pc += mips32_relative_offset (inst) + 4;
          else
            pc += 8;
@@ -1152,7 +1094,7 @@ mips32_next_pc (CORE_ADDR pc)
        case 7:
        default:
        greater_branch: /* BGTZ, BGTZL */
-         if (read_signed_register (itype_rs (inst)) > 0)
+         if (get_frame_register_signed (frame, itype_rs (inst)) > 0)
            pc += mips32_relative_offset (inst) + 4;
          else
            pc += 8;
@@ -1224,13 +1166,11 @@ extended_offset (unsigned int extension)
 }
 
 /* Only call this function if you know that this is an extendable
-   instruction, It wont malfunction, but why make excess remote memory references?
-   If the immediate operands get sign extended or somthing, do it after
-   the extension is performed.
- */
+   instruction.  It won't malfunction, but why make excess remote memory
+   references?  If the immediate operands get sign extended or something,
+   do it after the extension is performed.  */
 /* FIXME: Every one of these cases needs to worry about sign extension
-   when the offset is to be used in relative addressing */
-
+   when the offset is to be used in relative addressing.  */
 
 static unsigned int
 fetch_mips_16 (CORE_ADDR pc)
@@ -1333,7 +1273,7 @@ add_offset_16 (CORE_ADDR pc, int offset)
 }
 
 static CORE_ADDR
-extended_mips16_next_pc (CORE_ADDR pc,
+extended_mips16_next_pc (struct frame_info *frame, CORE_ADDR pc,
                         unsigned int extension, unsigned int insn)
 {
   int op = (insn >> 11);
@@ -1369,7 +1309,7 @@ extended_mips16_next_pc (CORE_ADDR pc,
        struct upk_mips16 upk;
        int reg;
        unpack_mips16 (pc, extension, insn, ritype, &upk);
-       reg = read_signed_register (upk.regx);
+       reg = get_frame_register_signed (frame, upk.regx);
        if (reg == 0)
          pc += (upk.offset << 1) + 2;
        else
@@ -1381,7 +1321,7 @@ extended_mips16_next_pc (CORE_ADDR pc,
        struct upk_mips16 upk;
        int reg;
        unpack_mips16 (pc, extension, insn, ritype, &upk);
-       reg = read_signed_register (upk.regx);
+       reg = get_frame_register_signed (frame, upk.regx);
        if (reg != 0)
          pc += (upk.offset << 1) + 2;
        else
@@ -1394,7 +1334,7 @@ extended_mips16_next_pc (CORE_ADDR pc,
        int reg;
        unpack_mips16 (pc, extension, insn, i8type, &upk);
        /* upk.regx contains the opcode */
-       reg = read_signed_register (24);        /* Test register is 24 */
+       reg = get_frame_register_signed (frame, 24);  /* Test register is 24 */
        if (((upk.regx == 0) && (reg == 0))     /* BTEZ */
            || ((upk.regx == 1) && (reg != 0))) /* BTNEZ */
          /* pc = add_offset_16(pc,upk.offset) ; */
@@ -1428,7 +1368,7 @@ extended_mips16_next_pc (CORE_ADDR pc,
                reg = 31;
                break;          /* BOGUS Guess */
              }
-           pc = read_signed_register (reg);
+           pc = get_frame_register_signed (frame, reg);
          }
        else
          pc += 2;
@@ -1440,7 +1380,7 @@ extended_mips16_next_pc (CORE_ADDR pc,
          that. */
       {
        pc += 2;
-       pc = extended_mips16_next_pc (pc, insn, fetch_mips_16 (pc));
+       pc = extended_mips16_next_pc (frame, pc, insn, fetch_mips_16 (pc));
        break;
       }
     default:
@@ -1453,24 +1393,24 @@ extended_mips16_next_pc (CORE_ADDR pc,
 }
 
 static CORE_ADDR
-mips16_next_pc (CORE_ADDR pc)
+mips16_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
   unsigned int insn = fetch_mips_16 (pc);
-  return extended_mips16_next_pc (pc, 0, insn);
+  return extended_mips16_next_pc (frame, pc, 0, insn);
 }
 
 /* The mips_next_pc function supports single_step when the remote
    target monitor or stub is not developed enough to do a single_step.
    It works by decoding the current instruction and predicting where a
    branch will go. This isnt hard because all the data is available.
-   The MIPS32 and MIPS16 variants are quite different */
+   The MIPS32 and MIPS16 variants are quite different */
 static CORE_ADDR
-mips_next_pc (CORE_ADDR pc)
+mips_next_pc (struct frame_info *frame, CORE_ADDR pc)
 {
-  if (pc & 0x01)
-    return mips16_next_pc (pc);
+  if (is_mips16_addr (pc))
+    return mips16_next_pc (frame, pc);
   else
-    return mips32_next_pc (pc);
+    return mips32_next_pc (frame, pc);
 }
 
 struct mips_frame_cache
@@ -1565,12 +1505,13 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   int extend_bytes = 0;
   int prev_extend_bytes;
   CORE_ADDR end_prologue_addr = 0;
+  struct gdbarch *gdbarch = get_frame_arch (next_frame);
 
   /* Can be called when there's no process, and hence when there's no
      NEXT_FRAME.  */
   if (next_frame != NULL)
     sp = frame_unwind_register_signed (next_frame,
-                                      gdbarch_num_regs (current_gdbarch)
+                                      gdbarch_num_regs (gdbarch)
                                       + MIPS_SP_REGNUM);
   else
     sp = 0;
@@ -1701,7 +1642,7 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
       for (reg = 4, offset = 0; reg < areg_count + 4; reg++)
        {
          set_reg_offset (this_cache, reg, sp + offset);
-         offset += mips_abi_regsize (current_gdbarch);
+         offset += mips_abi_regsize (gdbarch);
        }
 
       /* Check if the ra register was pushed on the stack.  */
@@ -1709,14 +1650,14 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
       if (entry_inst & 0x20)
        {
          set_reg_offset (this_cache, MIPS_RA_REGNUM, sp + offset);
-         offset -= mips_abi_regsize (current_gdbarch);
+         offset -= mips_abi_regsize (gdbarch);
        }
 
       /* Check if the s0 and s1 registers were pushed on the stack.  */
       for (reg = 16; reg < sreg_count + 16; reg++)
        {
          set_reg_offset (this_cache, reg, sp + offset);
-         offset -= mips_abi_regsize (current_gdbarch);
+         offset -= mips_abi_regsize (gdbarch);
        }
     }
 
@@ -1724,16 +1665,14 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
     {
       this_cache->base =
         (frame_unwind_register_signed (next_frame,
-                                      gdbarch_num_regs (current_gdbarch)
-                                      + frame_reg)
+                                      gdbarch_num_regs (gdbarch) + frame_reg)
          + frame_offset - frame_adjust);
       /* FIXME: brobecker/2004-10-10: Just as in the mips32 case, we should
          be able to get rid of the assignment below, evetually. But it's
          still needed for now.  */
-      this_cache->saved_regs[gdbarch_num_regs (current_gdbarch)
-                            + mips_regnum (current_gdbarch)->pc]
-        = this_cache->saved_regs[gdbarch_num_regs (current_gdbarch)
-                                + MIPS_RA_REGNUM];
+      this_cache->saved_regs[gdbarch_num_regs (gdbarch)
+                            + mips_regnum (gdbarch)->pc]
+        = this_cache->saved_regs[gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM];
     }
 
   /* If we didn't reach the end of the prologue when scanning the function
@@ -1777,9 +1716,11 @@ mips_insn16_frame_cache (struct frame_info *next_frame, void **this_cache)
     mips16_scan_prologue (start_addr, pc, next_frame, *this_cache);
   }
   
-  /* SP_REGNUM, contains the value and not the address.  */
-  trad_frame_set_value (cache->saved_regs, gdbarch_num_regs (current_gdbarch)
-                                          + MIPS_SP_REGNUM, cache->base);
+  /* gdbarch_sp_regnum contains the value and not the address.  */
+  trad_frame_set_value (cache->saved_regs,
+                       gdbarch_num_regs (get_frame_arch (next_frame))
+                         + MIPS_SP_REGNUM,
+                       cache->base);
 
   return (*this_cache);
 }
@@ -1887,12 +1828,13 @@ mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   CORE_ADDR end_prologue_addr = 0;
   int seen_sp_adjust = 0;
   int load_immediate_bytes = 0;
+  struct gdbarch *gdbarch = get_frame_arch (next_frame);
 
   /* Can be called when there's no process, and hence when there's no
      NEXT_FRAME.  */
   if (next_frame != NULL)
     sp = frame_unwind_register_signed (next_frame,
-                                      gdbarch_num_regs (current_gdbarch)
+                                      gdbarch_num_regs (gdbarch)
                                       + MIPS_SP_REGNUM);
   else
     sp = 0;
@@ -1949,8 +1891,7 @@ restart:
 
              frame_reg = 30;
              frame_addr = frame_unwind_register_signed
-                            (next_frame,
-                             gdbarch_num_regs (current_gdbarch) + 30);
+                            (next_frame, gdbarch_num_regs (gdbarch) + 30);
 
              alloca_adjust = (unsigned) (frame_addr - (sp + low_word));
              if (alloca_adjust > 0)
@@ -1980,8 +1921,7 @@ restart:
 
              frame_reg = 30;
              frame_addr = frame_unwind_register_signed
-                            (next_frame,
-                             gdbarch_num_regs (current_gdbarch) + 30);
+                            (next_frame, gdbarch_num_regs (gdbarch) + 30);
 
              alloca_adjust = (unsigned) (frame_addr - sp);
              if (alloca_adjust > 0)
@@ -2048,15 +1988,14 @@ restart:
     {
       this_cache->base = 
         (frame_unwind_register_signed (next_frame,
-                                      gdbarch_num_regs (current_gdbarch)
-                                      + frame_reg)
+                                      gdbarch_num_regs (gdbarch) + frame_reg)
          + frame_offset);
       /* FIXME: brobecker/2004-09-15: We should be able to get rid of
          this assignment below, eventually.  But it's still needed
          for now.  */
-      this_cache->saved_regs[gdbarch_num_regs (current_gdbarch)
-                            + mips_regnum (current_gdbarch)->pc]
-        = this_cache->saved_regs[gdbarch_num_regs (current_gdbarch)
+      this_cache->saved_regs[gdbarch_num_regs (gdbarch)
+                            + mips_regnum (gdbarch)->pc]
+        = this_cache->saved_regs[gdbarch_num_regs (gdbarch)
                                 + MIPS_RA_REGNUM];
     }
 
@@ -2112,9 +2051,10 @@ mips_insn32_frame_cache (struct frame_info *next_frame, void **this_cache)
     mips32_scan_prologue (start_addr, pc, next_frame, *this_cache);
   }
   
-  /* SP_REGNUM, contains the value and not the address.  */
+  /* gdbarch_sp_regnum contains the value and not the address.  */
   trad_frame_set_value (cache->saved_regs,
-                       gdbarch_num_regs (current_gdbarch) + MIPS_SP_REGNUM,
+                       gdbarch_num_regs (get_frame_arch (next_frame))
+                         + MIPS_SP_REGNUM,
                        cache->base);
 
   return (*this_cache);
@@ -2192,6 +2132,7 @@ mips_stub_frame_cache (struct frame_info *next_frame, void **this_cache)
   CORE_ADDR start_addr;
   CORE_ADDR stack_addr;
   struct trad_frame_cache *this_trad_cache;
+  struct gdbarch *gdbarch = get_frame_arch (next_frame);
 
   if ((*this_cache) != NULL)
     return (*this_cache);
@@ -2199,14 +2140,16 @@ mips_stub_frame_cache (struct frame_info *next_frame, void **this_cache)
   (*this_cache) = this_trad_cache;
 
   /* The return address is in the link register.  */
-  trad_frame_set_reg_realreg (this_trad_cache, PC_REGNUM, MIPS_RA_REGNUM);
+  trad_frame_set_reg_realreg (this_trad_cache,
+                             gdbarch_pc_regnum (gdbarch),
+                             (gdbarch_num_regs (gdbarch) + MIPS_RA_REGNUM));
 
   /* Frame ID, since it's a frameless / stackless function, no stack
      space is allocated and SP on entry is the current SP.  */
   pc = frame_pc_unwind (next_frame);
   find_pc_partial_function (pc, NULL, &start_addr, NULL);
   stack_addr = frame_unwind_register_signed (next_frame, MIPS_SP_REGNUM);
-  trad_frame_set_id (this_trad_cache, frame_id_build (start_addr, stack_addr));
+  trad_frame_set_id (this_trad_cache, frame_id_build (stack_addr, start_addr));
 
   /* Assume that the frame's base is the same as the
      stack-pointer.  */
@@ -2247,9 +2190,14 @@ static const struct frame_unwind mips_stub_frame_unwind =
 static const struct frame_unwind *
 mips_stub_frame_sniffer (struct frame_info *next_frame)
 {
+  gdb_byte dummy[4];
   struct obj_section *s;
   CORE_ADDR pc = frame_unwind_address_in_block (next_frame, NORMAL_FRAME);
 
+  /* Use the stub unwinder for unreadable code.  */
+  if (target_read_memory (frame_pc_unwind (next_frame), dummy, 4) != 0)
+    return &mips_stub_frame_unwind;
+
   if (in_plt_section (pc, NULL))
     return &mips_stub_frame_unwind;
 
@@ -2317,18 +2265,126 @@ mips_addr_bits_remove (CORE_ADDR addr)
     return addr;
 }
 
+/* Instructions used during single-stepping of atomic sequences.  */
+#define LL_OPCODE 0x30
+#define LLD_OPCODE 0x34
+#define SC_OPCODE 0x38
+#define SCD_OPCODE 0x3c
+
+/* Checks for an atomic sequence of instructions beginning with a LL/LLD
+   instruction and ending with a SC/SCD instruction.  If such a sequence
+   is found, attempt to step through it.  A breakpoint is placed at the end of 
+   the sequence.  */
+
+static int
+deal_with_atomic_sequence (CORE_ADDR pc)
+{
+  CORE_ADDR breaks[2] = {-1, -1};
+  CORE_ADDR loc = pc;
+  CORE_ADDR branch_bp; /* Breakpoint at branch instruction's destination.  */
+  unsigned long insn;
+  int insn_count;
+  int index;
+  int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed).  */  
+  const int atomic_sequence_length = 16; /* Instruction sequence length.  */
+
+  if (pc & 0x01)
+    return 0;
+
+  insn = mips_fetch_instruction (loc);
+  /* Assume all atomic sequences start with a ll/lld instruction.  */
+  if (itype_op (insn) != LL_OPCODE && itype_op (insn) != LLD_OPCODE)
+    return 0;
+
+  /* Assume that no atomic sequence is longer than "atomic_sequence_length" 
+     instructions.  */
+  for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count)
+    {
+      int is_branch = 0;
+      loc += MIPS_INSN32_SIZE;
+      insn = mips_fetch_instruction (loc);
+
+      /* Assume that there is at most one branch in the atomic
+        sequence.  If a branch is found, put a breakpoint in its
+        destination address.  */
+      switch (itype_op (insn))
+       {
+       case 0: /* SPECIAL */
+         if (rtype_funct (insn) >> 1 == 4) /* JR, JALR */
+           return 0; /* fallback to the standard single-step code. */
+         break;
+       case 1: /* REGIMM */
+         is_branch = ((itype_rt (insn) & 0xc0) == 0); /* B{LT,GE}Z* */
+         break;
+       case 2: /* J */
+       case 3: /* JAL */
+         return 0; /* fallback to the standard single-step code. */
+       case 4: /* BEQ */
+       case 5: /* BNE */
+       case 6: /* BLEZ */
+       case 7: /* BGTZ */
+       case 20: /* BEQL */
+       case 21: /* BNEL */
+       case 22: /* BLEZL */
+       case 23: /* BGTTL */
+         is_branch = 1;
+         break;
+       case 17: /* COP1 */
+       case 18: /* COP2 */
+       case 19: /* COP3 */
+         is_branch = (itype_rs (insn) == 8); /* BCzF, BCzFL, BCzT, BCzTL */
+         break;
+       }
+      if (is_branch)
+       {
+         branch_bp = loc + mips32_relative_offset (insn) + 4;
+         if (last_breakpoint >= 1)
+           return 0; /* More than one branch found, fallback to the
+                        standard single-step code.  */
+         breaks[1] = branch_bp;
+         last_breakpoint++;
+       }
+
+      if (itype_op (insn) == SC_OPCODE || itype_op (insn) == SCD_OPCODE)
+       break;
+    }
+
+  /* Assume that the atomic sequence ends with a sc/scd instruction.  */
+  if (itype_op (insn) != SC_OPCODE && itype_op (insn) != SCD_OPCODE)
+    return 0;
+
+  loc += MIPS_INSN32_SIZE;
+
+  /* Insert a breakpoint right after the end of the atomic sequence.  */
+  breaks[0] = loc;
+
+  /* Check for duplicated breakpoints.  Check also for a breakpoint
+     placed (branch instruction's destination) in the atomic sequence */
+  if (last_breakpoint && pc <= breaks[1] && breaks[1] <= breaks[0])
+    last_breakpoint = 0;
+
+  /* Effectively inserts the breakpoints.  */
+  for (index = 0; index <= last_breakpoint; index++)
+      insert_single_step_breakpoint (breaks[index]);
+
+  return 1;
+}
+
 /* mips_software_single_step() is called just before we want to resume
    the inferior, if we want to single-step it but there is no hardware
    or kernel single-step support (MIPS on GNU/Linux for example).  We find
    the target of the coming instruction and breakpoint it.  */
 
 int
-mips_software_single_step (struct regcache *regcache)
+mips_software_single_step (struct frame_info *frame)
 {
   CORE_ADDR pc, next_pc;
 
-  pc = read_register (mips_regnum (current_gdbarch)->pc);
-  next_pc = mips_next_pc (pc);
+  pc = get_frame_pc (frame);
+  if (deal_with_atomic_sequence (pc))
+    return 1;
+
+  next_pc = mips_next_pc (frame, pc);
 
   insert_single_step_breakpoint (next_pc);
   return 1;
@@ -2422,15 +2478,28 @@ heuristic-fence-post' command.\n", paddr_nz (pc), paddr_nz (pc));
 
        /* On MIPS16, any one of the following is likely to be the
           start of a function:
+          extend save
+          save
           entry
           addiu sp,-n
           daddiu sp,-n
           extend -n followed by 'addiu sp,+n' or 'daddiu sp,+n'  */
        inst = mips_fetch_instruction (start_pc);
-       if (((inst & 0xf81f) == 0xe809 && (inst & 0x700) != 0x700)      /* entry */
-           || (inst & 0xff80) == 0x6380        /* addiu sp,-n */
-           || (inst & 0xff80) == 0xfb80        /* daddiu sp,-n */
-           || ((inst & 0xf810) == 0xf010 && seen_adjsp))       /* extend -n */
+       if ((inst & 0xff80) == 0x6480)          /* save */
+         {
+           if (start_pc - instlen >= fence)
+             {
+               inst = mips_fetch_instruction (start_pc - instlen);
+               if ((inst & 0xf800) == 0xf000)  /* extend */
+                 start_pc -= instlen;
+             }
+           break;
+         }
+       else if (((inst & 0xf81f) == 0xe809
+                 && (inst & 0x700) != 0x700)   /* entry */
+                || (inst & 0xff80) == 0x6380   /* addiu sp,-n */
+                || (inst & 0xff80) == 0xfb80   /* daddiu sp,-n */
+                || ((inst & 0xf810) == 0xf010 && seen_adjsp))  /* extend -n */
          break;
        else if ((inst & 0xff00) == 0x6300      /* addiu sp */
                 || (inst & 0xff00) == 0xfb00)  /* daddiu sp */
@@ -2556,7 +2625,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Initialize the integer and float register pointers.  */
   argreg = MIPS_A0_REGNUM;
-  float_argreg = mips_fpa0_regnum (current_gdbarch);
+  float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
   if (struct_return)
@@ -2565,7 +2634,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        fprintf_unfiltered (gdb_stdlog,
                            "mips_eabi_push_dummy_call: struct_return reg=%d 0x%s\n",
                            argreg, paddr_nz (struct_addr));
-      write_register (argreg++, struct_addr);
+      regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
     }
 
   /* Now load as many as possible of the first arguments into
@@ -2633,7 +2702,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
             making the ABI determination.  */
          if (len == 8 && mips_abi (gdbarch) == MIPS_ABI_EABI32)
            {
-             int low_offset = gdbarch_byte_order (current_gdbarch)
+             int low_offset = gdbarch_byte_order (gdbarch)
                               == BFD_ENDIAN_BIG ? 4 : 0;
              unsigned long regval;
 
@@ -2642,14 +2711,14 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
-             write_register (float_argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
 
              /* Write the high word of the double to the odd register(s).  */
              regval = extract_unsigned_integer (val + 4 - low_offset, 4);
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
-             write_register (float_argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
            }
          else
            {
@@ -2661,7 +2730,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, len));
-             write_register (float_argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
            }
        }
       else
@@ -2698,7 +2767,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                  int longword_offset = 0;
                  CORE_ADDR addr;
                  stack_used_p = 1;
-                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+                 if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
                    {
                      if (regsize == 8
                          && (typecode == TYPE_CODE_INT
@@ -2750,7 +2819,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                    fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
                                      argreg,
                                      phex (regval, regsize));
-                 write_register (argreg, regval);
+                 regcache_cooked_write_unsigned (regcache, argreg, regval);
                  argreg++;
                }
 
@@ -2794,6 +2863,59 @@ mips_eabi_return_value (struct gdbarch *gdbarch,
 
 /* N32/N64 ABI stuff.  */
 
+/* Search for a naturally aligned double at OFFSET inside a struct
+   ARG_TYPE.  The N32 / N64 ABIs pass these in floating point
+   registers.  */
+
+static int
+mips_n32n64_fp_arg_chunk_p (struct type *arg_type, int offset)
+{
+  int i;
+
+  if (TYPE_CODE (arg_type) != TYPE_CODE_STRUCT)
+    return 0;
+
+  if (MIPS_FPU_TYPE != MIPS_FPU_DOUBLE)
+    return 0;
+
+  if (TYPE_LENGTH (arg_type) < offset + MIPS64_REGSIZE)
+    return 0;
+
+  for (i = 0; i < TYPE_NFIELDS (arg_type); i++)
+    {
+      int pos;
+      struct type *field_type;
+
+      /* We're only looking at normal fields.  */
+      if (TYPE_FIELD_STATIC (arg_type, i)
+         || (TYPE_FIELD_BITPOS (arg_type, i) % 8) != 0)
+       continue;
+
+      /* If we have gone past the offset, there is no double to pass.  */
+      pos = TYPE_FIELD_BITPOS (arg_type, i) / 8;
+      if (pos > offset)
+       return 0;
+
+      field_type = check_typedef (TYPE_FIELD_TYPE (arg_type, i));
+
+      /* If this field is entirely before the requested offset, go
+        on to the next one.  */
+      if (pos + TYPE_LENGTH (field_type) <= offset)
+       continue;
+
+      /* If this is our special aligned double, we can stop.  */
+      if (TYPE_CODE (field_type) == TYPE_CODE_FLT
+         && TYPE_LENGTH (field_type) == MIPS64_REGSIZE)
+       return 1;
+
+      /* This field starts at or before the requested offset, and
+        overlaps it.  If it is a structure, recurse inwards.  */
+      return mips_n32n64_fp_arg_chunk_p (field_type, offset - pos);
+    }
+
+  return 0;
+}
+
 static CORE_ADDR
 mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                             struct regcache *regcache, CORE_ADDR bp_addr,
@@ -2837,7 +2959,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Initialize the integer and float register pointers.  */
   argreg = MIPS_A0_REGNUM;
-  float_argreg = mips_fpa0_regnum (current_gdbarch);
+  float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
   if (struct_return)
@@ -2846,7 +2968,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        fprintf_unfiltered (gdb_stdlog,
                            "mips_n32n64_push_dummy_call: struct_return reg=%d 0x%s\n",
                            argreg, paddr_nz (struct_addr));
-      write_register (argreg++, struct_addr);
+      regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
     }
 
   /* Now load as many as possible of the first arguments into
@@ -2868,35 +2990,36 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
       val = value_contents (arg);
 
       if (fp_register_arg_p (typecode, arg_type)
-         && float_argreg <= MIPS_LAST_FP_ARG_REGNUM)
+         && argreg <= MIPS_LAST_ARG_REGNUM)
        {
          /* This is a floating point value that fits entirely
             in a single register.  */
-         /* On 32 bit ABI's the float_argreg is further adjusted
-            above to ensure that it is even register aligned.  */
          LONGEST regval = extract_unsigned_integer (val, len);
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                float_argreg, phex (regval, len));
-         write_register (float_argreg++, regval);
+         regcache_cooked_write_unsigned (regcache, float_argreg, regval);
 
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
                                argreg, phex (regval, len));
-         write_register (argreg, regval);
-         argreg += 1;
+         regcache_cooked_write_unsigned (regcache, argreg, regval);
+         float_argreg++;
+         argreg++;
        }
       else
        {
          /* Copy the argument to general registers or the stack in
             register-sized pieces.  Large arguments are split between
             registers and stack.  */
-         /* Note: structs whose size is not a multiple of MIPS64_REGSIZE
-            are treated specially: Irix cc passes them in registers
-            where gcc sometimes puts them on the stack.  For maximum
-            compatibility, we will put them in both places.  */
-         int odd_sized_struct = (len > MIPS64_REGSIZE
-                                 && len % MIPS64_REGSIZE != 0);
+         /* For N32/N64, structs, unions, or other composite types are
+            treated as a sequence of doublewords, and are passed in integer
+            or floating point registers as though they were simple scalar
+            parameters to the extent that they fit, with any excess on the
+            stack packed according to the normal memory layout of the
+            object.
+            The caller does not reserve space for the register arguments;
+            the callee is responsible for reserving it if required.  */
          /* Note: Floating-point values that didn't fit into an FP
             register are only written to memory.  */
          while (len > 0)
@@ -2909,17 +3032,18 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                fprintf_unfiltered (gdb_stdlog, " -- partial=%d",
                                    partial_len);
 
+             if (fp_register_arg_p (typecode, arg_type))
+               gdb_assert (argreg > MIPS_LAST_ARG_REGNUM);
+
              /* Write this portion of the argument to the stack.  */
-             if (argreg > MIPS_LAST_ARG_REGNUM
-                 || odd_sized_struct
-                 || fp_register_arg_p (typecode, arg_type))
+             if (argreg > MIPS_LAST_ARG_REGNUM)
                {
                  /* Should shorter than int integer values be
                     promoted to int before being stored? */
                  int longword_offset = 0;
                  CORE_ADDR addr;
                  stack_used_p = 1;
-                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+                 if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
                    {
                      if ((typecode == TYPE_CODE_INT
                           || typecode == TYPE_CODE_PTR
@@ -2953,12 +3077,10 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                }
 
              /* Note!!! This is NOT an else clause.  Odd sized
-                structs may go thru BOTH paths.  Floating point
-                arguments will not.  */
+                structs may go thru BOTH paths.  */
              /* Write this portion of the argument to a general
                 purpose register.  */
-             if (argreg <= MIPS_LAST_ARG_REGNUM
-                 && !fp_register_arg_p (typecode, arg_type))
+             if (argreg <= MIPS_LAST_ARG_REGNUM)
                {
                  LONGEST regval =
                    extract_unsigned_integer (val, partial_len);
@@ -2972,7 +3094,7 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                     It does not seem to be necessary to do the
                     same for integral types.  */
 
-                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
+                 if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
                      && partial_len < MIPS64_REGSIZE
                      && (typecode == TYPE_CODE_STRUCT
                          || typecode == TYPE_CODE_UNION))
@@ -2983,7 +3105,20 @@ mips_n32n64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                    fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
                                      argreg,
                                      phex (regval, MIPS64_REGSIZE));
-                 write_register (argreg, regval);
+                 regcache_cooked_write_unsigned (regcache, argreg, regval);
+
+                 if (mips_n32n64_fp_arg_chunk_p (arg_type,
+                                                 TYPE_LENGTH (arg_type) - len))
+                   {
+                     if (mips_debug)
+                       fprintf_filtered (gdb_stdlog, " - fpreg=%d val=%s",
+                                         float_argreg,
+                                         phex (regval, MIPS64_REGSIZE));
+                     regcache_cooked_write_unsigned (regcache, float_argreg,
+                                                     regval);
+                   }
+
+                 float_argreg++;
                  argreg++;
                }
 
@@ -3015,10 +3150,31 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
                          struct type *type, struct regcache *regcache,
                          gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-  if (TYPE_CODE (type) == TYPE_CODE_STRUCT
-      || TYPE_CODE (type) == TYPE_CODE_UNION
-      || TYPE_CODE (type) == TYPE_CODE_ARRAY
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* From MIPSpro N32 ABI Handbook, Document Number: 007-2816-004
+
+     Function results are returned in $2 (and $3 if needed), or $f0 (and $f2
+     if needed), as appropriate for the type.  Composite results (struct,
+     union, or array) are returned in $2/$f0 and $3/$f2 according to the
+     following rules:
+
+     * A struct with only one or two floating point fields is returned in $f0
+     (and $f2 if necessary).  This is a generalization of the Fortran COMPLEX
+     case.
+
+     * Any other struct or union results of at most 128 bits are returned in
+     $2 (first 64 bits) and $3 (remainder, if necessary).
+
+     * Larger composite results are handled by converting the function to a
+     procedure with an implicit first parameter, which is a pointer to an area
+     reserved by the caller to receive the result.  [The o32-bit ABI requires
+     that all composite results be handled by conversion to implicit first
+     parameters.  The MIPS/SGI Fortran implementation has always made a
+     specific exception to return COMPLEX results in the floating point
+     registers.]  */
+
+  if (TYPE_CODE (type) == TYPE_CODE_ARRAY
       || TYPE_LENGTH (type) > 2 * MIPS64_REGSIZE)
     return RETURN_VALUE_STRUCT_CONVENTION;
   else if (TYPE_CODE (type) == TYPE_CODE_FLT
@@ -3030,15 +3186,15 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
         eight bytes with the lower memory address are in $f0.  */
       if (mips_debug)
        fprintf_unfiltered (gdb_stderr, "Return float in $f0 and $f2\n");
-      mips_xfer_register (regcache,
-                         gdbarch_num_regs (current_gdbarch)
-                         + mips_regnum (current_gdbarch)->fp0,
-                         8, gdbarch_byte_order (current_gdbarch),
+      mips_xfer_register (gdbarch, regcache,
+                         gdbarch_num_regs (gdbarch)
+                         + mips_regnum (gdbarch)->fp0,
+                         8, gdbarch_byte_order (gdbarch),
                          readbuf, writebuf, 0);
-      mips_xfer_register (regcache,
-                         gdbarch_num_regs (current_gdbarch)
-                         + mips_regnum (current_gdbarch)->fp0 + 2,
-                         8, gdbarch_byte_order (current_gdbarch),
+      mips_xfer_register (gdbarch, regcache,
+                         gdbarch_num_regs (gdbarch)
+                         + mips_regnum (gdbarch)->fp0 + 2,
+                         8, gdbarch_byte_order (gdbarch),
                          readbuf ? readbuf + 8 : readbuf,
                          writebuf ? writebuf + 8 : writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -3046,15 +3202,14 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
   else if (TYPE_CODE (type) == TYPE_CODE_FLT
           && tdep->mips_fpu_type != MIPS_FPU_NONE)
     {
-      /* A floating-point value belongs in the least significant part
-         of FP0.  */
+      /* A single or double floating-point value that fits in FP0.  */
       if (mips_debug)
        fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
-      mips_xfer_register (regcache,
-                         gdbarch_num_regs (current_gdbarch)
-                         + mips_regnum (current_gdbarch)->fp0,
+      mips_xfer_register (gdbarch, regcache,
+                         gdbarch_num_regs (gdbarch)
+                         + mips_regnum (gdbarch)->fp0,
                          TYPE_LENGTH (type),
-                         gdbarch_byte_order (current_gdbarch),
+                         gdbarch_byte_order (gdbarch),
                          readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3062,12 +3217,12 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
           && TYPE_NFIELDS (type) <= 2
           && TYPE_NFIELDS (type) >= 1
           && ((TYPE_NFIELDS (type) == 1
-               && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+               && (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 0)))
                    == TYPE_CODE_FLT))
               || (TYPE_NFIELDS (type) == 2
-                  && (TYPE_CODE (TYPE_FIELD_TYPE (type, 0))
+                  && (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 0)))
                       == TYPE_CODE_FLT)
-                  && (TYPE_CODE (TYPE_FIELD_TYPE (type, 1))
+                  && (TYPE_CODE (check_typedef (TYPE_FIELD_TYPE (type, 1)))
                       == TYPE_CODE_FLT)))
           && tdep->mips_fpu_type != MIPS_FPU_NONE)
     {
@@ -3076,7 +3231,7 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
          register..  */
       int regnum;
       int field;
-      for (field = 0, regnum = mips_regnum (current_gdbarch)->fp0;
+      for (field = 0, regnum = mips_regnum (gdbarch)->fp0;
           field < TYPE_NFIELDS (type); field++, regnum += 2)
        {
          int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
@@ -3084,10 +3239,10 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n",
                                offset);
-         mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
-                                       + regnum,
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch) + regnum,
                              TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
-                             gdbarch_byte_order (current_gdbarch),
+                             gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -3102,17 +3257,18 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
       int regnum;
       for (offset = 0, regnum = MIPS_V0_REGNUM;
           offset < TYPE_LENGTH (type);
-          offset += register_size (current_gdbarch, regnum), regnum++)
+          offset += register_size (gdbarch, regnum), regnum++)
        {
-         int xfer = register_size (current_gdbarch, regnum);
+         int xfer = register_size (gdbarch, regnum);
          if (offset + xfer > TYPE_LENGTH (type))
            xfer = TYPE_LENGTH (type) - offset;
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
                                offset, xfer, regnum);
-         mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
-                                       + regnum, xfer,
-                             BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch) + regnum,
+                             xfer, BFD_ENDIAN_UNKNOWN, readbuf, writebuf,
+                             offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3124,17 +3280,17 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
       int regnum;
       for (offset = 0, regnum = MIPS_V0_REGNUM;
           offset < TYPE_LENGTH (type);
-          offset += register_size (current_gdbarch, regnum), regnum++)
+          offset += register_size (gdbarch, regnum), regnum++)
        {
-         int xfer = register_size (current_gdbarch, regnum);
+         int xfer = register_size (gdbarch, regnum);
          if (offset + xfer > TYPE_LENGTH (type))
            xfer = TYPE_LENGTH (type) - offset;
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
                                offset, xfer, regnum);
-         mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
-                                       + regnum, xfer,
-                             gdbarch_byte_order (current_gdbarch),
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch) + regnum,
+                             xfer, gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -3195,7 +3351,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Initialize the integer and float register pointers.  */
   argreg = MIPS_A0_REGNUM;
-  float_argreg = mips_fpa0_regnum (current_gdbarch);
+  float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
   if (struct_return)
@@ -3204,7 +3360,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        fprintf_unfiltered (gdb_stdlog,
                            "mips_o32_push_dummy_call: struct_return reg=%d 0x%s\n",
                            argreg, paddr_nz (struct_addr));
-      write_register (argreg++, struct_addr);
+      regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
       stack_offset += MIPS32_REGSIZE;
     }
 
@@ -3252,7 +3408,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        {
          if (register_size (gdbarch, float_argreg) < 8 && len == 8)
            {
-             int low_offset = gdbarch_byte_order (current_gdbarch)
+             int low_offset = gdbarch_byte_order (gdbarch)
                               == BFD_ENDIAN_BIG ? 4 : 0;
              unsigned long regval;
 
@@ -3261,23 +3417,23 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
-             write_register (float_argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
                                    argreg, phex (regval, 4));
-             write_register (argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, argreg++, regval);
 
              /* Write the high word of the double to the odd register(s).  */
              regval = extract_unsigned_integer (val + 4 - low_offset, 4);
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, 4));
-             write_register (float_argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
 
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
                                    argreg, phex (regval, 4));
-             write_register (argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, argreg++, regval);
            }
          else
            {
@@ -3289,7 +3445,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                    float_argreg, phex (regval, len));
-             write_register (float_argreg++, regval);
+             regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
              /* CAGNEY: 32 bit MIPS ABI's always reserve two FP
                 registers for each argument.  The below is (my
                 guess) to ensure that the corresponding integer
@@ -3297,7 +3453,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
              if (mips_debug)
                fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
                                    argreg, phex (regval, len));
-             write_register (argreg, regval);
+             regcache_cooked_write_unsigned (regcache, argreg, regval);
              argreg += 2;
            }
          /* Reserve space for the FP register.  */
@@ -3404,7 +3560,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                     identified as such and GDB gets tweaked
                     accordingly.  */
 
-                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
+                 if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
                      && partial_len < MIPS32_REGSIZE
                      && (typecode == TYPE_CODE_STRUCT
                          || typecode == TYPE_CODE_UNION))
@@ -3415,7 +3571,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                    fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
                                      argreg,
                                      phex (regval, MIPS32_REGSIZE));
-                 write_register (argreg, regval);
+                 regcache_cooked_write_unsigned (regcache, argreg, regval);
                  argreg++;
 
                  /* Prevent subsequent floating point arguments from
@@ -3452,7 +3608,7 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
                       struct regcache *regcache,
                       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT
       || TYPE_CODE (type) == TYPE_CODE_UNION
@@ -3465,11 +3621,11 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
          least significant part of FP0.  */
       if (mips_debug)
        fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
-      mips_xfer_register (regcache,
-                         gdbarch_num_regs (current_gdbarch)
-                           + mips_regnum (current_gdbarch)->fp0,
+      mips_xfer_register (gdbarch, regcache,
+                         gdbarch_num_regs (gdbarch)
+                           + mips_regnum (gdbarch)->fp0,
                          TYPE_LENGTH (type),
-                         gdbarch_byte_order (current_gdbarch),
+                         gdbarch_byte_order (gdbarch),
                          readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3481,30 +3637,30 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
          FP0.  */
       if (mips_debug)
        fprintf_unfiltered (gdb_stderr, "Return float in $fp1/$fp0\n");
-      switch (gdbarch_byte_order (current_gdbarch))
+      switch (gdbarch_byte_order (gdbarch))
        {
        case BFD_ENDIAN_LITTLE:
-         mips_xfer_register (regcache,
-                             gdbarch_num_regs (current_gdbarch)
-                               + mips_regnum (current_gdbarch)->fp0 +
-                             0, 4, gdbarch_byte_order (current_gdbarch),
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch)
+                               + mips_regnum (gdbarch)->fp0 +
+                             0, 4, gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, 0);
-         mips_xfer_register (regcache,
-                             gdbarch_num_regs (current_gdbarch)
-                               + mips_regnum (current_gdbarch)->fp0 + 1,
-                             4, gdbarch_byte_order (current_gdbarch),
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch)
+                               + mips_regnum (gdbarch)->fp0 + 1,
+                             4, gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, 4);
          break;
        case BFD_ENDIAN_BIG:
-         mips_xfer_register (regcache,
-                             gdbarch_num_regs (current_gdbarch)
-                               + mips_regnum (current_gdbarch)->fp0 + 1,
-                             4, gdbarch_byte_order (current_gdbarch),
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch)
+                               + mips_regnum (gdbarch)->fp0 + 1,
+                             4, gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, 0);
-         mips_xfer_register (regcache,
-                             gdbarch_num_regs (current_gdbarch)
-                               + mips_regnum (current_gdbarch)->fp0 + 0,
-                             4, gdbarch_byte_order (current_gdbarch),
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch)
+                               + mips_regnum (gdbarch)->fp0 + 0,
+                             4, gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, 4);
          break;
        default:
@@ -3532,7 +3688,7 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
       gdb_byte reg[MAX_REGISTER_SIZE];
       int regnum;
       int field;
-      for (field = 0, regnum = mips_regnum (current_gdbarch)->fp0;
+      for (field = 0, regnum = mips_regnum (gdbarch)->fp0;
           field < TYPE_NFIELDS (type); field++, regnum += 2)
        {
          int offset = (FIELD_BITPOS (TYPE_FIELDS (type)[field])
@@ -3540,10 +3696,10 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return float struct+%d\n",
                                offset);
-         mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
-                                       + regnum,
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch) + regnum,
                              TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
-                             gdbarch_byte_order (current_gdbarch),
+                             gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -3560,16 +3716,16 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
       int regnum;
       for (offset = 0, regnum = MIPS_V0_REGNUM;
           offset < TYPE_LENGTH (type);
-          offset += register_size (current_gdbarch, regnum), regnum++)
+          offset += register_size (gdbarch, regnum), regnum++)
        {
-         int xfer = register_size (current_gdbarch, regnum);
+         int xfer = register_size (gdbarch, regnum);
          if (offset + xfer > TYPE_LENGTH (type))
            xfer = TYPE_LENGTH (type) - offset;
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return struct+%d:%d in $%d\n",
                                offset, xfer, regnum);
-         mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
-                                       + regnum, xfer,
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch) + regnum, xfer,
                              BFD_ENDIAN_UNKNOWN, readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -3592,9 +3748,9 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
                                offset, xfer, regnum);
-         mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
-                                       + regnum, xfer,
-                             gdbarch_byte_order (current_gdbarch),
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch) + regnum, xfer,
+                             gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -3654,7 +3810,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 
   /* Initialize the integer and float register pointers.  */
   argreg = MIPS_A0_REGNUM;
-  float_argreg = mips_fpa0_regnum (current_gdbarch);
+  float_argreg = mips_fpa0_regnum (gdbarch);
 
   /* The struct_return pointer occupies the first parameter-passing reg.  */
   if (struct_return)
@@ -3663,7 +3819,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        fprintf_unfiltered (gdb_stdlog,
                            "mips_o64_push_dummy_call: struct_return reg=%d 0x%s\n",
                            argreg, paddr_nz (struct_addr));
-      write_register (argreg++, struct_addr);
+      regcache_cooked_write_unsigned (regcache, argreg++, struct_addr);
       stack_offset += MIPS64_REGSIZE;
     }
 
@@ -3702,11 +3858,11 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - fpreg=%d val=%s",
                                float_argreg, phex (regval, len));
-         write_register (float_argreg++, regval);
+         regcache_cooked_write_unsigned (regcache, float_argreg++, regval);
          if (mips_debug)
            fprintf_unfiltered (gdb_stdlog, " - reg=%d val=%s",
                                argreg, phex (regval, len));
-         write_register (argreg, regval);
+         regcache_cooked_write_unsigned (regcache, argreg, regval);
          argreg++;
          /* Reserve space for the FP register.  */
          stack_offset += align_up (len, MIPS64_REGSIZE);
@@ -3741,7 +3897,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                  int longword_offset = 0;
                  CORE_ADDR addr;
                  stack_used_p = 1;
-                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+                 if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
                    {
                      if ((typecode == TYPE_CODE_INT
                           || typecode == TYPE_CODE_PTR
@@ -3793,7 +3949,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                     It does not seem to be necessary to do the
                     same for integral types. */
 
-                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
+                 if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG
                      && partial_len < MIPS64_REGSIZE
                      && (typecode == TYPE_CODE_STRUCT
                          || typecode == TYPE_CODE_UNION))
@@ -3804,7 +3960,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                    fprintf_filtered (gdb_stdlog, " - reg=%d val=%s",
                                      argreg,
                                      phex (regval, MIPS64_REGSIZE));
-                 write_register (argreg, regval);
+                 regcache_cooked_write_unsigned (regcache, argreg, regval);
                  argreg++;
 
                  /* Prevent subsequent floating point arguments from
@@ -3841,7 +3997,7 @@ mips_o64_return_value (struct gdbarch *gdbarch,
                       struct type *type, struct regcache *regcache,
                       gdb_byte *readbuf, const gdb_byte *writebuf)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
   if (TYPE_CODE (type) == TYPE_CODE_STRUCT
       || TYPE_CODE (type) == TYPE_CODE_UNION
@@ -3853,11 +4009,11 @@ mips_o64_return_value (struct gdbarch *gdbarch,
          part of FP0.  */
       if (mips_debug)
        fprintf_unfiltered (gdb_stderr, "Return float in $fp0\n");
-      mips_xfer_register (regcache,
-                         gdbarch_num_regs (current_gdbarch)
-                           + mips_regnum (current_gdbarch)->fp0,
+      mips_xfer_register (gdbarch, regcache,
+                         gdbarch_num_regs (gdbarch)
+                           + mips_regnum (gdbarch)->fp0,
                          TYPE_LENGTH (type),
-                         gdbarch_byte_order (current_gdbarch),
+                         gdbarch_byte_order (gdbarch),
                          readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3877,9 +4033,9 @@ mips_o64_return_value (struct gdbarch *gdbarch,
          if (mips_debug)
            fprintf_unfiltered (gdb_stderr, "Return scalar+%d:%d in $%d\n",
                                offset, xfer, regnum);
-         mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
-                                       + regnum, xfer,
-                             gdbarch_byte_order (current_gdbarch),
+         mips_xfer_register (gdbarch, regcache,
+                             gdbarch_num_regs (gdbarch) + regnum,
+                             xfer, gdbarch_byte_order (gdbarch),
                              readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
@@ -3935,19 +4091,20 @@ static void
 mips_read_fp_register_single (struct frame_info *frame, int regno,
                              gdb_byte *rare_buffer)
 {
-  int raw_size = register_size (current_gdbarch, regno);
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
   gdb_byte *raw_buffer = alloca (raw_size);
 
   if (!frame_register_read (frame, regno, raw_buffer))
     error (_("can't read register %d (%s)"),
-          regno, gdbarch_register_name (current_gdbarch, regno));
+          regno, gdbarch_register_name (gdbarch, regno));
   if (raw_size == 8)
     {
       /* We have a 64-bit value for this register.  Find the low-order
          32 bits.  */
       int offset;
 
-      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
        offset = 4;
       else
        offset = 0;
@@ -3968,26 +4125,29 @@ static void
 mips_read_fp_register_double (struct frame_info *frame, int regno,
                              gdb_byte *rare_buffer)
 {
-  int raw_size = register_size (current_gdbarch, regno);
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  int raw_size = register_size (gdbarch, regno);
 
-  if (raw_size == 8 && !mips2_fp_compat ())
+  if (raw_size == 8 && !mips2_fp_compat (frame))
     {
       /* We have a 64-bit value for this register, and we should use
          all 64 bits.  */
       if (!frame_register_read (frame, regno, rare_buffer))
        error (_("can't read register %d (%s)"),
-              regno, gdbarch_register_name (current_gdbarch, regno));
+              regno, gdbarch_register_name (gdbarch, regno));
     }
   else
     {
-      if ((regno - mips_regnum (current_gdbarch)->fp0) & 1)
+      int rawnum = regno % gdbarch_num_regs (gdbarch);
+
+      if ((rawnum - mips_regnum (gdbarch)->fp0) & 1)
        internal_error (__FILE__, __LINE__,
                        _("mips_read_fp_register_double: bad access to "
                        "odd-numbered FP register"));
 
       /* mips_read_fp_register_single will find the correct 32 bits from
          each register.  */
-      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
        {
          mips_read_fp_register_single (frame, regno, rare_buffer + 4);
          mips_read_fp_register_single (frame, regno + 1, rare_buffer);
@@ -4004,21 +4164,19 @@ static void
 mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
                        int regnum)
 {                              /* do values for FP (float) regs */
+  struct gdbarch *gdbarch = get_frame_arch (frame);
   gdb_byte *raw_buffer;
   double doub, flt1;   /* doubles extracted from raw hex data */
   int inv1, inv2;
 
-  raw_buffer = alloca (2 * register_size (current_gdbarch,
-                                         mips_regnum (current_gdbarch)->fp0));
+  raw_buffer = alloca (2 * register_size (gdbarch, mips_regnum (gdbarch)->fp0));
 
-  fprintf_filtered (file, "%s:",
-                   gdbarch_register_name (current_gdbarch, regnum));
+  fprintf_filtered (file, "%s:", gdbarch_register_name (gdbarch, regnum));
   fprintf_filtered (file, "%*s",
-                   4 - (int) strlen (gdbarch_register_name
-                                       (current_gdbarch, regnum)),
+                   4 - (int) strlen (gdbarch_register_name (gdbarch, regnum)),
                    "");
 
-  if (register_size (current_gdbarch, regnum) == 4 || mips2_fp_compat ())
+  if (register_size (gdbarch, regnum) == 4 || mips2_fp_compat (frame))
     {
       /* 4-byte registers: Print hex and floating.  Also print even
          numbered registers as doubles.  */
@@ -4034,7 +4192,7 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
       else
        fprintf_filtered (file, "%-17.9g", flt1);
 
-      if (regnum % 2 == 0)
+      if ((regnum - gdbarch_num_regs (gdbarch)) % 2 == 0)
        {
          mips_read_fp_register_double (frame, regnum, raw_buffer);
          doub = unpack_double (mips_double_register_type (), raw_buffer,
@@ -4092,11 +4250,11 @@ mips_print_register (struct ui_file *file, struct frame_info *frame,
   if (!frame_register_read (frame, regnum, raw_buffer))
     {
       fprintf_filtered (file, "%s: [Invalid]",
-                       gdbarch_register_name (current_gdbarch, regnum));
+                       gdbarch_register_name (gdbarch, regnum));
       return;
     }
 
-  fputs_filtered (gdbarch_register_name (current_gdbarch, regnum), file);
+  fputs_filtered (gdbarch_register_name (gdbarch, regnum), file);
 
   /* The problem with printing numeric register names (r26, etc.) is that
      the user can't use them on input.  Probably the best solution is to
@@ -4107,10 +4265,9 @@ mips_print_register (struct ui_file *file, struct frame_info *frame,
   else
     fprintf_filtered (file, ": ");
 
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
     offset =
-      register_size (current_gdbarch,
-                    regnum) - register_size (current_gdbarch, regnum);
+      register_size (gdbarch, regnum) - register_size (gdbarch, regnum);
   else
     offset = 0;
 
@@ -4148,18 +4305,17 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
 
   /* For GP registers, we print a separate row of names above the vals */
   for (col = 0, regnum = start_regnum;
-       col < ncols && regnum < gdbarch_num_regs (current_gdbarch)
-                              + gdbarch_num_pseudo_regs (current_gdbarch);
+       col < ncols && regnum < gdbarch_num_regs (gdbarch)
+                              + gdbarch_num_pseudo_regs (gdbarch);
        regnum++)
     {
-      if (*gdbarch_register_name (current_gdbarch, regnum) == '\0')
+      if (*gdbarch_register_name (gdbarch, regnum) == '\0')
        continue;               /* unused register */
       if (TYPE_CODE (register_type (gdbarch, regnum)) ==
          TYPE_CODE_FLT)
        break;                  /* end the row: reached FP register */
       /* Large registers are handled separately.  */
-      if (register_size (current_gdbarch, regnum)
-         > mips_abi_regsize (current_gdbarch))
+      if (register_size (gdbarch, regnum) > mips_abi_regsize (gdbarch))
        {
          if (col > 0)
            break;              /* End the row before this register.  */
@@ -4172,8 +4328,8 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
       if (col == 0)
        fprintf_filtered (file, "     ");
       fprintf_filtered (file,
-                       mips_abi_regsize (current_gdbarch) == 8 ? "%17s" : "%9s",
-                       gdbarch_register_name (current_gdbarch, regnum));
+                       mips_abi_regsize (gdbarch) == 8 ? "%17s" : "%9s",
+                       gdbarch_register_name (gdbarch, regnum));
       col++;
     }
 
@@ -4181,45 +4337,43 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
     return regnum;
 
   /* print the R0 to R31 names */
-  if ((start_regnum % gdbarch_num_regs (current_gdbarch)) < MIPS_NUMREGS)
+  if ((start_regnum % gdbarch_num_regs (gdbarch)) < MIPS_NUMREGS)
     fprintf_filtered (file, "\n R%-4d",
-                     start_regnum % gdbarch_num_regs (current_gdbarch));
+                     start_regnum % gdbarch_num_regs (gdbarch));
   else
     fprintf_filtered (file, "\n      ");
 
   /* now print the values in hex, 4 or 8 to the row */
   for (col = 0, regnum = start_regnum;
-       col < ncols && regnum < gdbarch_num_regs (current_gdbarch)
-                              + gdbarch_num_pseudo_regs (current_gdbarch);
+       col < ncols && regnum < gdbarch_num_regs (gdbarch)
+                              + gdbarch_num_pseudo_regs (gdbarch);
        regnum++)
     {
-      if (*gdbarch_register_name (current_gdbarch, regnum) == '\0')
+      if (*gdbarch_register_name (gdbarch, regnum) == '\0')
        continue;               /* unused register */
       if (TYPE_CODE (register_type (gdbarch, regnum)) ==
          TYPE_CODE_FLT)
        break;                  /* end row: reached FP register */
-      if (register_size (current_gdbarch, regnum)
-         > mips_abi_regsize (current_gdbarch))
+      if (register_size (gdbarch, regnum) > mips_abi_regsize (gdbarch))
        break;                  /* End row: large register.  */
 
       /* OK: get the data in raw format.  */
       if (!frame_register_read (frame, regnum, raw_buffer))
        error (_("can't read register %d (%s)"),
-              regnum, gdbarch_register_name (current_gdbarch, regnum));
+              regnum, gdbarch_register_name (gdbarch, regnum));
       /* pad small registers */
       for (byte = 0;
-          byte < (mips_abi_regsize (current_gdbarch)
-                  - register_size (current_gdbarch, regnum)); byte++)
+          byte < (mips_abi_regsize (gdbarch)
+                  - register_size (gdbarch, regnum)); byte++)
        printf_filtered ("  ");
       /* Now print the register value in hex, endian order. */
-      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
        for (byte =
-            register_size (current_gdbarch,
-                           regnum) - register_size (current_gdbarch, regnum);
-            byte < register_size (current_gdbarch, regnum); byte++)
+            register_size (gdbarch, regnum) - register_size (gdbarch, regnum);
+            byte < register_size (gdbarch, regnum); byte++)
          fprintf_filtered (file, "%02x", raw_buffer[byte]);
       else
-       for (byte = register_size (current_gdbarch, regnum) - 1;
+       for (byte = register_size (gdbarch, regnum) - 1;
             byte >= 0; byte--)
          fprintf_filtered (file, "%02x", raw_buffer[byte]);
       fprintf_filtered (file, " ");
@@ -4239,8 +4393,8 @@ mips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
 {
   if (regnum != -1)            /* do one specified register */
     {
-      gdb_assert (regnum >= gdbarch_num_regs (current_gdbarch));
-      if (*(gdbarch_register_name (current_gdbarch, regnum)) == '\0')
+      gdb_assert (regnum >= gdbarch_num_regs (gdbarch));
+      if (*(gdbarch_register_name (gdbarch, regnum)) == '\0')
        error (_("Not a valid register for the current processor type"));
 
       mips_print_register (file, frame, regnum);
@@ -4249,9 +4403,9 @@ mips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
   else
     /* do all (or most) registers */
     {
-      regnum = gdbarch_num_regs (current_gdbarch);
-      while (regnum < gdbarch_num_regs (current_gdbarch)
-                     + gdbarch_num_pseudo_regs (current_gdbarch))
+      regnum = gdbarch_num_regs (gdbarch);
+      while (regnum < gdbarch_num_regs (gdbarch)
+                     + gdbarch_num_pseudo_regs (gdbarch))
        {
          if (TYPE_CODE (register_type (gdbarch, regnum)) ==
              TYPE_CODE_FLT)
@@ -4345,6 +4499,95 @@ mips_skip_prologue (CORE_ADDR pc)
     return mips32_scan_prologue (pc, limit_pc, NULL, NULL);
 }
 
+/* Check whether the PC is in a function epilogue (32-bit version).
+   This is a helper function for mips_in_function_epilogue_p.  */
+static int
+mips32_in_function_epilogue_p (CORE_ADDR pc)
+{
+  CORE_ADDR func_addr = 0, func_end = 0;
+
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      /* The MIPS epilogue is max. 12 bytes long.  */
+      CORE_ADDR addr = func_end - 12;
+
+      if (addr < func_addr + 4)
+        addr = func_addr + 4;
+      if (pc < addr)
+        return 0;
+
+      for (; pc < func_end; pc += MIPS_INSN32_SIZE)
+       {
+         unsigned long high_word;
+         unsigned long inst;
+
+         inst = mips_fetch_instruction (pc);
+         high_word = (inst >> 16) & 0xffff;
+
+         if (high_word != 0x27bd       /* addiu $sp,$sp,offset */
+             && high_word != 0x67bd    /* daddiu $sp,$sp,offset */
+             && inst != 0x03e00008     /* jr $ra */
+             && inst != 0x00000000)    /* nop */
+           return 0;
+       }
+
+      return 1;
+    }
+
+  return 0;
+}
+
+/* Check whether the PC is in a function epilogue (16-bit version).
+   This is a helper function for mips_in_function_epilogue_p.  */
+static int
+mips16_in_function_epilogue_p (CORE_ADDR pc)
+{
+  CORE_ADDR func_addr = 0, func_end = 0;
+
+  if (find_pc_partial_function (pc, NULL, &func_addr, &func_end))
+    {
+      /* The MIPS epilogue is max. 12 bytes long.  */
+      CORE_ADDR addr = func_end - 12;
+
+      if (addr < func_addr + 4)
+        addr = func_addr + 4;
+      if (pc < addr)
+        return 0;
+
+      for (; pc < func_end; pc += MIPS_INSN16_SIZE)
+       {
+         unsigned short inst;
+
+         inst = mips_fetch_instruction (pc);
+
+         if ((inst & 0xf800) == 0xf000)        /* extend */
+           continue;
+
+         if (inst != 0x6300            /* addiu $sp,offset */
+             && inst != 0xfb00         /* daddiu $sp,$sp,offset */
+             && inst != 0xe820         /* jr $ra */
+             && inst != 0xe8a0         /* jrc $ra */
+             && inst != 0x6500)        /* nop */
+           return 0;
+       }
+
+      return 1;
+    }
+
+  return 0;
+}
+
+/* The epilogue is defined here as the area at the end of a function,
+   after an instruction which destroys the function's stack frame.  */
+static int
+mips_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+  if (mips_pc_is_mips16 (pc))
+    return mips16_in_function_epilogue_p (pc);
+  else
+    return mips32_in_function_epilogue_p (pc);
+}
+
 /* Root of all "set mips "/"show mips " commands. This will eventually be
    used for all MIPS-specific commands.  */
 
@@ -4368,6 +4611,15 @@ static void
 show_mipsfpu_command (char *args, int from_tty)
 {
   char *fpu;
+
+  if (gdbarch_bfd_arch_info (current_gdbarch)->arch != bfd_arch_mips)
+    {
+      printf_unfiltered
+       ("The MIPS floating-point coprocessor is unknown "
+        "because the current architecture is not MIPS.\n");
+      return;
+    }
+
   switch (MIPS_FPU_TYPE)
     {
     case MIPS_FPU_SINGLE:
@@ -4460,7 +4712,7 @@ deprecated_mips_set_processor_regs_hack (void)
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   ULONGEST prid;
 
-  regcache_cooked_read_unsigned (current_regcache,
+  regcache_cooked_read_unsigned (get_current_regcache (),
                                 MIPS_PRID_REGNUM, &prid);
   if ((prid & ~0xf) == 0x700)
     tdep->mips_processor_reg_names = mips_r3041_reg_names;
@@ -4525,9 +4777,9 @@ gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
    should be inserted.  */
 
 static const gdb_byte *
-mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+mips_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *pcptr, int *lenptr)
 {
-  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
     {
       if (mips_pc_is_mips16 (*pcptr))
        {
@@ -4603,7 +4855,7 @@ mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
    gory details.  */
 
 static CORE_ADDR
-mips_skip_trampoline_code (CORE_ADDR pc)
+mips_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
 {
   char *name;
   CORE_ADDR start_addr;
@@ -4616,14 +4868,14 @@ mips_skip_trampoline_code (CORE_ADDR pc)
      target PC is in $31 ($ra).  */
   if (strcmp (name, "__mips16_ret_sf") == 0
       || strcmp (name, "__mips16_ret_df") == 0)
-    return read_signed_register (MIPS_RA_REGNUM);
+    return get_frame_register_signed (frame, MIPS_RA_REGNUM);
 
   if (strncmp (name, "__mips16_call_stub_", 19) == 0)
     {
       /* If the PC is in __mips16_call_stub_{1..10}, this is a call stub
          and the target PC is in $2.  */
       if (name[19] >= '0' && name[19] <= '9')
-       return read_signed_register (2);
+       return get_frame_register_signed (frame, 2);
 
       /* If the PC at the start of __mips16_call_stub_{s,d}f_{0..10}, i.e.
          before the jal instruction, this is effectively a call stub
@@ -4645,7 +4897,7 @@ mips_skip_trampoline_code (CORE_ADDR pc)
                 So scan down to the lui/addi and extract the target
                 address from those two instructions.  */
 
-             CORE_ADDR target_pc = read_signed_register (2);
+             CORE_ADDR target_pc = get_frame_register_signed (frame, 2);
              ULONGEST inst;
              int i;
 
@@ -4676,7 +4928,7 @@ mips_skip_trampoline_code (CORE_ADDR pc)
          else
            /* This is the 'return' part of a call stub.  The return
               address is in $r18.  */
-           return read_signed_register (18);
+           return get_frame_register_signed (frame, 18);
        }
     }
   return 0;                    /* not a stub */
@@ -4730,19 +4982,17 @@ mips_dwarf_dwarf2_ecoff_reg_to_regnum (int num)
 }
 
 static int
-mips_register_sim_regno (int regnum)
+mips_register_sim_regno (struct gdbarch *gdbarch, int regnum)
 {
   /* Only makes sense to supply raw registers.  */
-  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (current_gdbarch));
+  gdb_assert (regnum >= 0 && regnum < gdbarch_num_regs (gdbarch));
   /* FIXME: cagney/2002-05-13: Need to look at the pseudo register to
      decide if it is valid.  Should instead define a standard sim/gdb
      register numbering scheme.  */
-  if (gdbarch_register_name (current_gdbarch,
-                            gdbarch_num_regs
-                              (current_gdbarch) + regnum) != NULL
-      && gdbarch_register_name (current_gdbarch,
-                               gdbarch_num_regs
-                                 (current_gdbarch) + regnum)[0] != '\0')
+  if (gdbarch_register_name (gdbarch,
+                            gdbarch_num_regs (gdbarch) + regnum) != NULL
+      && gdbarch_register_name (gdbarch,
+                               gdbarch_num_regs (gdbarch) + regnum)[0] != '\0')
     return regnum;
   else
     return LEGACY_SIM_REGNO_IGNORE;
@@ -4759,6 +5009,19 @@ mips_integer_to_address (struct gdbarch *gdbarch,
   return (CORE_ADDR) extract_signed_integer (buf, TYPE_LENGTH (type));
 }
 
+/* Dummy virtual frame pointer method.  This is no more or less accurate
+   than most other architectures; we just need to be explicit about it,
+   because the pseudo-register gdbarch_sp_regnum will otherwise lead to
+   an assertion failure.  */
+
+static void
+mips_virtual_frame_pointer (struct gdbarch *gdbarch, 
+                           CORE_ADDR pc, int *reg, LONGEST *offset)
+{
+  *reg = MIPS_SP_REGNUM;
+  *offset = 0;
+}
+
 static void
 mips_find_abi_section (bfd *abfd, asection *sect, void *obj)
 {
@@ -4816,30 +5079,16 @@ global_mips_abi (void)
 static void
 mips_register_g_packet_guesses (struct gdbarch *gdbarch)
 {
-  static struct target_desc *tdesc_gp32, *tdesc_gp64;
-
-  if (tdesc_gp32 == NULL)
-    {
-      /* Create feature sets with the appropriate properties.  The values
-        are not important.  */
-
-      tdesc_gp32 = allocate_target_description ();
-      set_tdesc_property (tdesc_gp32, PROPERTY_GP32, "");
-
-      tdesc_gp64 = allocate_target_description ();
-      set_tdesc_property (tdesc_gp64, PROPERTY_GP64, "");
-    }
-
   /* If the size matches the set of 32-bit or 64-bit integer registers,
      assume that's what we've got.  */
-  register_remote_g_packet_guess (gdbarch, 38 * 4, tdesc_gp32);
-  register_remote_g_packet_guess (gdbarch, 38 * 8, tdesc_gp64);
+  register_remote_g_packet_guess (gdbarch, 38 * 4, mips_tdesc_gp32);
+  register_remote_g_packet_guess (gdbarch, 38 * 8, mips_tdesc_gp64);
 
   /* If the size matches the full set of registers GDB traditionally
      knows about, including floating point, for either 32-bit or
      64-bit, assume that's what we've got.  */
-  register_remote_g_packet_guess (gdbarch, 90 * 4, tdesc_gp32);
-  register_remote_g_packet_guess (gdbarch, 90 * 8, tdesc_gp64);
+  register_remote_g_packet_guess (gdbarch, 90 * 4, mips_tdesc_gp32);
+  register_remote_g_packet_guess (gdbarch, 90 * 8, mips_tdesc_gp64);
 
   /* Otherwise we don't have a useful guess.  */
 }
@@ -4861,6 +5110,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   int i, num_regs;
   enum mips_fpu_type fpu_type;
   struct tdesc_arch_data *tdesc_data = NULL;
+  int elf_fpu_type = 0;
 
   /* Check any target description for validity.  */
   if (tdesc_has_registers (info.target_desc))
@@ -5068,8 +5318,32 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
                        mips64_transfers_32bit_regs_p);
 
   /* Determine the MIPS FPU type.  */
+#ifdef HAVE_ELF
+  if (info.abfd
+      && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
+    elf_fpu_type = bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU,
+                                            Tag_GNU_MIPS_ABI_FP);
+#endif /* HAVE_ELF */
+
   if (!mips_fpu_type_auto)
     fpu_type = mips_fpu_type;
+  else if (elf_fpu_type != 0)
+    {
+      switch (elf_fpu_type)
+       {
+       case 1:
+         fpu_type = MIPS_FPU_DOUBLE;
+         break;
+       case 2:
+         fpu_type = MIPS_FPU_SINGLE;
+         break;
+       case 3:
+       default:
+         /* Soft float or unknown.  */
+         fpu_type = MIPS_FPU_NONE;
+         break;
+       }
+    }
   else if (info.bfd_arch_info != NULL
           && info.bfd_arch_info->arch == bfd_arch_mips)
     switch (info.bfd_arch_info->mach)
@@ -5221,7 +5495,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
        else
          reg_names = mips_generic_reg_names;
       }
-    /* FIXME: cagney/2003-11-15: For MIPS, hasn't PC_REGNUM been
+    /* FIXME: cagney/2003-11-15: For MIPS, hasn't gdbarch_pc_regnum been
        replaced by read_pc?  */
     set_gdbarch_pc_regnum (gdbarch, regnum->pc + num_regs);
     set_gdbarch_sp_regnum (gdbarch, MIPS_SP_REGNUM + num_regs);
@@ -5229,6 +5503,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     set_gdbarch_num_regs (gdbarch, num_regs);
     set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
     set_gdbarch_register_name (gdbarch, mips_register_name);
+    set_gdbarch_virtual_frame_pointer (gdbarch, mips_virtual_frame_pointer);
     tdep->mips_processor_reg_names = reg_names;
     tdep->regnum = regnum;
   }
@@ -5285,7 +5560,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_ptr_bit (gdbarch, 32);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     case MIPS_ABI_N64:
       set_gdbarch_push_dummy_call (gdbarch, mips_n32n64_push_dummy_call);
@@ -5297,7 +5572,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_ptr_bit (gdbarch, 64);
       set_gdbarch_long_long_bit (gdbarch, 64);
       set_gdbarch_long_double_bit (gdbarch, 128);
-      set_gdbarch_long_double_format (gdbarch, floatformats_n32n64_long);
+      set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
       break;
     default:
       internal_error (__FILE__, __LINE__, _("unknown ABI in switch"));
@@ -5415,6 +5690,8 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_skip_prologue (gdbarch, mips_skip_prologue);
 
+  set_gdbarch_in_function_epilogue_p (gdbarch, mips_in_function_epilogue_p);
+
   set_gdbarch_pointer_to_address (gdbarch, signed_pointer_to_address);
   set_gdbarch_address_to_pointer (gdbarch, address_to_signed_pointer);
   set_gdbarch_integer_to_address (gdbarch, mips_integer_to_address);
@@ -5459,7 +5736,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   if (tdesc_data)
     {
       set_tdesc_pseudo_register_type (gdbarch, mips_pseudo_register_type);
-      tdesc_use_registers (gdbarch, tdesc_data);
+      tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
 
       /* Override the normal target description methods to handle our
         dual real and pseudo registers.  */
@@ -5542,9 +5819,9 @@ show_mips_abi (struct ui_file *file,
 }
 
 static void
-mips_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+mips_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file)
 {
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
   if (tdep != NULL)
     {
       int ef_mips_arch;
@@ -5621,6 +5898,14 @@ _initialize_mips_tdep (void)
 
   mips_pdr_data = register_objfile_data ();
 
+  /* Create feature sets with the appropriate properties.  The values
+     are not important.  */
+  mips_tdesc_gp32 = allocate_target_description ();
+  set_tdesc_property (mips_tdesc_gp32, PROPERTY_GP32, "");
+
+  mips_tdesc_gp64 = allocate_target_description ();
+  set_tdesc_property (mips_tdesc_gp64, PROPERTY_GP64, "");
+
   /* Add root prefix command for all "set mips"/"show mips" commands */
   add_prefix_cmd ("mips", no_class, set_mips_command,
                  _("Various MIPS specific commands."),
This page took 0.061446 seconds and 4 git commands to generate.