This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 14/24] Implement core MSA stuff
- From: Bhushan Attarde <bhushan dot attarde at imgtec dot com>
- To: <gdb-patches at sourceware dot org>
- Cc: <Maciej dot Rozycki at imgtec dot com>, <Matthew dot Fortune at imgtec dot com>, <James dot Hogan at imgtec dot com>, <Andrew dot Bennett at imgtec dot com>, <Jaydeep dot Patil at imgtec dot com>, Bhushan Attarde <bhushan dot attarde at imgtec dot com>
- Date: Mon, 27 Jun 2016 20:19:41 +0530
- Subject: [PATCH 14/24] Implement core MSA stuff
- Authentication-results: sourceware.org; auth=none
- References: <1467038991-6600-1-git-send-email-bhushan dot attarde at imgtec dot com>
gdb/ChangeLog:
* mips-tdep.c (mips_vector_register_p, mips_msa_128b_type): New
functions.
(mips_register_name): Add mips_msa_names containing msa register
names and return msa register name when appropriate.
(mips_get_fp_single_location): Add new variable "offs" and set
"loc->offset" correctly.
(mips_pseudo_register_read): Consider msa registers.
(mips_pseudo_register_write): Likewise.
(mips_print_register, print_gp_register_row): Likewise.
(mips_register_type): Return mips_msa_128b_type for vector
registers.
(mips_gdbarch_init): Initialise w0, msa_ir and msa_csr to -1
and then set them appropriately.
(msa_128b_type): Initialise to NULL.
* mips-tdep.h (mips_regnum): New w0, msa_ir, msa_csr fields.
(gdbarch_tdep): Add msa_128b_type field.
---
gdb/mips-tdep.c | 198 ++++++++++++++++++++++++++++++++++++++++++++++++++++----
gdb/mips-tdep.h | 4 ++
2 files changed, 190 insertions(+), 12 deletions(-)
diff --git a/gdb/mips-tdep.c b/gdb/mips-tdep.c
index 13c1532..f98c288 100644
--- a/gdb/mips-tdep.c
+++ b/gdb/mips-tdep.c
@@ -221,6 +221,16 @@ mips_float_register_p (struct gdbarch *gdbarch, int regnum)
&& rawnum < mips_regnum (gdbarch)->fp0 + 32);
}
+static int
+mips_vector_register_p (struct gdbarch *gdbarch, int regnum)
+{
+ int rawnum = regnum % gdbarch_num_regs (gdbarch);
+
+ return (mips_regnum (gdbarch)->w0 >= 0
+ && rawnum >= mips_regnum (gdbarch)->w0
+ && rawnum < mips_regnum (gdbarch)->w0 + 32);
+}
+
#define MIPS_EABI(gdbarch) (gdbarch_tdep (gdbarch)->mips_abi \
== MIPS_ABI_EABI32 \
|| gdbarch_tdep (gdbarch)->mips_abi == MIPS_ABI_EABI64)
@@ -684,6 +694,8 @@ static const char *
mips_register_name (struct gdbarch *gdbarch, int regno)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ const struct mips_regnum *regnum = mips_regnum (gdbarch);
+
/* GPR names for all ABIs other than n32/n64. */
static char *mips_gpr_names[] = {
"zero", "at", "v0", "v1", "a0", "a1", "a2", "a3",
@@ -700,6 +712,14 @@ mips_register_name (struct gdbarch *gdbarch, int regno)
"t8", "t9", "k0", "k1", "gp", "sp", "s8", "ra"
};
+ /* MSA vector register names. */
+ static const char *const mips_msa_names[] = {
+ "w0", "w1", "w2", "w3", "w4", "w5", "w6", "w7",
+ "w8", "w9", "w10", "w11", "w12", "w13", "w14", "w15",
+ "w16", "w17", "w18", "w19", "w20", "w21", "w22", "w23",
+ "w24", "w25", "w26", "w27", "w28", "w29", "w30", "w31",
+ };
+
enum mips_abi abi = mips_abi (gdbarch);
/* Map [gdbarch_num_regs .. 2*gdbarch_num_regs) onto the raw registers,
@@ -727,6 +747,8 @@ mips_register_name (struct gdbarch *gdbarch, int regno)
else
return mips_gpr_names[rawnum];
}
+ else if (regnum->w0 >= 0 && rawnum >= regnum->w0 && rawnum < regnum->w0 + 32)
+ return mips_msa_names[rawnum - regnum->w0];
else if (tdesc_has_registers (gdbarch_target_desc (gdbarch)))
return tdesc_register_name (gdbarch, rawnum);
else if (32 <= rawnum && rawnum < gdbarch_num_regs (gdbarch))
@@ -831,7 +853,7 @@ mips_get_fp_single_location (struct gdbarch *gdbarch,
int raw_num = mips_regnum (gdbarch)->fp0;
int raw_len = register_size (gdbarch, raw_num);
enum mips_fpu_mode fp_mode = gdbarch_tdep (gdbarch)->fp_mode;
- int big_endian;
+ int big_endian, offs;
/* Only even doubles provided, in pairs of 32-bit registers. */
if (raw_len == 4)
@@ -846,11 +868,13 @@ mips_get_fp_single_location (struct gdbarch *gdbarch,
return 1;
}
- if (raw_len != 8)
+ if (raw_len < 8)
return 0;
- /* All doubles provided. */
+ /* All doubles provided, potentially at least significant end of vector
+ register. */
big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG);
+ offs = big_endian ? (raw_len - 8) : 0;
loc->size = 4;
switch (fp_mode)
@@ -858,11 +882,11 @@ mips_get_fp_single_location (struct gdbarch *gdbarch,
case MIPS_FPU_32:
case MIPS_FPU_HYBRID:
loc->regnum = raw_num + (idx & ~1);
- loc->offset = 4 * (big_endian ^ (idx & 1));
+ loc->offset = offs + 4 * (big_endian ^ (idx & 1));
return 1;
case MIPS_FPU_64:
loc->regnum = raw_num + idx;
- loc->offset = 4 * big_endian;
+ loc->offset = offs + 4 * big_endian;
return 1;
default:
return 0;
@@ -899,16 +923,17 @@ mips_get_fp_double_location (struct gdbarch *gdbarch,
return 2;
}
- if (raw_len != 8)
+ if (raw_len < 8)
return 0;
/* FPU32 doesn't have odd doubles */
if (fp_mode == MIPS_FPU_32 && idx & 1)
return 0;
- /* All doubles provided. */
+ /* All doubles provided, potentially at least significant end of vector
+ register. */
loc->regnum = raw_num + idx;
- loc->offset = 0;
+ loc->offset = big_endian ? (raw_len - 8) : 0;
loc->size = 8;
return 1;
}
@@ -999,6 +1024,7 @@ static enum register_status
mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
int cookednum, gdb_byte *buf)
{
+ int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG);
int rawnum = cookednum % gdbarch_num_regs (gdbarch);
int fpnum;
int raw_len, cooked_len;
@@ -1018,6 +1044,22 @@ mips_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache,
parts = mips_get_fp_multi_location (gdbarch, fpnum, cooked_len, loc);
return mips_regcache_raw_read_parts (regcache, loc, parts, &buf);
}
+ else if (mips_vector_register_p (gdbarch, rawnum))
+ {
+ int fp_rawnum, fp_raw_len;
+
+ fpnum = rawnum - mips_regnum (gdbarch)->w0;
+ fp_rawnum = mips_regnum (gdbarch)->fp0 + fpnum;
+ fp_raw_len = register_size (gdbarch, fp_rawnum);
+
+ if (fp_raw_len < cooked_len)
+ return REG_UNAVAILABLE;
+
+ /* fill from normal fp register */
+ return regcache_raw_read_part (regcache, fp_rawnum,
+ big_endian * (fp_raw_len - cooked_len),
+ cooked_len, buf);
+ }
else if (raw_len == cooked_len)
return regcache_raw_read (regcache, rawnum, buf);
else if (raw_len > cooked_len)
@@ -1045,6 +1087,7 @@ mips_pseudo_register_write (struct gdbarch *gdbarch,
struct regcache *regcache, int cookednum,
const gdb_byte *buf)
{
+ int big_endian = (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG);
int rawnum = cookednum % gdbarch_num_regs (gdbarch);
int fpnum;
int raw_len, cooked_len;
@@ -1064,6 +1107,22 @@ mips_pseudo_register_write (struct gdbarch *gdbarch,
parts = mips_get_fp_multi_location (gdbarch, fpnum, cooked_len, loc);
mips_regcache_raw_write_parts (regcache, loc, parts, &buf);
}
+ else if (mips_vector_register_p (gdbarch, rawnum))
+ {
+ int fp_rawnum, fp_raw_len;
+
+ fpnum = rawnum - mips_regnum (gdbarch)->w0;
+ fp_rawnum = mips_regnum (gdbarch)->fp0 + fpnum;
+ fp_raw_len = register_size (gdbarch, fp_rawnum);
+
+ if (fp_raw_len < cooked_len)
+ return;
+
+ /* write to normal fp register */
+ regcache_raw_write_part (regcache, fp_rawnum,
+ big_endian * (fp_raw_len - cooked_len),
+ cooked_len, buf);
+ }
else if (raw_len == cooked_len)
regcache_raw_write (regcache, rawnum, buf);
else if (raw_len > cooked_len)
@@ -1441,6 +1500,58 @@ mips_fp_type (struct gdbarch *gdbarch, int fpnum)
return mips_fp32_type (gdbarch);
}
+/* 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 *
+mips_msa_128b_type (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->msa_128b_type == NULL)
+ {
+ const struct builtin_type *bt = builtin_type (gdbarch);
+ struct type *t;
+
+ /* The type we're building is this:
+
+ union __gdb_builtin_type_msa_128
+ {
+ float f32[4];
+ double f64[2];
+ uint8_t u8[16];
+ uint16_t u16[8];
+ uint32_t u32[4];
+ uint64_t u64[2];
+ }; */
+
+ t = arch_composite_type (gdbarch, "__gdb_builtin_type_msa_128",
+ TYPE_CODE_UNION);
+ append_composite_type_field (t, "u8",
+ init_vector_type (bt->builtin_uint8, 16));
+ append_composite_type_field (t, "u16",
+ init_vector_type (bt->builtin_uint16, 8));
+ append_composite_type_field (t, "u32",
+ init_vector_type (bt->builtin_uint32, 4));
+ append_composite_type_field (t, "u64",
+ init_vector_type (bt->builtin_uint64, 2));
+ append_composite_type_field (t, "f32",
+ init_vector_type (bt->builtin_float, 4));
+ append_composite_type_field (t, "f64",
+ init_vector_type (bt->builtin_double, 2));
+
+ TYPE_VECTOR (t) = 1;
+ TYPE_NAME (t) = "msa_128";
+ tdep->msa_128b_type = t;
+ }
+
+ return tdep->msa_128b_type;
+}
+
/* Get floating point rounding mode enumeration type */
static struct type *
@@ -1693,6 +1804,9 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
return (mips_float_regsize (gdbarch) == 4
? builtin_type (gdbarch)->builtin_float
: builtin_type (gdbarch)->builtin_double);
+ else if (mips_vector_register_p (gdbarch, regnum))
+ /* no raw representation, share fp registers */
+ return builtin_type (gdbarch)->builtin_int0;
else
return (regsize == 4
? builtin_type (gdbarch)->builtin_int32
@@ -1710,6 +1824,8 @@ mips_register_type (struct gdbarch *gdbarch, int regnum)
Use the current setting for cooked registers. */
if (mips_float_register_p (gdbarch, regnum))
return mips_fp_type (gdbarch, rawnum - mips_regnum (gdbarch)->fp0);
+ else if (mips_vector_register_p (gdbarch, regnum))
+ return mips_msa_128b_type (gdbarch);
else if (rawnum == mips_regnum (gdbarch)->fp_control_status)
return mips_fcsr_type (gdbarch);
else if (rawnum == mips_regnum (gdbarch)->fp_implementation_revision)
@@ -1752,8 +1868,13 @@ mips_pseudo_register_type (struct gdbarch *gdbarch, int regnum)
gdb_assert (regnum >= num_regs && regnum < 2 * num_regs);
- /* Absent registers are still absent. */
rawtype = gdbarch_register_type (gdbarch, rawnum);
+
+ /* Vector registers extend FP registers */
+ if (mips_vector_register_p (gdbarch, rawnum))
+ return mips_msa_128b_type (gdbarch);
+
+ /* Absent registers are still absent. */
if (TYPE_LENGTH (rawtype) == 0)
return rawtype;
@@ -7111,6 +7232,11 @@ mips_print_register (struct ui_file *file, struct frame_info *frame, int regnum)
print_control_register (file, frame, regnum);
return;
}
+ if (mips_vector_register_p (gdbarch, regnum))
+ {
+ default_print_registers_info (gdbarch, file, frame, regnum, 0);
+ return;
+ }
val = get_frame_register_value (frame, regnum);
@@ -7257,7 +7383,8 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
{
if (*gdbarch_register_name (gdbarch, regnum) == '\0')
continue; /* unused register */
- if (mips_float_register_p (gdbarch, regnum))
+ if (mips_float_register_p (gdbarch, regnum) ||
+ mips_vector_register_p (gdbarch, regnum))
break; /* End the row: reached FP register. */
/* Large registers are handled separately. */
if (register_size (gdbarch, regnum) > mips_abi_regsize (gdbarch))
@@ -7296,7 +7423,8 @@ print_gp_register_row (struct ui_file *file, struct frame_info *frame,
{
if (*gdbarch_register_name (gdbarch, regnum) == '\0')
continue; /* unused register */
- if (mips_float_register_p (gdbarch, regnum))
+ if (mips_float_register_p (gdbarch, regnum) ||
+ mips_vector_register_p (gdbarch, regnum))
break; /* End row: reached FP register. */
if (register_size (gdbarch, regnum) > mips_abi_regsize (gdbarch))
break; /* End row: large register. */
@@ -7371,6 +7499,17 @@ mips_print_registers_info (struct gdbarch *gdbarch, struct ui_file *file,
else
regnum += MIPS_NUMREGS; /* Skip floating point regs. */
}
+ else if (mips_vector_register_p (gdbarch, regnum))
+ {
+ if (all) /* True for "INFO ALL-REGISTERS" command. */
+ {
+ default_print_registers_info (gdbarch, file, frame, regnum,
+ all);
+ ++regnum;
+ }
+ else
+ regnum += MIPS_NUMREGS; /* Skip vector regs. */
+ }
else if (mips_register_reggroup_p (gdbarch, regnum, float_reggroup) ||
mips_register_reggroup_p (gdbarch, regnum, vector_reggroup))
/* FP & MSA control registers */
@@ -8790,7 +8929,15 @@ mips_dwarf_dwarf2_ecoff_reg_to_regnum (struct gdbarch *gdbarch, int num)
if (num >= 0 && num < 32)
regnum = num;
else if (num >= 32 && num < 64)
- regnum = num + mips_regnum (gdbarch)->fp0 - 32;
+ {
+ /* If FR=1, it could be referring to an MSA vector register (which aliases
+ the corresponding single and double precision fp register). Therefore
+ if vector registers are available use them instead. */
+ if (mips_regnum (gdbarch)->w0 != -1 && mips_float_regsize (gdbarch) == 8)
+ regnum = num + mips_regnum (gdbarch)->w0 - 32;
+ else
+ regnum = num + mips_regnum (gdbarch)->fp0 - 32;
+ }
else if (num == 64)
regnum = mips_regnum (gdbarch)->hi;
else if (num == 65)
@@ -8964,6 +9111,9 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
/* Fill in the OS dependent register numbers and names. */
mips_regnum.config5 = -1;
+ mips_regnum.w0 = -1;
+ mips_regnum.msa_ir = -1;
+ mips_regnum.msa_csr = -1;
mips_regnum.linux_restart = -1;
if (info.osabi == GDB_OSABI_IRIX)
{
@@ -9167,6 +9317,29 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
}
}
+ /* MSA vector control registers */
+ feature = tdesc_find_feature (info.target_desc,
+ "org.gnu.gdb.mips.msa");
+ if (feature != NULL)
+ {
+ /* Allocate a new registers. */
+ mips_regnum.w0 = num_regs;
+ num_regs += 32;
+ mips_regnum.msa_ir = num_regs++;
+ mips_regnum.msa_csr = num_regs++;
+
+ valid_p = 1;
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ mips_regnum.msa_csr, "msacsr");
+ valid_p &= tdesc_numbered_register (feature, tdesc_data,
+ mips_regnum.msa_ir, "msair");
+ if (!valid_p)
+ {
+ tdesc_data_cleanup (tdesc_data);
+ return NULL;
+ }
+ }
+
/* It would be nice to detect an attempt to use a 64-bit ABI
when only 32-bit registers are provided. */
reg_names = NULL;
@@ -9409,6 +9582,7 @@ mips_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
tdep->fp32_type = NULL;
tdep->fp64_type = NULL;
tdep->fp96_type = NULL;
+ tdep->msa_128b_type = NULL;
if (info.target_desc)
{
diff --git a/gdb/mips-tdep.h b/gdb/mips-tdep.h
index 110eb6c..b5f00fc 100644
--- a/gdb/mips-tdep.h
+++ b/gdb/mips-tdep.h
@@ -70,6 +70,9 @@ struct mips_regnum
int lo; /* ... */
int dspacc; /* SmartMIPS/DSP accumulators. */
int dspctl; /* DSP control. */
+ int w0;
+ int msa_ir;
+ int msa_csr;
int linux_restart;
};
extern const struct mips_regnum *mips_regnum (struct gdbarch *gdbarch);
@@ -139,6 +142,7 @@ struct gdbarch_tdep
struct type *fp32_type;
struct type *fp64_type;
struct type *fp96_type;
+ struct type *msa_128b_type;
/* Return the expected next PC if FRAME is stopped at a syscall
instruction. */
--
1.9-rc2