aboutsummaryrefslogtreecommitdiff
path: root/opcodes/arc-ext.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/arc-ext.c')
-rw-r--r--opcodes/arc-ext.c306
1 files changed, 287 insertions, 19 deletions
diff --git a/opcodes/arc-ext.c b/opcodes/arc-ext.c
index 52f4556..45734a0 100644
--- a/opcodes/arc-ext.c
+++ b/opcodes/arc-ext.c
@@ -27,7 +27,6 @@
#include "elf/arc.h"
#include "libiberty.h"
-
/* This module provides support for extensions to the ARC processor
architecture. */
@@ -52,15 +51,6 @@
/* These types define the information stored in the table. */
-struct ExtInstruction
-{
- char major;
- char minor;
- char flags;
- char* name;
- struct ExtInstruction* next;
-};
-
struct ExtAuxRegister
{
long address;
@@ -141,6 +131,9 @@ create_map (unsigned char *block,
insn->minor = minor;
insn->flags = p[4];
insn->next = *bucket;
+ insn->suffix = 0;
+ insn->syntax = 0;
+ insn->modsyn = 0;
*bucket = insn;
break;
}
@@ -285,10 +278,8 @@ ExtReadWrite_image (enum ExtReadWrite val)
/* Get the name of an extension instruction. */
-const char *
-arcExtMap_instName (int opcode,
- int insn,
- int *flags)
+const extInstruction_t *
+arcExtMap_insn (int opcode, int insn)
{
/* Here the following tasks need to be done. First of all, the
opcode stored in the Extension Map is the real opcode. However,
@@ -306,7 +297,7 @@ arcExtMap_instName (int opcode,
then un-mangle using iiiiiI else iiiiii. */
unsigned char minor;
- struct ExtInstruction *temp;
+ extInstruction_t *temp;
/* 16-bit instructions. */
if (0x08 <= opcode && opcode <= 0x0b)
@@ -367,8 +358,7 @@ arcExtMap_instName (int opcode,
{
if ((temp->major == opcode) && (temp->minor == minor))
{
- *flags = temp->flags;
- return temp->name;
+ return temp;
}
temp = temp->next;
}
@@ -459,6 +449,8 @@ build_ARC_extmap (bfd *text_bfd)
}
}
+/* Debug function used to dump the ARC information fount in arcextmap
+ sections. */
void
dump_ARC_extmap (void)
@@ -480,8 +472,20 @@ dump_ARC_extmap (void)
for (insn = arc_extension_map.instructions[i];
insn != NULL; insn = insn->next)
- printf ("INST: %d %d %x %s\n", insn->major, insn->minor,
- insn->flags, insn->name);
+ {
+ printf ("INST: 0x%02x 0x%02x ", insn->major, insn->minor);
+ if (insn->flags & ARC_SYNTAX_2OP)
+ printf ("SYNTAX_2OP");
+ else if (insn->flags & ARC_SYNTAX_3OP)
+ printf ("SYNTAX_3OP");
+ else
+ printf ("SYNTAX_UNK");
+
+ if (insn->flags & 0x10)
+ printf ("|MODIFIER");
+
+ printf (" %s\n", insn->name);
+ }
}
for (i = 0; i < NUM_EXT_CORE; i++)
@@ -497,3 +501,267 @@ dump_ARC_extmap (void)
if (arc_extension_map.condCodes[i])
printf ("COND: %s\n", arc_extension_map.condCodes[i]);
}
+
+/* For a given extension instruction generate the equivalent arc
+ opcode structure. */
+
+struct arc_opcode *
+arcExtMap_genOpcode (const extInstruction_t *einsn,
+ unsigned arc_target,
+ const char **errmsg)
+{
+ struct arc_opcode *q, *arc_ext_opcodes = NULL;
+ const unsigned char *lflags_f;
+ const unsigned char *lflags_ccf;
+ int count;
+
+ /* Check for the class to see how many instructions we generate. */
+ switch (einsn->flags & (ARC_SYNTAX_3OP | ARC_SYNTAX_2OP))
+ {
+ case ARC_SYNTAX_3OP:
+ count = (einsn->modsyn & ARC_OP1_MUST_BE_IMM) ? 10 : 20;
+ break;
+ case ARC_SYNTAX_2OP:
+ count = (einsn->flags & 0x10) ? 7 : 6;
+ break;
+ default:
+ count = 0;
+ break;
+ }
+
+ /* Allocate memory. */
+ arc_ext_opcodes = (struct arc_opcode *)
+ xmalloc ((count + 1) * sizeof (*arc_ext_opcodes));
+
+ if (arc_ext_opcodes == NULL)
+ {
+ *errmsg = "Virtual memory exhausted";
+ return NULL;
+ }
+
+ /* Generate the patterns. */
+ q = arc_ext_opcodes;
+
+ if (einsn->suffix)
+ {
+ lflags_f = flags_none;
+ lflags_ccf = flags_none;
+ }
+ else
+ {
+ lflags_f = flags_f;
+ lflags_ccf = flags_ccf;
+ }
+
+ if (einsn->suffix & ARC_SUFFIX_COND)
+ lflags_ccf = flags_cc;
+ if (einsn->suffix & ARC_SUFFIX_FLAG)
+ {
+ lflags_f = flags_f;
+ lflags_ccf = flags_f;
+ }
+ if (einsn->suffix & (ARC_SUFFIX_FLAG | ARC_SUFFIX_COND))
+ lflags_ccf = flags_ccf;
+
+ if (einsn->flags & ARC_SYNTAX_2OP
+ && !(einsn->flags & 0x10))
+ {
+ /* Regular 2OP instruction. */
+ if (einsn->suffix & ARC_SUFFIX_COND)
+ *errmsg = "Suffix SUFFIX_COND ignored";
+
+ INSERT_XOP (q, einsn->name,
+ INSN2OP_BC (einsn->major, einsn->minor), MINSN2OP_BC,
+ arc_target, arg_32bit_rbrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN2OP_0C (einsn->major, einsn->minor), MINSN2OP_0C,
+ arc_target, arg_32bit_zarc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN2OP_BU (einsn->major, einsn->minor), MINSN2OP_BU,
+ arc_target, arg_32bit_rbu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN2OP_0U (einsn->major, einsn->minor), MINSN2OP_0U,
+ arc_target, arg_32bit_zau6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN2OP_BL (einsn->major, einsn->minor), MINSN2OP_BL,
+ arc_target, arg_32bit_rblimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN2OP_0L (einsn->major, einsn->minor), MINSN2OP_0L,
+ arc_target, arg_32bit_zalimm, lflags_f);
+ }
+ else if (einsn->flags & (0x10 | ARC_SYNTAX_2OP))
+ {
+ /* This is actually a 3OP pattern. The first operand is
+ immplied and is set to zero. */
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BC (einsn->major, einsn->minor), MINSN3OP_0BC,
+ arc_target, arg_32bit_rbrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BU (einsn->major, einsn->minor), MINSN3OP_0BU,
+ arc_target, arg_32bit_rbu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BL (einsn->major, einsn->minor), MINSN3OP_0BL,
+ arc_target, arg_32bit_rblimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
+ arc_target, arg_32bit_limmrc, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
+ arc_target, arg_32bit_limmu6, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LS (einsn->major, einsn->minor), MINSN3OP_0LS,
+ arc_target, arg_32bit_limms12, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
+ arc_target, arg_32bit_limmlimm, lflags_ccf);
+ }
+ else if (einsn->flags & ARC_SYNTAX_3OP
+ && !(einsn->modsyn & ARC_OP1_MUST_BE_IMM))
+ {
+ /* Regular 3OP instruction. */
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_ABC (einsn->major, einsn->minor), MINSN3OP_ABC,
+ arc_target, arg_32bit_rarbrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BC (einsn->major, einsn->minor), MINSN3OP_0BC,
+ arc_target, arg_32bit_zarbrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_CBBC (einsn->major, einsn->minor), MINSN3OP_CBBC,
+ arc_target, arg_32bit_rbrbrc, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_ABU (einsn->major, einsn->minor), MINSN3OP_ABU,
+ arc_target, arg_32bit_rarbu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BU (einsn->major, einsn->minor), MINSN3OP_0BU,
+ arc_target, arg_32bit_zarbu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_CBBU (einsn->major, einsn->minor), MINSN3OP_CBBU,
+ arc_target, arg_32bit_rbrbu6, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_BBS (einsn->major, einsn->minor), MINSN3OP_BBS,
+ arc_target, arg_32bit_rbrbs12, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_ALC (einsn->major, einsn->minor), MINSN3OP_ALC,
+ arc_target, arg_32bit_ralimmrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_ABL (einsn->major, einsn->minor), MINSN3OP_ABL,
+ arc_target, arg_32bit_rarblimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LC (einsn->major, einsn->minor), MINSN3OP_0LC,
+ arc_target, arg_32bit_zalimmrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BL (einsn->major, einsn->minor), MINSN3OP_0BL,
+ arc_target, arg_32bit_zarblimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
+ arc_target, arg_32bit_zalimmrc, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_CBBL (einsn->major, einsn->minor), MINSN3OP_CBBL,
+ arc_target, arg_32bit_rbrblimm, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_ALU (einsn->major, einsn->minor), MINSN3OP_ALU,
+ arc_target, arg_32bit_ralimmu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LU (einsn->major, einsn->minor), MINSN3OP_0LU,
+ arc_target, arg_32bit_zalimmu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
+ arc_target, arg_32bit_zalimmu6, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LS (einsn->major, einsn->minor), MINSN3OP_0LS,
+ arc_target, arg_32bit_zalimms12, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_ALL (einsn->major, einsn->minor), MINSN3OP_ALL,
+ arc_target, arg_32bit_ralimmlimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LL (einsn->major, einsn->minor), MINSN3OP_0LL,
+ arc_target, arg_32bit_zalimmlimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
+ arc_target, arg_32bit_zalimmlimm, lflags_ccf);
+ }
+ else if (einsn->flags & ARC_SYNTAX_3OP)
+ {
+ /* 3OP instruction which accepts only zero as first
+ argument. */
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BC (einsn->major, einsn->minor), MINSN3OP_0BC,
+ arc_target, arg_32bit_zarbrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BU (einsn->major, einsn->minor), MINSN3OP_0BU,
+ arc_target, arg_32bit_zarbu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LC (einsn->major, einsn->minor), MINSN3OP_0LC,
+ arc_target, arg_32bit_zalimmrc, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0BL (einsn->major, einsn->minor), MINSN3OP_0BL,
+ arc_target, arg_32bit_zarblimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LC (einsn->major, einsn->minor), MINSN3OP_C0LC,
+ arc_target, arg_32bit_zalimmrc, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LU (einsn->major, einsn->minor), MINSN3OP_0LU,
+ arc_target, arg_32bit_zalimmu6, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LU (einsn->major, einsn->minor), MINSN3OP_C0LU,
+ arc_target, arg_32bit_zalimmu6, lflags_ccf);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LS (einsn->major, einsn->minor), MINSN3OP_0LS,
+ arc_target, arg_32bit_zalimms12, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_0LL (einsn->major, einsn->minor), MINSN3OP_0LL,
+ arc_target, arg_32bit_zalimmlimm, lflags_f);
+
+ INSERT_XOP (q, einsn->name,
+ INSN3OP_C0LL (einsn->major, einsn->minor), MINSN3OP_C0LL,
+ arc_target, arg_32bit_zalimmlimm, lflags_ccf);
+ }
+ else
+ {
+ *errmsg = "Unknown syntax";
+ return NULL;
+ }
+
+ /* End marker. */
+ memset (q, 0, sizeof (*arc_ext_opcodes));
+
+ return arc_ext_opcodes;
+}