* sh-tdep.c (sh_generic_register_name): Remove.
[deliverable/binutils-gdb.git] / gdb / sh-tdep.c
index c42e4113b4272644b5afc31a011f45943c74d03e..52c2be5fce49eae8c2ab1da05957ddc0a6dd5c83 100644 (file)
@@ -1,6 +1,6 @@
-/* Target-dependent code for Hitachi Super-H, for GDB.
-   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003
-   Free Software Foundation, Inc.
+/* Target-dependent code for Renesas Super-H, for GDB.
+   Copyright 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+   2003, 2004 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -30,7 +30,6 @@
 #include "frame-unwind.h"
 #include "dwarf2-frame.h"
 #include "symtab.h"
-#include "symfile.h"
 #include "gdbtypes.h"
 #include "gdbcmd.h"
 #include "gdbcore.h"
@@ -74,27 +73,6 @@ struct sh_frame_cache
   CORE_ADDR saved_sp;
 };
 
-static const char *
-sh_generic_register_name (int reg_nr)
-{
-  static char *register_names[] = {
-    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
-    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
-    "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
-    "fpul", "fpscr",
-    "fr0", "fr1", "fr2", "fr3", "fr4", "fr5", "fr6", "fr7",
-    "fr8", "fr9", "fr10", "fr11", "fr12", "fr13", "fr14", "fr15",
-    "ssr", "spc",
-    "r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
-    "r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1",
-  };
-  if (reg_nr < 0)
-    return NULL;
-  if (reg_nr >= (sizeof (register_names) / sizeof (*register_names)))
-    return NULL;
-  return register_names[reg_nr];
-}
-
 static const char *
 sh_sh_register_name (int reg_nr)
 {
@@ -212,8 +190,8 @@ sh_sh3_dsp_register_name (int reg_nr)
     "y0", "y1", "", "", "", "", "", "mod",
     "ssr", "spc",
     "rs", "re", "", "", "", "", "", "",
-    "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b"
-      "", "", "", "", "", "", "", "",
+    "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b",
+    "", "", "", "", "", "", "", "",
   };
   if (reg_nr < 0)
     return NULL;
@@ -256,6 +234,60 @@ sh_sh4_register_name (int reg_nr)
   return register_names[reg_nr];
 }
 
+static const char *
+sh_sh4_nofpu_register_name (int reg_nr)
+{
+  static char *register_names[] = {
+    /* general registers 0-15 */
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    /* 16 - 22 */
+    "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+    /* 23, 24 */
+    "", "",
+    /* floating point registers 25 - 40 -- not for nofpu target */
+    "", "", "", "", "", "", "", "",
+    "", "", "", "", "", "", "", "",
+    /* 41, 42 */
+    "ssr", "spc",
+    /* bank 0 43 - 50 */
+    "r0b0", "r1b0", "r2b0", "r3b0", "r4b0", "r5b0", "r6b0", "r7b0",
+    /* bank 1 51 - 58 */
+    "r0b1", "r1b1", "r2b1", "r3b1", "r4b1", "r5b1", "r6b1", "r7b1",
+    /* double precision (pseudo) 59 - 66 -- not for nofpu target */
+    "", "", "", "", "", "", "", "",
+    /* vectors (pseudo) 67 - 70 -- not for nofpu target */
+    "", "", "", "",
+  };
+  if (reg_nr < 0)
+    return NULL;
+  if (reg_nr >= (sizeof (register_names) / sizeof (*register_names)))
+    return NULL;
+  return register_names[reg_nr];
+}
+
+static const char *
+sh_sh4al_dsp_register_name (int reg_nr)
+{
+  static char *register_names[] = {
+    "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+    "pc", "pr", "gbr", "vbr", "mach", "macl", "sr",
+    "", "dsr",
+    "a0g", "a0", "a1g", "a1", "m0", "m1", "x0", "x1",
+    "y0", "y1", "", "", "", "", "", "mod",
+    "ssr", "spc",
+    "rs", "re", "", "", "", "", "", "",
+    "r0b", "r1b", "r2b", "r3b", "r4b", "r5b", "r6b", "r7b",
+    "", "", "", "", "", "", "", "",
+  };
+  if (reg_nr < 0)
+    return NULL;
+  if (reg_nr >= (sizeof (register_names) / sizeof (*register_names)))
+    return NULL;
+  return register_names[reg_nr];
+}
+
 static const unsigned char *
 sh_breakpoint_from_pc (CORE_ADDR *pcptr, int *lenptr)
 {
@@ -543,9 +575,7 @@ sh_skip_prologue (CORE_ADDR start_pc)
   return pc;
 }
 
-/* Should call_function allocate stack space for a struct return?
-
-   The ABI says:
+/* The ABI says:
 
    Aggregate types not bigger than 8 bytes that have the same size and
    alignment as one of the integer scalar types are returned in the
@@ -568,7 +598,7 @@ sh_skip_prologue (CORE_ADDR start_pc)
    All other aggregate types are returned by address. The caller
    function passes the address of an area large enough to hold the
    aggregate value in R2. The called function stores the result in
-   this location."
+   this location.
 
    To reiterate, structs smaller than 8 bytes could also be returned
    in memory, if they don't pass the "same size and alignment as an
@@ -582,6 +612,16 @@ sh_skip_prologue (CORE_ADDR start_pc)
    the return value from foo() will be in memory, not
    in R0, because there is no 3-byte integer type.
 
+   Similarly, in 
+
+   struct s { char c[2]; } wibble;
+   struct s foo(void) {  return wibble; }
+
+   because a struct containing two chars has alignment 1, that matches
+   type char, but size 2, that matches type short.  There's no integer
+   type that has alignment 1 and size 2, so the struct is returned in
+   memory.
+
 */
 
 static int
@@ -589,8 +629,30 @@ sh_use_struct_convention (int gcc_p, struct type *type)
 {
   int len = TYPE_LENGTH (type);
   int nelem = TYPE_NFIELDS (type);
-  return ((len != 1 && len != 2 && len != 4 && len != 8) || nelem != 1) &&
-    (len != 8 || TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) != 4);
+
+  /* Non-power of 2 length types and types bigger than 8 bytes (which don't
+     fit in two registers anyway) use struct convention.  */
+  if (len != 1 && len != 2 && len != 4 && len != 8)
+    return 1;
+
+  /* Scalar types and aggregate types with exactly one field are aligned
+     by definition.  They are returned in registers.  */
+  if (nelem <= 1)
+    return 0;
+
+  /* If the first field in the aggregate has the same length as the entire
+     aggregate type, the type is returned in registers.  */
+  if (TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) == len)
+    return 0;
+
+  /* If the size of the aggregate is 8 bytes and the first field is
+     of size 4 bytes its alignment is equal to long long's alignment,
+     so it's returned in registers.  */
+  if (len == 8 && TYPE_LENGTH (TYPE_FIELD_TYPE (type, 0)) == 4)
+    return 0;
+
+  /* Otherwise use struct convention.  */
+  return 1;
 }
 
 /* Extract from an array REGBUF containing the (raw) register state
@@ -614,7 +676,7 @@ sh_frame_align (struct gdbarch *ignore, CORE_ADDR sp)
 /* Function: push_dummy_call (formerly push_arguments)
    Setup the function arguments for calling a function in the inferior.
 
-   On the Hitachi SH architecture, there are four registers (R4 to R7)
+   On the Renesas SH architecture, there are four registers (R4 to R7)
    which are dedicated for passing function arguments.  Up to the first
    four arguments (depending on size) may go into these registers.
    The rest go on the stack.
@@ -756,6 +818,55 @@ sh_next_flt_argreg (int len)
   return FLOAT_ARG0_REGNUM + argreg;
 }
 
+/* Helper function which figures out, if a type is treated like a float type.
+
+   The FPU ABIs have a special way how to treat types as float types.
+   Structures with exactly one member, which is of type float or double, are
+   treated exactly as the base types float or double:
+
+     struct sf {
+       float f;
+     };
+
+     struct sd {
+       double d;
+     };
+
+   are handled the same way as just
+
+     float f;
+
+     double d;
+
+   As a result, arguments of these struct types are pushed into floating point
+   registers exactly as floats or doubles, using the same decision algorithm.
+
+   The same is valid if these types are used as function return types.  The
+   above structs are returned in fr0 resp. fr0,fr1 instead of in r0, r0,r1
+   or even using struct convention as it is for other structs.  */
+
+static int
+sh_treat_as_flt_p (struct type *type)
+{
+  int len = TYPE_LENGTH (type);
+
+  /* Ordinary float types are obviously treated as float.  */
+  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+    return 1;
+  /* Otherwise non-struct types are not treated as float.  */
+  if (TYPE_CODE (type) != TYPE_CODE_STRUCT)
+    return 0;
+  /* Otherwise structs with more than one memeber are not treated as float.  */
+  if (TYPE_NFIELDS (type) != 1)
+    return 0;
+  /* Otherwise if the type of that member is float, the whole type is
+     treated as float.  */
+  if (TYPE_CODE (TYPE_FIELD_TYPE (type, 0)) == TYPE_CODE_FLT)
+    return 1;
+  /* Otherwise it's not treated as float.  */
+  return 0;
+}
+
 static CORE_ADDR
 sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
                        CORE_ADDR func_addr,
@@ -773,7 +884,8 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
   CORE_ADDR regval;
   char *val;
   int len, reg_size = 0;
-  int pass_on_stack;
+  int pass_on_stack = 0;
+  int treat_as_flt;
 
   /* first force sp to a 4-byte alignment */
   sp = sh_frame_align (gdbarch, sp);
@@ -800,43 +912,59 @@ sh_push_dummy_call_fpu (struct gdbarch *gdbarch,
       /* Some decisions have to be made how various types are handled.
          This also differs in different ABIs. */
       pass_on_stack = 0;
-      if (len > 16)
-       pass_on_stack = 1;      /* Types bigger than 16 bytes are passed on stack. */
 
       /* Find out the next register to use for a floating point value. */
-      if (TYPE_CODE (type) == TYPE_CODE_FLT)
+      treat_as_flt = sh_treat_as_flt_p (type);
+      if (treat_as_flt)
        flt_argreg = sh_next_flt_argreg (len);
+      /* In contrast to non-FPU CPUs, arguments are never split between
+        registers and stack.  If an argument doesn't fit in the remaining
+        registers it's always pushed entirely on the stack.  */
+      else if (len > ((ARGLAST_REGNUM - argreg + 1) * 4))
+       pass_on_stack = 1;
 
       while (len > 0)
        {
-         if ((TYPE_CODE (type) == TYPE_CODE_FLT
-              && flt_argreg > FLOAT_ARGLAST_REGNUM)
-             || argreg > ARGLAST_REGNUM || pass_on_stack)
+         if ((treat_as_flt && flt_argreg > FLOAT_ARGLAST_REGNUM)
+             || (!treat_as_flt && (argreg > ARGLAST_REGNUM
+                                   || pass_on_stack)))
            {
-             /* The remainder of the data goes entirely on the stack,
-                4-byte aligned. */
+             /* The data goes entirely on the stack, 4-byte aligned. */
              reg_size = (len + 3) & ~3;
              write_memory (sp + stack_offset, val, reg_size);
              stack_offset += reg_size;
            }
-         else if (TYPE_CODE (type) == TYPE_CODE_FLT
-                  && flt_argreg <= FLOAT_ARGLAST_REGNUM)
+         else if (treat_as_flt && flt_argreg <= FLOAT_ARGLAST_REGNUM)
            {
              /* Argument goes in a float argument register.  */
              reg_size = register_size (gdbarch, flt_argreg);
              regval = extract_unsigned_integer (val, reg_size);
+             /* In little endian mode, float types taking two registers
+                (doubles on sh4, long doubles on sh2e, sh3e and sh4) must
+                be stored swapped in the argument registers.  The below
+                code first writes the first 32 bits in the next but one
+                register, increments the val and len values accordingly
+                and then proceeds as normal by writing the second 32 bits
+                into the next register. */
+             if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE
+                 && TYPE_LENGTH (type) == 2 * reg_size)
+               {
+                 regcache_cooked_write_unsigned (regcache, flt_argreg + 1,
+                                                 regval);
+                 val += reg_size;
+                 len -= reg_size;
+                 regval = extract_unsigned_integer (val, reg_size);
+               }
              regcache_cooked_write_unsigned (regcache, flt_argreg++, regval);
            }
-         else if (argreg <= ARGLAST_REGNUM)
+         else if (!treat_as_flt && argreg <= ARGLAST_REGNUM)
            {
              /* there's room in a register */
              reg_size = register_size (gdbarch, argreg);
              regval = extract_unsigned_integer (val, reg_size);
              regcache_cooked_write_unsigned (regcache, argreg++, regval);
            }
-         /* Store the value reg_size bytes at a time.  This means that things
-            larger than reg_size bytes may go partly in registers and partly
-            on the stack.  */
+         /* Store the value one register at a time or in one step on stack.  */
          len -= reg_size;
          val += reg_size;
        }
@@ -954,12 +1082,15 @@ static void
 sh3e_sh4_extract_return_value (struct type *type, struct regcache *regcache,
                               void *valbuf)
 {
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  if (sh_treat_as_flt_p (type))
     {
       int len = TYPE_LENGTH (type);
       int i, regnum = FP0_REGNUM;
       for (i = 0; i < len; i += 4)
-       regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
+       if (TARGET_BYTE_ORDER == BFD_ENDIAN_LITTLE)
+         regcache_raw_read (regcache, regnum++, (char *) valbuf + len - 4 - i);
+       else
+         regcache_raw_read (regcache, regnum++, (char *) valbuf + i);
     }
   else
     sh_default_extract_return_value (type, regcache, valbuf);
@@ -995,7 +1126,7 @@ static void
 sh3e_sh4_store_return_value (struct type *type, struct regcache *regcache,
                             const void *valbuf)
 {
-  if (TYPE_CODE (type) == TYPE_CODE_FLT)
+  if (sh_treat_as_flt_p (type))
     {
       int len = TYPE_LENGTH (type);
       int i, regnum = FP0_REGNUM;
@@ -1240,6 +1371,36 @@ sh4_show_regs (void)
                   (long) read_register (FP0_REGNUM + 15));
 }
 
+static void
+sh4_nofpu_show_regs (void)
+{
+  printf_filtered ("PC=%s SR=%08lx PR=%08lx MACH=%08lx MACHL=%08lx\n",
+                  paddr (read_register (PC_REGNUM)),
+                  (long) read_register (SR_REGNUM),
+                  (long) read_register (PR_REGNUM),
+                  (long) read_register (MACH_REGNUM),
+                  (long) read_register (MACL_REGNUM));
+
+  printf_filtered ("GBR=%08lx VBR=%08lx",
+                  (long) read_register (GBR_REGNUM),
+                  (long) read_register (VBR_REGNUM));
+  printf_filtered (" SSR=%08lx SPC=%08lx",
+                  (long) read_register (SSR_REGNUM),
+                  (long) read_register (SPC_REGNUM));
+
+  printf_filtered
+    ("\nR0-R7  %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+     (long) read_register (0), (long) read_register (1),
+     (long) read_register (2), (long) read_register (3),
+     (long) read_register (4), (long) read_register (5),
+     (long) read_register (6), (long) read_register (7));
+  printf_filtered ("R8-R15 %08lx %08lx %08lx %08lx %08lx %08lx %08lx %08lx\n",
+                  (long) read_register (8), (long) read_register (9),
+                  (long) read_register (10), (long) read_register (11),
+                  (long) read_register (12), (long) read_register (13),
+                  (long) read_register (14), (long) read_register (15));
+}
+
 static void
 sh_dsp_show_regs (void)
 {
@@ -1998,13 +2159,20 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       break;
 
     case bfd_mach_sh3_dsp:
+    case bfd_mach_sh4al_dsp:
       sh_show_regs = sh3_dsp_show_regs;
       break;
 
     case bfd_mach_sh4:
+    case bfd_mach_sh4a:
       sh_show_regs = sh4_show_regs;
       break;
 
+    case bfd_mach_sh4_nofpu:
+    case bfd_mach_sh4a_nofpu:
+      sh_show_regs = sh4_nofpu_show_regs;
+      break;
+
     case bfd_mach_sh5:
       sh_show_regs = sh64_show_regs;
       /* SH5 is handled entirely in sh64-tdep.c */
@@ -2049,17 +2217,13 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_store_return_value (gdbarch, sh_default_store_return_value);
   set_gdbarch_extract_return_value (gdbarch, sh_default_extract_return_value);
-  set_gdbarch_extract_struct_value_address (gdbarch,
-                                           sh_extract_struct_value_address);
+  set_gdbarch_deprecated_extract_struct_value_address (gdbarch, sh_extract_struct_value_address);
 
   set_gdbarch_skip_prologue (gdbarch, sh_skip_prologue);
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
-  set_gdbarch_decr_pc_after_break (gdbarch, 0);
-  set_gdbarch_function_start_offset (gdbarch, 0);
 
   set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_nofpu);
 
-  set_gdbarch_frame_args_skip (gdbarch, 0);
   set_gdbarch_frameless_function_invocation (gdbarch,
                                             frameless_look_for_prologue);
   set_gdbarch_believe_pcc_promotion (gdbarch, 1);
@@ -2123,6 +2287,7 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       break;
 
     case bfd_mach_sh4:
+    case bfd_mach_sh4a:
       set_gdbarch_register_name (gdbarch, sh_sh4_register_name);
       set_gdbarch_register_type (gdbarch, sh_sh4_register_type);
       set_gdbarch_fp0_regnum (gdbarch, 25);
@@ -2135,8 +2300,18 @@ sh_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
       set_gdbarch_push_dummy_call (gdbarch, sh_push_dummy_call_fpu);
       break;
 
+    case bfd_mach_sh4_nofpu:
+    case bfd_mach_sh4a_nofpu:
+      set_gdbarch_register_name (gdbarch, sh_sh4_nofpu_register_name);
+      break;
+
+    case bfd_mach_sh4al_dsp:
+      set_gdbarch_register_name (gdbarch, sh_sh4al_dsp_register_name);
+      set_gdbarch_register_sim_regno (gdbarch, sh_dsp_register_sim_regno);
+      break;
+
     default:
-      set_gdbarch_register_name (gdbarch, sh_generic_register_name);
+      set_gdbarch_register_name (gdbarch, sh_sh_register_name);
       break;
     }
 
This page took 0.047207 seconds and 4 git commands to generate.