* lib/gdb.exp (build_id_debug_filename_get): Improve check for
[deliverable/binutils-gdb.git] / gdb / mips-tdep.c
index 974e42a4b0b7e7d635e01608c11aca1f18325cad..db4d9efb0bb9aab3a13711603231210b800ee5d8 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"
@@ -58,6 +56,7 @@
 #include "remote.h"
 #include "target-descriptions.h"
 #include "dwarf2-frame.h"
+#include "user-regs.h"
 
 static const struct objfile_data *mips_pdr_data;
 
@@ -94,6 +93,55 @@ static const char *mips_abi_strings[] = {
   NULL
 };
 
+/* The standard register names, and all the valid aliases for them.  */
+struct register_alias
+{
+  const char *name;
+  int regnum;
+};
+
+/* Aliases for o32 and most other ABIs.  */
+const struct register_alias mips_o32_aliases[] = {
+  { "ta0", 12 },
+  { "ta1", 13 },
+  { "ta2", 14 },
+  { "ta3", 15 }
+};
+
+/* Aliases for n32 and n64.  */
+const struct register_alias mips_n32_n64_aliases[] = {
+  { "ta0", 8 },
+  { "ta1", 9 },
+  { "ta2", 10 },
+  { "ta3", 11 }
+};
+
+/* Aliases for ABI-independent registers.  */
+const struct register_alias mips_register_aliases[] = {
+  /* The architecture manuals specify these ABI-independent names for
+     the GPRs.  */
+#define R(n) { "r" #n, n }
+  R(0), R(1), R(2), R(3), R(4), R(5), R(6), R(7),
+  R(8), R(9), R(10), R(11), R(12), R(13), R(14), R(15),
+  R(16), R(17), R(18), R(19), R(20), R(21), R(22), R(23),
+  R(24), R(25), R(26), R(27), R(28), R(29), R(30), R(31),
+#undef R
+
+  /* k0 and k1 are sometimes called these instead (for "kernel
+     temp").  */
+  { "kt0", 26 },
+  { "kt1", 27 },
+
+  /* This is the traditional GDB name for the CP0 status register.  */
+  { "sr", MIPS_PS_REGNUM },
+
+  /* This is the traditional GDB name for the CP0 BadVAddr register.  */
+  { "bad", MIPS_EMBED_BADVADDR_REGNUM },
+
+  /* This is the traditional GDB name for the FCSR.  */
+  { "fsr", MIPS_EMBED_FP0_REGNUM + 32 }
+};
+
 /* Some MIPS boards don't support floating point while others only
    support single-precision floating-point operations.  */
 
@@ -216,36 +264,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)
@@ -293,7 +311,7 @@ mips_abi_regsize (struct gdbarch *gdbarch)
    marks it as 16-bit function.  The MSB of the minimal symbol's
    "info" field is used for this purpose.
 
-   ELF_MAKE_MSYMBOL_SPECIAL tests whether an ELF symbol is "special",
+   gdbarch_elf_make_msymbol_special tests whether an ELF symbol is "special",
    i.e. refers to a 16-bit function, and sets a "special" bit in a
    minimal symbol to mark it as a 16-bit function
 
@@ -377,7 +395,7 @@ 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)
 {
   /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not
      meaningful.  */
@@ -391,7 +409,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
 
@@ -402,8 +420,6 @@ mips2_fp_compat (void)
 
 static CORE_ADDR heuristic_proc_start (CORE_ADDR);
 
-static CORE_ADDR read_next_frame_reg (struct frame_info *, int);
-
 static void reinit_frame_cache_sfunc (char *, int, struct cmd_list_element *);
 
 static struct type *mips_float_register_type (void);
@@ -509,6 +525,8 @@ 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))
     {
       gdb_assert (rawnum - 32 < NUM_MIPS_PROCESSOR_REGS);
@@ -537,7 +555,8 @@ mips_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
   /* 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 (REGISTER_NAME (regnum) == NULL || REGISTER_NAME (regnum)[0] == '\0')
+  if (gdbarch_register_name (current_gdbarch, regnum) == NULL
+      || gdbarch_register_name (current_gdbarch, regnum)[0] == '\0')
     return 0;
   if (reggroup == float_reggroup)
     return float_p && pseudo;
@@ -556,6 +575,35 @@ mips_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
   return 0;
 }
 
+/* Return the groups that a MIPS register can be categorised into.
+   This version is only used if we have a target description which
+   describes real registers (and their groups).  */
+
+static int
+mips_tdesc_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+                               struct reggroup *reggroup)
+{
+  int rawnum = regnum % gdbarch_num_regs (gdbarch);
+  int pseudo = regnum / gdbarch_num_regs (gdbarch);
+  int ret;
+
+  /* Only save, restore, and display the pseudo registers.  Need to
+     make certain that any code extracting register values from a
+     saved register cache also uses pseudo registers.
+
+     Note: saving and restoring the pseudo registers is slightly
+     strange; if we have 64 bits, we should save and restore all
+     64 bits.  But this is hard and has little benefit.  */
+  if (!pseudo)
+    return 0;
+
+  ret = tdesc_register_in_reggroup_p (gdbarch, rawnum, reggroup);
+  if (ret != -1)
+    return ret;
+
+  return mips_register_reggroup_p (gdbarch, regnum, reggroup);
+}
+
 /* Map the symbol table registers which live in the range [1 *
    gdbarch_num_regs .. 2 * gdbarch_num_regs) back onto the corresponding raw
    registers.  Take care of alignment and size problems.  */
@@ -573,7 +621,7 @@ mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
           register_size (gdbarch, cookednum))
     {
       if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
-         || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+         || gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
        regcache_raw_read_part (regcache, rawnum, 0, 4, buf);
       else
        regcache_raw_read_part (regcache, rawnum, 4, 4, buf);
@@ -596,7 +644,7 @@ mips_pseudo_register_write (struct gdbarch *gdbarch,
           register_size (gdbarch, cookednum))
     {
       if (gdbarch_tdep (gdbarch)->mips64_transfers_32bit_regs_p
-         || TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+         || gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_LITTLE)
        regcache_raw_write_part (regcache, rawnum, 0, 4, buf);
       else
        regcache_raw_write_part (regcache, rawnum, 4, 4, buf);
@@ -641,7 +689,7 @@ set_mips64_transfers_32bit_regs (char *args, int from_tty,
 static int
 mips_convert_register_p (int regnum, struct type *type)
 {
-  return (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+  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
@@ -720,6 +768,59 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
     }
 }
 
+/* Return the GDB type for the pseudo register REGNUM, which is the
+   ABI-level view.  This function is only called if there is a target
+   description which includes registers, so we know precisely the
+   types of hardware registers.  */
+
+static struct type *
+mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
+{
+  const int num_regs = gdbarch_num_regs (gdbarch);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int rawnum = regnum % num_regs;
+  struct type *rawtype;
+
+  gdb_assert (regnum >= num_regs && regnum < 2 * num_regs);
+
+  /* Absent registers are still absent.  */
+  rawtype = gdbarch_register_type (gdbarch, rawnum);
+  if (TYPE_LENGTH (rawtype) == 0)
+    return rawtype;
+
+  if (rawnum >= MIPS_EMBED_FP0_REGNUM && rawnum < MIPS_EMBED_FP0_REGNUM + 32)
+    /* Present the floating point registers however the hardware did;
+       do not try to convert between FPU layouts.  */
+    return rawtype;
+
+  if (rawnum >= MIPS_EMBED_FP0_REGNUM + 32 && rawnum <= MIPS_LAST_EMBED_REGNUM)
+    {
+      /* The pseudo/cooked view of embedded registers is always
+        32-bit, even if the target transfers 64-bit values for them.
+        New targets relying on XML descriptions should only transfer
+        the necessary 32 bits, but older versions of GDB expected 64,
+        so allow the target to provide 64 bits without interfering
+        with the displayed type.  */
+      return builtin_type_int32;
+    }
+
+  /* Use pointer types for registers if we can.  For n32 we can not,
+     since we do not have a 64-bit pointer type.  */
+  if (mips_abi_regsize (gdbarch) == TYPE_LENGTH (builtin_type_void_data_ptr))
+    {
+      if (rawnum == MIPS_SP_REGNUM || rawnum == MIPS_EMBED_BADVADDR_REGNUM)
+       return builtin_type_void_data_ptr;
+      else if (rawnum == MIPS_EMBED_PC_REGNUM)
+       return builtin_type_void_func_ptr;
+    }
+
+  if (mips_abi_regsize (gdbarch) == 4 && TYPE_LENGTH (rawtype) == 8
+      && rawnum >= MIPS_ZERO_REGNUM && rawnum <= MIPS_EMBED_PC_REGNUM)
+    return builtin_type_int32;
+
+  /* For all other registers, pass through the hardware type.  */
+  return rawtype;
+}
 
 /* Should the upper word of 64-bit addresses be zeroed? */
 enum auto_boolean mask_address_var = AUTO_BOOLEAN_AUTO;
@@ -793,9 +894,12 @@ 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
@@ -830,9 +934,10 @@ mips_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *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
@@ -884,7 +989,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;
@@ -915,8 +1020,8 @@ 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 (current_gdbarch)->
+                                               fp_control_status);
          int cond = ((fcrcs >> 24) & 0x0e) | ((fcrcs >> 23) & 0x01);
 
          if (((cond >> cnum) & 0x01) == tf)
@@ -940,7 +1045,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;
@@ -957,7 +1062,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 */
@@ -966,7 +1071,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 */
@@ -996,22 +1101,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;
@@ -1019,7 +1124,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;
@@ -1091,13 +1196,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)
@@ -1200,7 +1303,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);
@@ -1236,7 +1339,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
@@ -1248,7 +1351,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
@@ -1261,7 +1364,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) ; */
@@ -1295,7 +1398,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;
@@ -1307,7 +1410,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:
@@ -1320,24 +1423,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
@@ -1436,8 +1539,9 @@ mips16_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   /* Can be called when there's no process, and hence when there's no
      NEXT_FRAME.  */
   if (next_frame != NULL)
-    sp = read_next_frame_reg (next_frame, gdbarch_num_regs (current_gdbarch)
-                                          + MIPS_SP_REGNUM);
+    sp = frame_unwind_register_signed (next_frame,
+                                      gdbarch_num_regs (current_gdbarch)
+                                      + MIPS_SP_REGNUM);
   else
     sp = 0;
 
@@ -1643,7 +1747,7 @@ 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.  */
+  /* 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, cache->base);
 
@@ -1757,8 +1861,9 @@ mips32_scan_prologue (CORE_ADDR start_pc, CORE_ADDR limit_pc,
   /* Can be called when there's no process, and hence when there's no
      NEXT_FRAME.  */
   if (next_frame != NULL)
-    sp = read_next_frame_reg (next_frame, gdbarch_num_regs (current_gdbarch)
-                                         + MIPS_SP_REGNUM);
+    sp = frame_unwind_register_signed (next_frame,
+                                      gdbarch_num_regs (current_gdbarch)
+                                      + MIPS_SP_REGNUM);
   else
     sp = 0;
 
@@ -1808,14 +1913,15 @@ restart:
          /* Old gcc frame, r30 is virtual frame pointer.  */
          if ((long) low_word != frame_offset)
            frame_addr = sp + low_word;
-         else if (frame_reg == MIPS_SP_REGNUM)
+         else if (next_frame && frame_reg == MIPS_SP_REGNUM)
            {
              unsigned alloca_adjust;
 
              frame_reg = 30;
-             frame_addr = read_next_frame_reg (next_frame,
-                                               gdbarch_num_regs
-                                                 (current_gdbarch) + 30);
+             frame_addr = frame_unwind_register_signed
+                            (next_frame,
+                             gdbarch_num_regs (current_gdbarch) + 30);
+
              alloca_adjust = (unsigned) (frame_addr - (sp + low_word));
              if (alloca_adjust > 0)
                {
@@ -1838,14 +1944,15 @@ restart:
       else if (inst == 0x03A0F021 || inst == 0x03a0f025 || inst == 0x03a0f02d)
        {
          /* New gcc frame, virtual frame pointer is at r30 + frame_size.  */
-         if (frame_reg == MIPS_SP_REGNUM)
+         if (next_frame && frame_reg == MIPS_SP_REGNUM)
            {
              unsigned alloca_adjust;
 
              frame_reg = 30;
-             frame_addr = read_next_frame_reg (next_frame,
-                                               gdbarch_num_regs 
-                                                 (current_gdbarch) + 30);
+             frame_addr = frame_unwind_register_signed
+                            (next_frame,
+                             gdbarch_num_regs (current_gdbarch) + 30);
+
              alloca_adjust = (unsigned) (frame_addr - sp);
              if (alloca_adjust > 0)
                {
@@ -1975,7 +2082,7 @@ 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,
                        cache->base);
@@ -2062,7 +2169,9 @@ 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 (current_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.  */
@@ -2153,22 +2262,6 @@ mips_stub_frame_base_sniffer (struct frame_info *next_frame)
     return NULL;
 }
 
-static CORE_ADDR
-read_next_frame_reg (struct frame_info *fi, int regno)
-{
-  /* Always a pseudo.  */
-  gdb_assert (regno >= gdbarch_num_regs (current_gdbarch));
-  if (fi == NULL)
-    {
-      LONGEST val;
-      regcache_cooked_read_signed (current_regcache, regno, &val);
-      return val;
-    }
-  else
-    return frame_unwind_register_signed (fi, regno);
-
-}
-
 /* mips_addr_bits_remove - remove useless address bits  */
 
 static CORE_ADDR
@@ -2202,12 +2295,12 @@ mips_addr_bits_remove (CORE_ADDR addr)
    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);
+  next_pc = mips_next_pc (frame, pc);
 
   insert_single_step_breakpoint (next_pc);
   return 1;
@@ -2244,7 +2337,7 @@ heuristic_proc_start (CORE_ADDR pc)
   int instlen;
   int seen_adjsp = 0;
 
-  pc = ADDR_BITS_REMOVE (pc);
+  pc = gdbarch_addr_bits_remove (current_gdbarch, pc);
   start_pc = pc;
   fence = start_pc - heuristic_fence_post;
   if (start_pc == 0)
@@ -2301,15 +2394,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 */
@@ -2444,7 +2550,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
@@ -2512,7 +2618,8 @@ 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 = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+             int low_offset = gdbarch_byte_order (current_gdbarch)
+                              == BFD_ENDIAN_BIG ? 4 : 0;
              unsigned long regval;
 
              /* Write the low word of the double to the even register(s).  */
@@ -2520,14 +2627,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
            {
@@ -2539,7 +2646,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
@@ -2576,7 +2683,7 @@ mips_eabi_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                  int longword_offset = 0;
                  CORE_ADDR addr;
                  stack_used_p = 1;
-                 if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
                    {
                      if (regsize == 8
                          && (typecode == TYPE_CODE_INT
@@ -2628,7 +2735,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++;
                }
 
@@ -2672,6 +2779,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,
@@ -2724,7 +2884,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
@@ -2746,23 +2906,22 @@ 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
        {
@@ -2787,17 +2946,19 @@ 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))
+                 || odd_sized_struct)
                {
                  /* 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 (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
                    {
                      if ((typecode == TYPE_CODE_INT
                           || typecode == TYPE_CODE_PTR
@@ -2831,12 +2992,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);
@@ -2850,7 +3009,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 (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
                      && partial_len < MIPS64_REGSIZE
                      && (typecode == TYPE_CODE_STRUCT
                          || typecode == TYPE_CODE_UNION))
@@ -2861,7 +3020,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++;
                }
 
@@ -2911,11 +3083,13 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
       mips_xfer_register (regcache,
                          gdbarch_num_regs (current_gdbarch)
                          + mips_regnum (current_gdbarch)->fp0,
-                         8, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+                         8, gdbarch_byte_order (current_gdbarch),
+                         readbuf, writebuf, 0);
       mips_xfer_register (regcache,
                          gdbarch_num_regs (current_gdbarch)
                          + mips_regnum (current_gdbarch)->fp0 + 2,
-                         8, TARGET_BYTE_ORDER, readbuf ? readbuf + 8 : readbuf,
+                         8, gdbarch_byte_order (current_gdbarch),
+                         readbuf ? readbuf + 8 : readbuf,
                          writebuf ? writebuf + 8 : writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -2930,7 +3104,8 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
                          gdbarch_num_regs (current_gdbarch)
                          + mips_regnum (current_gdbarch)->fp0,
                          TYPE_LENGTH (type),
-                         TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+                         gdbarch_byte_order (current_gdbarch),
+                         readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else if (TYPE_CODE (type) == TYPE_CODE_STRUCT
@@ -2962,7 +3137,8 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
          mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
                                        + regnum,
                              TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
-                             TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+                             gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3008,7 +3184,8 @@ mips_n32n64_return_value (struct gdbarch *gdbarch,
                                offset, xfer, regnum);
          mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
                                        + regnum, xfer,
-                             TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+                             gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3077,7 +3254,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;
     }
 
@@ -3125,7 +3302,8 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
        {
          if (register_size (gdbarch, float_argreg) < 8 && len == 8)
            {
-             int low_offset = TARGET_BYTE_ORDER == BFD_ENDIAN_BIG ? 4 : 0;
+             int low_offset = gdbarch_byte_order (current_gdbarch)
+                              == BFD_ENDIAN_BIG ? 4 : 0;
              unsigned long regval;
 
              /* Write the low word of the double to the even register(s).  */
@@ -3133,23 +3311,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
            {
@@ -3161,7 +3339,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
@@ -3169,7 +3347,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.  */
@@ -3276,7 +3454,7 @@ mips_o32_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                     identified as such and GDB gets tweaked
                     accordingly.  */
 
-                 if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
                      && partial_len < MIPS32_REGSIZE
                      && (typecode == TYPE_CODE_STRUCT
                          || typecode == TYPE_CODE_UNION))
@@ -3287,7 +3465,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
@@ -3341,7 +3519,8 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
                          gdbarch_num_regs (current_gdbarch)
                            + mips_regnum (current_gdbarch)->fp0,
                          TYPE_LENGTH (type),
-                         TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+                         gdbarch_byte_order (current_gdbarch),
+                         readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else if (TYPE_CODE (type) == TYPE_CODE_FLT
@@ -3352,27 +3531,31 @@ 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 (TARGET_BYTE_ORDER)
+      switch (gdbarch_byte_order (current_gdbarch))
        {
        case BFD_ENDIAN_LITTLE:
          mips_xfer_register (regcache,
                              gdbarch_num_regs (current_gdbarch)
                                + mips_regnum (current_gdbarch)->fp0 +
-                             0, 4, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+                             0, 4, gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, 0);
          mips_xfer_register (regcache,
                              gdbarch_num_regs (current_gdbarch)
                                + mips_regnum (current_gdbarch)->fp0 + 1,
-                             4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
+                             4, gdbarch_byte_order (current_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, TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+                             4, gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, 0);
          mips_xfer_register (regcache,
                              gdbarch_num_regs (current_gdbarch)
                                + mips_regnum (current_gdbarch)->fp0 + 0,
-                             4, TARGET_BYTE_ORDER, readbuf, writebuf, 4);
+                             4, gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, 4);
          break;
        default:
          internal_error (__FILE__, __LINE__, _("bad switch"));
@@ -3410,7 +3593,8 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
          mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
                                        + regnum,
                              TYPE_LENGTH (TYPE_FIELD_TYPE (type, field)),
-                             TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+                             gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3460,7 +3644,8 @@ mips_o32_return_value (struct gdbarch *gdbarch, struct type *type,
                                offset, xfer, regnum);
          mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
                                        + regnum, xfer,
-                             TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+                             gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3528,7 +3713,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;
     }
 
@@ -3567,11 +3752,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);
@@ -3606,7 +3791,7 @@ mips_o64_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
                  int longword_offset = 0;
                  CORE_ADDR addr;
                  stack_used_p = 1;
-                 if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
                    {
                      if ((typecode == TYPE_CODE_INT
                           || typecode == TYPE_CODE_PTR
@@ -3658,7 +3843,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 (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG
+                 if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG
                      && partial_len < MIPS64_REGSIZE
                      && (typecode == TYPE_CODE_STRUCT
                          || typecode == TYPE_CODE_UNION))
@@ -3669,7 +3854,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
@@ -3722,7 +3907,8 @@ mips_o64_return_value (struct gdbarch *gdbarch,
                          gdbarch_num_regs (current_gdbarch)
                            + mips_regnum (current_gdbarch)->fp0,
                          TYPE_LENGTH (type),
-                         TARGET_BYTE_ORDER, readbuf, writebuf, 0);
+                         gdbarch_byte_order (current_gdbarch),
+                         readbuf, writebuf, 0);
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
   else
@@ -3743,7 +3929,8 @@ mips_o64_return_value (struct gdbarch *gdbarch,
                                offset, xfer, regnum);
          mips_xfer_register (regcache, gdbarch_num_regs (current_gdbarch)
                                        + regnum, xfer,
-                             TARGET_BYTE_ORDER, readbuf, writebuf, offset);
+                             gdbarch_byte_order (current_gdbarch),
+                             readbuf, writebuf, offset);
        }
       return RETURN_VALUE_REGISTER_CONVENTION;
     }
@@ -3802,14 +3989,15 @@ mips_read_fp_register_single (struct frame_info *frame, int regno,
   gdb_byte *raw_buffer = alloca (raw_size);
 
   if (!frame_register_read (frame, regno, raw_buffer))
-    error (_("can't read register %d (%s)"), regno, REGISTER_NAME (regno));
+    error (_("can't read register %d (%s)"),
+          regno, gdbarch_register_name (current_gdbarch, regno));
   if (raw_size == 8)
     {
       /* We have a 64-bit value for this register.  Find the low-order
          32 bits.  */
       int offset;
 
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
        offset = 4;
       else
        offset = 0;
@@ -3832,12 +4020,13 @@ mips_read_fp_register_double (struct frame_info *frame, int regno,
 {
   int raw_size = register_size (current_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, REGISTER_NAME (regno));
+       error (_("can't read register %d (%s)"),
+              regno, gdbarch_register_name (current_gdbarch, regno));
     }
   else
     {
@@ -3848,7 +4037,7 @@ mips_read_fp_register_double (struct frame_info *frame, int regno,
 
       /* mips_read_fp_register_single will find the correct 32 bits from
          each register.  */
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
        {
          mips_read_fp_register_single (frame, regno, rare_buffer + 4);
          mips_read_fp_register_single (frame, regno + 1, rare_buffer);
@@ -3872,11 +4061,14 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
   raw_buffer = alloca (2 * register_size (current_gdbarch,
                                          mips_regnum (current_gdbarch)->fp0));
 
-  fprintf_filtered (file, "%s:", REGISTER_NAME (regnum));
-  fprintf_filtered (file, "%*s", 4 - (int) strlen (REGISTER_NAME (regnum)),
+  fprintf_filtered (file, "%s:",
+                   gdbarch_register_name (current_gdbarch, regnum));
+  fprintf_filtered (file, "%*s",
+                   4 - (int) strlen (gdbarch_register_name
+                                       (current_gdbarch, regnum)),
                    "");
 
-  if (register_size (current_gdbarch, regnum) == 4 || mips2_fp_compat ())
+  if (register_size (current_gdbarch, regnum) == 4 || mips2_fp_compat (frame))
     {
       /* 4-byte registers: Print hex and floating.  Also print even
          numbered registers as doubles.  */
@@ -3934,7 +4126,7 @@ mips_print_fp_register (struct ui_file *file, struct frame_info *frame,
 
 static void
 mips_print_register (struct ui_file *file, struct frame_info *frame,
-                    int regnum, int all)
+                    int regnum)
 {
   struct gdbarch *gdbarch = get_frame_arch (frame);
   gdb_byte raw_buffer[MAX_REGISTER_SIZE];
@@ -3949,11 +4141,12 @@ mips_print_register (struct ui_file *file, struct frame_info *frame,
   /* Get the data in raw format.  */
   if (!frame_register_read (frame, regnum, raw_buffer))
     {
-      fprintf_filtered (file, "%s: [Invalid]", REGISTER_NAME (regnum));
+      fprintf_filtered (file, "%s: [Invalid]",
+                       gdbarch_register_name (current_gdbarch, regnum));
       return;
     }
 
-  fputs_filtered (REGISTER_NAME (regnum), file);
+  fputs_filtered (gdbarch_register_name (current_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
@@ -3964,7 +4157,7 @@ mips_print_register (struct ui_file *file, struct frame_info *frame,
   else
     fprintf_filtered (file, ": ");
 
-  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
     offset =
       register_size (current_gdbarch,
                     regnum) - register_size (current_gdbarch, regnum);
@@ -4009,16 +4202,28 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
                               + gdbarch_num_pseudo_regs (current_gdbarch);
        regnum++)
     {
-      if (*REGISTER_NAME (regnum) == '\0')
+      if (*gdbarch_register_name (current_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 (col > 0)
+           break;              /* End the row before this register.  */
+
+         /* Print this register on a row by itself.  */
+         mips_print_register (file, frame, regnum);
+         fprintf_filtered (file, "\n");
+         return regnum + 1;
+       }
       if (col == 0)
        fprintf_filtered (file, "     ");
       fprintf_filtered (file,
                        mips_abi_regsize (current_gdbarch) == 8 ? "%17s" : "%9s",
-                       REGISTER_NAME (regnum));
+                       gdbarch_register_name (current_gdbarch, regnum));
       col++;
     }
 
@@ -4038,21 +4243,26 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
                               + gdbarch_num_pseudo_regs (current_gdbarch);
        regnum++)
     {
-      if (*REGISTER_NAME (regnum) == '\0')
+      if (*gdbarch_register_name (current_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))
+       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, REGISTER_NAME (regnum));
+       error (_("can't read register %d (%s)"),
+              regnum, gdbarch_register_name (current_gdbarch, regnum));
       /* pad small registers */
       for (byte = 0;
           byte < (mips_abi_regsize (current_gdbarch)
                   - register_size (current_gdbarch, regnum)); byte++)
        printf_filtered ("  ");
       /* Now print the register value in hex, endian order. */
-      if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+      if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
        for (byte =
             register_size (current_gdbarch,
                            regnum) - register_size (current_gdbarch, regnum);
@@ -4080,10 +4290,10 @@ 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 (*(REGISTER_NAME (regnum)) == '\0')
+      if (*(gdbarch_register_name (current_gdbarch, regnum)) == '\0')
        error (_("Not a valid register for the current processor type"));
 
-      mips_print_register (file, frame, regnum, 0);
+      mips_print_register (file, frame, regnum);
       fprintf_filtered (file, "\n");
     }
   else
@@ -4298,10 +4508,10 @@ void
 deprecated_mips_set_processor_regs_hack (void)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
-  CORE_ADDR prid;
-
-  prid = read_register (MIPS_PRID_REGNUM);
+  ULONGEST prid;
 
+  regcache_cooked_read_unsigned (get_current_regcache (),
+                                MIPS_PRID_REGNUM, &prid);
   if ((prid & ~0xf) == 0x700)
     tdep->mips_processor_reg_names = mips_r3041_reg_names;
 }
@@ -4351,23 +4561,23 @@ gdb_print_insn_mips (bfd_vma memaddr, struct disassemble_info *info)
     info->disassembler_options = "gpr-names=32";
 
   /* Call the appropriate disassembler based on the target endian-ness.  */
-  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
     return print_insn_big_mips (memaddr, info);
   else
     return print_insn_little_mips (memaddr, info);
 }
 
-/* This function implements the BREAKPOINT_FROM_PC macro.  It uses the program
-   counter value to determine whether a 16- or 32-bit breakpoint should be
-   used.  It returns a pointer to a string of bytes that encode a breakpoint
-   instruction, stores the length of the string to *lenptr, and adjusts pc
-   (if necessary) to point to the actual memory location where the
-   breakpoint should be inserted.  */
+/* This function implements gdbarch_breakpoint_from_pc.  It uses the program
+   counter value to determine whether a 16- or 32-bit breakpoint should be used.
+   It returns a pointer to a string of bytes that encode a breakpoint
+   instruction, stores the length of the string to *lenptr, and adjusts pc (if
+   necessary) to point to the actual memory location where the breakpoint
+   should be inserted.  */
 
 static const gdb_byte *
 mips_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
-  if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG)
+  if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG)
     {
       if (mips_pc_is_mips16 (*pcptr))
        {
@@ -4443,7 +4653,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;
@@ -4456,14 +4666,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
@@ -4485,7 +4695,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;
 
@@ -4516,7 +4726,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 */
@@ -4577,8 +4787,12 @@ mips_register_sim_regno (int regnum)
   /* 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 (REGISTER_NAME (gdbarch_num_regs (current_gdbarch) + regnum) != NULL
-      && REGISTER_NAME (gdbarch_num_regs (current_gdbarch) + regnum)[0] != '\0')
+  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')
     return regnum;
   else
     return LEGACY_SIM_REGNO_IGNORE;
@@ -4680,6 +4894,13 @@ mips_register_g_packet_guesses (struct gdbarch *gdbarch)
   /* Otherwise we don't have a useful guess.  */
 }
 
+static struct value *
+value_of_mips_user_reg (struct frame_info *frame, const void *baton)
+{
+  const int *reg_p = baton;
+  return value_of_register (*reg_p, frame);
+}
+
 static struct gdbarch *
 mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
@@ -4687,8 +4908,109 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   struct gdbarch_tdep *tdep;
   int elf_flags;
   enum mips_abi mips_abi, found_abi, wanted_abi;
-  int num_regs;
+  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))
+    {
+      static const char *const mips_gprs[] = {
+       "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+       "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+       "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+       "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31"
+      };
+      static const char *const mips_fprs[] = {
+       "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
+       "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
+       "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23",
+       "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31",
+      };
+
+      const struct tdesc_feature *feature;
+      int valid_p;
+
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.mips.cpu");
+      if (feature == NULL)
+       return NULL;
+
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = MIPS_ZERO_REGNUM; i <= MIPS_RA_REGNUM; i++)
+       valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                           mips_gprs[i]);
+
+
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_EMBED_LO_REGNUM, "lo");
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_EMBED_HI_REGNUM, "hi");
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_EMBED_PC_REGNUM, "pc");
+
+      if (!valid_p)
+       {
+         tdesc_data_cleanup (tdesc_data);
+         return NULL;
+       }
+
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.mips.cp0");
+      if (feature == NULL)
+       {
+         tdesc_data_cleanup (tdesc_data);
+         return NULL;
+       }
+
+      valid_p = 1;
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_EMBED_BADVADDR_REGNUM,
+                                         "badvaddr");
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_PS_REGNUM, "status");
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_EMBED_CAUSE_REGNUM, "cause");
+
+      if (!valid_p)
+       {
+         tdesc_data_cleanup (tdesc_data);
+         return NULL;
+       }
+
+      /* FIXME drow/2007-05-17: The FPU should be optional.  The MIPS
+        backend is not prepared for that, though.  */
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.mips.fpu");
+      if (feature == NULL)
+       {
+         tdesc_data_cleanup (tdesc_data);
+         return NULL;
+       }
+
+      valid_p = 1;
+      for (i = 0; i < 32; i++)
+       valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                           i + MIPS_EMBED_FP0_REGNUM,
+                                           mips_fprs[i]);
+
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_EMBED_FP0_REGNUM + 32, "fcsr");
+      valid_p &= tdesc_numbered_register (feature, tdesc_data,
+                                         MIPS_EMBED_FP0_REGNUM + 33, "fir");
+
+      if (!valid_p)
+       {
+         tdesc_data_cleanup (tdesc_data);
+         return NULL;
+       }
+
+      /* It would be nice to detect an attempt to use a 64-bit ABI
+        when only 32-bit registers are provided.  */
+    }
 
   /* First of all, extract the elf_flags, if available.  */
   if (info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour)
@@ -4797,8 +5119,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)
@@ -4832,7 +5178,11 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       && tdesc_property (info.target_desc, PROPERTY_GP32) != NULL
       && mips_abi != MIPS_ABI_EABI32
       && mips_abi != MIPS_ABI_O32)
-    return NULL;
+    {
+      if (tdesc_data != NULL)
+       tdesc_data_cleanup (tdesc_data);
+      return NULL;
+    }
 
   /* try to find a pre-existing architecture */
   for (arches = gdbarch_list_lookup_by_info (arches, &info);
@@ -4853,6 +5203,9 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       /* Be pedantic about which FPU is selected.  */
       if (gdbarch_tdep (arches->gdbarch)->mips_fpu_type != fpu_type)
        continue;
+
+      if (tdesc_data != NULL)
+       tdesc_data_cleanup (tdesc_data);
       return arches->gdbarch;
     }
 
@@ -4900,7 +5253,20 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
     const char **reg_names;
     struct mips_regnum *regnum = GDBARCH_OBSTACK_ZALLOC (gdbarch,
                                                         struct mips_regnum);
-    if (info.osabi == GDB_OSABI_IRIX)
+    if (tdesc_has_registers (info.target_desc))
+      {
+       regnum->lo = MIPS_EMBED_LO_REGNUM;
+       regnum->hi = MIPS_EMBED_HI_REGNUM;
+       regnum->badvaddr = MIPS_EMBED_BADVADDR_REGNUM;
+       regnum->cause = MIPS_EMBED_CAUSE_REGNUM;
+       regnum->pc = MIPS_EMBED_PC_REGNUM;
+       regnum->fp0 = MIPS_EMBED_FP0_REGNUM;
+       regnum->fp_control_status = 70;
+       regnum->fp_implementation_revision = 71;
+       num_regs = MIPS_LAST_EMBED_REGNUM + 1;
+       reg_names = NULL;
+      }
+    else if (info.osabi == GDB_OSABI_IRIX)
       {
        regnum->fp0 = 32;
        regnum->pc = 64;
@@ -4930,7 +5296,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);
@@ -5152,6 +5518,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   mips_register_g_packet_guesses (gdbarch);
 
   /* Hook in OS ABI-specific overrides, if they have been registered.  */
+  info.tdep_info = (void *) tdesc_data;
   gdbarch_init_osabi (info, gdbarch);
 
   /* Unwind the frame.  */
@@ -5164,6 +5531,37 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   frame_base_append_sniffer (gdbarch, mips_insn16_frame_base_sniffer);
   frame_base_append_sniffer (gdbarch, mips_insn32_frame_base_sniffer);
 
+  if (tdesc_data)
+    {
+      set_tdesc_pseudo_register_type (gdbarch, mips_pseudo_register_type);
+      tdesc_use_registers (gdbarch, tdesc_data);
+
+      /* Override the normal target description methods to handle our
+        dual real and pseudo registers.  */
+      set_gdbarch_register_name (gdbarch, mips_register_name);
+      set_gdbarch_register_reggroup_p (gdbarch, mips_tdesc_register_reggroup_p);
+
+      num_regs = gdbarch_num_regs (gdbarch);
+      set_gdbarch_num_pseudo_regs (gdbarch, num_regs);
+      set_gdbarch_pc_regnum (gdbarch, tdep->regnum->pc + num_regs);
+      set_gdbarch_sp_regnum (gdbarch, MIPS_SP_REGNUM + num_regs);
+    }
+
+  /* Add ABI-specific aliases for the registers.  */
+  if (mips_abi == MIPS_ABI_N32 || mips_abi == MIPS_ABI_N64)
+    for (i = 0; i < ARRAY_SIZE (mips_n32_n64_aliases); i++)
+      user_reg_add (gdbarch, mips_n32_n64_aliases[i].name,
+                   value_of_mips_user_reg, &mips_n32_n64_aliases[i].regnum);
+  else
+    for (i = 0; i < ARRAY_SIZE (mips_o32_aliases); i++)
+      user_reg_add (gdbarch, mips_o32_aliases[i].name,
+                   value_of_mips_user_reg, &mips_o32_aliases[i].regnum);
+
+  /* Add some other standard aliases.  */
+  for (i = 0; i < ARRAY_SIZE (mips_register_aliases); i++)
+    user_reg_add (gdbarch, mips_register_aliases[i].name,
+                 value_of_mips_user_reg, &mips_register_aliases[i].regnum);
+
   return gdbarch;
 }
 
This page took 0.049969 seconds and 4 git commands to generate.