From mboxrd@z Thu Jan 1 00:00:00 1970 From: Don Howard To: gdb-patches@sources.redhat.com Subject: [RFA] MIPS2 float register display Date: Fri, 23 Mar 2001 13:18:00 -0000 Message-id: X-SW-Source: 2001-03/msg00437.html 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 * 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: " : + " %-5s%-17.9g", REGISTER_NAME (even_regnum), flt1); + printf_filtered (inv2 ? " %-5s: " : + " %-5s%-17.9g", REGISTER_NAME (even_regnum + 1), + flt2); + printf_filtered (inv3 ? " dbl: \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: ", + 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