This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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},

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]