2008-03-25 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / mt-tdep.c
index 243fdd3a49cd96fd1088644dafd1cab6b4d39b8e..a3098b25bed5d471222a11e65b5ebd56964696cd 100644 (file)
@@ -1,12 +1,12 @@
 /* Target-dependent code for Morpho mt processor, for GDB.
 
-   Copyright (C) 2005 Free Software Foundation, Inc.
+   Copyright (C) 2005, 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,
@@ -15,9 +15,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/>.  */
 
 /* Contributed by Michael Snyder, msnyder@redhat.com.  */
 
@@ -109,6 +107,12 @@ enum mt_gdb_regnums
   MT_OUT_REGNUM,                       /* 16 bits.  */
   MT_EXMAC_REGNUM,             /* 32 bits (8 used).  */
   MT_QCHANNEL_REGNUM,          /* 32 bits.  */
+  MT_ZI2_REGNUM,                /* 16 bits.  */
+  MT_ZQ2_REGNUM,                /* 16 bits.  */
+  MT_CHANNEL2_REGNUM,           /* 32 bits.  */
+  MT_ISCRAMB2_REGNUM,           /* 32 bits.  */
+  MT_QSCRAMB2_REGNUM,           /* 32 bits.  */
+  MT_QCHANNEL2_REGNUM,          /* 32 bits.  */
 
   /* Number of real registers.  */
   MT_NUM_REGS,
@@ -116,15 +120,27 @@ enum mt_gdb_regnums
   /* Pseudo-registers.  */
   MT_COPRO_PSEUDOREG_REGNUM = MT_NUM_REGS,
   MT_MAC_PSEUDOREG_REGNUM,
+  MT_COPRO_PSEUDOREG_ARRAY,
+
+  MT_COPRO_PSEUDOREG_DIM_1 = 2,
+  MT_COPRO_PSEUDOREG_DIM_2 = 8,
+  /* The number of pseudo-registers for each coprocessor.  These
+     include the real coprocessor registers, the pseudo-registe for
+     the coprocessor number, and the pseudo-register for the MAC.  */
+  MT_COPRO_PSEUDOREG_REGS = MT_NUM_REGS - MT_NUM_CPU_REGS + 2,
+  /* The register number of the MAC, relative to a given coprocessor.  */
+  MT_COPRO_PSEUDOREG_MAC_REGNUM = MT_COPRO_PSEUDOREG_REGS - 1,
 
   /* Two pseudo-regs ('coprocessor' and 'mac').  */
-  MT_NUM_PSEUDO_REGS = 2
+  MT_NUM_PSEUDO_REGS = 2 + (MT_COPRO_PSEUDOREG_REGS
+                           * MT_COPRO_PSEUDOREG_DIM_1
+                           * MT_COPRO_PSEUDOREG_DIM_2)
 };
 
 /* Return name of register number specified by REGNUM.  */
 
 static const char *
-mt_register_name (int regnum)
+mt_register_name (struct gdbarch *gdbarch, int regnum)
 {
   static const char *const register_names[] = {
     /* CPU regs.  */
@@ -137,12 +153,95 @@ mt_register_name (int regnum)
     "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",
     "bypa", "bypb", "bypc", "flag", "context", "" /* mac.  */ , "z1", "z2",
     "Ichannel", "Iscramb", "Qscramb", "out", "" /* ex-mac.  */ , "Qchannel",
+    "zi2", "zq2", "Ichannel2", "Iscramb2", "Qscramb2", "Qchannel2",
     /* Pseudo-registers.  */
     "coprocessor", "MAC"
   };
+  static const char *array_names[MT_COPRO_PSEUDOREG_REGS
+                                * MT_COPRO_PSEUDOREG_DIM_1
+                                * MT_COPRO_PSEUDOREG_DIM_2];
+
+  if (regnum < 0)
+    return "";
+  if (regnum < ARRAY_SIZE (register_names))
+    return register_names[regnum];
+  if (array_names[regnum - MT_COPRO_PSEUDOREG_ARRAY])
+    return array_names[regnum - MT_COPRO_PSEUDOREG_ARRAY];
+  
+  {
+    char *name;
+    const char *stub;
+    unsigned dim_1;
+    unsigned dim_2;
+    unsigned index;
+    
+    regnum -= MT_COPRO_PSEUDOREG_ARRAY;
+    index = regnum % MT_COPRO_PSEUDOREG_REGS;
+    dim_2 = (regnum / MT_COPRO_PSEUDOREG_REGS) % MT_COPRO_PSEUDOREG_DIM_2;
+    dim_1 = ((regnum / MT_COPRO_PSEUDOREG_REGS / MT_COPRO_PSEUDOREG_DIM_2)
+            %  MT_COPRO_PSEUDOREG_DIM_1);
+    
+    if (index == MT_COPRO_PSEUDOREG_MAC_REGNUM)
+      stub = register_names[MT_MAC_PSEUDOREG_REGNUM];
+    else if (index >= MT_NUM_REGS - MT_CPR0_REGNUM)
+      stub = "";
+    else
+      stub = register_names[index + MT_CPR0_REGNUM];
+    if (!*stub)
+      {
+       array_names[regnum] = stub;
+       return stub;
+      }
+    name = xmalloc (30);
+    sprintf (name, "copro_%d_%d_%s", dim_1, dim_2, stub);
+    array_names[regnum] = name;
+    return name;
+  }
+}
 
-  gdb_assert (regnum >= 0 && regnum < ARRAY_SIZE (register_names));
-  return register_names[regnum];
+/* Return the type of a coprocessor register.  */
+
+static struct type *
+mt_copro_register_type (struct gdbarch *arch, int regnum)
+{
+  switch (regnum)
+    {
+    case MT_INT_ENABLE_REGNUM:
+    case MT_ICHANNEL_REGNUM:
+    case MT_QCHANNEL_REGNUM:
+    case MT_ISCRAMB_REGNUM:
+    case MT_QSCRAMB_REGNUM:
+      return builtin_type_int32;
+    case MT_BYPA_REGNUM:
+    case MT_BYPB_REGNUM:
+    case MT_BYPC_REGNUM:
+    case MT_Z1_REGNUM:
+    case MT_Z2_REGNUM:
+    case MT_OUT_REGNUM:
+    case MT_ZI2_REGNUM:
+    case MT_ZQ2_REGNUM:
+      return builtin_type_int16;
+    case MT_EXMAC_REGNUM:
+    case MT_MAC_REGNUM:
+      return builtin_type_uint32;
+    case MT_CONTEXT_REGNUM:
+      return builtin_type_long_long;
+    case MT_FLAG_REGNUM:
+      return builtin_type_unsigned_char;
+    default:
+      if (regnum >= MT_CPR0_REGNUM && regnum <= MT_CPR15_REGNUM)
+       return builtin_type_int16;
+      else if (regnum == MT_CPR0_REGNUM + MT_COPRO_PSEUDOREG_MAC_REGNUM)
+       {
+         if (gdbarch_bfd_arch_info (arch)->mach == bfd_mach_mrisc2
+             || gdbarch_bfd_arch_info (arch)->mach == bfd_mach_ms2)
+           return builtin_type_uint64;
+         else
+           return builtin_type_uint32;
+       }
+      else
+       return builtin_type_uint32;
+    }
 }
 
 /* Given ARCH and a register number specified by REGNUM, return the
@@ -176,40 +275,25 @@ mt_register_type (struct gdbarch *arch, int regnum)
        case MT_SP_REGNUM:
        case MT_FP_REGNUM:
          return void_ptr;
-       case MT_INT_ENABLE_REGNUM:
-       case MT_ICHANNEL_REGNUM:
-       case MT_QCHANNEL_REGNUM:
-       case MT_ISCRAMB_REGNUM:
-       case MT_QSCRAMB_REGNUM:
-         return builtin_type_int32;
-       case MT_EXMAC_REGNUM:
-       case MT_MAC_REGNUM:
-         return builtin_type_uint32;
-       case MT_BYPA_REGNUM:
-       case MT_BYPB_REGNUM:
-       case MT_BYPC_REGNUM:
-       case MT_Z1_REGNUM:
-       case MT_Z2_REGNUM:
-       case MT_OUT_REGNUM:
-         return builtin_type_int16;
-       case MT_CONTEXT_REGNUM:
-         return builtin_type_long_long;
        case MT_COPRO_REGNUM:
        case MT_COPRO_PSEUDOREG_REGNUM:
          return copro_type;
        case MT_MAC_PSEUDOREG_REGNUM:
-         if (gdbarch_bfd_arch_info (arch)->mach == bfd_mach_mrisc2
-             || gdbarch_bfd_arch_info (arch)->mach == bfd_mach_ms2)
-           return builtin_type_uint64;
-         else
-           return builtin_type_uint32;
-       case MT_FLAG_REGNUM:
-         return builtin_type_unsigned_char;
+         return mt_copro_register_type (arch,
+                                        MT_CPR0_REGNUM
+                                        + MT_COPRO_PSEUDOREG_MAC_REGNUM);
        default:
          if (regnum >= MT_R0_REGNUM && regnum <= MT_R15_REGNUM)
            return builtin_type_int32;
-         else if (regnum >= MT_CPR0_REGNUM && regnum <= MT_CPR15_REGNUM)
-           return builtin_type_int16;
+         else if (regnum < MT_COPRO_PSEUDOREG_ARRAY)
+           return mt_copro_register_type (arch, regnum);
+         else
+           {
+             regnum -= MT_COPRO_PSEUDOREG_ARRAY;
+             regnum %= MT_COPRO_PSEUDOREG_REGS;
+             regnum += MT_CPR0_REGNUM;
+             return mt_copro_register_type (arch, regnum);
+           }
        }
     }
   internal_error (__FILE__, __LINE__,
@@ -227,7 +311,7 @@ mt_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
   if (group == all_reggroup)
     return (regnum >= 0
            && regnum < MT_NUM_REGS + MT_NUM_PSEUDO_REGS
-           && mt_register_name (regnum)[0] != '\0');
+           && mt_register_name (gdbarch, regnum)[0] != '\0');
 
   if (group == general_reggroup)
     return (regnum >= MT_R0_REGNUM && regnum <= MT_R15_REGNUM);
@@ -314,7 +398,7 @@ mt_return_value (struct gdbarch *gdbarch, struct type *type,
    call.  */
 
 static CORE_ADDR
-mt_skip_prologue (CORE_ADDR pc)
+mt_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
 {
   CORE_ADDR func_addr = 0, func_end = 0;
   char *func_name;
@@ -367,26 +451,66 @@ mt_skip_prologue (CORE_ADDR pc)
    The BP for ms2 is defined as 0x69000000 (illegal)  */
 
 static const gdb_byte *
-mt_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size)
+mt_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
+                      int *bp_size)
 {
   static gdb_byte ms1_breakpoint[] = { 0x68, 0, 0, 0 };
   static gdb_byte ms2_breakpoint[] = { 0x69, 0, 0, 0 };
 
   *bp_size = 4;
-  if (gdbarch_bfd_arch_info (current_gdbarch)->mach == bfd_mach_ms2)
+  if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_ms2)
     return ms2_breakpoint;
   
   return ms1_breakpoint;
 }
 
+/* Select the correct coprocessor register bank.  Return the pseudo
+   regnum we really want to read.  */
+
+static int
+mt_select_coprocessor (struct gdbarch *gdbarch,
+                       struct regcache *regcache, int regno)
+{
+  unsigned index, base;
+  gdb_byte copro[4];
+
+  /* Get the copro pseudo regnum. */
+  regcache_raw_read (regcache, MT_COPRO_REGNUM, copro);
+  base = (extract_signed_integer (&copro[0], 2) * MT_COPRO_PSEUDOREG_DIM_2
+         + extract_signed_integer (&copro[2], 2));
+
+  regno -= MT_COPRO_PSEUDOREG_ARRAY;
+  index = regno % MT_COPRO_PSEUDOREG_REGS;
+  regno /= MT_COPRO_PSEUDOREG_REGS;
+  if (base != regno)
+    {
+      /* Select the correct coprocessor register bank.  Invalidate the
+        coprocessor register cache.  */
+      unsigned ix;
+
+      store_signed_integer (&copro[0], 2, regno / MT_COPRO_PSEUDOREG_DIM_2);
+      store_signed_integer (&copro[2], 2, regno % MT_COPRO_PSEUDOREG_DIM_2);
+      regcache_raw_write (regcache, MT_COPRO_REGNUM, copro);
+      
+      /* We must flush the cache, as it is now invalid.  */
+      for (ix = MT_NUM_CPU_REGS; ix != MT_NUM_REGS; ix++)
+       regcache_invalidate (regcache, ix);
+    }
+  
+  return index;
+}
+
 /* Fetch the pseudo registers:
 
-   There are two pseudo-registers:
+   There are two regular pseudo-registers:
    1) The 'coprocessor' pseudo-register (which mirrors the 
    "real" coprocessor register sent by the target), and
    2) The 'MAC' pseudo-register (which represents the union
    of the original 32 bit target MAC register and the new
-   8-bit extended-MAC register).  */
+   8-bit extended-MAC register).
+
+   Additionally there is an array of coprocessor registers which track
+   the coprocessor registers for each coprocessor.  */
 
 static void
 mt_pseudo_register_read (struct gdbarch *gdbarch,
@@ -416,8 +540,15 @@ mt_pseudo_register_read (struct gdbarch *gdbarch,
        regcache_raw_read (regcache, MT_MAC_REGNUM, buf);
       break;
     default:
-      internal_error (__FILE__, __LINE__,
-                     _("mt_pseudo_register_read: bad reg # (%d)"), regno);
+      {
+       unsigned index = mt_select_coprocessor (gdbarch, regcache, regno);
+       
+       if (index == MT_COPRO_PSEUDOREG_MAC_REGNUM)
+         mt_pseudo_register_read (gdbarch, regcache,
+                                  MT_MAC_PSEUDOREG_REGNUM, buf);
+       else if (index < MT_NUM_REGS - MT_CPR0_REGNUM)
+         regcache_raw_read (regcache, index + MT_CPR0_REGNUM, buf);
+      }
       break;
     }
 }
@@ -441,7 +572,7 @@ mt_pseudo_register_write (struct gdbarch *gdbarch,
     case MT_COPRO_PSEUDOREG_REGNUM:
       regcache_raw_write (regcache, MT_COPRO_REGNUM, buf);
       for (i = MT_NUM_CPU_REGS; i < MT_NUM_REGS; i++)
-       set_register_cached (i, 0);
+       regcache_invalidate (regcache, i);
       break;
     case MT_MAC_REGNUM:
     case MT_MAC_PSEUDOREG_REGNUM:
@@ -463,8 +594,15 @@ mt_pseudo_register_write (struct gdbarch *gdbarch,
        regcache_raw_write (regcache, MT_MAC_REGNUM, buf);
       break;
     default:
-      internal_error (__FILE__, __LINE__,
-                     _("mt_pseudo_register_write: bad reg # (%d)"), regno);
+      {
+       unsigned index = mt_select_coprocessor (gdbarch, regcache, regno);
+       
+       if (index == MT_COPRO_PSEUDOREG_MAC_REGNUM)
+         mt_pseudo_register_write (gdbarch, regcache,
+                                   MT_MAC_PSEUDOREG_REGNUM, buf);
+       else if (index < MT_NUM_REGS - MT_CPR0_REGNUM)
+         regcache_raw_write (regcache, index + MT_CPR0_REGNUM, buf);
+      }
       break;
     }
 }
@@ -482,8 +620,8 @@ mt_frame_align (struct gdbarch *gdbarch, CORE_ADDR sp)
 
 static void
 mt_registers_info (struct gdbarch *gdbarch,
-                   struct ui_file *file,
-                   struct frame_info *frame, int regnum, int all)
+                  struct ui_file *file,
+                  struct frame_info *frame, int regnum, int all)
 {
   if (regnum == -1)
     {
@@ -522,8 +660,11 @@ mt_registers_info (struct gdbarch *gdbarch,
 
          frame_register_read (frame, regnum, buff);
 
-         fputs_filtered (REGISTER_NAME (regnum), file);
-         print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
+         fputs_filtered (gdbarch_register_name
+                         (gdbarch, regnum), file);
+         print_spaces_filtered (15 - strlen (gdbarch_register_name
+                                               (gdbarch, regnum)),
+                                file);
          fputs_filtered ("0x", file);
 
          for (i = 0; i < regsize; i++)
@@ -544,8 +685,11 @@ mt_registers_info (struct gdbarch *gdbarch,
          frame_register_read (frame, MT_COPRO_REGNUM, buf);
          /* And print.  */
          regnum = MT_COPRO_PSEUDOREG_REGNUM;
-         fputs_filtered (REGISTER_NAME (regnum), file);
-         print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
+         fputs_filtered (gdbarch_register_name (gdbarch, regnum),
+                         file);
+         print_spaces_filtered (15 - strlen (gdbarch_register_name
+                                               (gdbarch, regnum)),
+                                file);
          val_print (register_type (gdbarch, regnum), buf,
                     0, 0, file, 0, 1, 0, Val_no_prettyprint);
          fputs_filtered ("\n", file);
@@ -574,8 +718,11 @@ mt_registers_info (struct gdbarch *gdbarch,
 
          /* And print.  */
          regnum = MT_MAC_PSEUDOREG_REGNUM;
-         fputs_filtered (REGISTER_NAME (regnum), file);
-         print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
+         fputs_filtered (gdbarch_register_name (gdbarch, regnum),
+                         file);
+         print_spaces_filtered (15 - strlen (gdbarch_register_name
+                                             (gdbarch, regnum)),
+                                file);
          fputs_filtered ("0x", file);
          print_longest (file, 'x', 0, newmac);
          fputs_filtered ("\t", file);
@@ -749,10 +896,10 @@ mt_frame_unwind_cache (struct frame_info *next_frame,
   /* Grab the frame-relative values of SP and FP, needed below. 
      The frame_saved_register function will find them on the
      stack or in the registers as appropriate.  */
-  frame_unwind_unsigned_register (next_frame, MT_SP_REGNUM, &sp);
-  frame_unwind_unsigned_register (next_frame, MT_FP_REGNUM, &fp);
+  sp = frame_unwind_register_unsigned (next_frame, MT_SP_REGNUM);
+  fp = frame_unwind_register_unsigned (next_frame, MT_FP_REGNUM);
 
-  start_addr = frame_func_unwind (next_frame);
+  start_addr = frame_func_unwind (next_frame, NORMAL_FRAME);
 
   /* Return early if GDB couldn't find the function.  */
   if (start_addr == 0)
@@ -866,7 +1013,7 @@ mt_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   ULONGEST pc;
 
-  frame_unwind_unsigned_register (next_frame, MT_PC_REGNUM, &pc);
+  pc = frame_unwind_register_unsigned (next_frame, MT_PC_REGNUM);
   return pc;
 }
 
@@ -875,7 +1022,7 @@ mt_unwind_sp (struct gdbarch *gdbarch, struct frame_info *next_frame)
 {
   ULONGEST sp;
 
-  frame_unwind_unsigned_register (next_frame, MT_SP_REGNUM, &sp);
+  sp = frame_unwind_register_unsigned (next_frame, MT_SP_REGNUM);
   return sp;
 }
 
@@ -902,10 +1049,9 @@ mt_frame_this_id (struct frame_info *next_frame,
     mt_frame_unwind_cache (next_frame, this_prologue_cache);
 
   if (!(info == NULL || info->prev_sp == 0))
-    {
-      (*this_id) = frame_id_build (info->prev_sp,
-                                  frame_func_unwind (next_frame));
-    }
+    (*this_id) = frame_id_build (info->prev_sp,
+                                frame_func_unwind (next_frame, NORMAL_FRAME));
+
   return;
 }
 
@@ -979,23 +1125,9 @@ mt_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
      provided.  */
   gdbarch = gdbarch_alloc (&info, NULL);
 
-  switch (info.byte_order)
-    {
-    case BFD_ENDIAN_BIG:
-      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
-      set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
-      set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
-      break;
-    case BFD_ENDIAN_LITTLE:
-      set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
-      set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
-      set_gdbarch_long_double_format (gdbarch,
-                                     &floatformat_ieee_double_little);
-      break;
-    default:
-      internal_error (__FILE__, __LINE__,
-                     _("mt_gdbarch_init: bad byte order for float format"));
-    }
+  set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+  set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
 
   set_gdbarch_register_name (gdbarch, mt_register_name);
   set_gdbarch_num_regs (gdbarch, MT_NUM_REGS);
This page took 0.030577 seconds and 4 git commands to generate.