2005-07-29 Paul Brook <paul@codesourcery.com>
[deliverable/binutils-gdb.git] / gas / config / tc-arm.c
index 0c9911f767289cb23b6f9fe47b6dc1709e7d8fd6..12b4addd3a839bfdc55ed6d4c0577695d98d7299 100644 (file)
@@ -3491,6 +3491,55 @@ parse_cond (char **str)
   return c->value;
 }
 
+/* Parse the operands of a table branch instruction.  Similar to a memory
+   operand.  */
+static int
+parse_tb (char **str)
+{
+  char * p = *str;
+  int reg;
+
+  if (skip_past_char (&p, '[') == FAIL)
+    return FAIL;
+
+  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
+    {
+      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
+      return FAIL;
+    }
+  inst.operands[0].reg = reg;
+
+  if (skip_past_comma (&p) == FAIL)
+    return FAIL;
+  
+  if ((reg = arm_reg_parse (&p, REG_TYPE_RN)) == FAIL)
+    {
+      inst.error = _(reg_expected_msgs[REG_TYPE_RN]);
+      return FAIL;
+    }
+  inst.operands[0].imm = reg;
+
+  if (skip_past_comma (&p) == SUCCESS)
+    {
+      if (parse_shift (&p, 0, SHIFT_LSL_IMMEDIATE) == FAIL)
+       return FAIL;
+      if (inst.reloc.exp.X_add_number != 1)
+       {
+         inst.error = _("invalid shift");
+         return FAIL;
+       }
+      inst.operands[0].shifted = 1;
+    }
+
+  if (skip_past_char (&p, ']') == FAIL)
+    {
+      inst.error = _("']' expected");
+      return FAIL;
+    }
+  *str = p;
+  return SUCCESS;
+}
+
 /* Matcher codes for parse_operands.  */
 enum operand_parse_code
 {
@@ -3546,6 +3595,7 @@ enum operand_parse_code
   OP_ENDI,     /* Endianness specifier */
   OP_PSR,      /* CPSR/SPSR mask for msr */
   OP_COND,     /* conditional code */
+  OP_TB,       /* Table branch.  */
 
   OP_RRnpc_I0, /* ARM register or literal 0 */
   OP_RR_EXr,   /* ARM register or expression with opt. reloc suff. */
@@ -3787,6 +3837,10 @@ parse_operands (char *str, const unsigned char *pattern)
        case OP_PSR:     val = parse_psr (&str);                break;
        case OP_COND:    val = parse_cond (&str);               break;
 
+       case OP_TB:
+         po_misc_or_fail (parse_tb (&str));
+         break;
+
          /* Register lists */
        case OP_REGLST:
          val = parse_reg_list (&str);
@@ -5774,6 +5828,20 @@ static const unsigned int thumb_op32[] = { T16_32_TAB };
 
 /* Thumb instruction encoders, in alphabetical order.  */
 
+/* ADDW or SUBW.  */
+static void
+do_t_add_sub_w (void)
+{
+  int Rd, Rn;
+
+  Rd = inst.operands[0].reg;
+  Rn = inst.operands[1].reg;
+
+  constraint (Rd == 15, _("PC not allowed as destination"));
+  inst.instruction |= (Rn << 16) | (Rd << 8);
+  inst.reloc.type = BFD_RELOC_ARM_T32_IMM12;
+}
+
 /* Parse an add or subtract instruction.  We get here with inst.instruction
    equalling any of THUMB_OPCODE_add, adds, sub, or subs.  */
 
@@ -7223,6 +7291,21 @@ do_t_swi (void)
   inst.reloc.type = BFD_RELOC_ARM_SWI;
 }
 
+static void
+do_t_tb (void)
+{
+  int half;
+
+  half = (inst.instruction & 0x10) != 0;
+  constraint (inst.operands[0].imm == 15,
+             _("PC is not a valid index register"));
+  constraint (!half && inst.operands[0].shifted,
+             _("instruction does not allow shifted index"));
+  constraint (half && !inst.operands[0].shifted,
+             _("instruction requires shifted index"));
+  inst.instruction |= (inst.operands[0].reg << 16) | inst.operands[0].imm;
+}
+
 static void
 do_t_usat (void)
 {
@@ -8464,6 +8547,15 @@ static const struct asm_opcode insns[] =
  TUE(ittee,     0, bf09, 1, (COND),    it, t_it),
  TUE(iteee,     0, bf01, 1, (COND),    it, t_it),
 
+ /* Thumb2 only instructions.  */
+#undef ARM_VARIANT
+#define ARM_VARIANT 0
+
+ TCE(addw,     0, f2000000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
+ TCE(subw,     0, f2a00000, 3, (RR, RR, EXPi), 0, t_add_sub_w),
+ TCE(tbb,       0, e8d0f000, 1, (TB), 0, t_tb),
+ TCE(tbh,       0, e8d0f010, 1, (TB), 0, t_tb),
+
 #undef ARM_VARIANT
 #define ARM_VARIANT FPU_FPA_EXT_V1  /* Core FPA instruction set (V1).  */
   CE(wfs,      e200110, 1, (RR),            rd),
@@ -10439,6 +10531,7 @@ md_apply_fix (fixS *    fixP,
       break;
 
     case BFD_RELOC_ARM_T32_IMMEDIATE:
+    case BFD_RELOC_ARM_T32_IMM12:
       /* We claim that this fixup has been processed here,
         even if in fact we generate an error because we do
         not have a reloc for it, so tc_gen_reloc will reject it.  */
@@ -10457,7 +10550,15 @@ md_apply_fix (fixS *   fixP,
       newval <<= 16;
       newval |= md_chars_to_number (buf+2, THUMB_SIZE);
 
-      newimm = encode_thumb32_immediate (value);
+      if (fixP->fx_r_type == BFD_RELOC_ARM_T32_IMM12)
+       {
+         if (value > 0xfff)
+           newimm = (unsigned int) FAIL;
+         else
+           newimm = value;
+       }
+      else
+       newimm = encode_thumb32_immediate (value);
 
       /* FUTURE: Implement analogue of negate_data_op for T32.  */
       if (newimm == (unsigned int)FAIL)
This page took 0.02817 seconds and 4 git commands to generate.