This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Thumb32 assembler (24/69)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Tue, 26 Apr 2005 02:54:32 -0700
- Subject: Thumb32 assembler (24/69)
parse_operands conversion of the generic coprocessor instructions.
zw
* config/tc-arm.c (struct arm_it): Expand operands array to 6 entries.
(co_proc_number, cp_opc_expr): Delete.
(OP_bI7, OP_bI15, OP_obI7): New operand parser codes.
(parse_operands): Handle them. Add generic support for
optional operands, and for immediate values lacking a prefix.
Treat the pattern string as an array of unsigned char.
Give a more specific diagnostic when an unknown opcode is
encountered.
(do_cdp, do_co_reg, do_co_reg2c): Use parse_operands.
(do_lstc): Use reg_or_fail. Remove unwanted blank lines.
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c (revision 25)
+++ gas/config/tc-arm.c (revision 26)
@@ -195,7 +195,7 @@
{
int reg;
int imm;
- } operands[4];
+ } operands[6];
};
static struct arm_it inst;
@@ -2211,33 +2211,6 @@
}
static int
-co_proc_number (char ** str)
-{
- int processor;
-
- if ((processor = arm_reg_parse (str, REG_TYPE_CP)) == FAIL)
- {
- inst.error = reg_expected_msgs[REG_TYPE_CP];
- return FAIL;
- }
-
- inst.instruction |= processor << 8;
- return SUCCESS;
-}
-
-static int
-cp_opc_expr (char ** str, int where, int length)
-{
- unsigned int val;
-
- if (immediate_required_here (str, &val, 0, (1 << length) - 1, TRUE) == FAIL)
- return FAIL;
-
- inst.instruction |= val << where;
- return SUCCESS;
-}
-
-static int
cp_address_offset (char ** str)
{
int offset;
@@ -4310,6 +4283,7 @@
macros below. */
#define OP_stop 000 /* end of line */
+
#define OP_RR 001 /* ARM register */
#define OP_RRnpc 002 /* ARM register, not r15 */
#define OP_bRRnpc 003 /* ARM register, not r15, in square brackets */
@@ -4329,8 +4303,10 @@
#define OP_RIWC 021 /* iWMMXt wC register */
#define OP_RIWG 022 /* iWMMXt wCG register */
#define OP_RXA 023 /* XScale accumulator register */
+
#define OP_EXP 024 /* arbitrary expression */
#define OP_iEXP 025 /* same, with optional immediate prefix */
+
#define OP_I0 026 /* immediate value 0 */
#define OP_I4 027 /* 1 .. 4 */
#define OP_I7 030 /* 0 .. 7 */
@@ -4342,6 +4318,12 @@
#define OP_I255 036 /* 0 .. 255 */
#define OP_Iffff 037 /* 0 .. 65535 */
+#define OP_bI7 040 /* immediate, prefix optional, 0 .. 7 */
+#define OP_bI15 041 /* 0 .. 15 */
+
+/* Optional operands. All have the high bit set. */
+#define OP_obI7 200 /* optional bI7 */
+
/* Macro for referring to one of the above constants as a number.
Should appear solely in parse_operands(). */
#define OP_(x) OP__(OP_##x)
@@ -4355,11 +4337,13 @@
#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)
+#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)
+#define OPERANDS5(a,b,c,d,e) OPS_(a) OPS_(b) OPS_(c) OPS_(d) OPS_(e)
+#define OPERANDS6(a,b,c,d,e,f) OPS_(a) OPS_(b) OPS_(c) OPS_(d) OPS_(e) OPS_(f)
/* Generic instruction operand parser. This does no encoding and no
semantic validation; it merely squirrels values away in the inst
@@ -4369,6 +4353,7 @@
parse_operands (char *str, const char *pattern)
{
int i;
+ unsigned const char *p = pattern;
#define po_char_or_fail(chr) do { \
if (skip_past_char (&str, chr) == FAIL) \
@@ -4385,16 +4370,16 @@
inst.operands[i].reg = reg_; \
} while (0)
-#define po_imm_or_fail(min, max) do { \
+#define po_imm_or_fail(min, max, popt) do { \
int imm_; \
- if (immediate_required_here (&str, &imm_, min, max, FALSE) == FAIL) \
+ if (immediate_required_here (&str, &imm_, min, max, popt) == FAIL) \
return FAIL; \
inst.operands[i].imm = imm_; \
} while (0)
for (i = 0; ; i++)
{
- switch (*pattern)
+ switch (*p)
{
/* Registers */
case OP_(RR): po_reg_or_fail (REG_TYPE_RN); break;
@@ -4434,17 +4419,21 @@
break;
/* Immediates */
- case OP_(I0): po_imm_or_fail (0, 0); break;
- case OP_(I4): po_imm_or_fail (1, 4); break;
- case OP_(I7): po_imm_or_fail (0, 7); break;
- case OP_(I15): po_imm_or_fail (0, 15); break;
- case OP_(I16): po_imm_or_fail (1, 16); break;
- case OP_(I31): po_imm_or_fail (0, 31); break;
- case OP_(I32): po_imm_or_fail (1, 32); break;
- case OP_(Is63): po_imm_or_fail (-64, 63); break;
- case OP_(I255): po_imm_or_fail (0, 255); break;
- case OP_(Iffff): po_imm_or_fail (0, 0xffff); break;
+ case OP_(I0): po_imm_or_fail ( 0, 0, FALSE); break;
+ case OP_(I4): po_imm_or_fail ( 1, 4, FALSE); break;
+ case OP_(I7): po_imm_or_fail ( 0, 7, FALSE); break;
+ case OP_(I15): po_imm_or_fail ( 0, 15, FALSE); break;
+ case OP_(I16): po_imm_or_fail ( 1, 16, FALSE); break;
+ case OP_(I31): po_imm_or_fail ( 0, 31, FALSE); break;
+ case OP_(I32): po_imm_or_fail ( 1, 32, FALSE); break;
+ case OP_(Is63): po_imm_or_fail (-64, 63, FALSE); break;
+ case OP_(I255): po_imm_or_fail ( 0, 255, FALSE); break;
+ case OP_(Iffff): po_imm_or_fail ( 0, 0xffff, FALSE); break;
+ 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;
+
/* Expressions */
case OP_(iEXP):
if (is_immediate_prefix (*str))
@@ -4462,12 +4451,17 @@
goto done;
default:
- abort ();
+ as_fatal ("unhandled operand code %03o", *p);
}
- if (*++pattern == OP_(stop))
+ if (*++p == OP_(stop))
break;
+ /* If this is an optional argument, and we have no further
+ operands, stop. */
+ if ((*p & 0200) && *str == '\0')
+ break;
+
if (skip_past_comma (&str) == FAIL)
goto bad_args;
}
@@ -4863,27 +4857,15 @@
static void
do_cdp (char * str)
{
- if (co_proc_number (&str) == FAIL)
+ if (parse_operands (str, OPERANDS6(RCP,bI15,RCN,RCN,RCN,obI7)))
return;
- comma_or_fail (&str);
- if (cp_opc_expr (&str, 20, 4) == FAIL)
- return;
- comma_or_fail (&str);
-
- reg_or_fail (&str, 12, REG_TYPE_CN);
- comma_or_fail (&str);
-
- reg_or_fail (&str, 16, REG_TYPE_CN);
- comma_or_fail (&str);
-
- reg_or_fail (&str, 0, REG_TYPE_CN);
-
- if (skip_past_comma (&str) == SUCCESS)
- if (cp_opc_expr (&str, 5, 3) == FAIL)
- return;
-
- end_of_line (str);
+ inst.instruction |= inst.operands[0].reg << 8;
+ inst.instruction |= inst.operands[1].imm << 20;
+ inst.instruction |= inst.operands[2].reg << 12;
+ inst.instruction |= inst.operands[3].reg << 16;
+ inst.instruction |= inst.operands[4].reg << 0;
+ inst.instruction |= inst.operands[5].imm << 5;
}
/* ARM V5 count-leading-zeroes instruction (argument parse)
@@ -4928,31 +4910,15 @@
static void
do_co_reg (char * str)
{
- if (co_proc_number (&str) == FAIL)
+ if (parse_operands (str, OPERANDS6(RCP,bI7,RR,RCN,RCN,obI7)))
return;
- comma_or_fail (&str);
-
- if (cp_opc_expr (&str, 21, 3) == FAIL)
- return;
-
- comma_or_fail (&str);
-
- reg_or_fail (&str, 12, REG_TYPE_RN);
-
- comma_or_fail (&str);
-
- reg_or_fail (&str, 16, REG_TYPE_CN);
-
- comma_or_fail (&str);
-
- reg_or_fail (&str, 0, REG_TYPE_CN);
-
- if (skip_past_comma (&str) == SUCCESS)
- if (cp_opc_expr (&str, 5, 3) == FAIL)
- return;
-
- end_of_line (str);
+ inst.instruction |= inst.operands[0].reg << 8;
+ inst.instruction |= inst.operands[1].imm << 21;
+ inst.instruction |= inst.operands[2].reg << 12;
+ inst.instruction |= inst.operands[3].reg << 16;
+ inst.instruction |= inst.operands[4].reg << 0;
+ inst.instruction |= inst.operands[5].imm << 5;
}
/* Transfer between coprocessor register and pair of ARM registers.
@@ -4971,25 +4937,14 @@
static void
do_co_reg2c (char * str)
{
- if (co_proc_number (& str) == FAIL)
+ if (parse_operands (str, OPERANDS5(RCP,bI15,RRnpc,RRnpc,RCN)))
return;
- comma_or_fail (&str);
-
- if (cp_opc_expr (&str, 4, 4) == FAIL)
- return;
-
- comma_or_fail (&str);
- reg_nonpc_or_fail (&str, 12);
-
- comma_or_fail (&str);
- reg_nonpc_or_fail (&str, 16);
-
- comma_or_fail (&str);
-
- reg_or_fail (& str, 0, REG_TYPE_CN);
-
- end_of_line (str);
+ inst.instruction |= inst.operands[0].reg << 8;
+ inst.instruction |= inst.operands[1].imm << 4;
+ inst.instruction |= inst.operands[2].reg << 12;
+ inst.instruction |= inst.operands[3].reg << 16;
+ inst.instruction |= inst.operands[4].reg << 0;
}
/* ARM V6 change processor state instruction (argument parse)
@@ -5590,18 +5545,14 @@
/* Co-processor register load/store.
Format: <LDC|STC{cond}[L] CP#,CRd,<address> */
- if (co_proc_number (&str) == FAIL)
- return;
-
+ reg_or_fail (&str, 8, REG_TYPE_CP);
comma_or_fail (&str);
reg_or_fail (&str, 12, REG_TYPE_CN);
-
comma_or_fail (&str);
if (cp_address_required_here (&str, CP_WB_OK) == FAIL)
return;
-
end_of_line (str);
}