aboutsummaryrefslogtreecommitdiff
path: root/opcodes
diff options
context:
space:
mode:
authorVictor Do Nascimento <victor.donascimento@arm.com>2024-01-05 17:27:04 +0000
committerVictor Do Nascimento <victor.donascimento@arm.com>2024-01-15 13:11:48 +0000
commitc35460087723932ba7300072099bd0d65d9ce6d2 (patch)
tree63de650feaf214b78cfe9f4be4425d7b79729ac6 /opcodes
parent2f8890efc521d0477728ade637cb1d03a4aa799d (diff)
downloadfsf-binutils-gdb-c35460087723932ba7300072099bd0d65d9ce6d2.zip
fsf-binutils-gdb-c35460087723932ba7300072099bd0d65d9ce6d2.tar.gz
fsf-binutils-gdb-c35460087723932ba7300072099bd0d65d9ce6d2.tar.bz2
aarch64: rcpc3: Define address operand fields and inserter/extractors
Beyond the need to encode any registers involved in data transfer and the address base register for load/stores, it is necessary to specify the data register addressing mode and whether the address register is to be pre/post-indexed, whereby loads may be post-indexed and stores pre-indexed with write-back. The use of a single bit to specify both the indexing mode and indexing value requires a novel function be written to accommodate this for address operand insertion in assembly and another for extraction in disassembly, along with the definition of two insn fields for use with these instructions. This therefore defines the following functions: - aarch64_ins_rcpc3_addr_opt_offset - aarch64_ins_rcpc3_addr_offset - aarch64_ext_rcpc3_addr_opt_offset - aarch64_ext_rcpc3_addr_offset It extends the `do_special_{encoding|decoding}' functions and defines two rcpc3 instruction fields: - FLD_opc2 - FLD_rcpc3_size
Diffstat (limited to 'opcodes')
-rw-r--r--opcodes/aarch64-asm.c56
-rw-r--r--opcodes/aarch64-asm.h2
-rw-r--r--opcodes/aarch64-dis.c84
-rw-r--r--opcodes/aarch64-dis.h3
-rw-r--r--opcodes/aarch64-opc.c2
-rw-r--r--opcodes/aarch64-opc.h4
6 files changed, 150 insertions, 1 deletions
diff --git a/opcodes/aarch64-asm.c b/opcodes/aarch64-asm.c
index 4d0b13e..565c4b1 100644
--- a/opcodes/aarch64-asm.c
+++ b/opcodes/aarch64-asm.c
@@ -702,6 +702,24 @@ aarch64_ins_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
return true;
}
+/* Encode the address operand for e.g.
+ stlur <Xt>, [<Xn|SP>{, <amount>}]. */
+bool
+aarch64_ins_rcpc3_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
+ const aarch64_opnd_info *info, aarch64_insn *code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED,
+ aarch64_operand_error *errors ATTRIBUTE_UNUSED)
+{
+ /* Rn */
+ insert_field (self->fields[0], code, info->addr.base_regno, 0);
+
+ /* simm9 */
+ int imm = info->addr.offset.imm;
+ insert_field (self->fields[1], code, imm, 0);
+
+ return true;
+}
+
/* Encode the address operand for e.g. LDRSW <Xt>, [<Xn|SP>, #<simm>]!. */
bool
aarch64_ins_addr_simm (const aarch64_operand *self,
@@ -736,6 +754,28 @@ aarch64_ins_addr_simm (const aarch64_operand *self,
return true;
}
+/* Encode the address operand, potentially offset by the load/store ammount,
+ e.g. LDIAPP <Xt>, <Xt2> [<Xn|SP>, #<simm>]
+ and STILP <Xt>, <Xt2> [<Xn|SP>], #<simm>.*/
+bool
+aarch64_ins_rcpc3_addr_opt_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
+ const aarch64_opnd_info *info,
+ aarch64_insn *code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED,
+ aarch64_operand_error *errors ATTRIBUTE_UNUSED)
+{
+ int imm;
+
+ /* Rn */
+ insert_field (FLD_Rn, code, info->addr.base_regno, 0);
+ /* simm */
+ imm = info->addr.offset.imm;
+ if (!imm)
+ insert_field (FLD_opc2, code, 1, 0);
+
+ return true;
+}
+
/* Encode the address operand for e.g. LDRAA <Xt>, [<Xn|SP>{, #<simm>}]. */
bool
aarch64_ins_addr_simm10 (const aarch64_operand *self,
@@ -1943,6 +1983,22 @@ do_special_encoding (struct aarch64_inst *inst)
? 1 : 0;
insert_field (FLD_lse_sz, &inst->value, value, 0);
}
+ if (inst->opcode->flags & F_RCPC3_SIZE)
+ {
+ switch (inst->operands[0].qualifier)
+ {
+ case AARCH64_OPND_QLF_W: value = 2; break;
+ case AARCH64_OPND_QLF_X: value = 3; break;
+ case AARCH64_OPND_QLF_S_B: value = 0; break;
+ case AARCH64_OPND_QLF_S_H: value = 1; break;
+ case AARCH64_OPND_QLF_S_S: value = 2; break;
+ case AARCH64_OPND_QLF_S_D: value = 3; break;
+ case AARCH64_OPND_QLF_S_Q: value = 0; break;
+ default: return;
+ }
+ insert_field (FLD_rcpc3_size, &inst->value, value, 0);
+ }
+
if (inst->opcode->flags & F_SIZEQ)
encode_sizeq (inst);
if (inst->opcode->flags & F_FPTYPE)
diff --git a/opcodes/aarch64-asm.h b/opcodes/aarch64-asm.h
index e48bf0d..c6dde1c 100644
--- a/opcodes/aarch64-asm.h
+++ b/opcodes/aarch64-asm.h
@@ -115,6 +115,8 @@ AARCH64_DECL_OPD_INSERTER (ins_imm_rotate2);
AARCH64_DECL_OPD_INSERTER (ins_x0_to_x30);
AARCH64_DECL_OPD_INSERTER (ins_simple_index);
AARCH64_DECL_OPD_INSERTER (ins_plain_shrimm);
+AARCH64_DECL_OPD_INSERTER (ins_rcpc3_addr_opt_offset);
+AARCH64_DECL_OPD_INSERTER (ins_rcpc3_addr_offset);
#undef AARCH64_DECL_OPD_INSERTER
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 2896a11..f63b747 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -1032,6 +1032,70 @@ aarch64_ext_addr_simple (const aarch64_operand *self ATTRIBUTE_UNUSED,
return true;
}
+/* Decode the address operand for rcpc3 instructions with optional load/store
+ datasize offset, e.g. STILPP <Xs>, <Xt>, [<Xn|SP>{,#-16}]! and
+ LIDAP <Xs>, <Xt>, [<Xn|SP>]{,#-16}. */
+bool
+aarch64_ext_rcpc3_addr_opt_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
+ aarch64_opnd_info *info,
+ aarch64_insn code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED,
+ aarch64_operand_error *err ATTRIBUTE_UNUSED)
+{
+ info->addr.base_regno = extract_field (FLD_Rn, code, 0);
+ if (!extract_field (FLD_opc2, code, 0))
+ {
+ info->addr.writeback = 1;
+
+ enum aarch64_opnd type;
+ for (int i = 0; i < AARCH64_MAX_OPND_NUM; i++)
+ {
+ aarch64_opnd_info opnd = info[i];
+ type = opnd.type;
+ if (aarch64_operands[type].op_class == AARCH64_OPND_CLASS_ADDRESS)
+ break;
+ }
+
+ assert (aarch64_operands[type].op_class == AARCH64_OPND_CLASS_ADDRESS);
+ int offset = calc_ldst_datasize (inst->operands);
+
+ switch (type)
+ {
+ case AARCH64_OPND_RCPC3_ADDR_OPT_PREIND_WB:
+ case AARCH64_OPND_RCPC3_ADDR_PREIND_WB:
+ info->addr.offset.imm = -offset;
+ info->addr.preind = 1;
+ break;
+ case AARCH64_OPND_RCPC3_ADDR_OPT_POSTIND:
+ case AARCH64_OPND_RCPC3_ADDR_POSTIND:
+ info->addr.offset.imm = offset;
+ info->addr.postind = 1;
+ break;
+ default:
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+aarch64_ext_rcpc3_addr_offset (const aarch64_operand *self ATTRIBUTE_UNUSED,
+ aarch64_opnd_info *info,
+ aarch64_insn code,
+ const aarch64_inst *inst ATTRIBUTE_UNUSED,
+ aarch64_operand_error *errors ATTRIBUTE_UNUSED)
+{
+ info->qualifier = get_expected_qualifier (inst, info->idx);
+
+ /* Rn */
+ info->addr.base_regno = extract_field (self->fields[0], code, 0);
+
+ /* simm9 */
+ aarch64_insn imm = extract_fields (code, 0, 1, self->fields[1]);
+ info->addr.offset.imm = sign_extend (imm, 8);
+ return true;
+}
+
/* Decode the address operand for e.g.
stlur <Xt>, [<Xn|SP>{, <amount>}]. */
bool
@@ -2579,6 +2643,26 @@ do_special_decoding (aarch64_inst *inst)
value = extract_field (FLD_lse_sz, inst->value, 0);
inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
}
+ /* rcpc3 'size' field. */
+ if (inst->opcode->flags & F_RCPC3_SIZE)
+ {
+ value = extract_field (FLD_rcpc3_size, inst->value, 0);
+ for (int i = 0;
+ aarch64_operands[inst->operands[i].type].op_class != AARCH64_OPND_CLASS_ADDRESS;
+ i++)
+ {
+ if (aarch64_operands[inst->operands[i].type].op_class
+ == AARCH64_OPND_CLASS_INT_REG)
+ inst->operands[i].qualifier = get_greg_qualifier_from_value (value & 1);
+ else if (aarch64_operands[inst->operands[i].type].op_class
+ == AARCH64_OPND_CLASS_FP_REG)
+ {
+ value += (extract_field (FLD_opc1, inst->value, 0) << 2);
+ inst->operands[i].qualifier = get_sreg_qualifier_from_value (value);
+ }
+ }
+ }
+
/* size:Q fields. */
if (inst->opcode->flags & F_SIZEQ)
return decode_sizeq (inst);
diff --git a/opcodes/aarch64-dis.h b/opcodes/aarch64-dis.h
index 48bebfe..6ed6776 100644
--- a/opcodes/aarch64-dis.h
+++ b/opcodes/aarch64-dis.h
@@ -140,6 +140,9 @@ AARCH64_DECL_OPD_EXTRACTOR (ext_x0_to_x30);
AARCH64_DECL_OPD_EXTRACTOR (ext_simple_index);
AARCH64_DECL_OPD_EXTRACTOR (ext_plain_shrimm);
AARCH64_DECL_OPD_EXTRACTOR (ext_sve_reglist_zt);
+AARCH64_DECL_OPD_EXTRACTOR (ext_rcpc3_addr_opt_offset);
+AARCH64_DECL_OPD_EXTRACTOR (ext_rcpc3_addr_offset);
+
#undef AARCH64_DECL_OPD_EXTRACTOR
diff --git a/opcodes/aarch64-opc.c b/opcodes/aarch64-opc.c
index 091df2c..9a72d30 100644
--- a/opcodes/aarch64-opc.c
+++ b/opcodes/aarch64-opc.c
@@ -410,6 +410,8 @@ const aarch64_field fields[] =
{ 6, 2 }, /* ZAn_2: name of the 2bit encoded ZA tile. */
{ 5, 3 }, /* ZAn_3: name of the 3bit encoded ZA tile. */
{ 6, 1 }, /* ZAn: name of the bit encoded ZA tile. */
+ { 12, 4 }, /* opc2: in rcpc3 ld/st inst deciding the pre/post-index. */
+ { 30, 2 }, /* rcpc3_size: in rcpc3 ld/st, field controls Rt/Rt2 width. */
};
enum aarch64_operand_class
diff --git a/opcodes/aarch64-opc.h b/opcodes/aarch64-opc.h
index 5877751..4e781f0 100644
--- a/opcodes/aarch64-opc.h
+++ b/opcodes/aarch64-opc.h
@@ -216,7 +216,9 @@ enum aarch64_field_kind
FLD_ol,
FLD_ZAn_2,
FLD_ZAn_3,
- FLD_ZAn
+ FLD_ZAn,
+ FLD_opc2,
+ FLD_rcpc3_size,
};
/* Field description. */