aboutsummaryrefslogtreecommitdiff
path: root/gdb/mt-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/mt-tdep.c')
-rw-r--r--gdb/mt-tdep.c197
1 files changed, 161 insertions, 36 deletions
diff --git a/gdb/mt-tdep.c b/gdb/mt-tdep.c
index 243fdd3..99725e7 100644
--- a/gdb/mt-tdep.c
+++ b/gdb/mt-tdep.c
@@ -116,9 +116,16 @@ enum mt_gdb_regnums
/* 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,
+ MT_COPRO_PSEUDOREG_REGS = 32,
/* 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. */
@@ -140,9 +147,89 @@ mt_register_name (int regnum)
/* 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_REGS - 1)
+ stub = register_names[MT_MAC_PSEUDOREG_REGNUM];
+ else if (index > MT_QCHANNEL_REGNUM - 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:
+ 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_REGS - 1)
+ {
+ 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
@@ -176,40 +263,25 @@ mt_register_type (struct gdbarch *arch, int regnum)
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_REGS - 1);
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__,
@@ -379,14 +451,53 @@ mt_breakpoint_from_pc (CORE_ADDR *bp_addr, int *bp_size)
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++)
+ set_register_cached (ix, 0);
+ }
+
+ 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,
@@ -416,8 +527,15 @@ 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_REGS - 1)
+ mt_pseudo_register_read (gdbarch, regcache,
+ MT_COPRO_PSEUDOREG_REGNUM, buf);
+ else if (index < MT_NUM_REGS - MT_CPR0_REGNUM)
+ regcache_raw_read (regcache, index + MT_CPR0_REGNUM, buf);
+ }
break;
}
}
@@ -463,8 +581,15 @@ mt_pseudo_register_write (struct gdbarch *gdbarch,
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_REGS - 1)
+ mt_pseudo_register_write (gdbarch, regcache,
+ MT_COPRO_PSEUDOREG_REGNUM, buf);
+ else if (index < MT_NUM_REGS - MT_CPR0_REGNUM)
+ regcache_raw_write (regcache, index + MT_CPR0_REGNUM, buf);
+ }
break;
}
}