From b99747aeed79ad69af8b8be4d9aa3a74200fca7d Mon Sep 17 00:00:00 2001 From: Claudiu Zissulescu Date: Mon, 4 Apr 2016 16:03:53 +0200 Subject: [PATCH] Add support for .extInstruction pseudo-op. gas/ 2016-04-04 Claudiu Zissulescu * testsuite/gas/arc/textinsn-errors.d: New File. * testsuite/gas/arc/textinsn-errors.err: Likewise. * testsuite/gas/arc/textinsn-errors.s: Likewise. * testsuite/gas/arc/textinsn2op.d: Likewise. * testsuite/gas/arc/textinsn2op.s: Likewise. * testsuite/gas/arc/textinsn2op01.d: Likewise. * testsuite/gas/arc/textinsn2op01.s: Likewise. * testsuite/gas/arc/textinsn3op.d: Likewise. * testsuite/gas/arc/textinsn3op.s: Likewise. * doc/c-arc.texi (ARC Directives): Add .extInstruction documentation. * config/tc-arc.c (arcext_section): New variable. (arc_extinsn): New function. (md_pseudo_table): Add .extInstruction pseudo op. (attributes_t): New type. (suffixclass, syntaxclass, syntaxclassmod): New constant structures. (find_opcode_match): Remove arc_num_opcodes. (md_begin): Likewise. (tokenize_extinsn): New function. (arc_set_ext_seg): Likewise. (create_extinst_section): Likewise. include/ 2016-04-04 Claudiu Zissulescu * opcode/arc.h (arc_num_opcodes): Remove. (ARC_SYNTAX_3OP, ARC_SYNTAX_2OP, ARC_OP1_MUST_BE_IMM) (ARC_OP1_IMM_IMPLIED, ARC_SUFFIX_NONE, ARC_SUFFIX_COND) (ARC_SUFFIX_FLAG): Define. (flags_none, flags_f, flags_cc, flags_ccf): Declare. (arg_none, arg_32bit_rarbrc, arg_32bit_zarbrc, arg_32bit_rbrbrc) (arg_32bit_rarbu6, arg_32bit_zarbu6, arg_32bit_rbrbu6) (arg_32bit_rbrbs12, arg_32bit_ralimmrc, arg_32bit_rarblimm) (arg_32bit_zalimmrc, arg_32bit_zarblimm, arg_32bit_rbrblimm) (arg_32bit_ralimmu6, arg_32bit_zalimmu6, arg_32bit_zalimms12) (arg_32bit_ralimmlimm, arg_32bit_zalimmlimm, arg_32bit_rbrc) (arg_32bit_zarc, arg_32bit_rbu6, arg_32bit_zau6, arg_32bit_rblimm) (arg_32bit_zalimm, arg_32bit_limmrc, arg_32bit_limmu6) (arg_32bit_limms12, arg_32bit_limmlimm): Likewise. opcodes/ 2016-04-04 Claudiu Zissulescu * arc-opc.c (flags_none, flags_f, flags_cc, flags_ccf): Initialize. (arg_none, arg_32bit_rarbrc, arg_32bit_zarbrc, arg_32bit_rbrbrc) (arg_32bit_rarbu6, arg_32bit_zarbu6, arg_32bit_rbrbu6) (arg_32bit_rbrbs12, arg_32bit_ralimmrc, arg_32bit_rarblimm) (arg_32bit_zalimmrc, arg_32bit_zarblimm, arg_32bit_rbrblimm) (arg_32bit_ralimmu6, arg_32bit_zalimmu6, arg_32bit_zalimms12) (arg_32bit_ralimmlimm, arg_32bit_zalimmlimm, arg_32bit_rbrc) (arg_32bit_zarc, arg_32bit_rbu6, arg_32bit_zau6, arg_32bit_rblimm) (arg_32bit_zalimm, arg_32bit_limmrc, arg_32bit_limmu6) (arg_32bit_limms12, arg_32bit_limmlimm): Likewise. (arc_opcode arc_opcodes): Null terminate the array. (arc_num_opcodes): Remove. * arc-ext.h (INSERT_XOP): Define. (extInstruction_t): Likewise. (arcExtMap_instName): Delete. (arcExtMap_insn): New function. (arcExtMap_genOpcode): Likewise. * arc-ext.c (ExtInstruction): Remove. (create_map): Zero initialize instruction fields. (arcExtMap_instName): Remove. (arcExtMap_insn): New function. (dump_ARC_extmap): More info while debuging. (arcExtMap_genOpcode): New function. * arc-dis.c (find_format): New function. (print_insn_arc): Use find_format. (arc_get_disassembler): Enable dump_ARC_extmap only when debugging. Signed-off-by: Claudiu Zissulescu --- gas/ChangeLog | 25 ++ gas/config/tc-arc.c | 385 ++++++++++++++++++++-- gas/doc/c-arc.texi | 95 +++++- gas/testsuite/gas/arc/textinsn-errors.d | 1 + gas/testsuite/gas/arc/textinsn-errors.err | 2 + gas/testsuite/gas/arc/textinsn-errors.s | 1 + gas/testsuite/gas/arc/textinsn2op.d | 24 ++ gas/testsuite/gas/arc/textinsn2op.s | 22 ++ gas/testsuite/gas/arc/textinsn2op01.d | 27 ++ gas/testsuite/gas/arc/textinsn2op01.s | 26 ++ gas/testsuite/gas/arc/textinsn3op.d | 63 ++++ gas/testsuite/gas/arc/textinsn3op.s | 64 ++++ include/ChangeLog | 63 ++-- include/opcode/arc.h | 51 ++- opcodes/ChangeLog | 69 ++-- opcodes/arc-dis.c | 228 +++++++------ opcodes/arc-ext.c | 306 +++++++++++++++-- opcodes/arc-ext.h | 51 ++- opcodes/arc-opc.c | 42 ++- 19 files changed, 1343 insertions(+), 202 deletions(-) create mode 100644 gas/testsuite/gas/arc/textinsn-errors.d create mode 100644 gas/testsuite/gas/arc/textinsn-errors.err create mode 100644 gas/testsuite/gas/arc/textinsn-errors.s create mode 100644 gas/testsuite/gas/arc/textinsn2op.d create mode 100644 gas/testsuite/gas/arc/textinsn2op.s create mode 100644 gas/testsuite/gas/arc/textinsn2op01.d create mode 100644 gas/testsuite/gas/arc/textinsn2op01.s create mode 100644 gas/testsuite/gas/arc/textinsn3op.d create mode 100644 gas/testsuite/gas/arc/textinsn3op.s diff --git a/gas/ChangeLog b/gas/ChangeLog index 517331283e..688ffdec4b 100644 --- a/gas/ChangeLog +++ b/gas/ChangeLog @@ -1,3 +1,28 @@ +2016-04-12 Claudiu Zissulescu + + * testsuite/gas/arc/textinsn-errors.d: New File. + * testsuite/gas/arc/textinsn-errors.err: Likewise. + * testsuite/gas/arc/textinsn-errors.s: Likewise. + * testsuite/gas/arc/textinsn2op.d: Likewise. + * testsuite/gas/arc/textinsn2op.s: Likewise. + * testsuite/gas/arc/textinsn2op01.d: Likewise. + * testsuite/gas/arc/textinsn2op01.s: Likewise. + * testsuite/gas/arc/textinsn3op.d: Likewise. + * testsuite/gas/arc/textinsn3op.s: Likewise. + * doc/c-arc.texi (ARC Directives): Add .extInstruction + documentation. + * config/tc-arc.c (arcext_section): New variable. + (arc_extinsn): New function. + (md_pseudo_table): Add .extInstruction pseudo op. + (attributes_t): New type. + (suffixclass, syntaxclass, syntaxclassmod): New constant + structures. + (find_opcode_match): Remove arc_num_opcodes. + (md_begin): Likewise. + (tokenize_extinsn): New function. + (arc_set_ext_seg): Likewise. + (create_extinst_section): Likewise. + 2016-04-12 Claudiu Zissulescu * config/tc-arc.c (preprocess_operands): Mark AUX symbol. diff --git a/gas/config/tc-arc.c b/gas/config/tc-arc.c index 98cac6a3f4..3aeedb1943 100644 --- a/gas/config/tc-arc.c +++ b/gas/config/tc-arc.c @@ -29,6 +29,7 @@ #include "opcode/arc.h" #include "elf/arc.h" +#include "../opcodes/arc-ext.h" /* Defines section. */ @@ -126,6 +127,9 @@ extern int target_big_endian; const char *arc_target_format = DEFAULT_TARGET_FORMAT; static int byte_order = DEFAULT_BYTE_ORDER; +/* Arc extension section. */ +static segT arcext_section; + /* By default relaxation is disabled. */ static int relaxation_state = 0; @@ -135,7 +139,7 @@ extern int arc_get_mach (char *); static void arc_lcomm (int); static void arc_option (int); static void arc_extra_reloc (int); - +static void arc_extinsn (int); const pseudo_typeS md_pseudo_table[] = { @@ -147,6 +151,8 @@ const pseudo_typeS md_pseudo_table[] = { "lcommon", arc_lcomm, 0 }, { "cpu", arc_option, 0 }, + { "extinstruction", arc_extinsn, 0 }, + { "tls_gd_ld", arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_LD }, { "tls_gd_call", arc_extra_reloc, BFD_RELOC_ARC_TLS_GD_CALL }, @@ -308,6 +314,35 @@ static struct arc_last_insn bfd_boolean has_delay_slot; } arc_last_insns[2]; +/* Extension instruction suffix classes. */ +typedef struct +{ + const char *name; + int len; + int class; +} attributes_t; + +static const attributes_t suffixclass[] = +{ + { "SUFFIX_FLAG", 11, ARC_SUFFIX_FLAG }, + { "SUFFIX_COND", 11, ARC_SUFFIX_COND }, + { "SUFFIX_NONE", 11, ARC_SUFFIX_NONE } +}; + +/* Extension instruction syntax classes. */ +static const attributes_t syntaxclass[] = +{ + { "SYNTAX_3OP", 10, ARC_SYNTAX_3OP }, + { "SYNTAX_2OP", 10, ARC_SYNTAX_2OP } +}; + +/* Extension instruction syntax classes modifiers. */ +static const attributes_t syntaxclassmod[] = +{ + { "OP1_IMM_IMPLIED" , 15, ARC_OP1_IMM_IMPLIED }, + { "OP1_MUST_BE_IMM" , 15, ARC_OP1_MUST_BE_IMM } +}; + /* Structure to hold an entry in ARC_OPCODE_HASH. */ struct arc_opcode_hash_entry { @@ -615,8 +650,8 @@ arc_opcode_hash_entry_iterator_next (const struct arc_opcode_hash_entry *entry, const char *old_name = iter->opcode->name; iter->opcode++; - if ((iter->opcode - arc_opcodes >= (int) arc_num_opcodes) - || (strcmp (old_name, iter->opcode->name) != 0)) + if (iter->opcode->name + && (strcmp (old_name, iter->opcode->name) != 0)) { iter->index++; if (iter->index == entry->count) @@ -629,6 +664,40 @@ arc_opcode_hash_entry_iterator_next (const struct arc_opcode_hash_entry *entry, return iter->opcode; } +/* Insert an opcode into opcode hash structure. */ + +static void +arc_insert_opcode (const struct arc_opcode *opcode) +{ + const char *name, *retval; + struct arc_opcode_hash_entry *entry; + name = opcode->name; + + entry = hash_find (arc_opcode_hash, name); + if (entry == NULL) + { + entry = xmalloc (sizeof (*entry)); + entry->count = 0; + entry->opcode = NULL; + + retval = hash_insert (arc_opcode_hash, name, (void *) entry); + if (retval) + as_fatal (_("internal error: can't hash opcode '%s': %s"), + name, retval); + } + + entry->opcode = xrealloc (entry->opcode, + sizeof (const struct arc_opcode *) + * (entry->count + 1)); + + if (entry->opcode == NULL) + as_fatal (_("Virtual memory exhausted")); + + entry->opcode[entry->count] = opcode; + entry->count++; +} + + /* Like md_number_to_chars but used for limms. The 4-byte limm value, is encoded as 'middle-endian' for a little-endian target. FIXME! this function is used for regular 4 byte instructions as well. */ @@ -1611,7 +1680,7 @@ find_opcode_match (const struct arc_opcode_hash_entry *entry, from BKTOK. */ tok[tokidx].X_op = O_constant; tok[tokidx].X_add_number = auxr->address; - ARC_SET_FLAG (tok[i].X_add_symbol, ARC_FLAG_AUX); + ARC_SET_FLAG (tok[tokidx].X_add_symbol, ARC_FLAG_AUX); break; } @@ -2218,7 +2287,7 @@ declare_register_set (void) void md_begin (void) { - unsigned int i; + const struct arc_opcode *opcode = arc_opcodes; if (!mach_type_specified_p) arc_select_cpu ("arc700"); @@ -2238,37 +2307,17 @@ md_begin (void) as_fatal (_("Virtual memory exhausted")); /* Initialize the hash table with the insns. */ - for (i = 0; i < arc_num_opcodes;) + do { - const char *name, *retval; - struct arc_opcode_hash_entry *entry; - - name = arc_opcodes[i].name; - - entry = hash_find (arc_opcode_hash, name); - if (entry == NULL) - { - entry = xmalloc (sizeof (*entry)); - entry->count = 0; - entry->opcode = NULL; - - retval = hash_insert (arc_opcode_hash, name, (void *) entry); - if (retval) - as_fatal (_("internal error: can't hash opcode '%s': %s"), - name, retval); - } + const char *name = opcode->name; - entry->opcode = xrealloc (entry->opcode, - sizeof (const struct arc_opcode *) - * entry->count + 1); - entry->opcode [entry->count] = &arc_opcodes[i]; - entry->count++; + arc_insert_opcode (opcode); - while (++i < arc_num_opcodes - && (arc_opcodes[i].name == name - || !strcmp (arc_opcodes[i].name, name))) + while (++opcode && opcode->name + && (opcode->name == name + || !strcmp (opcode->name, name))) continue; - } + }while (opcode->name); /* Register declaration. */ arc_reg_hash = hash_new (); @@ -3877,3 +3926,275 @@ arc_adjust_symtab (void) /* Now do generic ELF adjustments. */ elf_adjust_symtab (); } + +static void +tokenize_extinsn (extInstruction_t *einsn) +{ + char *p, c; + char *insn_name; + unsigned char major_opcode; + unsigned char sub_opcode; + unsigned char syntax_class = 0; + unsigned char syntax_class_modifiers = 0; + unsigned char suffix_class = 0; + unsigned int i; + + SKIP_WHITESPACE (); + + /* 1st: get instruction name. */ + p = input_line_pointer; + c = get_symbol_name (&p); + + insn_name = xstrdup (p); + restore_line_pointer (c); + + /* 2nd: get major opcode. */ + if (*input_line_pointer != ',') + { + as_bad (_("expected comma after instruction name")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + major_opcode = get_absolute_expression (); + + /* 3rd: get sub-opcode. */ + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + as_bad (_("expected comma after major opcode")); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + sub_opcode = get_absolute_expression (); + + /* 4th: get suffix class. */ + SKIP_WHITESPACE (); + + if (*input_line_pointer != ',') + { + as_bad ("expected comma after sub opcode"); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + + while (1) + { + SKIP_WHITESPACE (); + + for (i = 0; i < ARRAY_SIZE (suffixclass); i++) + { + if (!strncmp (suffixclass[i].name, input_line_pointer, + suffixclass[i].len)) + { + suffix_class |= suffixclass[i].class; + input_line_pointer += suffixclass[i].len; + break; + } + } + + if (i == ARRAY_SIZE (suffixclass)) + { + as_bad ("invalid suffix class"); + ignore_rest_of_line (); + return; + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer == '|') + input_line_pointer++; + else + break; + } + + /* 5th: get syntax class and syntax class modifiers. */ + if (*input_line_pointer != ',') + { + as_bad ("expected comma after suffix class"); + ignore_rest_of_line (); + return; + } + input_line_pointer++; + + while (1) + { + SKIP_WHITESPACE (); + + for (i = 0; i < ARRAY_SIZE (syntaxclassmod); i++) + { + if (!strncmp (syntaxclassmod[i].name, + input_line_pointer, + syntaxclassmod[i].len)) + { + syntax_class_modifiers |= syntaxclassmod[i].class; + input_line_pointer += syntaxclassmod[i].len; + break; + } + } + + if (i == ARRAY_SIZE (syntaxclassmod)) + { + for (i = 0; i < ARRAY_SIZE (syntaxclass); i++) + { + if (!strncmp (syntaxclass[i].name, + input_line_pointer, + syntaxclass[i].len)) + { + syntax_class |= syntaxclass[i].class; + input_line_pointer += syntaxclass[i].len; + break; + } + } + + if (i == ARRAY_SIZE (syntaxclass)) + { + as_bad ("missing syntax class"); + ignore_rest_of_line (); + return; + } + } + + SKIP_WHITESPACE (); + + if (*input_line_pointer == '|') + input_line_pointer++; + else + break; + } + + demand_empty_rest_of_line (); + + einsn->name = insn_name; + einsn->major = major_opcode; + einsn->minor = sub_opcode; + einsn->syntax = syntax_class; + einsn->modsyn = syntax_class_modifiers; + einsn->suffix = suffix_class; + einsn->flags = syntax_class + | (syntax_class_modifiers & ARC_OP1_IMM_IMPLIED ? 0x10 : 0); +} + +/* Generate an extension section. */ + +static int +arc_set_ext_seg (void) +{ + if (!arcext_section) + { + arcext_section = subseg_new (".arcextmap", 0); + bfd_set_section_flags (stdoutput, arcext_section, + SEC_READONLY | SEC_HAS_CONTENTS); + } + else + subseg_set (arcext_section, 0); + return 1; +} + +/* Create an extension instruction description in the arc extension + section of the output file. + The structure for an instruction is like this: + [0]: Length of the record. + [1]: Type of the record. + + [2]: Major opcode. + [3]: Sub-opcode. + [4]: Syntax (flags). + [5]+ Name instruction. + + The sequence is terminated by an empty entry. */ + +static void +create_extinst_section (extInstruction_t *einsn) +{ + + segT old_sec = now_seg; + int old_subsec = now_subseg; + char *p; + int name_len = strlen (einsn->name); + + arc_set_ext_seg (); + + p = frag_more (1); + *p = 5 + name_len + 1; + p = frag_more (1); + *p = EXT_INSTRUCTION; + p = frag_more (1); + *p = einsn->major; + p = frag_more (1); + *p = einsn->minor; + p = frag_more (1); + *p = einsn->flags; + p = frag_more (name_len + 1); + strcpy (p, einsn->name); + + subseg_set (old_sec, old_subsec); +} + +/* Handler .extinstruction pseudo-op. */ + +static void +arc_extinsn (int ignore ATTRIBUTE_UNUSED) +{ + extInstruction_t einsn; + struct arc_opcode *arc_ext_opcodes; + const char *errmsg = NULL; + unsigned char moplow, mophigh; + + memset (&einsn, 0, sizeof (einsn)); + tokenize_extinsn (&einsn); + + /* Check if the name is already used. */ + if (arc_find_opcode (einsn.name)) + as_warn (_("Pseudocode already used %s"), einsn.name); + + /* Check the opcode ranges. */ + moplow = 0x05; + mophigh = (arc_target & (ARC_OPCODE_ARCv2EM + | ARC_OPCODE_ARCv2HS)) ? 0x07 : 0x0a; + + if ((einsn.major > mophigh) || (einsn.major < moplow)) + as_fatal (_("major opcode not in range [0x%02x - 0x%02x]"), moplow, mophigh); + + if ((einsn.minor > 0x3f) && (einsn.major != 0x0a) + && (einsn.major != 5) && (einsn.major != 9)) + as_fatal (_("minor opcode not in range [0x00 - 0x3f]")); + + switch (einsn.syntax & (ARC_SYNTAX_3OP | ARC_SYNTAX_2OP)) + { + case ARC_SYNTAX_3OP: + if (einsn.modsyn & ARC_OP1_IMM_IMPLIED) + as_fatal (_("Improper use of OP1_IMM_IMPLIED")); + break; + case ARC_SYNTAX_2OP: + if (einsn.modsyn & ARC_OP1_MUST_BE_IMM) + as_fatal (_("Improper use of OP1_MUST_BE_IMM")); + break; + default: + break; + } + + arc_ext_opcodes = arcExtMap_genOpcode (&einsn, arc_target, &errmsg); + if (arc_ext_opcodes == NULL) + { + if (errmsg) + as_fatal ("%s", errmsg); + else + as_fatal (_("Couldn't generate extension instruction opcodes")); + } + else if (errmsg) + as_warn ("%s", errmsg); + + /* Insert the extension instruction. */ + arc_insert_opcode ((const struct arc_opcode *) arc_ext_opcodes); + + create_extinst_section (&einsn); +} + +/* Local variables: + eval: (c-set-style "gnu") + indent-tabs-mode: t + End: */ diff --git a/gas/doc/c-arc.texi b/gas/doc/c-arc.texi index 4824027e06..a237285805 100644 --- a/gas/doc/c-arc.texi +++ b/gas/doc/c-arc.texi @@ -320,7 +320,7 @@ machine directives: @table @code @cindex @code{lcomm} directive -@item .lcomm @var{symbol} , @var{length}[, @var{alignment}] +@item .lcomm @var{symbol}, @var{length}[, @var{alignment}] Reserve @var{length} (an absolute expression) bytes for a local common denoted by @var{symbol}. The section and value of @var{symbol} are those of the new local common. The addresses are allocated in the bss @@ -336,11 +336,11 @@ largest power of two less than or equal to the size of the symbol, up to a maximum of 16. @cindex @code{lcommon} directive -@item .lcommon @var{symbol} , @var{length}[, @var{alignment}] +@item .lcommon @var{symbol}, @var{length}[, @var{alignment}] The same as @code{lcomm} directive. -@cindex @code{cpu} directive, ARC -@cindex @code{cpu} directive, ARC +@cindex @code{cpu} directive +@item .cpu @var{cpu} The @code{.cpu} directive must be followed by the desired core version. Permitted values for CPU are: @table @code @@ -361,6 +361,93 @@ Assemble for the ARC HS instruction set. Note: the @code{.cpu} directive overrides the command line option @code{-mcpu=@var{cpu}}; a warning is emitted when the version is not consistent between the two. + +@item .extInstruction @var{name}, @var{opcode}, @var{subopcode}, @var{suffixclass}, @var{syntaxclass} +@cindex @code{extInstruction} directive +ARC allows the user to specify extension instructions. These +extension instructions are not macros; the assembler creates encodings +for use of these instructions according to the specification by the +user. + +The first argument, @var{name}, gives the name of the instruction. + +The second argument, @var{opcode}, is the opcode to be used (bits 31:27 +in the encoding). + +The third argument, @var{subopcode}, is the sub-opcode to be used, but +the correct value also depends on the fifth argument, +@var{syntaxclass} + +The fourth argument, @var{suffixclass}, determines the kinds of +suffixes to be allowed. Valid values are: +@table @code +@item SUFFIX_NONE +No suffixes are permitted; + +@item SUFFIX_COND +Conditional suffixes are permitted; + +@item SUFFIX_FLAG +Flag setting suffixes are permitted. + +@item SUFFIX_COND|SUFFIX_FLAG +Both conditional and flag setting suffices are permitted. + +@end table + +The fifth and final argument, @var{syntaxclass}, determines the syntax +class for the instruction. It can have the following values: +@table @code +@item SYNTAX_2OP +Two Operand Instruction; + +@item SYNTAX_3OP +Three Operand Instruction. +@end table + +The syntax class may be followed by @samp{|} and one of the following +modifiers. +@table @code + +@item OP1_MUST_BE_IMM +Modifies syntax class @code{SYNTAX_3OP}, specifying that the first +operand of a three-operand instruction must be an immediate (i.e., the +result is discarded). This is usually used to set the flags using +specific instructions and not retain results. + +@item OP1_IMM_IMPLIED +Modifies syntax class @code{SYNTAX_20P}, specifying that there is an +implied immediate destination operand which does not appear in the +syntax. + +For example, if the source code contains an instruction like: +@example +inst r1,r2 +@end example +the first argument is an implied immediate (that is, the result is +discarded). This is the same as though the source code were: inst +0,r1,r2. + +@end table + +For example, defining a 64-bit multiplier with immediate operands: +@example + .extInstruction mp64, 0x07, 0x2d, SUFFIX_COND|SUFFIX_FLAG, + SYNTAX_3OP|OP1_MUST_BE_IMM +@end example +which specifies an extension instruction named @code{mp64} with 3 +operands. It sets the flags and can be used with a condition code, +for which the first operand is an immediate, i.e. equivalent to +discarding the result of the operation. + +A two operands instruction variant would be: +@example + .extInstruction mul64, 0x07, 0x2d, SUFFIX_COND, + SYNTAX_2OP|OP1_IMM_IMPLIED +@end example +which describes a two operand instruction with an implicit first +immediate operand. The result of this operation would be discarded. + @end table @node ARC Modifiers diff --git a/gas/testsuite/gas/arc/textinsn-errors.d b/gas/testsuite/gas/arc/textinsn-errors.d new file mode 100644 index 0000000000..b2f4a718d0 --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn-errors.d @@ -0,0 +1 @@ +#error-output: textinsn-errors.err diff --git a/gas/testsuite/gas/arc/textinsn-errors.err b/gas/testsuite/gas/arc/textinsn-errors.err new file mode 100644 index 0000000000..2d9932535e --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn-errors.err @@ -0,0 +1,2 @@ +[^:]*: Assembler messages: +[^:]*:1: Warning: Suffix SUFFIX_COND ignored diff --git a/gas/testsuite/gas/arc/textinsn-errors.s b/gas/testsuite/gas/arc/textinsn-errors.s new file mode 100644 index 0000000000..87417f2d09 --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn-errors.s @@ -0,0 +1 @@ + .extInstruction myinsn0, 0x07, 0x2d, SUFFIX_FLAG|SUFFIX_COND, SYNTAX_2OP diff --git a/gas/testsuite/gas/arc/textinsn2op.d b/gas/testsuite/gas/arc/textinsn2op.d new file mode 100644 index 0000000000..52d52cea2f --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn2op.d @@ -0,0 +1,24 @@ +#objdump: -dr + +.*: +file format .*arc.* + + +Disassembly of section .text: + +[0-9a-f]+ <.text>: + 0: 382f 006d myinsn r0,r1 + 4: 3b2f 372d myinsn fp,sp + 8: 386f 002d myinsn r0,0 + c: 392f 0fad ffff ffff myinsn r1,0xffffffff + 14: 3e2f 70ad myinsn 0,r2 + 18: 3c2f 0fad 0000 00ff myinsn r4,0xff + 20: 3e2f 0fad ffff ff00 myinsn r6,0xffffff00 + 28: 382f 1fad 0000 0100 myinsn r8,0x100 + 30: 392f 1fad ffff feff myinsn r9,0xfffffeff + 38: 3b2f 1fad 4242 4242 myinsn r11,0x42424242 + 40: 382f 0fad 0000 0000 myinsn r0,0 + 44: R_ARC_32_ME foo + 48: 382f 806d myinsn.f r0,r1 + 4c: 3a6f 806d myinsn.f r2,0x1 + 50: 3e2f f12d myinsn.f 0,r4 + 54: 3d2f 8fad 0000 0200 myinsn.f r5,0x200 diff --git a/gas/testsuite/gas/arc/textinsn2op.s b/gas/testsuite/gas/arc/textinsn2op.s new file mode 100644 index 0000000000..ec96c705f7 --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn2op.s @@ -0,0 +1,22 @@ +# Insn 3 .extInstruction test + .extInstruction myinsn, 0x07, 0x2d, SUFFIX_FLAG, SYNTAX_2OP + + myinsn r0,r1 + myinsn fp,sp + + myinsn r0,0 + myinsn r1,-1 + myinsn 0,r2 + myinsn r4,255 + myinsn r6,-256 + + myinsn r8,256 + myinsn r9,-257 + myinsn r11,0x42424242 + + myinsn r0,foo + + myinsn.f r0,r1 + myinsn.f r2,1 + myinsn.f 0,r4 + myinsn.f r5,512 diff --git a/gas/testsuite/gas/arc/textinsn2op01.d b/gas/testsuite/gas/arc/textinsn2op01.d new file mode 100644 index 0000000000..ea14df761c --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn2op01.d @@ -0,0 +1,27 @@ +#objdump: -dr + +.*: +file format .*arc.* + + +Disassembly of section .text: + +[0-9a-f]+ <.text>: + 0: 382d 007e myinsn r0,r1 + 4: 3b2d 373e myinsn fp,sp + 8: 386d 003e myinsn r0,0 + c: 392d 0fbe ffff ffff myinsn r1,0xffffffff + 14: 3eed 7080 0000 0000 myinsn 0,r2 + 1c: 3c2d 0fbe 0000 00ff myinsn r4,0xff + 24: 3e2d 0fbe ffff ff00 myinsn r6,0xffffff00 + 2c: 382d 1fbe 0000 0100 myinsn r8,0x100 + 34: 392d 1fbe ffff feff myinsn r9,0xfffffeff + 3c: 3b2d 1fbe 4242 4242 myinsn r11,0x42424242 + 44: 382d 0fbe 0000 0000 myinsn r0,0 + 48: R_ARC_32_ME foo + 4c: 382d 807e myinsn.f r0,r1 + 50: 3a6d 807e myinsn.f r2,0x1 + 54: 3eed f100 0000 0000 myinsn.f 0,r4 + 5c: 3d2d 8fbe 0000 0200 myinsn.f r5,0x200 + 64: 3eed f102 0000 0000 myinsn.ne.f 0,r4 + 6c: 3eed ff85 dead beef myinsn.c.f 0xdeadbeef,0xdeadbeef + 74: 3eed f0a6 dead beef myinsn.nc.f 0xdeadbeef,0x2 diff --git a/gas/testsuite/gas/arc/textinsn2op01.s b/gas/testsuite/gas/arc/textinsn2op01.s new file mode 100644 index 0000000000..dbd5b24009 --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn2op01.s @@ -0,0 +1,26 @@ +# Insn 2op .extInstruction test + .extInstruction myinsn, 0x07, 0x2d, SUFFIX_FLAG|SUFFIX_COND, SYNTAX_2OP|OP1_IMM_IMPLIED + + myinsn r0,r1 + myinsn fp,sp + + myinsn r0,0 + myinsn r1,-1 + myinsn 0,r2 + myinsn r4,255 + myinsn r6,-256 + + myinsn r8,256 + myinsn r9,-257 + myinsn r11,0x42424242 + + myinsn r0,foo + + myinsn.f r0,r1 + myinsn.f r2,1 + myinsn.f 0,r4 + myinsn.f r5,512 + + myinsn.ne.f 0,r4 + myinsn.c.f 0xdeadbeef, 0xdeadbeef + myinsn.nc.f 0xdeadbeef, 0x02 diff --git a/gas/testsuite/gas/arc/textinsn3op.d b/gas/testsuite/gas/arc/textinsn3op.d new file mode 100644 index 0000000000..abf69ff388 --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn3op.d @@ -0,0 +1,63 @@ +#objdump: -dr + +.*: +file format .*arc.* + + +Disassembly of section .text: + +[0-9a-f]+ <.text>: + 0: 392d 0080 myinsn r0,r1,r2 + 4: 3b2d 371a myinsn gp,fp,sp + 8: 3e2d 37dd myinsn ilink,r30,blink + c: 396d 0000 myinsn r0,r1,0 + 10: 3e2d 7080 0000 0000 myinsn r0,0,r2 + 18: 392d 00be myinsn 0,r1,r2 + 1c: 392d 0f80 ffff ffff myinsn r0,r1,0xffffffff + 24: 3e2d 7080 ffff ffff myinsn r0,0xffffffff,r2 + 2c: 392d 0f80 0000 00ff myinsn r0,r1,0xff + 34: 3e2d 7080 0000 00ff myinsn r0,0xff,r2 + 3c: 392d 0f80 ffff ff00 myinsn r0,r1,0xffffff00 + 44: 3e2d 7080 ffff ff00 myinsn r0,0xffffff00,r2 + 4c: 392d 0f80 0000 0100 myinsn r0,r1,0x100 + 54: 3e2d 7080 ffff feff myinsn r0,0xfffffeff,r2 + 5c: 3e2d 7f80 0000 0100 myinsn r0,0x100,0x100 + 64: 392d 0f80 0000 0000 myinsn r0,r1,0 + 68: R_ARC_32_ME foo + 6c: 38ed 0080 myinsn r0,r0,r2 + 70: 3bed 0140 myinsn r3,r3,r5 + 74: 3eed 0201 myinsn.eq r6,r6,r8 + 78: 39ed 12c1 myinsn.eq r9,r9,r11 + 7c: 3ced 1382 myinsn.ne r12,r12,r14 + 80: 3fed 1442 myinsn.ne r15,r15,r17 + 84: 3aed 2503 myinsn.p r18,r18,r20 + 88: 3ded 25c3 myinsn.p r21,r21,r23 + 8c: 38ed 3684 myinsn.n r24,r24,gp + 90: 3bed 3744 myinsn.n fp,fp,ilink + 94: 3eed 37c5 myinsn.c r30,r30,blink + 98: 3bed 00c5 myinsn.c r3,r3,r3 + 9c: 3bed 0205 myinsn.c r3,r3,r8 + a0: 3bed 0106 myinsn.nc r3,r3,r4 + a4: 3ced 0106 myinsn.nc r4,r4,r4 + a8: 3ced 01c6 myinsn.nc r4,r4,r7 + ac: 3ced 0147 myinsn.v r4,r4,r5 + b0: 3ded 0147 myinsn.v r5,r5,r5 + b4: 3ded 0148 myinsn.nv r5,r5,r5 + b8: 3ded 0148 myinsn.nv r5,r5,r5 + bc: 3eed 0009 myinsn.gt r6,r6,r0 + c0: 38ed 002a myinsn.ge r0,r0,0 + c4: 39ed 006b myinsn.lt r1,r1,0x1 + c8: 3bed 00ed myinsn.hi r3,r3,0x3 + cc: 3ced 012e myinsn.ls r4,r4,0x4 + d0: 3ded 016f myinsn.pnz r5,r5,0x5 + d4: 392d 8080 myinsn.f r0,r1,r2 + d8: 396d 8040 myinsn.f r0,r1,0x1 + dc: 3e2d f080 0000 0001 myinsn.f r0,0x1,r2 + e4: 392d 80be myinsn.f 0,r1,r2 + e8: 392d 8f80 0000 0200 myinsn.f r0,r1,0x200 + f0: 3e2d f080 0000 0200 myinsn.f r0,0x200,r2 + f8: 39ed 8081 myinsn.eq.f r1,r1,r2 + fc: 38ed 8022 myinsn.ne.f r0,r0,0 + 100: 3aed 808b myinsn.lt.f r2,r2,r2 + 104: 3eed f0a9 0000 0001 myinsn.gt.f 0,0x1,0x2 + 10c: 3eed ff8c 0000 0200 myinsn.le.f 0,0x200,0x200 + 114: 3eed f0aa 0000 0200 myinsn.ge.f 0,0x200,0x2 diff --git a/gas/testsuite/gas/arc/textinsn3op.s b/gas/testsuite/gas/arc/textinsn3op.s new file mode 100644 index 0000000000..a07aa9dd20 --- /dev/null +++ b/gas/testsuite/gas/arc/textinsn3op.s @@ -0,0 +1,64 @@ +# Insn 3op .extInstruction test + .extInstruction myinsn, 0x07, 0x2d, SUFFIX_FLAG|SUFFIX_COND, SYNTAX_3OP + + myinsn r0,r1,r2 + myinsn r26,fp,sp + myinsn ilink1,ilink2,blink + + myinsn r0,r1,0 + myinsn r0,0,r2 + myinsn 0,r1,r2 + myinsn r0,r1,-1 + myinsn r0,-1,r2 + myinsn r0,r1,255 + myinsn r0,255,r2 + myinsn r0,r1,-256 + myinsn r0,-256,r2 + + myinsn r0,r1,256 + myinsn r0,-257,r2 + + myinsn r0,256,256 + + myinsn r0,r1,foo + + myinsn.al r0,r0,r2 + myinsn.ra r3,r3,r5 + myinsn.eq r6,r6,r8 + myinsn.z r9,r9,r11 + myinsn.ne r12,r12,r14 + myinsn.nz r15,r15,r17 + myinsn.pl r18,r18,r20 + myinsn.p r21,r21,r23 + myinsn.mi r24,r24,r26 + myinsn.n r27,r27,r29 + myinsn.cs r30,r30,r31 + myinsn.c r3,r3,r3 + myinsn.lo r3,r3,r8 + myinsn.cc r3,r3,r4 + myinsn.nc r4,r4,r4 + myinsn.hs r4,r4,r7 + myinsn.vs r4,r4,r5 + myinsn.v r5,r5,r5 + myinsn.vc r5,r5,r5 + myinsn.nv r5,r5,r5 + myinsn.gt r6,r6,r0 + myinsn.ge r0,r0,0 + myinsn.lt r1,r1,1 + myinsn.hi r3,r3,3 + myinsn.ls r4,r4,4 + myinsn.pnz r5,r5,5 + + myinsn.f r0,r1,r2 + myinsn.f r0,r1,1 + myinsn.f r0,1,r2 + myinsn.f 0,r1,r2 + myinsn.f r0,r1,512 + myinsn.f r0,512,r2 + + myinsn.eq.f r1,r1,r2 + myinsn.ne.f r0,r0,0 + myinsn.lt.f r2,r2,r2 + myinsn.gt.f 0,1,2 + myinsn.le.f 0,512,512 + myinsn.ge.f 0,512,2 diff --git a/include/ChangeLog b/include/ChangeLog index 4b2215fa1c..87333aa679 100644 --- a/include/ChangeLog +++ b/include/ChangeLog @@ -1,30 +1,47 @@ -22016-04-05 Claudiu Zissulescu - - * opcode/arc.h (DPA, DPX, SPX): New subclass enums. - (ARC_FPUDA): Define. - (arc_aux_reg): Add new field. - -016-04-05 Cupertino Miranda +2016-04-12 Claudiu Zissulescu + + * opcode/arc.h (arc_num_opcodes): Remove. + (ARC_SYNTAX_3OP, ARC_SYNTAX_2OP, ARC_OP1_MUST_BE_IMM) + (ARC_OP1_IMM_IMPLIED, ARC_SUFFIX_NONE, ARC_SUFFIX_COND) + (ARC_SUFFIX_FLAG): Define. + (flags_none, flags_f, flags_cc, flags_ccf): Declare. + (arg_none, arg_32bit_rarbrc, arg_32bit_zarbrc, arg_32bit_rbrbrc) + (arg_32bit_rarbu6, arg_32bit_zarbu6, arg_32bit_rbrbu6) + (arg_32bit_rbrbs12, arg_32bit_ralimmrc, arg_32bit_rarblimm) + (arg_32bit_zalimmrc, arg_32bit_zarblimm, arg_32bit_rbrblimm) + (arg_32bit_ralimmu6, arg_32bit_zalimmu6, arg_32bit_zalimms12) + (arg_32bit_ralimmlimm, arg_32bit_zalimmlimm, arg_32bit_rbrc) + (arg_32bit_zarc, arg_32bit_rbu6, arg_32bit_zau6, arg_32bit_rblimm) + (arg_32bit_zalimm, arg_32bit_limmrc, arg_32bit_limmu6) + (arg_32bit_limms12, arg_32bit_limmlimm): Likewise. + +2016-04-05 Claudiu Zissulescu + + * opcode/arc.h (DPA, DPX, SPX): New subclass enums. + (ARC_FPUDA): Define. + (arc_aux_reg): Add new field. + +2016-04-05 Cupertino Miranda * opcode/arc-func.h (replace_bits24): Changed. (replace_bits24_be): Created. 2016-03-29 Claudiu Zissulescu - * opcode/arc.h (insn_subclass_t): Add QUARKSE subclass. - (FIELDA, FIELDB, FIELDC, FIELDF, FIELDQ, INSN3OP, INSN2OP) - (INSN2OP, INSN3OP_ABC, INSN3OP_ALC, INSN3OP_ABL, INSN3OP_ALL) - (INSN3OP_0BC, INSN3OP_0LC, INSN3OP_0BL, INSN3OP_0LL, INSN3OP_ABU) - (INSN3OP_ALU, INSN3OP_0BU, INSN3OP_0LU, INSN3OP_BBS, INSN3OP_0LS) - (INSN3OP_CBBC, INSN3OP_CBBL, INSN3OP_C0LC, INSN3OP_C0LL) - (INSN3OP_CBBU, INSN3OP_C0LU, MINSN3OP_ABC, MINSN3OP_ALC) - (MINSN3OP_ABL, MINSN3OP_ALL, MINSN3OP_0BC, MINSN3OP_0LC) - (MINSN3OP_0BL, MINSN3OP_0LL, MINSN3OP_ABU, MINSN3OP_ALU) - (MINSN3OP_0BU, MINSN3OP_0LU, MINSN3OP_BBS, MINSN3OP_0LS) - (MINSN3OP_CBBC, MINSN3OP_CBBL, MINSN3OP_C0LC, MINSN3OP_C0LL) - (MINSN3OP_CBBU, MINSN3OP_C0LU, INSN2OP_BC, INSN2OP_BL, INSN2OP_0C) - (INSN2OP_0L INSN2OP_BU, INSN2OP_0U, MINSN2OP_BC, MINSN2OP_BL) - (MINSN2OP_0C, MINSN2OP_0L, MINSN2OP_BU, MINSN2OP_0U): Define. + * opcode/arc.h (insn_subclass_t): Add QUARKSE subclass. + (FIELDA, FIELDB, FIELDC, FIELDF, FIELDQ, INSN3OP, INSN2OP) + (INSN2OP, INSN3OP_ABC, INSN3OP_ALC, INSN3OP_ABL, INSN3OP_ALL) + (INSN3OP_0BC, INSN3OP_0LC, INSN3OP_0BL, INSN3OP_0LL, INSN3OP_ABU) + (INSN3OP_ALU, INSN3OP_0BU, INSN3OP_0LU, INSN3OP_BBS, INSN3OP_0LS) + (INSN3OP_CBBC, INSN3OP_CBBL, INSN3OP_C0LC, INSN3OP_C0LL) + (INSN3OP_CBBU, INSN3OP_C0LU, MINSN3OP_ABC, MINSN3OP_ALC) + (MINSN3OP_ABL, MINSN3OP_ALL, MINSN3OP_0BC, MINSN3OP_0LC) + (MINSN3OP_0BL, MINSN3OP_0LL, MINSN3OP_ABU, MINSN3OP_ALU) + (MINSN3OP_0BU, MINSN3OP_0LU, MINSN3OP_BBS, MINSN3OP_0LS) + (MINSN3OP_CBBC, MINSN3OP_CBBL, MINSN3OP_C0LC, MINSN3OP_C0LL) + (MINSN3OP_CBBU, MINSN3OP_C0LU, INSN2OP_BC, INSN2OP_BL, INSN2OP_0C) + (INSN2OP_0L INSN2OP_BU, INSN2OP_0U, MINSN2OP_BC, MINSN2OP_BL) + (MINSN2OP_0C, MINSN2OP_0L, MINSN2OP_BU, MINSN2OP_0U): Define. 2016-03-22 Trevor Saunders @@ -124,8 +141,8 @@ 2016-02-10 Claudiu Zissulescu Janek van Oirschot - * opcode/arc.h (arc_opcode arc_relax_opcodes, arc_num_relax_opcodes): - Declare. + * opcode/arc.h (arc_opcode arc_relax_opcodes) + (arc_num_relax_opcodes): Declare. 2016-02-09 Nick Clifton diff --git a/include/opcode/arc.h b/include/opcode/arc.h index bc0e1ad510..a98a2d6763 100644 --- a/include/opcode/arc.h +++ b/include/opcode/arc.h @@ -130,7 +130,6 @@ struct arc_opcode in the order in which the disassembler should consider instructions. */ extern const struct arc_opcode arc_opcodes[]; -extern const unsigned arc_num_opcodes; /* CPU Availability. */ #define ARC_OPCODE_ARC600 0x0001 /* ARC 600 specific insns. */ @@ -494,4 +493,54 @@ extern const unsigned arc_num_relax_opcodes; #define MINSN2OP_BU (~(FIELDF | FIELDB (63) | FIELDC (63))) #define MINSN2OP_0U (~(FIELDF | FIELDC (63))) +/* Various constants used when defining an extension instruction. */ +#define ARC_SYNTAX_3OP (1 << 0) +#define ARC_SYNTAX_2OP (1 << 1) +#define ARC_OP1_MUST_BE_IMM (1 << 2) +#define ARC_OP1_IMM_IMPLIED (1 << 3) + +#define ARC_SUFFIX_NONE (1 << 0) +#define ARC_SUFFIX_COND (1 << 1) +#define ARC_SUFFIX_FLAG (1 << 2) + + +/* Constants needed to initialize extension instructions. */ +extern const unsigned char flags_none[MAX_INSN_FLGS + 1]; +extern const unsigned char flags_f[MAX_INSN_FLGS + 1]; +extern const unsigned char flags_cc[MAX_INSN_FLGS + 1]; +extern const unsigned char flags_ccf[MAX_INSN_FLGS + 1]; + +extern const unsigned char arg_none[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rarbrc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zarbrc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rbrbrc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rarbu6[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zarbu6[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rbrbu6[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rbrbs12[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_ralimmrc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rarblimm[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zalimmrc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zarblimm[MAX_INSN_ARGS + 1]; + +extern const unsigned char arg_32bit_rbrblimm[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_ralimmu6[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zalimmu6[MAX_INSN_ARGS + 1]; + +extern const unsigned char arg_32bit_zalimms12[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_ralimmlimm[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zalimmlimm[MAX_INSN_ARGS + 1]; + +extern const unsigned char arg_32bit_rbrc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zarc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rbu6[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zau6[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_rblimm[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_zalimm[MAX_INSN_ARGS + 1]; + +extern const unsigned char arg_32bit_limmrc[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_limmu6[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_limms12[MAX_INSN_ARGS + 1]; +extern const unsigned char arg_32bit_limmlimm[MAX_INSN_ARGS + 1]; + #endif /* OPCODE_ARC_H */ diff --git a/opcodes/ChangeLog b/opcodes/ChangeLog index 4d23c24306..4eec5ee9df 100644 --- a/opcodes/ChangeLog +++ b/opcodes/ChangeLog @@ -1,3 +1,34 @@ +2016-04-12 Claudiu Zissulescu + + * arc-opc.c (flags_none, flags_f, flags_cc, flags_ccf): + Initialize. + (arg_none, arg_32bit_rarbrc, arg_32bit_zarbrc, arg_32bit_rbrbrc) + (arg_32bit_rarbu6, arg_32bit_zarbu6, arg_32bit_rbrbu6) + (arg_32bit_rbrbs12, arg_32bit_ralimmrc, arg_32bit_rarblimm) + (arg_32bit_zalimmrc, arg_32bit_zarblimm, arg_32bit_rbrblimm) + (arg_32bit_ralimmu6, arg_32bit_zalimmu6, arg_32bit_zalimms12) + (arg_32bit_ralimmlimm, arg_32bit_zalimmlimm, arg_32bit_rbrc) + (arg_32bit_zarc, arg_32bit_rbu6, arg_32bit_zau6, arg_32bit_rblimm) + (arg_32bit_zalimm, arg_32bit_limmrc, arg_32bit_limmu6) + (arg_32bit_limms12, arg_32bit_limmlimm): Likewise. + (arc_opcode arc_opcodes): Null terminate the array. + (arc_num_opcodes): Remove. + * arc-ext.h (INSERT_XOP): Define. + (extInstruction_t): Likewise. + (arcExtMap_instName): Delete. + (arcExtMap_insn): New function. + (arcExtMap_genOpcode): Likewise. + * arc-ext.c (ExtInstruction): Remove. + (create_map): Zero initialize instruction fields. + (arcExtMap_instName): Remove. + (arcExtMap_insn): New function. + (dump_ARC_extmap): More info while debuging. + (arcExtMap_genOpcode): New function. + * arc-dis.c (find_format): New function. + (print_insn_arc): Use find_format. + (arc_get_disassembler): Enable dump_ARC_extmap only when + debugging. + 2016-04-11 Maciej W. Rozycki * mips-dis.c (print_mips16_insn_arg): Mask unused extended @@ -27,12 +58,12 @@ 2016-04-05 Claudiu Zissulescu - * arc-regs.h: Add a new subclass field. Add double assist - accumulator register values. - * arc-tbl.h: Use DPA subclass to mark the double assist - instructions. Use DPX/SPX subclas to mark the FPX instructions. - * arc-opc.c (RSP): Define instead of SP. - (arc_aux_regs): Add the subclass field. + * arc-regs.h: Add a new subclass field. Add double assist + accumulator register values. + * arc-tbl.h: Use DPA subclass to mark the double assist + instructions. Use DPX/SPX subclas to mark the FPX instructions. + * arc-opc.c (RSP): Define instead of SP. + (arc_aux_regs): Add the subclass field. 2016-04-05 Jiong Wang @@ -50,23 +81,23 @@ 2016-03-30 Claudiu Zissulescu - * arc-regs.h (IC_RAM_ADDRESS, IC_TAG, IC_WP, IC_DATA, CONTROL0) - (AX2, AY2, MX2, MY2, AY0, AY1, DC_RAM_ADDR, DC_TAG, CONTROL1) - (RTT): Remove duplicate. - (LCDINSTR, LCDDATA, LCDSTAT, CC_*, PCT_COUNT*, PCT_SNAP*) - (PCT_CONFIG*): Remove. - (D1L, D1H, D2H, D2L): Define. + * arc-regs.h (IC_RAM_ADDRESS, IC_TAG, IC_WP, IC_DATA, CONTROL0) + (AX2, AY2, MX2, MY2, AY0, AY1, DC_RAM_ADDR, DC_TAG, CONTROL1) + (RTT): Remove duplicate. + (LCDINSTR, LCDDATA, LCDSTAT, CC_*, PCT_COUNT*, PCT_SNAP*) + (PCT_CONFIG*): Remove. + (D1L, D1H, D2H, D2L): Define. 2016-03-29 Claudiu Zissulescu - * arc-ext-tbl.h (dsp_fp_i2flt): Fix typo. + * arc-ext-tbl.h (dsp_fp_i2flt): Fix typo. 2016-03-29 Claudiu Zissulescu - * arc-tbl.h (invld07): Remove. - * arc-ext-tbl.h: New file. - * arc-dis.c (FIELDA, FIELDB, FIELDC): Remove. - * arc-opc.c (arc_opcodes): Add ext-tbl include. + * arc-tbl.h (invld07): Remove. + * arc-ext-tbl.h: New file. + * arc-dis.c (FIELDA, FIELDB, FIELDC): Remove. + * arc-opc.c (arc_opcodes): Add ext-tbl include. 2016-03-24 Jan Kratochvil @@ -164,8 +195,8 @@ 2016-02-10 Claudiu Zissulescu Janek van Oirschot - * arc-opc.c (arc_relax_opcodes, arc_num_relax_opcodes): New - variable. + * arc-opc.c (arc_relax_opcodes, arc_num_relax_opcodes): New + variable. 2016-02-04 Nick Clifton diff --git a/opcodes/arc-dis.c b/opcodes/arc-dis.c index 5f8fa42d85..0a03a0f305 100644 --- a/opcodes/arc-dis.c +++ b/opcodes/arc-dis.c @@ -102,6 +102,107 @@ special_flag_p (const char *opname, return 0; } +/* Find proper format for the given opcode. */ +static const struct arc_opcode * +find_format (const struct arc_opcode *arc_table, + unsigned *insn, int insnLen, + unsigned isa_mask) +{ + unsigned int i = 0; + const struct arc_opcode *opcode = NULL; + const unsigned char *opidx; + const unsigned char *flgidx; + + do { + bfd_boolean invalid = FALSE; + + opcode = &arc_table[i++]; + + if (ARC_SHORT (opcode->mask) && (insnLen == 2)) + { + if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0])) + continue; + } + else if (!ARC_SHORT (opcode->mask) && (insnLen == 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; + + /* Possible candidate, check the operands. */ + for (opidx = opcode->operands; *opidx; opidx++) + { + int value; + const struct arc_operand *operand = &arc_operands[*opidx]; + + if (operand->flags & ARC_OPERAND_FAKE) + continue; + + if (operand->extract) + value = (*operand->extract) (insn[0], &invalid); + else + value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1); + + /* Check for LIMM indicator. If it is there, then make sure + we pick the right format. */ + if (operand->flags & ARC_OPERAND_IR + && !(operand->flags & ARC_OPERAND_LIMM)) + { + if ((value == 0x3E && insnLen == 4) + || (value == 0x1E && insnLen == 2)) + { + invalid = TRUE; + break; + } + } + } + + /* Check the flags. */ + 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 foundA = 0, foundB = 0; + + for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx) + { + const struct arc_flag_operand *flg_operand = + &arc_flag_operands[*flgopridx]; + unsigned int value; + + value = (insn[0] >> flg_operand->shift) + & ((1 << flg_operand->bits) - 1); + if (value == flg_operand->code) + foundA = 1; + if (value) + foundB = 1; + } + if (!foundA && foundB) + { + invalid = TRUE; + break; + } + } + + if (invalid) + continue; + + /* The instruction is valid. */ + return opcode; + } while (opcode->mask); + + return NULL; +} + /* Disassemble ARC instructions. */ static int @@ -111,15 +212,13 @@ print_insn_arc (bfd_vma memaddr, bfd_byte buffer[4]; unsigned int lowbyte, highbyte; int status; - unsigned int i; int insnLen = 0; unsigned insn[2] = { 0, 0 }; unsigned isa_mask; const unsigned char *opidx; const unsigned char *flgidx; const struct arc_opcode *opcode; - const char *instrName; - int flags; + const extInstruction_t *einsn; bfd_boolean need_comma; bfd_boolean open_braket; int size; @@ -218,7 +317,7 @@ print_insn_arc (bfd_vma memaddr, return size; } - if ( (((buffer[lowbyte] & 0xf8) > 0x38) + if ((((buffer[lowbyte] & 0xf8) > 0x38) && ((buffer[lowbyte] & 0xf8) != 0x48)) || ((info->mach == bfd_mach_arc_arcv2) && ((buffer[lowbyte] & 0xF8) == 0x48)) /* FIXME! ugly. */ @@ -254,110 +353,40 @@ print_insn_arc (bfd_vma memaddr, info->disassembler_needs_relocs = TRUE; /* Find the first match in the opcode table. */ - for (i = 0; i < arc_num_opcodes; i++) - { - bfd_boolean invalid = FALSE; + opcode = find_format (arc_opcodes, insn, insnLen, isa_mask); - opcode = &arc_opcodes[i]; - - if (ARC_SHORT (opcode->mask) && (insnLen == 2)) - { - if (OPCODE_AC (opcode->opcode) != OPCODE_AC (insn[0])) - continue; - } - else if (!ARC_SHORT (opcode->mask) && (insnLen == 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; - - /* Possible candidate, check the operands. */ - for (opidx = opcode->operands; *opidx; opidx++) + if (!opcode) + { + /* No instruction found. Try the extensions. */ + einsn = arcExtMap_insn (OPCODE (insn[0]), insn[0]); + if (einsn) { - int value; - const struct arc_operand *operand = &arc_operands[*opidx]; - - if (operand->flags & ARC_OPERAND_FAKE) - continue; - - if (operand->extract) - value = (*operand->extract) (insn[0], &invalid); - else - value = (insn[0] >> operand->shift) & ((1 << operand->bits) - 1); - - /* Check for LIMM indicator. If it is there, then make sure - we pick the right format. */ - if (operand->flags & ARC_OPERAND_IR - && !(operand->flags & ARC_OPERAND_LIMM)) + const char *errmsg = NULL; + opcode = arcExtMap_genOpcode (einsn, isa_mask, &errmsg); + if (opcode == NULL) { - if ((value == 0x3E && insnLen == 4) - || (value == 0x1E && insnLen == 2)) - { - invalid = TRUE; - break; - } + (*info->fprintf_func) (info->stream, + "An error occured while " + "generating the extension instruction " + "operations"); + return -1; } - } - /* Check the flags. */ - for (flgidx = opcode->flags; *flgidx; flgidx++) + opcode = find_format (opcode, insn, insnLen, isa_mask); + assert (opcode != NULL); + } + else { - /* Get a valid flag class. */ - const struct arc_flag_class *cl_flags = &arc_flag_classes[*flgidx]; - const unsigned *flgopridx; - int foundA = 0, foundB = 0; + if (insnLen == 2) + (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]); + else + (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]); - for (flgopridx = cl_flags->flags; *flgopridx; ++flgopridx) - { - const struct arc_flag_operand *flg_operand = &arc_flag_operands[*flgopridx]; - unsigned int value; - - value = (insn[0] >> flg_operand->shift) & ((1 << flg_operand->bits) - 1); - if (value == flg_operand->code) - foundA = 1; - if (value) - foundB = 1; - } - if (!foundA && foundB) - { - invalid = TRUE; - break; - } + info->insn_type = dis_noninsn; + return insnLen; } - - if (invalid) - continue; - - /* The instruction is valid. */ - goto found; } - /* No instruction found. Try the extenssions. */ - instrName = arcExtMap_instName (OPCODE (insn[0]), insn[0], &flags); - if (instrName) - { - opcode = &arc_opcodes[0]; - (*info->fprintf_func) (info->stream, "%s", instrName); - goto print_flags; - } - - if (insnLen == 2) - (*info->fprintf_func) (info->stream, ".long %#04x", insn[0]); - else - (*info->fprintf_func) (info->stream, ".long %#08x", insn[0]); - - info->insn_type = dis_noninsn; - return insnLen; - - found: /* Print the mnemonic. */ (*info->fprintf_func) (info->stream, "%s", opcode->name); @@ -382,7 +411,6 @@ print_insn_arc (bfd_vma memaddr, pr_debug ("%s: 0x%08x\n", opcode->name, opcode->opcode); - print_flags: /* Now extract and print the flags. */ for (flgidx = opcode->flags; *flgidx; flgidx++) { @@ -557,7 +585,9 @@ arc_get_disassembler (bfd *abfd) { /* Read the extenssion insns and registers, if any. */ build_ARC_extmap (abfd); +#ifdef DEBUG dump_ARC_extmap (); +#endif return print_insn_arc; } diff --git a/opcodes/arc-ext.c b/opcodes/arc-ext.c index 52f455639e..45734a0832 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; +} diff --git a/opcodes/arc-ext.h b/opcodes/arc-ext.h index 9c2f4b7374..fcce7e2bd4 100644 --- a/opcodes/arc-ext.h +++ b/opcodes/arc-ext.h @@ -39,13 +39,14 @@ #ifndef ARC_EXTENSIONS_H #define ARC_EXTENSIONS_H +#include "opcode/arc.h" + #define IGNORE_FIRST_OPD 1 /* Define this if we do not want to encode instructions based on the ARCompact Programmer's Reference. */ #define UNMANGLED - /* This defines the kinds of extensions which may be read from the ections in the executable files. */ enum ExtOperType @@ -63,7 +64,6 @@ enum ExtOperType EXT_CORE_REGISTER_CLASS = 9 }; - enum ExtReadWrite { REG_INVALID, @@ -72,6 +72,48 @@ enum ExtReadWrite REG_READWRITE }; +/* Macro used when generating the patterns for an extension + instruction. */ +#define INSERT_XOP(OP, NAME, CODE, MASK, CPU, ARG, FLG) \ + do { \ + (OP)->name = NAME; \ + (OP)->opcode = CODE; \ + (OP)->mask = MASK; \ + (OP)->cpu = CPU; \ + (OP)->class = ARITH; \ + (OP)->subclass = NONE; \ + memcpy ((OP)->operands, (ARG), MAX_INSN_ARGS); \ + memcpy ((OP)->flags, (FLG), MAX_INSN_FLGS); \ + (OP++); \ + } while (0) + +/* Typedef to hold the extension instruction definition. */ +typedef struct ExtInstruction +{ + /* Name. */ + char *name; + + /* Major opcode. */ + char major; + + /* Minor(sub) opcode. */ + char minor; + + /* Flags, holds the syntax class and modifiers. */ + char flags; + + /* Syntax class. Use by assembler. */ + unsigned char syntax; + + /* Syntax class modifier. Used by assembler. */ + unsigned char modsyn; + + /* Suffix class. Used by assembler. */ + unsigned char suffix; + + /* Pointer to the next extension instruction. */ + struct ExtInstruction* next; +} extInstruction_t; /* Constructor function. */ extern void build_ARC_extmap (bfd *); @@ -81,7 +123,10 @@ extern enum ExtReadWrite arcExtMap_coreReadWrite (int); extern const char * arcExtMap_coreRegName (int); extern const char * arcExtMap_auxRegName (long); extern const char * arcExtMap_condCodeName (int); -extern const char * arcExtMap_instName (int, int, int *); +extern const extInstruction_t *arcExtMap_insn (int, int); +extern struct arc_opcode *arcExtMap_genOpcode (const extInstruction_t *, + unsigned arc_target, + const char **errmsg); /* Dump function (for debugging). */ extern void dump_ARC_extmap (void); diff --git a/opcodes/arc-opc.c b/opcodes/arc-opc.c index d667a78d65..028b80bfb5 100644 --- a/opcodes/arc-opc.c +++ b/opcodes/arc-opc.c @@ -1136,6 +1136,11 @@ const struct arc_flag_class arc_flag_classes[] = }; +const unsigned char flags_none[] = { 0 }; +const unsigned char flags_f[] = { C_F }; +const unsigned char flags_cc[] = { C_CC }; +const unsigned char flags_ccf[] = { C_CC, C_F }; + /* The operands table. The format of the operands table is: @@ -1499,6 +1504,39 @@ const unsigned arc_num_operands = ARRAY_SIZE (arc_operands); const unsigned arc_Toperand = FKT_T; const unsigned arc_NToperand = FKT_NT; +const unsigned char arg_none[] = { 0 }; +const unsigned char arg_32bit_rarbrc[] = { RA, RB, RC }; +const unsigned char arg_32bit_zarbrc[] = { ZA, RB, RC }; +const unsigned char arg_32bit_rbrbrc[] = { RB, RBdup, RC }; +const unsigned char arg_32bit_rarbu6[] = { RA, RB, UIMM6_20 }; +const unsigned char arg_32bit_zarbu6[] = { ZA, RB, UIMM6_20 }; +const unsigned char arg_32bit_rbrbu6[] = { RB, RBdup, UIMM6_20 }; +const unsigned char arg_32bit_rbrbs12[] = { RB, RBdup, SIMM12_20 }; +const unsigned char arg_32bit_ralimmrc[] = { RA, LIMM, RC }; +const unsigned char arg_32bit_rarblimm[] = { RA, RB, LIMM }; +const unsigned char arg_32bit_zalimmrc[] = { ZA, LIMM, RC }; +const unsigned char arg_32bit_zarblimm[] = { ZA, RB, LIMM }; + +const unsigned char arg_32bit_rbrblimm[] = { RB, RBdup, LIMM }; +const unsigned char arg_32bit_ralimmu6[] = { RA, LIMM, UIMM6_20 }; +const unsigned char arg_32bit_zalimmu6[] = { ZA, LIMM, UIMM6_20 }; + +const unsigned char arg_32bit_zalimms12[] = { ZA, LIMM, SIMM12_20 }; +const unsigned char arg_32bit_ralimmlimm[] = { RA, LIMM, LIMMdup }; +const unsigned char arg_32bit_zalimmlimm[] = { ZA, LIMM, LIMMdup }; + +const unsigned char arg_32bit_rbrc[] = { RB, RC }; +const unsigned char arg_32bit_zarc[] = { ZA, RC }; +const unsigned char arg_32bit_rbu6[] = { RB, UIMM6_20 }; +const unsigned char arg_32bit_zau6[] = { ZA, UIMM6_20 }; +const unsigned char arg_32bit_rblimm[] = { RB, LIMM }; +const unsigned char arg_32bit_zalimm[] = { ZA, LIMM }; + +const unsigned char arg_32bit_limmrc[] = { LIMM, RC }; +const unsigned char arg_32bit_limmu6[] = { LIMM, UIMM6_20 }; +const unsigned char arg_32bit_limms12[] = { LIMM, SIMM12_20 }; +const unsigned char arg_32bit_limmlimm[] = { LIMM, LIMMdup }; + /* The opcode table. The format of the opcode table is: @@ -1539,9 +1577,9 @@ const struct arc_opcode arc_opcodes[] = #include "arc-tbl.h" #include "arc-nps400-tbl.h" #include "arc-ext-tbl.h" -}; -const unsigned arc_num_opcodes = ARRAY_SIZE (arc_opcodes); + { NULL, 0, 0, 0, 0, 0, { 0 }, { 0 } } +}; /* List with special cases instructions and the applicable flags. */ const struct arc_flag_special arc_flag_special_cases[] = -- 2.34.1