aboutsummaryrefslogtreecommitdiff
path: root/opcodes/arc-dis.c
diff options
context:
space:
mode:
authorClaudiu Zissulescu <claziss@synopsys.com>2017-02-06 11:26:13 +0100
committerClaudiu Zissulescu <claziss@synopsys.com>2017-02-06 11:26:13 +0100
commit6ec7c1ae19e9e1bf2edad5125941a2fd5fdfde0b (patch)
tree2618ac0c1711a72e5ad9151057af06ad140e9cd0 /opcodes/arc-dis.c
parent20b477a75c00de06a92b9577fd74416699d2c37f (diff)
downloadfsf-binutils-gdb-6ec7c1ae19e9e1bf2edad5125941a2fd5fdfde0b.zip
fsf-binutils-gdb-6ec7c1ae19e9e1bf2edad5125941a2fd5fdfde0b.tar.gz
fsf-binutils-gdb-6ec7c1ae19e9e1bf2edad5125941a2fd5fdfde0b.tar.bz2
[ARC] Provide an interface to decode ARC instructions.
gas/ 2017-02-06 Claudiu Zissulescu <claziss@synopsys.com> * config/tc-arc.c (parse_opcode_flags): Ignore implicit flags. include/ 2017-02-06 Claudiu Zissulescu <claziss@synopsys.com> Anton Kolesov <anton.kolesov@synopsys.com> * opcode/arc.h (insn_class_t): Add ENTER, LEAVE, POP, PUSH, BBIT0, BBIT1, BI, BIH, BRCC, EI, JLI, and SUB instruction classes. (flag_class_t): Add F_CLASS_WB, F_CLASS_ZZ, and F_CLASS_IMPLICIT flag classes. opcode/ 2017-02-06 Claudiu Zissulescu <claziss@synopsys.com> Anton Kolesov <anton.kolesov@synopsys.com> * arc-dis.c (arc_disassemble_info): New structure. (init_arc_disasm_info): New function. (find_format_from_table): Ignore implicit flags. (find_format): Update dissassembler private data. (print_flags): Likewise. (print_insn_arc): Likewise. (arc_opcode_to_insn_type): Consider the new added instruction classes. (arcAnalyzeInstr): Remove. (arc_insn_decode): New function. * arc-dis.h (arc_ldst_writeback_mode): New enum. (arc_ldst_data_size): Likewise. (arc_condition_code): Likewise. (arc_operand_kind): Likewise. (arc_insn_kind): New struct. (arc_instruction): Likewise. (arc_insn_decode): Declare function. (ARC_Debugger_OperandType): Deleted. (Flow): Likewise. (NullifyMode): Likewise. (allOperandsSize): Likewise. (arcDisState): Likewise. (arcAnalyzeInstr): Likewise. * arc-dis.c (arc_opcode_to_insn_type): Handle newly introduced insn_class_t enums. * arc-opc.c (F_SIZED): New define. (C_CC_EQ, C_CC_GE, C_CC_GT, C_CC_HI, C_CC_HS): Likewise. (C_CC_LE, C_CC_LO, C_CC_LS, C_CC_LT, C_CC_NE): Likewise. (C_CC_NE, C_AA_AB, C_AA_AW, C_ZZ_D, C_ZZ_H, C_ZZ_B): Likewise. (arc_flag_classes): Add F_CLASS_COND/F_CLASS_IMPLICIT flags. * opcodes/arc-tbl.h: Update instructions to include new F_CLASS_IMPLICIT flags. (bbit0, lp): Change class. (bbit1, bi, bih, br*, ei_s, jli_s): Likewsie
Diffstat (limited to 'opcodes/arc-dis.c')
-rw-r--r--opcodes/arc-dis.c211
1 files changed, 174 insertions, 37 deletions
diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c
index 53ba5f5..3afd253 100644
--- a/opcodes/arc-dis.c
+++ b/opcodes/arc-dis.c
@@ -51,6 +51,33 @@ struct arc_operand_iterator
const unsigned char *opidx;
};
+/* A private data used by ARC decoder. */
+struct arc_disassemble_info
+{
+ /* The current disassembled arc opcode. */
+ const struct arc_opcode *opcode;
+
+ /* Instruction length w/o limm field. */
+ unsigned insn_len;
+
+ /* TRUE if we have limm. */
+ bfd_boolean limm_p;
+
+ /* LIMM value, if exists. */
+ unsigned limm;
+
+ /* Condition code, if exists. */
+ unsigned condition_code;
+
+ /* Writeback mode. */
+ unsigned writeback_mode;
+
+ /* Number of operands. */
+ unsigned operands_count;
+
+ struct arc_insn_operand operands[MAX_INSN_ARGS];
+};
+
/* Globals variables. */
static const char * const regnames[64] =
@@ -108,6 +135,20 @@ static linkclass decodelist = NULL;
/* Functions implementation. */
+/* Initialize private data. */
+static bfd_boolean
+init_arc_disasm_info (struct disassemble_info *info)
+{
+ struct arc_disassemble_info *arc_infop
+ = calloc (sizeof (*arc_infop), 1);
+
+ if (arc_infop == NULL)
+ return FALSE;
+
+ info->private_data = arc_infop;
+ return TRUE;
+}
+
/* Add a new element to the decode list. */
static void
@@ -280,6 +321,10 @@ find_format_from_table (struct disassemble_info *info,
continue;
}
+ /* Check for the implicit flags. */
+ if (cl_flags->flag_class & F_CLASS_IMPLICIT)
+ continue;
+
for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
{
const struct arc_flag_operand *flg_operand =
@@ -367,6 +412,7 @@ find_format (bfd_vma memaddr,
bfd_boolean needs_limm;
const extInstruction_t *einsn, *i;
unsigned limm = 0;
+ struct arc_disassemble_info *arc_infop = info->private_data;
/* First, try the extension instructions. */
if (*insn_len == 4)
@@ -422,6 +468,12 @@ An error occured while generating the extension instruction operations");
}
*opcode_result = opcode;
+
+ /* Update private data. */
+ arc_infop->opcode = opcode;
+ arc_infop->limm = (needs_limm) ? limm : 0;
+ arc_infop->limm_p = needs_limm;
+
return TRUE;
}
@@ -432,6 +484,7 @@ print_flags (const struct arc_opcode *opcode,
{
const unsigned char *flgidx;
unsigned int value;
+ struct arc_disassemble_info *arc_infop = info->private_data;
/* Now extract and print the flags. */
for (flgidx = opcode->flags; *flgidx; flgidx++)
@@ -459,6 +512,18 @@ print_flags (const struct arc_opcode *opcode,
const struct arc_flag_operand *flg_operand =
&arc_flag_operands[*flgopridx];
+ /* Implicit flags are only used for the insn decoder. */
+ if (cl_flags->flag_class & F_CLASS_IMPLICIT)
+ {
+ if (cl_flags->flag_class & F_CLASS_COND)
+ arc_infop->condition_code = flg_operand->code;
+ else if (cl_flags->flag_class & F_CLASS_WB)
+ arc_infop->writeback_mode = flg_operand->code;
+ else if (cl_flags->flag_class & F_CLASS_ZZ)
+ info->data_size = flg_operand->code;
+ continue;
+ }
+
if (!flg_operand->favail)
continue;
@@ -496,8 +561,13 @@ print_flags (const struct arc_opcode *opcode,
info->insn_type = dis_condjsr;
else if (info->insn_type == dis_branch)
info->insn_type = dis_condbranch;
+ arc_infop->condition_code = flg_operand->code;
}
+ /* Check for the write back modes. */
+ if (cl_flags->flag_class & F_CLASS_WB)
+ arc_infop->writeback_mode = flg_operand->code;
+
(*info->fprintf_func) (info->stream, "%s", flg_operand->name);
}
}
@@ -733,7 +803,15 @@ arc_opcode_to_insn_type (const struct arc_opcode *opcode)
switch (opcode->insn_class)
{
case BRANCH:
+ case BBIT0:
+ case BBIT1:
+ case BI:
+ case BIH:
+ case BRCC:
+ case EI:
+ case JLI:
case JUMP:
+ case LOOP:
if (!strncmp (opcode->name, "bl", 2)
|| !strncmp (opcode->name, "jl", 2))
{
@@ -753,8 +831,14 @@ arc_opcode_to_insn_type (const struct arc_opcode *opcode)
case LOAD:
case STORE:
case MEMORY:
+ case ENTER:
+ case PUSH:
+ case POP:
insn_type = dis_dref;
break;
+ case LEAVE:
+ insn_type = dis_branch;
+ break;
default:
insn_type = dis_nonbranch;
break;
@@ -783,6 +867,7 @@ print_insn_arc (bfd_vma memaddr,
int value;
struct arc_operand_iterator iter;
Elf_Internal_Ehdr *header = NULL;
+ struct arc_disassemble_info *arc_infop;
if (info->disassembler_options)
{
@@ -792,6 +877,9 @@ print_insn_arc (bfd_vma memaddr,
info->disassembler_options = NULL;
}
+ if (info->private_data == NULL && !init_arc_disasm_info (info))
+ return -1;
+
memset (&iter, 0, sizeof (iter));
highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
@@ -813,7 +901,7 @@ print_insn_arc (bfd_vma memaddr,
default:
isa_mask = ARC_OPCODE_ARCv2EM;
/* TODO: Perhaps remove defitinion of header since it is only used at
- this location. */
+ this location. */
if (header != NULL
&& (header->e_flags & EF_ARC_MACH_MSK) == EF_ARC_CPU_ARCV2HS)
{
@@ -899,6 +987,8 @@ print_insn_arc (bfd_vma memaddr,
insn_len = arc_insn_length (buffer[highbyte], buffer[lowbyte], info);
pr_debug ("instruction length = %d bytes\n", insn_len);
+ arc_infop = info->private_data;
+ arc_infop->insn_len = insn_len;
switch (insn_len)
{
@@ -957,7 +1047,7 @@ print_insn_arc (bfd_vma memaddr,
/* Set some defaults for the insn info. */
info->insn_info_valid = 1;
info->branch_delay_insns = 0;
- info->data_size = 0;
+ info->data_size = 4;
info->insn_type = dis_nonbranch;
info->target = 0;
info->target2 = 0;
@@ -1016,6 +1106,7 @@ print_insn_arc (bfd_vma memaddr,
need_comma = FALSE;
open_braket = FALSE;
+ arc_infop->operands_count = 0;
/* Now extract and print the operands. */
operand = NULL;
@@ -1034,14 +1125,14 @@ print_insn_arc (bfd_vma memaddr,
if ((operand->flags & ARC_OPERAND_IGNORE)
&& (operand->flags & ARC_OPERAND_IR)
- && value == -1)
+ && value == -1)
continue;
if (operand->flags & ARC_OPERAND_COLON)
- {
- (*info->fprintf_func) (info->stream, ":");
- continue;
- }
+ {
+ (*info->fprintf_func) (info->stream, ":");
+ continue;
+ }
if (need_comma)
(*info->fprintf_func) (info->stream, ",");
@@ -1106,12 +1197,12 @@ print_insn_arc (bfd_vma memaddr,
(*info->fprintf_func) (info->stream, "%d", value);
}
else if (operand->flags & ARC_OPERAND_ADDRTYPE)
- {
- const char *addrtype = get_addrtype (value);
- (*info->fprintf_func) (info->stream, "%s", addrtype);
- /* A colon follow an address type. */
- need_comma = FALSE;
- }
+ {
+ const char *addrtype = get_addrtype (value);
+ (*info->fprintf_func) (info->stream, "%s", addrtype);
+ /* A colon follow an address type. */
+ need_comma = FALSE;
+ }
else
{
if (operand->flags & ARC_OPERAND_TRUNCATE
@@ -1129,6 +1220,24 @@ print_insn_arc (bfd_vma memaddr,
(*info->fprintf_func) (info->stream, "%#x", value);
}
}
+
+ if (operand->flags & ARC_OPERAND_LIMM)
+ {
+ arc_infop->operands[arc_infop->operands_count].kind
+ = ARC_OPERAND_KIND_LIMM;
+ /* It is not important to have exactly the LIMM indicator
+ here. */
+ arc_infop->operands[arc_infop->operands_count].value = 63;
+ }
+ else
+ {
+ arc_infop->operands[arc_infop->operands_count].value = value;
+ arc_infop->operands[arc_infop->operands_count].kind
+ = (operand->flags & ARC_OPERAND_IR
+ ? ARC_OPERAND_KIND_REG
+ : ARC_OPERAND_KIND_SHIMM);
+ }
+ arc_infop->operands_count ++;
}
return insn_len;
@@ -1152,30 +1261,6 @@ arc_get_disassembler (bfd *abfd)
return print_insn_arc;
}
-/* Disassemble ARC instructions. Used by debugger. */
-
-struct arcDisState
-arcAnalyzeInstr (bfd_vma memaddr,
- struct disassemble_info *info)
-{
- struct arcDisState ret;
- memset (&ret, 0, sizeof (struct arcDisState));
-
- ret.instructionLen = print_insn_arc (memaddr, info);
-
-#if 0
- ret.words[0] = insn[0];
- ret.words[1] = insn[1];
- ret._this = &ret;
- ret.coreRegName = _coreRegName;
- ret.auxRegName = _auxRegName;
- ret.condCodeName = _condCodeName;
- ret.instName = _instName;
-#endif
-
- return ret;
-}
-
void
print_arc_disassembler_options (FILE *stream)
{
@@ -1199,6 +1284,58 @@ with -M switch (multiple options should be separated by commas):\n"));
fpud Recognize double precision FPU instructions.\n"));
}
+void arc_insn_decode (bfd_vma addr,
+ struct disassemble_info *info,
+ disassembler_ftype disasm_func,
+ struct arc_instruction *insn)
+{
+ const struct arc_opcode *opcode;
+ struct arc_disassemble_info *arc_infop;
+
+ /* Ensure that insn would be in the reset state. */
+ memset (insn, 0, sizeof (struct arc_instruction));
+
+ /* There was an error when disassembling, for example memory read error. */
+ if (disasm_func (addr, info) < 0)
+ {
+ insn->valid = FALSE;
+ return;
+ }
+
+ assert (info->private_data != NULL);
+ arc_infop = info->private_data;
+
+ insn->length = arc_infop->insn_len;;
+ insn->address = addr;
+
+ /* Quick exit if memory at this address is not an instruction. */
+ if (info->insn_type == dis_noninsn)
+ {
+ insn->valid = FALSE;
+ return;
+ }
+
+ insn->valid = TRUE;
+
+ opcode = (const struct arc_opcode *) arc_infop->opcode;
+ insn->insn_class = opcode->insn_class;
+ insn->limm_value = arc_infop->limm;
+ insn->limm_p = arc_infop->limm_p;
+
+ insn->is_control_flow = (info->insn_type == dis_branch
+ || info->insn_type == dis_condbranch
+ || info->insn_type == dis_jsr
+ || info->insn_type == dis_condjsr);
+
+ insn->has_delay_slot = info->branch_delay_insns;
+ insn->writeback_mode
+ = (enum arc_ldst_writeback_mode) arc_infop->writeback_mode;
+ insn->data_size_mode = info->data_size;
+ insn->condition_code = arc_infop->condition_code;
+ memcpy (insn->operands, arc_infop->operands,
+ sizeof (struct arc_insn_operand) * MAX_INSN_ARGS);
+ insn->operands_count = arc_infop->operands_count;
+}
/* Local variables:
eval: (c-set-style "gnu")