This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Thumb32 assembler (37/69)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Tue, 26 Apr 2005 02:55:07 -0700
- Subject: Thumb32 assembler (37/69)
Teach parse_operands about register lists for Thumb and ARM.
zw
* config/tc-arm.c (OP_RLw): New operand parse code.
(parse_operands): Implement OP_RLw and OP_REGLST.
(do_ldmstm, do_t_ldmstm, do_t_push_pop): Use parse_operands.
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c (revision 39)
+++ gas/config/tc-arm.c (revision 40)
@@ -4302,7 +4302,8 @@
#define OP_RL 052 /* Thumb low register */
#define OP_RLlb 053 /* Thumb low register, leading [ */
-#define OP_RLtb 054 /* Thumb low register. trailing ] */
+#define OP_RLtb 054 /* Thumb low register, trailing ] */
+#define OP_RLw 055 /* Thumb low register, optional trailing ! */
#define OP_CPSF 060 /* CPS flags */
#define OP_ENDI 061 /* Endianness specifier */
@@ -4472,6 +4473,17 @@
inst.error = BAD_HIREG;
break;
+ case OP_(RLw):
+ po_reg_or_fail (REG_TYPE_RN);
+ if (inst.operands[i].reg > 7)
+ inst.error = BAD_HIREG;
+ if (*str == '!')
+ {
+ inst.operands[i].writeback = 1;
+ str++;
+ }
+ break;
+
/* Immediates */
I0:
case OP_(I0): po_imm_or_fail ( 0, 0, FALSE); break;
@@ -4608,6 +4620,17 @@
inst.operands[i].imm = val;
break;
+ case OP_(REGLST):
+ if ((val = reg_list (&str)) == FAIL)
+ return FAIL;
+ inst.operands[i].imm = val;
+ if (*str == '^')
+ {
+ inst.operands[1].writeback = 1;
+ str++;
+ }
+ break;
+
case OP_(VRSLST):
val = vfp_parse_reg_list (&str, &inst.operands[i].reg, 0);
goto vfp_reglist;
@@ -5055,29 +5078,22 @@
do_ldmstm (char * str)
{
int base_reg;
- long range;
+ int range;
+ if (parse_operands (str, OPERANDS2(RRw,REGLST)))
+ return;
- note_reg_nonpc_or_fail (base_reg, &str, 16);
+ base_reg = inst.operands[0].reg;
+ range = inst.operands[1].imm;
- if (*str == '!')
- {
- inst.instruction |= WRITE_BACK;
- str++;
- }
+ inst.instruction |= base_reg << 16;
+ inst.instruction |= range;
- comma_or_fail (&str);
+ if (inst.operands[1].writeback)
+ inst.instruction |= LDM_TYPE_2_OR_3;
- if ((range = reg_list (&str)) == FAIL)
- return;
-
- if (*str == '^')
+ if (inst.operands[0].writeback)
{
- str++;
- inst.instruction |= LDM_TYPE_2_OR_3;
- }
-
- if (inst.instruction & WRITE_BACK)
- {
+ inst.instruction |= WRITE_BACK;
/* Check for unpredictable uses of writeback. */
if (inst.instruction & LOAD_BIT)
{
@@ -5100,9 +5116,6 @@
as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
}
}
-
- inst.instruction |= range;
- end_of_line (str);
}
/* ARMv5TE load-consecutive (argument parse)
@@ -6891,25 +6904,9 @@
static void
do_t_ldmstm (char * str)
{
- int Rb;
- long range;
-
- if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
+ if (parse_operands (str, OPERANDS2(RLw,REGLST)))
return;
- if (*str != '!')
- as_warn (_("inserted missing '!': load/store multiple always writes back base register"));
- else
- str++;
-
- if (skip_past_comma (&str) == FAIL
- || (range = reg_list (&str)) == FAIL)
- {
- if (! inst.error)
- inst.error = BAD_ARGS;
- return;
- }
-
if (inst.reloc.type != BFD_RELOC_UNUSED)
{
/* This really doesn't seem worth it. */
@@ -6917,15 +6914,21 @@
inst.error = _("expression too complex");
return;
}
-
- if (range & ~0xff)
+ if (inst.operands[1].imm & ~0xff)
{
inst.error = _("only lo-regs valid in load/store multiple");
return;
}
+ if (inst.operands[1].writeback)
+ {
+ inst.error = _("Thumb load/store multiple does not support {reglist}^");
+ return;
+ }
+ if (!inst.operands[0].writeback)
+ as_warn (_("Thumb load/store multiple always writes back base register"));
- inst.instruction |= (Rb << 8) | range;
- end_of_line (str);
+ inst.instruction |= inst.operands[0].reg << 8;
+ inst.instruction |= inst.operands[1].imm;
}
static void
@@ -6966,15 +6969,13 @@
static void
do_t_push_pop (char * str)
{
- long range;
-
- if ((range = reg_list (&str)) == FAIL)
+ if (parse_operands (str, OPERANDS1(REGLST)))
+ return;
+ if (inst.operands[0].writeback)
{
- if (! inst.error)
- inst.error = BAD_ARGS;
+ inst.error = _("push/pop do not support {reglist}^");
return;
}
-
if (inst.reloc.type != BFD_RELOC_UNUSED)
{
/* This really doesn't seem worth it. */
@@ -6982,16 +6983,15 @@
inst.error = _("expression too complex");
return;
}
-
- if (range & ~0xff)
+ if (inst.operands[0].imm & ~0xff)
{
if ((inst.instruction == T_OPCODE_PUSH
- && (range & ~0xff) == 1 << REG_LR)
+ && (inst.operands[0].imm & ~0xff) == 1 << REG_LR)
|| (inst.instruction == T_OPCODE_POP
- && (range & ~0xff) == 1 << REG_PC))
+ && (inst.operands[0].imm & ~0xff) == 1 << REG_PC))
{
inst.instruction |= THUMB_PP_PC_LR;
- range &= 0xff;
+ inst.operands[0].imm &= 0xff;
}
else
{
@@ -7000,8 +7000,7 @@
}
}
- inst.instruction |= range;
- end_of_line (str);
+ inst.instruction |= inst.operands[0].imm;
}
/* THUMB SETEND instruction (argument parse). */