Add support for 48 and 64 bit ARC instructions.

gas	* config/tc-arc.c (parse_opcode_flags): New function.
	(find_opcode_match): Move flag parsing code out to new function.
	Ignore operands marked IGNORE.
	(build_fake_opcode_hash_entry): New function.
	(find_special_case_long_opcode): New function.
	(find_special_case): Lookup long opcodes.
	* testsuite/gas/arc/nps400-7.d: New file.
	* testsuite/gas/arc/nps400-7.s: New file.

include	* opcode/arc.h (MAX_INSN_ARGS): Increase to 16.
	(struct arc_long_opcode): New structure.
	(arc_long_opcodes): Declare.
	(arc_num_long_opcodes): Declare.

opcodes	* arc-dis.c (struct arc_operand_iterator): New structure.
	(find_format_from_table): All the old content from find_format,
	with some minor adjustments, and parameter renaming.
	(find_format_long_instructions): New function.
	(find_format): Rewritten.
	(arc_insn_length): Add LSB parameter.
	(extract_operand_value): New function.
	(operand_iterator_next): New function.
	(print_insn_arc): Use new functions to find opcode, and iterator
	over operands.
	* arc-opc.c (insert_nps_3bit_dst_short): New function.
	(extract_nps_3bit_dst_short): New function.
	(insert_nps_3bit_src2_short): New function.
	(extract_nps_3bit_src2_short): New function.
	(insert_nps_bitop1_size): New function.
	(extract_nps_bitop1_size): New function.
	(insert_nps_bitop2_size): New function.
	(extract_nps_bitop2_size): New function.
	(insert_nps_bitop_mod4_msb): New function.
	(extract_nps_bitop_mod4_msb): New function.
	(insert_nps_bitop_mod4_lsb): New function.
	(extract_nps_bitop_mod4_lsb): New function.
	(insert_nps_bitop_dst_pos3_pos4): New function.
	(extract_nps_bitop_dst_pos3_pos4): New function.
	(insert_nps_bitop_ins_ext): New function.
	(extract_nps_bitop_ins_ext): New function.
	(arc_operands): Add new operands.
	(arc_long_opcodes): New global array.
	(arc_num_long_opcodes): New global.
	* arc-nps400-tbl.h: Add comments referencing arc_long_opcodes.
This commit is contained in:
Andrew Burgess 2016-06-02 14:03:23 +01:00 committed by Nick Clifton
parent 5b6312fd20
commit 4eb6f89250
10 changed files with 1030 additions and 163 deletions

View File

@ -1,3 +1,14 @@
2016-06-02 Andrew Burgess <andrew.burgess@embecosm.com>
* config/tc-arc.c (parse_opcode_flags): New function.
(find_opcode_match): Move flag parsing code out to new function.
Ignore operands marked IGNORE.
(build_fake_opcode_hash_entry): New function.
(find_special_case_long_opcode): New function.
(find_special_case): Lookup long opcodes.
* testsuite/gas/arc/nps400-7.d: New file.
* testsuite/gas/arc/nps400-7.s: New file.
2016-06-01 Trevor Saunders <tbsaunde+binutils@tbsaunde.org>
* config/tc-ns32k.c: Remove definition of input_line_pointer.

View File

@ -1548,6 +1548,90 @@ check_cpu_feature (insn_subclass_t sc)
return TRUE;
}
/* Parse the flags described by FIRST_PFLAG and NFLGS against the flag
operands in OPCODE. Stores the matching OPCODES into the FIRST_PFLAG
array and returns TRUE if the flag operands all match, otherwise,
returns FALSE, in which case the FIRST_PFLAG array may have been
modified. */
static bfd_boolean
parse_opcode_flags (const struct arc_opcode *opcode,
int nflgs,
struct arc_flags *first_pflag)
{
int lnflg, i;
const unsigned char *flgidx;
lnflg = nflgs;
for (i = 0; i < nflgs; i++)
first_pflag[i].flgp = NULL;
/* Check the flags. Iterate over the valid flag classes. */
for (flgidx = opcode->flags; *flgidx; ++flgidx)
{
/* Get a valid flag class. */
const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
const unsigned *flgopridx;
int cl_matches = 0;
struct arc_flags *pflag = NULL;
/* Check for extension conditional codes. */
if (ext_condcode.arc_ext_condcode
&& cl_flags->flag_class & F_CLASS_EXTEND)
{
struct arc_flag_operand *pf = ext_condcode.arc_ext_condcode;
while (pf->name)
{
pflag = first_pflag;
for (i = 0; i < nflgs; i++, pflag++)
{
if (!strcmp (pf->name, pflag->name))
{
if (pflag->flgp != NULL)
return FALSE;
/* Found it. */
cl_matches++;
pflag->flgp = pf;
lnflg--;
break;
}
}
pf++;
}
}
for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
{
const struct arc_flag_operand *flg_operand;
pflag = first_pflag;
flg_operand = &arc_flag_operands[*flgopridx];
for (i = 0; i < nflgs; i++, pflag++)
{
/* Match against the parsed flags. */
if (!strcmp (flg_operand->name, pflag->name))
{
if (pflag->flgp != NULL)
return FALSE;
cl_matches++;
pflag->flgp = flg_operand;
lnflg--;
break; /* goto next flag class and parsed flag. */
}
}
}
if ((cl_flags->flag_class & F_CLASS_REQUIRED) && cl_matches == 0)
return FALSE;
if ((cl_flags->flag_class & F_CLASS_OPTIONAL) && cl_matches > 1)
return FALSE;
}
/* Did I check all the parsed flags? */
return lnflg ? FALSE : TRUE;
}
/* Search forward through all variants of an opcode looking for a
syntax match. */
@ -1577,8 +1661,7 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
opcode = arc_opcode_hash_entry_iterator_next (entry, &iter))
{
const unsigned char *opidx;
const unsigned char *flgidx;
int tokidx = 0, lnflg, i;
int tokidx = 0;
const expressionS *t = &emptyE;
pr_debug ("%s:%d: find_opcode_match: trying opcode 0x%08X ",
@ -1754,7 +1837,7 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
if (errmsg)
goto match_failed;
}
else
else if (!(operand->flags & ARC_OPERAND_IGNORE))
goto match_failed;
}
break;
@ -1831,72 +1914,7 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry,
pr_debug ("opr ");
/* Setup ready for flag parsing. */
lnflg = nflgs;
for (i = 0; i < nflgs; i++)
first_pflag[i].flgp = NULL;
/* Check the flags. Iterate over the valid flag classes. */
for (flgidx = opcode->flags; *flgidx; ++flgidx)
{
/* Get a valid flag class. */
const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx];
const unsigned *flgopridx;
int cl_matches = 0;
struct arc_flags *pflag = NULL;
/* Check for extension conditional codes. */
if (ext_condcode.arc_ext_condcode
&& cl_flags->flag_class & F_CLASS_EXTEND)
{
struct arc_flag_operand *pf = ext_condcode.arc_ext_condcode;
while (pf->name)
{
pflag = first_pflag;
for (i = 0; i < nflgs; i++, pflag++)
{
if (!strcmp (pf->name, pflag->name))
{
if (pflag->flgp != NULL)
goto match_failed;
/* Found it. */
cl_matches++;
pflag->flgp = pf;
lnflg--;
break;
}
}
pf++;
}
}
for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx)
{
const struct arc_flag_operand *flg_operand;
pflag = first_pflag;
flg_operand = &arc_flag_operands[*flgopridx];
for (i = 0; i < nflgs; i++, pflag++)
{
/* Match against the parsed flags. */
if (!strcmp (flg_operand->name, pflag->name))
{
if (pflag->flgp != NULL)
goto match_failed;
cl_matches++;
pflag->flgp = flg_operand;
lnflg--;
break; /* goto next flag class and parsed flag. */
}
}
}
if ((cl_flags->flag_class & F_CLASS_REQUIRED) && cl_matches == 0)
goto match_failed;
if ((cl_flags->flag_class & F_CLASS_OPTIONAL) && cl_matches > 1)
goto match_failed;
}
/* Did I check all the parsed flags? */
if (lnflg)
if (!parse_opcode_flags (opcode, nflgs, first_pflag))
goto match_failed;
pr_debug ("flg");
@ -2179,6 +2197,108 @@ find_special_case_flag (const char *opname,
return NULL;
}
/* The long instructions are not stored in a hash (there's not many of
them) and so there's no arc_opcode_hash_entry structure to return. This
helper function for find_special_case_long_opcode takes an arc_opcode
result and places it into a fake arc_opcode_hash_entry that points to
the single arc_opcode OPCODE, which is then returned. */
static const struct arc_opcode_hash_entry *
build_fake_opcode_hash_entry (const struct arc_opcode *opcode)
{
static struct arc_opcode_hash_entry entry;
static struct arc_opcode tmp[2];
static const struct arc_opcode *ptr[2];
memcpy (&tmp[0], opcode, sizeof (struct arc_opcode));
memset (&tmp[1], 0, sizeof (struct arc_opcode));
entry.count = 1;
entry.opcode = ptr;
ptr[0] = tmp;
ptr[1] = NULL;
return &entry;
}
/* Used by the assembler to match the list of tokens against a long (48 or
64 bits) instruction. If a matching long instruction is found, then
some of the tokens are consumed in this function and converted into a
single LIMM value, which is then added to the end of the token list,
where it will be consumed by a LIMM operand that exists in the base
opcode of the long instruction. */
static const struct arc_opcode_hash_entry *
find_special_case_long_opcode (const char *opname,
int *ntok ATTRIBUTE_UNUSED,
expressionS *tok ATTRIBUTE_UNUSED,
int *nflgs,
struct arc_flags *pflags)
{
unsigned i;
if (*ntok == MAX_INSN_ARGS)
return NULL;
for (i = 0; i < arc_num_long_opcodes; ++i)
{
struct arc_opcode fake_opcode;
const struct arc_opcode *opcode;
struct arc_insn insn;
expressionS *limm_token;
opcode = &arc_long_opcodes[i].base_opcode;
if (!(opcode->cpu & arc_target))
continue;
if (!check_cpu_feature (opcode->subclass))
continue;
if (strcmp (opname, opcode->name) != 0)
continue;
/* Check that the flags are a match. */
if (!parse_opcode_flags (opcode, *nflgs, pflags))
continue;
/* Parse the LIMM operands into the LIMM template. */
memset (&fake_opcode, 0, sizeof (fake_opcode));
fake_opcode.name = "fake limm";
fake_opcode.opcode = arc_long_opcodes[i].limm_template;
fake_opcode.mask = arc_long_opcodes[i].limm_mask;
fake_opcode.cpu = opcode->cpu;
fake_opcode.insn_class = opcode->insn_class;
fake_opcode.subclass = opcode->subclass;
memcpy (&fake_opcode.operands[0],
&arc_long_opcodes[i].operands,
MAX_INSN_ARGS);
/* Leave fake_opcode.flags as zero. */
pr_debug ("Calling assemble_insn to build fake limm value\n");
assemble_insn (&fake_opcode, tok, *ntok,
NULL, 0, &insn);
pr_debug (" got limm value: 0x%x\n", insn.insn);
/* Now create a new token at the end of the token array (We know this
is safe as the token array is always created with enough space for
MAX_INSN_ARGS, and we check at the start at the start of this
function that we're not there yet). This new token will
correspond to a LIMM operand that will be contained in the
base_opcode of the arc_long_opcode. */
limm_token = &tok[(*ntok)];
(*ntok)++;
/* Modify the LIMM token to hold the constant. */
limm_token->X_op = O_constant;
limm_token->X_add_number = insn.insn;
/* Return the base opcode. */
return build_fake_opcode_hash_entry (opcode);
}
return NULL;
}
/* Used to find special case opcode. */
static const struct arc_opcode_hash_entry *
@ -2195,6 +2315,9 @@ find_special_case (const char *opname,
if (entry == NULL)
entry = find_special_case_flag (opname, nflgs, pflags);
if (entry == NULL)
entry = find_special_case_long_opcode (opname, ntok, tok, nflgs, pflags);
return entry;
}

View File

@ -0,0 +1,32 @@
#as: -mcpu=nps400
#objdump: -dr
.*: +file format .*arc.*
Disassembly of section .text:
[0-9a-f]+ <.*>:
0: 5823 0224 10c5 mrgb r0,r0,r1,0x4,0x5,0x3,0x8,0x6,0x2
6: 5a23 8224 10c5 mrgb.cl r2,r2,r1,0x4,0x5,0x3,0x8,0x6,0x2
c: 5940 0e04 10c2 mov2b r1,r1,r2,0x4,0x3,0x2,0x8,0x1,0x6
12: 5940 8e04 10c2 mov2b.cl r1,r2,0x4,0x3,0x2,0x8,0x1,0x6
18: 5b81 01cf f945 ext4b r3,r3,r12,0x1c,0x5,0xa,0x1e,0x1f
1e: 5aa1 81cf f945 ext4b.cl r2,r13,0x1c,0x5,0xa,0x1e,0x1f
24: 5b82 01cf f945 ins4b r3,r3,r12,0x5,0xa,0x1e,0x1f,0x1c
2a: 5aa2 81cf f945 ins4b.cl r2,r13,0x5,0xa,0x1e,0x1f,0x1c
30: 5e90 5280 d953 8446 mov3b r14,r14,r12,0x1,0,0x6,0x7,0x3,0x2,0x14,0x2,0x15
38: 5990 0c60 e281 9201 mov3b r1,r1,r12,0x4,0x1,0x1,0x3,0,0x10,0x3,0x3,0x8
40: 5e90 39c0 8c34 204e mov3b r14,r14,r12,0x8,0x2,0xe,0x8,0x1,0x2,0xe,0,0x3
48: 5990 14a0 b621 b1a1 mov3b r1,r1,r12,0xc,0x3,0x1,0x3,0x2,0xd,0x5,0x1,0x2
50: 5831 3180 e800 0421 mov3bcl r0,r1,0x1,0,0x1,0,0x1,0x1,0xc,0x3,0
58: 5831 7fe0 d23b 0845 mov3bcl r0,r1,0x2,0x1,0x5,0x16,0x2,0x2,0x1f,0x2,0x3
60: 5831 7bc0 bdfb 8cc9 mov3bcl r0,r1,0x3,0x2,0x9,0x17,0x3,0x6,0x1e,0x1,0x1f
68: 5831 7bc0 87ec 13cb mov3bcl r0,r1,0x4,0x3,0xb,0x18,0,0x1e,0x1e,0,0x1e
70: 58d0 38c3 3671 2814 mov4b r0,r0,r14,0xa,0x3,0x14,0x2,0x2,0,0x6,0x1,0x7,0xe,0,0x3
78: 58d0 e3e2 58b6 048b mov4b r0,r0,r14,0x1,0,0xb,0xc,0x3,0x4,0x1f,0x2,0xb,0x18,0x1,0x2
80: 58d0 2068 e3fa 97c8 mov4b r0,r0,r14,0x5,0x1,0x8,0x15,0,0x1e,0x3,0x3,0x1f,0x8,0x2,0x8
88: 58d0 91a4 8deb 3ecd mov4b r0,r0,r14,0xf,0x2,0xd,0x16,0x1,0x16,0xd,0,0x1e,0x4,0x3,0x4
90: 5cb1 1064 7231 0441 mov4bcl r12,r13,0x1,0x1,0x1,0x2,0x2,0x2,0x3,0x3,0x3,0x4,0,0x4
98: 5dd1 9064 1c31 0441 mov4bcl r13,r14,0x1,0x2,0x1,0x2,0x3,0x2,0x3,0,0x3,0x4,0x1,0x4
a0: 5a71 1064 a631 0441 mov4bcl r2,r3,0x1,0x3,0x1,0x2,0,0x2,0x3,0x1,0x3,0x4,0x2,0x4
a8: 5951 9064 c831 0441 mov4bcl r1,r2,0x1,0,0x1,0x2,0x1,0x2,0x3,0x2,0x3,0x4,0x3,0x4

View File

@ -0,0 +1,41 @@
.text
;; mrgb
mrgb r0,r0,r1,4,5,3,8,6,2
mrgb.cl r2,r2,r1,4,5,3,8,6,2
;; mov2b
mov2b r1,r1,r2,4,3,2,8,1,6
mov2b.cl r1,r2,4,3,2,8,1,6
;; ext4b
ext4b r3,r3,r12,28,5,10,30,31
ext4b.cl r2,r13,28,5,10,30,31
;; ins4b
ins4b r3,r3,r12,5,10,30,31,28
ins4b.cl r2,r13,5,10,30,31,28
;; mov3b
mov3b r14,r14,r12, 1,0,6, 7,3,2, 20,2,21
mov3b r1,r1,r12, 4,1,1, 3,0,16, 3,3,8
mov3b r14,r14,r12, 8,2,14, 8,1,2, 14,0,3
mov3b r1,r1,r12, 12,3,1, 3,2,13, 5,1,2
;; mov3bcl
mov3bcl r0,r1, 1,0,1, 0,1,1, 12,3,0
mov3b.cl r0,r1, 2,1,5, 22,2,2, 31,2,3
mov3bcl r0,r1, 3,2,9, 23,3,6, 30,1,31
mov3b.cl r0,r1, 4,3,11, 24,0,30, 30,0,30
;; mov4b
mov4b r0,r0,r14, 10,3,20, 2,2,0, 6,1,7, 14,0,3
mov4b r0,r0,r14, 1,0,11, 12,3,4, 31,2,11, 24,1,2
mov4b r0,r0,r14, 5,1,8, 21,0,30, 3,3,31, 8,2,8
mov4b r0,r0,r14, 15,2,13, 22,1,22, 13,0,30, 4,3,4
;; mov4bl
mov4bcl r12,r13,1,1,1,2,2,2,3,3,3,4,0,4
mov4b.cl r13,r14,1,2,1,2,3,2,3,0,3,4,1,4
mov4bcl r2,r3, 1,3,1,2,0,2,3,1,3,4,2,4
mov4b.cl r1,r2, 1,0,1,2,1,2,3,2,3,4,3,4

View File

@ -1,3 +1,10 @@
2016-06-02 Andrew Burgess <andrew.burgess@embecosm.com>
* opcode/arc.h (MAX_INSN_ARGS): Increase to 16.
(struct arc_long_opcode): New structure.
(arc_long_opcodes): Declare.
(arc_num_long_opcodes): Declare.
2016-06-01 Trevor Saunders <tbsaunde+binutils@tbsaunde.org>
* elf/mips.h: Add extern "C".

View File

@ -25,7 +25,7 @@
#define OPCODE_ARC_H
#ifndef MAX_INSN_ARGS
#define MAX_INSN_ARGS 8
#define MAX_INSN_ARGS 16
#endif
#ifndef MAX_INSN_FLGS
@ -136,6 +136,30 @@ struct arc_opcode
unsigned char flags[MAX_INSN_FLGS + 1];
};
/* Structure used to describe 48 and 64 bit instructions. */
struct arc_long_opcode
{
/* The base instruction is either 16 or 32 bits, and is described like a
normal instruction. */
struct arc_opcode base_opcode;
/* The template value for the 32-bit LIMM extension. Used by the
assembler and disassembler in the same way as the 'opcode' field of
'struct arc_opcode'. */
unsigned limm_template;
/* The mask value for the 32-bit LIMM extension. Used by the
disassembler just like the 'mask' field in 'struct arc_opcode'. */
unsigned limm_mask;
/* Array of operand codes similar to the 'operands' array in 'struct
arc_opcode'. These operands are used to fill in the LIMM value. */
unsigned char operands[MAX_INSN_ARGS + 1];
};
extern const struct arc_long_opcode arc_long_opcodes[];
extern const unsigned arc_num_long_opcodes;
/* The table itself is sorted by major opcode number, and is otherwise
in the order in which the disassembler should consider
instructions. */

View File

@ -1,3 +1,36 @@
2016-06-02 Andrew Burgess <andrew.burgess@embecosm.com>
* arc-dis.c (struct arc_operand_iterator): New structure.
(find_format_from_table): All the old content from find_format,
with some minor adjustments, and parameter renaming.
(find_format_long_instructions): New function.
(find_format): Rewritten.
(arc_insn_length): Add LSB parameter.
(extract_operand_value): New function.
(operand_iterator_next): New function.
(print_insn_arc): Use new functions to find opcode, and iterator
over operands.
* arc-opc.c (insert_nps_3bit_dst_short): New function.
(extract_nps_3bit_dst_short): New function.
(insert_nps_3bit_src2_short): New function.
(extract_nps_3bit_src2_short): New function.
(insert_nps_bitop1_size): New function.
(extract_nps_bitop1_size): New function.
(insert_nps_bitop2_size): New function.
(extract_nps_bitop2_size): New function.
(insert_nps_bitop_mod4_msb): New function.
(extract_nps_bitop_mod4_msb): New function.
(insert_nps_bitop_mod4_lsb): New function.
(extract_nps_bitop_mod4_lsb): New function.
(insert_nps_bitop_dst_pos3_pos4): New function.
(extract_nps_bitop_dst_pos3_pos4): New function.
(insert_nps_bitop_ins_ext): New function.
(extract_nps_bitop_ins_ext): New function.
(arc_operands): Add new operands.
(arc_long_opcodes): New global array.
(arc_num_long_opcodes): New global.
* arc-nps400-tbl.h: Add comments referencing arc_long_opcodes.
2016-06-01 Trevor Saunders <tbsaunde+binutils@tbsaunde.org>
* nds32-asm.h: Add extern "C".

View File

@ -28,6 +28,43 @@
#include "arc-dis.h"
#include "arc-ext.h"
/* Structure used to iterate over, and extract the values for, operands of
an opcode. */
struct arc_operand_iterator
{
enum
{
OPERAND_ITERATOR_STANDARD,
OPERAND_ITERATOR_LONG
} mode;
/* The array of 32-bit values that make up this instruction. All
required values have been pre-loaded into this array during the
find_format call. */
unsigned *insn;
union
{
struct
{
/* The opcode this iterator is operating on. */
const struct arc_opcode *opcode;
/* The index into the opcodes operand index list. */
const unsigned char *opidx;
} standard;
struct
{
/* The long instruction opcode this iterator is operating on. */
const struct arc_long_opcode *long_opcode;
/* Two indexes into the opcodes operand index lists. */
const unsigned char *opidx_base, *opidx_limm;
} long_insn;
} state;
};
/* Globals variables. */
@ -102,11 +139,13 @@ special_flag_p (const char *opname,
return 0;
}
/* Find proper format for the given opcode. */
/* Find opcode from ARC_TABLE given the instruction described by INSN and
INSNLEN. The ISA_MASK restricts the possible matches in ARC_TABLE. */
static const struct arc_opcode *
find_format (const struct arc_opcode *arc_table,
unsigned *insn, unsigned int insnLen,
unsigned isa_mask)
find_format_from_table (const struct arc_opcode *arc_table,
unsigned *insn, unsigned int insn_len,
unsigned isa_mask, bfd_boolean *has_limm)
{
unsigned int i = 0;
const struct arc_opcode *opcode = NULL;
@ -118,12 +157,12 @@ find_format (const struct arc_opcode *arc_table,
opcode = &arc_table[i++];
if (ARC_SHORT (opcode->mask) && (insnLen == 2))
if (ARC_SHORT (opcode->mask) && (insn_len == 2))
{
if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
continue;
}
else if (!ARC_SHORT (opcode->mask) && (insnLen == 4))
else if (!ARC_SHORT (opcode->mask) && (insn_len == 4))
{
if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
continue;
@ -137,6 +176,8 @@ find_format (const struct arc_opcode *arc_table,
if (!(opcode->cpu & isa_mask))
continue;
*has_limm = FALSE;
/* Possible candidate, check the operands. */
for (opidx = opcode->operands; *opidx; opidx++)
{
@ -156,13 +197,17 @@ find_format (const struct arc_opcode *arc_table,
if (operand->flags & ARC_OPERAND_IR
&& !(operand->flags & ARC_OPERAND_LIMM))
{
if ((value == 0x3E && insnLen == 4)
|| (value == 0x1E && insnLen == 2))
if ((value == 0x3E && insn_len == 4)
|| (value == 0x1E && insn_len == 2))
{
invalid = TRUE;
break;
}
}
if (operand->flags & ARC_OPERAND_LIMM
&& !(operand->flags & ARC_OPERAND_DUPLICATE))
*has_limm = TRUE;
}
/* Check the flags. */
@ -210,6 +255,184 @@ find_format (const struct arc_opcode *arc_table,
return NULL;
}
/* Find long instructions matching values in INSN array. */
static const struct arc_long_opcode *
find_format_long_instructions (unsigned *insn,
unsigned int *insn_len,
unsigned isa_mask,
bfd_vma memaddr,
struct disassemble_info *info)
{
unsigned int i;
unsigned limm = 0;
bfd_boolean limm_loaded = FALSE;
for (i = 0; i < arc_num_long_opcodes; ++i)
{
bfd_byte buffer[4];
int status;
const struct arc_opcode *opcode;
opcode = &arc_long_opcodes[i].base_opcode;
if (ARC_SHORT (opcode->mask) && (*insn_len == 2))
{
if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0]))
continue;
}
else if (!ARC_SHORT (opcode->mask) && (*insn_len == 4))
{
if (OPCODE (opcode->opcode) != OPCODE (insn[0]))
continue;
}
else
continue;
if ((insn[0] ^ opcode->opcode) & opcode->mask)
continue;
if (!(opcode->cpu & isa_mask))
continue;
if (!limm_loaded)
{
status = (*info->read_memory_func) (memaddr + *insn_len, buffer,
4, info);
if (status != 0)
return NULL;
limm = ARRANGE_ENDIAN (info, buffer);
limm_loaded = TRUE;
}
/* Check the second word using the mask and template. */
if ((limm & arc_long_opcodes[i].limm_mask)
!= arc_long_opcodes[i].limm_template)
continue;
(*insn_len) += 4;
insn[1] = limm;
return &arc_long_opcodes[i];
}
return NULL;
}
/* Find opcode for INSN, trying various different sources. The instruction
length in INSN_LEN will be updated if the instruction requires a LIMM
extension, and the additional values loaded into the INSN array (which
must be big enough).
A pointer to the opcode is placed into OPCODE_RESULT, and ITER is
initialised, ready to iterate over the operands of the found opcode.
This function returns TRUE in almost all cases, FALSE is reserved to
indicate an error (failing to find an opcode is not an error) a
returned result of FALSE would indicate that the disassembler can't
continue.
If no matching opcode is found then the returned result will be TRUE,
the value placed into OPCODE_RESULT will be NULL, ITER will be
undefined, and INSN_LEN will be unchanged.
If a matching opcode is found, then the returned result will be TRUE,
the opcode pointer is placed into OPCODE_RESULT, INSN_LEN will be
increased by 4 if the instruction requires a LIMM, and the LIMM value
will have been loaded into the INSN[1]. Finally, ITER will have been
initialised so that calls to OPERAND_ITERATOR_NEXT will iterate over
the opcode's operands. */
static bfd_boolean
find_format (bfd_vma memaddr, unsigned *insn, unsigned int *insn_len,
unsigned isa_mask, struct disassemble_info *info,
const struct arc_opcode **opcode_result,
struct arc_operand_iterator *iter)
{
const struct arc_opcode *opcode;
bfd_boolean needs_limm;
/* Find the first match in the opcode table. */
opcode = find_format_from_table (arc_opcodes, insn, *insn_len,
isa_mask, &needs_limm);
if (opcode == NULL)
{
const extInstruction_t *einsn;
/* No instruction found. Try the extensions. */
einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
if (einsn != NULL)
{
const char *errmsg = NULL;
opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
if (opcode == NULL)
{
(*info->fprintf_func) (info->stream,
"An error occured while "
"generating the extension instruction "
"operations");
*opcode_result = NULL;
return FALSE;
}
opcode = find_format_from_table (opcode, insn, *insn_len,
isa_mask, &needs_limm);
assert (opcode != NULL);
}
}
if (needs_limm && opcode != NULL)
{
bfd_byte buffer[4];
int status;
status = (*info->read_memory_func) (memaddr + *insn_len, buffer,
4, info);
if (status != 0)
{
opcode = NULL;
}
else
{
insn[1] = ARRANGE_ENDIAN (info, buffer);
*insn_len += 4;
}
}
if (opcode == NULL)
{
const struct arc_long_opcode *long_opcode;
/* No instruction found yet, try the long instructions. */
long_opcode =
find_format_long_instructions (insn, insn_len, isa_mask,
memaddr, info);
if (long_opcode != NULL)
{
iter->mode = OPERAND_ITERATOR_LONG;
iter->insn = insn;
iter->state.long_insn.long_opcode = long_opcode;
iter->state.long_insn.opidx_base =
long_opcode->base_opcode.operands;
iter->state.long_insn.opidx_limm =
long_opcode->operands;
opcode = &long_opcode->base_opcode;
}
}
else
{
iter->mode = OPERAND_ITERATOR_STANDARD;
iter->insn = insn;
iter->state.standard.opcode = opcode;
iter->state.standard.opidx = opcode->operands;
}
*opcode_result = opcode;
return TRUE;
}
static void
print_flags (const struct arc_opcode *opcode,
unsigned *insn,
@ -328,13 +551,20 @@ get_auxreg (const struct arc_opcode *opcode,
cached for later use. */
static unsigned int
arc_insn_length (bfd_byte msb, struct disassemble_info *info)
arc_insn_length (bfd_byte msb, bfd_byte lsb, struct disassemble_info *info)
{
bfd_byte major_opcode = msb >> 3;
switch (info->mach)
{
case bfd_mach_arc_nps400:
if (major_opcode == 0xb)
{
bfd_byte minor_opcode = lsb & 0x1f;
if (minor_opcode < 4)
return 2;
}
case bfd_mach_arc_arc700:
case bfd_mach_arc_arc600:
return (major_opcode > 0xb) ? 2 : 4;
@ -349,6 +579,120 @@ arc_insn_length (bfd_byte msb, struct disassemble_info *info)
}
}
/* Extract and return the value of OPERAND from the instruction whose value
is held in the array INSN. */
static int
extract_operand_value (const struct arc_operand *operand, unsigned *insn)
{
int value;
/* Read the limm operand, if required. */
if (operand->flags & ARC_OPERAND_LIMM)
/* The second part of the instruction value will have been loaded as
part of the find_format call made earlier. */
value = insn[1];
else
{
if (operand->extract)
value = (*operand->extract) (insn[0], (int *) NULL);
else
{
if (operand->flags & ARC_OPERAND_ALIGNED32)
{
value = (insn[0] >> operand->shift)
& ((1 << (operand->bits - 2)) - 1);
value = value << 2;
}
else
{
value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
}
if (operand->flags & ARC_OPERAND_SIGNED)
{
int signbit = 1 << (operand->bits - 1);
value = (value ^ signbit) - signbit;
}
}
}
return value;
}
/* Find the next operand, and the operands value from ITER. Return TRUE if
there is another operand, otherwise return FALSE. If there is an
operand returned then the operand is placed into OPERAND, and the value
into VALUE. If there is no operand returned then OPERAND and VALUE are
unchanged. */
static bfd_boolean
operand_iterator_next (struct arc_operand_iterator *iter,
const struct arc_operand **operand,
int *value)
{
if (iter->mode == OPERAND_ITERATOR_STANDARD)
{
if (*iter->state.standard.opidx == 0)
{
*operand = NULL;
return FALSE;
}
*operand = &arc_operands[*iter->state.standard.opidx];
*value = extract_operand_value (*operand, iter->insn);
iter->state.standard.opidx++;
}
else
{
const struct arc_operand *operand_base, *operand_limm;
int value_base, value_limm;
if (*iter->state.long_insn.opidx_limm == 0)
{
*operand = NULL;
return FALSE;
}
operand_base = &arc_operands[*iter->state.long_insn.opidx_base];
operand_limm = &arc_operands[*iter->state.long_insn.opidx_limm];
if (operand_base->flags & ARC_OPERAND_LIMM)
{
/* We've reached the end of the operand list. */
*operand = NULL;
return FALSE;
}
value_base = value_limm = 0;
if (!(operand_limm->flags & ARC_OPERAND_IGNORE))
{
/* This should never happen. If it does then the use of
extract_operand_value below will access memory beyond
the insn array. */
assert ((operand_limm->flags & ARC_OPERAND_LIMM) == 0);
*operand = operand_limm;
value_limm = extract_operand_value (*operand, &iter->insn[1]);
}
if (!(operand_base->flags & ARC_OPERAND_IGNORE))
{
*operand = operand_base;
value_base = extract_operand_value (*operand, iter->insn);
}
/* This is a bit of a fudge. There's no reason why simply ORing
together the two values is the right thing to do, however, for all
the cases we currently have, it is the right thing, so, for now,
I've put off solving the more complex problem. */
*value = value_base | value_limm;
iter->state.long_insn.opidx_base++;
iter->state.long_insn.opidx_limm++;
}
return TRUE;
}
/* Disassemble ARC instructions. */
static int
@ -358,16 +702,18 @@ print_insn_arc (bfd_vma memaddr,
bfd_byte buffer[4];
unsigned int lowbyte, highbyte;
int status;
unsigned int insnLen;
unsigned int insn_len;
unsigned insn[2] = { 0, 0 };
unsigned isa_mask;
const unsigned char *opidx;
const struct arc_opcode *opcode;
const extInstruction_t *einsn;
bfd_boolean need_comma;
bfd_boolean open_braket;
int size;
const struct arc_operand *operand;
int value;
struct arc_operand_iterator iter;
memset (&iter, 0, sizeof (iter));
lowbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 1 : 0);
highbyte = ((info->endian == BFD_ENDIAN_LITTLE) ? 0 : 1);
@ -462,8 +808,9 @@ print_insn_arc (bfd_vma memaddr,
return size;
}
insnLen = arc_insn_length (buffer[lowbyte], info);
switch (insnLen)
insn_len = arc_insn_length (buffer[lowbyte], buffer[highbyte], info);
pr_debug ("instruction length = %d bytes\n", insn_len);
switch (insn_len)
{
case 2:
insn[0] = (buffer[lowbyte] << 8) | buffer[highbyte];
@ -498,38 +845,18 @@ print_insn_arc (bfd_vma memaddr,
info->disassembler_needs_relocs = TRUE;
/* Find the first match in the opcode table. */
opcode = find_format (arc_opcodes, insn, insnLen, isa_mask);
if (!find_format (memaddr, insn, &insn_len, isa_mask, info, &opcode, &iter))
return -1;
if (!opcode)
{
/* No instruction found. Try the extensions. */
einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]);
if (einsn)
{
const char *errmsg = NULL;
opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg);
if (opcode == NULL)
{
(*info->fprintf_func) (info->stream,
"An error occured while "
"generating the extension instruction "
"operations");
return -1;
}
opcode = find_format (opcode, insn, insnLen, isa_mask);
assert (opcode != NULL);
}
if (insn_len == 2)
(*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
else
{
if (insnLen == 2)
(*info->fprintf_func) (info->stream, ".long %#04x", insn[0]);
else
(*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
(*info->fprintf_func) (info->stream, ".long %#08x", insn[0]);
info->insn_type = dis_noninsn;
return insnLen;
}
info->insn_type = dis_noninsn;
return insn_len;
}
/* Print the mnemonic. */
@ -575,11 +902,9 @@ print_insn_arc (bfd_vma memaddr,
open_braket = FALSE;
/* Now extract and print the operands. */
for (opidx = opcode->operands; *opidx; opidx++)
operand = NULL;
while (operand_iterator_next (&iter, &operand, &value))
{
const struct arc_operand *operand = &arc_operands[*opidx];
int value;
if (open_braket && (operand->flags & ARC_OPERAND_BRAKET))
{
(*info->fprintf_func) (info->stream, "]");
@ -592,30 +917,9 @@ print_insn_arc (bfd_vma memaddr,
&& !(operand->flags & ARC_OPERAND_BRAKET))
continue;
if (operand->extract)
value = (*operand->extract) (insn[0], (int *) NULL);
else
{
if (operand->flags & ARC_OPERAND_ALIGNED32)
{
value = (insn[0] >> operand->shift)
& ((1 << (operand->bits - 2)) - 1);
value = value << 2;
}
else
{
value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1);
}
if (operand->flags & ARC_OPERAND_SIGNED)
{
int signbit = 1 << (operand->bits - 1);
value = (value ^ signbit) - signbit;
}
}
if (operand->flags & ARC_OPERAND_IGNORE
&& (operand->flags & ARC_OPERAND_IR
&& value == -1))
if ((operand->flags & ARC_OPERAND_IGNORE)
&& (operand->flags & ARC_OPERAND_IR)
&& value == -1)
continue;
if (need_comma)
@ -629,20 +933,6 @@ print_insn_arc (bfd_vma memaddr,
continue;
}
/* Read the limm operand, if required. */
if (operand->flags & ARC_OPERAND_LIMM
&& !(operand->flags & ARC_OPERAND_DUPLICATE))
{
status = (*info->read_memory_func) (memaddr + insnLen, buffer,
4, info);
if (status != 0)
{
(*info->memory_error_func) (status, memaddr + insnLen, info);
return -1;
}
insn[1] = ARRANGE_ENDIAN (info, buffer);
}
/* Print the operand as directed by the flags. */
if (operand->flags & ARC_OPERAND_IR)
{
@ -663,15 +953,15 @@ print_insn_arc (bfd_vma memaddr,
}
else if (operand->flags & ARC_OPERAND_LIMM)
{
const char *rname = get_auxreg (opcode, insn[1], isa_mask);
const char *rname = get_auxreg (opcode, value, isa_mask);
if (rname && open_braket)
(*info->fprintf_func) (info->stream, "%s", rname);
else
{
(*info->fprintf_func) (info->stream, "%#x", insn[1]);
(*info->fprintf_func) (info->stream, "%#x", value);
if (info->insn_type == dis_branch
|| info->insn_type == dis_jsr)
info->target = (bfd_vma) insn[1];
info->target = (bfd_vma) value;
}
}
else if (operand->flags & ARC_OPERAND_PCREL)
@ -710,14 +1000,9 @@ print_insn_arc (bfd_vma memaddr,
}
need_comma = TRUE;
/* Adjust insn len. */
if (operand->flags & ARC_OPERAND_LIMM
&& !(operand->flags & ARC_OPERAND_DUPLICATE))
insnLen += 4;
}
return insnLen;
return insn_len;
}

View File

@ -34,6 +34,21 @@
/* encode1<.f> */
{ "encode1", 0x48048000, 0xf80f8000, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B, NPS_R_SRC2_3B, NPS_BITOP_SRC_POS, NPS_BITOP_SIZE }, { C_NPS_F }},
/* mrgb - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mrgb.cl - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov2b - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov2b.cl - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* ext4 - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* ext4.cl - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* ins4 - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* ins4.cl - 48 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov3b - 64 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov4b - 64 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov3bcl - 64 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov4bcl - 64 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov3b.cl - 64 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* mov4b.cl - 64 bit instruction, see arc_long_opcodes in arc-opc.c. */
/* rflt a,b,c 00111bbb00101110FBBBCCCCCCAAAAAA */
{ "rflt", 0x382e0000, 0xf8ff8000, ARC_OPCODE_NPS400, BITOP, NONE, { RA, RB, RC }, { 0 }},

View File

@ -681,6 +681,43 @@ extract_nps_3bit_dst (unsigned insn ATTRIBUTE_UNUSED,
return value;
}
static unsigned
insert_nps_3bit_dst_short (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
const char **errmsg ATTRIBUTE_UNUSED)
{
switch (value)
{
case 0:
case 1:
case 2:
case 3:
insn |= value << 8;
break;
case 12:
case 13:
case 14:
case 15:
insn |= (value - 8) << 8;
break;
default:
*errmsg = _("Register must be either r0-r3 or r12-r15.");
break;
}
return insn;
}
static int
extract_nps_3bit_dst_short (unsigned insn ATTRIBUTE_UNUSED,
bfd_boolean * invalid ATTRIBUTE_UNUSED)
{
int value = (insn >> 8) & 0x07;
if (value > 3)
return (value + 8);
else
return value;
}
static unsigned
insert_nps_3bit_src2 (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
@ -718,6 +755,43 @@ extract_nps_3bit_src2 (unsigned insn ATTRIBUTE_UNUSED,
return value;
}
static unsigned
insert_nps_3bit_src2_short (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
const char **errmsg ATTRIBUTE_UNUSED)
{
switch (value)
{
case 0:
case 1:
case 2:
case 3:
insn |= value << 5;
break;
case 12:
case 13:
case 14:
case 15:
insn |= (value - 8) << 5;
break;
default:
*errmsg = _("Register must be either r0-r3 or r12-r15.");
break;
}
return insn;
}
static int
extract_nps_3bit_src2_short (unsigned insn ATTRIBUTE_UNUSED,
bfd_boolean * invalid ATTRIBUTE_UNUSED)
{
int value = (insn >> 5) & 0x07;
if (value > 3)
return (value + 8);
else
return value;
}
static unsigned
insert_nps_bitop_size_2b (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
@ -896,6 +970,8 @@ MAKE_SIZE_INSERT_EXTRACT_FUNCS(fxorb,8,32,5,8,5)
MAKE_SIZE_INSERT_EXTRACT_FUNCS(wxorb,16,32,5,16,5)
MAKE_SIZE_INSERT_EXTRACT_FUNCS(bitop,1,32,5,1,10)
MAKE_SIZE_INSERT_EXTRACT_FUNCS(qcmp,1,8,3,1,9)
MAKE_SIZE_INSERT_EXTRACT_FUNCS(bitop1,1,32,5,1,20)
MAKE_SIZE_INSERT_EXTRACT_FUNCS(bitop2,1,32,5,1,25)
static int
extract_nps_qcmp_m3 (unsigned insn ATTRIBUTE_UNUSED,
@ -967,6 +1043,73 @@ extract_nps_calc_entry_size (unsigned insn ATTRIBUTE_UNUSED,
return 1 << entry_size;
}
static unsigned
insert_nps_bitop_mod4_msb (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
const char **errmsg ATTRIBUTE_UNUSED)
{
return insn | ((value & 0x2) << 30);
}
static int
extract_nps_bitop_mod4_msb (unsigned insn ATTRIBUTE_UNUSED,
bfd_boolean * invalid ATTRIBUTE_UNUSED)
{
return (insn >> 30) & 0x2;
}
static unsigned
insert_nps_bitop_mod4_lsb (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
const char **errmsg ATTRIBUTE_UNUSED)
{
return insn | ((value & 0x1) << 15);
}
static int
extract_nps_bitop_mod4_lsb (unsigned insn ATTRIBUTE_UNUSED,
bfd_boolean * invalid ATTRIBUTE_UNUSED)
{
return (insn >> 15) & 0x1;
}
static unsigned
insert_nps_bitop_dst_pos3_pos4 (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
const char **errmsg ATTRIBUTE_UNUSED)
{
return insn | (value << 10) | (value << 5);
}
static int
extract_nps_bitop_dst_pos3_pos4 (unsigned insn ATTRIBUTE_UNUSED,
bfd_boolean * invalid ATTRIBUTE_UNUSED)
{
if (((insn >> 10) & 0x1f) != ((insn >> 5) & 0x1f))
*invalid = TRUE;
return ((insn >> 5) & 0x1f);
}
static unsigned
insert_nps_bitop_ins_ext (unsigned insn ATTRIBUTE_UNUSED,
int value ATTRIBUTE_UNUSED,
const char **errmsg ATTRIBUTE_UNUSED)
{
if (value < 0 || value > 28)
*errmsg = _("Value must be in the range 0 to 28");
return insn | (value << 20);
}
static int
extract_nps_bitop_ins_ext (unsigned insn ATTRIBUTE_UNUSED,
bfd_boolean * invalid ATTRIBUTE_UNUSED)
{
int value = (insn >> 20) & 0x1f;
if (value > 28)
*invalid = TRUE;
return value;
}
/* Include the generic extract/insert functions. Order is important
as some of the functions present in the .h may be disabled via
defines. */
@ -1295,9 +1438,13 @@ const struct arc_operand arc_operands[] =
index is used to indicate end-of-list. */
#define UNUSED 0
{ 0, 0, 0, 0, 0, 0 },
#define IGNORED (UNUSED + 1)
{ 0, 0, 0, ARC_OPERAND_IGNORE | ARC_OPERAND_UNSIGNED | ARC_OPERAND_NCHK, 0, 0 },
/* The plain integer register fields. Used by 32 bit
instructions. */
#define RA (UNUSED + 1)
#define RA (IGNORED + 1)
{ 6, 0, 0, ARC_OPERAND_IR, 0, 0 },
#define RB (RA + 1)
{ 6, 12, 0, ARC_OPERAND_IR, insert_rb, extract_rb },
@ -1682,6 +1829,66 @@ const struct arc_operand arc_operands[] =
#define NPS_CALC_ENTRY_SIZE (NPS_QCMP_M3 + 1)
{ 0, 0, 0, ARC_OPERAND_UNSIGNED | ARC_OPERAND_NCHK, insert_nps_calc_entry_size, extract_nps_calc_entry_size },
#define NPS_R_DST_3B_SHORT (NPS_CALC_ENTRY_SIZE + 1)
{ 3, 8, 0, ARC_OPERAND_IR | ARC_OPERAND_NCHK, insert_nps_3bit_dst_short, extract_nps_3bit_dst_short },
#define NPS_R_SRC1_3B_SHORT (NPS_R_DST_3B_SHORT + 1)
{ 3, 8, 0, ARC_OPERAND_IR | ARC_OPERAND_DUPLICATE | ARC_OPERAND_NCHK, insert_nps_3bit_dst_short, extract_nps_3bit_dst_short },
#define NPS_R_SRC2_3B_SHORT (NPS_R_SRC1_3B_SHORT + 1)
{ 3, 5, 0, ARC_OPERAND_IR | ARC_OPERAND_NCHK, insert_nps_3bit_src2_short, extract_nps_3bit_src2_short },
#define NPS_BITOP_SIZE2 (NPS_R_SRC2_3B_SHORT + 1)
{ 5, 25, 0, ARC_OPERAND_UNSIGNED | ARC_OPERAND_NCHK, insert_nps_bitop2_size, extract_nps_bitop2_size },
#define NPS_BITOP_SIZE1 (NPS_BITOP_SIZE2 + 1)
{ 5, 20, 0, ARC_OPERAND_UNSIGNED | ARC_OPERAND_NCHK, insert_nps_bitop1_size, extract_nps_bitop1_size },
#define NPS_BITOP_DST_POS3_POS4 (NPS_BITOP_SIZE1 + 1)
{ 5, 0, 0, ARC_OPERAND_UNSIGNED, insert_nps_bitop_dst_pos3_pos4, extract_nps_bitop_dst_pos3_pos4 },
#define NPS_BITOP_DST_POS4 (NPS_BITOP_DST_POS3_POS4 + 1)
{ 5, 10, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_DST_POS3 (NPS_BITOP_DST_POS4 + 1)
{ 5, 5, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_DST_POS2 (NPS_BITOP_DST_POS3 + 1)
{ 5, 15, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_DST_POS1 (NPS_BITOP_DST_POS2 + 1)
{ 5, 10, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_SRC_POS4 (NPS_BITOP_DST_POS1 + 1)
{ 5, 0, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_SRC_POS3 (NPS_BITOP_SRC_POS4 + 1)
{ 5, 20, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_SRC_POS2 (NPS_BITOP_SRC_POS3 + 1)
{ 5, 5, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_SRC_POS1 (NPS_BITOP_SRC_POS2 + 1)
{ 5, 0, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_MOD4_MSB (NPS_BITOP_SRC_POS1 + 1)
{ 2, 0, 0, ARC_OPERAND_UNSIGNED, insert_nps_bitop_mod4_msb, extract_nps_bitop_mod4_msb },
#define NPS_BITOP_MOD4_LSB (NPS_BITOP_MOD4_MSB + 1)
{ 2, 0, 0, ARC_OPERAND_UNSIGNED, insert_nps_bitop_mod4_lsb, extract_nps_bitop_mod4_lsb },
#define NPS_BITOP_MOD3 (NPS_BITOP_MOD4_LSB + 1)
{ 2, 29, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_MOD2 (NPS_BITOP_MOD3 + 1)
{ 2, 27, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_MOD1 (NPS_BITOP_MOD2 + 1)
{ 2, 25, 0, ARC_OPERAND_UNSIGNED, NULL, NULL },
#define NPS_BITOP_INS_EXT (NPS_BITOP_MOD1 + 1)
{ 5, 20, 0, ARC_OPERAND_UNSIGNED, insert_nps_bitop_ins_ext, extract_nps_bitop_ins_ext },
};
const unsigned arc_num_operands = ARRAY_SIZE (arc_operands);
@ -2053,3 +2260,92 @@ const struct arc_opcode arc_relax_opcodes[] =
};
const unsigned arc_num_relax_opcodes = ARRAY_SIZE (arc_relax_opcodes);
/* The following instructions are all either 48 or 64 bits long, and
require special handling in the assembler and disassembler.
The first part of each ARC_LONG_OPCODE is the base ARC_OPCODE, this is
either the 16 or 32 bit base instruction, and its opcode list will
always end in a LIMM.
The rest of the ARC_LONG_OPCODE describes how to build the LIMM from the
instruction operands. There are therefore two lists of operands for
each ARC_LONG_OPCODE, the second list contains operands that are merged
into the limm template, in the same way that a standard 32-bit
instruction is built. This generated limm is then added to the list of
tokens that is passed to the standard instruction encoder, along with
the first list of operands (from the base arc_opcode).
The first list of operands then, describes how to build the base
instruction, and includes the 32-bit limm that was previously generated
as the last operand.
In most cases operands are either encoded into the base instruction or
into the limm. When this happens the operand slot will be filled with
an operand identifier in one list, and will be IGNORED in the other
list, this special operand value causes the operand to be ignored,
without being encoded at this point.
However, in some cases, an operand is split between the base instruction
and the 32-bit limm, in this case the operand slot will be filled in
both operand lists (see mov4b for one example of this). */
const struct arc_long_opcode arc_long_opcodes[] =
{
/* mrgb - (48 bit instruction). */
{ { "mrgb", 0x5803, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC1_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { 0 }},
0x00000000, 0x80000000, { IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_SRC_POS1, NPS_BITOP_SIZE1, NPS_BITOP_DST_POS2, NPS_BITOP_SRC_POS2, NPS_BITOP_SIZE2 }},
/* mrgb.cl - (48 bit instruction). */
{ { "mrgb", 0x5803, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC1_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { C_NPS_CL }},
0x80000000, 0x80000000, { IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_SRC_POS1, NPS_BITOP_SIZE1, NPS_BITOP_DST_POS2, NPS_BITOP_SRC_POS2, NPS_BITOP_SIZE2 }},
/* mov2b - (48 bit instruction). */
{ { "mov2b", 0x5800, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC1_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { 0 }},
0x00000000, 0x80000000, { IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2 }},
/* mov2b.cl - (48 bit instruction). */
{ { "mov2b", 0x5800, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { C_NPS_CL }},
0x80000000, 0x80000000, { IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2 }},
/* ext4 - (48 bit instruction). */
{ { "ext4b", 0x5801, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC1_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { 0 }},
0x00000000, 0x80000000, { IGNORED, IGNORED, IGNORED, NPS_BITOP_INS_EXT, NPS_BITOP_SRC_POS1, NPS_BITOP_SRC_POS2, NPS_BITOP_DST_POS1, NPS_BITOP_DST_POS2 }},
/* ext4.cl - (48 bit instruction). */
{ { "ext4b", 0x5801, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { C_NPS_CL }},
0x80000000, 0x80000000, { IGNORED, IGNORED, NPS_BITOP_INS_EXT, NPS_BITOP_SRC_POS1, NPS_BITOP_SRC_POS2, NPS_BITOP_DST_POS1, NPS_BITOP_DST_POS2 }},
/* ins4 - (48 bit instruction). */
{ { "ins4b", 0x5802, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC1_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { 0 }},
0x00000000, 0x80000000, { IGNORED, IGNORED, IGNORED, NPS_BITOP_SRC_POS1, NPS_BITOP_SRC_POS2, NPS_BITOP_DST_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_INS_EXT }},
/* ins4.cl - (48 bit instruction). */
{ { "ins4b", 0x5802, 0xf81f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B_SHORT, NPS_R_SRC2_3B_SHORT, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, LIMM }, { C_NPS_CL }},
0x80000000, 0x80000000, { IGNORED, IGNORED, NPS_BITOP_SRC_POS1, NPS_BITOP_SRC_POS2, NPS_BITOP_DST_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_INS_EXT }},
/* mov3b - (64 bit instruction). */
{ { "mov3b", 0x58100000, 0xf81f801f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B, NPS_R_SRC1_3B, NPS_R_SRC2_3B, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS3_POS4, IGNORED, IGNORED, LIMM }, { 0 }},
0x80000000, 0x80000000, { IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2, IGNORED, NPS_BITOP_MOD3, NPS_BITOP_SRC_POS3 }},
/* mov4b - (64 bit instruction). */
{ { "mov4b", 0x58100000, 0xf81f0000, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B, NPS_R_SRC1_3B, NPS_R_SRC2_3B, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS3, IGNORED, IGNORED, NPS_BITOP_DST_POS4, NPS_BITOP_MOD4_LSB, NPS_BITOP_SRC_POS4, LIMM }, { 0 }},
0x00000000, 0x00000000, { IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2, IGNORED, NPS_BITOP_MOD3, NPS_BITOP_SRC_POS3, IGNORED, NPS_BITOP_MOD4_MSB, IGNORED}},
/* mov3bcl - (64 bit instruction). */
{ { "mov3bcl", 0x58110000, 0xf81f801f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B, NPS_R_SRC2_3B, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS3_POS4, IGNORED, IGNORED, LIMM }, { 0 }},
0x80000000, 0x80000000, { IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2, IGNORED, NPS_BITOP_MOD3, NPS_BITOP_SRC_POS3 }},
/* mov4bcl - (64 bit instruction). */
{ { "mov4bcl", 0x58110000, 0xf81f0000, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B, NPS_R_SRC2_3B, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS3, IGNORED, IGNORED, NPS_BITOP_DST_POS4, NPS_BITOP_MOD4_LSB, NPS_BITOP_SRC_POS4, LIMM }, { 0 }},
0x00000000, 0x00000000, { IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2, IGNORED, NPS_BITOP_MOD3, NPS_BITOP_SRC_POS3, IGNORED, NPS_BITOP_MOD4_MSB, IGNORED}},
/* mov3b.cl - (64 bit instruction). */
{ { "mov3b", 0x58110000, 0xf81f801f, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B, NPS_R_SRC2_3B, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS3_POS4, IGNORED, IGNORED, LIMM }, { C_NPS_CL }},
0x80000000, 0x80000000, { IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2, IGNORED, NPS_BITOP_MOD3, NPS_BITOP_SRC_POS3 }},
/* mov4b.cl - (64 bit instruction). */
{ { "mov4b", 0x58110000, 0xf81f0000, ARC_OPCODE_NPS400, BITOP, NONE, { NPS_R_DST_3B, NPS_R_SRC2_3B, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, IGNORED, NPS_BITOP_DST_POS3, IGNORED, IGNORED, NPS_BITOP_DST_POS4, NPS_BITOP_MOD4_LSB, NPS_BITOP_SRC_POS4, LIMM }, { C_NPS_CL }},
0x00000000, 0x00000000, { IGNORED, IGNORED, NPS_BITOP_DST_POS1, NPS_BITOP_MOD1, NPS_BITOP_SRC_POS1, NPS_BITOP_DST_POS2, NPS_BITOP_MOD2, NPS_BITOP_SRC_POS2, IGNORED, NPS_BITOP_MOD3, NPS_BITOP_SRC_POS3, IGNORED, NPS_BITOP_MOD4_MSB, IGNORED}},
};
const unsigned arc_num_long_opcodes = ARRAY_SIZE (arc_long_opcodes);