* target-descriptions.c (tdesc_register_type): Make public.
(tdesc_unnumbered_register): New function.
(tdesc_register_reggroup_p): Allow missing
pseudo_register_reggroup_p.
* target-descriptions.h (tdesc_register_type): Declare.
(tdesc_unnumbered_register): Declare.
* arm-tdep.c (arm_neon_quad_read, arm_neon_quad_write): New functions.
(arm_push_dummy_call): Use arm_neon_quad_write.
(arm_neon_double_type, arm_neon_quad_type): New functions.
(arm_register_type): Handle VFP and NEON registers. Override the
types of double-precision registers for NEON. Disable FPA registers
if they are not present.
(arm_dwarf_reg_to_regnum): Add current VFP and NEON register numbers.
(arm_return_value): Use arm_neon_quad_write and arm_neon_quad_read.
(arm_register_name): Handle VFP single and NEON quad registers.
(arm_pseudo_read, arm_pseudo_write): New functions.
(arm_gdbarch_init): Check for VFP and NEON in the target description.
Assign numbers to double-precision registers. Register VFP and NEON
pseudo registers. Remove a shadowed "i" variable.
* arm-tdep.h (enum gdb_regnum): Add ARM_D0_REGNUM and
ARM_D31_REGNUM.
(struct gdbarch_tdep): Add have_neon_pseudos, have_neon,
have_vfp_registers, have_vfp_pseudos, neon_double_type,
and neon_quad_type.
* features/Makefile: Make expedite settings only architecture
specific.
(WHICH): Add new ARM descriptions.
* features/arm-with-neon.xml, features/arm-with-vfpv2.c,
features/arm-with-vfpv3.c, features/arm-vfpv2.xml,
features/arm-vfpv3.xml, features/arm-with-vfpv2.xml,
features/arm-with-vfpv3.xml, features/arm-with-neon.c: New files.
* regformats/arm-with-neon.dat, regformats/arm-with-vfpv2.dat,
regformats/arm-with-vfpv3.dat: Generate.
doc/
* gdb.texinfo (ARM Features): Document org.gnu.gdb.arm.vfp and
org.gnu.gdb.arm.neon.
gdbserver/
* linux-low.c (linux_write_memory): Update debugging output.
* Makefile.in (clean): Add new descriptions.
(arm-with-vfpv2.o, arm-with-vfpv2.c, arm-with-vfpv3.o)
(arm-with-vfpv3.c, arm-with-neon.o, arm-with-neon.c): New rules.
* configure.srv: Add new files for arm*-*-linux*.
* linux-arm-low.c: Add new declarations.
(PTRACE_GETVFPREGS, PTRACE_SETVFPREGS): Define if undefined.
(arm_hwcap, HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3)
(HWCAP_VFPv3D16): New.
(arm_fill_wmmxregset, arm_store_wmmxregset): Check HWCAP_IWMMXT
instead of __IWMMXT__.
(arm_fill_vfpregset, arm_store_vfpregset, arm_get_hwcap)
(arm_arch_setup): New.
(target_regsets): Remove #ifdef. Add VFP regset.
(the_low_target): Use arm_arch_setup.
testsuite/
* gdb.base/float.exp: Handle VFP registers.
+2009-07-28 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * NEWS: Mention ARM VFP support.
+ * target-descriptions.c (tdesc_register_type): Make public.
+ (tdesc_unnumbered_register): New function.
+ (tdesc_register_reggroup_p): Allow missing
+ pseudo_register_reggroup_p.
+ * target-descriptions.h (tdesc_register_type): Declare.
+ (tdesc_unnumbered_register): Declare.
+ * arm-tdep.c (arm_neon_quad_read, arm_neon_quad_write): New functions.
+ (arm_push_dummy_call): Use arm_neon_quad_write.
+ (arm_neon_double_type, arm_neon_quad_type): New functions.
+ (arm_register_type): Handle VFP and NEON registers. Override the
+ types of double-precision registers for NEON. Disable FPA registers
+ if they are not present.
+ (arm_dwarf_reg_to_regnum): Add current VFP and NEON register numbers.
+ (arm_return_value): Use arm_neon_quad_write and arm_neon_quad_read.
+ (arm_register_name): Handle VFP single and NEON quad registers.
+ (arm_pseudo_read, arm_pseudo_write): New functions.
+ (arm_gdbarch_init): Check for VFP and NEON in the target description.
+ Assign numbers to double-precision registers. Register VFP and NEON
+ pseudo registers. Remove a shadowed "i" variable.
+ * arm-tdep.h (enum gdb_regnum): Add ARM_D0_REGNUM and
+ ARM_D31_REGNUM.
+ (struct gdbarch_tdep): Add have_neon_pseudos, have_neon,
+ have_vfp_registers, have_vfp_pseudos, neon_double_type,
+ and neon_quad_type.
+
+ * features/Makefile: Make expedite settings only architecture
+ specific.
+ (WHICH): Add new ARM descriptions.
+ * features/arm-with-neon.xml, features/arm-with-vfpv2.c,
+ features/arm-with-vfpv3.c, features/arm-vfpv2.xml,
+ features/arm-vfpv3.xml, features/arm-with-vfpv2.xml,
+ features/arm-with-vfpv3.xml, features/arm-with-neon.c: New files.
+ * regformats/arm-with-neon.dat, regformats/arm-with-vfpv2.dat,
+ regformats/arm-with-vfpv3.dat: Generate.
+
2009-07-28 Daniel Jacobowitz <dan@codesourcery.com>
* infrun.c (handle_inferior_event): Clear trap_expected after
macros.
* GDB now supports inspecting extra signal information, exported by
- the new $_siginfo convenience variable. The feature is currently
- implemented on linux ARM, i386 and amd64.
+the new $_siginfo convenience variable. The feature is currently
+implemented on linux ARM, i386 and amd64.
+
+* GDB can now display the VFP floating point registers and NEON vector
+registers on ARM targets. Both ARM GNU/Linux native GDB and gdbserver
+can provide these registers (requires Linux 2.6.30 or later). Remote
+and simulator targets may also provide them.
* New remote packets
static void convert_to_extended (const struct floatformat *, void *,
const void *, int);
+static void arm_neon_quad_read (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, gdb_byte *buf);
+static void arm_neon_quad_write (struct gdbarch *gdbarch,
+ struct regcache *regcache,
+ int regnum, const gdb_byte *buf);
+
struct arm_prologue_cache
{
/* The stack pointer at the time this frame was created; i.e. the
{
char name_buf[4];
int regnum;
- sprintf (name_buf, "%c%d", reg_char, reg_scaled + i);
- regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- regcache_cooked_write (regcache, regnum,
+ if (reg_char == 'q')
+ arm_neon_quad_write (gdbarch, regcache, reg_scaled + i,
val + i * unit_length);
+ else
+ {
+ sprintf (name_buf, "%c%d", reg_char, reg_scaled + i);
+ regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+ regcache_cooked_write (regcache, regnum,
+ val + i * unit_length);
+ }
}
continue;
}
return tdep->arm_ext_type;
}
+static struct type *
+arm_neon_double_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->neon_double_type == NULL)
+ {
+ struct type *t, *elem;
+
+ t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_d",
+ TYPE_CODE_UNION);
+ elem = builtin_type (gdbarch)->builtin_uint8;
+ append_composite_type_field (t, "u8", init_vector_type (elem, 8));
+ elem = builtin_type (gdbarch)->builtin_uint16;
+ append_composite_type_field (t, "u16", init_vector_type (elem, 4));
+ elem = builtin_type (gdbarch)->builtin_uint32;
+ append_composite_type_field (t, "u32", init_vector_type (elem, 2));
+ elem = builtin_type (gdbarch)->builtin_uint64;
+ append_composite_type_field (t, "u64", elem);
+ elem = builtin_type (gdbarch)->builtin_float;
+ append_composite_type_field (t, "f32", init_vector_type (elem, 2));
+ elem = builtin_type (gdbarch)->builtin_double;
+ append_composite_type_field (t, "f64", elem);
+
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "neon_d";
+ tdep->neon_double_type = t;
+ }
+
+ return tdep->neon_double_type;
+}
+
+/* FIXME: The vector types are not correctly ordered on big-endian
+ targets. Just as s0 is the low bits of d0, d0[0] is also the low
+ bits of d0 - regardless of what unit size is being held in d0. So
+ the offset of the first uint8 in d0 is 7, but the offset of the
+ first float is 4. This code works as-is for little-endian
+ targets. */
+
+static struct type *
+arm_neon_quad_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->neon_quad_type == NULL)
+ {
+ struct type *t, *elem;
+
+ t = arch_composite_type (gdbarch, "__gdb_builtin_type_neon_q",
+ TYPE_CODE_UNION);
+ elem = builtin_type (gdbarch)->builtin_uint8;
+ append_composite_type_field (t, "u8", init_vector_type (elem, 16));
+ elem = builtin_type (gdbarch)->builtin_uint16;
+ append_composite_type_field (t, "u16", init_vector_type (elem, 8));
+ elem = builtin_type (gdbarch)->builtin_uint32;
+ append_composite_type_field (t, "u32", init_vector_type (elem, 4));
+ elem = builtin_type (gdbarch)->builtin_uint64;
+ append_composite_type_field (t, "u64", init_vector_type (elem, 2));
+ elem = builtin_type (gdbarch)->builtin_float;
+ append_composite_type_field (t, "f32", init_vector_type (elem, 4));
+ elem = builtin_type (gdbarch)->builtin_double;
+ append_composite_type_field (t, "f64", init_vector_type (elem, 2));
+
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "neon_q";
+ tdep->neon_quad_type = t;
+ }
+
+ return tdep->neon_quad_type;
+}
+
/* Return the GDB type object for the "standard" data type of data in
register N. */
static struct type *
arm_register_type (struct gdbarch *gdbarch, int regnum)
{
+ int num_regs = gdbarch_num_regs (gdbarch);
+
+ if (gdbarch_tdep (gdbarch)->have_vfp_pseudos
+ && regnum >= num_regs && regnum < num_regs + 32)
+ return builtin_type (gdbarch)->builtin_float;
+
+ if (gdbarch_tdep (gdbarch)->have_neon_pseudos
+ && regnum >= num_regs + 32 && regnum < num_regs + 32 + 16)
+ return arm_neon_quad_type (gdbarch);
+
+ /* If the target description has register information, we are only
+ in this function so that we can override the types of
+ double-precision registers for NEON. */
+ if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
+ {
+ struct type *t = tdesc_register_type (gdbarch, regnum);
+
+ if (regnum >= ARM_D0_REGNUM && regnum < ARM_D0_REGNUM + 32
+ && TYPE_CODE (t) == TYPE_CODE_FLT
+ && gdbarch_tdep (gdbarch)->have_neon)
+ return arm_neon_double_type (gdbarch);
+ else
+ return t;
+ }
+
if (regnum >= ARM_F0_REGNUM && regnum < ARM_F0_REGNUM + NUM_FREGS)
- return arm_ext_type (gdbarch);
+ {
+ if (!gdbarch_tdep (gdbarch)->have_fpa_registers)
+ return builtin_type (gdbarch)->builtin_void;
+
+ return arm_ext_type (gdbarch);
+ }
else if (regnum == ARM_SP_REGNUM)
return builtin_type (gdbarch)->builtin_data_ptr;
else if (regnum == ARM_PC_REGNUM)
if (reg >= 192 && reg <= 199)
return ARM_WC0_REGNUM + reg - 192;
+ /* VFP v2 registers. A double precision value is actually
+ in d1 rather than s2, but the ABI only defines numbering
+ for the single precision registers. This will "just work"
+ in GDB for little endian targets (we'll read eight bytes,
+ starting in s0 and then progressing to s1), but will be
+ reversed on big endian targets with VFP. This won't
+ be a problem for the new Neon quad registers; you're supposed
+ to use DW_OP_piece for those. */
+ if (reg >= 64 && reg <= 95)
+ {
+ char name_buf[4];
+
+ sprintf (name_buf, "s%d", reg - 64);
+ return user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+ }
+
+ /* VFP v3 / Neon registers. This range is also used for VFP v2
+ registers, except that it now describes d0 instead of s0. */
+ if (reg >= 256 && reg <= 287)
+ {
+ char name_buf[4];
+
+ sprintf (name_buf, "d%d", reg - 256);
+ return user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+ }
+
return -1;
}
int i;
for (i = 0; i < vfp_base_count; i++)
{
- char name_buf[4];
- int regnum;
- sprintf (name_buf, "%c%d", reg_char, i);
- regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
- strlen (name_buf));
- if (writebuf)
- regcache_cooked_write (regcache, regnum,
- writebuf + i * unit_length);
- if (readbuf)
- regcache_cooked_read (regcache, regnum,
- readbuf + i * unit_length);
+ if (reg_char == 'q')
+ {
+ if (writebuf)
+ arm_neon_quad_write (gdbarch, regcache, i,
+ writebuf + i * unit_length);
+
+ if (readbuf)
+ arm_neon_quad_read (gdbarch, regcache, i,
+ readbuf + i * unit_length);
+ }
+ else
+ {
+ char name_buf[4];
+ int regnum;
+
+ sprintf (name_buf, "%c%d", reg_char, i);
+ regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+ if (writebuf)
+ regcache_cooked_write (regcache, regnum,
+ writebuf + i * unit_length);
+ if (readbuf)
+ regcache_cooked_read (regcache, regnum,
+ readbuf + i * unit_length);
+ }
}
return RETURN_VALUE_REGISTER_CONVENTION;
}
static const char *
arm_register_name (struct gdbarch *gdbarch, int i)
{
+ const int num_regs = gdbarch_num_regs (gdbarch);
+
+ if (gdbarch_tdep (gdbarch)->have_vfp_pseudos
+ && i >= num_regs && i < num_regs + 32)
+ {
+ static const char *const vfp_pseudo_names[] = {
+ "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
+ "s8", "s9", "s10", "s11", "s12", "s13", "s14", "s15",
+ "s16", "s17", "s18", "s19", "s20", "s21", "s22", "s23",
+ "s24", "s25", "s26", "s27", "s28", "s29", "s30", "s31",
+ };
+
+ return vfp_pseudo_names[i - num_regs];
+ }
+
+ if (gdbarch_tdep (gdbarch)->have_neon_pseudos
+ && i >= num_regs + 32 && i < num_regs + 32 + 16)
+ {
+ static const char *const neon_pseudo_names[] = {
+ "q0", "q1", "q2", "q3", "q4", "q5", "q6", "q7",
+ "q8", "q9", "q10", "q11", "q12", "q13", "q14", "q15",
+ };
+
+ return neon_pseudo_names[i - num_regs - 32];
+ }
+
if (i >= ARRAY_SIZE (arm_register_names))
/* These registers are only supported on targets which supply
an XML description. */
}
}
+/* Read the contents of a NEON quad register, by reading from two
+ double registers. This is used to implement the quad pseudo
+ registers, and for argument passing in case the quad registers are
+ missing; vectors are passed in quad registers when using the VFP
+ ABI, even if a NEON unit is not present. REGNUM is the index of
+ the quad register, in [0, 15]. */
+
+static void
+arm_neon_quad_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, gdb_byte *buf)
+{
+ char name_buf[4];
+ gdb_byte reg_buf[8];
+ int offset, double_regnum;
+
+ sprintf (name_buf, "d%d", regnum << 1);
+ double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+
+ /* d0 is always the least significant half of q0. */
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ offset = 8;
+ else
+ offset = 0;
+
+ regcache_raw_read (regcache, double_regnum, reg_buf);
+ memcpy (buf + offset, reg_buf, 8);
+
+ offset = 8 - offset;
+ regcache_raw_read (regcache, double_regnum + 1, reg_buf);
+ memcpy (buf + offset, reg_buf, 8);
+}
+
+static void
+arm_pseudo_read (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, gdb_byte *buf)
+{
+ const int num_regs = gdbarch_num_regs (gdbarch);
+ char name_buf[4];
+ gdb_byte reg_buf[8];
+ int offset, double_regnum;
+
+ gdb_assert (regnum >= num_regs);
+ regnum -= num_regs;
+
+ if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
+ /* Quad-precision register. */
+ arm_neon_quad_read (gdbarch, regcache, regnum - 32, buf);
+ else
+ {
+ /* Single-precision register. */
+ gdb_assert (regnum < 32);
+
+ /* s0 is always the least significant half of d0. */
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ offset = (regnum & 1) ? 0 : 4;
+ else
+ offset = (regnum & 1) ? 4 : 0;
+
+ sprintf (name_buf, "d%d", regnum >> 1);
+ double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+
+ regcache_raw_read (regcache, double_regnum, reg_buf);
+ memcpy (buf, reg_buf + offset, 4);
+ }
+}
+
+/* Store the contents of BUF to a NEON quad register, by writing to
+ two double registers. This is used to implement the quad pseudo
+ registers, and for argument passing in case the quad registers are
+ missing; vectors are passed in quad registers when using the VFP
+ ABI, even if a NEON unit is not present. REGNUM is the index
+ of the quad register, in [0, 15]. */
+
+static void
+arm_neon_quad_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, const gdb_byte *buf)
+{
+ char name_buf[4];
+ gdb_byte reg_buf[8];
+ int offset, double_regnum;
+
+ sprintf (name_buf, "d%d", regnum << 1);
+ double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+
+ /* d0 is always the least significant half of q0. */
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ offset = 8;
+ else
+ offset = 0;
+
+ regcache_raw_write (regcache, double_regnum, buf + offset);
+ offset = 8 - offset;
+ regcache_raw_write (regcache, double_regnum + 1, buf + offset);
+}
+
+static void
+arm_pseudo_write (struct gdbarch *gdbarch, struct regcache *regcache,
+ int regnum, const gdb_byte *buf)
+{
+ const int num_regs = gdbarch_num_regs (gdbarch);
+ char name_buf[4];
+ gdb_byte reg_buf[8];
+ int offset, double_regnum;
+
+ gdb_assert (regnum >= num_regs);
+ regnum -= num_regs;
+
+ if (gdbarch_tdep (gdbarch)->have_neon_pseudos && regnum >= 32 && regnum < 48)
+ /* Quad-precision register. */
+ arm_neon_quad_write (gdbarch, regcache, regnum - 32, buf);
+ else
+ {
+ /* Single-precision register. */
+ gdb_assert (regnum < 32);
+
+ /* s0 is always the least significant half of d0. */
+ if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
+ offset = (regnum & 1) ? 0 : 4;
+ else
+ offset = (regnum & 1) ? 4 : 0;
+
+ sprintf (name_buf, "d%d", regnum >> 1);
+ double_regnum = user_reg_map_name_to_regnum (gdbarch, name_buf,
+ strlen (name_buf));
+
+ regcache_raw_read (regcache, double_regnum, reg_buf);
+ memcpy (reg_buf + offset, buf, 4);
+ regcache_raw_write (regcache, double_regnum, reg_buf);
+ }
+}
+
static struct value *
value_of_arm_user_reg (struct frame_info *frame, const void *baton)
{
enum arm_float_model fp_model = arm_fp_model;
struct tdesc_arch_data *tdesc_data = NULL;
int i;
+ int have_vfp_registers = 0, have_vfp_pseudos = 0, have_neon_pseudos = 0;
+ int have_neon = 0;
int have_fpa_registers = 1;
/* Check any target description for validity. */
static const char *const arm_pc_names[] = { "r15", "pc", NULL };
const struct tdesc_feature *feature;
- int i, valid_p;
+ int valid_p;
feature = tdesc_find_feature (info.target_desc,
"org.gnu.gdb.arm.core");
return NULL;
}
}
+
+ /* If we have a VFP unit, check whether the single precision registers
+ are present. If not, then we will synthesize them as pseudo
+ registers. */
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.arm.vfp");
+ if (feature != NULL)
+ {
+ static const char *const vfp_double_names[] = {
+ "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
+ "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15",
+ "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23",
+ "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31",
+ };
+
+ /* Require the double precision registers. There must be either
+ 16 or 32. */
+ valid_p = 1;
+ for (i = 0; i < 32; i++)
+ {
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ ARM_D0_REGNUM + i,
+ vfp_double_names[i]);
+ if (!valid_p)
+ break;
+ }
+
+ if (!valid_p && i != 16)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ if (tdesc_unnumbered_register (feature, "s0") == 0)
+ have_vfp_pseudos = 1;
+
+ have_vfp_registers = 1;
+
+ /* If we have VFP, also check for NEON. The architecture allows
+ NEON without VFP (integer vector operations only), but GDB
+ does not support that. */
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.arm.neon");
+ if (feature != NULL)
+ {
+ /* NEON requires 32 double-precision registers. */
+ if (i != 32)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ /* If there are quad registers defined by the stub, use
+ their type; otherwise (normally) provide them with
+ the default type. */
+ if (tdesc_unnumbered_register (feature, "q0") == 0)
+ have_neon_pseudos = 1;
+
+ have_neon = 1;
+ }
+ }
}
/* If we have an object to base this architecture on, try to determine
&& fp_model != gdbarch_tdep (best_arch->gdbarch)->fp_model)
continue;
+ /* There are various other properties in tdep that we do not
+ need to check here: those derived from a target description,
+ since gdbarches with a different target description are
+ automatically disqualified. */
+
/* Found a match. */
break;
}
tdep->arm_abi = arm_abi;
tdep->fp_model = fp_model;
tdep->have_fpa_registers = have_fpa_registers;
+ tdep->have_vfp_registers = have_vfp_registers;
+ tdep->have_vfp_pseudos = have_vfp_pseudos;
+ tdep->have_neon_pseudos = have_neon_pseudos;
+ tdep->have_neon = have_neon;
/* Breakpoints. */
switch (info.byte_order_for_code)
set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
}
+ if (have_vfp_pseudos)
+ {
+ /* NOTE: These are the only pseudo registers used by
+ the ARM target at the moment. If more are added, a
+ little more care in numbering will be needed. */
+
+ int num_pseudos = 32;
+ if (have_neon_pseudos)
+ num_pseudos += 16;
+ set_gdbarch_num_pseudo_regs (gdbarch, num_pseudos);
+ set_gdbarch_pseudo_register_read (gdbarch, arm_pseudo_read);
+ set_gdbarch_pseudo_register_write (gdbarch, arm_pseudo_write);
+ }
+
if (tdesc_data)
- tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+ {
+ set_tdesc_pseudo_register_name (gdbarch, arm_register_name);
+
+ tdesc_use_registers (gdbarch, info.target_desc, tdesc_data);
+
+ /* Override tdesc_register_type to adjust the types of VFP
+ registers for NEON. */
+ set_gdbarch_register_type (gdbarch, arm_register_type);
+ }
/* Add standard register aliases. We add aliases even for those
nanes which are used by the current architecture - it's simpler,
ARM_WCGR0_REGNUM, /* WMMX general purpose registers. */
ARM_WCGR3_REGNUM = ARM_WCGR0_REGNUM + 3,
ARM_WCGR7_REGNUM = ARM_WCGR0_REGNUM + 7,
+ ARM_D0_REGNUM, /* VFP double-precision registers. */
+ ARM_D31_REGNUM = ARM_D0_REGNUM + 31,
ARM_NUM_REGS,
enum arm_float_model fp_model; /* Floating point calling conventions. */
int have_fpa_registers; /* Does the target report the FPA registers? */
+ int have_vfp_registers; /* Does the target report the VFP registers? */
+ int have_vfp_pseudos; /* Are we synthesizing the single precision
+ VFP registers? */
+ int have_neon_pseudos; /* Are we synthesizing the quad precision
+ NEON registers? Requires
+ have_vfp_pseudos. */
+ int have_neon; /* Do we have a NEON unit? */
CORE_ADDR lowest_pc; /* Lowest address at which instructions
will appear. */
/* ISA-specific data types. */
struct type *arm_ext_type;
+ struct type *neon_double_type;
+ struct type *neon_quad_type;
};
+2009-07-28 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * gdb.texinfo (ARM Features): Document org.gnu.gdb.arm.vfp and
+ org.gnu.gdb.arm.neon.
+
2009-07-20 Pedro Alves <pedro@codesourcery.com>
* gdb.texinfo (Target Description Format): Mention the new <osabi>
@samp{wCGR0} through @samp{wCGR3}. The @samp{wCID}, @samp{wCon},
@samp{wCSSF}, and @samp{wCASF} registers are optional.
+The @samp{org.gnu.gdb.arm.vfp} feature is optional. If present, it
+should contain at least registers @samp{d0} through @samp{d15}. If
+they are present, @samp{d16} through @samp{d31} should also be included.
+@value{GDBN} will synthesize the single-precision registers from
+halves of the double-precision registers.
+
+The @samp{org.gnu.gdb.arm.neon} feature is optional. It does not
+need to contain registers; it instructs @value{GDBN} to display the
+VFP double-precision registers as vectors and to synthesize the
+quad-precision registers from pairs of double-precision registers.
+If this feature is present, @samp{org.gnu.gdb.arm.vfp} must also
+be present and include 32 double-precision registers.
+
@node MIPS Features
@subsection MIPS Features
@cindex target descriptions, MIPS features
# in the GDB repository. To generate C files:
# make GDB=/path/to/gdb XMLTOC="xml files" cfiles
-WHICH = arm-with-iwmmxt mips-linux mips64-linux \
+WHICH = arm-with-iwmmxt arm-with-vfpv2 arm-with-vfpv3 arm-with-neon \
+ mips-linux mips64-linux \
rs6000/powerpc-32l rs6000/powerpc-altivec32l rs6000/powerpc-e500l \
rs6000/powerpc-64l rs6000/powerpc-altivec64l rs6000/powerpc-vsx32l \
rs6000/powerpc-vsx64l
# Record which registers should be sent to GDB by default after stop.
-arm-with-iwmmxt-expedite = r11,sp,pc
-mips-linux-expedite = r29,pc
-mips64-linux-expedite = r29,pc
-rs6000/powerpc-32l-expedite = r1,pc
-rs6000/powerpc-altivec32l-expedite = r1,pc
-rs6000/powerpc-vsx32l-expedite = r1,pc
-rs6000/powerpc-isa205-32l-expedite = r1,pc
-rs6000/powerpc-isa205-altivec32l-expedite = r1,pc
-rs6000/powerpc-isa205-vsx32l-expedite = r1,pc
-rs6000/powerpc-e500l-expedite = r1,pc
-rs6000/powerpc-64l-expedite = r1,pc
-rs6000/powerpc-altivec64l-expedite = r1,pc
-rs6000/powerpc-vsx64l-expedite = r1,pc
-rs6000/powerpc-isa205-64l-expedite = r1,pc
-rs6000/powerpc-isa205-altivec64l-expedite = r1,pc
-rs6000/powerpc-isa205-vsx64l-expedite = r1,pc
+arm-expedite = r11,sp,pc
+mips-expedite = r29,pc
+mips64-expedite = r29,pc
+powerpc-expedite = r1,pc
XSLTPROC = xsltproc
echo "# DO NOT EDIT: generated from $<" > $(outdir)/$*.tmp
echo "name:`echo $(notdir $*) | sed 's/-/_/g'`" >> $(outdir)/$*.tmp
echo "xmltarget:$(<F)" >> $(outdir)/$*.tmp
- echo "expedite:$($*-expedite)" >> $(outdir)/$*.tmp
+ echo "expedite:$($(firstword $(subst -, ,$(notdir $*)))-expedite)" >> $(outdir)/$*.tmp
$(XSLTPROC) --path "$(PWD)" --xinclude number-regs.xsl $< | \
$(XSLTPROC) sort-regs.xsl - | \
$(XSLTPROC) gdbserver-regs.xsl - >> $(outdir)/$*.tmp
--- /dev/null
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+ <reg name="d0" bitsize="64" type="ieee_double"/>
+ <reg name="d1" bitsize="64" type="ieee_double"/>
+ <reg name="d2" bitsize="64" type="ieee_double"/>
+ <reg name="d3" bitsize="64" type="ieee_double"/>
+ <reg name="d4" bitsize="64" type="ieee_double"/>
+ <reg name="d5" bitsize="64" type="ieee_double"/>
+ <reg name="d6" bitsize="64" type="ieee_double"/>
+ <reg name="d7" bitsize="64" type="ieee_double"/>
+ <reg name="d8" bitsize="64" type="ieee_double"/>
+ <reg name="d9" bitsize="64" type="ieee_double"/>
+ <reg name="d10" bitsize="64" type="ieee_double"/>
+ <reg name="d11" bitsize="64" type="ieee_double"/>
+ <reg name="d12" bitsize="64" type="ieee_double"/>
+ <reg name="d13" bitsize="64" type="ieee_double"/>
+ <reg name="d14" bitsize="64" type="ieee_double"/>
+ <reg name="d15" bitsize="64" type="ieee_double"/>
+
+ <reg name="fpscr" bitsize="32" type="int" group="float"/>
+</feature>
--- /dev/null
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE feature SYSTEM "gdb-target.dtd">
+<feature name="org.gnu.gdb.arm.vfp">
+ <reg name="d0" bitsize="64" type="ieee_double"/>
+ <reg name="d1" bitsize="64" type="ieee_double"/>
+ <reg name="d2" bitsize="64" type="ieee_double"/>
+ <reg name="d3" bitsize="64" type="ieee_double"/>
+ <reg name="d4" bitsize="64" type="ieee_double"/>
+ <reg name="d5" bitsize="64" type="ieee_double"/>
+ <reg name="d6" bitsize="64" type="ieee_double"/>
+ <reg name="d7" bitsize="64" type="ieee_double"/>
+ <reg name="d8" bitsize="64" type="ieee_double"/>
+ <reg name="d9" bitsize="64" type="ieee_double"/>
+ <reg name="d10" bitsize="64" type="ieee_double"/>
+ <reg name="d11" bitsize="64" type="ieee_double"/>
+ <reg name="d12" bitsize="64" type="ieee_double"/>
+ <reg name="d13" bitsize="64" type="ieee_double"/>
+ <reg name="d14" bitsize="64" type="ieee_double"/>
+ <reg name="d15" bitsize="64" type="ieee_double"/>
+ <reg name="d16" bitsize="64" type="ieee_double"/>
+ <reg name="d17" bitsize="64" type="ieee_double"/>
+ <reg name="d18" bitsize="64" type="ieee_double"/>
+ <reg name="d19" bitsize="64" type="ieee_double"/>
+ <reg name="d20" bitsize="64" type="ieee_double"/>
+ <reg name="d21" bitsize="64" type="ieee_double"/>
+ <reg name="d22" bitsize="64" type="ieee_double"/>
+ <reg name="d23" bitsize="64" type="ieee_double"/>
+ <reg name="d24" bitsize="64" type="ieee_double"/>
+ <reg name="d25" bitsize="64" type="ieee_double"/>
+ <reg name="d26" bitsize="64" type="ieee_double"/>
+ <reg name="d27" bitsize="64" type="ieee_double"/>
+ <reg name="d28" bitsize="64" type="ieee_double"/>
+ <reg name="d29" bitsize="64" type="ieee_double"/>
+ <reg name="d30" bitsize="64" type="ieee_double"/>
+ <reg name="d31" bitsize="64" type="ieee_double"/>
+
+ <reg name="fpscr" bitsize="32" type="int" group="float"/>
+</feature>
--- /dev/null
+/* THIS FILE IS GENERATED. Original: arm-with-neon.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_arm_with_neon;
+static void
+initialize_tdesc_arm_with_neon (void)
+{
+ struct target_desc *result = allocate_target_description ();
+ struct tdesc_feature *feature;
+ struct type *field_type, *type;
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core");
+ tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr");
+ tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr");
+ tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int");
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp");
+ tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d16", 42, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d17", 43, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d18", 44, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d19", 45, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d20", 46, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d21", 47, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d22", 48, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d23", 49, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d24", 50, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d25", 51, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d26", 52, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d27", 53, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d28", 54, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d29", 55, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d30", 56, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d31", 57, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "fpscr", 58, 1, "float", 32, "int");
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.neon");
+
+ tdesc_arm_with_neon = result;
+}
--- /dev/null
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+ <xi:include href="arm-core.xml"/>
+ <xi:include href="arm-vfpv3.xml"/>
+ <feature name="org.gnu.gdb.arm.neon"/>
+</target>
--- /dev/null
+/* THIS FILE IS GENERATED. Original: arm-with-vfpv2.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_arm_with_vfpv2;
+static void
+initialize_tdesc_arm_with_vfpv2 (void)
+{
+ struct target_desc *result = allocate_target_description ();
+ struct tdesc_feature *feature;
+ struct type *field_type, *type;
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core");
+ tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr");
+ tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr");
+ tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int");
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp");
+ tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "fpscr", 42, 1, "float", 32, "int");
+
+ tdesc_arm_with_vfpv2 = result;
+}
--- /dev/null
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+ <xi:include href="arm-core.xml"/>
+ <xi:include href="arm-vfpv2.xml"/>
+</target>
--- /dev/null
+/* THIS FILE IS GENERATED. Original: arm-with-vfpv3.xml */
+
+#include "defs.h"
+#include "gdbtypes.h"
+#include "target-descriptions.h"
+
+struct target_desc *tdesc_arm_with_vfpv3;
+static void
+initialize_tdesc_arm_with_vfpv3 (void)
+{
+ struct target_desc *result = allocate_target_description ();
+ struct tdesc_feature *feature;
+ struct type *field_type, *type;
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.core");
+ tdesc_create_reg (feature, "r0", 0, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r1", 1, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r2", 2, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r3", 3, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r4", 4, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r5", 5, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r6", 6, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r7", 7, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r8", 8, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r9", 9, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r10", 10, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r11", 11, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "r12", 12, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "sp", 13, 1, NULL, 32, "data_ptr");
+ tdesc_create_reg (feature, "lr", 14, 1, NULL, 32, "int");
+ tdesc_create_reg (feature, "pc", 15, 1, NULL, 32, "code_ptr");
+ tdesc_create_reg (feature, "cpsr", 25, 1, NULL, 32, "int");
+
+ feature = tdesc_create_feature (result, "org.gnu.gdb.arm.vfp");
+ tdesc_create_reg (feature, "d0", 26, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d1", 27, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d2", 28, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d3", 29, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d4", 30, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d5", 31, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d6", 32, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d7", 33, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d8", 34, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d9", 35, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d10", 36, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d11", 37, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d12", 38, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d13", 39, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d14", 40, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d15", 41, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d16", 42, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d17", 43, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d18", 44, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d19", 45, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d20", 46, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d21", 47, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d22", 48, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d23", 49, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d24", 50, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d25", 51, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d26", 52, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d27", 53, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d28", 54, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d29", 55, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d30", 56, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "d31", 57, 1, NULL, 64, "ieee_double");
+ tdesc_create_reg (feature, "fpscr", 58, 1, "float", 32, "int");
+
+ tdesc_arm_with_vfpv3 = result;
+}
--- /dev/null
+<?xml version="1.0"?>
+<!-- Copyright (C) 2009 Free Software Foundation, Inc.
+
+ Copying and distribution of this file, with or without modification,
+ are permitted in any medium without royalty provided the copyright
+ notice and this notice are preserved. -->
+
+<!DOCTYPE target SYSTEM "gdb-target.dtd">
+<target>
+ <xi:include href="arm-core.xml"/>
+ <xi:include href="arm-vfpv3.xml"/>
+</target>
+2009-07-28 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * linux-low.c (linux_write_memory): Update debugging output.
+ * Makefile.in (clean): Add new descriptions.
+ (arm-with-vfpv2.o, arm-with-vfpv2.c, arm-with-vfpv3.o)
+ (arm-with-vfpv3.c, arm-with-neon.o, arm-with-neon.c): New rules.
+ * configure.srv: Add new files for arm*-*-linux*.
+ * linux-arm-low.c: Add new declarations.
+ (PTRACE_GETVFPREGS, PTRACE_SETVFPREGS): Define if undefined.
+ (arm_hwcap, HWCAP_VFP, HWCAP_IWMMXT, HWCAP_NEON, HWCAP_VFPv3)
+ (HWCAP_VFPv3D16): New.
+ (arm_fill_wmmxregset, arm_store_wmmxregset): Check HWCAP_IWMMXT
+ instead of __IWMMXT__.
+ (arm_fill_vfpregset, arm_store_vfpregset, arm_get_hwcap)
+ (arm_arch_setup): New.
+ (target_regsets): Remove #ifdef. Add VFP regset.
+ (the_low_target): Use arm_arch_setup.
+
2009-07-28 Daniel Jacobowitz <dan@codesourcery.com>
* linux-low.c (linux_kill_one_lwp): Adjust kernel workaround to skip
rm -f reg-arm.c reg-i386.c reg-ia64.c reg-m32r.c reg-m68k.c
rm -f reg-sh.c reg-sparc.c reg-spu.c reg-x86-64.c reg-i386-linux.c
rm -f reg-cris.c reg-crisv32.c reg-x86-64-linux.c reg-xtensa.c
- rm -f arm-with-iwmmxt.c mips-linux.c mips64-linux.c
+ rm -f arm-with-iwmmxt.c
+ rm -f arm-with-vfpv2.c arm-with-vfpv3.c arm-with-neon.c
+ rm -f mips-linux.c mips64-linux.c
rm -f powerpc-32l.c powerpc-64l.c powerpc-e500l.c
rm -f powerpc-altivec32l.c powerpc-vsx32l.c powerpc-altivec64l.c
rm -f powerpc-vsx64l.c
arm-with-iwmmxt.o : arm-with-iwmmxt.c $(regdef_h)
arm-with-iwmmxt.c : $(srcdir)/../regformats/arm-with-iwmmxt.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-iwmmxt.dat arm-with-iwmmxt.c
+arm-with-vfpv2.o : arm-with-vfpv2.c $(regdef_h)
+arm-with-vfpv2.c : $(srcdir)/../regformats/arm-with-vfpv2.dat $(regdat_sh)
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-vfpv2.dat arm-with-vfpv2.c
+arm-with-vfpv3.o : arm-with-vfpv3.c $(regdef_h)
+arm-with-vfpv3.c : $(srcdir)/../regformats/arm-with-vfpv3.dat $(regdat_sh)
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-vfpv3.dat arm-with-vfpv3.c
+arm-with-neon.o : arm-with-neon.c $(regdef_h)
+arm-with-neon.c : $(srcdir)/../regformats/arm-with-neon.dat $(regdat_sh)
+ $(SHELL) $(regdat_sh) $(srcdir)/../regformats/arm-with-neon.dat arm-with-neon.c
reg-cris.o : reg-cris.c $(regdef_h)
reg-cris.c : $(srcdir)/../regformats/reg-cris.dat $(regdat_sh)
$(SHELL) $(regdat_sh) $(srcdir)/../regformats/reg-cris.dat reg-cris.c
case "${target}" in
arm*-*-linux*) srv_regobj="reg-arm.o arm-with-iwmmxt.o"
+ srv_regobj="${srv_regobj} arm-with-vfpv2.o"
+ srv_regobj="${srv_regobj} arm-with-vfpv3.o"
+ srv_regobj="${srv_regobj} arm-with-neon.o"
srv_tgtobj="linux-low.o linux-arm-low.o"
srv_xmlfiles="arm-with-iwmmxt.xml"
+ srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv2.xml"
+ srv_xmlfiles="${srv_xmlfiles} arm-with-vfpv3.xml"
+ srv_xmlfiles="${srv_xmlfiles} arm-with-neon.xml"
srv_xmlfiles="${srv_xmlfiles} arm-core.xml"
srv_xmlfiles="${srv_xmlfiles} xscale-iwmmxt.xml"
+ srv_xmlfiles="${srv_xmlfiles} arm-vfpv2.xml"
+ srv_xmlfiles="${srv_xmlfiles} arm-vfpv3.xml"
srv_linux_usrregs=yes
srv_linux_regsets=yes
srv_linux_thread_db=yes
#include "server.h"
#include "linux-low.h"
+#include <elf.h>
#include <sys/ptrace.h>
#include "gdb_proc_service.h"
-/* Defined in auto-generated file reg-arm.c. */
+/* Defined in auto-generated files. */
void init_registers_arm (void);
-/* Defined in auto-generated file arm-with-iwmmxt.c. */
void init_registers_arm_with_iwmmxt (void);
+void init_registers_arm_with_vfpv2 (void);
+void init_registers_arm_with_vfpv3 (void);
+void init_registers_arm_with_neon (void);
#ifndef PTRACE_GET_THREAD_AREA
#define PTRACE_GET_THREAD_AREA 22
# define PTRACE_SETWMMXREGS 19
#endif
+#ifndef PTRACE_GETVFPREGS
+# define PTRACE_GETVFPREGS 27
+# define PTRACE_SETVFPREGS 28
+#endif
+
+static unsigned long arm_hwcap;
+
+/* These are in <asm/elf.h> in current kernels. */
+#define HWCAP_VFP 64
+#define HWCAP_IWMMXT 512
+#define HWCAP_NEON 4096
+#define HWCAP_VFPv3 8192
+#define HWCAP_VFPv3D16 16384
+
#ifdef HAVE_SYS_REG_H
#include <sys/reg.h>
#endif
supply_register (i, zerobuf);
}
-#ifdef __IWMMXT__
-
static void
arm_fill_wmmxregset (void *buf)
{
int i;
+ if (!(arm_hwcap & HWCAP_IWMMXT))
+ return;
+
for (i = 0; i < 16; i++)
collect_register (arm_num_regs + i, (char *) buf + i * 8);
{
int i;
+ if (!(arm_hwcap & HWCAP_IWMMXT))
+ return;
+
for (i = 0; i < 16; i++)
supply_register (arm_num_regs + i, (char *) buf + i * 8);
supply_register (arm_num_regs + i + 16, (char *) buf + 16 * 8 + i * 4);
}
-#endif /* __IWMMXT__ */
+static void
+arm_fill_vfpregset (void *buf)
+{
+ int i, num, base;
+
+ if (!(arm_hwcap & HWCAP_VFP))
+ return;
+
+ if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+ num = 32;
+ else
+ num = 16;
+
+ base = find_regno ("d0");
+ for (i = 0; i < num; i++)
+ collect_register (base + i, (char *) buf + i * 8);
+
+ collect_register_by_name ("fpscr", (char *) buf + 32 * 8);
+}
+
+static void
+arm_store_vfpregset (const void *buf)
+{
+ int i, num, base;
+
+ if (!(arm_hwcap & HWCAP_VFP))
+ return;
+
+ if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+ num = 32;
+ else
+ num = 16;
+
+ base = find_regno ("d0");
+ for (i = 0; i < num; i++)
+ supply_register (base + i, (char *) buf + i * 8);
+
+ supply_register_by_name ("fpscr", (char *) buf + 32 * 8);
+}
extern int debug_threads;
return PS_OK;
}
+static int
+arm_get_hwcap (unsigned long *valp)
+{
+ unsigned char *data = alloca (8);
+ int offset = 0;
+
+ while ((*the_target->read_auxv) (offset, data, 8) == 8)
+ {
+ unsigned int *data_p = (unsigned int *)data;
+ if (data_p[0] == AT_HWCAP)
+ {
+ *valp = data_p[1];
+ return 1;
+ }
+
+ offset += 8;
+ }
+
+ *valp = 0;
+ return 0;
+}
+
+static void
+arm_arch_setup (void)
+{
+ arm_hwcap = 0;
+ if (arm_get_hwcap (&arm_hwcap) == 0)
+ {
+ init_registers_arm ();
+ return;
+ }
+
+ if (arm_hwcap & HWCAP_IWMMXT)
+ {
+ init_registers_arm_with_iwmmxt ();
+ return;
+ }
+
+ if (arm_hwcap & HWCAP_VFP)
+ {
+ int pid;
+ char *buf;
+
+ /* NEON implies either no VFP, or VFPv3-D32. We only support
+ it with VFP. */
+ if (arm_hwcap & HWCAP_NEON)
+ init_registers_arm_with_neon ();
+ else if ((arm_hwcap & (HWCAP_VFPv3 | HWCAP_VFPv3D16)) == HWCAP_VFPv3)
+ init_registers_arm_with_vfpv3 ();
+ else
+ init_registers_arm_with_vfpv2 ();
+
+ /* Now make sure that the kernel supports reading these
+ registers. Support was added in 2.6.30. */
+ pid = lwpid_of (get_thread_lwp (current_inferior));
+ errno = 0;
+ buf = malloc (32 * 8 + 4);
+ if (ptrace (PTRACE_GETVFPREGS, pid, 0, buf) < 0
+ && errno == EIO)
+ {
+ arm_hwcap = 0;
+ init_registers_arm ();
+ }
+ free (buf);
+
+ return;
+ }
+
+ /* The default configuration uses legacy FPA registers, probably
+ simulated. */
+ init_registers_arm ();
+}
+
struct regset_info target_regsets[] = {
{ PTRACE_GETREGS, PTRACE_SETREGS, 18 * 4,
GENERAL_REGS,
arm_fill_gregset, arm_store_gregset },
-#ifdef __IWMMXT__
{ PTRACE_GETWMMXREGS, PTRACE_SETWMMXREGS, 16 * 8 + 6 * 4,
EXTENDED_REGS,
arm_fill_wmmxregset, arm_store_wmmxregset },
-#endif
+ { PTRACE_GETVFPREGS, PTRACE_SETVFPREGS, 32 * 8 + 4,
+ EXTENDED_REGS,
+ arm_fill_vfpregset, arm_store_vfpregset },
{ 0, 0, -1, -1, NULL, NULL }
};
struct linux_target_ops the_low_target = {
-#ifdef __IWMMXT__
- init_registers_arm_with_iwmmxt,
-#else
- init_registers_arm,
-#endif
+ arm_arch_setup,
arm_num_regs,
arm_regmap,
arm_cannot_fetch_register,
if (debug_threads)
{
- fprintf (stderr, "Writing %02x to %08lx\n", (unsigned)myaddr[0], (long)memaddr);
+ /* Dump up to four bytes. */
+ unsigned int val = * (unsigned int *) myaddr;
+ if (len == 1)
+ val = val & 0xff;
+ else if (len == 2)
+ val = val & 0xffff;
+ else if (len == 3)
+ val = val & 0xffffff;
+ fprintf (stderr, "Writing %0*x to 0x%08lx\n", 2 * ((len < 4) ? len : 4),
+ val, (long)memaddr);
}
/* Fill start and end extra bytes of buffer with existing memory data. */
--- /dev/null
+# DO NOT EDIT: generated from arm-with-neon.xml
+name:arm_with_neon
+xmltarget:arm-with-neon.xml
+expedite:r11,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:sp
+32:lr
+32:pc
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+32:cpsr
+64:d0
+64:d1
+64:d2
+64:d3
+64:d4
+64:d5
+64:d6
+64:d7
+64:d8
+64:d9
+64:d10
+64:d11
+64:d12
+64:d13
+64:d14
+64:d15
+64:d16
+64:d17
+64:d18
+64:d19
+64:d20
+64:d21
+64:d22
+64:d23
+64:d24
+64:d25
+64:d26
+64:d27
+64:d28
+64:d29
+64:d30
+64:d31
+32:fpscr
--- /dev/null
+# DO NOT EDIT: generated from arm-with-vfpv2.xml
+name:arm_with_vfpv2
+xmltarget:arm-with-vfpv2.xml
+expedite:r11,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:sp
+32:lr
+32:pc
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+32:cpsr
+64:d0
+64:d1
+64:d2
+64:d3
+64:d4
+64:d5
+64:d6
+64:d7
+64:d8
+64:d9
+64:d10
+64:d11
+64:d12
+64:d13
+64:d14
+64:d15
+32:fpscr
--- /dev/null
+# DO NOT EDIT: generated from arm-with-vfpv3.xml
+name:arm_with_vfpv3
+xmltarget:arm-with-vfpv3.xml
+expedite:r11,sp,pc
+32:r0
+32:r1
+32:r2
+32:r3
+32:r4
+32:r5
+32:r6
+32:r7
+32:r8
+32:r9
+32:r10
+32:r11
+32:r12
+32:sp
+32:lr
+32:pc
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+0:
+32:cpsr
+64:d0
+64:d1
+64:d2
+64:d3
+64:d4
+64:d5
+64:d6
+64:d7
+64:d8
+64:d9
+64:d10
+64:d11
+64:d12
+64:d13
+64:d14
+64:d15
+64:d16
+64:d17
+64:d18
+64:d19
+64:d20
+64:d21
+64:d22
+64:d23
+64:d24
+64:d25
+64:d26
+64:d27
+64:d28
+64:d29
+64:d30
+64:d31
+32:fpscr
return 1;
}
+/* Search FEATURE for a register named NAME, but do not assign a fixed
+ register number to it. */
+
+int
+tdesc_unnumbered_register (const struct tdesc_feature *feature,
+ const char *name)
+{
+ struct tdesc_reg *reg = tdesc_find_register_early (feature, name);
+
+ if (reg == NULL)
+ return 0;
+
+ return 1;
+}
+
/* Search FEATURE for a register whose name is in NAMES and assign
REGNO to it. */
return "";
}
-static struct type *
+struct type *
tdesc_register_type (struct gdbarch *gdbarch, int regno)
{
struct tdesc_arch_reg *arch_reg = tdesc_find_arch_register (gdbarch, regno);
if (regno >= num_regs && regno < num_regs + num_pseudo_regs)
{
struct tdesc_arch_data *data = gdbarch_data (gdbarch, tdesc_data);
- gdb_assert (data->pseudo_register_reggroup_p != NULL);
- return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup);
+ if (data->pseudo_register_reggroup_p != NULL)
+ return data->pseudo_register_reggroup_p (gdbarch, regno, reggroup);
+ /* Otherwise fall through to the default reggroup_p. */
}
ret = tdesc_register_in_reggroup_p (gdbarch, regno, reggroup);
struct tdesc_arch_data *data,
int regno, const char *name);
+/* Search FEATURE for a register named NAME, but do not assign a fixed
+ register number to it. */
+
+int tdesc_unnumbered_register (const struct tdesc_feature *feature,
+ const char *name);
+
/* Search FEATURE for a register named NAME, and return its size in
bits. The register must exist. */
const char *tdesc_register_name (struct gdbarch *gdbarch, int regno);
+/* Return the type of register REGNO, from the target description or
+ from an architecture-provided pseudo_register_type method. */
+
+struct type *tdesc_register_type (struct gdbarch *gdbarch, int regno);
+
/* Check whether REGNUM is a member of REGGROUP using the target
description. Return -1 if the target description does not
specify a group. */
+2009-07-28 Daniel Jacobowitz <dan@codesourcery.com>
+
+ * gdb.base/float.exp: Handle VFP registers.
+
2009-07-14 Michael Snyder <msnyder@vmware.com>
* gdb.reverse/finish-reverse.exp: Do not expect reverse-finish
-re "Software FPU type.*mask:.*flags:.*$gdb_prompt $" {
pass "info float (FPA)"
}
+ -re "fpscr.*s0.*s1.*s31.*$gdb_prompt $" {
+ # Only check for single precision; d0 might be a vector register
+ # if we have NEON.
+ pass "info float (VFP)"
+ }
-re "No floating.point info available for this processor.*" {
pass "info float (without FPU)"
}