This is the mail archive of the
binutils@sources.redhat.com
mailing list for the binutils project.
Thumb32 assembler (66/69)
- From: Zack Weinberg <zack at codesourcery dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Tue, 26 Apr 2005 03:02:19 -0700
- Subject: Thumb32 assembler (66/69)
Finally we get to implement some new instructions in the assembler!
This adds the new 16-bit Thumb instructions CZB and IT. Now you see
what I kept the conditions table around for.
zw
gas:
* config/tc-arm.c (parse_cond): New operand parser function.
(OP_COND): New operand parser code.
(parse_operands): Handle it.
(do_t_czb, do_t_it): New encoding functions.
(conds): Remove offsets from values.
(UT): New notational macro for insns.
(insns): Add CZB (2 variants) and IT (15 variants).
(md_apply_fix3): Add support for BFD_RELOC_THUMB_PCREL_BRANCH7.
(tc_gen_reloc): Add support for BFD_RELOC_THUMB_PCREL_BRANCH7,
BFD_RELOC_PCREL_BRANCH20, and BFD_RELOC_PCREL_BRANCH25.
opcodes:
* arm-dis.c (thumb_opcodes): Add CZB (2 variants) and IT (7 variants).
Use %8-11c, not %T, for conditional branch.
(print_insn_thumb16): Remove %T support. Add %b and %<bitfield>c
support.
===================================================================
Index: gas/config/tc-arm.c
--- gas/config/tc-arm.c (revision 76)
+++ gas/config/tc-arm.c (revision 77)
@@ -3400,6 +3400,29 @@
}
}
+/* Parse a conditional code (from conds[] below). The value returned is in the
+ range 0 .. 14, or FAIL. */
+static int
+parse_cond (char **str)
+{
+ char *p, *q;
+ const struct asm_cond *c;
+
+ p = q = *str;
+ while (ISALPHA (*q))
+ q++;
+
+ c = hash_find_n (arm_cond_hsh, p, q - p);
+ if (!c)
+ {
+ inst.error = _("condition required");
+ return FAIL;
+ }
+
+ *str = q;
+ return c->value;
+}
+
/* Matcher codes for parse_operands. */
enum operand_parse_code
{
@@ -3454,6 +3477,7 @@
OP_CPSF, /* CPS flags */
OP_ENDI, /* Endianness specifier */
OP_PSR, /* CPSR/SPSR mask for msr */
+ OP_COND, /* conditional code */
OP_RRnpc_I0, /* ARM register or literal 0 */
OP_RR_EXr, /* ARM register or expression with opt. reloc suff. */
@@ -3689,6 +3713,7 @@
case OP_ENDI: val = parse_endian_specifier (&str); break;
case OP_oROR: val = parse_ror (&str); break;
case OP_PSR: val = parse_psr (&str); break;
+ case OP_COND: val = parse_cond (&str); break;
/* Register lists */
case OP_REGLST:
@@ -3750,6 +3775,7 @@
case OP_ENDI:
case OP_oROR:
case OP_PSR:
+ case OP_COND:
case OP_REGLST:
case OP_VRSLST:
case OP_VRDLST:
@@ -5540,6 +5566,39 @@
}
static void
+do_t_czb (void)
+{
+ constraint (inst.operands[0].reg > 7, BAD_HIREG);
+ inst.instruction |= inst.operands[0].reg;
+ inst.reloc.pc_rel = 1;
+ inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH7;
+}
+
+static void
+do_t_it (void)
+{
+ unsigned int cond = inst.operands[0].imm;
+ if (cond & 0x1)
+ {
+ unsigned int mask = inst.instruction & 0x000f;
+ inst.instruction &= 0xfff0;
+
+ if ((mask & 0x7) == 0)
+ /* no conversion needed */;
+ else if ((mask & 0x3) == 0)
+ mask = (~(mask & 0x8) & 0x8) | 0x4;
+ else if ((mask & 1) == 0)
+ mask = (~(mask & 0xC) & 0xC) | 0x2;
+ else
+ mask = (~(mask & 0xE) & 0xE) | 0x1;
+
+ inst.instruction |= (mask & 0xF);
+ }
+
+ inst.instruction |= cond << 4;
+}
+
+static void
do_t_ldmstm (void)
{
/* This really doesn't seem worth it. */
@@ -6246,25 +6305,24 @@
#endif
};
-/* Table of all conditional suffixes. 0xF... is for special-case,
- unconditional instructions. */
+/* Table of all conditional suffixes. 0xF is not defined as a condition code. */
static const struct asm_cond conds[] =
{
- {"eq", 0x00000000},
- {"ne", 0x10000000},
- {"cs", 0x20000000}, {"hs", 0x20000000},
- {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000},
- {"mi", 0x40000000},
- {"pl", 0x50000000},
- {"vs", 0x60000000},
- {"vc", 0x70000000},
- {"hi", 0x80000000},
- {"ls", 0x90000000},
- {"ge", 0xa0000000},
- {"lt", 0xb0000000},
- {"gt", 0xc0000000},
- {"le", 0xd0000000},
- {"al", 0xe0000000}
+ {"eq", 0x0},
+ {"ne", 0x1},
+ {"cs", 0x2}, {"hs", 0x2},
+ {"cc", 0x3}, {"ul", 0x3}, {"lo", 0x3},
+ {"mi", 0x4},
+ {"pl", 0x5},
+ {"vs", 0x6},
+ {"vc", 0x7},
+ {"hi", 0x8},
+ {"ls", 0x9},
+ {"ge", 0xa},
+ {"lt", 0xb},
+ {"gt", 0xc},
+ {"le", 0xd},
+ {"al", 0xe}
};
/* Table of ARM-format instructions. */
@@ -6356,6 +6414,11 @@
#define UF(mnem, op, nops, ops, ae) TUF(mnem, op, 0, nops, ops, ae, 0)
#define do_0 0
+/* unconditional Thumb-only */
+#define UT(mnem, op, nops, ops, te) \
+ { #mnem, OPS##nops ops, 0, 0x##op, 0, THUMB_VARIANT, 0, do_##te }
+
+
static const struct asm_opcode insns[] =
{
#define ARM_VARIANT ARM_EXT_V1 /* Core ARM Instructions. */
@@ -6714,6 +6777,24 @@
CM(ldr,sbt, 03000d0, 2, (RR, ADDR), ldsttv4),
CM(str,ht, 02000b0, 2, (RR, ADDR), ldsttv4),
+ UT(czbne, b900, 2, (RR, EXP), t_czb),
+ UT(czbeq, b100, 2, (RR, EXP), t_czb),
+ UT(it, bf08, 1, (COND), t_it),
+ UT(itt, bf0c, 1, (COND), t_it),
+ UT(ite, bf04, 1, (COND), t_it),
+ UT(ittt, bf0e, 1, (COND), t_it),
+ UT(itet, bf06, 1, (COND), t_it),
+ UT(itte, bf0a, 1, (COND), t_it),
+ UT(itee, bf02, 1, (COND), t_it),
+ UT(itttt, bf0f, 1, (COND), t_it),
+ UT(itett, bf07, 1, (COND), t_it),
+ UT(ittet, bf0b, 1, (COND), t_it),
+ UT(iteet, bf03, 1, (COND), t_it),
+ UT(ittte, bf0d, 1, (COND), t_it),
+ UT(itete, bf05, 1, (COND), t_it),
+ UT(ittee, bf09, 1, (COND), t_it),
+ UT(iteee, bf01, 1, (COND), t_it),
+
#undef ARM_VARIANT
#define ARM_VARIANT FPU_FPA_EXT_V1 /* Core FPA instruction set (V1). */
CE(wfs, e200110, 1, (RR), rd),
@@ -7542,6 +7623,7 @@
#undef CM
#undef UE
#undef UF
+#undef UT
#undef OPS0
#undef OPS1
#undef OPS2
@@ -8664,6 +8746,32 @@
}
break;
+ case BFD_RELOC_THUMB_PCREL_BRANCH7: /* CZB */
+ newval = md_chars_to_number (buf, THUMB_SIZE);
+ {
+ addressT diff = ((newval & 0x00f8) >> 2) | (newval & 0x0200) >> 3;
+ fprintf (stderr, "%lx %lx\n", value, diff);
+ value = value + diff;
+ /* CZB can only branch forward. */
+ if (value & ~0x3f)
+ as_bad_where (fixP->fx_file, fixP->fx_line,
+ _("branch out of range"));
+ if (seg->use_rela_p && !fixP->fx_done)
+ {
+#ifdef OBJ_ELF
+ fixP->fx_offset = value;
+#endif
+ fixP->fx_addnumber = value;
+ newval = newval & 0xfd07;
+ }
+ else
+ newval = ((newval & 0xfd07)
+ | ((value & 0x1e) << 2)
+ | ((value & 0x20) << 3));
+ }
+ md_number_to_chars (buf, newval, THUMB_SIZE);
+ break;
+
case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
newval = md_chars_to_number (buf, THUMB_SIZE);
{
@@ -9105,9 +9213,12 @@
case BFD_RELOC_ARM_PCREL_BRANCH:
case BFD_RELOC_ARM_PCREL_BLX:
case BFD_RELOC_RVA:
+ case BFD_RELOC_THUMB_PCREL_BRANCH7:
case BFD_RELOC_THUMB_PCREL_BRANCH9:
case BFD_RELOC_THUMB_PCREL_BRANCH12:
+ case BFD_RELOC_THUMB_PCREL_BRANCH20:
case BFD_RELOC_THUMB_PCREL_BRANCH23:
+ case BFD_RELOC_THUMB_PCREL_BRANCH25:
case BFD_RELOC_THUMB_PCREL_BLX:
case BFD_RELOC_VTABLE_ENTRY:
case BFD_RELOC_VTABLE_INHERIT:
===================================================================
Index: opcodes/arm-dis.c
--- opcodes/arm-dis.c (revision 76)
+++ opcodes/arm-dis.c (revision 77)
@@ -98,12 +98,12 @@
%M print Thumb register mask
%N print Thumb register mask (with LR)
%O print Thumb register mask (with PC)
- %T print Thumb condition code (always bits 8-11)
%I print cirrus signed shift immediate: bits 0..3|4..6
%<bitfield>B print Thumb branch destination (signed displacement)
%<bitfield>W print (bitfield * 4) as a decimal
%<bitfield>H print (bitfield * 2) as a decimal
%<bitfield>a print (bitfield * 4) as a pc-rel offset + decoded symbol
+ %<bitfield>c print bitfield as a condition code
%e print arm SMI operand (bits 0..7,8..19).
%s print Thumb right-shift immediate (6..10; 0 == 32). */
@@ -643,6 +643,17 @@
{ARM_EXT_V6K, 0xbf30, 0xffff, "wfi"},
{ARM_EXT_V6K, 0xbf40, 0xffff, "sev"},
+ /* ARM V6T2 instructions. */
+ {ARM_EXT_V6T2, 0xb900, 0xfd00, "czbne\t%0-2r, %b"},
+ {ARM_EXT_V6T2, 0xb100, 0xfd00, "czbeq\t%0-2r, %b"},
+ {ARM_EXT_V6T2, 0xbf08, 0xff0f, "it\t%4-7c"},
+ {ARM_EXT_V6T2, 0xbf14, 0xff17, "it%3?te\t%4-7c"},
+ {ARM_EXT_V6T2, 0xbf04, 0xff17, "it%3?et\t%4-7c"},
+ {ARM_EXT_V6T2, 0xbf12, 0xff13, "it%3?te%2?te\t%4-7c"},
+ {ARM_EXT_V6T2, 0xbf02, 0xff13, "it%3?et%2?et\t%4-7c"},
+ {ARM_EXT_V6T2, 0xbf11, 0xff11, "it%3?te%2?te%1?te\t%4-7c"},
+ {ARM_EXT_V6T2, 0xbf01, 0xff11, "it%3?et%2?et%1?et\t%4-7c"},
+
/* ARM V6. */
{ARM_EXT_V6, 0xb660, 0xfff8, "cpsie\t%2'a%1'i%0'f"},
{ARM_EXT_V6, 0xb670, 0xfff8, "cpsid\t%2'a%1'i%0'f"},
@@ -733,7 +744,7 @@
/* format 17 */
{ARM_EXT_V4T, 0xDF00, 0xFF00, "swi\t%0-7d"},
/* format 16 */
- {ARM_EXT_V4T, 0xD000, 0xF000, "b%T.n\t%0-7B"},
+ {ARM_EXT_V4T, 0xD000, 0xF000, "b%8-11c.n\t%0-7B"},
/* format 18 */
{ARM_EXT_V4T, 0xE000, 0xF800, "b.n\t%0-10B"},
@@ -1952,18 +1963,6 @@
}
break;
- case 'T':
- {
- long cc = (given >> 8) & 0xf;
- /* Must print 0xE as 'al' to distinguish
- unconditional B from conditional BAL. */
- if (cc == 0xE)
- func (stream, "al");
- else
- func (stream, "%s", arm_conditional [cc]);
- }
- break;
-
case 'N':
if (given & (1 << 8))
domasklr = 1;
@@ -2009,6 +2008,16 @@
}
break;
+ case 'b':
+ /* Print ARM V6T2 CZB address: pc+4+6 bits. */
+ {
+ bfd_vma address = (pc + 4
+ + ((given & 0x00f8) >> 2)
+ + ((given & 0x0200) >> 3));
+ info->print_address_func (address, info);
+ }
+ break;
+
case 's':
/* Right shift immediate -- bits 6..10; 1-31 print
as themselves, 0 prints as 32. */
@@ -2083,6 +2092,17 @@
(reg * 2 + pc + 4, info);
break;
+ case 'c':
+ {
+ /* Must print 0xE as 'al' to distinguish
+ unconditional B from conditional BAL. */
+ if (reg == 0xE)
+ func (stream, "al");
+ else
+ func (stream, "%s", arm_conditional [reg]);
+ }
+ break;
+
default:
abort ();
}