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 (25/69)


parse_operands conversion of a bunch of miscellaneous instructions,
notably the CPS family, BKPT, SETEND, and NOP.

zw

	* config/tc-arm.c (do_cps_mode): Rename parse_cps_flags.  Adjust
	interface for use from parse_operands.  Simplify internals.
	(do_endian_specifier): Similarly.
	(OP_CPSF, OP_ENDI, OP_obI31, OP_obIffff, OP_ocI255): New operand parse
	codes.
	(parse_operands): Handle them.  Support instructions with all operands
	optional.
	(do_bkpt, do_cps, do_cpsi, do_nop, do_t_cps, do_t_setend): 
	Use parse_operands.
	(do_srs): Use immediate_or_fail instead of do_cps_mode.

===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c	(revision 26)
+++ gas/config/tc-arm.c	(revision 27)
@@ -2516,59 +2516,42 @@
   return SUCCESS;
 }
 
-static void
-do_cps_mode (char ** str)
+/* Parse the flags argument to CPSI[ED].  Returns SUCCESS or FAIL as
+   appropriate; on success, *valp gets a value suitable for splatting
+   into the AIF field of the instruction.  */
+
+static int
+parse_cps_flags (int *valp, char **str)
 {
-  int val;
+  int val = 0;
+  int saw_a_flag = 0;
+  char *s = *str;
 
-  /* The mode is a 5 bit field.  Valid values are 0-31.  */
-  if (immediate_required_here (str, &val, 0, 31, TRUE) == FAIL)
-    return;
+  for (;;)
+    switch (*s++)
+      {
+      case '\0': case ',':
+	goto done;
 
-  inst.instruction |= val;
-}
+      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;
 
-static void
-do_cps_flags (char ** str, int thumb_p)
-{
-  struct cps_flag
-  {
-    char character;
-    unsigned long arm_value;
-    unsigned long thumb_value;
-  };
-  static struct cps_flag flag_table[] =
-  {
-    {'a', 0x100, 0x4 },
-    {'i', 0x080, 0x2 },
-    {'f', 0x040, 0x1 }
-  };
+      default:
+	inst.error = _("unrecognized CPS flag");
+	return FAIL;
+      }
 
-  int saw_a_flag = 0;
-
-  /* Get the a, f and i flags.  */
-  while (**str && **str != ',')
+ done:
+  if (saw_a_flag == 0)
     {
-      struct cps_flag *p;
-      struct cps_flag *q = flag_table + sizeof (flag_table)/sizeof (*p);
-
-      for (p = flag_table; p < q; ++p)
-	if (strncasecmp (*str, &p->character, 1) == 0)
-	  {
-	    inst.instruction |= (thumb_p ? p->thumb_value : p->arm_value);
-	    saw_a_flag = 1;
-	    break;
-	  }
-      if (p == q)
-	{
-	  inst.error = _("unrecognized flag");
-	  return;
-	}
-      (*str)++;
+      inst.error = _("missing CPS flags");
+      return FAIL;
     }
 
-  if (!saw_a_flag)
-    inst.error = _("no 'a', 'i', or 'f' flags for 'cps'");
+  *str = s - 1;
+  *valp = val;
+  return SUCCESS;
 }
 
 static int
@@ -2593,28 +2576,35 @@
   return offset;
 }
 
-/* Returns true if the endian-specifier indicates big-endianness.  */
+/* Parse an endian specifier ("BE" or "LE", case insensitive);
+   write 0 into *val for big-endian, 1 for little-endian; return
+   SUCCESS for successful parse, or FAIL and set inst.error.  */
 
 static int
-do_endian_specifier (char * str)
+parse_endian_specifier (int *val, char **str)
 {
-  int big_endian = 0;
+  int little_endian;
+  char *s = *str;
 
-  if (strlen (str) < 2)
-    inst.error = _("missing endian specifier");
-  else if (strncasecmp (str, "BE", 2) == 0)
+  if (strncasecmp (s, "BE", 2))
+    little_endian = 0;
+  else if (strncasecmp (s, "LE", 2))
+    little_endian = 1;
+  else
     {
-      str += 2;
-      big_endian = 1;
+      inst.error = _("valid endian specifiers are be or le");
+      return FAIL;
     }
-  else if (strncasecmp (str, "LE", 2) == 0)
-    str += 2;
-  else
-    inst.error = _("valid endian specifiers are be or le");
 
-  end_of_line (str);
+  if (ISALNUM (s[2]) || s[2] == '_')
+    {
+      inst.error = _("valid endian specifiers are be or le");
+      return FAIL;
+    }
 
-  return big_endian;
+  *val = little_endian;
+  *str = s + 2;
+  return SUCCESS;
 }
 
 /* Directives: register aliases.  */
@@ -4320,10 +4310,19 @@
 
 #define OP_bI7	   040  /* immediate, prefix optional, 0 .. 7 */
 #define OP_bI15    041  /*                             0 .. 15 */
+#define OP_bI31    042  /*                             0 .. 31 */
 
+#define OP_CPSF	   060  /* CPS flags */
+#define OP_ENDI	   061	/* Endianness specifier */
+
 /* Optional operands.  All have the high bit set.  */
-#define OP_obI7    200  /* optional bI7 */
+#define OP_obI7    200  /* optional, prefix optional, immediate 0 .. 7 */
+#define OP_obI31   201  /*                                      0 .. 31 */
+#define OP_obIffff 202  /*                                      0 .. 65535 */
 
+#define OP_ocI255  210  /* optional, curly-brace enclosed, imm  0 .. 255 */
+
+
 /* Macro for referring to one of the above constants as a number.
    Should appear solely in parse_operands().  */
 #define OP_(x) OP__(OP_##x)
@@ -4377,6 +4376,11 @@
   inst.operands[i].imm = imm_;						\
 } while (0)
 
+  /* Check for a no-operand instruction, or an instruction with only
+     optional operands given none, and bypass the loop if so.  */
+  if (*p == OP_(stop) || ((*p & 0200) && *str == 0))
+    goto done;
+
   for (i = 0; ; i++)
     {
       switch (*p)
@@ -4433,6 +4437,16 @@
 	case OP_(obI7):
 	case OP_(bI7):   po_imm_or_fail (  0,      7, TRUE);    break;
 	case OP_(bI15):  po_imm_or_fail (  0,     15, TRUE);    break;
+	case OP_(obI31):
+	case OP_(bI31):  po_imm_or_fail (  0,     31, TRUE);    break;
+	case OP_(obIffff): po_imm_or_fail (0, 0xffff, TRUE);    break;
+
+	case OP_(ocI255):
+	  po_char_or_fail ('{');
+	  po_imm_or_fail (0, 255, TRUE);
+	  po_char_or_fail ('}');
+	  inst.operands[i].imm += 1;  /* to distinguish 0 from omitted */
+	  break;
 	  
 	  /* Expressions */
 	case OP_(iEXP):
@@ -4446,10 +4460,16 @@
 	  break;
 
 	  /* Misc */
-	case OP_(stop):
-	  /* We only get here for 0 operands.  */
-	  goto done;
+	case OP_(CPSF):
+	  if (parse_cps_flags (&inst.operands[i].imm, &str))
+	    return FAIL;
+	  break;
 
+	case OP_(ENDI):
+	  if (parse_endian_specifier (&inst.operands[i].imm, &str))
+	    return FAIL;
+	  break;
+
 	default:
 	  as_fatal ("unhandled operand code %03o", *p);
 	}
@@ -4674,20 +4694,16 @@
 static void
 do_bkpt (char * str)
 {
-  int number = 0;
+  /* As a convenience, we allow BKPT with no immediate (corresponding
+     to BKPT #0).  */
+  if (parse_operands (str, OPERANDS1(obIffff)))
+    return;
 
-  /* As a convenience we allow 'bkpt' without an operand.  */
-  if (is_immediate_prefix (*str) || ISDIGIT (*str))
-    if (immediate_required_here (&str, &number, 0, 0xffff, TRUE) == FAIL)
-      return;
-
   /* Top 12 of 16 bits to bits 19:8.  */
-  inst.instruction |= (number & 0xfff0) << 4;
+  inst.instruction |= (inst.operands[0].imm & 0xfff0) << 4;
 
   /* Bottom 4 of 16 bits to bits 3:0.  */
-  inst.instruction |= number & 0xf;
-
-  end_of_line (str);
+  inst.instruction |= inst.operands[0].imm & 0xf;
 }
 
 static void
@@ -4953,19 +4969,19 @@
 static void
 do_cps (char * str)
 {
-  do_cps_mode (&str);
-  end_of_line (str);
+  if (parse_operands (str, OPERANDS1(bI31)))
+    return;
+  inst.instruction |= inst.operands[0].imm;
 }
 
 static void
 do_cpsi (char * str)
 {
-  do_cps_flags (&str, /*thumb_p=*/0);
+  if (parse_operands (str, OPERANDS2(CPSF,obI31)))
+    return;
 
-  if (skip_past_comma (&str) == SUCCESS)
-    do_cps_mode (&str);
-
-  end_of_line (str);
+  inst.instruction |= inst.operands[0].imm << 6;
+  inst.instruction |= inst.operands[1].imm;
 }
 
 static void
@@ -5749,27 +5765,15 @@
 static void
 do_nop (char * str)
 {
-  int hint;
+  if (parse_operands (str, OPERANDS1(ocI255)))
+    return;
 
-  if (*str == '{')
+  if (inst.operands[0].imm)
     {
-      str++;
-      if (immediate_required_here (&str, &hint, 0, 255, TRUE) == FAIL)
-	return;
-
-      if (*str != '}')
-	{
-	  inst.error = _("'}' expected at end of hint field");
-	  return;
-	}
-      str++;
-
       /* Architectural NOP hints are CPSR sets with no bits selected.  */
       inst.instruction &= 0xf0000000;
-      inst.instruction |= 0x0320f000 + hint;
+      inst.instruction |= 0x0320f000 + inst.operands[0].imm - 1;
     }
-
-  end_of_line (str);
 }
 
 static void
@@ -6043,7 +6047,10 @@
 static void
 do_setend (char * str)
 {
-  if (do_endian_specifier (str))
+  if (parse_operands (str, OPERANDS1(ENDI)))
+    return;
+
+  if (inst.operands[0].imm)
     inst.instruction |= 0x200;
 }
 
@@ -6124,12 +6131,16 @@
 static void
 do_srs (char * str)
 {
+  int val;
   /* This is necessary because the generic expression parser will
      choke on "#16!".  */
   char *exclam = strchr (str, '!');
   if (exclam)
     *exclam = '\0';
-  do_cps_mode (&str);
+
+  immediate_or_fail (&str, &val, 0, 31, TRUE);
+  inst.instruction |= val;
+
   if (exclam)
     *exclam = '!';
   if (*str == '!')
@@ -7069,8 +7080,10 @@
 static void
 do_t_cps (char * str)
 {
-  do_cps_flags (&str, /*thumb_p=*/1);
-  end_of_line (str);
+  if (parse_operands (str, OPERANDS1(CPSF)))
+    return;
+
+  inst.instruction |= inst.operands[0].imm;
 }
 
 /* THUMB CPY instruction (argument parse).  */
@@ -7225,7 +7238,10 @@
 static void
 do_t_setend (char * str)
 {
-  if (do_endian_specifier (str))
+  if (parse_operands (str, OPERANDS1(ENDI)))
+    return;
+
+  if (inst.operands[0].imm)
     inst.instruction |= 0x8;
 }
 

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