Updated copyright notices for most files.
[deliverable/binutils-gdb.git] / gdb / m68k-tdep.c
index fb6d73d298ab49960b5df857d062215614500351..a42f699d746f6c2a77437597433d99fe6cf17e80 100644 (file)
@@ -1,13 +1,13 @@
 /* Target-dependent code for the Motorola 68000 series.
 
-   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+   Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1999, 2000, 2001,
+   2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    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,
    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 "dwarf2-frame.h"
 #include "frame.h"
 #include "frame-base.h"
 #include "frame-unwind.h"
-#include "floatformat.h"
+#include "gdbtypes.h"
 #include "symtab.h"
 #include "gdbcore.h"
 #include "value.h"
@@ -36,6 +34,7 @@
 #include "arch-utils.h"
 #include "osabi.h"
 #include "dis-asm.h"
+#include "target-descriptions.h"
 
 #include "m68k-tdep.h"
 \f
 #define P_MOVEL_SP     0x2f00
 #define P_MOVEML_SP    0x48e7
 
-
-#define REGISTER_BYTES_FP (16*4 + 8 + 8*12 + 3*4)
-#define REGISTER_BYTES_NOFP (16*4 + 8)
-
 /* Offset from SP to first arg on stack at first instruction of a function */
 #define SP_ARG0 (1 * 4)
 
 #endif
 
 static const gdb_byte *
-m68k_local_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
+m68k_local_breakpoint_from_pc (struct gdbarch *gdbarch,
+                              CORE_ADDR *pcptr, int *lenptr)
 {
   static gdb_byte break_insn[] = {0x4e, (0x40 | BPT_VECTOR)};
   *lenptr = sizeof (break_insn);
   return break_insn;
 }
+\f
 
+/* Type for %ps.  */
+struct type *m68k_ps_type;
 
-static int
-m68k_register_bytes_ok (long numbytes)
+/* Construct types for ISA-specific registers.  */
+static void
+m68k_init_types (void)
 {
-  return ((numbytes == REGISTER_BYTES_FP)
-         || (numbytes == REGISTER_BYTES_NOFP));
+  struct type *type;
+
+  type = init_flags_type ("builtin_type_m68k_ps", 4);
+  append_flags_type_flag (type, 0, "C");
+  append_flags_type_flag (type, 1, "V");
+  append_flags_type_flag (type, 2, "Z");
+  append_flags_type_flag (type, 3, "N");
+  append_flags_type_flag (type, 4, "X");
+  append_flags_type_flag (type, 8, "I0");
+  append_flags_type_flag (type, 9, "I1");
+  append_flags_type_flag (type, 10, "I2");
+  append_flags_type_flag (type, 12, "M");
+  append_flags_type_flag (type, 13, "S");
+  append_flags_type_flag (type, 14, "T0");
+  append_flags_type_flag (type, 15, "T1");
+  m68k_ps_type = type;
 }
 
 /* Return the GDB type object for the "standard" data type of data in
@@ -92,50 +106,74 @@ m68k_register_bytes_ok (long numbytes)
 static struct type *
 m68k_register_type (struct gdbarch *gdbarch, int regnum)
 {
-  if (regnum >= FP0_REGNUM && regnum <= FP0_REGNUM + 7)
-    return builtin_type_m68881_ext;
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (regnum == M68K_FPI_REGNUM || regnum == PC_REGNUM)
-    return builtin_type_void_func_ptr;
+  if (tdep->fpregs_present)
+    {
+      if (regnum >= gdbarch_fp0_regnum (gdbarch)
+         && regnum <= gdbarch_fp0_regnum (gdbarch) + 7)
+       {
+         if (tdep->flavour == m68k_coldfire_flavour)
+           return builtin_type (gdbarch)->builtin_double;
+         else
+           return builtin_type_m68881_ext;
+       }
+
+      if (regnum == M68K_FPI_REGNUM)
+       return builtin_type_void_func_ptr;
 
-  if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM
-      || regnum == PS_REGNUM)
-    return builtin_type_int32;
+      if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM)
+       return builtin_type_int32;
+    }
+  else
+    {
+      if (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FPI_REGNUM)
+       return builtin_type_int0;
+    }
+
+  if (regnum == gdbarch_pc_regnum (gdbarch))
+    return builtin_type_void_func_ptr;
 
   if (regnum >= M68K_A0_REGNUM && regnum <= M68K_A0_REGNUM + 7)
     return builtin_type_void_data_ptr;
 
+  if (regnum == M68K_PS_REGNUM)
+    return m68k_ps_type;
+
   return builtin_type_int32;
 }
 
-/* Function: m68k_register_name
-   Returns the name of the standard m68k register regnum. */
-
-static const char *
-m68k_register_name (int regnum)
-{
-  static char *register_names[] = {
+static const char *m68k_register_names[] = {
     "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
     "a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp",
     "ps", "pc",
     "fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7",
-    "fpcontrol", "fpstatus", "fpiaddr", "fpcode", "fpflags"
+    "fpcontrol", "fpstatus", "fpiaddr"
   };
 
-  if (regnum < 0 || regnum >= ARRAY_SIZE (register_names))
+/* Function: m68k_register_name
+   Returns the name of the standard m68k register regnum. */
+
+static const char *
+m68k_register_name (struct gdbarch *gdbarch, int regnum)
+{
+  if (regnum < 0 || regnum >= ARRAY_SIZE (m68k_register_names))
     internal_error (__FILE__, __LINE__,
                    _("m68k_register_name: illegal register number %d"), regnum);
   else
-    return register_names[regnum];
+    return m68k_register_names[regnum];
 }
 \f
 /* Return nonzero if a value of type TYPE stored in register REGNUM
    needs any special handling.  */
 
 static int
-m68k_convert_register_p (int regnum, struct type *type)
+m68k_convert_register_p (struct gdbarch *gdbarch, int regnum, struct type *type)
 {
-  return (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FP0_REGNUM + 7);
+  if (!gdbarch_tdep (gdbarch)->fpregs_present)
+    return 0;
+  return (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FP0_REGNUM + 7
+         && type != builtin_type_m68881_ext);
 }
 
 /* Read a value of type TYPE from register REGNUM in frame FRAME, and
@@ -146,6 +184,8 @@ m68k_register_to_value (struct frame_info *frame, int regnum,
                        struct type *type, gdb_byte *to)
 {
   gdb_byte from[M68K_MAX_REGISTER_SIZE];
+  struct type *fpreg_type = register_type (get_frame_arch (frame),
+                                          M68K_FP0_REGNUM);
 
   /* We only support floating-point values.  */
   if (TYPE_CODE (type) != TYPE_CODE_FLT)
@@ -155,10 +195,9 @@ m68k_register_to_value (struct frame_info *frame, int regnum,
       return;
     }
 
-  /* Convert to TYPE.  This should be a no-op if TYPE is equivalent to
-     the extended floating-point format used by the FPU.  */
+  /* Convert to TYPE.  */
   get_frame_register (frame, regnum, from);
-  convert_typed_floating (from, builtin_type_m68881_ext, to, type);
+  convert_typed_floating (from, fpreg_type, to, type);
 }
 
 /* Write the contents FROM of a value of type TYPE into register
@@ -169,6 +208,8 @@ m68k_value_to_register (struct frame_info *frame, int regnum,
                        struct type *type, const gdb_byte *from)
 {
   gdb_byte to[M68K_MAX_REGISTER_SIZE];
+  struct type *fpreg_type = register_type (get_frame_arch (frame),
+                                          M68K_FP0_REGNUM);
 
   /* We only support floating-point values.  */
   if (TYPE_CODE (type) != TYPE_CODE_FLT)
@@ -178,9 +219,8 @@ m68k_value_to_register (struct frame_info *frame, int regnum,
       return;
     }
 
-  /* Convert from TYPE.  This should be a no-op if TYPE is equivalent
-     to the extended floating-point format used by the FPU.  */
-  convert_typed_floating (from, type, to, builtin_type_m68881_ext);
+  /* Convert from TYPE.  */
+  convert_typed_floating (from, type, to, fpreg_type);
   put_frame_register (frame, regnum, to);
 }
 
@@ -246,11 +286,14 @@ m68k_svr4_extract_return_value (struct type *type, struct regcache *regcache,
 {
   int len = TYPE_LENGTH (type);
   gdb_byte buf[M68K_MAX_REGISTER_SIZE];
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
     {
+      struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM);
       regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
-      convert_typed_floating (buf, builtin_type_m68881_ext, valbuf, type);
+      convert_typed_floating (buf, fpreg_type, valbuf, type);
     }
   else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
     regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
@@ -284,11 +327,14 @@ m68k_svr4_store_return_value (struct type *type, struct regcache *regcache,
                              const gdb_byte *valbuf)
 {
   int len = TYPE_LENGTH (type);
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
     {
+      struct type *fpreg_type = register_type (gdbarch, M68K_FP0_REGNUM);
       gdb_byte buf[M68K_MAX_REGISTER_SIZE];
-      convert_typed_floating (valbuf, type, buf, builtin_type_m68881_ext);
+      convert_typed_floating (valbuf, type, buf, fpreg_type);
       regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
     }
   else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
@@ -481,7 +527,7 @@ m68k_push_dummy_call (struct gdbarch *gdbarch, struct value *function,
 /* Convert a dwarf or dwarf2 regnumber to a GDB regnum.  */
 
 static int
-m68k_dwarf_reg_to_regnum (int num)
+m68k_dwarf_reg_to_regnum (struct gdbarch *gdbarch, int num)
 {
   if (num < 8)
     /* d0..7 */
@@ -489,14 +535,14 @@ m68k_dwarf_reg_to_regnum (int num)
   else if (num < 16)
     /* a0..7 */
     return (num - 8) + M68K_A0_REGNUM;
-  else if (num < 24)
+  else if (num < 24 && gdbarch_tdep (gdbarch)->fpregs_present)
     /* fp0..7 */
     return (num - 16) + M68K_FP0_REGNUM;
   else if (num == 25)
     /* pc */
     return M68K_PC_REGNUM;
   else
-    return NUM_REGS + NUM_PSEUDO_REGS;
+    return gdbarch_num_regs (gdbarch) + gdbarch_num_pseudo_regs (gdbarch);
 }
 
 \f
@@ -657,7 +703,8 @@ m68k_analyze_register_saves (CORE_ADDR pc, CORE_ADDR current_pc,
       while (pc < current_pc)
        {
          op = read_memory_unsigned_integer (pc, 2);
-         if (op == P_FMOVEMX_SP)
+         if (op == P_FMOVEMX_SP
+             && gdbarch_tdep (current_gdbarch)->fpregs_present)
            {
              /* fmovem.x REGS,-(%sp) */
              op = read_memory_unsigned_integer (pc + 2, 2);
@@ -783,7 +830,7 @@ m68k_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   gdb_byte buf[8];
 
-  frame_unwind_register (next_frame, PC_REGNUM, buf);
+  frame_unwind_register (next_frame, gdbarch_pc_regnum (gdbarch), buf);
   return extract_typed_address (buf, builtin_type_void_func_ptr);
 }
 \f
@@ -819,7 +866,7 @@ m68k_frame_cache (struct frame_info *next_frame, void **this_cache)
   /* For normal frames, %pc is stored at 4(%fp).  */
   cache->saved_regs[M68K_PC_REGNUM] = 4;
 
-  cache->pc = frame_func_unwind (next_frame);
+  cache->pc = frame_func_unwind (next_frame, NORMAL_FRAME);
   if (cache->pc != 0)
     m68k_analyze_prologue (cache->pc, frame_pc_unwind (next_frame), cache);
 
@@ -898,7 +945,7 @@ m68k_frame_prev_register (struct frame_info *next_frame, void **this_cache,
        {
          /* Read the value in from memory.  */
          read_memory (*addrp, valuep,
-                      register_size (current_gdbarch, regnum));
+                      register_size (get_frame_arch (next_frame), regnum));
        }
       return;
     }
@@ -953,139 +1000,6 @@ m68k_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame)
   return frame_id_build (fp + 8, frame_pc_unwind (next_frame));
 }
 \f
-#ifdef USE_PROC_FS             /* Target dependent support for /proc */
-
-#include <sys/procfs.h>
-
-/* Prototypes for supply_gregset etc. */
-#include "gregset.h"
-
-/*  The /proc interface divides the target machine's register set up into
-   two different sets, the general register set (gregset) and the floating
-   point register set (fpregset).  For each set, there is an ioctl to get
-   the current register set and another ioctl to set the current values.
-
-   The actual structure passed through the ioctl interface is, of course,
-   naturally machine dependent, and is different for each set of registers.
-   For the m68k for example, the general register set is typically defined
-   by:
-
-   typedef int gregset_t[18];
-
-   #define      R_D0    0
-   ...
-   #define      R_PS    17
-
-   and the floating point set by:
-
-   typedef      struct fpregset {
-   int  f_pcr;
-   int  f_psr;
-   int  f_fpiaddr;
-   int  f_fpregs[8][3];         (8 regs, 96 bits each)
-   } fpregset_t;
-
-   These routines provide the packing and unpacking of gregset_t and
-   fpregset_t formatted data.
-
- */
-
-/* Atari SVR4 has R_SR but not R_PS */
-
-#if !defined (R_PS) && defined (R_SR)
-#define R_PS R_SR
-#endif
-
-/*  Given a pointer to a general register set in /proc format (gregset_t *),
-   unpack the register contents and supply them as gdb's idea of the current
-   register values. */
-
-void
-supply_gregset (gregset_t *gregsetp)
-{
-  int regi;
-  greg_t *regp = (greg_t *) gregsetp;
-
-  for (regi = 0; regi < R_PC; regi++)
-    {
-      regcache_raw_supply (current_regcache, regi, (char *) (regp + regi));
-    }
-  regcache_raw_supply (current_regcache, PS_REGNUM, (char *) (regp + R_PS));
-  regcache_raw_supply (current_regcache, PC_REGNUM, (char *) (regp + R_PC));
-}
-
-void
-fill_gregset (gregset_t *gregsetp, int regno)
-{
-  int regi;
-  greg_t *regp = (greg_t *) gregsetp;
-
-  for (regi = 0; regi < R_PC; regi++)
-    {
-      if (regno == -1 || regno == regi)
-       regcache_raw_collect (current_regcache, regi, regp + regi);
-    }
-  if (regno == -1 || regno == PS_REGNUM)
-    regcache_raw_collect (current_regcache, PS_REGNUM, regp + R_PS);
-  if (regno == -1 || regno == PC_REGNUM)
-    regcache_raw_collect (current_regcache, PC_REGNUM, regp + R_PC);
-}
-
-#if defined (FP0_REGNUM)
-
-/*  Given a pointer to a floating point register set in /proc format
-   (fpregset_t *), unpack the register contents and supply them as gdb's
-   idea of the current floating point register values. */
-
-void
-supply_fpregset (fpregset_t *fpregsetp)
-{
-  int regi;
-  char *from;
-
-  for (regi = FP0_REGNUM; regi < M68K_FPC_REGNUM; regi++)
-    {
-      from = (char *) &(fpregsetp->f_fpregs[regi - FP0_REGNUM][0]);
-      regcache_raw_supply (current_regcache, regi, from);
-    }
-  regcache_raw_supply (current_regcache, M68K_FPC_REGNUM,
-                      (char *) &(fpregsetp->f_pcr));
-  regcache_raw_supply (current_regcache, M68K_FPS_REGNUM,
-                      (char *) &(fpregsetp->f_psr));
-  regcache_raw_supply (current_regcache, M68K_FPI_REGNUM,
-                      (char *) &(fpregsetp->f_fpiaddr));
-}
-
-/*  Given a pointer to a floating point register set in /proc format
-   (fpregset_t *), update the register specified by REGNO from gdb's idea
-   of the current floating point register set.  If REGNO is -1, update
-   them all. */
-
-void
-fill_fpregset (fpregset_t *fpregsetp, int regno)
-{
-  int regi;
-
-  for (regi = FP0_REGNUM; regi < M68K_FPC_REGNUM; regi++)
-    {
-      if (regno == -1 || regno == regi)
-       regcache_raw_collect (current_regcache, regi,
-                             &fpregsetp->f_fpregs[regi - FP0_REGNUM][0]);
-    }
-  if (regno == -1 || regno == M68K_FPC_REGNUM)
-    regcache_raw_collect (current_regcache, M68K_FPC_REGNUM,
-                         &fpregsetp->f_pcr);
-  if (regno == -1 || regno == M68K_FPS_REGNUM)
-    regcache_raw_collect (current_regcache, M68K_FPS_REGNUM,
-                         &fpregsetp->f_psr);
-  if (regno == -1 || regno == M68K_FPI_REGNUM)
-    regcache_raw_collect (current_regcache, M68K_FPI_REGNUM,
-                         &fpregsetp->f_fpiaddr);
-}
-
-#endif /* defined (FP0_REGNUM) */
-
-#endif /* USE_PROC_FS */
 
 /* Figure out where the longjmp will land.  Slurp the args out of the stack.
    We expect the first arg to be a pointer to the jmp_buf structure from which
@@ -1093,11 +1007,12 @@ fill_fpregset (fpregset_t *fpregsetp, int regno)
    This routine returns true on success. */
 
 static int
-m68k_get_longjmp_target (CORE_ADDR *pc)
+m68k_get_longjmp_target (struct frame_info *frame, CORE_ADDR *pc)
 {
   gdb_byte *buf;
   CORE_ADDR sp, jb_addr;
-  struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
 
   if (tdep->jb_pc < 0)
     {
@@ -1106,20 +1021,22 @@ m68k_get_longjmp_target (CORE_ADDR *pc)
       return 0;
     }
 
-  buf = alloca (TARGET_PTR_BIT / TARGET_CHAR_BIT);
-  sp = read_register (SP_REGNUM);
+  buf = alloca (gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT);
+  sp = get_frame_register_unsigned (frame, gdbarch_sp_regnum (gdbarch));
 
   if (target_read_memory (sp + SP_ARG0,        /* Offset of first arg on stack */
-                         buf, TARGET_PTR_BIT / TARGET_CHAR_BIT))
+                         buf, gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
     return 0;
 
-  jb_addr = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+  jb_addr = extract_unsigned_integer (buf, gdbarch_ptr_bit (gdbarch)
+                                            / TARGET_CHAR_BIT);
 
   if (target_read_memory (jb_addr + tdep->jb_pc * tdep->jb_elt_size, buf,
-                         TARGET_PTR_BIT / TARGET_CHAR_BIT))
+                         gdbarch_ptr_bit (gdbarch) / TARGET_CHAR_BIT))
     return 0;
 
-  *pc = extract_unsigned_integer (buf, TARGET_PTR_BIT / TARGET_CHAR_BIT);
+  *pc = extract_unsigned_integer (buf, gdbarch_ptr_bit (gdbarch)
+                                        / TARGET_CHAR_BIT);
   return 1;
 }
 \f
@@ -1148,17 +1065,113 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 {
   struct gdbarch_tdep *tdep = NULL;
   struct gdbarch *gdbarch;
+  struct gdbarch_list *best_arch;
+  struct tdesc_arch_data *tdesc_data = NULL;
+  int i;
+  enum m68k_flavour flavour = m68k_no_flavour;
+  int has_fp = 1;
+  const struct floatformat **long_double_format = floatformats_m68881_ext;
+
+  /* Check any target description for validity.  */
+  if (tdesc_has_registers (info.target_desc))
+    {
+      const struct tdesc_feature *feature;
+      int valid_p;
+
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.m68k.core");
+      if (feature != NULL)
+       /* Do nothing.  */
+       ;
 
-  /* find a candidate among the list of pre-declared architectures. */
-  arches = gdbarch_list_lookup_by_info (arches, &info);
-  if (arches != NULL)
-    return (arches->gdbarch);
+      if (feature == NULL)
+       {
+         feature = tdesc_find_feature (info.target_desc,
+                                       "org.gnu.gdb.coldfire.core");
+         if (feature != NULL)
+           flavour = m68k_coldfire_flavour;
+       }
+
+      if (feature == NULL)
+       {
+         feature = tdesc_find_feature (info.target_desc,
+                                       "org.gnu.gdb.fido.core");
+         if (feature != NULL)
+           flavour = m68k_fido_flavour;
+       }
+
+      if (feature == NULL)
+       return NULL;
+
+      tdesc_data = tdesc_data_alloc ();
+
+      valid_p = 1;
+      for (i = 0; i <= M68K_PC_REGNUM; i++)
+       valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                           m68k_register_names[i]);
+
+      if (!valid_p)
+       {
+         tdesc_data_cleanup (tdesc_data);
+         return NULL;
+       }
+
+      feature = tdesc_find_feature (info.target_desc,
+                                   "org.gnu.gdb.coldfire.fp");
+      if (feature != NULL)
+       {
+         valid_p = 1;
+         for (i = M68K_FP0_REGNUM; i <= M68K_FPI_REGNUM; i++)
+           valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+                                               m68k_register_names[i]);
+         if (!valid_p)
+           {
+             tdesc_data_cleanup (tdesc_data);
+             return NULL;
+           }
+       }
+      else
+       has_fp = 0;
+    }
+
+  /* The mechanism for returning floating values from function
+     and the type of long double depend on whether we're
+     on ColdFire or standard m68k. */
+
+  if (info.bfd_arch_info && info.bfd_arch_info->mach != 0)
+    {
+      const bfd_arch_info_type *coldfire_arch = 
+       bfd_lookup_arch (bfd_arch_m68k, bfd_mach_mcf_isa_a_nodiv);
+
+      if (coldfire_arch
+         && ((*info.bfd_arch_info->compatible) 
+             (info.bfd_arch_info, coldfire_arch)))
+       flavour = m68k_coldfire_flavour;
+    }
+  
+  /* If there is already a candidate, use it.  */
+  for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+       best_arch != NULL;
+       best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+    {
+      if (flavour != gdbarch_tdep (best_arch->gdbarch)->flavour)
+       continue;
+
+      if (has_fp != gdbarch_tdep (best_arch->gdbarch)->fpregs_present)
+       continue;
+
+      break;
+    }
 
   tdep = xmalloc (sizeof (struct gdbarch_tdep));
   gdbarch = gdbarch_alloc (&info, tdep);
+  tdep->fpregs_present = has_fp;
+  tdep->flavour = flavour;
 
-  set_gdbarch_long_double_format (gdbarch, &floatformat_m68881_ext);
-  set_gdbarch_long_double_bit (gdbarch, 96);
+  if (flavour == m68k_coldfire_flavour || flavour == m68k_fido_flavour)
+    long_double_format = floatformats_ieee_double;
+  set_gdbarch_long_double_format (gdbarch, long_double_format);
+  set_gdbarch_long_double_bit (gdbarch, long_double_format[0]->totalsize);
 
   set_gdbarch_skip_prologue (gdbarch, m68k_skip_prologue);
   set_gdbarch_breakpoint_from_pc (gdbarch, m68k_local_breakpoint_from_pc);
@@ -1168,7 +1181,8 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_frame_align (gdbarch, m68k_frame_align);
 
   set_gdbarch_believe_pcc_promotion (gdbarch, 1);
-  set_gdbarch_decr_pc_after_break (gdbarch, 2);
+  if (flavour == m68k_coldfire_flavour || flavour == m68k_fido_flavour)
+    set_gdbarch_decr_pc_after_break (gdbarch, 2);
 
   set_gdbarch_frame_args_skip (gdbarch, 8);
   set_gdbarch_dwarf_reg_to_regnum (gdbarch, m68k_dwarf_reg_to_regnum);
@@ -1177,7 +1191,6 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_register_type (gdbarch, m68k_register_type);
   set_gdbarch_register_name (gdbarch, m68k_register_name);
   set_gdbarch_num_regs (gdbarch, M68K_NUM_REGS);
-  set_gdbarch_register_bytes_ok (gdbarch, m68k_register_bytes_ok);
   set_gdbarch_sp_regnum (gdbarch, M68K_SP_REGNUM);
   set_gdbarch_pc_regnum (gdbarch, M68K_PC_REGNUM);
   set_gdbarch_ps_regnum (gdbarch, M68K_PS_REGNUM);
@@ -1186,9 +1199,30 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_register_to_value (gdbarch,  m68k_register_to_value);
   set_gdbarch_value_to_register (gdbarch, m68k_value_to_register);
 
+  if (has_fp)
+    set_gdbarch_fp0_regnum (gdbarch, M68K_FP0_REGNUM);
+
+  /* Try to figure out if the arch uses floating registers to return
+     floating point values from functions.  */
+  if (has_fp)
+    {
+      /* On ColdFire, floating point values are returned in D0.  */
+      if (flavour == m68k_coldfire_flavour)
+       tdep->float_return = 0;
+      else
+       tdep->float_return = 1;
+    }
+  else
+    {
+      /* No floating registers, so can't use them for returning values.  */
+      tdep->float_return = 0;
+    }
+
+  /* Function call & return */
   set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call);
   set_gdbarch_return_value (gdbarch, m68k_return_value);
 
+
   /* Disassembler.  */
   set_gdbarch_print_insn (gdbarch, print_insn_m68k);
 
@@ -1221,14 +1255,17 @@ m68k_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   frame_unwind_append_sniffer (gdbarch, m68k_frame_sniffer);
 
+  if (tdesc_data)
+    tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+
   return gdbarch;
 }
 
 
 static void
-m68k_dump_tdep (struct gdbarch *current_gdbarch, struct ui_file *file)
+m68k_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)
     return;
@@ -1240,4 +1277,7 @@ void
 _initialize_m68k_tdep (void)
 {
   gdbarch_register (bfd_arch_m68k, m68k_gdbarch_init, m68k_dump_tdep);
+
+  /* Initialize the m68k-specific register types.  */
+  m68k_init_types ();
 }
This page took 0.031918 seconds and 4 git commands to generate.