This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Thumb32 assembler (43/69)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Tue, 26 Apr 2005 02:55:28 -0700
- Subject: Thumb32 assembler (43/69)
With all the function renames, the Thumb instruction section has
gotten out of alphabetical order. Re-sort it.
zw
* tc-arm.c: Sort Thumb instruction section alphabetically again.
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c (revision 45)
+++ gas/config/tc-arm.c (revision 46)
@@ -6230,9 +6230,7 @@
}
-/* Thumb instructions. The generic argument parsing routines
- (thumb_*) come first, in alphabetical order, then the
- per-instruction routines (do_t_*), also in alphabetical order. */
+/* Thumb instructions, in alphabetical order. */
/* Parse an add or subtract instruction. The high bit of inst.instruction
is set if the opcode was SUB. */
@@ -6306,191 +6304,6 @@
}
static void
-do_t_ldst (char *str)
-{
- if (parse_operands (str, OPERANDS2(RL,TADDR)))
- return;
-
- if (!inst.operands[1].isreg) /* =expr pseudo */
- {
- if (inst.instruction & THUMB_LOAD_BIT)
- {
- inst.error = _("invalid pseudo operation");
- return;
- }
-
- if (inst.reloc.exp.X_op == O_constant
- && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
- {
- /* This can be done with a mov instruction. */
- inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[0].reg << 8);
- inst.instruction |= inst.reloc.exp.X_add_number;
- return;
- }
-
- /* Insert into literal pool. */
- if (add_to_lit_pool () == FAIL)
- {
- inst.error = _("literal pool insertion failed");
- return;
- }
-
- inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
- inst.reloc.exp.X_add_number += 4; /* pipeline offset */
- inst.operands[1].reg = REG_PC;
- }
-
- if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
- {
- if (inst.instruction & 0x0600)
- {
- inst.error = _("byte or halfword not valid for base register");
- return;
- }
- else if (inst.operands[1].reg == REG_PC
- && !(inst.instruction & THUMB_LOAD_BIT))
- {
- inst.error = _("r15 based store not allowed");
- return;
- }
- else if (inst.operands[1].immisreg)
- {
- inst.error = _("invalid base register for register offset");
- return;
- }
-
- if (inst.operands[1].reg == REG_PC)
- inst.instruction = T_OPCODE_LDR_PC;
- else if (inst.instruction & THUMB_LOAD_BIT)
- inst.instruction = T_OPCODE_LDR_SP;
- else
- inst.instruction = T_OPCODE_STR_SP;
-
- inst.instruction |= inst.operands[0].reg << 8;
- }
- else if (!inst.operands[1].immisreg)
- {
- /* Immediate offset. */
- switch (inst.instruction)
- {
- case T_OPCODE_STR_RW: inst.instruction = T_OPCODE_STR_IW; break;
- case T_OPCODE_STR_RH: inst.instruction = T_OPCODE_STR_IH; break;
- case T_OPCODE_STR_RB: inst.instruction = T_OPCODE_STR_IB; break;
- case T_OPCODE_LDR_RW: inst.instruction = T_OPCODE_LDR_IW; break;
- case T_OPCODE_LDR_RH: inst.instruction = T_OPCODE_LDR_IH; break;
- case T_OPCODE_LDR_RB: inst.instruction = T_OPCODE_LDR_IB; break;
- default: abort ();
- }
-
- inst.instruction |= inst.operands[0].reg;
- inst.instruction |= inst.operands[1].reg << 3;
- }
- else
- {
- /* Register offset. Opcode is already correct. */
- inst.instruction |= inst.operands[0].reg;
- inst.instruction |= inst.operands[1].reg << 3;
- inst.instruction |= inst.operands[1].imm << 6;
- }
-}
-
-static void
-do_t_mov_cmp (char * str)
-{
- if (parse_operands (str, OPERANDS2(RR,RR_iEX)))
- return;
-
- if (inst.operands[1].isreg)
- {
- if (inst.operands[0].reg < 8 && inst.operands[1].reg < 8)
- {
- /* A move of two lowregs is encoded as ADD Rd, Rs, #0
- since a MOV instruction produces unpredictable results. */
- if (inst.instruction == T_OPCODE_MOV_HR)
- inst.instruction = T_OPCODE_ADD_I3;
- else
- inst.instruction = T_OPCODE_CMP_LR;
-
- inst.instruction |= inst.operands[0].reg;
- inst.instruction |= inst.operands[1].reg << 3;
- }
- else
- {
- /* Opcode in inst.instruction is already correct. */
- inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
- inst.instruction |= (inst.operands[0].reg & 0x7);
- inst.instruction |= inst.operands[1].reg << 3;
- }
- }
- else
- {
- if (inst.operands[0].reg > 7)
- {
- inst.error = _("only lo regs allowed with immediate");
- return;
- }
-
- if (inst.instruction == T_OPCODE_MOV_HR)
- inst.instruction = T_OPCODE_MOV_I8;
- else
- inst.instruction = T_OPCODE_CMP_I8;
-
- inst.instruction |= inst.operands[0].reg << 8;
- inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
- }
-}
-
-static void
-do_t_shift (char * str)
-{
- int Rs;
- if (parse_operands (str, OPERANDS3(RL,RL_iEX,oRL_iEX)))
- return;
-
- if (inst.operands[2].present)
- {
- /* If there were three operands, operand 1 must be a register. */
- if (!inst.operands[1].isreg)
- {
- inst.error = BAD_ARGS;
- return;
- }
- else if (inst.operands[2].isreg) /* Rd, Rs, Rn */
- {
- if (inst.operands[0].reg != inst.operands[1].reg)
- {
- inst.error = _("source1 and dest must be same register");
- return;
- }
- inst.instruction |= inst.operands[0].reg;
- inst.instruction |= inst.operands[2].reg << 3;
- return;
- }
- else /* Rd, Rs, imm */
- Rs = inst.operands[1].reg;
- }
- else if (inst.operands[1].isreg) /* Rd, Rs -> Rd, Rd, Rs */
- {
- inst.instruction |= inst.operands[0].reg;
- inst.instruction |= inst.operands[2].reg << 3;
- return;
- }
- else /* Rd, imm -> Rd, Rd, imm */
- Rs = inst.operands[0].reg;
-
- /* If we get here, we are doing a shift by an immediate. inst.operands[0].reg
- and Rs are the registers, and inst.reloc is the immediate. */
- switch (inst.instruction)
- {
- case T_OPCODE_ASR_R: inst.instruction = T_OPCODE_ASR_I; break;
- case T_OPCODE_LSL_R: inst.instruction = T_OPCODE_LSL_I; break;
- case T_OPCODE_LSR_R: inst.instruction = T_OPCODE_LSR_I; break;
- }
- inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
- inst.instruction |= inst.operands[0].reg | (Rs << 3);
-}
-
-static void
do_t_adr (char * str)
{
if (parse_operands (str, OPERANDS2(RL,EXP)))
@@ -6703,43 +6516,140 @@
}
static void
-do_t_push_pop (char * str)
+do_t_ldst (char *str)
{
- if (parse_operands (str, OPERANDS1(REGLST)))
+ if (parse_operands (str, OPERANDS2(RL,TADDR)))
return;
- if (inst.operands[0].writeback)
+
+ if (!inst.operands[1].isreg) /* =expr pseudo */
{
- inst.error = _("push/pop do not support {reglist}^");
- return;
+ if (inst.instruction & THUMB_LOAD_BIT)
+ {
+ inst.error = _("invalid pseudo operation");
+ return;
+ }
+
+ if (inst.reloc.exp.X_op == O_constant
+ && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
+ {
+ /* This can be done with a mov instruction. */
+ inst.instruction = T_OPCODE_MOV_I8 | (inst.operands[0].reg << 8);
+ inst.instruction |= inst.reloc.exp.X_add_number;
+ return;
+ }
+
+ /* Insert into literal pool. */
+ if (add_to_lit_pool () == FAIL)
+ {
+ inst.error = _("literal pool insertion failed");
+ return;
+ }
+
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
+ inst.reloc.exp.X_add_number += 4; /* pipeline offset */
+ inst.operands[1].reg = REG_PC;
}
- if (inst.reloc.type != BFD_RELOC_UNUSED)
+
+ if (inst.operands[1].reg == REG_PC || inst.operands[1].reg == REG_SP)
{
- /* This really doesn't seem worth it. */
- inst.reloc.type = BFD_RELOC_UNUSED;
- inst.error = _("expression too complex");
- return;
+ if (inst.instruction & 0x0600)
+ {
+ inst.error = _("byte or halfword not valid for base register");
+ return;
+ }
+ else if (inst.operands[1].reg == REG_PC
+ && !(inst.instruction & THUMB_LOAD_BIT))
+ {
+ inst.error = _("r15 based store not allowed");
+ return;
+ }
+ else if (inst.operands[1].immisreg)
+ {
+ inst.error = _("invalid base register for register offset");
+ return;
+ }
+
+ if (inst.operands[1].reg == REG_PC)
+ inst.instruction = T_OPCODE_LDR_PC;
+ else if (inst.instruction & THUMB_LOAD_BIT)
+ inst.instruction = T_OPCODE_LDR_SP;
+ else
+ inst.instruction = T_OPCODE_STR_SP;
+
+ inst.instruction |= inst.operands[0].reg << 8;
}
- if (inst.operands[0].imm & ~0xff)
+ else if (!inst.operands[1].immisreg)
{
- if ((inst.instruction == T_OPCODE_PUSH
- && (inst.operands[0].imm & ~0xff) == 1 << REG_LR)
- || (inst.instruction == T_OPCODE_POP
- && (inst.operands[0].imm & ~0xff) == 1 << REG_PC))
+ /* Immediate offset. */
+ switch (inst.instruction)
{
- inst.instruction |= THUMB_PP_PC_LR;
- inst.operands[0].imm &= 0xff;
+ case T_OPCODE_STR_RW: inst.instruction = T_OPCODE_STR_IW; break;
+ case T_OPCODE_STR_RH: inst.instruction = T_OPCODE_STR_IH; break;
+ case T_OPCODE_STR_RB: inst.instruction = T_OPCODE_STR_IB; break;
+ case T_OPCODE_LDR_RW: inst.instruction = T_OPCODE_LDR_IW; break;
+ case T_OPCODE_LDR_RH: inst.instruction = T_OPCODE_LDR_IH; break;
+ case T_OPCODE_LDR_RB: inst.instruction = T_OPCODE_LDR_IB; break;
+ default: abort ();
}
+
+ inst.instruction |= inst.operands[0].reg;
+ inst.instruction |= inst.operands[1].reg << 3;
+ }
+ else
+ {
+ /* Register offset. Opcode is already correct. */
+ inst.instruction |= inst.operands[0].reg;
+ inst.instruction |= inst.operands[1].reg << 3;
+ inst.instruction |= inst.operands[1].imm << 6;
+ }
+}
+
+static void
+do_t_mov_cmp (char * str)
+{
+ if (parse_operands (str, OPERANDS2(RR,RR_iEX)))
+ return;
+
+ if (inst.operands[1].isreg)
+ {
+ if (inst.operands[0].reg < 8 && inst.operands[1].reg < 8)
+ {
+ /* A move of two lowregs is encoded as ADD Rd, Rs, #0
+ since a MOV instruction produces unpredictable results. */
+ if (inst.instruction == T_OPCODE_MOV_HR)
+ inst.instruction = T_OPCODE_ADD_I3;
+ else
+ inst.instruction = T_OPCODE_CMP_LR;
+
+ inst.instruction |= inst.operands[0].reg;
+ inst.instruction |= inst.operands[1].reg << 3;
+ }
else
{
- inst.error = _("invalid register list to push/pop instruction");
- return;
+ /* Opcode in inst.instruction is already correct. */
+ inst.instruction |= (inst.operands[0].reg & 0x8) << 4;
+ inst.instruction |= (inst.operands[0].reg & 0x7);
+ inst.instruction |= inst.operands[1].reg << 3;
}
}
+ else
+ {
+ if (inst.operands[0].reg > 7)
+ {
+ inst.error = _("only lo regs allowed with immediate");
+ return;
+ }
- inst.instruction |= inst.operands[0].imm;
+ if (inst.instruction == T_OPCODE_MOV_HR)
+ inst.instruction = T_OPCODE_MOV_I8;
+ else
+ inst.instruction = T_OPCODE_CMP_I8;
+
+ inst.instruction |= inst.operands[0].reg << 8;
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
+ }
}
-/* THUMB SETEND instruction (argument parse). */
static void
do_t_setend (char * str)
@@ -6752,6 +6662,56 @@
}
static void
+do_t_shift (char * str)
+{
+ int Rs;
+ if (parse_operands (str, OPERANDS3(RL,RL_iEX,oRL_iEX)))
+ return;
+
+ if (inst.operands[2].present)
+ {
+ /* If there were three operands, operand 1 must be a register. */
+ if (!inst.operands[1].isreg)
+ {
+ inst.error = BAD_ARGS;
+ return;
+ }
+ else if (inst.operands[2].isreg) /* Rd, Rs, Rn */
+ {
+ if (inst.operands[0].reg != inst.operands[1].reg)
+ {
+ inst.error = _("source1 and dest must be same register");
+ return;
+ }
+ inst.instruction |= inst.operands[0].reg;
+ inst.instruction |= inst.operands[2].reg << 3;
+ return;
+ }
+ else /* Rd, Rs, imm */
+ Rs = inst.operands[1].reg;
+ }
+ else if (inst.operands[1].isreg) /* Rd, Rs -> Rd, Rd, Rs */
+ {
+ inst.instruction |= inst.operands[0].reg;
+ inst.instruction |= inst.operands[2].reg << 3;
+ return;
+ }
+ else /* Rd, imm -> Rd, Rd, imm */
+ Rs = inst.operands[0].reg;
+
+ /* If we get here, we are doing a shift by an immediate. inst.operands[0].reg
+ and Rs are the registers, and inst.reloc is the immediate. */
+ switch (inst.instruction)
+ {
+ case T_OPCODE_ASR_R: inst.instruction = T_OPCODE_ASR_I; break;
+ case T_OPCODE_LSL_R: inst.instruction = T_OPCODE_LSL_I; break;
+ case T_OPCODE_LSR_R: inst.instruction = T_OPCODE_LSR_I; break;
+ }
+ inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
+ inst.instruction |= inst.operands[0].reg | (Rs << 3);
+}
+
+static void
do_t_swi (char * str)
{
if (parse_operands (str, OPERANDS1(EXP)))
@@ -6759,6 +6719,43 @@
inst.reloc.type = BFD_RELOC_ARM_SWI;
}
+
+static void
+do_t_push_pop (char * str)
+{
+ if (parse_operands (str, OPERANDS1(REGLST)))
+ return;
+ if (inst.operands[0].writeback)
+ {
+ inst.error = _("push/pop do not support {reglist}^");
+ return;
+ }
+ if (inst.reloc.type != BFD_RELOC_UNUSED)
+ {
+ /* This really doesn't seem worth it. */
+ inst.reloc.type = BFD_RELOC_UNUSED;
+ inst.error = _("expression too complex");
+ return;
+ }
+ if (inst.operands[0].imm & ~0xff)
+ {
+ if ((inst.instruction == T_OPCODE_PUSH
+ && (inst.operands[0].imm & ~0xff) == 1 << REG_LR)
+ || (inst.instruction == T_OPCODE_POP
+ && (inst.operands[0].imm & ~0xff) == 1 << REG_PC))
+ {
+ inst.instruction |= THUMB_PP_PC_LR;
+ inst.operands[0].imm &= 0xff;
+ }
+ else
+ {
+ inst.error = _("invalid register list to push/pop instruction");
+ return;
+ }
+ }
+
+ inst.instruction |= inst.operands[0].imm;
+}
/* VFP instructions. In a logical order: SP variant first, monad
before dyad, arithmetic then move then load/store. */