/* Target-dependent code for Morpho mt processor, for GDB.
- Copyright 2005 Free Software Foundation, Inc.
+ Copyright (C) 2005, 2007 Free Software Foundation, Inc.
This file is part of GDB.
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., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
/* 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. */
"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__,
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;
}
}
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
+ (current_gdbarch, regnum), file);
+ print_spaces_filtered (15 - strlen (gdbarch_register_name
+ (current_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 (current_gdbarch, regnum),
+ file);
+ print_spaces_filtered (15 - strlen (gdbarch_register_name
+ (current_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 (current_gdbarch, regnum),
+ file);
+ print_spaces_filtered (15 - strlen (gdbarch_register_name
+ (current_gdbarch, regnum)),
+ file);
fputs_filtered ("0x", file);
print_longest (file, 'x', 0, newmac);
fputs_filtered ("\t", file);
frame_unwind_unsigned_register (next_frame, MT_SP_REGNUM, &sp);
frame_unwind_unsigned_register (next_frame, MT_FP_REGNUM, &fp);
- 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)
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);