diff options
-rw-r--r-- | gdb/ChangeLog | 10 | ||||
-rw-r--r-- | gdb/mips-tdep.c | 211 |
2 files changed, 177 insertions, 44 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index c9e552c8..f398fc8 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2002-03-10 Daniel Jacobowitz <drow@mvista.com> + Don Howard <dhoward@redhat.com> + + * mips-tdep.c (ST0_FR): Define. + (mips2_fp_compat): New function, temporarily disabled. + (mips_read_fp_register_single): New function. + (mips_read_fp_register_double): New function. + (mips_print_register): Use them. + (do_fp_register_row): Likewise. + 2002-03-09 Andrew Cagney <ac131313@redhat.com> * MAINTAINERS: Add Jim Ingham and Klee Dienes to ``write after diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c index f0a27d9..55abc53 100644 --- a/gdb/mips-tdep.c +++ b/gdb/mips-tdep.c @@ -44,6 +44,10 @@ #include "elf-bfd.h" #include "symcat.h" +/* A useful bit in the CP0 status register (PS_REGNUM). */ +/* This bit is set if we are emulating 32-bit FPRs on a 64-bit chip. */ +#define ST0_FR (1 << 26) + /* The sizes of floating point registers. */ enum @@ -174,6 +178,31 @@ mips_saved_regsize (void) return 4; } +/* Determine if a MIPS3 or later cpu is operating in MIPS{1,2} FPU + compatiblity mode. A return value of 1 means that we have + physical 64-bit registers, but should treat them as 32-bit registers. */ + +static int +mips2_fp_compat (void) +{ + /* MIPS1 and MIPS2 have only 32 bit FPRs, and the FR bit is not + meaningful. */ + if (REGISTER_RAW_SIZE (FP0_REGNUM) == 4) + return 0; + +#if 0 + /* FIXME drow 2002-03-10: This is disabled until we can do it consistently, + in all the places we deal with FP registers. PR gdb/413. */ + /* Otherwise check the FR bit in the status register - it controls + the FP compatiblity mode. If it is clear we are in compatibility + mode. */ + if ((read_register (PS_REGNUM) & ST0_FR) == 0) + return 1; +#endif + + return 0; +} + /* Indicate that the ABI makes use of double-precision registers provided by the FPU (rather than combining pairs of registers to form double-precision values). Do not use "TARGET_IS_MIPS64" to @@ -257,6 +286,9 @@ find_proc_desc (CORE_ADDR pc, struct frame_info *next_frame, int cur_frame); static CORE_ADDR after_prologue (CORE_ADDR pc, mips_extra_func_info_t proc_desc); +static void mips_read_fp_register_single (int regno, char *rare_buffer); +static void mips_read_fp_register_double (int regno, char *rare_buffer); + /* This value is the model of MIPS in use. It is derived from the value of the PrID register. */ @@ -2676,6 +2708,104 @@ mips_pop_frame (void) } } +/* Floating point register management. + + Background: MIPS1 & 2 fp registers are 32 bits wide. To support + 64bit operations, these early MIPS cpus treat fp register pairs + (f0,f1) as a single register (d0). Later MIPS 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 two 32-bit chunks and store them in + consecutive fp regs. To display 64-bit 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. + + The way this works is: + - If we are in 32-bit mode or on a 32-bit processor, then a 64-bit + double-precision value will be split across two logical registers. + The lower-numbered logical register will hold the low-order bits, + regardless of the processor's endianness. + - If we are on a 64-bit processor, and we are looking for a + single-precision value, it will be in the low ordered bits + of a 64-bit GPR (after mfc1, for example) or a 64-bit register + save slot in memory. + - If we are in 64-bit mode, everything is straightforward. + + Note that this code 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). */ + +/* Copy a 32-bit single-precision value from the current frame + into rare_buffer. */ + +static void +mips_read_fp_register_single (int regno, char *rare_buffer) +{ + int raw_size = REGISTER_RAW_SIZE (regno); + char *raw_buffer = alloca (raw_size); + + if (read_relative_register_raw_bytes (regno, raw_buffer)) + error ("can't read register %d (%s)", regno, REGISTER_NAME (regno)); + if (raw_size == 8) + { + /* We have a 64-bit value for this register. Find the low-order + 32 bits. */ + int offset; + + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + offset = 4; + else + offset = 0; + + memcpy (rare_buffer, raw_buffer + offset, 4); + } + else + { + memcpy (rare_buffer, raw_buffer, 4); + } +} + +/* Copy a 64-bit double-precision value from the current frame into + rare_buffer. This may include getting half of it from the next + register. */ + +static void +mips_read_fp_register_double (int regno, char *rare_buffer) +{ + int raw_size = REGISTER_RAW_SIZE (regno); + + if (raw_size == 8 && !mips2_fp_compat ()) + { + /* We have a 64-bit value for this register, and we should use + all 64 bits. */ + if (read_relative_register_raw_bytes (regno, rare_buffer)) + error ("can't read register %d (%s)", regno, REGISTER_NAME (regno)); + } + else + { + if ((regno - FP0_REGNUM) & 1) + internal_error (__FILE__, __LINE__, + "mips_read_fp_register_double: bad access to " + "odd-numbered FP register"); + + /* mips_read_fp_register_single will find the correct 32 bits from + each register. */ + if (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG) + { + mips_read_fp_register_single (regno, rare_buffer + 4); + mips_read_fp_register_single (regno + 1, rare_buffer); + } + else + { + mips_read_fp_register_single (regno, rare_buffer); + mips_read_fp_register_single (regno + 1, rare_buffer + 4); + } + } +} + static void mips_print_register (int regnum, int all) { @@ -2688,22 +2818,23 @@ mips_print_register (int regnum, int all) return; } - /* If an even floating point register, also print as double. */ + /* If we have a actual 32-bit floating point register (or we are in + 32-bit compatibility mode), and the register is even-numbered, + also print it as a double (spanning two registers). */ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT + && (REGISTER_RAW_SIZE (regnum) == 4 + || mips2_fp_compat ()) && !((regnum - FP0_REGNUM) & 1)) - if (REGISTER_RAW_SIZE (regnum) == 4) /* this would be silly on MIPS64 or N32 (Irix 6) */ - { - char dbuffer[2 * MAX_REGISTER_RAW_SIZE]; + { + char dbuffer[2 * MAX_REGISTER_RAW_SIZE]; - read_relative_register_raw_bytes (regnum, dbuffer); - read_relative_register_raw_bytes (regnum + 1, dbuffer + MIPS_REGSIZE); - REGISTER_CONVERT_TO_TYPE (regnum, builtin_type_double, dbuffer); + mips_read_fp_register_double (regnum, dbuffer); - printf_filtered ("(d%d: ", regnum - FP0_REGNUM); - val_print (builtin_type_double, dbuffer, 0, 0, - gdb_stdout, 0, 1, 0, Val_pretty_default); - printf_filtered ("); "); - } + printf_filtered ("(d%d: ", regnum - FP0_REGNUM); + val_print (builtin_type_double, dbuffer, 0, 0, + gdb_stdout, 0, 1, 0, Val_pretty_default); + printf_filtered ("); "); + } fputs_filtered (REGISTER_NAME (regnum), gdb_stdout); /* The problem with printing numeric register names (r26, etc.) is that @@ -2717,8 +2848,10 @@ mips_print_register (int regnum, int all) /* If virtual format is floating, print it that way. */ if (TYPE_CODE (REGISTER_VIRTUAL_TYPE (regnum)) == TYPE_CODE_FLT) - if (FP_REGISTER_DOUBLE) - { /* show 8-byte floats as float AND double: */ + if (REGISTER_RAW_SIZE (regnum) == 8 && !mips2_fp_compat ()) + { + /* We have a meaningful 64-bit value in this register. Show + it as a 32-bit float and a 64-bit double. */ int offset = 4 * (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG); printf_filtered (" (float) "); @@ -2753,35 +2886,25 @@ mips_print_register (int regnum, int all) static int do_fp_register_row (int regnum) { /* do values for FP (float) regs */ - 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 == BFD_ENDIAN_BIG); - int LO = (TARGET_BYTE_ORDER != BFD_ENDIAN_BIG); + char *raw_buffer; double doub, flt1, flt2; /* doubles extracted from raw hex data */ int inv1, inv2, inv3; - 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)); + raw_buffer = (char *) alloca (2 * REGISTER_RAW_SIZE (FP0_REGNUM)); - /* Get the data in raw format. */ - if (read_relative_register_raw_bytes (regnum, raw_buffer[HI])) - error ("can't read register %d (%s)", regnum, REGISTER_NAME (regnum)); - if (REGISTER_RAW_SIZE (regnum) == 4) + if (REGISTER_RAW_SIZE (regnum) == 4 || mips2_fp_compat ()) { - /* 4-byte registers: we can fit two registers per row. */ - /* Also print every pair of 4-byte regs as an 8-byte double. */ - if (read_relative_register_raw_bytes (regnum + 1, raw_buffer[LO])) - error ("can't read register %d (%s)", - regnum + 1, REGISTER_NAME (regnum + 1)); - - /* copy the two floats into one double, and unpack both */ - memcpy (dbl_buffer, raw_buffer, 2 * REGISTER_RAW_SIZE (FP0_REGNUM)); - flt1 = unpack_double (builtin_type_float, raw_buffer[HI], &inv1); - flt2 = unpack_double (builtin_type_float, raw_buffer[LO], &inv2); - doub = unpack_double (builtin_type_double, dbl_buffer, &inv3); + /* 4-byte registers: we can fit two registers per row. */ + /* Also print every pair of 4-byte regs as an 8-byte double. */ + mips_read_fp_register_single (regnum, raw_buffer); + flt1 = unpack_double (builtin_type_float, raw_buffer, &inv1); + mips_read_fp_register_single (regnum + 1, raw_buffer); + flt2 = unpack_double (builtin_type_float, raw_buffer, &inv2); + + mips_read_fp_register_double (regnum, raw_buffer); + doub = unpack_double (builtin_type_double, raw_buffer, &inv3); + printf_filtered (" %-5s", REGISTER_NAME (regnum)); if (inv1) printf_filtered (": <invalid float>"); @@ -2805,14 +2928,14 @@ do_fp_register_row (int regnum) regnum += 2; } else - { /* eight byte registers: print each one as float AND as double. */ - int offset = 4 * (TARGET_BYTE_ORDER == BFD_ENDIAN_BIG); - - memcpy (dbl_buffer, raw_buffer[HI], 2 * REGISTER_RAW_SIZE (FP0_REGNUM)); - flt1 = unpack_double (builtin_type_float, - &raw_buffer[HI][offset], &inv1); - doub = unpack_double (builtin_type_double, dbl_buffer, &inv3); + { + /* Eight byte registers: print each one as float AND as double. */ + mips_read_fp_register_single (regnum, raw_buffer); + flt1 = unpack_double (builtin_type_double, raw_buffer, &inv1); + mips_read_fp_register_double (regnum, raw_buffer); + doub = unpack_double (builtin_type_double, raw_buffer, &inv3); + printf_filtered (" %-5s: ", REGISTER_NAME (regnum)); if (inv1) printf_filtered ("<invalid float>"); |