aboutsummaryrefslogtreecommitdiff
path: root/opcodes/aarch64-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/aarch64-dis.c')
-rw-r--r--opcodes/aarch64-dis.c123
1 files changed, 77 insertions, 46 deletions
diff --git a/opcodes/aarch64-dis.c b/opcodes/aarch64-dis.c
index 6552d0e..c9e60a9 100644
--- a/opcodes/aarch64-dis.c
+++ b/opcodes/aarch64-dis.c
@@ -149,7 +149,6 @@ aarch64_insn
extract_fields (aarch64_insn code, aarch64_insn mask, ...)
{
uint32_t num;
- const aarch64_field *field;
enum aarch64_field_kind kind;
va_list va;
@@ -160,8 +159,7 @@ extract_fields (aarch64_insn code, aarch64_insn mask, ...)
while (num--)
{
kind = va_arg (va, enum aarch64_field_kind);
- field = &fields[kind];
- value <<= field->width;
+ value <<= aarch64_fields[kind].width;
value |= extract_field (kind, code, mask);
}
va_end (va);
@@ -184,7 +182,7 @@ extract_all_fields_after (const aarch64_operand *self, unsigned int start,
i < ARRAY_SIZE (self->fields) && self->fields[i] != FLD_NIL; ++i)
{
kind = self->fields[i];
- value <<= fields[kind].width;
+ value <<= aarch64_fields[kind].width;
value |= extract_field (kind, code, 0);
}
return value;
@@ -297,8 +295,7 @@ aarch64_ext_regno (const aarch64_operand *self, aarch64_opnd_info *info,
const aarch64_inst *inst ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
- info->reg.regno = (extract_field (self->fields[0], code, 0)
- + get_operand_specific_data (self));
+ info->reg.regno = extract_all_fields (self, code);
return true;
}
@@ -501,23 +498,23 @@ aarch64_ext_ldst_reglist (const aarch64_operand *self ATTRIBUTE_UNUSED,
/* Number of elements in each structure to be loaded/stored. */
unsigned expected_num = get_opcode_dependent_value (inst->opcode);
- struct
+ static const struct
{
- unsigned is_reserved;
- unsigned num_regs;
- unsigned num_elements;
+ unsigned num_regs:8;
+ unsigned num_elements:8;
+ bool is_reserved:1;
} data [] =
- { {0, 4, 4},
- {1, 4, 4},
- {0, 4, 1},
- {0, 4, 2},
- {0, 3, 3},
- {1, 3, 3},
- {0, 3, 1},
- {0, 1, 1},
- {0, 2, 2},
- {1, 2, 2},
- {0, 2, 1},
+ { {4, 4, false},
+ {4, 4, true},
+ {4, 1, false},
+ {4, 2, false},
+ {3, 3, false},
+ {3, 3, true},
+ {3, 1, false},
+ {1, 1, false},
+ {2, 2, false},
+ {2, 2, true},
+ {2, 1, false},
};
/* Rt */
@@ -586,7 +583,7 @@ aarch64_ext_ldst_elemlist (const aarch64_operand *self ATTRIBUTE_UNUSED,
const aarch64_inst *inst ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
- aarch64_field field = {0, 0};
+ aarch64_field field = AARCH64_FIELD_NIL;
aarch64_insn QSsize; /* fields Q:S:size. */
aarch64_insn opcodeh2; /* opcode<2:1> */
@@ -798,7 +795,7 @@ aarch64_ext_advsimd_imm_modified (const aarch64_operand *self ATTRIBUTE_UNUSED,
{
uint64_t imm;
enum aarch64_opnd_qualifier opnd0_qualifier = inst->operands[0].qualifier;
- aarch64_field field = {0, 0};
+ aarch64_field field = AARCH64_FIELD_NIL;
assert (info->idx == 1);
@@ -1240,7 +1237,8 @@ aarch64_ext_addr_simm (const aarch64_operand *self, aarch64_opnd_info *info,
info->addr.base_regno = extract_field (FLD_Rn, code, 0);
/* simm (imm9 or imm7) */
imm = extract_field (self->fields[0], code, 0);
- info->addr.offset.imm = sign_extend (imm, fields[self->fields[0]].width - 1);
+ info->addr.offset.imm
+ = sign_extend (imm, aarch64_fields[self->fields[0]].width - 1);
if (self->fields[0] == FLD_imm7
|| info->qualifier == AARCH64_OPND_QLF_imm_tag)
/* scaled immediate in ld/st pair instructions. */
@@ -1429,6 +1427,9 @@ aarch64_ext_sysins_op (const aarch64_operand *self ATTRIBUTE_UNUSED,
switch (info->type)
{
+ case AARCH64_OPND_GIC: sysins_ops = aarch64_sys_ins_gic; break;
+ case AARCH64_OPND_GICR: sysins_ops = aarch64_sys_ins_gicr; break;
+ case AARCH64_OPND_GSB: sysins_ops = aarch64_sys_ins_gsb; break;
case AARCH64_OPND_SYSREG_AT: sysins_ops = aarch64_sys_regs_at; break;
case AARCH64_OPND_SYSREG_DC: sysins_ops = aarch64_sys_regs_dc; break;
case AARCH64_OPND_SYSREG_IC: sysins_ops = aarch64_sys_regs_ic; break;
@@ -1890,8 +1891,7 @@ aarch64_ext_sve_aligned_reglist (const aarch64_operand *self,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
unsigned int num_regs = get_operand_specific_data (self);
- unsigned int val = extract_field (self->fields[0], code, 0);
- info->reglist.first_regno = val * num_regs;
+ info->reglist.first_regno = extract_all_fields (self, code);
info->reglist.num_regs = num_regs;
info->reglist.stride = 1;
return true;
@@ -2440,17 +2440,17 @@ aarch64_ext_x0_to_x30 (const aarch64_operand *self, aarch64_opnd_info *info,
return info->reg.regno <= 30;
}
-/* Decode an indexed register, with the first field being the register
- number and the remaining fields being the index. */
+/* Decode an indexed register, with the last five field bits holding the
+ register number and the remaining bits holding the index. */
bool
aarch64_ext_simple_index (const aarch64_operand *self, aarch64_opnd_info *info,
const aarch64_insn code,
const aarch64_inst *inst ATTRIBUTE_UNUSED,
aarch64_operand_error *errors ATTRIBUTE_UNUSED)
{
- int bias = get_operand_specific_data (self);
- info->reglane.regno = extract_field (self->fields[0], code, 0) + bias;
- info->reglane.index = extract_all_fields_after (self, 1, code);
+ unsigned int val = extract_all_fields (self, code);
+ info->reglane.regno = val & 31;
+ info->reglane.index = val >> 5;
return true;
}
@@ -2597,7 +2597,7 @@ decode_sizeq (aarch64_inst *inst)
static int
decode_asimd_fcvt (aarch64_inst *inst)
{
- aarch64_field field = {0, 0};
+ aarch64_field field = AARCH64_FIELD_NIL;
aarch64_insn value;
enum aarch64_opnd_qualifier qualifier;
@@ -2630,7 +2630,7 @@ decode_asimd_fcvt (aarch64_inst *inst)
static int
decode_asisd_fcvtxn (aarch64_inst *inst)
{
- aarch64_field field = {0, 0};
+ aarch64_field field = AARCH64_FIELD_NIL;
gen_sub_field (FLD_size, 0, 1, &field);
if (!extract_field_2 (&field, inst->value, 0))
return 0;
@@ -2644,7 +2644,7 @@ decode_fcvt (aarch64_inst *inst)
{
enum aarch64_opnd_qualifier qualifier;
aarch64_insn value;
- const aarch64_field field = {15, 2};
+ const aarch64_field field = AARCH64_FIELD (15, 2);
/* opc dstsize */
value = extract_field_2 (&field, inst->value, 0);
@@ -2746,7 +2746,16 @@ do_special_decoding (aarch64_inst *inst)
{
idx = select_operand_for_sf_field_coding (inst->opcode);
value = extract_field (FLD_sf, inst->value, 0);
- inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
+ if (inst->opcode->iclass == fprcvtfloat2int
+ || inst->opcode->iclass == fprcvtint2float)
+ {
+ if (value == 0)
+ inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_S;
+ else
+ inst->operands[idx].qualifier = AARCH64_OPND_QLF_S_D;
+ }
+ else
+ inst->operands[idx].qualifier = get_greg_qualifier_from_value (value);
if (inst->operands[idx].qualifier == AARCH64_OPND_QLF_ERR)
return 0;
if ((inst->opcode->flags & F_N)
@@ -2831,6 +2840,23 @@ do_special_decoding (aarch64_inst *inst)
}
}
+ if (inst->opcode->flags & F_LSFE_SZ)
+ {
+ value = extract_field (FLD_ldst_size, inst->value, 0);
+
+ if (value > 0x3)
+ return 0;
+
+ for (int i = 0;
+ aarch64_operands[inst->operands[i].type].op_class != AARCH64_OPND_CLASS_ADDRESS;
+ i++)
+ {
+ inst->operands[i].qualifier = get_sreg_qualifier_from_value (value);
+ if (inst->operands[i].qualifier == AARCH64_OPND_QLF_ERR)
+ return 0;
+ }
+ }
+
if (inst->opcode->flags & F_T)
{
/* Num of consecutive '0's on the right side of imm5<3:0>. */
@@ -2897,7 +2923,7 @@ do_special_decoding (aarch64_inst *inst)
if (inst->opcode->flags & F_LDS_SIZE)
{
- aarch64_field field = {0, 0};
+ aarch64_field field = AARCH64_FIELD_NIL;
assert (aarch64_get_operand_class (inst->opcode->operands[0])
== AARCH64_OPND_CLASS_INT_REG);
gen_sub_field (FLD_opc, 0, 1, &field);
@@ -3577,6 +3603,14 @@ aarch64_decode_variant_using_iclass (aarch64_inst *inst)
variant = extract_field (FLD_SVE_sz2, inst->value, 0);
break;
+ case sve_size_sd3:
+ variant = extract_field (FLD_SVE_sz3, inst->value, 0);
+ break;
+
+ case sve_size_sd4:
+ variant = extract_field (FLD_SVE_sz4, inst->value, 0);
+ break;
+
case sve_size_hsd2:
i = extract_field (FLD_SVE_size, inst->value, 0);
if (i < 1)
@@ -3584,6 +3618,13 @@ aarch64_decode_variant_using_iclass (aarch64_inst *inst)
variant = i - 1;
break;
+ case sve_size_hsd3:
+ i = extract_field (FLD_len, inst->value, 0);
+ if (i < 1)
+ return false;
+ variant = i - 1;
+ break;
+
case sve_size_13:
/* Ignore low bit of this field since that is set in the opcode for
instructions of this iclass. */
@@ -4147,7 +4188,6 @@ print_aarch64_insn (bfd_vma pc, const aarch64_inst *inst,
break;
case ERR_UND:
case ERR_UNP:
- case ERR_NYI:
default:
break;
}
@@ -4166,7 +4206,6 @@ print_insn_aarch64_word (bfd_vma pc,
[ERR_OK] = "_",
[ERR_UND] = "undefined",
[ERR_UNP] = "unpredictable",
- [ERR_NYI] = "NYI"
};
enum err_type ret;
@@ -4188,18 +4227,10 @@ print_insn_aarch64_word (bfd_vma pc,
ret = aarch64_decode_insn (word, &inst, no_aliases, errors);
- if (((word >> 21) & 0x3ff) == 1)
- {
- /* RESERVED for ALES. */
- assert (ret != ERR_OK);
- ret = ERR_NYI;
- }
-
switch (ret)
{
case ERR_UND:
case ERR_UNP:
- case ERR_NYI:
/* Handle undefined instructions. */
info->insn_type = dis_noninsn;
(*info->fprintf_styled_func) (info->stream,