This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH] MIPS: Provide FPU info and decode FCSR in `info float'
- From: "Maciej W. Rozycki" <macro at codesourcery dot com>
- To: <gdb-patches at sourceware dot org>
- Date: Thu, 24 May 2012 18:32:50 +0100
- Subject: [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 $" {