[RFA] MIPS2 float register display

Don Howard dhoward@redhat.com
Fri Mar 23 13:18:00 GMT 2001


This patch fixes an obscure MIPS floating point register display bug.
It's been tested on linux-cross-mips with both big and little endian
executables.

2001-03-21  Don Howard  <dhoward@redhat.com>

        * mips-tdep.c (print_mips2_fp_register): New function.  Properly
        displays floating point registers on MIPS3 or later cpus operating
        in MIPS2 fp emulation mode.
        (mips2_fp_compat): New function. Determines if a MIPS3 or later
        cpu is operating in MIPS2 fp emulation mode.
        (mips_print_register): Added MIPS2 emulation check and handling.
        (do_fp_register_row): Ditto.


Index: mips-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/mips-tdep.c,v
retrieving revision 1.45
diff -p -u -w -r1.45 mips-tdep.c
--- mips-tdep.c	2001/03/20 18:16:10	1.45
+++ mips-tdep.c	2001/03/23 21:08:31
@@ -2572,11 +2572,136 @@ mips_pop_frame (void)
     }
 }
 
+
+/* Determine if a MIPS3 or later cpu is operating in MIPS2 FPU
+   compatiblitiy mode. */
+
+static int
+mips2_fp_compat ()
+{
+  if (8 != REGISTER_RAW_SIZE (FP0_REGNUM)) /* MIPS2 has 32 bit fp regs */
+    return 0;
+
+  /* Read the status register and check the FR bit. 
+     0 == MIPS2; 1 == NORMAL */
+
+#define FR_BIT (1 << 26)
+  return !(read_register (PS_REGNUM) & FR_BIT);
+}
+
+/* Display a MIPS2 floating point register (or register row).  This is
+   for use on MIPS3 or later cpus operating in MIPS2 fpu compatiblity
+   mode.
+
+   Background: MIPS2 fp registers are 32 bits wide.  To support 64bit
+   operations, MIPS2 cpus treat fp register pairs (f0,f1) as a single
+   register (d0).  Later cpu's have 64 bit fp registers and offer a
+   compatibility mode that emulates the MIPS2 fp model.  When
+   operating in MIPS2 fp compat mode, later cpu's split double
+   precision floats into 2 32 bit chunks and store them in consecutive
+   fp regs.  To display 64bit floats stored in this fashion, we have
+   to combine 32 bits from f0 and 32 bits from f1.  Throw in
+   user-configurable endianness and you have a real mess.
+
+   Note that this only deals with "live" registers at the top of the
+   stack.  We will attempt to deal with saved registers later, when
+   the raw/cooked register interface is in place. (We need a general
+   interface that can deal with dynamic saved register sizes -- fp
+   regs could be 32 bits wide in one frame and 64 on the frame above
+   and below) */
+
+static int
+print_mips2_fp_register (int regnum, int printrow)
+{
+  char *raw_buffer[2];
+  char *dbl_buffer;
+  /* use HI and LO to control the order of combining two flt regs */
+  int HI = (TARGET_BYTE_ORDER == BIG_ENDIAN);
+  int LO = (TARGET_BYTE_ORDER != BIG_ENDIAN);
+  double doub, flt1, flt2;	/* doubles extracted from raw hex data */
+  int inv1, inv2, inv3;
+  int even_regnum = regnum;
+
+
+  if (mips_debug)
+    fprintf_unfiltered (gdb_stdlog, "MIPS II compatibility (%s)\n",
+			HI ? "BE" : "LE");
+
+  if (regnum & 1)
+    {
+      if (printrow)
+	return regnum + 1;
+
+      else
+	even_regnum = regnum - 1;
+    }
+
+
+  if (0 == selected_frame_level)
+    {
+      raw_buffer[0] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM));
+      raw_buffer[1] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM));
+      dbl_buffer = (char *) alloca (2 * REGISTER_RAW_SIZE (FP0_REGNUM));
+
+      read_register_gen (even_regnum, raw_buffer[LO]);
+      read_register_gen (even_regnum + 1, raw_buffer[HI]);
+
+      memcpy (&dbl_buffer[HI * 4], &raw_buffer[LO][HI * 4], 4);
+      memcpy (&dbl_buffer[LO * 4], &raw_buffer[HI][HI * 4], 4);
+
+      flt1 =
+	unpack_double (builtin_type_float, &raw_buffer[LO][HI * 4], &inv1);
+      flt2 =
+	unpack_double (builtin_type_float, &raw_buffer[HI][HI * 4], &inv2);
+      doub = unpack_double (builtin_type_double, dbl_buffer, &inv3);
+
+      if (printrow)
+	{
+	  printf_filtered (inv1 ? " %-5s: <invalid float>" :
+			   " %-5s%-17.9g", REGISTER_NAME (even_regnum), flt1);
+	  printf_filtered (inv2 ? " %-5s: <invalid float>" :
+			   " %-5s%-17.9g", REGISTER_NAME (even_regnum + 1),
+			   flt2);
+	  printf_filtered (inv3 ? " dbl: <invalid double>\n" :
+			   " dbl: %-24.17g\n", doub);
+	  regnum += 2;
+	}
+      else
+	{
+	  int even_or_odd = regnum & 1;
+
+	  printf_filtered ("%-5s: (float) ", REGISTER_NAME (regnum));
+	  val_print (builtin_type_float, &raw_buffer[even_or_odd][HI * 4], 0,
+		     0, gdb_stdout, 0, 1, 0, Val_pretty_default);
+	  printf_filtered (", (double) ");
+	  val_print (builtin_type_double, dbl_buffer, 0, 0,
+		     gdb_stdout, 0, 1, 0, Val_pretty_default);
+
+	  regnum++;
+	}
+    }
+  else
+    {
+      printf_filtered ("%-5s: <invalid float/double>",
+		       REGISTER_NAME (regnum));
+      regnum++;
+    }
+
+  return regnum;
+}
+
 static void
 mips_print_register (int regnum, int all)
 {
   char raw_buffer[MAX_REGISTER_RAW_SIZE];
 
+  if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT && 
+      mips2_fp_compat ())
+    {
+      print_mips2_fp_register (regnum, 0);
+      return;
+    }
+
   /* Get the data in raw format.  */
   if (read_relative_register_raw_bytes (regnum, raw_buffer))
     {
@@ -2656,6 +2781,9 @@ do_fp_register_row (int regnum)
   int LO = (TARGET_BYTE_ORDER != BIG_ENDIAN);
   double doub, flt1, flt2;	/* doubles extracted from raw hex data */
   int inv1, inv2, inv3;
+
+  if (mips2_fp_compat ())
+    return print_mips2_fp_register (regnum, 1);
 
   raw_buffer[0] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM));
   raw_buffer[1] = (char *) alloca (REGISTER_RAW_SIZE (FP0_REGNUM));

-- 
-Don
dhoward@redhat.com




More information about the Gdb-patches mailing list