This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Thumb32 assembler (17/69)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Tue, 26 Apr 2005 02:54:11 -0700
- Subject: Thumb32 assembler (17/69)
This patch introduces parse_operands, a completely generic routine for
parsing all arguments to an assembly instruction. At this point it
can only handle registers, but that's enough for a lot of the encoder
routines.
The reject_* functions are a blind alley; I eventually went back to
detecting invalid use of r15 at parse time, and register conflicts
with ad-hoc code.
I'd also like to assure readers that the horrific OP_ and OPS_ macros
are only to facilitate the transition; they go away once every
instruction is parseable using parse_operands. We won't be getting
there for awhile yet, though.
zw
* config/tc-arm.c (struct arm_it): Add operands field.
(inst): Make static.
(BAD_OVERLAP): New canned diagnostic.
(OP_stop, OP_RR, OP_bRR, OP_RCP, OP_RCN, OP_RF, OP_RVS, OP_RVD, OP_RVC)
(OP_RMF, OP_RMD, OP_RMFX, OP_RMDX, OP_RMAX, OP_RMDS, OP_RIWR, OP_RIWC)
(OP_RIWG, OP_RXA, OP_EXP, OP_iEXP, OP_, OP__, OP___, OPS_, OPS__)
(OPS___): New macros.
(parse_operands, reject_pc, reject_overlap): New functions.
(do_empty, do_adr, do_adrl, do_bx, do_bxj, do_clz, do_ldrex, do_mlas)
(do_mul, do_mull, do_qadd, do_qadd16, do_rbit, do_rev, do_smi, do_swi)
(do_smla, do_smlal, do_strex, do_swap, do_t_branch9, do_t_branch12)
(do_t_branch23, do_t_bx, do_t_swi, do_vfp_sp_monadic, do_vfp_dp_monadic)
(do_vfp_sp_dyadic, do_vfp_dp_dyadic, do_vfp_sp_compare_z)
(do_vfp_dp_compare_z, do_vfp_dp_sp_cvt, do_vfp_sp_dp_cvt)
(do_vfp_reg_from_sp, do_vfp_sp_from_reg, do_vfp_reg_from_dp)
(do_vfp_reg2_from_dp, do_vfp_dp_from_reg, do_vfp_dp_from_reg2)
(do_vfp_reg_from_ctrl, do_vfp_ctrl_from_reg, do_fpa_ctrl)
(do_fpa_from_reg, do_fpa_to_reg, do_xsc_mia, do_xsc_mar, do_xsc_mra):
Use parse_operands, reject_pc, and reject_overlap.
(do_t_nop): Delete.
(tinsns): Use do_empty for nop.
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c (revision 18)
+++ gas/config/tc-arm.c (revision 19)
@@ -190,9 +190,14 @@
expressionS exp;
int pc_rel;
} reloc;
+
+ union
+ {
+ int reg;
+ } operands[4];
};
-struct arm_it inst;
+static struct arm_it inst;
enum asm_shift_index
{
@@ -605,6 +610,7 @@
#define BAD_ARGS _("bad arguments to instruction")
#define BAD_PC _("r15 not allowed here")
#define BAD_COND _("instruction is not conditional")
+#define BAD_OVERLAP _("registers may not be the same")
static struct hash_control *arm_ops_hsh;
static struct hash_control *arm_tops_hsh;
@@ -4319,31 +4325,215 @@
{ "packed", float_cons, 'p' },
{ 0, 0, 0 }
};
+
+/* Matcher codes for operand_parse. These are in octal, because of
+ the macros below. Never refer to these constants except via the
+ macros below. */
+#define OP_stop 000 /* end of line */
+#define OP_RR 001 /* ARM register */
+#define OP_bRR 002 /* ARM register in square brackets */
+#define OP_RCP 003 /* Coprocessor number */
+#define OP_RCN 004 /* Coprocessor register */
+#define OP_RF 005 /* FPA register */
+#define OP_RVS 006 /* VFP single precision register */
+#define OP_RVD 007 /* VFP double precision register */
+#define OP_RVC 010 /* VFP control register */
+#define OP_RMF 011 /* Maverick F register */
+#define OP_RMD 012 /* Maverick D register */
+#define OP_RMFX 013 /* Maverick FX register */
+#define OP_RMDX 014 /* Maverick DX register */
+#define OP_RMAX 015 /* Maverick AX register */
+#define OP_RMDS 016 /* Maverick DSPSC register */
+#define OP_RIWR 017 /* iWMMXt wR register */
+#define OP_RIWC 020 /* iWMMXt wC register */
+#define OP_RIWG 021 /* iWMMXt wCG register */
+#define OP_RXA 022 /* XScale accumulator register */
+#define OP_EXP 023 /* arbitrary expression */
+#define OP_iEXP 024 /* same, with optional immediate prefix */
+
+/* Macro for referring to one of the above constants as a number.
+ Should appear solely in parse_operands(). */
+#define OP_(x) OP__(OP_##x)
+#define OP__(x) OP___(x)
+#define OP___(x) 0##x
+
+/* Macro for referring to one of the above constants as a 1-character
+ string. Used by OPERANDSn(). */
+#define OPS_(x) OPS__(\OP_##x)
+#define OPS__(x) OPS___(x)
+#define OPS___(x) #x
+
+/* Macros for gluing together operand strings. */
+#define OPERANDS0() ""
+#define OPERANDS1(a) OPS_(a)
+#define OPERANDS2(a,b) OPS_(a) OPS_(b)
+#define OPERANDS3(a,b,c) OPS_(a) OPS_(b) OPS_(c)
+#define OPERANDS4(a,b,c,d) OPS_(a) OPS_(b) OPS_(c) OPS_(d)
+
+/* Generic instruction operand parser. This does no encoding and no
+ semantic validation; it merely squirrels values away in the inst
+ structure. Returns SUCCESS or FAIL depending on whether the
+ specified grammar matched. */
+static int
+parse_operands (char *str, char *pattern)
+{
+ int i;
+
+#define po_char_or_fail(chr) do { \
+ if (skip_past_char (&str, chr) == FAIL) \
+ goto bad_args; \
+} while (0)
+
+#define po_reg_or_fail(regtype) do { \
+ int reg_ = reg_required_here (&str, -1, regtype); \
+ if (reg_ == FAIL) \
+ { \
+ inst.error = _(reg_expected_msgs[regtype]); \
+ return FAIL; \
+ } \
+ inst.operands[i].reg = reg_; \
+} while (0)
+
+ for (i = 0; ; i++)
+ {
+ switch (*pattern)
+ {
+ /* Registers */
+ case OP_(RR): po_reg_or_fail (REG_TYPE_RN); break;
+ case OP_(RCP): po_reg_or_fail (REG_TYPE_CP); break;
+ case OP_(RCN): po_reg_or_fail (REG_TYPE_CN); break;
+ case OP_(RF): po_reg_or_fail (REG_TYPE_FN); break;
+ case OP_(RVS): po_reg_or_fail (REG_TYPE_VFS); break;
+ case OP_(RVD): po_reg_or_fail (REG_TYPE_VFD); break;
+ case OP_(RVC): po_reg_or_fail (REG_TYPE_VFC); break;
+ case OP_(RMF): po_reg_or_fail (REG_TYPE_MVF); break;
+ case OP_(RMD): po_reg_or_fail (REG_TYPE_MVD); break;
+ case OP_(RMFX): po_reg_or_fail (REG_TYPE_MVFX); break;
+ case OP_(RMAX): po_reg_or_fail (REG_TYPE_MVAX); break;
+ case OP_(RMDS): po_reg_or_fail (REG_TYPE_DSPSC); break;
+ case OP_(RIWR): po_reg_or_fail (REG_TYPE_MMXWR); break;
+ case OP_(RIWC): po_reg_or_fail (REG_TYPE_MMXWC); break;
+ case OP_(RIWG): po_reg_or_fail (REG_TYPE_MMXWCG); break;
+ case OP_(RXA): po_reg_or_fail (REG_TYPE_XSCALE); break;
+
+ /* Decorated registers */
+ case OP_(bRR):
+ po_char_or_fail ('[');
+ po_reg_or_fail (REG_TYPE_RN);
+ po_char_or_fail (']');
+ break;
+
+ /* Expressions and immediates */
+ case OP_(iEXP):
+ if (is_immediate_prefix (*str))
+ str++;
+ /* fall through */
+
+ case OP_(EXP):
+ if (my_get_expression (&inst.reloc.exp, &str))
+ return FAIL;
+ break;
+
+ /* Misc */
+ case OP_(stop):
+ /* We only get here for 0 operands. */
+ goto done;
+
+ default:
+ abort ();
+ }
+
+ if (*++pattern == OP_(stop))
+ break;
+
+ if (skip_past_comma (&str) == FAIL)
+ goto bad_args;
+ }
+
+ done:
+ end_of_line (str);
+ return inst.error ? FAIL : SUCCESS;
+
+ bad_args:
+ inst.error = BAD_ARGS;
+ return FAIL;
+
+#undef po_char_or_fail
+#undef po_reg_or_fail
+}
+
+#undef OP_
+#undef OP__
+#undef OP___
+
+/* Operand validation functions. */
+
+/* Set inst.error to BAD_PC and return FAIL if any of the specified register
+ operands are REG_PC. N is the number of operands. */
+static int
+reject_pc (int n, ...)
+{
+ va_list ap;
+ va_start (ap, n);
+ while (n--)
+ {
+ int op = va_arg (ap, int);
+ if (inst.operands[op].reg == REG_PC)
+ {
+ inst.error = BAD_PC;
+ return FAIL;
+ }
+ }
+ va_end (ap);
+ return SUCCESS;
+}
+
+/* Set inst.error to BAD_OVERLAP and return FAIL if any of the
+ specified pairs of register operands are the same. N is the number
+ of pairs. */
+static int
+reject_overlap (int n, ...)
+{
+ va_list ap;
+ va_start (ap, n);
+ while (n--)
+ {
+ int op1 = va_arg (ap, int);
+ int op2 = va_arg (ap, int);
+ if (inst.operands[op1].reg == inst.operands[op2].reg)
+ {
+ inst.error = BAD_OVERLAP;
+ return FAIL;
+ }
+ }
+ va_end (ap);
+ return SUCCESS;
+}
+
/* Functions for instruction parsing, sorted by subarchitecture. */
static void
do_empty (char * str)
{
- /* Do nothing really. */
- end_of_line (str);
+ parse_operands (str, OPERANDS0 ());
}
/* ARM instructions, in alphabetical order by function name (except
that wrapper functions appear immediately after the function they
wrap). */
+/* This is a pseudo-op of the form "adr rd, label" to be converted
+ into a relative address of the form "add rd, pc, #label-.-8". */
+
static void
do_adr (char * str)
{
- /* This is a pseudo-op of the form "adr rd, label" to be converted
- into a relative address of the form "add rd, pc, #label-.-8". */
+ if (parse_operands (str, OPERANDS2 (RR, EXP)) == FAIL)
+ return;
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
- expression_or_fail (&inst.reloc.exp, &str);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12); /* Rd */
/* Frag hacking will turn this into a sub instruction if the offset turns
out to be negative. */
@@ -4354,18 +4544,18 @@
inst.reloc.pc_rel = 1;
}
+/* This is a pseudo-op of the form "adrl rd, label" to be converted
+ into a relative address of the form:
+ add rd, pc, #low(label-.-8)"
+ add rd, rd, #high(label-.-8)" */
+
static void
do_adrl (char * str)
{
- /* This is a pseudo-op of the form "adrl rd, label" to be converted
- into a relative address of the form:
- add rd, pc, #low(label-.-8)"
- add rd, rd, #high(label-.-8)" */
+ if (parse_operands (str, OPERANDS2 (RR, EXP)) == FAIL)
+ return;
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
- expression_or_fail (&inst.reloc.exp, &str);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12); /* Rd */
/* Frag hacking will turn this into a sub instruction if the offset turns
out to be negative. */
@@ -4598,19 +4788,6 @@
end_of_line (str);
}
-static void
-do_bx (char * str)
-{
- int reg;
-
- note_reg_or_fail (reg, &str, 0, REG_TYPE_RN);
- end_of_line (str);
-
- /* Note - it is not illegal to do a "bx pc". Useless, but not illegal. */
- if (reg == REG_PC)
- as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
-}
-
/* ARM V5 branch-link-exchange instruction (argument parse)
BLX <target_addr> ie BLX(1)
BLX{<condition>} <Rm> ie BLX(2)
@@ -4654,19 +4831,31 @@
}
}
+static void
+do_bx (char * str)
+{
+ if (parse_operands (str, OPERANDS1 (RR)) == FAIL)
+ return;
+
+ if (inst.operands[0].reg == REG_PC)
+ as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
+
+ inst.instruction |= (inst.operands[0].reg << 0);
+}
+
+
/* ARM v5TEJ. Jump to Jazelle code. */
static void
do_bxj (char * str)
{
- int reg;
+ if (parse_operands (str, OPERANDS1 (RR)) == FAIL)
+ return;
- note_reg_or_fail (reg, &str, 0, REG_TYPE_RN);
- end_of_line (str);
+ if (inst.operands[0].reg == REG_PC)
+ as_tsktsk (_("use of r15 in bxj is not really useful"));
- /* Note - it is not illegal to do a "bxj pc". Useless, but not illegal. */
- if (reg == REG_PC)
- as_tsktsk (_("use of r15 in bxj is not really useful"));
+ inst.instruction |= (inst.operands[0].reg << 0);
}
/* Co-processor data operation:
@@ -4706,10 +4895,12 @@
static void
do_clz (char * str)
{
- reg_nonpc_or_fail (&str, 12);
- comma_or_fail (&str);
- reg_nonpc_or_fail (&str, 0);
- end_of_line (str);
+ if (parse_operands (str, OPERANDS2 (RR, RR)) == FAIL)
+ return;
+ if (reject_pc (2, 0,1))
+ return;
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 0);
}
static void
@@ -4942,15 +5133,12 @@
static void
do_ldrex (char * str)
{
- /* Parse Rd. */
- reg_nonpc_or_fail (&str, 12);
- comma_or_fail (&str);
-
- char_or_fail (&str, '[');
- reg_nonpc_or_fail (&str, 16);
- char_or_fail (&str, ']');
-
- end_of_line (str);
+ if (parse_operands (str, OPERANDS2(RR, bRR)))
+ return;
+ if (reject_pc (2, 0,1))
+ return;
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 16);
}
static void
@@ -5423,25 +5611,19 @@
static void
do_mlas (char * str, bfd_boolean is_mls)
{
- int rd, rm;
+ if (parse_operands (str, OPERANDS4(RR,RR,RR,RR)))
+ return;
+ if (reject_pc (4, 0,1,2,3))
+ return;
- /* Only one format "rd, rm, rs, rn". */
-
- note_reg_nonpc_or_fail (rd, &str, 16);
- comma_or_fail (&str);
-
- note_reg_nonpc_or_fail (rm, &str, 0);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 8);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 12);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 16);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 8);
+ inst.instruction |= (inst.operands[3].reg << 12);
/* This restriction does not apply to mls (nor to mla in v6, but
that's hard to detect at present). */
- if (rm == rd && !is_mls)
+ if (inst.operands[0].reg == inst.operands[1].reg && !is_mls)
as_tsktsk (_("rd and rm should be different in mla"));
}
@@ -5586,20 +5768,16 @@
static void
do_mul (char * str)
{
- int rd, rm;
+ if (parse_operands (str, OPERANDS3(RR,RR,RR)))
+ return;
+ if (reject_pc (2, 0,1))
+ return;
- /* Only one format "rd, rm, rs". */
+ inst.instruction |= (inst.operands[0].reg << 16);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 8);
- note_reg_nonpc_or_fail (rd, &str, 16);
- comma_or_fail (&str);
-
- note_reg_nonpc_or_fail (rm, &str, 0);
- comma_or_fail (&str);
-
- reg_or_fail (&str, 8, REG_TYPE_RN);
- end_of_line (str);
-
- if (rm == rd)
+ if (inst.operands[0].reg == inst.operands[1].reg)
as_tsktsk (_("rd and rm should be different in mul"));
}
@@ -5612,23 +5790,20 @@
static void
do_mull (char * str)
{
- int rdlo, rdhi, rm;
+ if (parse_operands (str, OPERANDS4(RR,RR,RR,RR)))
+ return;
+ if (reject_pc (4, 0,1,2,3))
+ return;
- /* Only one format "rdlo, rdhi, rm, rs". */
- note_reg_nonpc_or_fail (rdlo, &str, 12);
- comma_or_fail (&str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 16);
+ inst.instruction |= (inst.operands[2].reg << 0);
+ inst.instruction |= (inst.operands[3].reg << 8);
- note_reg_nonpc_or_fail (rdhi, &str, 16);
- comma_or_fail (&str);
-
- note_reg_nonpc_or_fail (rm, &str, 0);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 8);
- end_of_line (str);
-
/* rdhi, rdlo and rm must all be different. */
- if (rdlo == rdhi || rdlo == rm || rdhi == rm)
+ if (inst.operands[0].reg == inst.operands[1].reg
+ || inst.operands[0].reg == inst.operands[2].reg
+ || inst.operands[1].reg == inst.operands[2].reg)
as_tsktsk (_("rdhi, rdlo and rm must all be different"));
}
@@ -5788,14 +5963,14 @@
static void
do_qadd (char * str)
{
- reg_nonpc_or_fail (&str, 12);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RR,RR,RR)))
+ return;
+ if (reject_pc (3, 0,1,2))
+ return;
- reg_nonpc_or_fail (&str, 0);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 16);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 16);
}
/* ARM V6 Perform Two Sixteen Bit Integer Additions. (argument parse).
@@ -5806,24 +5981,24 @@
static void
do_qadd16 (char * str)
{
- reg_nonpc_or_fail (&str, 12);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RR,RR,RR)))
+ return;
+ if (reject_pc (3, 0,1,2))
+ return;
- reg_nonpc_or_fail (&str, 16);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 0);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 16);
+ inst.instruction |= (inst.operands[2].reg << 0);
}
static void
do_rbit (char *str)
{
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RR,RR)))
+ return;
- reg_or_fail (&str, 0, REG_TYPE_RN);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 0);
}
/* ARM V6 REV (Byte Reverse Word) reverses the byte order in a 32-bit
@@ -5835,11 +6010,13 @@
static void
do_rev (char * str)
{
- reg_nonpc_or_fail (&str, 12);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RR,RR)))
+ return;
+ if (reject_pc (2, 0,1))
+ return;
- reg_nonpc_or_fail (&str, 0);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 0);
}
/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
@@ -5949,29 +6126,21 @@
static void
do_smi (char * str)
{
- /* Allow optional leading '#'. */
- if (is_immediate_prefix (*str))
- str++;
+ if (parse_operands (str, OPERANDS1(iEXP)))
+ return;
- expression_or_fail (& inst.reloc.exp, & str);
-
inst.reloc.type = BFD_RELOC_ARM_SMI;
inst.reloc.pc_rel = 0;
- end_of_line (str);
}
static void
do_swi (char * str)
{
- /* Allow optional leading '#'. */
- if (is_immediate_prefix (*str))
- str++;
+ if (parse_operands (str, OPERANDS1(iEXP)))
+ return;
- expression_or_fail (& inst.reloc.exp, & str);
-
inst.reloc.type = BFD_RELOC_ARM_SWI;
inst.reloc.pc_rel = 0;
- end_of_line (str);
}
/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
@@ -5982,18 +6151,15 @@
static void
do_smla (char * str)
{
- reg_nonpc_or_fail (&str, 16);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS4(RR,RR,RR,RR)))
+ return;
+ if (reject_pc (4, 0,1,2,3))
+ return;
- reg_nonpc_or_fail (&str, 0);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 8);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 12);
-
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 16);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 8);
+ inst.instruction |= (inst.operands[3].reg << 12);
}
/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
@@ -6004,23 +6170,18 @@
static void
do_smlal (char * str)
{
- int rdlo, rdhi;
+ if (parse_operands (str, OPERANDS4(RR,RR,RR,RR)))
+ return;
+ if (reject_pc (4, 0,1,2,3))
+ return;
- note_reg_nonpc_or_fail (rdlo, &str, 12);
- comma_or_fail (&str);
-
- note_reg_nonpc_or_fail (rdhi, &str, 16);
- comma_or_fail (&str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 16);
+ inst.instruction |= (inst.operands[2].reg << 0);
+ inst.instruction |= (inst.operands[3].reg << 8);
- reg_nonpc_or_fail (&str, 0);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 8);
-
- if (rdlo == rdhi)
+ if (inst.operands[0].reg == inst.operands[1].reg)
as_tsktsk (_("rdhi and rdlo must be different"));
-
- end_of_line (str);
}
/* ARM V5E (El Segundo) signed-multiply (argument parse)
@@ -6030,15 +6191,14 @@
static void
do_smul (char * str)
{
- reg_nonpc_or_fail (&str, 16);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RR,RR,RR)))
+ return;
+ if (reject_pc (3, 0,1,2))
+ return;
- reg_nonpc_or_fail (&str, 0);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 8);
-
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 16);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 8);
}
/* ARM V6 srs (argument parse). */
@@ -6067,40 +6227,27 @@
static void
do_strex (char * str)
{
- int rd, rm, rn;
+ if (parse_operands (str, OPERANDS3(RR,RR,bRR)))
+ return;
+ if (reject_pc (3, 0,1,2) || reject_overlap (2, 0,1, 0,2))
+ return;
- note_reg_nonpc_or_fail (rd, &str, 12);
- comma_or_fail (&str);
-
- note_reg_nonpc_or_fail (rm, &str, 0);
- comma_or_fail (&str);
-
- char_or_fail (&str, '[');
- note_reg_nonpc_or_fail (rn, &str, 16);
- char_or_fail (&str, ']');
-
- end_of_line (str);
-
- if (rd == rm || rd == rn)
- inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 16);
}
static void
do_swap (char * str)
{
- int reg;
+ if (parse_operands (str, OPERANDS3(RR,RR,bRR)))
+ return;
+ if (reject_pc (3, 0,1,2))
+ return;
- reg_nonpc_or_fail (&str, 12);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 0);
- comma_or_fail (&str);
-
- char_or_fail (&str, '[');
- note_reg_nonpc_or_fail (reg, &str, 16);
- char_or_fail (&str, ']');
-
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 16);
}
/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
@@ -6943,29 +7090,31 @@
static void
do_t_branch9 (char * str)
{
- expression_or_fail (&inst.reloc.exp, &str);
+ if (parse_operands (str, OPERANDS1(EXP)))
+ return;
+
inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
inst.reloc.pc_rel = 1;
- end_of_line (str);
}
static void
do_t_branch12 (char * str)
{
- expression_or_fail (&inst.reloc.exp, &str);
+ if (parse_operands (str, OPERANDS1(EXP)))
+ return;
+
inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
inst.reloc.pc_rel = 1;
- end_of_line (str);
}
static void
do_t_branch23 (char * str)
{
- expression_or_fail (& inst.reloc.exp, & str);
+ if (parse_operands (str, OPERANDS1(EXP)))
+ return;
inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
inst.reloc.pc_rel = 1;
- end_of_line (str);
/* If the destination of the branch is a defined symbol which does not have
the THUMB_FUNC attribute, then we must be calling a function which has
@@ -6982,19 +7131,15 @@
static void
do_t_bx (char * str)
{
- int reg;
-
- if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
+ if (parse_operands (str, OPERANDS1(RR)))
return;
/* This sets THUMB_H2 from the top bit of reg. */
- inst.instruction |= reg << 3;
+ inst.instruction |= (inst.operands[0].reg << 3);
/* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc
should cause the alignment to be checked once it is known. This is
because BX PC only works if the instruction is word aligned. */
-
- end_of_line (str);
}
static void
@@ -7119,13 +7264,6 @@
}
static void
-do_t_nop (char * str)
-{
- /* Do nothing. */
- end_of_line (str);
-}
-
-static void
do_t_push_pop (char * str)
{
long range;
@@ -7202,10 +7340,10 @@
static void
do_t_swi (char * str)
{
- expression_or_fail (&inst.reloc.exp, &str);
+ if (parse_operands (str, OPERANDS1(EXP)))
+ return;
inst.reloc.type = BFD_RELOC_ARM_SWI;
- end_of_line (str);
}
/* VFP instructions. In a logical order: SP variant first, monad
@@ -7214,91 +7352,91 @@
static void
do_vfp_sp_monadic (char * str)
{
- reg_or_fail (&str, VFP_REG_Sd, REG_TYPE_VFS);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RVS,RVS)))
+ return;
- reg_or_fail (&str, VFP_REG_Sm, REG_TYPE_VFS);
- end_of_line (str);
+ 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_dp_monadic (char * str)
{
- reg_or_fail (&str, VFP_REG_Dd, REG_TYPE_VFD);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RVD,RVD)))
+ return;
- reg_or_fail (&str, VFP_REG_Dm, REG_TYPE_VFD);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << VFP_REG_Dd);
+ inst.instruction |= (inst.operands[1].reg << VFP_REG_Dm);
}
static void
do_vfp_sp_dyadic (char * str)
{
- reg_or_fail (&str, VFP_REG_Sd, REG_TYPE_VFS);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RVS,RVS,RVS)))
+ return;
- reg_or_fail (&str, VFP_REG_Sn, REG_TYPE_VFS);
- comma_or_fail (&str);
-
- reg_or_fail (&str, VFP_REG_Sm, REG_TYPE_VFS);
- end_of_line (str);
+ 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_dp_dyadic (char * str)
{
- reg_or_fail (&str, VFP_REG_Dd, REG_TYPE_VFD);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RVD,RVD,RVD)))
+ return;
- reg_or_fail (&str, VFP_REG_Dn, REG_TYPE_VFD);
- comma_or_fail (&str);
-
- reg_or_fail (&str, VFP_REG_Dm, REG_TYPE_VFD);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << VFP_REG_Dd);
+ inst.instruction |= (inst.operands[1].reg << VFP_REG_Dn);
+ inst.instruction |= (inst.operands[2].reg << VFP_REG_Dm);
}
static void
do_vfp_sp_compare_z (char * str)
{
- reg_or_fail (&str, VFP_REG_Sd, REG_TYPE_VFS);
- end_of_line (str);
+ if (parse_operands (str, OPERANDS1(RVS)))
+ return;
+
+ vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sd);
}
static void
do_vfp_dp_compare_z (char * str)
{
- reg_or_fail (&str, VFP_REG_Dd, REG_TYPE_VFD);
- end_of_line (str);
+ if (parse_operands (str, OPERANDS1(RVD)))
+ return;
+
+ inst.instruction |= (inst.operands[0].reg << VFP_REG_Dd);
}
static void
do_vfp_dp_sp_cvt (char * str)
{
- reg_or_fail (&str, VFP_REG_Dd, REG_TYPE_VFD);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RVD,RVS)))
+ return;
- reg_or_fail (&str, VFP_REG_Sm, REG_TYPE_VFS);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << VFP_REG_Dd);
+ vfp_sp_encode_reg (inst.operands[1].reg, VFP_REG_Sm);
}
static void
do_vfp_sp_dp_cvt (char * str)
{
- reg_or_fail (&str, VFP_REG_Sd, REG_TYPE_VFS);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RVS,RVD)))
+ return;
- reg_or_fail (&str, VFP_REG_Dm, REG_TYPE_VFD);
- end_of_line (str);
+ vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sd);
+ inst.instruction |= (inst.operands[1].reg << VFP_REG_Dm);
}
static void
do_vfp_reg_from_sp (char * str)
{
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RR,RVS)))
+ return;
- reg_or_fail (&str, VFP_REG_Sn, REG_TYPE_VFS);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ vfp_sp_encode_reg (inst.operands[1].reg, VFP_REG_Sn);
}
static void
@@ -7326,13 +7464,11 @@
static void
do_vfp_sp_from_reg (char * str)
{
- reg_or_fail (&str, VFP_REG_Sn, REG_TYPE_VFS);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RVS,RR)))
+ return;
- reg_or_fail (&str, 12, REG_TYPE_RN);
- end_of_line (str);
-
- end_of_line (str);
+ vfp_sp_encode_reg (inst.operands[0].reg, VFP_REG_Sn);
+ inst.instruction |= (inst.operands[1].reg << 12);
}
static void
@@ -7359,67 +7495,63 @@
static void
do_vfp_reg_from_dp (char * str)
{
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RR,RVD)))
+ return;
- reg_or_fail (&str, VFP_REG_Dn, REG_TYPE_VFD);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << VFP_REG_Dn);
}
static void
do_vfp_reg2_from_dp (char * str)
{
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RR,RR,RVD)))
+ return;
- reg_or_fail (&str, 16, REG_TYPE_RN);
- comma_or_fail (&str);
-
- reg_or_fail (&str, VFP_REG_Dm, REG_TYPE_VFD);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 16);
+ inst.instruction |= (inst.operands[2].reg << VFP_REG_Dm);
}
static void
do_vfp_dp_from_reg (char * str)
{
- reg_or_fail (&str, VFP_REG_Dn, REG_TYPE_VFD);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RVD,RR)))
+ return;
- reg_or_fail (&str, 12, REG_TYPE_RN);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << VFP_REG_Dn);
+ inst.instruction |= (inst.operands[1].reg << 12);
}
static void
do_vfp_dp_from_reg2 (char * str)
{
- reg_or_fail (&str, VFP_REG_Dm, REG_TYPE_VFD);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RVD,RR,RR)))
+ return;
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
-
- reg_or_fail (&str, 16, REG_TYPE_RN);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << VFP_REG_Dm);
+ inst.instruction |= (inst.operands[1].reg << 12);
+ inst.instruction |= (inst.operands[2].reg << 16);
}
static void
do_vfp_reg_from_ctrl (char * str)
{
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RR,RVC)))
+ return;
- reg_or_fail (&str, 16, REG_TYPE_VFC);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 16);
}
static void
do_vfp_ctrl_from_reg (char * str)
{
- reg_or_fail (&str, 16, REG_TYPE_VFC);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS2(RVC,RR)))
+ return;
- reg_or_fail (&str, 12, REG_TYPE_RN);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 16);
+ inst.instruction |= (inst.operands[1].reg << 12);
}
static void
@@ -7547,14 +7679,16 @@
/* FPA instructions. Also in a logical order. */
+/* FP control register read/write.
+ Format: <WFS|RFS|WFC|RFC>{cond} Rn */
+
static void
do_fpa_ctrl (char * str)
{
- /* FP control registers.
- Format: <WFS|RFS|WFC|RFC>{cond} Rn */
+ if (parse_operands (str, OPERANDS1(RR)))
+ return;
- reg_or_fail (&str, 12, REG_TYPE_RN);
- end_of_line (str);
+ inst.instruction |= (inst.operands[0].reg << 12);
}
static void
@@ -7599,21 +7733,21 @@
static void
do_fpa_from_reg (char * str)
{
- reg_or_fail (&str, 16, REG_TYPE_FN);
- comma_or_fail (&str);
-
- reg_or_fail (&str, 12, REG_TYPE_RN);
- end_of_line (str);
+ if (parse_operands (str, OPERANDS2(RF,RR)))
+ return;
+
+ inst.instruction |= (inst.operands[0].reg << 16);
+ inst.instruction |= (inst.operands[1].reg << 12);
}
static void
do_fpa_to_reg (char * str)
{
- reg_or_fail (&str, 12, REG_TYPE_RN);
- comma_or_fail (&str);
-
- reg_or_fail (&str, 0, REG_TYPE_FN);
- end_of_line (str);
+ if (parse_operands (str, OPERANDS2(RR,RF)))
+ return;
+
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 0);
}
static void
@@ -8564,14 +8698,13 @@
static void
do_xsc_mia (char * str)
{
- reg_or_fail (&str, -1, REG_TYPE_XSCALE);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RXA,RR,RR)))
+ return;
+ if (reject_pc (2, 1,2))
+ return;
- reg_nonpc_or_fail (&str, 0);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 12);
- end_of_line (str);
+ inst.instruction |= (inst.operands[1].reg << 0);
+ inst.instruction |= (inst.operands[2].reg << 12);
}
/* Xscale move-accumulator-register (argument parse)
@@ -8581,14 +8714,13 @@
static void
do_xsc_mar (char * str)
{
- reg_or_fail (&str, -1, REG_TYPE_XSCALE);
- comma_or_fail (&str);
+ if (parse_operands (str, OPERANDS3(RXA,RR,RR)))
+ return;
+ if (reject_pc (2, 1,2))
+ return;
- reg_nonpc_or_fail (&str, 12);
- comma_or_fail (&str);
-
- reg_nonpc_or_fail (&str, 16);
- end_of_line (str);
+ inst.instruction |= (inst.operands[1].reg << 12);
+ inst.instruction |= (inst.operands[2].reg << 16);
}
/* Xscale move-register-accumulator (argument parse)
@@ -8598,21 +8730,13 @@
static void
do_xsc_mra (char * str)
{
- int rdlo;
- int rdhi;
+ if (parse_operands (str, OPERANDS3(RR,RR,RXA)))
+ return;
+ if (reject_pc (2, 0,1) || reject_overlap (1, 0,1))
+ return;
- note_reg_nonpc_or_fail (rdlo, &str, 12);
- comma_or_fail (&str);
-
- note_reg_nonpc_or_fail (rdhi, &str, 16);
- comma_or_fail (&str);
-
- reg_or_fail (&str, -1, REG_TYPE_XSCALE);
- end_of_line (str);
-
- /* inst.instruction has now been zapped with both rdlo and rdhi. */
- if (rdlo == rdhi)
- inst.error = BAD_ARGS; /* Undefined result if 2 writes to same reg. */
+ inst.instruction |= (inst.operands[0].reg << 12);
+ inst.instruction |= (inst.operands[1].reg << 16);
}
/* Overall per-instruction processing. */
@@ -10233,7 +10357,7 @@
{"tst", T_OPCODE_TST, 2, ARM_EXT_V4T, do_t_arit},
/* Pseudo ops: */
{"adr", 0x0000, 2, ARM_EXT_V4T, do_t_adr},
- {"nop", 0x46C0, 2, ARM_EXT_V4T, do_t_nop}, /* mov r8,r8 */
+ {"nop", 0x46C0, 2, ARM_EXT_V4T, do_empty}, /* mov r8,r8 */
/* Thumb v2 (ARMv5T). */
{"blx", 0, 0, ARM_EXT_V5T, do_t_blx},
{"bkpt", 0xbe00, 2, ARM_EXT_V5T, do_t_bkpt},