/* Target-dependent code for Morpho mt processor, for GDB.
- Copyright (C) 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2007, 2008 Free Software Foundation, Inc.
This file is part of GDB.
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 2 of the License, or
+ 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,
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, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Contributed by Michael Snyder, msnyder@redhat.com. */
MT_OUT_REGNUM, /* 16 bits. */
MT_EXMAC_REGNUM, /* 32 bits (8 used). */
MT_QCHANNEL_REGNUM, /* 32 bits. */
+ MT_ZI2_REGNUM, /* 16 bits. */
+ MT_ZQ2_REGNUM, /* 16 bits. */
+ MT_CHANNEL2_REGNUM, /* 32 bits. */
+ MT_ISCRAMB2_REGNUM, /* 32 bits. */
+ MT_QSCRAMB2_REGNUM, /* 32 bits. */
+ MT_QCHANNEL2_REGNUM, /* 32 bits. */
/* Number of real registers. */
MT_NUM_REGS,
/* Pseudo-registers. */
MT_COPRO_PSEUDOREG_REGNUM = MT_NUM_REGS,
MT_MAC_PSEUDOREG_REGNUM,
+ MT_COPRO_PSEUDOREG_ARRAY,
+
+ MT_COPRO_PSEUDOREG_DIM_1 = 2,
+ MT_COPRO_PSEUDOREG_DIM_2 = 8,
+ /* The number of pseudo-registers for each coprocessor. These
+ include the real coprocessor registers, the pseudo-registe for
+ the coprocessor number, and the pseudo-register for the MAC. */
+ MT_COPRO_PSEUDOREG_REGS = MT_NUM_REGS - MT_NUM_CPU_REGS + 2,
+ /* The register number of the MAC, relative to a given coprocessor. */
+ MT_COPRO_PSEUDOREG_MAC_REGNUM = MT_COPRO_PSEUDOREG_REGS - 1,
/* Two pseudo-regs ('coprocessor' and 'mac'). */
- MT_NUM_PSEUDO_REGS = 2
+ MT_NUM_PSEUDO_REGS = 2 + (MT_COPRO_PSEUDOREG_REGS
+ * MT_COPRO_PSEUDOREG_DIM_1
+ * MT_COPRO_PSEUDOREG_DIM_2)
};
/* Return name of register number specified by REGNUM. */
static const char *
-mt_register_name (int regnum)
+mt_register_name (struct gdbarch *gdbarch, int regnum)
{
static const char *const register_names[] = {
/* CPU regs. */
"cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", "cr15",
"bypa", "bypb", "bypc", "flag", "context", "" /* mac. */ , "z1", "z2",
"Ichannel", "Iscramb", "Qscramb", "out", "" /* ex-mac. */ , "Qchannel",
+ "zi2", "zq2", "Ichannel2", "Iscramb2", "Qscramb2", "Qchannel2",
/* Pseudo-registers. */
"coprocessor", "MAC"
};
+ static const char *array_names[MT_COPRO_PSEUDOREG_REGS
+ * MT_COPRO_PSEUDOREG_DIM_1
+ * MT_COPRO_PSEUDOREG_DIM_2];
+
+ if (regnum < 0)
+ return "";
+ if (regnum < ARRAY_SIZE (register_names))
+ return register_names[regnum];
+ if (array_names[regnum - MT_COPRO_PSEUDOREG_ARRAY])
+ return array_names[regnum - MT_COPRO_PSEUDOREG_ARRAY];
+
+ {
+ char *name;
+ const char *stub;
+ unsigned dim_1;
+ unsigned dim_2;
+ unsigned index;
+
+ regnum -= MT_COPRO_PSEUDOREG_ARRAY;
+ index = regnum % MT_COPRO_PSEUDOREG_REGS;
+ dim_2 = (regnum / MT_COPRO_PSEUDOREG_REGS) % MT_COPRO_PSEUDOREG_DIM_2;
+ dim_1 = ((regnum / MT_COPRO_PSEUDOREG_REGS / MT_COPRO_PSEUDOREG_DIM_2)
+ % MT_COPRO_PSEUDOREG_DIM_1);
+
+ if (index == MT_COPRO_PSEUDOREG_MAC_REGNUM)
+ stub = register_names[MT_MAC_PSEUDOREG_REGNUM];
+ else if (index >= MT_NUM_REGS - MT_CPR0_REGNUM)
+ stub = "";
+ else
+ stub = register_names[index + MT_CPR0_REGNUM];
+ if (!*stub)
+ {
+ array_names[regnum] = stub;
+ return stub;
+ }
+ name = xmalloc (30);
+ sprintf (name, "copro_%d_%d_%s", dim_1, dim_2, stub);
+ array_names[regnum] = name;
+ return name;
+ }
+}
- gdb_assert (regnum >= 0 && regnum < ARRAY_SIZE (register_names));
- return register_names[regnum];
+/* Return the type of a coprocessor register. */
+
+static struct type *
+mt_copro_register_type (struct gdbarch *arch, int regnum)
+{
+ switch (regnum)
+ {
+ case MT_INT_ENABLE_REGNUM:
+ case MT_ICHANNEL_REGNUM:
+ case MT_QCHANNEL_REGNUM:
+ case MT_ISCRAMB_REGNUM:
+ case MT_QSCRAMB_REGNUM:
+ return builtin_type_int32;
+ case MT_BYPA_REGNUM:
+ case MT_BYPB_REGNUM:
+ case MT_BYPC_REGNUM:
+ case MT_Z1_REGNUM:
+ case MT_Z2_REGNUM:
+ case MT_OUT_REGNUM:
+ case MT_ZI2_REGNUM:
+ case MT_ZQ2_REGNUM:
+ return builtin_type_int16;
+ case MT_EXMAC_REGNUM:
+ case MT_MAC_REGNUM:
+ return builtin_type_uint32;
+ case MT_CONTEXT_REGNUM:
+ return builtin_type_long_long;
+ case MT_FLAG_REGNUM:
+ return builtin_type_unsigned_char;
+ default:
+ if (regnum >= MT_CPR0_REGNUM && regnum <= MT_CPR15_REGNUM)
+ return builtin_type_int16;
+ else if (regnum == MT_CPR0_REGNUM + MT_COPRO_PSEUDOREG_MAC_REGNUM)
+ {
+ if (gdbarch_bfd_arch_info (arch)->mach == bfd_mach_mrisc2
+ || gdbarch_bfd_arch_info (arch)->mach == bfd_mach_ms2)
+ return builtin_type_uint64;
+ else
+ return builtin_type_uint32;
+ }
+ else
+ return builtin_type_uint32;
+ }
}
/* Given ARCH and a register number specified by REGNUM, return the
case MT_SP_REGNUM:
case MT_FP_REGNUM:
return void_ptr;
- case MT_INT_ENABLE_REGNUM:
- case MT_ICHANNEL_REGNUM:
- case MT_QCHANNEL_REGNUM:
- case MT_ISCRAMB_REGNUM:
- case MT_QSCRAMB_REGNUM:
- return builtin_type_int32;
- case MT_EXMAC_REGNUM:
- case MT_MAC_REGNUM:
- return builtin_type_uint32;
- case MT_BYPA_REGNUM:
- case MT_BYPB_REGNUM:
- case MT_BYPC_REGNUM:
- case MT_Z1_REGNUM:
- case MT_Z2_REGNUM:
- case MT_OUT_REGNUM:
- return builtin_type_int16;
- case MT_CONTEXT_REGNUM:
- return builtin_type_long_long;
case MT_COPRO_REGNUM:
case MT_COPRO_PSEUDOREG_REGNUM:
return copro_type;
case MT_MAC_PSEUDOREG_REGNUM:
- if (gdbarch_bfd_arch_info (arch)->mach == bfd_mach_mrisc2
- || gdbarch_bfd_arch_info (arch)->mach == bfd_mach_ms2)
- return builtin_type_uint64;
- else
- return builtin_type_uint32;
- case MT_FLAG_REGNUM:
- return builtin_type_unsigned_char;
+ return mt_copro_register_type (arch,
+ MT_CPR0_REGNUM
+ + MT_COPRO_PSEUDOREG_MAC_REGNUM);
default:
if (regnum >= MT_R0_REGNUM && regnum <= MT_R15_REGNUM)
return builtin_type_int32;
- else if (regnum >= MT_CPR0_REGNUM && regnum <= MT_CPR15_REGNUM)
- return builtin_type_int16;
+ else if (regnum < MT_COPRO_PSEUDOREG_ARRAY)
+ return mt_copro_register_type (arch, regnum);
+ else
+ {
+ regnum -= MT_COPRO_PSEUDOREG_ARRAY;
+ regnum %= MT_COPRO_PSEUDOREG_REGS;
+ regnum += MT_CPR0_REGNUM;
+ return mt_copro_register_type (arch, regnum);
+ }
}
}
internal_error (__FILE__, __LINE__,
if (group == all_reggroup)
return (regnum >= 0
&& regnum < MT_NUM_REGS + MT_NUM_PSEUDO_REGS
- && mt_register_name (regnum)[0] != '\0');
+ && mt_register_name (gdbarch, regnum)[0] != '\0');
if (group == general_reggroup)
return (regnum >= MT_R0_REGNUM && regnum <= MT_R15_REGNUM);
call. */
static CORE_ADDR
-mt_skip_prologue (CORE_ADDR pc)
+mt_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc)
{
CORE_ADDR func_addr = 0, func_end = 0;
char *func_name;
The BP for ms2 is defined as 0x69000000 (illegal) */
static const gdb_byte *
-mt_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size)
+mt_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
+ int *bp_size)
{
static gdb_byte ms1_breakpoint[] = { 0x68, 0, 0, 0 };
static gdb_byte ms2_breakpoint[] = { 0x69, 0, 0, 0 };
*bp_size = 4;
- if (gdbarch_bfd_arch_info (current_gdbarch)->mach == bfd_mach_ms2)
+ if (gdbarch_bfd_arch_info (gdbarch)->mach == bfd_mach_ms2)
return ms2_breakpoint;
return ms1_breakpoint;
}
+/* Select the correct coprocessor register bank. Return the pseudo
+ regnum we really want to read. */
+
+static int
+mt_select_coprocessor (struct gdbarch *gdbarch,
+ struct regcache *regcache, int regno)
+{
+ unsigned index, base;
+ gdb_byte copro[4];
+
+ /* Get the copro pseudo regnum. */
+ regcache_raw_read (regcache, MT_COPRO_REGNUM, copro);
+ base = (extract_signed_integer (&copro[0], 2) * MT_COPRO_PSEUDOREG_DIM_2
+ + extract_signed_integer (&copro[2], 2));
+
+ regno -= MT_COPRO_PSEUDOREG_ARRAY;
+ index = regno % MT_COPRO_PSEUDOREG_REGS;
+ regno /= MT_COPRO_PSEUDOREG_REGS;
+ if (base != regno)
+ {
+ /* Select the correct coprocessor register bank. Invalidate the
+ coprocessor register cache. */
+ unsigned ix;
+
+ store_signed_integer (&copro[0], 2, regno / MT_COPRO_PSEUDOREG_DIM_2);
+ store_signed_integer (&copro[2], 2, regno % MT_COPRO_PSEUDOREG_DIM_2);
+ regcache_raw_write (regcache, MT_COPRO_REGNUM, copro);
+
+ /* We must flush the cache, as it is now invalid. */
+ for (ix = MT_NUM_CPU_REGS; ix != MT_NUM_REGS; ix++)
+ regcache_invalidate (regcache, ix);
+ }
+
+ return index;
+}
+
/* Fetch the pseudo registers:
- There are two pseudo-registers:
+ There are two regular pseudo-registers:
1) The 'coprocessor' pseudo-register (which mirrors the
"real" coprocessor register sent by the target), and
2) The 'MAC' pseudo-register (which represents the union
of the original 32 bit target MAC register and the new
- 8-bit extended-MAC register). */
+ 8-bit extended-MAC register).
+
+ Additionally there is an array of coprocessor registers which track
+ the coprocessor registers for each coprocessor. */
static void
mt_pseudo_register_read (struct gdbarch *gdbarch,
regcache_raw_read (regcache, MT_MAC_REGNUM, buf);
break;
default:
- internal_error (__FILE__, __LINE__,
- _("mt_pseudo_register_read: bad reg # (%d)"), regno);
+ {
+ unsigned index = mt_select_coprocessor (gdbarch, regcache, regno);
+
+ if (index == MT_COPRO_PSEUDOREG_MAC_REGNUM)
+ mt_pseudo_register_read (gdbarch, regcache,
+ MT_MAC_PSEUDOREG_REGNUM, buf);
+ else if (index < MT_NUM_REGS - MT_CPR0_REGNUM)
+ regcache_raw_read (regcache, index + MT_CPR0_REGNUM, buf);
+ }
break;
}
}
case MT_COPRO_PSEUDOREG_REGNUM:
regcache_raw_write (regcache, MT_COPRO_REGNUM, buf);
for (i = MT_NUM_CPU_REGS; i < MT_NUM_REGS; i++)
- set_register_cached (i, 0);
+ regcache_invalidate (regcache, i);
break;
case MT_MAC_REGNUM:
case MT_MAC_PSEUDOREG_REGNUM:
regcache_raw_write (regcache, MT_MAC_REGNUM, buf);
break;
default:
- internal_error (__FILE__, __LINE__,
- _("mt_pseudo_register_write: bad reg # (%d)"), regno);
+ {
+ unsigned index = mt_select_coprocessor (gdbarch, regcache, regno);
+
+ if (index == MT_COPRO_PSEUDOREG_MAC_REGNUM)
+ mt_pseudo_register_write (gdbarch, regcache,
+ MT_MAC_PSEUDOREG_REGNUM, buf);
+ else if (index < MT_NUM_REGS - MT_CPR0_REGNUM)
+ regcache_raw_write (regcache, index + MT_CPR0_REGNUM, buf);
+ }
break;
}
}
static void
mt_registers_info (struct gdbarch *gdbarch,
- struct ui_file *file,
- struct frame_info *frame, int regnum, int all)
+ struct ui_file *file,
+ struct frame_info *frame, int regnum, int all)
{
if (regnum == -1)
{
frame_register_read (frame, regnum, buff);
- fputs_filtered (REGISTER_NAME (regnum), file);
- print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
+ fputs_filtered (gdbarch_register_name
+ (gdbarch, regnum), file);
+ print_spaces_filtered (15 - strlen (gdbarch_register_name
+ (gdbarch, regnum)),
+ file);
fputs_filtered ("0x", file);
for (i = 0; i < regsize; i++)
frame_register_read (frame, MT_COPRO_REGNUM, buf);
/* And print. */
regnum = MT_COPRO_PSEUDOREG_REGNUM;
- fputs_filtered (REGISTER_NAME (regnum), file);
- print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
+ fputs_filtered (gdbarch_register_name (gdbarch, regnum),
+ file);
+ print_spaces_filtered (15 - strlen (gdbarch_register_name
+ (gdbarch, regnum)),
+ file);
val_print (register_type (gdbarch, regnum), buf,
0, 0, file, 0, 1, 0, Val_no_prettyprint);
fputs_filtered ("\n", file);
/* And print. */
regnum = MT_MAC_PSEUDOREG_REGNUM;
- fputs_filtered (REGISTER_NAME (regnum), file);
- print_spaces_filtered (15 - strlen (REGISTER_NAME (regnum)), file);
+ fputs_filtered (gdbarch_register_name (gdbarch, regnum),
+ file);
+ print_spaces_filtered (15 - strlen (gdbarch_register_name
+ (gdbarch, regnum)),
+ file);
fputs_filtered ("0x", file);
print_longest (file, 'x', 0, newmac);
fputs_filtered ("\t", file);
/* Grab the frame-relative values of SP and FP, needed below.
The frame_saved_register function will find them on the
stack or in the registers as appropriate. */
- frame_unwind_unsigned_register (next_frame, MT_SP_REGNUM, &sp);
- frame_unwind_unsigned_register (next_frame, MT_FP_REGNUM, &fp);
+ sp = frame_unwind_register_unsigned (next_frame, MT_SP_REGNUM);
+ fp = frame_unwind_register_unsigned (next_frame, MT_FP_REGNUM);
- start_addr = frame_func_unwind (next_frame);
+ start_addr = frame_func_unwind (next_frame, NORMAL_FRAME);
/* Return early if GDB couldn't find the function. */
if (start_addr == 0)
{
ULONGEST pc;
- frame_unwind_unsigned_register (next_frame, MT_PC_REGNUM, &pc);
+ pc = frame_unwind_register_unsigned (next_frame, MT_PC_REGNUM);
return pc;
}
{
ULONGEST sp;
- frame_unwind_unsigned_register (next_frame, MT_SP_REGNUM, &sp);
+ sp = frame_unwind_register_unsigned (next_frame, MT_SP_REGNUM);
return sp;
}
mt_frame_unwind_cache (next_frame, this_prologue_cache);
if (!(info == NULL || info->prev_sp == 0))
- {
- (*this_id) = frame_id_build (info->prev_sp,
- frame_func_unwind (next_frame));
- }
+ (*this_id) = frame_id_build (info->prev_sp,
+ frame_func_unwind (next_frame, NORMAL_FRAME));
+
return;
}
provided. */
gdbarch = gdbarch_alloc (&info, NULL);
- switch (info.byte_order)
- {
- case BFD_ENDIAN_BIG:
- set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_big);
- set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_big);
- set_gdbarch_long_double_format (gdbarch, &floatformat_ieee_double_big);
- break;
- case BFD_ENDIAN_LITTLE:
- set_gdbarch_float_format (gdbarch, &floatformat_ieee_single_little);
- set_gdbarch_double_format (gdbarch, &floatformat_ieee_double_little);
- set_gdbarch_long_double_format (gdbarch,
- &floatformat_ieee_double_little);
- break;
- default:
- internal_error (__FILE__, __LINE__,
- _("mt_gdbarch_init: bad byte order for float format"));
- }
+ set_gdbarch_float_format (gdbarch, floatformats_ieee_single);
+ set_gdbarch_double_format (gdbarch, floatformats_ieee_double);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
set_gdbarch_register_name (gdbarch, mt_register_name);
set_gdbarch_num_regs (gdbarch, MT_NUM_REGS);