ColdFire/fido support

Vladimir Prus
2007-05-05T09:37:17Z

[-- Attachment #1: Type: text/plain, Size: 424 bytes --]

This patch adds initial support for ColdFire and fido versions of m68k.
The primary difference is different format of floating point, and different
return convention for floating point values on coldfire. This patch also
adds support for XML description, which allows remote stub to
advertise presense of floating point registers in a clean way.

No change in behaviour for classic m68k-tdep.c is expected. OK?

- Volodya

[-- Attachment #2: 2.ChangeLog --]
[-- Type: text/plain, Size: 1064 bytes --]

* m68k-tdep.h (struct gdbarch_tdep): New fields
float_return, fpreg_type, coldire, fido and
fpregs_present.
* m68k-tdep.c (m68k_register_type): Use
fpregs_present and fpreg_type.
(m68k_register_names): New.
(m68k_register_name): Use the above.
(m68k_convert_register_p): Consult fpregs_present.
(m68k_register_to_value, m68k_value_to_register):
Use register_type to obtain the type of floating
point registers.
(m68k_svr4_extract_return_value): Check tdep->float_return.
Use register_type to get the type of floating
point regiters.
(m68k_svr4_store_return_value): Likewise.
(m68k_dwarf_reg_to_regnum): Check tdep->fpregs_present.
(m68k_analyze_register_saves): Likewise.
(m68k_gdbarch_init): Extract infromation
from XML description, if present. Guess coldfire by
looking at the file, if present. Conditionalize
setting of long double format. Set decr_pc_after_break
to 2 on coldfire and fido. Enable XML-driven
register description.
* m68kbsd-tdep.c (m68kbsd_fpreg_offset): Use
size of tdep->fpreg_type, as opposed to hardcoded value.

[-- Attachment #3: 2.diff --]
[-- Type: text/x-diff, Size: 13455 bytes --]

--- gdb/m68k-tdep.c (/patches/gdb/coldfire_1) (revision 4079)
+++ gdb/m68k-tdep.c (/patches/gdb/coldfire_2) (revision 4079)
@@ -36,6 +36,7 @@
#include "arch-utils.h"
#include "osabi.h"
#include "dis-asm.h"
+#include "target-descriptions.h"

#include "m68k-tdep.h"
\f
@@ -80,15 +81,25 @@ m68k_local_breakpoint_from_pc (CORE_ADDR
static struct type *
m68k_register_type (struct gdbarch *gdbarch, int regnum)
{
- if (regnum >= FP0_REGNUM && regnum <= FP0_REGNUM + 7)
- return builtin_type_m68881_ext;
+ if (gdbarch_tdep (gdbarch)->fpregs_present)
+ {
+ if (regnum >= FP0_REGNUM && regnum <= FP0_REGNUM + 7)
+ return *gdbarch_tdep (gdbarch)->fpreg_type;

- if (regnum == M68K_FPI_REGNUM || regnum == PC_REGNUM)
- return builtin_type_void_func_ptr;
+ if (regnum == M68K_FPI_REGNUM)
+ return builtin_type_void_func_ptr;
+
+ if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM)
+ return builtin_type_int32;
+ }
+ else
+ {
+ if (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FPI_REGNUM)
+ return builtin_type_int0;
+ }

- if (regnum == M68K_FPC_REGNUM || regnum == M68K_FPS_REGNUM
- || regnum == PS_REGNUM)
- return builtin_type_int32;
+ if (regnum == PC_REGNUM)
+ return builtin_type_void_func_ptr;

if (regnum >= M68K_A0_REGNUM && regnum <= M68K_A0_REGNUM + 7)
return builtin_type_void_data_ptr;
@@ -96,25 +107,25 @@ m68k_register_type (struct gdbarch *gdba
return builtin_type_int32;
}

-/* Function: m68k_register_name
- Returns the name of the standard m68k register regnum. */
-
-static const char *
-m68k_register_name (int regnum)
-{
- static char *register_names[] = {
+static const char *m68k_register_names[] = {
"d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
"a0", "a1", "a2", "a3", "a4", "a5", "fp", "sp",
"ps", "pc",
"fp0", "fp1", "fp2", "fp3", "fp4", "fp5", "fp6", "fp7",
- "fpcontrol", "fpstatus", "fpiaddr", "fpcode", "fpflags"
+ "fpcontrol", "fpstatus", "fpiaddr"
};

- if (regnum < 0 || regnum >= ARRAY_SIZE (register_names))
+/* Function: m68k_register_name
+ Returns the name of the standard m68k register regnum. */
+
+static const char *
+m68k_register_name (int regnum)
+{
+ if (regnum < 0 || regnum >= ARRAY_SIZE (m68k_register_names))
internal_error (__FILE__, __LINE__,
_("m68k_register_name: illegal register number %d"), regnum);
else
- return register_names[regnum];
+ return m68k_register_names[regnum];
}
\f
/* Return nonzero if a value of type TYPE stored in register REGNUM
@@ -123,6 +134,8 @@ m68k_register_name (int regnum)
static int
m68k_convert_register_p (int regnum, struct type *type)
{
+ if (!gdbarch_tdep (current_gdbarch)->fpregs_present)
+ return 0;
return (regnum >= M68K_FP0_REGNUM && regnum <= M68K_FP0_REGNUM + 7);
}

@@ -134,6 +147,7 @@ m68k_register_to_value (struct frame_inf
struct type *type, gdb_byte *to)
{
gdb_byte from[M68K_MAX_REGISTER_SIZE];
+ struct type *fpreg_type = register_type (current_gdbarch, M68K_FP0_REGNUM);

/* We only support floating-point values. */
if (TYPE_CODE (type) != TYPE_CODE_FLT)
@@ -146,7 +160,7 @@ m68k_register_to_value (struct frame_inf
/* Convert to TYPE. This should be a no-op if TYPE is equivalent to
the extended floating-point format used by the FPU. */
get_frame_register (frame, regnum, from);
- convert_typed_floating (from, builtin_type_m68881_ext, to, type);
+ convert_typed_floating (from, fpreg_type, to, type);
}

/* Write the contents FROM of a value of type TYPE into register
@@ -157,6 +171,7 @@ m68k_value_to_register (struct frame_inf
struct type *type, const gdb_byte *from)
{
gdb_byte to[M68K_MAX_REGISTER_SIZE];
+ struct type *fpreg_type = register_type (current_gdbarch, M68K_FP0_REGNUM);

/* We only support floating-point values. */
if (TYPE_CODE (type) != TYPE_CODE_FLT)
@@ -168,7 +183,7 @@ m68k_value_to_register (struct frame_inf

/* Convert from TYPE. This should be a no-op if TYPE is equivalent
to the extended floating-point format used by the FPU. */
- convert_typed_floating (from, type, to, builtin_type_m68881_ext);
+ convert_typed_floating (from, type, to, fpreg_type);
put_frame_register (frame, regnum, to);
}

@@ -234,11 +249,14 @@ m68k_svr4_extract_return_value (struct t
{
int len = TYPE_LENGTH (type);
gdb_byte buf[M68K_MAX_REGISTER_SIZE];
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);

- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
{
+ struct type *fpreg_type = register_type
+ (current_gdbarch, M68K_FP0_REGNUM);
regcache_raw_read (regcache, M68K_FP0_REGNUM, buf);
- convert_typed_floating (buf, builtin_type_m68881_ext, valbuf, type);
+ convert_typed_floating (buf, fpreg_type, valbuf, type);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
regcache_raw_read (regcache, M68K_A0_REGNUM, valbuf);
@@ -272,11 +290,14 @@ m68k_svr4_store_return_value (struct typ
const gdb_byte *valbuf)
{
int len = TYPE_LENGTH (type);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);

- if (TYPE_CODE (type) == TYPE_CODE_FLT)
+ if (tdep->float_return && TYPE_CODE (type) == TYPE_CODE_FLT)
{
+ struct type *fpreg_type = register_type
+ (current_gdbarch, M68K_FP0_REGNUM);
gdb_byte buf[M68K_MAX_REGISTER_SIZE];
- convert_typed_floating (valbuf, type, buf, builtin_type_m68881_ext);
+ convert_typed_floating (valbuf, type, buf, fpreg_type);
regcache_raw_write (regcache, M68K_FP0_REGNUM, buf);
}
else if (TYPE_CODE (type) == TYPE_CODE_PTR && len == 4)
@@ -477,7 +498,7 @@ m68k_dwarf_reg_to_regnum (int num)
else if (num < 16)
/* a0..7 */
return (num - 8) + M68K_A0_REGNUM;
- else if (num < 24)
+ else if (num < 24 && gdbarch_tdep (current_gdbarch)->fpregs_present)
/* fp0..7 */
return (num - 16) + M68K_FP0_REGNUM;
else if (num == 25)
@@ -645,7 +666,8 @@ m68k_analyze_register_saves (CORE_ADDR p
while (pc < current_pc)
{
op = read_memory_unsigned_integer (pc, 2);
- if (op == P_FMOVEMX_SP)
+ if (op == P_FMOVEMX_SP
+ && gdbarch_tdep (current_gdbarch)->fpregs_present)
{
/* fmovem.x REGS,-(%sp) */
op = read_memory_unsigned_integer (pc + 2, 2);
@@ -1136,17 +1158,118 @@ m68k_gdbarch_init (struct gdbarch_info i
{
struct gdbarch_tdep *tdep = NULL;
struct gdbarch *gdbarch;
+ struct gdbarch_list *best_arch;
+ struct tdesc_arch_data *tdesc_data = NULL;
+ int i;
+ int coldfire = 0;
+ int fido = 0;
+ int has_fp = 1;
+ const struct floatformat **long_double_format = floatformats_m68881_ext;
+
+ /* Check any target description for validity. */
+ if (tdesc_has_registers (info.target_desc))
+ {
+ const struct tdesc_feature *feature;
+ int valid_p;
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.m68k.core");
+ if (feature != NULL)
+ /* Do nothing. */
+ ;
+
+ if (feature == NULL)
+ {
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.coldfire.core");
+ if (feature != NULL)
+ coldfire = 1;
+ }
+
+ if (feature == NULL)
+ {
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.fido.core");
+ if (feature != NULL)
+ fido = 1;
+ }
+
+ if (feature == NULL)
+ return NULL;
+
+ tdesc_data = tdesc_data_alloc ();

- /* find a candidate among the list of pre-declared architectures. */
- arches = gdbarch_list_lookup_by_info (arches, &info);
- if (arches != NULL)
- return (arches->gdbarch);
+ valid_p = 1;
+ for (i = 0; i <= M68K_PC_REGNUM; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+ m68k_register_names[i]);
+
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.coldfire.fp");
+ if (feature != NULL)
+ {
+ valid_p = 1;
+ for (i = M68K_FP0_REGNUM; i <= M68K_FPI_REGNUM; i++)
+ valid_p &= tdesc_numbered_register (feature, tdesc_data, i,
+ m68k_register_names[i]);
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+ }
+ else
+ has_fp = 0;
+ }
+
+ /* The mechanism for returning floating values from function
+ and the type of long double depend on whether we're
+ on ColdFire or standard m68k. */
+
+ if (info.bfd_arch_info)
+ {
+ const bfd_arch_info_type *coldfire_arch =
+ bfd_lookup_arch (bfd_arch_m68k, bfd_mach_mcf_isa_a_nodiv);
+
+ if (coldfire_arch
+ && (*info.bfd_arch_info->compatible)
+ (info.bfd_arch_info, coldfire_arch))
+ coldfire = 1;
+ }
+
+ /* If there is already a candidate, use it. */
+ for (best_arch = gdbarch_list_lookup_by_info (arches, &info);
+ best_arch != NULL;
+ best_arch = gdbarch_list_lookup_by_info (best_arch->next, &info))
+ {
+ if (coldfire != gdbarch_tdep (best_arch->gdbarch)->coldfire)
+ continue;
+
+ if (fido != gdbarch_tdep (best_arch->gdbarch)->fido)
+ continue;
+
+ if (has_fp != gdbarch_tdep (best_arch->gdbarch)->fpregs_present)
+ continue;
+
+ break;
+ }

tdep = xmalloc (sizeof (struct gdbarch_tdep));
gdbarch = gdbarch_alloc (&info, tdep);
-
- set_gdbarch_long_double_format (gdbarch, floatformats_m68881_ext);
- set_gdbarch_long_double_bit (gdbarch, 96);
+ tdep->fpregs_present = has_fp;
+ tdep->coldfire = coldfire;
+ tdep->fido = fido;
+
+ if (coldfire || fido)
+ long_double_format = floatformats_ieee_double;
+ set_gdbarch_long_double_format (gdbarch, long_double_format);
+ set_gdbarch_long_double_bit (gdbarch, long_double_format[0]->totalsize);

set_gdbarch_skip_prologue (gdbarch, m68k_skip_prologue);
set_gdbarch_breakpoint_from_pc (gdbarch, m68k_local_breakpoint_from_pc);
@@ -1156,6 +1279,8 @@ m68k_gdbarch_init (struct gdbarch_info i
set_gdbarch_frame_align (gdbarch, m68k_frame_align);

set_gdbarch_believe_pcc_promotion (gdbarch, 1);
+ if (coldfire || fido)
+ set_gdbarch_decr_pc_after_break (gdbarch, 2);

set_gdbarch_frame_args_skip (gdbarch, 8);
set_gdbarch_dwarf_reg_to_regnum (gdbarch, m68k_dwarf_reg_to_regnum);
@@ -1172,9 +1297,35 @@ m68k_gdbarch_init (struct gdbarch_info i
set_gdbarch_register_to_value (gdbarch, m68k_register_to_value);
set_gdbarch_value_to_register (gdbarch, m68k_value_to_register);

+ if (has_fp)
+ set_gdbarch_fp0_regnum (gdbarch, M68K_FP0_REGNUM);
+
+ if (coldfire)
+ tdep->fpreg_type = &builtin_type_double;
+ else
+ tdep->fpreg_type = &builtin_type_m68881_ext;
+
+ /* Try to figure out if the arch uses floating registers to return
+ floating point values from functions. */
+ if (has_fp)
+ {
+ /* On ColdFire, floating point values are returned in D0. */
+ if (coldfire)
+ tdep->float_return = 0;
+ else
+ tdep->float_return = 1;
+ }
+ else
+ {
+ /* No floating registers, so can't use them for returning values. */
+ tdep->float_return = 0;
+ }
+
+ /* Function call & return */
set_gdbarch_push_dummy_call (gdbarch, m68k_push_dummy_call);
set_gdbarch_return_value (gdbarch, m68k_return_value);

+
/* Disassembler. */
set_gdbarch_print_insn (gdbarch, print_insn_m68k);

@@ -1207,6 +1358,9 @@ m68k_gdbarch_init (struct gdbarch_info i

frame_unwind_append_sniffer (gdbarch, m68k_frame_sniffer);

+ if (tdesc_data)
+ tdesc_use_registers (gdbarch, tdesc_data);
+
return gdbarch;
}

--- gdb/m68k-tdep.h (/patches/gdb/coldfire_1) (revision 4079)
+++ gdb/m68k-tdep.h (/patches/gdb/coldfire_2) (revision 4079)
@@ -76,6 +76,27 @@ struct gdbarch_tdep

/* Convention for returning structures. */
enum struct_return struct_return;
+
+ /* Convention for returning floats. zero in int regs, non-zero in float. */
+ int float_return;
+
+ /* Type of an fpreg. NULL if there are no fpregs. This is a
+ pointer to the pointer to type struct, because when architecture
+ init function is running, the types for the old architecture are swapped
+ out, and the types for the new architecture are not yet swapped in,
+ so all types that don't have specific sizes (like builting_type_double)
+ are NULL. */
+ struct type **fpreg_type;
+
+ /* Is this ColdFire architecture, as opposed to generic m68k? */
+ int coldfire;
+
+ /* Is this fido architecture, as opposed to generic m68k? */
+ int fido;
+
+ /* Flag set if the floating point registers are present, or assumed
+ to be present. */
+ int fpregs_present;
};

/* Initialize a SVR4 architecture variant. */
--- gdb/m68kbsd-tdep.c (/patches/gdb/coldfire_1) (revision 4079)
+++ gdb/m68kbsd-tdep.c (/patches/gdb/coldfire_2) (revision 4079)
@@ -45,10 +45,12 @@
int
m68kbsd_fpreg_offset (int regnum)
{
+ int fp_len = TYPE_LENGTH (*gdbarch_tdep (current_gdbarch)->fpreg_type);
+
if (regnum >= M68K_FPC_REGNUM)
- return 8 * 12 + (regnum - M68K_FPC_REGNUM) * 4;
+ return 8 * fp_len + (regnum - M68K_FPC_REGNUM) * 4;

- return (regnum - M68K_FP0_REGNUM) * 12;
+ return (regnum - M68K_FP0_REGNUM) * fp_len;
}

/* Supply register REGNUM from the buffer specified by FPREGS and LEN

Property changes on:
___________________________________________________________________
Name: svk:merge
+d48a11ec-ee1c-0410-b3f5-c20844f99675:/patches/gdb/coldfire_submission:4065