This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Thumb32 assembler (60/69)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Tue, 26 Apr 2005 03:01:44 -0700
- Subject: Thumb32 assembler (60/69)
Another pass of rearrangement and function renames.
zw
* config/tc-arm.c: Another general reorganization. Move parser
functions used only (transitively) from parse_operands to just above
parse_operands. Move all encoding subroutines just above all
per-instruction encoding routines. Move Thumb encoding routines below
all ARM-format encoding routines.
Rename all parse functions to begin with parse_, except
my_get_expression. Rename all encoding subroutines encode_arm_*
instead of encode_*_arm.
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c (revision 62)
+++ gas/config/tc-arm.c (revision 63)
@@ -502,7 +502,6 @@
/* Pointer to a linked list of literal pools. */
literal_pool * list_of_pools = NULL;
-
/* Pure syntax. */
/* This array holds the chars that always start a comment. If the
@@ -742,97 +741,6 @@
return 0;
}
-/* Returns the pseudo-register number of an FPA immediate constant,
- or FAIL if there isn't a valid constant here. */
-
-static int
-fpa_immediate (char ** str)
-{
- LITTLENUM_TYPE words[MAX_LITTLENUMS];
- char * save_in;
- expressionS exp;
- int i;
- int j;
-
- /* First try and match exact strings, this is to guarantee
- that some formats will work even for cross assembly. */
-
- for (i = 0; fp_const[i]; i++)
- {
- if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
- {
- char *start = *str;
-
- *str += strlen (fp_const[i]);
- if (is_end_of_line[(unsigned char) **str])
- return i + 8;
- *str = start;
- }
- }
-
- /* Just because we didn't get a match doesn't mean that the constant
- isn't valid, just that it is in a format that we don't
- automatically recognize. Try parsing it with the standard
- expression routines. */
-
- memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
-
- /* Look for a raw floating point number. */
- if ((save_in = atof_ieee (*str, 'x', words)) != NULL
- && is_end_of_line[(unsigned char) *save_in])
- {
- for (i = 0; i < NUM_FLOAT_VALS; i++)
- {
- for (j = 0; j < MAX_LITTLENUMS; j++)
- {
- if (words[j] != fp_values[i][j])
- break;
- }
-
- if (j == MAX_LITTLENUMS)
- {
- *str = save_in;
- return i + 8;
- }
- }
- }
-
- /* Try and parse a more complex expression, this will probably fail
- unless the code uses a floating point prefix (eg "0f"). */
- save_in = input_line_pointer;
- input_line_pointer = *str;
- if (expression (&exp) == absolute_section
- && exp.X_op == O_big
- && exp.X_add_number < 0)
- {
- /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
- Ditto for 15. */
- if (gen_to_words (words, 5, (long) 15) == 0)
- {
- for (i = 0; i < NUM_FLOAT_VALS; i++)
- {
- for (j = 0; j < MAX_LITTLENUMS; j++)
- {
- if (words[j] != fp_values[i][j])
- break;
- }
-
- if (j == MAX_LITTLENUMS)
- {
- *str = input_line_pointer;
- input_line_pointer = save_in;
- return i + 8;
- }
- }
- }
- }
-
- *str = input_line_pointer;
- input_line_pointer = save_in;
- inst.error = _("invalid FPA immediate expression");
- return FAIL;
-}
-
/* We handle all bad expressions here, so that we can report the faulty
instruction in the error message. */
void
@@ -844,38 +752,11 @@
/* Immediate values. */
-/* Generic immediate-value read function for use in insn parsing.
- STR points to the beginning of the immediate (the leading #);
- VAL receives the value; if the value is outside [MIN, MAX]
- issue an error. PREFIX_OPT is true if the immediate prefix is
- optional. */
+/* Generic immediate-value read function for use in directives.
+ Accepts anything that 'expression' can fold to a constant.
+ *val receives the number. */
static int
-immediate_required_here (char **str, int *val, int min, int max,
- bfd_boolean prefix_opt)
-{
- expressionS exp;
- my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX);
- if (exp.X_op != O_constant)
- {
- inst.error = _("constant expression required");
- return FAIL;
- }
-
- if (exp.X_add_number < min || exp.X_add_number > max)
- {
- inst.error = _("immediate value out of range");
- return FAIL;
- }
-
- *val = exp.X_add_number;
- return SUCCESS;
-}
-
-/* As above, but for use in directives, and does not provide
- range checking. */
-
-static int
immediate_for_directive (int *val)
{
expressionS exp;
@@ -897,24 +778,6 @@
return SUCCESS;
}
-#define rotate_left(v, n) (v << n | v >> (32 - n))
-
-/* If VAL can be encoded in the immediate field of an ARM instruction,
- return the encoded form. Otherwise, return FAIL. */
-
-static unsigned int
-encode_immediate_arm (unsigned int val)
-{
- unsigned int a;
- unsigned int i;
-
- for (i = 0; i < 32; i += 2)
- if ((a = rotate_left (val, i)) <= 0xff)
- return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */
-
- return FAIL;
-}
-
/* Register parsing. */
/* Generic register parser. CCP points to what should be the
@@ -997,34 +860,9 @@
return FAIL;
}
-/* Encode a VFP SP register number into inst.instruction. */
-
-static void
-vfp_sp_encode_reg (int reg, enum vfp_sp_reg_pos pos)
-{
- switch (pos)
- {
- case VFP_REG_Sd:
- inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
- break;
-
- case VFP_REG_Sn:
- inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
- break;
-
- case VFP_REG_Sm:
- inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
- break;
-
- default:
- abort ();
- }
-}
-
-/* Register lists. */
-
+/* Parse an ARM register list. Returns the bitmask, or FAIL. */
static long
-reg_list (char ** strp)
+parse_reg_list (char ** strp)
{
char * str = * strp;
long range = 0;
@@ -1152,7 +990,7 @@
register. Double precision registers are matched if DP is nonzero. */
static int
-vfp_parse_reg_list (char **str, int *pbase, int dp)
+parse_vfp_reg_list (char **str, int *pbase, int dp)
{
int base_reg;
int new_base;
@@ -1263,217 +1101,6 @@
return count;
}
-/* Shift operands. */
-enum shift_kind
-{
- SHIFT_LSL, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX
-};
-
-struct asm_shift_name
-{
- const char *name;
- enum shift_kind kind;
-};
-
-/* Third argument to parse_shift. */
-enum parse_shift_mode
-{
- NO_SHIFT_RESTRICT, /* Any kind of shift is accepted. */
- SHIFT_IMMEDIATE, /* Shift operand must be an immediate. */
- SHIFT_LSL_OR_ASR_IMMEDIATE, /* Shift must be LSL or ASR immediate. */
- SHIFT_ASR_IMMEDIATE, /* Shift must be ASR immediate. */
- SHIFT_LSL_IMMEDIATE, /* Shift must be LSL immediate. */
-};
-
-/* Parse a <shift> specifier on an ARM data processing instruction.
- This has three forms:
-
- (LSL|LSR|ASL|ASR|ROR) Rs
- (LSL|LSR|ASL|ASR|ROR) #imm
- RRX
-
- Note that ASL is assimilated to LSL in the instruction encoding, and
- RRX to ROR #0 (which cannot be written as such). */
-
-static int
-parse_shift (char **str, int i, enum parse_shift_mode mode)
-{
- const struct asm_shift_name *shift_name;
- enum shift_kind shift;
- char *s = *str;
- char *p = s;
- int reg;
-
- for (p = *str; ISALPHA (*p); p++)
- ;
-
- if (p == *str)
- {
- inst.error = _("shift expression expected");
- return FAIL;
- }
-
- shift_name = hash_find_n (arm_shift_hsh, *str, p - *str);
-
- if (shift_name == NULL)
- {
- inst.error = _("shift expression expected");
- return FAIL;
- }
-
- shift = shift_name->kind;
-
- switch (mode)
- {
- case NO_SHIFT_RESTRICT:
- case SHIFT_IMMEDIATE: break;
-
- case SHIFT_LSL_OR_ASR_IMMEDIATE:
- if (shift != SHIFT_LSL && shift != SHIFT_ASR)
- {
- inst.error = _("'LSL' or 'ASR' required");
- return FAIL;
- }
- break;
-
- case SHIFT_LSL_IMMEDIATE:
- if (shift != SHIFT_LSL)
- {
- inst.error = _("'LSL' required");
- return FAIL;
- }
- break;
-
- case SHIFT_ASR_IMMEDIATE:
- if (shift != SHIFT_ASR)
- {
- inst.error = _("'ASR' required");
- return FAIL;
- }
- break;
-
- default: abort ();
- }
-
- if (shift != SHIFT_RRX)
- {
- /* Whitespace can appear here if the next thing is a bare digit. */
- skip_whitespace (p);
-
- if (mode == NO_SHIFT_RESTRICT
- && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
- {
- inst.operands[i].imm = reg;
- inst.operands[i].immisreg = 1;
- }
- else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
- return FAIL;
- }
- inst.operands[i].shift_kind = shift;
- inst.operands[i].shifted = 1;
- *str = p;
- return SUCCESS;
-}
-
-/* Encode a <shift> in an ARM-format instruction. The immediate,
- if any, is handled by md_apply_fix3. */
-static void
-encode_shift_arm (int i)
-{
- if (inst.operands[i].shift_kind == SHIFT_RRX)
- inst.instruction |= SHIFT_ROR << 5;
- else
- {
- inst.instruction |= inst.operands[i].shift_kind << 5;
- if (inst.operands[i].immisreg)
- {
- inst.instruction |= SHIFT_BY_REG;
- inst.instruction |= inst.operands[i].imm << 8;
- }
- else
- inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
- }
-}
-
-/* Parse a <shifter_operand> for an ARM data processing instruction:
-
- #<immediate>
- #<immediate>, <rotate>
- <Rm>
- <Rm>, <shift>
-
- where <shift> is defined by parse_shift above, and <rotate> is a
- multiple of 2 between 0 and 30. Validation of immediate operands
- is deferred to md_apply_fix3. */
-
-static int
-parse_shifter_operand (char **str, int i)
-{
- int value;
- expressionS expr;
-
- if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL)
- {
- inst.operands[i].reg = value;
- inst.operands[i].isreg = 1;
-
- if (skip_past_comma (str) == FAIL)
- return SUCCESS;
-
- /* Shift operation on register. */
- return parse_shift (str, i, NO_SHIFT_RESTRICT);
- }
-
- if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
- return FAIL;
-
- if (skip_past_comma (str) == SUCCESS)
- {
- /* #x, y -- ie explicit rotation by Y. */
- if (my_get_expression (&expr, str, GE_NO_PREFIX))
- return FAIL;
-
- if (expr.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
- {
- inst.error = _("constant expression expected");
- return FAIL;
- }
-
- value = expr.X_add_number;
- if (value < 0 || value > 30 || value % 2 != 0)
- {
- inst.error = _("invalid rotation");
- return FAIL;
- }
- if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
- {
- inst.error = _("invalid constant");
- return FAIL;
- }
-
- /* Convert to decoded value. md_apply_fix3 will put it back. */
- inst.reloc.exp.X_add_number
- = (((inst.reloc.exp.X_add_number << (32 - value))
- | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
- }
-
- inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
- inst.reloc.pc_rel = 0;
- return SUCCESS;
-}
-
-static void
-encode_shifter_operand_arm (int i)
-{
- if (inst.operands[i].isreg)
- {
- inst.instruction |= inst.operands[i].reg;
- encode_shift_arm (i);
- }
- else
- inst.instruction |= INST_IMMEDIATE;
-}
-
/* Parse an explicit relocation suffix on an expression. This is
either nothing, or a word in parentheses. Note that if !OBJ_ELF,
arm_reloc_hsh contains no entries, so this function can only
@@ -1503,497 +1130,6 @@
return r->reloc;
}
-/* Parse all forms of an ARM address expression. Information is written
- to inst.operands[i] and/or inst.reloc.
-
- Preindexed addressing (.preind=1):
-
- [Rn, #offset] .reg=Rn .reloc.exp=offset
- [Rn, +/-Rm] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
- [Rn, +/-Rm, shift] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
- .shift_kind=shift .reloc.exp=shift_imm
-
- These three may have a trailing ! which causes .writeback to be set also.
-
- Postindexed addressing (.postind=1, .writeback=1):
-
- [Rn], #offset .reg=Rn .reloc.exp=offset
- [Rn], +/-Rm .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
- [Rn], +/-Rm, shift .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
- .shift_kind=shift .reloc.exp=shift_imm
-
- Unindexed addressing (.preind=0, .postind=0):
-
- [Rn], {option} .reg=Rn .imm=option .immisreg=0
-
- Other:
-
- [Rn]{!} shorthand for [Rn,#0]{!}
- =immediate .isreg=0 .reloc.exp=immediate
- label .reg=PC .reloc.pc_rel=1 .reloc.exp=label
-
- It is the caller's responsibility to check for addressing modes not
- supported by the instruction, and to set inst.reloc.type. */
-
-static int
-parse_address (char **str, int i)
-{
- char *p = *str;
- int reg;
-
- if (skip_past_char (&p, '[') == FAIL)
- {
- if (skip_past_char (&p, '=') == FAIL)
- {
- /* bare address - translate to PC-relative offset */
- inst.reloc.pc_rel = 1;
- inst.operands[i].reg = REG_PC;
- inst.operands[i].isreg = 1;
- inst.operands[i].preind = 1;
- }
- /* else a load-constant pseudo op, no special treatment needed here */
-
- if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
- return FAIL;
-
- *str = p;
- return SUCCESS;
- }
-
- if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
- {
- inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
- return FAIL;
- }
- inst.operands[i].reg = reg;
- inst.operands[i].isreg = 1;
-
- if (skip_past_comma (&p) == SUCCESS)
- {
- inst.operands[i].preind = 1;
-
- if (*p == '+') p++;
- else if (*p == '-') p++, inst.operands[i].negative = 1;
-
- if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
- {
- inst.operands[i].imm = reg;
- inst.operands[i].immisreg = 1;
-
- if (skip_past_comma (&p) == SUCCESS)
- if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
- return FAIL;
- }
- else
- {
- if (inst.operands[i].negative)
- {
- inst.operands[i].negative = 0;
- p--;
- }
- if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
- return FAIL;
- }
- }
-
- if (skip_past_char (&p, ']') == FAIL)
- {
- inst.error = _("']' expected");
- return FAIL;
- }
-
- if (skip_past_char (&p, '!') == SUCCESS)
- inst.operands[i].writeback = 1;
-
- else if (skip_past_comma (&p) == SUCCESS)
- {
- if (skip_past_char (&p, '{') == SUCCESS)
- {
- /* [Rn], {expr} - unindexed, with option */
- if (immediate_required_here (&p, &inst.operands[i].imm,
- 0, 255, TRUE) == FAIL)
- return FAIL;
-
- if (skip_past_char (&p, '}') == FAIL)
- {
- inst.error = _("'}' expected at end of 'option' field");
- return FAIL;
- }
- if (inst.operands[i].preind)
- {
- inst.error = _("cannot combine index with option");
- return FAIL;
- }
- *str = p;
- return SUCCESS;
- }
- else
- {
- inst.operands[i].postind = 1;
- inst.operands[i].writeback = 1;
-
- if (inst.operands[i].preind)
- {
- inst.error = _("cannot combine pre- and post-indexing");
- return FAIL;
- }
-
- if (*p == '+') p++;
- else if (*p == '-') p++, inst.operands[i].negative = 1;
-
- if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
- {
- inst.operands[i].imm = reg;
- inst.operands[i].immisreg = 1;
-
- if (skip_past_comma (&p) == SUCCESS)
- if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
- return FAIL;
- }
- else
- {
- if (inst.operands[i].negative)
- {
- inst.operands[i].negative = 0;
- p--;
- }
- if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
- return FAIL;
- }
- }
- }
-
- /* If at this point neither .preind nor .postind is set, we have a
- bare [Rn]{!}, which is shorthand for [Rn,#0]{!}. */
- if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
- {
- inst.operands[i].preind = 1;
- inst.reloc.exp.X_op = O_constant;
- inst.reloc.exp.X_add_number = 0;
- }
- *str = p;
- return SUCCESS;
-}
-
-/* Miscellaneous: PSR flags, endian specifiers, coprocessor
- operands. */
-
-/* Parse a PSR flag operand. The value returned is FAIL on syntax error,
- or a bitmask suitable to be or-ed into the ARM msr instruction. */
-static int
-parse_psr (char **str)
-{
- char *p;
- unsigned long psr_field;
-
- /* CPSR's and SPSR's can now be lowercase. This is just a convenience
- feature for ease of use and backwards compatibility. */
- p = *str;
- if (*p == 's' || *p == 'S')
- psr_field = SPSR_BIT;
- else if (*p == 'c' || *p == 'C')
- psr_field = 0;
- else
- goto error;
-
- p++;
- if (strncasecmp (p, "PSR", 3) != 0)
- goto error;
- p += 3;
-
- if (*p == '_')
- {
- /* A suffix follows. */
- const struct asm_psr *psr;
- char *start;
-
- p++;
- start = p;
-
- do
- p++;
- while (ISALNUM (*p) || *p == '_');
-
- psr = hash_find_n (arm_psr_hsh, start, p - start);
- if (!psr)
- goto error;
-
- psr_field |= psr->field;
- }
- else
- {
- if (ISALNUM (*p))
- goto error; /* Garbage after "[CS]PSR". */
-
- psr_field |= (PSR_c | PSR_f);
- }
- *str = p;
- return psr_field;
-
- error:
- inst.error = _("flag for {c}psr instruction expected");
- return FAIL;
-}
-
-/* Subroutine of encode_addr_mode_2_arm and encode_addr_mode_3_arm. */
-static void
-encode_addr_mode_common_arm (int i, bfd_boolean is_t)
-{
- assert (inst.operands[i].isreg);
- inst.instruction |= inst.operands[i].reg << 16;
-
- if (inst.operands[i].preind)
- {
- if (is_t)
- {
- inst.error = _("instruction does not accept preindexed addressing");
- return;
- }
- inst.instruction |= PRE_INDEX;
- if (inst.operands[i].writeback)
- inst.instruction |= WRITE_BACK;
-
- }
- else if (inst.operands[i].postind)
- {
- assert (inst.operands[i].writeback);
- if (is_t)
- inst.instruction |= WRITE_BACK;
- }
- else /* unindexed - only for coprocessor */
- {
- inst.error = _("instruction does not accept unindexed addressing");
- return;
- }
-
- if (((inst.instruction & WRITE_BACK) || !(inst.instruction & PRE_INDEX))
- && (((inst.instruction & 0x000f0000) >> 16)
- == ((inst.instruction & 0x0000f000) >> 12)))
- as_warn ((inst.instruction & LOAD_BIT)
- ? _("destination register same as write-back base")
- : _("source register same as write-back base"));
-}
-
-/* inst.operands[i] was set up by parse_address. Encode it into an
- ARM-format mode 2 load or store instruction. If is_t is true,
- reject forms that cannot be used with a T instruction (i.e. not
- post-indexed). */
-static void
-encode_addr_mode_2_arm (int i, bfd_boolean is_t)
-{
- encode_addr_mode_common_arm (i, is_t);
-
- if (inst.operands[i].immisreg)
- {
- inst.instruction |= INST_IMMEDIATE; /* yes, this is backwards */
- inst.instruction |= inst.operands[i].imm;
- if (!inst.operands[i].negative)
- inst.instruction |= INDEX_UP;
- if (inst.operands[i].shifted)
- {
- if (inst.operands[i].shift_kind == SHIFT_RRX)
- inst.instruction |= SHIFT_ROR << 5;
- else
- {
- inst.instruction |= inst.operands[i].shift_kind << 5;
- inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
- }
- }
- }
- else /* immediate offset in inst.reloc */
- {
- if (inst.reloc.type == BFD_RELOC_UNUSED)
- inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
- if (inst.reloc.pc_rel)
- inst.reloc.exp.X_add_number -= 8; /* pipeline offset */
- }
-}
-
-/* inst.operands[i] was set up by parse_address. Encode it into an
- ARM-format mode 3 load or store instruction. Reject forms that
- cannot be used with such instructions. If is_t is true, reject
- forms that cannot be used with a T instruction (i.e. not
- post-indexed). */
-static void
-encode_addr_mode_3_arm (int i, bfd_boolean is_t)
-{
- if (inst.operands[i].immisreg && inst.operands[i].shifted)
- {
- inst.error = _("instruction does not accept scaled register index");
- return;
- }
-
- encode_addr_mode_common_arm (i, is_t);
-
- if (inst.operands[i].immisreg)
- {
- inst.instruction |= inst.operands[i].imm;
- if (!inst.operands[i].negative)
- inst.instruction |= INDEX_UP;
- }
- else /* immediate offset in inst.reloc */
- {
- inst.instruction |= HWOFFSET_IMM;
- if (inst.reloc.type == BFD_RELOC_UNUSED)
- inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
- if (inst.reloc.pc_rel)
- inst.reloc.exp.X_add_number -= 8; /* pipeline offset */
- }
-}
-
-/* inst.operands[i] was set up by parse_address. Encode it into an
- ARM-format instruction. Reject all forms which cannot be encoded
- into a coprocessor load/store instruction. If wb_ok is false,
- reject use of writeback; if unind_ok is false, reject use of
- unindexed addressing. If reloc_override is not 0, use it instead
- of BFD_ARM_CP_OFF_IMM. */
-
-static int
-encode_cp_address_arm (int i, int wb_ok, int unind_ok, int reloc_override)
-{
- inst.instruction |= inst.operands[i].reg << 16;
-
- assert (!(inst.operands[i].preind && inst.operands[i].postind));
-
- if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
- {
- assert (!inst.operands[i].writeback);
- if (!unind_ok)
- {
- inst.error = _("instruction does not support unindexed addressing");
- return FAIL;
- }
- inst.instruction |= inst.operands[i].imm;
- inst.instruction |= INDEX_UP;
- return SUCCESS;
- }
-
- if (inst.operands[i].preind)
- inst.instruction |= PRE_INDEX;
-
- if (inst.operands[i].writeback)
- {
- if (inst.operands[i].reg == REG_PC)
- {
- inst.error = _("pc may not be used with write-back");
- return FAIL;
- }
- if (!wb_ok)
- {
- inst.error = _("instruction does not support writeback");
- return FAIL;
- }
- inst.instruction |= WRITE_BACK;
- }
-
- if (reloc_override)
- inst.reloc.type = reloc_override;
- else
- inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
- if (inst.reloc.pc_rel)
- inst.reloc.exp.X_add_number -= 8;
- return SUCCESS;
-}
-
-/* Parse the flags argument to CPSI[ED]. Returns FAIL on error, or a
- value suitable for splatting into the AIF field of the instruction. */
-
-static int
-parse_cps_flags (char **str)
-{
- int val = 0;
- int saw_a_flag = 0;
- char *s = *str;
-
- for (;;)
- switch (*s++)
- {
- case '\0': case ',':
- goto done;
-
- case 'a': case 'A': saw_a_flag = 1; val |= 0x4; break;
- case 'i': case 'I': saw_a_flag = 1; val |= 0x2; break;
- case 'f': case 'F': saw_a_flag = 1; val |= 0x1; break;
-
- default:
- inst.error = _("unrecognized CPS flag");
- return FAIL;
- }
-
- done:
- if (saw_a_flag == 0)
- {
- inst.error = _("missing CPS flags");
- return FAIL;
- }
-
- *str = s - 1;
- return val;
-}
-
-/* Parse an endian specifier ("BE" or "LE", case insensitive);
- returns 0 for big-endian, 1 for little-endian, FAIL for an error. */
-
-static int
-parse_endian_specifier (char **str)
-{
- int little_endian;
- char *s = *str;
-
- if (strncasecmp (s, "BE", 2))
- little_endian = 0;
- else if (strncasecmp (s, "LE", 2))
- little_endian = 1;
- else
- {
- inst.error = _("valid endian specifiers are be or le");
- return FAIL;
- }
-
- if (ISALNUM (s[2]) || s[2] == '_')
- {
- inst.error = _("valid endian specifiers are be or le");
- return FAIL;
- }
-
- *str = s + 2;
- return little_endian;
-}
-
-/* Parse a rotation specifier: ROR #0, #8, #16, #24. *val receives a
- value suitable for poking into the rotate field of an sxt or sxta
- instruction, or FAIL on error. */
-
-static int
-parse_ror (char **str)
-{
- int rot;
- char *s = *str;
-
- if (strncasecmp (s, "ROR", 3) == 0)
- s += 3;
- else
- {
- inst.error = _("missing rotation field after comma");
- return FAIL;
- }
-
- if (immediate_required_here (&s, &rot, 0, 24, FALSE) == FAIL)
- return FAIL;
-
- switch (rot)
- {
- case 0: *str = s; return 0x0;
- case 8: *str = s; return 0x1;
- case 16: *str = s; return 0x2;
- case 24: *str = s; return 0x3;
-
- default:
- inst.error = _("rotation can only be 0, 8, 16, or 24");
- return FAIL;
- }
-}
-
/* Directives: register aliases. */
static void
@@ -2686,81 +1822,6 @@
return SUCCESS;
}
-/* inst.reloc.exp describes an "=expr" load pseudo-operation.
- Determine whether it can be performed with a move instruction; if
- it can, convert inst.instruction to that move instruction and
- return 1; if it can't, convert inst.instruction to a literal-pool
- load and return 0. If this is not a valid thing to do in the
- current context, set inst.error and return 1.
-
- inst.operands[i] describes the destination register. */
-
-static int
-move_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3)
-{
- if ((inst.instruction & (thumb_p ? THUMB_LOAD_BIT : LOAD_BIT)) == 0)
- {
- inst.error = _("invalid pseudo operation");
- return 1;
- }
- if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol)
- {
- inst.error = _("constant expression expected");
- return 1;
- }
- if (inst.reloc.exp.X_op == O_constant)
- {
- if (thumb_p)
- {
- if ((inst.reloc.exp.X_add_number & ~0xFF) == 0)
- {
- /* This can be done with a mov instruction. */
- inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
- inst.instruction |= inst.reloc.exp.X_add_number;
- return 1;
- }
- }
- else
- {
- int value = encode_immediate_arm (inst.reloc.exp.X_add_number);
- if (value != FAIL)
- {
- /* This can be done with a mov instruction. */
- inst.instruction &= LITERAL_MASK;
- inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
- inst.instruction |= value & 0xfff;
- return 1;
- }
-
- value = encode_immediate_arm (~inst.reloc.exp.X_add_number);
- if (value != FAIL)
- {
- /* This can be done with a mvn instruction. */
- inst.instruction &= LITERAL_MASK;
- inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
- inst.instruction |= value & 0xfff;
- return 1;
- }
- }
- }
-
- if (add_to_lit_pool () == FAIL)
- {
- inst.error = _("literal pool insertion failed");
- return 1;
- }
- inst.operands[1].reg = REG_PC;
- inst.operands[1].isreg = 1;
- inst.operands[1].preind = 1;
- inst.reloc.pc_rel = 1;
- inst.reloc.type = (thumb_p
- ? BFD_RELOC_ARM_THUMB_OFFSET
- : (mode_3
- ? BFD_RELOC_ARM_HWLITERAL
- : BFD_RELOC_ARM_LITERAL));
- return 0;
-}
-
/* Can't use symbol_new here, so have to create a symbol and then at
a later date assign it a value. Thats what these functions do. */
@@ -3123,7 +2184,7 @@
long range;
int n;
- range = reg_list (&input_line_pointer);
+ range = parse_reg_list (&input_line_pointer);
if (range == FAIL)
{
as_bad (_("expected register list"));
@@ -3245,7 +2306,7 @@
int reg;
valueT op;
- count = vfp_parse_reg_list (&input_line_pointer, ®, 1);
+ count = parse_vfp_reg_list (&input_line_pointer, ®, 1);
if (count == FAIL)
{
as_bad (_("expected register list"));
@@ -3740,7 +2801,637 @@
{ 0, 0, 0 }
};
-/* Matcher codes for operand_parse. */
+/* Parser functions used exclusively in instruction operands. */
+
+/* Generic immediate-value read function for use in insn parsing.
+ STR points to the beginning of the immediate (the leading #);
+ VAL receives the value; if the value is outside [MIN, MAX]
+ issue an error. PREFIX_OPT is true if the immediate prefix is
+ optional. */
+
+static int
+parse_immediate (char **str, int *val, int min, int max,
+ bfd_boolean prefix_opt)
+{
+ expressionS exp;
+ my_get_expression (&exp, str, prefix_opt ? GE_OPT_PREFIX : GE_IMM_PREFIX);
+ if (exp.X_op != O_constant)
+ {
+ inst.error = _("constant expression required");
+ return FAIL;
+ }
+
+ if (exp.X_add_number < min || exp.X_add_number > max)
+ {
+ inst.error = _("immediate value out of range");
+ return FAIL;
+ }
+
+ *val = exp.X_add_number;
+ return SUCCESS;
+}
+
+/* Returns the pseudo-register number of an FPA immediate constant,
+ or FAIL if there isn't a valid constant here. */
+
+static int
+parse_fpa_immediate (char ** str)
+{
+ LITTLENUM_TYPE words[MAX_LITTLENUMS];
+ char * save_in;
+ expressionS exp;
+ int i;
+ int j;
+
+ /* First try and match exact strings, this is to guarantee
+ that some formats will work even for cross assembly. */
+
+ for (i = 0; fp_const[i]; i++)
+ {
+ if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
+ {
+ char *start = *str;
+
+ *str += strlen (fp_const[i]);
+ if (is_end_of_line[(unsigned char) **str])
+ return i + 8;
+ *str = start;
+ }
+ }
+
+ /* Just because we didn't get a match doesn't mean that the constant
+ isn't valid, just that it is in a format that we don't
+ automatically recognize. Try parsing it with the standard
+ expression routines. */
+
+ memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
+
+ /* Look for a raw floating point number. */
+ if ((save_in = atof_ieee (*str, 'x', words)) != NULL
+ && is_end_of_line[(unsigned char) *save_in])
+ {
+ for (i = 0; i < NUM_FLOAT_VALS; i++)
+ {
+ for (j = 0; j < MAX_LITTLENUMS; j++)
+ {
+ if (words[j] != fp_values[i][j])
+ break;
+ }
+
+ if (j == MAX_LITTLENUMS)
+ {
+ *str = save_in;
+ return i + 8;
+ }
+ }
+ }
+
+ /* Try and parse a more complex expression, this will probably fail
+ unless the code uses a floating point prefix (eg "0f"). */
+ save_in = input_line_pointer;
+ input_line_pointer = *str;
+ if (expression (&exp) == absolute_section
+ && exp.X_op == O_big
+ && exp.X_add_number < 0)
+ {
+ /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
+ Ditto for 15. */
+ if (gen_to_words (words, 5, (long) 15) == 0)
+ {
+ for (i = 0; i < NUM_FLOAT_VALS; i++)
+ {
+ for (j = 0; j < MAX_LITTLENUMS; j++)
+ {
+ if (words[j] != fp_values[i][j])
+ break;
+ }
+
+ if (j == MAX_LITTLENUMS)
+ {
+ *str = input_line_pointer;
+ input_line_pointer = save_in;
+ return i + 8;
+ }
+ }
+ }
+ }
+
+ *str = input_line_pointer;
+ input_line_pointer = save_in;
+ inst.error = _("invalid FPA immediate expression");
+ return FAIL;
+}
+
+/* Shift operands. */
+enum shift_kind
+{
+ SHIFT_LSL, SHIFT_LSR, SHIFT_ASR, SHIFT_ROR, SHIFT_RRX
+};
+
+struct asm_shift_name
+{
+ const char *name;
+ enum shift_kind kind;
+};
+
+/* Third argument to parse_shift. */
+enum parse_shift_mode
+{
+ NO_SHIFT_RESTRICT, /* Any kind of shift is accepted. */
+ SHIFT_IMMEDIATE, /* Shift operand must be an immediate. */
+ SHIFT_LSL_OR_ASR_IMMEDIATE, /* Shift must be LSL or ASR immediate. */
+ SHIFT_ASR_IMMEDIATE, /* Shift must be ASR immediate. */
+ SHIFT_LSL_IMMEDIATE, /* Shift must be LSL immediate. */
+};
+
+/* Parse a <shift> specifier on an ARM data processing instruction.
+ This has three forms:
+
+ (LSL|LSR|ASL|ASR|ROR) Rs
+ (LSL|LSR|ASL|ASR|ROR) #imm
+ RRX
+
+ Note that ASL is assimilated to LSL in the instruction encoding, and
+ RRX to ROR #0 (which cannot be written as such). */
+
+static int
+parse_shift (char **str, int i, enum parse_shift_mode mode)
+{
+ const struct asm_shift_name *shift_name;
+ enum shift_kind shift;
+ char *s = *str;
+ char *p = s;
+ int reg;
+
+ for (p = *str; ISALPHA (*p); p++)
+ ;
+
+ if (p == *str)
+ {
+ inst.error = _("shift expression expected");
+ return FAIL;
+ }
+
+ shift_name = hash_find_n (arm_shift_hsh, *str, p - *str);
+
+ if (shift_name == NULL)
+ {
+ inst.error = _("shift expression expected");
+ return FAIL;
+ }
+
+ shift = shift_name->kind;
+
+ switch (mode)
+ {
+ case NO_SHIFT_RESTRICT:
+ case SHIFT_IMMEDIATE: break;
+
+ case SHIFT_LSL_OR_ASR_IMMEDIATE:
+ if (shift != SHIFT_LSL && shift != SHIFT_ASR)
+ {
+ inst.error = _("'LSL' or 'ASR' required");
+ return FAIL;
+ }
+ break;
+
+ case SHIFT_LSL_IMMEDIATE:
+ if (shift != SHIFT_LSL)
+ {
+ inst.error = _("'LSL' required");
+ return FAIL;
+ }
+ break;
+
+ case SHIFT_ASR_IMMEDIATE:
+ if (shift != SHIFT_ASR)
+ {
+ inst.error = _("'ASR' required");
+ return FAIL;
+ }
+ break;
+
+ default: abort ();
+ }
+
+ if (shift != SHIFT_RRX)
+ {
+ /* Whitespace can appear here if the next thing is a bare digit. */
+ skip_whitespace (p);
+
+ if (mode == NO_SHIFT_RESTRICT
+ && (reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
+ {
+ inst.operands[i].imm = reg;
+ inst.operands[i].immisreg = 1;
+ }
+ else if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+ return FAIL;
+ }
+ inst.operands[i].shift_kind = shift;
+ inst.operands[i].shifted = 1;
+ *str = p;
+ return SUCCESS;
+}
+
+/* Parse a <shifter_operand> for an ARM data processing instruction:
+
+ #<immediate>
+ #<immediate>, <rotate>
+ <Rm>
+ <Rm>, <shift>
+
+ where <shift> is defined by parse_shift above, and <rotate> is a
+ multiple of 2 between 0 and 30. Validation of immediate operands
+ is deferred to md_apply_fix3. */
+
+static int
+parse_shifter_operand (char **str, int i)
+{
+ int value;
+ expressionS expr;
+
+ if ((value = arm_reg_parse (str, REG_TYPE_RN)) != FAIL)
+ {
+ inst.operands[i].reg = value;
+ inst.operands[i].isreg = 1;
+
+ if (skip_past_comma (str) == FAIL)
+ return SUCCESS;
+
+ /* Shift operation on register. */
+ return parse_shift (str, i, NO_SHIFT_RESTRICT);
+ }
+
+ if (my_get_expression (&inst.reloc.exp, str, GE_IMM_PREFIX))
+ return FAIL;
+
+ if (skip_past_comma (str) == SUCCESS)
+ {
+ /* #x, y -- ie explicit rotation by Y. */
+ if (my_get_expression (&expr, str, GE_NO_PREFIX))
+ return FAIL;
+
+ if (expr.X_op != O_constant || inst.reloc.exp.X_op != O_constant)
+ {
+ inst.error = _("constant expression expected");
+ return FAIL;
+ }
+
+ value = expr.X_add_number;
+ if (value < 0 || value > 30 || value % 2 != 0)
+ {
+ inst.error = _("invalid rotation");
+ return FAIL;
+ }
+ if (inst.reloc.exp.X_add_number < 0 || inst.reloc.exp.X_add_number > 255)
+ {
+ inst.error = _("invalid constant");
+ return FAIL;
+ }
+
+ /* Convert to decoded value. md_apply_fix3 will put it back. */
+ inst.reloc.exp.X_add_number
+ = (((inst.reloc.exp.X_add_number << (32 - value))
+ | (inst.reloc.exp.X_add_number >> value)) & 0xffffffff);
+ }
+
+ inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
+ inst.reloc.pc_rel = 0;
+ return SUCCESS;
+}
+
+/* Parse all forms of an ARM address expression. Information is written
+ to inst.operands[i] and/or inst.reloc.
+
+ Preindexed addressing (.preind=1):
+
+ [Rn, #offset] .reg=Rn .reloc.exp=offset
+ [Rn, +/-Rm] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
+ [Rn, +/-Rm, shift] .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
+ .shift_kind=shift .reloc.exp=shift_imm
+
+ These three may have a trailing ! which causes .writeback to be set also.
+
+ Postindexed addressing (.postind=1, .writeback=1):
+
+ [Rn], #offset .reg=Rn .reloc.exp=offset
+ [Rn], +/-Rm .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
+ [Rn], +/-Rm, shift .reg=Rn .imm=Rm .immisreg=1 .negative=0/1
+ .shift_kind=shift .reloc.exp=shift_imm
+
+ Unindexed addressing (.preind=0, .postind=0):
+
+ [Rn], {option} .reg=Rn .imm=option .immisreg=0
+
+ Other:
+
+ [Rn]{!} shorthand for [Rn,#0]{!}
+ =immediate .isreg=0 .reloc.exp=immediate
+ label .reg=PC .reloc.pc_rel=1 .reloc.exp=label
+
+ It is the caller's responsibility to check for addressing modes not
+ supported by the instruction, and to set inst.reloc.type. */
+
+static int
+parse_address (char **str, int i)
+{
+ char *p = *str;
+ int reg;
+
+ if (skip_past_char (&p, '[') == FAIL)
+ {
+ if (skip_past_char (&p, '=') == FAIL)
+ {
+ /* bare address - translate to PC-relative offset */
+ inst.reloc.pc_rel = 1;
+ inst.operands[i].reg = REG_PC;
+ inst.operands[i].isreg = 1;
+ inst.operands[i].preind = 1;
+ }
+ /* else a load-constant pseudo op, no special treatment needed here */
+
+ if (my_get_expression (&inst.reloc.exp, &p, GE_NO_PREFIX))
+ return FAIL;
+
+ *str = p;
+ return SUCCESS;
+ }
+
+ if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
+ {
+ inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
+ return FAIL;
+ }
+ inst.operands[i].reg = reg;
+ inst.operands[i].isreg = 1;
+
+ if (skip_past_comma (&p) == SUCCESS)
+ {
+ inst.operands[i].preind = 1;
+
+ if (*p == '+') p++;
+ else if (*p == '-') p++, inst.operands[i].negative = 1;
+
+ if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
+ {
+ inst.operands[i].imm = reg;
+ inst.operands[i].immisreg = 1;
+
+ if (skip_past_comma (&p) == SUCCESS)
+ if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (inst.operands[i].negative)
+ {
+ inst.operands[i].negative = 0;
+ p--;
+ }
+ if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+ return FAIL;
+ }
+ }
+
+ if (skip_past_char (&p, ']') == FAIL)
+ {
+ inst.error = _("']' expected");
+ return FAIL;
+ }
+
+ if (skip_past_char (&p, '!') == SUCCESS)
+ inst.operands[i].writeback = 1;
+
+ else if (skip_past_comma (&p) == SUCCESS)
+ {
+ if (skip_past_char (&p, '{') == SUCCESS)
+ {
+ /* [Rn], {expr} - unindexed, with option */
+ if (parse_immediate (&p, &inst.operands[i].imm,
+ 0, 255, TRUE) == FAIL)
+ return FAIL;
+
+ if (skip_past_char (&p, '}') == FAIL)
+ {
+ inst.error = _("'}' expected at end of 'option' field");
+ return FAIL;
+ }
+ if (inst.operands[i].preind)
+ {
+ inst.error = _("cannot combine index with option");
+ return FAIL;
+ }
+ *str = p;
+ return SUCCESS;
+ }
+ else
+ {
+ inst.operands[i].postind = 1;
+ inst.operands[i].writeback = 1;
+
+ if (inst.operands[i].preind)
+ {
+ inst.error = _("cannot combine pre- and post-indexing");
+ return FAIL;
+ }
+
+ if (*p == '+') p++;
+ else if (*p == '-') p++, inst.operands[i].negative = 1;
+
+ if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) != FAIL)
+ {
+ inst.operands[i].imm = reg;
+ inst.operands[i].immisreg = 1;
+
+ if (skip_past_comma (&p) == SUCCESS)
+ if (parse_shift (&p, i, SHIFT_IMMEDIATE) == FAIL)
+ return FAIL;
+ }
+ else
+ {
+ if (inst.operands[i].negative)
+ {
+ inst.operands[i].negative = 0;
+ p--;
+ }
+ if (my_get_expression (&inst.reloc.exp, &p, GE_IMM_PREFIX))
+ return FAIL;
+ }
+ }
+ }
+
+ /* If at this point neither .preind nor .postind is set, we have a
+ bare [Rn]{!}, which is shorthand for [Rn,#0]{!}. */
+ if (inst.operands[i].preind == 0 && inst.operands[i].postind == 0)
+ {
+ inst.operands[i].preind = 1;
+ inst.reloc.exp.X_op = O_constant;
+ inst.reloc.exp.X_add_number = 0;
+ }
+ *str = p;
+ return SUCCESS;
+}
+
+/* Miscellaneous. */
+
+/* Parse a PSR flag operand. The value returned is FAIL on syntax error,
+ or a bitmask suitable to be or-ed into the ARM msr instruction. */
+static int
+parse_psr (char **str)
+{
+ char *p;
+ unsigned long psr_field;
+
+ /* CPSR's and SPSR's can now be lowercase. This is just a convenience
+ feature for ease of use and backwards compatibility. */
+ p = *str;
+ if (*p == 's' || *p == 'S')
+ psr_field = SPSR_BIT;
+ else if (*p == 'c' || *p == 'C')
+ psr_field = 0;
+ else
+ goto error;
+
+ p++;
+ if (strncasecmp (p, "PSR", 3) != 0)
+ goto error;
+ p += 3;
+
+ if (*p == '_')
+ {
+ /* A suffix follows. */
+ const struct asm_psr *psr;
+ char *start;
+
+ p++;
+ start = p;
+
+ do
+ p++;
+ while (ISALNUM (*p) || *p == '_');
+
+ psr = hash_find_n (arm_psr_hsh, start, p - start);
+ if (!psr)
+ goto error;
+
+ psr_field |= psr->field;
+ }
+ else
+ {
+ if (ISALNUM (*p))
+ goto error; /* Garbage after "[CS]PSR". */
+
+ psr_field |= (PSR_c | PSR_f);
+ }
+ *str = p;
+ return psr_field;
+
+ error:
+ inst.error = _("flag for {c}psr instruction expected");
+ return FAIL;
+}
+
+/* Parse the flags argument to CPSI[ED]. Returns FAIL on error, or a
+ value suitable for splatting into the AIF field of the instruction. */
+
+static int
+parse_cps_flags (char **str)
+{
+ int val = 0;
+ int saw_a_flag = 0;
+ char *s = *str;
+
+ for (;;)
+ switch (*s++)
+ {
+ case '\0': case ',':
+ goto done;
+
+ case 'a': case 'A': saw_a_flag = 1; val |= 0x4; break;
+ case 'i': case 'I': saw_a_flag = 1; val |= 0x2; break;
+ case 'f': case 'F': saw_a_flag = 1; val |= 0x1; break;
+
+ default:
+ inst.error = _("unrecognized CPS flag");
+ return FAIL;
+ }
+
+ done:
+ if (saw_a_flag == 0)
+ {
+ inst.error = _("missing CPS flags");
+ return FAIL;
+ }
+
+ *str = s - 1;
+ return val;
+}
+
+/* Parse an endian specifier ("BE" or "LE", case insensitive);
+ returns 0 for big-endian, 1 for little-endian, FAIL for an error. */
+
+static int
+parse_endian_specifier (char **str)
+{
+ int little_endian;
+ char *s = *str;
+
+ if (strncasecmp (s, "BE", 2))
+ little_endian = 0;
+ else if (strncasecmp (s, "LE", 2))
+ little_endian = 1;
+ else
+ {
+ inst.error = _("valid endian specifiers are be or le");
+ return FAIL;
+ }
+
+ if (ISALNUM (s[2]) || s[2] == '_')
+ {
+ inst.error = _("valid endian specifiers are be or le");
+ return FAIL;
+ }
+
+ *str = s + 2;
+ return little_endian;
+}
+
+/* Parse a rotation specifier: ROR #0, #8, #16, #24. *val receives a
+ value suitable for poking into the rotate field of an sxt or sxta
+ instruction, or FAIL on error. */
+
+static int
+parse_ror (char **str)
+{
+ int rot;
+ char *s = *str;
+
+ if (strncasecmp (s, "ROR", 3) == 0)
+ s += 3;
+ else
+ {
+ inst.error = _("missing rotation field after comma");
+ return FAIL;
+ }
+
+ if (parse_immediate (&s, &rot, 0, 24, FALSE) == FAIL)
+ return FAIL;
+
+ switch (rot)
+ {
+ case 0: *str = s; return 0x0;
+ case 8: *str = s; return 0x1;
+ case 16: *str = s; return 0x2;
+ case 24: *str = s; return 0x3;
+
+ default:
+ inst.error = _("rotation can only be 0, 8, 16, or 24");
+ return FAIL;
+ }
+}
+
+/* Matcher codes for parse_operands. */
enum operand_parse_code
{
OP_stop, /* end of line */
@@ -3853,10 +3544,10 @@
inst.operands[i].isreg = 1; \
} while (0)
-#define po_imm_or_fail(min, max, popt) do { \
- if (immediate_required_here (&str, &val, min, max, popt) == FAIL) \
- goto failure; \
- inst.operands[i].imm = val; \
+#define po_imm_or_fail(min, max, popt) do { \
+ if (parse_immediate (&str, &val, min, max, popt) == FAIL) \
+ goto failure; \
+ inst.operands[i].imm = val; \
} while (0)
#define po_misc_or_fail(expr) do { \
@@ -4001,11 +3692,11 @@
if (!is_immediate_prefix (*str))
goto bad_args;
str++;
- val = fpa_immediate (&str);
+ val = parse_fpa_immediate (&str);
if (val == FAIL)
goto failure;
/* FPA immediates are encoded as registers 8-15.
- fpa_immediate has already applied the offset. */
+ parse_fpa_immediate has already applied the offset. */
inst.operands[i].reg = val;
inst.operands[i].isreg = 1;
break;
@@ -4032,7 +3723,7 @@
/* Register lists */
case OP_REGLST:
- val = reg_list (&str);
+ val = parse_reg_list (&str);
if (*str == '^')
{
inst.operands[1].writeback = 1;
@@ -4041,11 +3732,11 @@
break;
case OP_VRSLST:
- val = vfp_parse_reg_list (&str, &inst.operands[i].reg, 0);
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, 0);
break;
case OP_VRDLST:
- val = vfp_parse_reg_list (&str, &inst.operands[i].reg, 1);
+ val = parse_vfp_reg_list (&str, &inst.operands[i].reg, 1);
break;
/* Addressing modes */
@@ -4132,7 +3823,6 @@
#undef po_reg_or_fail
#undef po_reg_or_goto
#undef po_imm_or_fail
-
/* Shorthand macro for instruction encoding functions issuing errors. */
#define constraint(expr, err) do { \
@@ -4143,6 +3833,317 @@
} \
} while (0)
+/* Functions for operand encoding. ARM, then Thumb. */
+
+#define rotate_left(v, n) (v << n | v >> (32 - n))
+
+/* If VAL can be encoded in the immediate field of an ARM instruction,
+ return the encoded form. Otherwise, return FAIL. */
+
+static unsigned int
+encode_arm_immediate (unsigned int val)
+{
+ unsigned int a;
+ unsigned int i;
+
+ for (i = 0; i < 32; i += 2)
+ if ((a = rotate_left (val, i)) <= 0xff)
+ return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */
+
+ return FAIL;
+}
+
+/* Encode a VFP SP register number into inst.instruction. */
+
+static void
+encode_arm_vfp_sp_reg (int reg, enum vfp_sp_reg_pos pos)
+{
+ switch (pos)
+ {
+ case VFP_REG_Sd:
+ inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
+ break;
+
+ case VFP_REG_Sn:
+ inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
+ break;
+
+ case VFP_REG_Sm:
+ inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
+ break;
+
+ default:
+ abort ();
+ }
+}
+
+/* Encode a <shift> in an ARM-format instruction. The immediate,
+ if any, is handled by md_apply_fix3. */
+static void
+encode_arm_shift (int i)
+{
+ if (inst.operands[i].shift_kind == SHIFT_RRX)
+ inst.instruction |= SHIFT_ROR << 5;
+ else
+ {
+ inst.instruction |= inst.operands[i].shift_kind << 5;
+ if (inst.operands[i].immisreg)
+ {
+ inst.instruction |= SHIFT_BY_REG;
+ inst.instruction |= inst.operands[i].imm << 8;
+ }
+ else
+ inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+ }
+}
+
+static void
+encode_arm_shifter_operand (int i)
+{
+ if (inst.operands[i].isreg)
+ {
+ inst.instruction |= inst.operands[i].reg;
+ encode_arm_shift (i);
+ }
+ else
+ inst.instruction |= INST_IMMEDIATE;
+}
+
+/* Subroutine of encode_arm_addr_mode_2 and encode_arm_addr_mode_3. */
+static void
+encode_arm_addr_mode_common (int i, bfd_boolean is_t)
+{
+ assert (inst.operands[i].isreg);
+ inst.instruction |= inst.operands[i].reg << 16;
+
+ if (inst.operands[i].preind)
+ {
+ if (is_t)
+ {
+ inst.error = _("instruction does not accept preindexed addressing");
+ return;
+ }
+ inst.instruction |= PRE_INDEX;
+ if (inst.operands[i].writeback)
+ inst.instruction |= WRITE_BACK;
+
+ }
+ else if (inst.operands[i].postind)
+ {
+ assert (inst.operands[i].writeback);
+ if (is_t)
+ inst.instruction |= WRITE_BACK;
+ }
+ else /* unindexed - only for coprocessor */
+ {
+ inst.error = _("instruction does not accept unindexed addressing");
+ return;
+ }
+
+ if (((inst.instruction & WRITE_BACK) || !(inst.instruction & PRE_INDEX))
+ && (((inst.instruction & 0x000f0000) >> 16)
+ == ((inst.instruction & 0x0000f000) >> 12)))
+ as_warn ((inst.instruction & LOAD_BIT)
+ ? _("destination register same as write-back base")
+ : _("source register same as write-back base"));
+}
+
+/* inst.operands[i] was set up by parse_address. Encode it into an
+ ARM-format mode 2 load or store instruction. If is_t is true,
+ reject forms that cannot be used with a T instruction (i.e. not
+ post-indexed). */
+static void
+encode_arm_addr_mode_2 (int i, bfd_boolean is_t)
+{
+ encode_arm_addr_mode_common (i, is_t);
+
+ if (inst.operands[i].immisreg)
+ {
+ inst.instruction |= INST_IMMEDIATE; /* yes, this is backwards */
+ inst.instruction |= inst.operands[i].imm;
+ if (!inst.operands[i].negative)
+ inst.instruction |= INDEX_UP;
+ if (inst.operands[i].shifted)
+ {
+ if (inst.operands[i].shift_kind == SHIFT_RRX)
+ inst.instruction |= SHIFT_ROR << 5;
+ else
+ {
+ inst.instruction |= inst.operands[i].shift_kind << 5;
+ inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
+ }
+ }
+ }
+ else /* immediate offset in inst.reloc */
+ {
+ if (inst.reloc.type == BFD_RELOC_UNUSED)
+ inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
+ if (inst.reloc.pc_rel)
+ inst.reloc.exp.X_add_number -= 8; /* pipeline offset */
+ }
+}
+
+/* inst.operands[i] was set up by parse_address. Encode it into an
+ ARM-format mode 3 load or store instruction. Reject forms that
+ cannot be used with such instructions. If is_t is true, reject
+ forms that cannot be used with a T instruction (i.e. not
+ post-indexed). */
+static void
+encode_arm_addr_mode_3 (int i, bfd_boolean is_t)
+{
+ if (inst.operands[i].immisreg && inst.operands[i].shifted)
+ {
+ inst.error = _("instruction does not accept scaled register index");
+ return;
+ }
+
+ encode_arm_addr_mode_common (i, is_t);
+
+ if (inst.operands[i].immisreg)
+ {
+ inst.instruction |= inst.operands[i].imm;
+ if (!inst.operands[i].negative)
+ inst.instruction |= INDEX_UP;
+ }
+ else /* immediate offset in inst.reloc */
+ {
+ inst.instruction |= HWOFFSET_IMM;
+ if (inst.reloc.type == BFD_RELOC_UNUSED)
+ inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
+ if (inst.reloc.pc_rel)
+ inst.reloc.exp.X_add_number -= 8; /* pipeline offset */
+ }
+}
+
+/* inst.operands[i] was set up by parse_address. Encode it into an
+ ARM-format instruction. Reject all forms which cannot be encoded
+ into a coprocessor load/store instruction. If wb_ok is false,
+ reject use of writeback; if unind_ok is false, reject use of
+ unindexed addressing. If reloc_override is not 0, use it instead
+ of BFD_ARM_CP_OFF_IMM. */
+
+static int
+encode_arm_cp_address (int i, int wb_ok, int unind_ok, int reloc_override)
+{
+ inst.instruction |= inst.operands[i].reg << 16;
+
+ assert (!(inst.operands[i].preind && inst.operands[i].postind));
+
+ if (!inst.operands[i].preind && !inst.operands[i].postind) /* unindexed */
+ {
+ assert (!inst.operands[i].writeback);
+ if (!unind_ok)
+ {
+ inst.error = _("instruction does not support unindexed addressing");
+ return FAIL;
+ }
+ inst.instruction |= inst.operands[i].imm;
+ inst.instruction |= INDEX_UP;
+ return SUCCESS;
+ }
+
+ if (inst.operands[i].preind)
+ inst.instruction |= PRE_INDEX;
+
+ if (inst.operands[i].writeback)
+ {
+ if (inst.operands[i].reg == REG_PC)
+ {
+ inst.error = _("pc may not be used with write-back");
+ return FAIL;
+ }
+ if (!wb_ok)
+ {
+ inst.error = _("instruction does not support writeback");
+ return FAIL;
+ }
+ inst.instruction |= WRITE_BACK;
+ }
+
+ if (reloc_override)
+ inst.reloc.type = reloc_override;
+ else
+ inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
+ if (inst.reloc.pc_rel)
+ inst.reloc.exp.X_add_number -= 8;
+ return SUCCESS;
+}
+
+/* inst.reloc.exp describes an "=expr" load pseudo-operation.
+ Determine whether it can be performed with a move instruction; if
+ it can, convert inst.instruction to that move instruction and
+ return 1; if it can't, convert inst.instruction to a literal-pool
+ load and return 0. If this is not a valid thing to do in the
+ current context, set inst.error and return 1.
+
+ inst.operands[i] describes the destination register. */
+
+static int
+move_or_literal_pool (int i, bfd_boolean thumb_p, bfd_boolean mode_3)
+{
+ if ((inst.instruction & (thumb_p ? THUMB_LOAD_BIT : LOAD_BIT)) == 0)
+ {
+ inst.error = _("invalid pseudo operation");
+ return 1;
+ }
+ if (inst.reloc.exp.X_op != O_constant && inst.reloc.exp.X_op != O_symbol)
+ {
+ inst.error = _("constant expression expected");
+ return 1;
+ }
+ if (inst.reloc.exp.X_op == O_constant)
+ {
+ if (thumb_p)
+ {
+ if ((inst.reloc.exp.X_add_number & ~0xFF) == 0)
+ {
+ /* This can be done with a mov instruction. */
+ inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[i].reg << 8);
+ inst.instruction |= inst.reloc.exp.X_add_number;
+ return 1;
+ }
+ }
+ else
+ {
+ int value = encode_arm_immediate (inst.reloc.exp.X_add_number);
+ if (value != FAIL)
+ {
+ /* This can be done with a mov instruction. */
+ inst.instruction &= LITERAL_MASK;
+ inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
+ inst.instruction |= value & 0xfff;
+ return 1;
+ }
+
+ value = encode_arm_immediate (~inst.reloc.exp.X_add_number);
+ if (value != FAIL)
+ {
+ /* This can be done with a mvn instruction. */
+ inst.instruction &= LITERAL_MASK;
+ inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
+ inst.instruction |= value & 0xfff;
+ return 1;
+ }
+ }
+ }
+
+ if (add_to_lit_pool () == FAIL)
+ {
+ inst.error = _("literal pool insertion failed");
+ return 1;
+ }
+ inst.operands[1].reg = REG_PC;
+ inst.operands[1].isreg = 1;
+ inst.operands[1].preind = 1;
+ inst.reloc.pc_rel = 1;
+ inst.reloc.type = (thumb_p
+ ? BFD_RELOC_ARM_THUMB_OFFSET
+ : (mode_3
+ ? BFD_RELOC_ARM_HWLITERAL
+ : BFD_RELOC_ARM_LITERAL));
+ return 0;
+}
+
/* Functions for instruction encoding, sorted by subarchitecture.
First some generics; their names are taken from the conventional
bit positions for register arguments in ARM format instructions. */
@@ -4213,7 +4214,7 @@
do_rd_cpaddr (void)
{
inst.instruction |= inst.operands[0].reg << 12;
- encode_cp_address_arm (1, TRUE, TRUE, 0);
+ encode_arm_cp_address (1, TRUE, TRUE, 0);
}
/* ARM instructions, in alphabetical order by function name (except
@@ -4264,7 +4265,7 @@
inst.operands[1].reg = inst.operands[0].reg;
inst.instruction |= inst.operands[0].reg << 12;
inst.instruction |= inst.operands[1].reg << 16;
- encode_shifter_operand_arm (2);
+ encode_arm_shifter_operand (2);
}
static void
@@ -4418,7 +4419,7 @@
do_cmp (void)
{
inst.instruction |= inst.operands[0].reg << 16;
- encode_shifter_operand_arm (1);
+ encode_arm_shifter_operand (1);
}
/* Transfer between coprocessor and ARM registers.
@@ -4524,7 +4525,7 @@
constraint (inst.operands[0].reg == REG_LR, _("r14 not allowed here"));
if (inst.instruction & LOAD_BIT)
{
- /* encode_addr_mode_3_arm will diagnose overlap between the base
+ /* encode_arm_addr_mode_3 will diagnose overlap between the base
register and the first register written; we have to diagnose
overlap between the base and the second register written here. */
@@ -4542,7 +4543,7 @@
}
inst.instruction |= inst.operands[0].reg << 12;
- encode_addr_mode_3_arm (1, /*is_t=*/FALSE);
+ encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
}
static void
@@ -4552,7 +4553,7 @@
if (!inst.operands[1].isreg)
if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/FALSE))
return;
- encode_addr_mode_2_arm (1, /*is_t=*/FALSE);
+ encode_arm_addr_mode_2 (1, /*is_t=*/FALSE);
}
static void
@@ -4571,7 +4572,7 @@
inst.operands[1].writeback = 1;
}
inst.instruction |= inst.operands[0].reg << 12;
- encode_addr_mode_2_arm (1, /*is_t=*/TRUE);
+ encode_arm_addr_mode_2 (1, /*is_t=*/TRUE);
}
/* Halfword and signed-byte load/store operations. */
@@ -4583,7 +4584,7 @@
if (!inst.operands[1].isreg)
if (move_or_literal_pool (0, /*thumb_p=*/FALSE, /*mode_3=*/TRUE))
return;
- encode_addr_mode_3_arm (1, /*is_t=*/FALSE);
+ encode_arm_addr_mode_3 (1, /*is_t=*/FALSE);
}
static void
@@ -4602,7 +4603,7 @@
inst.operands[1].writeback = 1;
}
inst.instruction |= inst.operands[0].reg << 12;
- encode_addr_mode_3_arm (1, /*is_t=*/TRUE);
+ encode_arm_addr_mode_3 (1, /*is_t=*/TRUE);
}
/* Co-processor register load/store.
@@ -4612,7 +4613,7 @@
{
inst.instruction |= inst.operands[0].reg << 8;
inst.instruction |= inst.operands[1].reg << 12;
- encode_cp_address_arm (2, TRUE, TRUE, 0);
+ encode_arm_cp_address (2, TRUE, TRUE, 0);
}
static void
@@ -4635,7 +4636,7 @@
do_mov (void)
{
inst.instruction |= inst.operands[0].reg << 12;
- encode_shifter_operand_arm (1);
+ encode_arm_shifter_operand (1);
}
/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>. */
@@ -4734,7 +4735,7 @@
inst.instruction |= inst.operands[1].reg << 16;
inst.instruction |= inst.operands[2].reg;
if (inst.operands[3].present)
- encode_shift_arm (3);
+ encode_arm_shift (3);
}
/* ARM V6 PKHTB (Argument Parse). */
@@ -4756,7 +4757,7 @@
inst.instruction |= inst.operands[0].reg << 12;
inst.instruction |= inst.operands[1].reg << 16;
inst.instruction |= inst.operands[2].reg;
- encode_shift_arm (3);
+ encode_arm_shift (3);
}
}
@@ -4778,7 +4779,7 @@
constraint (!inst.operands[0].preind,
_("unindexed addressing used in preload instruction"));
inst.instruction |= inst.operands[0].reg;
- encode_addr_mode_2_arm (0, /*is_t=*/FALSE);
+ encode_arm_addr_mode_2 (0, /*is_t=*/FALSE);
}
static void
@@ -4816,7 +4817,7 @@
inst.instruction |= inst.operands[2].reg;
if (inst.operands[3].present)
- encode_shift_arm (3);
+ encode_arm_shift (3);
}
/* ARM V6 usat (argument parse). */
@@ -4829,7 +4830,7 @@
inst.instruction |= inst.operands[2].reg;
if (inst.operands[3].present)
- encode_shift_arm (3);
+ encode_arm_shift (3);
}
/* ARM V6 ssat16 (argument parse). */
@@ -4993,8 +4994,396 @@
inst.instruction |= inst.operands[1].reg;
inst.instruction |= inst.operands[2].imm << 10;
}
+
+/* VFP instructions. In a logical order: SP variant first, monad
+ before dyad, arithmetic then move then load/store. */
+static void
+do_vfp_sp_monadic (void)
+{
+ encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd);
+ encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sm);
+}
+
+static void
+do_vfp_sp_dyadic (void)
+{
+ encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd);
+ encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sn);
+ encode_arm_vfp_sp_reg (inst.operands[2].reg, VFP_REG_Sm);
+}
+
+static void
+do_vfp_sp_compare_z (void)
+{
+ encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd);
+}
+
+static void
+do_vfp_dp_sp_cvt (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sm);
+}
+
+static void
+do_vfp_sp_dp_cvt (void)
+{
+ encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd);
+ inst.instruction |= inst.operands[1].reg;
+}
+
+static void
+do_vfp_reg_from_sp (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sn);
+}
+
+static void
+do_vfp_reg2_from_sp2 (void)
+{
+ constraint (inst.operands[2].imm != 2,
+ _("only two consecutive VFP SP registers allowed here"));
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+ encode_arm_vfp_sp_reg (inst.operands[2].reg, VFP_REG_Sm);
+}
+
+static void
+do_vfp_sp_from_reg (void)
+{
+ encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sn);
+ inst.instruction |= inst.operands[1].reg << 12;
+}
+
+static void
+do_vfp_sp2_from_reg2 (void)
+{
+ constraint (inst.operands[0].imm != 2,
+ _("only two consecutive VFP SP registers allowed here"));
+ encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sm);
+ inst.instruction |= inst.operands[1].reg << 12;
+ inst.instruction |= inst.operands[2].reg << 16;
+}
+
+static void
+do_vfp_sp_ldst (void)
+{
+ encode_arm_vfp_sp_reg (inst.operands[0].reg, VFP_REG_Sd);
+ encode_arm_cp_address (1, FALSE, TRUE, 0);
+}
+
+static void
+do_vfp_dp_ldst (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ encode_arm_cp_address (1, FALSE, TRUE, 0);
+}
+
+
+static void
+vfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
+{
+ if (inst.operands[0].writeback)
+ inst.instruction |= WRITE_BACK;
+ else
+ constraint (ldstm_type != VFP_LDSTMIA,
+ _("this addressing mode requires base-register writeback"));
+ inst.instruction |= inst.operands[0].reg << 16;
+ encode_arm_vfp_sp_reg (inst.operands[1].reg, VFP_REG_Sd);
+ inst.instruction |= inst.operands[1].imm;
+}
+
+static void
+vfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
+{
+ int count;
+
+ if (inst.operands[0].writeback)
+ inst.instruction |= WRITE_BACK;
+ else
+ constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
+ _("this addressing mode requires base-register writeback"));
+
+ inst.instruction |= inst.operands[0].reg << 16;
+ inst.instruction |= inst.operands[1].reg << 12;
+
+ count = inst.operands[1].imm << 1;
+ if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
+ count += 1;
+
+ inst.instruction |= count;
+}
+
+static void
+do_vfp_sp_ldstmia (void)
+{
+ vfp_sp_ldstm (VFP_LDSTMIA);
+}
+
+static void
+do_vfp_sp_ldstmdb (void)
+{
+ vfp_sp_ldstm (VFP_LDSTMDB);
+}
+
+static void
+do_vfp_dp_ldstmia (void)
+{
+ vfp_dp_ldstm (VFP_LDSTMIA);
+}
+
+static void
+do_vfp_dp_ldstmdb (void)
+{
+ vfp_dp_ldstm (VFP_LDSTMDB);
+}
+
+static void
+do_vfp_xp_ldstmia (void)
+{
+ vfp_dp_ldstm (VFP_LDSTMIAX);
+}
+
+static void
+do_vfp_xp_ldstmdb (void)
+{
+ vfp_dp_ldstm (VFP_LDSTMDBX);
+}
+/* FPA instructions. Also in a logical order. */
+
+static void
+do_fpa_cmp (void)
+{
+ inst.instruction |= inst.operands[0].reg << 16;
+ inst.instruction |= inst.operands[1].reg;
+}
+
+static void
+do_fpa_ldmstm (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ switch (inst.operands[1].imm)
+ {
+ case 1: inst.instruction |= CP_T_X; break;
+ case 2: inst.instruction |= CP_T_Y; break;
+ case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
+ case 4: break;
+ default: abort ();
+ }
+
+ if (inst.instruction & (PRE_INDEX | INDEX_UP))
+ {
+ /* The instruction specified "ea" or "fd", so we can only accept
+ [Rn]{!}. The instruction does not really support stacking or
+ unstacking, so we have to emulate these by setting appropriate
+ bits and offsets. */
+ constraint (inst.reloc.exp.X_op != O_constant
+ || inst.reloc.exp.X_add_number != 0,
+ _("this instruction does not support indexing"));
+ if (inst.operands[2].writeback)
+ inst.instruction |= WRITE_BACK;
+ if (inst.instruction & (PRE_INDEX | WRITE_BACK))
+ inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
+ else
+ inst.instruction |= PRE_INDEX; /* prevent use of unindexed mode */
+
+ if (!(inst.instruction & INDEX_UP))
+ inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
+
+ inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
+ }
+ else
+ encode_arm_cp_address (2, TRUE, TRUE, 0);
+}
+
+/* iWMMXt instructions: strictly in alphabetical order. */
+
+static void
+do_iwmmxt_tandorc (void)
+{
+ constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
+}
+
+static void
+do_iwmmxt_textrc (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].imm;
+}
+
+static void
+do_iwmmxt_textrm (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+ inst.instruction |= inst.operands[2].imm;
+}
+
+static void
+do_iwmmxt_tinsr (void)
+{
+ inst.instruction |= inst.operands[0].reg << 16;
+ inst.instruction |= inst.operands[1].reg << 12;
+ inst.instruction |= inst.operands[2].imm;
+}
+
+static void
+do_iwmmxt_tmia (void)
+{
+ inst.instruction |= inst.operands[0].reg << 5;
+ inst.instruction |= inst.operands[1].reg;
+ inst.instruction |= inst.operands[2].reg << 12;
+}
+
+static void
+do_iwmmxt_waligni (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+ inst.instruction |= inst.operands[2].reg;
+ inst.instruction |= inst.operands[3].imm << 20;
+}
+
+static void
+do_iwmmxt_wmov (void)
+{
+ /* WMOV rD, rN is an alias for WOR rD, rN, rN. */
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+ inst.instruction |= inst.operands[1].reg;
+}
+
+static void
+do_iwmmxt_wldst (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ encode_arm_cp_address (1, TRUE, FALSE, BFD_RELOC_ARM_CP_OFF_IMM_S2);
+}
+
+static void
+do_iwmmxt_wldstw (void)
+{
+ /* RIWR_RIWC clears .isreg for a control register. */
+ if (!inst.operands[0].isreg)
+ {
+ constraint ((inst.instruction & COND_MASK) != COND_ALWAYS, BAD_COND);
+ inst.instruction |= 0xf0000000;
+ }
+
+ inst.instruction |= inst.operands[0].reg << 12;
+ encode_arm_cp_address (1, TRUE, TRUE, 0);
+}
+
+static void
+do_iwmmxt_wshufh (void)
+{
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+ inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
+ inst.instruction |= (inst.operands[2].imm & 0x0f);
+}
+
+static void
+do_iwmmxt_wzero (void)
+{
+ /* WZERO reg is an alias for WANDN reg, reg, reg. */
+ inst.instruction |= inst.operands[0].reg;
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[0].reg << 16;
+}
+
+/* Cirrus Maverick instructions. Simple 2-, 3-, and 4-register
+ operations first, then control, shift, and load/store. */
+
+/* Insns like "foo X,Y,Z". */
+
+static void
+do_mav_triple (void)
+{
+ inst.instruction |= inst.operands[0].reg << 16;
+ inst.instruction |= inst.operands[1].reg;
+ inst.instruction |= inst.operands[2].reg << 12;
+}
+
+/* Insns like "foo W,X,Y,Z".
+ where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */
+
+static void
+do_mav_quad (void)
+{
+ inst.instruction |= inst.operands[0].reg << 5;
+ inst.instruction |= inst.operands[1].reg << 12;
+ inst.instruction |= inst.operands[2].reg << 16;
+ inst.instruction |= inst.operands[3].reg;
+}
+
+/* cfmvsc32<cond> DSPSC,MVDX[15:0]. */
+static void
+do_mav_dspsc (void)
+{
+ inst.instruction |= inst.operands[1].reg << 12;
+}
+
+/* Maverick shift immediate instructions.
+ cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
+ cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */
+
+static void
+do_mav_shift (void)
+{
+ int imm = inst.operands[2].imm;
+
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+
+ /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
+ Bits 5-7 of the insn should have bits 4-6 of the immediate.
+ Bit 4 should be 0. */
+ imm = (imm & 0xf) | ((imm & 0x70) << 1);
+
+ inst.instruction |= imm;
+}
+
+/* XScale instructions. Also sorted arithmetic before move. */
+
+/* Xscale multiply-accumulate (argument parse)
+ MIAcc acc0,Rm,Rs
+ MIAPHcc acc0,Rm,Rs
+ MIAxycc acc0,Rm,Rs. */
+
+static void
+do_xsc_mia (void)
+{
+ inst.instruction |= inst.operands[1].reg;
+ inst.instruction |= inst.operands[2].reg << 12;
+}
+
+/* Xscale move-accumulator-register (argument parse)
+
+ MARcc acc0,RdLo,RdHi. */
+
+static void
+do_xsc_mar (void)
+{
+ inst.instruction |= inst.operands[1].reg << 12;
+ inst.instruction |= inst.operands[2].reg << 16;
+}
+
+/* Xscale move-register-accumulator (argument parse)
+
+ MRAcc RdLo,RdHi,acc0. */
+
+static void
+do_xsc_mra (void)
+{
+ constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
+ inst.instruction |= inst.operands[0].reg << 12;
+ inst.instruction |= inst.operands[1].reg << 16;
+}
+
/* Thumb instructions, in alphabetical order. */
/* Parse an add or subtract instruction. The high bit of inst.instruction
@@ -5421,397 +5810,6 @@
inst.instruction |= inst.operands[0].imm;
}
-/* VFP instructions. In a logical order: SP variant first, monad
- before dyad, arithmetic then move then load/store. */
-
-static void
-do_vfp_sp_monadic (void)
-{
- vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sd);
- vfp_sp_encode_reg (inst.operands[1].reg, VFP_REG_Sm);
-}
-
-static void
-do_vfp_sp_dyadic (void)
-{
- vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sd);
- vfp_sp_encode_reg (inst.operands[1].reg, VFP_REG_Sn);
- vfp_sp_encode_reg (inst.operands[2].reg, VFP_REG_Sm);
-}
-
-static void
-do_vfp_sp_compare_z (void)
-{
- vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sd);
-}
-
-static void
-do_vfp_dp_sp_cvt (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- vfp_sp_encode_reg (inst.operands[1].reg, VFP_REG_Sm);
-}
-
-static void
-do_vfp_sp_dp_cvt (void)
-{
- vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sd);
- inst.instruction |= inst.operands[1].reg;
-}
-
-static void
-do_vfp_reg_from_sp (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- vfp_sp_encode_reg (inst.operands[1].reg, VFP_REG_Sn);
-}
-
-static void
-do_vfp_reg2_from_sp2 (void)
-{
- constraint (inst.operands[2].imm != 2,
- _("only two consecutive VFP SP registers allowed here"));
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].reg << 16;
- vfp_sp_encode_reg (inst.operands[2].reg, VFP_REG_Sm);
-}
-
-static void
-do_vfp_sp_from_reg (void)
-{
- vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sn);
- inst.instruction |= inst.operands[1].reg << 12;
-}
-
-static void
-do_vfp_sp2_from_reg2 (void)
-{
- constraint (inst.operands[0].imm != 2,
- _("only two consecutive VFP SP registers allowed here"));
- vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sm);
- inst.instruction |= inst.operands[1].reg << 12;
- inst.instruction |= inst.operands[2].reg << 16;
-}
-
-static void
-do_vfp_sp_ldst (void)
-{
- vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sd);
- encode_cp_address_arm (1, FALSE, TRUE, 0);
-}
-
-static void
-do_vfp_dp_ldst (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- encode_cp_address_arm (1, FALSE, TRUE, 0);
-}
-
-
-static void
-vfp_sp_ldstm (enum vfp_ldstm_type ldstm_type)
-{
- if (inst.operands[0].writeback)
- inst.instruction |= WRITE_BACK;
- else
- constraint (ldstm_type != VFP_LDSTMIA,
- _("this addressing mode requires base-register writeback"));
- inst.instruction |= inst.operands[0].reg << 16;
- vfp_sp_encode_reg (inst.operands[1].reg, VFP_REG_Sd);
- inst.instruction |= inst.operands[1].imm;
-}
-
-static void
-vfp_dp_ldstm (enum vfp_ldstm_type ldstm_type)
-{
- int count;
-
- if (inst.operands[0].writeback)
- inst.instruction |= WRITE_BACK;
- else
- constraint (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX,
- _("this addressing mode requires base-register writeback"));
-
- inst.instruction |= inst.operands[0].reg << 16;
- inst.instruction |= inst.operands[1].reg << 12;
-
- count = inst.operands[1].imm << 1;
- if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
- count += 1;
-
- inst.instruction |= count;
-}
-
-static void
-do_vfp_sp_ldstmia (void)
-{
- vfp_sp_ldstm (VFP_LDSTMIA);
-}
-
-static void
-do_vfp_sp_ldstmdb (void)
-{
- vfp_sp_ldstm (VFP_LDSTMDB);
-}
-
-static void
-do_vfp_dp_ldstmia (void)
-{
- vfp_dp_ldstm (VFP_LDSTMIA);
-}
-
-static void
-do_vfp_dp_ldstmdb (void)
-{
- vfp_dp_ldstm (VFP_LDSTMDB);
-}
-
-static void
-do_vfp_xp_ldstmia (void)
-{
- vfp_dp_ldstm (VFP_LDSTMIAX);
-}
-
-static void
-do_vfp_xp_ldstmdb (void)
-{
- vfp_dp_ldstm (VFP_LDSTMDBX);
-}
-
-
-/* FPA instructions. Also in a logical order. */
-
-static void
-do_fpa_cmp (void)
-{
- inst.instruction |= inst.operands[0].reg << 16;
- inst.instruction |= inst.operands[1].reg;
-}
-
-static void
-do_fpa_ldmstm (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- switch (inst.operands[1].imm)
- {
- case 1: inst.instruction |= CP_T_X; break;
- case 2: inst.instruction |= CP_T_Y; break;
- case 3: inst.instruction |= CP_T_Y | CP_T_X; break;
- case 4: break;
- default: abort ();
- }
-
- if (inst.instruction & (PRE_INDEX | INDEX_UP))
- {
- /* The instruction specified "ea" or "fd", so we can only accept
- [Rn]{!}. The instruction does not really support stacking or
- unstacking, so we have to emulate these by setting appropriate
- bits and offsets. */
- constraint (inst.reloc.exp.X_op != O_constant
- || inst.reloc.exp.X_add_number != 0,
- _("this instruction does not support indexing"));
- if (inst.operands[2].writeback)
- inst.instruction |= WRITE_BACK;
- if (inst.instruction & (PRE_INDEX | WRITE_BACK))
- inst.reloc.exp.X_add_number = 12 * inst.operands[1].imm;
- else
- inst.instruction |= PRE_INDEX; /* prevent use of unindexed mode */
-
- if (!(inst.instruction & INDEX_UP))
- inst.reloc.exp.X_add_number = -inst.reloc.exp.X_add_number;
-
- inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
- }
- else
- encode_cp_address_arm (2, TRUE, TRUE, 0);
-}
-
-
-/* iWMMXt instructions: strictly in alphabetical order. */
-
-static void
-do_iwmmxt_tandorc (void)
-{
- constraint (inst.operands[0].reg != REG_PC, _("only r15 allowed here"));
-}
-
-static void
-do_iwmmxt_textrc (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].imm;
-}
-
-static void
-do_iwmmxt_textrm (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].reg << 16;
- inst.instruction |= inst.operands[2].imm;
-}
-
-static void
-do_iwmmxt_tinsr (void)
-{
- inst.instruction |= inst.operands[0].reg << 16;
- inst.instruction |= inst.operands[1].reg << 12;
- inst.instruction |= inst.operands[2].imm;
-}
-
-static void
-do_iwmmxt_tmia (void)
-{
- inst.instruction |= inst.operands[0].reg << 5;
- inst.instruction |= inst.operands[1].reg;
- inst.instruction |= inst.operands[2].reg << 12;
-}
-
-static void
-do_iwmmxt_waligni (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].reg << 16;
- inst.instruction |= inst.operands[2].reg;
- inst.instruction |= inst.operands[3].imm << 20;
-}
-
-static void
-do_iwmmxt_wmov (void)
-{
- /* WMOV rD, rN is an alias for WOR rD, rN, rN. */
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].reg << 16;
- inst.instruction |= inst.operands[1].reg;
-}
-
-static void
-do_iwmmxt_wldst (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- encode_cp_address_arm (1, TRUE, FALSE, BFD_RELOC_ARM_CP_OFF_IMM_S2);
-}
-
-static void
-do_iwmmxt_wldstw (void)
-{
- /* RIWR_RIWC clears .isreg for a control register. */
- if (!inst.operands[0].isreg)
- {
- constraint ((inst.instruction & COND_MASK) != COND_ALWAYS, BAD_COND);
- inst.instruction |= 0xf0000000;
- }
-
- inst.instruction |= inst.operands[0].reg << 12;
- encode_cp_address_arm (1, TRUE, TRUE, 0);
-}
-
-static void
-do_iwmmxt_wshufh (void)
-{
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].reg << 16;
- inst.instruction |= ((inst.operands[2].imm & 0xf0) << 16);
- inst.instruction |= (inst.operands[2].imm & 0x0f);
-}
-
-static void
-do_iwmmxt_wzero (void)
-{
- /* WZERO reg is an alias for WANDN reg, reg, reg. */
- inst.instruction |= inst.operands[0].reg;
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[0].reg << 16;
-}
-
-/* Cirrus Maverick instructions. Simple 2-, 3-, and 4-register
- operations first, then control, shift, and load/store. */
-
-/* Insns like "foo X,Y,Z". */
-
-static void
-do_mav_triple (void)
-{
- inst.instruction |= inst.operands[0].reg << 16;
- inst.instruction |= inst.operands[1].reg;
- inst.instruction |= inst.operands[2].reg << 12;
-}
-
-/* Insns like "foo W,X,Y,Z".
- where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */
-
-static void
-do_mav_quad (void)
-{
- inst.instruction |= inst.operands[0].reg << 5;
- inst.instruction |= inst.operands[1].reg << 12;
- inst.instruction |= inst.operands[2].reg << 16;
- inst.instruction |= inst.operands[3].reg;
-}
-
-/* cfmvsc32<cond> DSPSC,MVDX[15:0]. */
-static void
-do_mav_dspsc (void)
-{
- inst.instruction |= inst.operands[1].reg << 12;
-}
-
-/* Maverick shift immediate instructions.
- cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
- cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */
-
-static void
-do_mav_shift (void)
-{
- int imm = inst.operands[2].imm;
-
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].reg << 16;
-
- /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
- Bits 5-7 of the insn should have bits 4-6 of the immediate.
- Bit 4 should be 0. */
- imm = (imm & 0xf) | ((imm & 0x70) << 1);
-
- inst.instruction |= imm;
-}
-
-/* XScale instructions. Also sorted arithmetic before move. */
-
-/* Xscale multiply-accumulate (argument parse)
- MIAcc acc0,Rm,Rs
- MIAPHcc acc0,Rm,Rs
- MIAxycc acc0,Rm,Rs. */
-
-static void
-do_xsc_mia (void)
-{
- inst.instruction |= inst.operands[1].reg;
- inst.instruction |= inst.operands[2].reg << 12;
-}
-
-/* Xscale move-accumulator-register (argument parse)
-
- MARcc acc0,RdLo,RdHi. */
-
-static void
-do_xsc_mar (void)
-{
- inst.instruction |= inst.operands[1].reg << 12;
- inst.instruction |= inst.operands[2].reg << 16;
-}
-
-/* Xscale move-register-accumulator (argument parse)
-
- MRAcc RdLo,RdHi,acc0. */
-
-static void
-do_xsc_mra (void)
-{
- constraint (inst.operands[0].reg == inst.operands[1].reg, BAD_OVERLAP);
- inst.instruction |= inst.operands[0].reg << 12;
- inst.instruction |= inst.operands[1].reg << 16;
-}
-
/* Overall per-instruction processing. */
/* We need to be able to fix up arbitrary expressions in some statements.
@@ -6060,7 +6058,6 @@
return name;
}
-
/* Table of all register names defined by default. The user can
define additional names with .req. Note that all register names
@@ -7572,7 +7569,6 @@
#undef OPS6
#undef do_0
-
/* MD interface: bits in the object file. */
/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
@@ -7768,7 +7764,6 @@
return -1;
}
-
/* Code to deal with unwinding tables. */
@@ -8298,8 +8293,8 @@
int op, new_inst;
unsigned long negated, inverted;
- negated = encode_immediate_arm (-value);
- inverted = encode_immediate_arm (~value);
+ negated = encode_arm_immediate (-value);
+ inverted = encode_arm_immediate (~value);
op = (*instruction >> DATA_OP_SHIFT) & 0xf;
switch (op)
@@ -8426,7 +8421,7 @@
break;
}
- newimm = encode_immediate_arm (value);
+ newimm = encode_arm_immediate (value);
temp = md_chars_to_number (buf, INSN_SIZE);
/* If the instruction will fail, see if we can fix things up by
@@ -8449,7 +8444,7 @@
unsigned int highpart = 0;
unsigned int newinsn = 0xe1a00000; /* nop. */
- newimm = encode_immediate_arm (value);
+ newimm = encode_arm_immediate (value);
temp = md_chars_to_number (buf, INSN_SIZE);
/* If the instruction will fail, see if we can fix things up by