2007-11-07 Luis Machado * rs6000-tdep.c (rs6000_gdbarch_init): Add support for Decimal128 pseudo-registers. (rs6000_pseudo_register_type): Returns the correct type for Decimal128 pseudo-registers. (rs6000_pseudo_register_reggroup_p): Returns the correct register group for Decimal128 pseudo-registers. (ppc_pseudo_register_read): New function. (ppc_pseudo_register_write): New function. * ppc-tdep.h: Add new variables ppc_dl0_upper_regnum, ppc_dl0_regnum and ppc_dl15_regnum. * target-descriptions.c: Add new predefined DFP types. * c-exp.y: Fix DFP type names. * gdbtypes.c (_initialize_gdbtypes): Initialize new global DFP types. * gdbtypes.h: Declare new global DFP types and remove the old ones. * printcmd.c: Fix displaying of DFP types as hex. * features/rs6000/powerpc-64.c (initialize_tdesc_powerpc_64): Create a new feature for Decimal128 pseudo-registers. * features/rs6000/powerpc-32.c (initialize_tdesc_powerpc_32): Create a new feature for Decimal128 pseudo-registers. * testsuite/gdb.arch/powerpc-d128-regs.exp: New testcase expect file. * testsuite/gdb.arch/powerpc-d128-regs.c: New testcase source file. * doc/gdb.textinfo: Add new powerpc dfp128 feature documentation. Index: git/gdb/rs6000-tdep.c =================================================================== --- git.orig/gdb/rs6000-tdep.c 2007-11-05 11:37:24.000000000 -0800 +++ git/gdb/rs6000-tdep.c 2007-11-07 07:43:50.000000000 -0800 @@ -2381,6 +2381,20 @@ return spe_regnames[regno - tdep->ppc_ev0_regnum]; } + /* Check if the Decimal128 pseudo-registers are available. */ + if (tdep->ppc_dl0_regnum >= 0 + && tdep->ppc_dl0_regnum <= regno + && regno < tdep->ppc_dl0_regnum + 16) + { + static const char *const dfp128_regnames[] = { + "dl0", "dl1", "dl2", "dl3", + "dl4", "dl5", "dl6", "dl7", + "dl8", "dl9", "dl10", "dl11", + "dl12", "dl13", "dl14", "dl15" + }; + return dfp128_regnames[regno - tdep->ppc_dl0_regnum]; + } + return tdesc_register_name (gdbarch, regno); } @@ -2392,12 +2406,19 @@ { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - /* These are the only pseudo-registers we support. */ - gdb_assert (tdep->ppc_ev0_regnum >= 0 - && regnum >= tdep->ppc_ev0_regnum - && regnum < tdep->ppc_ev0_regnum + 32); + /* These are the e500 pseudo-registers. */ + if (tdep->ppc_ev0_regnum >= 0 + && regnum >= tdep->ppc_ev0_regnum + && regnum < tdep->ppc_ev0_regnum + 32) + return rs6000_builtin_type_vec64 (gdbarch); + + /* These are the ppc Decimal128 pseudo-registers. */ + if (tdep->ppc_dl0_regnum >= 0 + && regnum >= tdep->ppc_dl0_regnum + && regnum < tdep->ppc_dl0_regnum + 16) + return builtin_type_declong; - return rs6000_builtin_type_vec64 (gdbarch); + return NULL; } /* Is REGNUM a member of REGGROUP? */ @@ -2407,10 +2428,16 @@ { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - /* These are the only pseudo-registers we support. */ - gdb_assert (tdep->ppc_ev0_regnum >= 0 - && regnum >= tdep->ppc_ev0_regnum - && regnum < tdep->ppc_ev0_regnum + 32); + /* These are the e500 pseudo-registers. */ + if (tdep->ppc_ev0_regnum < 0 + && regnum < tdep->ppc_ev0_regnum + && regnum >= tdep->ppc_ev0_regnum + 32) + return -1; + + if (tdep->ppc_dl0_regnum < 0 + && regnum < tdep->ppc_dl0_regnum + && regnum >= tdep->ppc_dl0_regnum + 16) + return -1; if (group == all_reggroup || group == vector_reggroup) return 1; @@ -2552,6 +2579,89 @@ gdbarch_register_name (gdbarch, reg_nr), reg_nr); } +/* Read method for PPC pseudo-registers. Currently this is handling the + 16 Decimal 128 registers that map into 16 pairs of FP registers. */ +static void +ppc_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, + int reg_nr, gdb_byte *buffer) +{ + struct gdbarch *regcache_arch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index; + gdb_byte *byte_buffer = buffer; + + gdb_assert (regcache_arch == gdbarch); + + if (tdep->ppc_dl0_regnum <= reg_nr + && reg_nr < tdep->ppc_dl0_regnum + 16) + { + reg_index = reg_nr - tdep->ppc_dl0_regnum; + + if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) + { + /* Read two FP registers to form a whole dl register. */ + regcache_raw_read (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index, byte_buffer); + regcache_raw_read (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index + 1, byte_buffer + 8); + } + else + { + regcache_raw_read (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index + 1, byte_buffer + 8); + regcache_raw_read (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index, byte_buffer); + } + } + else + internal_error (__FILE__, __LINE__, + _("ppc_pseudo_register_read: " + "called on unexpected register '%s' (%d)"), + gdbarch_register_name (gdbarch, reg_nr), reg_nr); +} + +/* Write method for PPC pseudo-registers. Currently this is handling the + 16 Decimal 128 registers that map into 16 pairs of FP registers. */ +static void +ppc_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, + int reg_nr, const gdb_byte *buffer) +{ + struct gdbarch *regcache_arch = get_regcache_arch (regcache); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index; + const gdb_byte *byte_buffer = buffer; + + gdb_assert (regcache_arch == gdbarch); + + if (tdep->ppc_dl0_regnum <= reg_nr + && reg_nr < tdep->ppc_dl0_regnum + 16) + { + reg_index = reg_nr - tdep->ppc_dl0_regnum; + + if (gdbarch_byte_order (current_gdbarch) == BFD_ENDIAN_BIG) + { + /* Write each half of the dl register into a separate + FP register. */ + regcache_raw_write (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index, byte_buffer); + regcache_raw_write (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index + 1, byte_buffer + 8); + } + else + { + regcache_raw_write (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index + 1, byte_buffer + 8); + regcache_raw_write (regcache, tdep->ppc_dl0_upper_regnum + + 2 * reg_index, byte_buffer); + } + } + else + internal_error (__FILE__, __LINE__, + _("ppc_pseudo_register_read: " + "called on unexpected register '%s' (%d)"), + gdbarch_register_name (gdbarch, reg_nr), reg_nr); +} + /* Convert a DBX STABS register number to a GDB register number. */ static int rs6000_stab_reg_to_regnum (int num) @@ -3170,7 +3280,8 @@ enum auto_boolean soft_float_flag = powerpc_soft_float_global; int soft_float; enum powerpc_vector_abi vector_abi = powerpc_vector_abi_global; - int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0; + int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0, + have_dfp128 = 0; int tdesc_wordsize = -1; const struct target_desc *tdesc = info.target_desc; struct tdesc_arch_data *tdesc_data = NULL; @@ -3376,6 +3487,12 @@ else have_altivec = 0; + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.dfp128"); + + if (feature != NULL) + have_dfp128 = 1; + /* On machines supporting the SPE APU, the general-purpose registers are 64 bits long. There are SIMD vector instructions to treat them as pairs of floats, but the rest of the instruction set treats them @@ -3564,6 +3681,7 @@ tdep->ppc_ev0_upper_regnum = have_spe ? PPC_SPE_UPPER_GP0_REGNUM : -1; tdep->ppc_acc_regnum = have_spe ? PPC_SPE_ACC_REGNUM : -1; tdep->ppc_spefscr_regnum = have_spe ? PPC_SPE_FSCR_REGNUM : -1; + tdep->ppc_dl0_upper_regnum = have_dfp128 ? PPC_F0_REGNUM : -1; set_gdbarch_pc_regnum (gdbarch, PPC_PC_REGNUM); set_gdbarch_sp_regnum (gdbarch, PPC_R0_REGNUM + 1); @@ -3596,6 +3714,12 @@ set_gdbarch_pseudo_register_read (gdbarch, e500_pseudo_register_read); set_gdbarch_pseudo_register_write (gdbarch, e500_pseudo_register_write); } + else + if (have_dfp128) + { + set_gdbarch_pseudo_register_read (gdbarch, ppc_pseudo_register_read); + set_gdbarch_pseudo_register_write (gdbarch, ppc_pseudo_register_write); + } set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1); @@ -3606,7 +3730,12 @@ set_gdbarch_print_insn (gdbarch, gdb_print_insn_powerpc); set_gdbarch_num_regs (gdbarch, PPC_NUM_REGS + num_sprs); - set_gdbarch_num_pseudo_regs (gdbarch, have_spe ? 32 : 0); + + if (have_spe) + set_gdbarch_num_pseudo_regs (gdbarch, 32); + else + if (have_dfp128) + set_gdbarch_num_pseudo_regs (gdbarch, 16); set_gdbarch_ptr_bit (gdbarch, wordsize * TARGET_CHAR_BIT); set_gdbarch_short_bit (gdbarch, 2 * TARGET_CHAR_BIT); @@ -3730,6 +3859,10 @@ tdep->ppc_ev0_regnum = have_spe ? gdbarch_num_regs (gdbarch) : -1; tdep->ppc_ev31_regnum = have_spe ? tdep->ppc_ev0_regnum + 31 : -1; + /* Set the register number for Decimal128 pseudo-registers. */ + tdep->ppc_dl0_regnum = have_dfp128 ? gdbarch_num_regs (gdbarch) : -1; + tdep->ppc_dl15_regnum = have_dfp128 ? tdep->ppc_dl0_regnum + 15 : -1; + return gdbarch; } Index: git/gdb/ppc-tdep.h =================================================================== --- git.orig/gdb/ppc-tdep.h 2007-11-05 11:37:24.000000000 -0800 +++ git/gdb/ppc-tdep.h 2007-11-06 04:20:22.000000000 -0800 @@ -205,6 +205,11 @@ int ppc_acc_regnum; /* SPE 'acc' register */ int ppc_spefscr_regnum; /* SPE 'spefscr' register */ + /* Decimal 128 registers. */ + int ppc_dl0_regnum; /* First Decimal128 register pair. */ + int ppc_dl15_regnum; /* Last Decimal128 register pair. */ + int ppc_dl0_upper_regnum; /* First FPR upper half register for dl0. */ + /* Offset to ABI specific location where link register is saved. */ int lr_frame_offset; Index: git/gdb/printcmd.c =================================================================== --- git.orig/gdb/printcmd.c 2007-11-06 04:20:21.000000000 -0800 +++ git/gdb/printcmd.c 2007-11-06 04:20:22.000000000 -0800 @@ -326,7 +326,8 @@ if (len > sizeof(LONGEST) && (TYPE_CODE (type) == TYPE_CODE_INT - || TYPE_CODE (type) == TYPE_CODE_ENUM)) + || TYPE_CODE (type) == TYPE_CODE_ENUM + || TYPE_CODE (type) == TYPE_CODE_DECFLOAT)) { switch (format) { Index: git/gdb/target-descriptions.c =================================================================== --- git.orig/gdb/target-descriptions.c 2007-11-05 11:37:24.000000000 -0800 +++ git/gdb/target-descriptions.c 2007-11-06 04:20:22.000000000 -0800 @@ -360,7 +360,10 @@ { "uint128", &builtin_type_uint128 }, { "ieee_single", &builtin_type_ieee_single }, { "ieee_double", &builtin_type_ieee_double }, - { "arm_fpa_ext", &builtin_type_arm_ext } + { "arm_fpa_ext", &builtin_type_arm_ext }, + { "decfloat", &builtin_type_decfloat }, + { "decdouble", &builtin_type_decdouble }, + { "declong", &builtin_type_declong } }; /* Return the type associated with ID in the context of FEATURE, or Index: git/gdb/c-exp.y =================================================================== --- git.orig/gdb/c-exp.y 2007-11-05 11:37:24.000000000 -0800 +++ git/gdb/c-exp.y 2007-11-06 04:20:22.000000000 -0800 @@ -1098,7 +1098,7 @@ { p[len - 2] = '\0'; putithere->typed_val_decfloat.type - = builtin_type (current_gdbarch)->builtin_decfloat; + = builtin_type_decfloat; decimal_from_string (putithere->typed_val_decfloat.val, 4, p); p[len] = saved_char; return (DECFLOAT); @@ -1108,7 +1108,7 @@ { p[len - 2] = '\0'; putithere->typed_val_decfloat.type - = builtin_type (current_gdbarch)->builtin_decdouble; + = builtin_type_decdouble; decimal_from_string (putithere->typed_val_decfloat.val, 8, p); p[len] = saved_char; return (DECFLOAT); @@ -1118,7 +1118,7 @@ { p[len - 2] = '\0'; putithere->typed_val_decfloat.type - = builtin_type (current_gdbarch)->builtin_declong; + = builtin_type_declong; decimal_from_string (putithere->typed_val_decfloat.val, 16, p); p[len] = saved_char; return (DECFLOAT); Index: git/gdb/gdbtypes.c =================================================================== --- git.orig/gdb/gdbtypes.c 2007-11-05 11:37:24.000000000 -0800 +++ git/gdb/gdbtypes.c 2007-11-07 06:40:37.000000000 -0800 @@ -103,7 +103,9 @@ struct type *builtin_type_arm_ext; struct type *builtin_type_ia64_spill; struct type *builtin_type_ia64_quad; - +struct type *builtin_type_decfloat; +struct type *builtin_type_decdouble; +struct type *builtin_type_declong; int opaque_type_resolution = 1; static void @@ -3172,21 +3174,6 @@ 0, "bool", (struct objfile *) NULL); - /* The following three are about decimal floating point types, which - are 32-bits, 64-bits and 128-bits respectively. */ - builtin_type->builtin_decfloat - = init_type (TYPE_CODE_DECFLOAT, 32 / 8, - 0, - "decimal float", (struct objfile *) NULL); - builtin_type->builtin_decdouble - = init_type (TYPE_CODE_DECFLOAT, 64 / 8, - 0, - "decimal double", (struct objfile *) NULL); - builtin_type->builtin_declong - = init_type (TYPE_CODE_DECFLOAT, 128 / 8, - 0, - "decimal long double", (struct objfile *) NULL); - /* Pointer/Address types. */ /* NOTE: on some targets, addresses and pointers are not necessarily @@ -3305,6 +3292,21 @@ TYPE_FLAG_UNSIGNED, "uint128_t", (struct objfile *) NULL); + builtin_type_decfloat + = init_type (TYPE_CODE_DECFLOAT, 32 / 8, + 0, + "decimal float", (struct objfile *) NULL); + + builtin_type_decdouble + = init_type (TYPE_CODE_DECFLOAT, 64 / 8, + 0, + "decimal double", (struct objfile *) NULL); + + builtin_type_declong + = init_type (TYPE_CODE_DECFLOAT, 128 / 8, + 0, + "decimal long double", (struct objfile *) NULL); + builtin_type_ieee_single = build_flt (-1, "builtin_type_ieee_single", floatformats_ieee_single); builtin_type_ieee_double = Index: git/gdb/gdbtypes.h =================================================================== --- git.orig/gdb/gdbtypes.h 2007-11-05 11:37:24.000000000 -0800 +++ git/gdb/gdbtypes.h 2007-11-07 06:41:15.000000000 -0800 @@ -1016,9 +1016,6 @@ struct type *builtin_bool; struct type *builtin_long_long; struct type *builtin_unsigned_long_long; - struct type *builtin_decfloat; - struct type *builtin_decdouble; - struct type *builtin_declong; }; /* Return the type table for the specified architecture. */ @@ -1107,6 +1104,9 @@ extern struct type *builtin_type_arm_ext; extern struct type *builtin_type_ia64_spill; extern struct type *builtin_type_ia64_quad; +extern struct type *builtin_type_decfloat; +extern struct type *builtin_type_decdouble; +extern struct type *builtin_type_declong; /* This type represents a type that was unrecognized in symbol read-in. */ Index: git/gdb/features/rs6000/powerpc-64.c =================================================================== --- git.orig/gdb/features/rs6000/powerpc-64.c 2007-11-05 11:37:24.000000000 -0800 +++ git/gdb/features/rs6000/powerpc-64.c 2007-11-06 04:20:22.000000000 -0800 @@ -160,5 +160,7 @@ tdesc_create_reg (feature, "vscr", 103, 1, "vector", 32, "int"); tdesc_create_reg (feature, "vrsave", 104, 1, "vector", 32, "int"); + feature = tdesc_create_feature (result, "org.gnu.gdb.power.dfp128"); + tdesc_powerpc_64 = result; } Index: git/gdb/features/rs6000/powerpc-32.c =================================================================== --- git.orig/gdb/features/rs6000/powerpc-32.c 2007-10-21 12:33:37.000000000 -0700 +++ git/gdb/features/rs6000/powerpc-32.c 2007-11-07 06:52:18.000000000 -0800 @@ -160,5 +160,7 @@ tdesc_create_reg (feature, "vscr", 103, 1, "vector", 32, "int"); tdesc_create_reg (feature, "vrsave", 104, 1, "vector", 32, "int"); + feature = tdesc_create_feature (result, "org.gnu.gdb.power.dfp128"); + tdesc_powerpc_32 = result; } Index: git/gdb/doc/gdb.texinfo =================================================================== --- git.orig/gdb/doc/gdb.texinfo 2007-11-06 04:20:21.000000000 -0800 +++ git/gdb/doc/gdb.texinfo 2007-11-07 07:12:34.000000000 -0800 @@ -26322,6 +26322,13 @@ these to present registers @samp{ev0} through @samp{ev31} to the user. +The @samp{org.gnu.gdb.power.dfp128} feature is optional and i aimed at Targets +that support DFP types. It should contain registers @samp{dl0} through +@samp{dl15}. Each @samp{dl} register is actually a pair of 64-bit Floating +Point registers, so, for example, @samp{dl0} is composed by joining @samp{f0} +and @samp{f1}. @value{GDBN} will combined the pair of Floating +Point registers to present a single @samp{dl} register. + @include gpl.texi @raisesections Index: git/gdb/testsuite/gdb.arch/powerpc-d128-regs.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ git/gdb/testsuite/gdb.arch/powerpc-d128-regs.c 2007-11-06 09:41:24.000000000 -0800 @@ -0,0 +1,25 @@ +/* This file is part of GDB, the GNU debugger. + + Copyright 2007 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +/* Tests the PPC64 Decimal128 pseudo-registers. */ + +int main(void) +{ + _Decimal128 d128 = 1.2345678910dl; + + return 0; +} Index: git/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ git/gdb/testsuite/gdb.arch/powerpc-d128-regs.exp 2007-11-06 10:04:57.000000000 -0800 @@ -0,0 +1,77 @@ +# This testcase is part of GDB, the GNU debugger. + +# Copyright 2007 +# Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +# Please email any bugs, comments, and/or additions to this file to: +# bug-gdb@gnu.org + +# Testcase for the PPC64 Decimal128 pseudo-registers. + +if $tracelevel then { + strace $tracelevel +} + +if ![istarget "powerpc64-*"] then { + verbose "Skipping powerpc64 Decimal128 pseudo-registers testcase." + return +} + +set testfile "powerpc64-d128-regs" +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} + +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {quiet debug}] != "" } { + untested printcmds.exp + return -1 +} + +# Start with a fresh gdb. + +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +if { ![runto main] } then { + fail "run to main" + return +} + +if ![gdb_test "show arch" ".*currently powerpc:common64.*" "Checking for PPC64 arch"] { + return -1; +} + +gdb_test "next" "" + +for {set i 0} {$i < 16} {incr i 1} { +gdb_test "set \$dl$i=d128" "" "Set dl$i register" + +gdb_test "print \$dl$i" "\\\$$decimal = 1\.2345678910" "Print dl$i register as DFP" + +gdb_test "info reg dl$i" \ + "dl$i\[ \]*0x2205800000000000000000049c5de09c\[\t\]*1\.2345678910" \ + "Print dl$i register with the info reg command" + +gdb_test "info reg f[expr 2*$i]" \ + "f[expr 2*$i]\[ \]*8\.608957309287334e\-145\[\t\]*\\(raw 0x2205800000000000\\)" \ + "Testing lower half of dl$i register" + +gdb_test "info reg f[expr 2*$i+1]" \ + "f[expr 2*$i+1]\[ \]*9\.7841140127686122e\-314\[\t\]*\\(raw 0x000000049c5de09c\\)" \ + "Testing upper half of dl$i register" + +}