This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] MIPS: Provide FPU info and decode FCSR in `info float'


Hi,

 I'm asking for feedback on this change, see below for details.

 The change below provides a MIPS-specific handler for the:

(gdb) info float

command.  It provides information about the FPU type available (if any), 
the FPU register width, and decodes the CP1 Floating Point Control and 
Status Register (FCSR):

(gdb) print /x $fsr
$1 = 0xff83ffff
(gdb) info float
fpu type: double-precision
reg size: 32 bits
cond    : 0 1 2 3 4 5 6 7
cause   : inexact uflow oflow div0 inval unimp
mask    : inexact uflow oflow div0 inval
flags   : inexact uflow oflow div0 inval
rounding: -inf
flush   : zero
(gdb)

 One point to note about CP1.FCSR are the non-standard Flush-to-Nearest 
and Flush-Override bits.  They are not a part of the MIPS architecture and 
take two positions reserved for an implementation-dependent use in the 
architecture.  They are present in all the FPU implementations made by 
MIPS Technologies since the spin-off from SGI.

 I haven't been able to track down a single other MIPS FPU implementation 
that would make any use of these bits and they are required to be 
hardwired to zero by the architecture specification if unimplemented.  
Therefore I think it makes sense to report them in the current way.

 GDB has no guaranteed access to the CP0 Processor Identification (PRId) 
register to validate this feature properly and the ID information stored 
in the CP1 Floating Point Implementation Register (FIR) is from my 
experience not reliable enough (there's no Company ID available there for 
once unlike in CP0.PRId and Processor ID is not guaranteed to be unique).  

 As a side note we should probably dump CP1.FIR information as well, as 
there's useful stuff indicating some FPU features there.  That's material 
for another change however.

 Another point is that the dump above now replaces generic `info float' 
information that comprises the FP registers, either:

(gdb) info float
f0:  0x00000000 flt: 0                 dbl: nan                     
f1:  0x7ff80000 flt: nan              
f2:  0x7ff80000 flt: nan               dbl: nan                     
f3:  0x7ff80000 flt: nan              
f4:  0x7ff80000 flt: nan               dbl: nan                     
f5:  0x7ff80000 flt: nan              
f6:  0x7ff80000 flt: nan               dbl: nan                     
f7:  0x7ff80000 flt: nan              
f8:  0x7ff80000 flt: nan               dbl: nan                     
f9:  0x7ff80000 flt: nan              
f10: 0x7ff80000 flt: nan               dbl: nan                     
f11: 0x7ff80000 flt: nan              
f12: 0x7ff80000 flt: nan               dbl: nan                     
f13: 0x7ff80000 flt: nan              
f14: 0x7ff80000 flt: nan               dbl: nan                     
f15: 0x7ff80000 flt: nan              
f16: 0x7ff80000 flt: nan               dbl: nan                     
f17: 0x7ff80000 flt: nan              
f18: 0x7ff80000 flt: nan               dbl: nan                     
f19: 0x7ff80000 flt: nan              
f20: 0x7ff80000 flt: nan               dbl: nan                     
f21: 0x7ff80000 flt: nan              
f22: 0x7ff80000 flt: nan               dbl: nan                     
f23: 0x7ff80000 flt: nan              
f24: 0x7ff80000 flt: nan               dbl: nan                     
f25: 0x7ff80000 flt: nan              
f26: 0x7ff80000 flt: nan               dbl: nan                     
f27: 0x7ff80000 flt: nan              
f28: 0x7ff80000 flt: nan               dbl: nan                     
f29: 0x7ff80000 flt: nan              
f30: 0x7ff80000 flt: nan               dbl: nan                     
f31: 0x7ff80000 flt: nan              
fcsr: 0x0
fir: 0x0
(gdb) 

-- for Linux, or:

(gdb) info float
f0:  0x00000000 flt: 0                 dbl: 0                       
f1:  0x00000000 flt: 0                
f2:  0x00000000 flt: 0                 dbl: 0                       
f3:  0x00000000 flt: 0                
f4:  0x00000000 flt: 0                 dbl: 0                       
f5:  0x00000000 flt: 0                
f6:  0x00000000 flt: 0                 dbl: 0                       
f7:  0x00000000 flt: 0                
f8:  0x00000000 flt: 0                 dbl: 0                       
f9:  0x00000000 flt: 0                
f10: 0x00000000 flt: 0                 dbl: 0                       
f11: 0x00000000 flt: 0                
f12: 0x00000000 flt: 0                 dbl: 0                       
f13: 0x00000000 flt: 0                
f14: 0x00000000 flt: 0                 dbl: 0                       
f15: 0x00000000 flt: 0                
f16: 0x00000000 flt: 0                 dbl: 0                       
f17: 0x00000000 flt: 0                
f18: 0x00000000 flt: 0                 dbl: 0                       
f19: 0x00000000 flt: 0                
f20: 0x00000000 flt: 0                 dbl: 0                       
f21: 0x00000000 flt: 0                
f22: 0x00000000 flt: 0                 dbl: 0                       
f23: 0x00000000 flt: 0                
f24: 0x00000000 flt: 0                 dbl: 0                       
f25: 0x00000000 flt: 0                
f26: 0x00000000 flt: 0                 dbl: 0                       
f27: 0x00000000 flt: 0                
f28: 0x00000000 flt: 0                 dbl: 0                       
f29: 0x00000000 flt: 0                
f30: 0x00000000 flt: 0                 dbl: 0                       
f31: 0x00000000 flt: 0                
(gdb)

-- for bare iron (I'm not sure where the difference comes from, I would 
expect CP1 FCSR and FIR control registers to be printed in both cases; it 
could be related to default register group assignments being overridden by 
target descriptions used by Linux).  This is useful information, however 
still accessible with the:

(gdb) info all-registers

command.  So I am asking for feedback, specifically whether it would be 
preferable for this change to go in as is or whether the simple dump of 
FPU registers should be retained.

 I'll wait a couple of days and push the change as is if there are no 
objections.  Nigel unfortunately may not be available to defend his code.

 While testing this I noticed that the "set mipsfpu" knob is effectively 
ignored.  Or at least setting it to "none" does not seem to impress GDB in 
any way, it still keeps poking at the FPU.  This will have to be addressed 
one way or another.

 There are some other places apparently that assume that the FPU is 
present as long as mips_regnum (gdbarch)->fp_control_status is a valid 
register number, which is not enough either, just as handled by this 
change.

2012-05-24  Nigel Stephens  <nigel@mips.com>
            Maciej W. Rozycki  <macro@codesourcery.com>

	gdb/
	* mips-tdep.c (print_fpu_flags): New function.
	(mips_print_float_info): Likewise.
	(mips_gdbarch_init): Install mips_print_float_info as gdbarch
	print_float_info routine.

	gdb/testsuite/
	* gdb.base/float.exp: Handle the new output from "info float" on
	MIPS targets.

  Maciej

gdb-mips-info-float.diff
Index: gdb-fsf-trunk-quilt/gdb/mips-tdep.c
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/mips-tdep.c	2012-05-24 03:50:20.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/mips-tdep.c	2012-05-24 03:52:19.535415096 +0100
@@ -6180,6 +6180,98 @@ mips_print_register (struct ui_file *fil
 			      &opts, 0, file);
 }
 
+/* Print IEEE exception condition bits in FLAGS.  */
+
+static void
+print_fpu_flags (struct ui_file *file, int flags)
+{
+  if (flags & (1 << 0))
+    fputs_filtered (" inexact", file);
+  if (flags & (1 << 1))
+    fputs_filtered (" uflow", file);
+  if (flags & (1 << 2))
+    fputs_filtered (" oflow", file);
+  if (flags & (1 << 3))
+    fputs_filtered (" div0", file);
+  if (flags & (1 << 4))
+    fputs_filtered (" inval", file);
+  if (flags & (1 << 5))
+    fputs_filtered (" unimp", file);
+  fputc_filtered ('\n', file);
+}
+
+/* Print interesting information about the floating point processor
+   (if present) or emulator.  */
+
+static void
+mips_print_float_info (struct gdbarch *gdbarch, struct ui_file *file,
+		       struct frame_info *frame, const char *args)
+{
+  int fcsr = mips_regnum (gdbarch)->fp_control_status;
+  enum mips_fpu_type type = MIPS_FPU_TYPE (gdbarch);
+  ULONGEST fcs = 0;
+  int i;
+
+  if (fcsr == -1 || !frame_register_read (frame, fcsr, NULL))
+    type = MIPS_FPU_NONE;
+
+  fprintf_filtered (file, "fpu type: %s\n",
+		    (type == MIPS_FPU_DOUBLE ? "double-precision"
+		     : type == MIPS_FPU_SINGLE ? "single-precision"
+		     : "none / unused"));
+
+  if (type == MIPS_FPU_NONE)
+    return;
+
+  fprintf_filtered (file, "reg size: %d bits\n",
+		    register_size (gdbarch, mips_regnum (gdbarch)->fp0) * 8);
+
+  fcs = get_frame_register_unsigned (frame, fcsr);
+
+  fputs_filtered ("cond    :", file);
+  if (fcs & (1 << 23))
+    fputs_filtered (" 0", file);
+  for (i = 1; i <= 7; i++)
+    if (fcs & (1 << (24 + i)))
+      fprintf_filtered (file, " %d", i);
+  fputc_filtered ('\n', file);
+
+  fputs_filtered ("cause   :", file);
+  print_fpu_flags (file, (fcs >> 12) & 0x3f);
+  fputs ("mask    :", stdout);
+  print_fpu_flags (file, (fcs >> 7) & 0x1f);
+  fputs ("flags   :", stdout);
+  print_fpu_flags (file, (fcs >> 2) & 0x1f);
+
+  fputs_filtered ("rounding: ", file);
+  switch (fcs & 3)
+    {
+    case 0:
+      fputs_filtered ("nearest\n", file);
+      break;
+    case 1:
+      fputs_filtered ("zero\n", file);
+      break;
+    case 2:
+      fputs_filtered ("+inf\n", file);
+      break;
+    case 3:
+      fputs_filtered ("-inf\n", file);
+      break;
+    }
+
+  fputs_filtered ("flush   :", file);
+  if (fcs & (1 << 21))
+    fputs_filtered (" nearest", file);
+  if (fcs & (1 << 22))
+    fputs_filtered (" override", file);
+  if (fcs & (1 << 24))
+    fputs_filtered (" zero", file);
+  if ((fcs & (0xb << 21)) == 0)
+    fputs_filtered (" no", file);
+  fputc_filtered ('\n', file);
+}
+
 /* Replacement for generic do_registers_info.
    Print regs in pretty columns.  */
 
@@ -8491,6 +8583,8 @@ mips_gdbarch_init (struct gdbarch_info i
   set_gdbarch_push_dummy_code (gdbarch, mips_push_dummy_code);
   set_gdbarch_frame_align (gdbarch, mips_frame_align);
 
+  set_gdbarch_print_float_info (gdbarch, mips_print_float_info);
+
   set_gdbarch_convert_register_p (gdbarch, mips_convert_register_p);
   set_gdbarch_register_to_value (gdbarch, mips_register_to_value);
   set_gdbarch_value_to_register (gdbarch, mips_value_to_register);
Index: gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/float.exp
===================================================================
--- gdb-fsf-trunk-quilt.orig/gdb/testsuite/gdb.base/float.exp	2012-05-24 03:08:28.000000000 +0100
+++ gdb-fsf-trunk-quilt/gdb/testsuite/gdb.base/float.exp	2012-05-24 03:50:53.055561138 +0100
@@ -66,7 +66,14 @@ if { [istarget "alpha*-*-*"] } then {
 	}
     }
 } elseif [istarget "mips*-*-*"] then {
-    gdb_test "info float" "f0:.*flt:.*dbl:.*" "info float"
+    gdb_test_multiple "info float" "info float" {
+	-re "fpu type: none*" {
+	      pass "info float (without FPU)"
+	  }
+	-re "fpu type:.*cause.*mask.*flags.*round.*flush.*" {
+	      pass "info float (with FPU)"
+	  }
+    }
 } elseif [istarget "powerpc*-*-*"] then {
     gdb_test_multiple "info float" "info_float" {
         -re "f0.*f1.*f31.*fpscr.*$gdb_prompt $" {


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]