struct svp64_ctx {
const struct svp64_desc *desc;
+ struct svp64_insn insn;
unsigned int pmmode : 1;
unsigned int pmask : 3;
unsigned int smmode : 1;
svp64_validate_and_fix_mode (svp64);
}
+static void
+svp64_remap_extra (struct svp64_ctx *svp64,
+ ppc_opindex_t opindex, uint32_t value)
+{
+ const struct svp64_extra_desc *desc;
+
+ desc = svp64_extra_desc (svp64->desc, opindex);
+ svp64_raise_if ((desc == NULL), "cannot remap EXTRA");
+
+ return (*desc->set) (&svp64->insn, value);
+}
+
+static int64_t
+svp64_remap_reg (struct svp64_ctx *svp64, int64_t value,
+ ppc_opindex_t opindex, bool vector)
+{
+ uint32_t field;
+ uint32_t sv_extra;
+
+ svp64_raise_if (((value < 0) || (value > 127)),
+ "register does not fit the expected range 0..127");
+ field = (uint32_t)value;
+
+ if (vector)
+ {
+ /* cut into 5-bits 2-bits FFFFF SS */
+ sv_extra = (field & 0x3);
+ field >>= 2;
+ }
+ else
+ {
+ /* cut into 2-bits 5-bits SS FFFFF */
+ sv_extra = (field >> 5);
+ field &= 0x1F;
+ }
+
+ if (svp64->desc->etype == SVP64_ETYPE_EXTRA2)
+ {
+ if (vector)
+ {
+ /* range is r0-r127 in increments of 2 (r0 r2 ... r126) */
+ svp64_raise_if ( ((sv_extra & 1) != 0),
+ "vector register cannot fit into EXTRA2");
+ sv_extra = (0x2 | (sv_extra >> 1));
+ }
+ else
+ {
+ /* range is r0-r63 in increments of 1 */
+ svp64_raise_if ( ((sv_extra >> 1) != 0),
+ "scalar register cannot fit into EXTRA2");
+ sv_extra &= 0x1;
+ }
+ }
+ else if (vector)
+ {
+ /* EXTRA3 vector bit needs marking */
+ sv_extra |= 0x4;
+ }
+
+ svp64_remap_extra (svp64, opindex, sv_extra);
+
+ return field;
+}
+
+static int64_t
+svp64_remap_gpr (struct svp64_ctx *svp64, int64_t value,
+ ppc_opindex_t opindex, bool vector)
+{
+ return svp64_remap_reg (svp64, value, opindex, vector);
+}
+
+static int64_t
+svp64_remap_fpr (struct svp64_ctx *svp64, int64_t value,
+ ppc_opindex_t opindex, bool vector)
+{
+ return svp64_remap_reg (svp64, value, opindex, vector);
+}
+
+static int64_t
+svp64_remap_cr (struct svp64_ctx *svp64, int64_t value,
+ ppc_opindex_t opindex, bool vector, bool cr_bit)
+{
+ uint32_t field;
+ uint32_t subfield;
+ uint32_t sv_extra;
+
+ svp64_raise_if (((value < 0) || (value > 127)),
+ "register does not fit the expected range 0..127");
+ field = (uint32_t)value;
+
+ if (cr_bit)
+ {
+ subfield = (field & 0x3);
+ field >>= 2;
+ }
+
+ if (vector)
+ {
+ /* cut into 3-bits 4-bits FFF SSSS but will cut 2 zeros off later */
+ sv_extra = (field & 0xf);
+ field >>= 4;
+ }
+ else
+ {
+ /* cut into 2-bits 3-bits SS FFF */
+ sv_extra = (field >> 3);
+ field &= 0x7;
+ }
+
+ if (svp64->desc->etype == SVP64_ETYPE_EXTRA2)
+ {
+ if (vector)
+ {
+ svp64_raise_if (((sv_extra & 0x7) != 0),
+ "vector CR cannot fit into EXTRA2");
+ sv_extra = (0x2 | (sv_extra >> 3));
+ }
+ else
+ {
+ svp64_raise_if (((sv_extra >> 1) != 0),
+ "scalar CR cannot fit into EXTRA2");
+ sv_extra &= 0x1;
+ }
+ }
+ else
+ {
+ if (vector)
+ {
+ svp64_raise_if (((sv_extra & 0x3) != 0),
+ "vector CR cannot fit into EXTRA3");
+ sv_extra = (0x4 | (sv_extra >> 2));
+ }
+ else
+ {
+ svp64_raise_if (((sv_extra >> 2) != 0),
+ "scalar CR cannot fit into EXTRA3");
+ sv_extra &= 0x3;
+ }
+ }
+
+ if (cr_bit)
+ field = ((field << 2) | subfield);
+
+ svp64_remap_extra (svp64, opindex, sv_extra);
+
+ return field;
+}
+
+static int64_t
+svp64_remap (struct svp64_ctx *ctx, int64_t value,
+ const struct powerpc_operand *operand, bool vector)
+{
+ const ppc_opindex_t opindex = (ppc_opindex_t)(operand - powerpc_operands);
+
+ if ((operand->flags & (PPC_OPERAND_GPR | PPC_OPERAND_GPR_0)) != 0)
+ return svp64_remap_gpr (ctx, value, opindex, vector);
+ else if ((operand->flags & PPC_OPERAND_FPR) != 0)
+ return svp64_remap_fpr (ctx, value, opindex, vector);
+ else if ((operand->flags & (PPC_OPERAND_CR_BIT | PPC_OPERAND_CR_REG)) != 0)
+ {
+ bool cr_bit = ((operand->flags & PPC_OPERAND_CR_BIT) != 0);
+
+ return svp64_remap_cr (ctx, value, opindex, vector, cr_bit);
+ }
+
+ return value;
+}
+
static void
svp64_assemble (char *str)
{
svp64_decode (str, &svp64);
svp64_validate_and_fix (&svp64);
+ svp64_insn_set_prefix_po (&svp64.insn, 0x1);
+ svp64_insn_set_prefix_id (&svp64.insn, 0x3);
+
+ svp64_insn_set_prefix_rm_mode (&svp64.insn, svp64.mode);
+ if (svp64.desc->ptype == SVP64_PTYPE_P2)
+ svp64_insn_set_prefix_rm_smask (&svp64.insn, svp64.smask);
+ svp64_insn_set_prefix_rm_mmode (&svp64.insn, svp64.mmode);
+ svp64_insn_set_prefix_rm_mask (&svp64.insn, svp64.pmask);
+ svp64_insn_set_prefix_rm_subvl (&svp64.insn, svp64.subvl);
+ svp64_insn_set_prefix_rm_ewsrc (&svp64.insn, svp64.srcwid);
+ svp64_insn_set_prefix_rm_elwidth (&svp64.insn, svp64.destwid);
+
ppc_assemble (str, &svp64);
}
as_bad (_("missing operand"));
else if (ex.X_op == O_register)
{
+ int64_t val = ex.X_add_number;
+
if ((ex.X_md
& ~operand->flags
& (PPC_OPERAND_GPR | PPC_OPERAND_FPR | PPC_OPERAND_VR
&& ex.X_add_number != 0
&& (operand->flags & PPC_OPERAND_GPR_0) != 0)))
as_warn (_("invalid register expression"));
- insn = ppc_insert_operand (insn, operand, ex.X_add_number,
+
+ if (svp64)
+ val = svp64_remap (svp64, val, operand, vector);
+ insn = ppc_insert_operand (insn, operand, val,
ppc_cpu, (char *) NULL, 0);
}
else if (ex.X_op == O_constant
break;
}
#endif /* OBJ_ELF */
+ if (svp64)
+ val = svp64_remap (svp64, val, operand, vector);
insn = ppc_insert_operand (insn, operand, val, ppc_cpu, NULL, 0);
}
else
if ((frag_now_fix () & addr_mask) != 0)
as_bad (_("instruction address is not a multiple of %d"), addr_mask + 1);
+ /* Take care of SVP64 instructions. */
+ if (svp64)
+ {
+ svp64_insn_set_suffix (&svp64->insn, insn);
+ insn = svp64_insn_get (&svp64->insn);
+ }
+
/* Differentiate between two, four, and eight byte insns. */
insn_length = 4;
if ((ppc_cpu & PPC_OPCODE_VLE) != 0 && PPC_OP_SE_VLE (insn))
insn_length = 2;
- else if ((opcode->flags & PPC_OPCODE_POWER10) != 0
- && PPC_PREFIX_P (insn))
+ else if ((svp64 || ((opcode->flags & PPC_OPCODE_POWER10) != 0)) && PPC_PREFIX_P (insn))
{
struct insn_label_list *l;