]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blame - gas/config/tc-arm.c
2005-05-17 Daniel Jacobowitz <dan@codesourcery.com>
[thirdparty/binutils-gdb.git] / gas / config / tc-arm.c
CommitLineData
b99bd4ef 1/* tc-arm.c -- Assemble for the ARM
f17c130b
AM
2 Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003,
3 2004, 2005
b99bd4ef
NC
4 Free Software Foundation, Inc.
5 Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
6 Modified by David Taylor (dtaylor@armltd.co.uk)
22d9c8c5 7 Cirrus coprocessor mods by Aldy Hernandez (aldyh@redhat.com)
34920d91
NC
8 Cirrus coprocessor fixes by Petko Manolov (petkan@nucleusys.com)
9 Cirrus coprocessor fixes by Vladimir Ivanov (vladitx@nucleusys.com)
b99bd4ef
NC
10
11 This file is part of GAS, the GNU Assembler.
12
13 GAS is free software; you can redistribute it and/or modify
14 it under the terms of the GNU General Public License as published by
15 the Free Software Foundation; either version 2, or (at your option)
16 any later version.
17
18 GAS is distributed in the hope that it will be useful,
19 but WITHOUT ANY WARRANTY; without even the implied warranty of
20 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 GNU General Public License for more details.
22
23 You should have received a copy of the GNU General Public License
24 along with GAS; see the file COPYING. If not, write to the Free
699d2810
NC
25 Software Foundation, 51 Franklin Street - Fifth Floor, Boston, MA
26 02110-1301, USA. */
b99bd4ef 27
b99bd4ef
NC
28#include <string.h>
29#define NO_RELOC 0
30#include "as.h"
3882b010 31#include "safe-ctype.h"
b99bd4ef
NC
32
33/* Need TARGET_CPU. */
34#include "config.h"
35#include "subsegs.h"
36#include "obstack.h"
37#include "symbols.h"
38#include "listing.h"
39
f263249b
RE
40#include "opcode/arm.h"
41
b99bd4ef
NC
42#ifdef OBJ_ELF
43#include "elf/arm.h"
44#include "dwarf2dbg.h"
a394c00f 45#include "dw2gencfi.h"
b99bd4ef
NC
46#endif
47
7ed4c4c5 48/* XXX Set this to 1 after the next binutils release. */
03b1477f
RE
49#define WARN_DEPRECATED 0
50
7ed4c4c5
NC
51#ifdef OBJ_ELF
52/* Must be at least the size of the largest unwind opcode (currently two). */
53#define ARM_OPCODE_CHUNK_SIZE 8
54
55/* This structure holds the unwinding state. */
56
57static struct
58{
59 symbolS * proc_start;
60 symbolS * table_entry;
61 symbolS * personality_routine;
62 int personality_index;
63 /* The segment containing the function. */
64 segT saved_seg;
65 subsegT saved_subseg;
66 /* Opcodes generated from this function. */
67 unsigned char * opcodes;
68 int opcode_count;
69 int opcode_alloc;
70 /* The number of bytes pushed to the stack. */
71 offsetT frame_size;
72 /* We don't add stack adjustment opcodes immediately so that we can merge
73 multiple adjustments. We can also omit the final adjustment
74 when using a frame pointer. */
75 offsetT pending_offset;
76 /* These two fields are set by both unwind_movsp and unwind_setfp. They
77 hold the reg+offset to use when restoring sp from a frame pointer. */
78 offsetT fp_offset;
79 int fp_reg;
80 /* Nonzero if an unwind_setfp directive has been seen. */
81 unsigned fp_used:1;
82 /* Nonzero if the last opcode restores sp from fp_reg. */
83 unsigned sp_restored:1;
84} unwind;
85
84798bd6
JB
86/* Bit N indicates that an R_ARM_NONE relocation has been output for
87 __aeabi_unwind_cpp_prN already if set. This enables dependencies to be
88 emitted only once per section, to save unnecessary bloat. */
89static unsigned int marked_pr_dependency = 0;
90
7ed4c4c5
NC
91#endif /* OBJ_ELF */
92
33a392fb
PB
93enum arm_float_abi
94{
95 ARM_FLOAT_ABI_HARD,
96 ARM_FLOAT_ABI_SOFTFP,
97 ARM_FLOAT_ABI_SOFT
98};
99
b89dddec
RE
100/* Types of processor to assemble for. */
101#define ARM_1 ARM_ARCH_V1
102#define ARM_2 ARM_ARCH_V2
103#define ARM_3 ARM_ARCH_V2S
104#define ARM_250 ARM_ARCH_V2S
105#define ARM_6 ARM_ARCH_V3
106#define ARM_7 ARM_ARCH_V3
107#define ARM_8 ARM_ARCH_V4
108#define ARM_9 ARM_ARCH_V4T
109#define ARM_STRONG ARM_ARCH_V4
110#define ARM_CPU_MASK 0x0000000f /* XXX? */
b99bd4ef
NC
111
112#ifndef CPU_DEFAULT
113#if defined __XSCALE__
b89dddec 114#define CPU_DEFAULT (ARM_ARCH_XSCALE)
b99bd4ef
NC
115#else
116#if defined __thumb__
b89dddec 117#define CPU_DEFAULT (ARM_ARCH_V5T)
b99bd4ef 118#else
03b1477f 119#define CPU_DEFAULT ARM_ANY
b99bd4ef
NC
120#endif
121#endif
122#endif
123
124#ifndef FPU_DEFAULT
c820d418
MM
125# ifdef TE_LINUX
126# define FPU_DEFAULT FPU_ARCH_FPA
127# elif defined (TE_NetBSD)
128# ifdef OBJ_ELF
129# define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, but VFP order. */
130# else
131 /* Legacy a.out format. */
132# define FPU_DEFAULT FPU_ARCH_FPA /* Soft-float, but FPA order. */
133# endif
4e7fd91e
PB
134# elif defined (TE_VXWORKS)
135# define FPU_DEFAULT FPU_ARCH_VFP /* Soft-float, VFP order. */
c820d418
MM
136# else
137 /* For backwards compatibility, default to FPA. */
138# define FPU_DEFAULT FPU_ARCH_FPA
139# endif
140#endif /* ifndef FPU_DEFAULT */
b99bd4ef
NC
141
142#define streq(a, b) (strcmp (a, b) == 0)
143#define skip_whitespace(str) while (*(str) == ' ') ++(str)
144
03b1477f 145static unsigned long cpu_variant;
b99bd4ef 146
b99bd4ef 147/* Flags stored in private area of BFD structure. */
b34976b6
AM
148static int uses_apcs_26 = FALSE;
149static int atpcs = FALSE;
150static int support_interwork = FALSE;
151static int uses_apcs_float = FALSE;
152static int pic_code = FALSE;
03b1477f
RE
153
154/* Variables that we set while parsing command-line options. Once all
155 options have been read we re-process these values to set the real
156 assembly flags. */
157static int legacy_cpu = -1;
158static int legacy_fpu = -1;
159
160static int mcpu_cpu_opt = -1;
161static int mcpu_fpu_opt = -1;
162static int march_cpu_opt = -1;
163static int march_fpu_opt = -1;
164static int mfpu_opt = -1;
33a392fb 165static int mfloat_abi_opt = -1;
7cc69913 166#ifdef OBJ_ELF
deeaaff8
DJ
167# ifdef EABI_DEFAULT
168static int meabi_flags = EABI_DEFAULT;
169# else
d507cf36 170static int meabi_flags = EF_ARM_EABI_UNKNOWN;
deeaaff8 171# endif
7cc69913 172#endif
b99bd4ef
NC
173
174/* This array holds the chars that always start a comment. If the
175 pre-processor is disabled, these aren't very useful. */
f57c81f6 176const char comment_chars[] = "@";
b99bd4ef
NC
177
178/* This array holds the chars that only start a comment at the beginning of
179 a line. If the line seems to have the form '# 123 filename'
180 .line and .file directives will appear in the pre-processed output. */
181/* Note that input_file.c hand checks for '#' at the beginning of the
182 first line of the input file. This is because the compiler outputs
183 #NO_APP at the beginning of its output. */
184/* Also note that comments like this one will always work. */
05d2d07e 185const char line_comment_chars[] = "#";
b99bd4ef 186
da89cce1 187const char line_separator_chars[] = ";";
b99bd4ef
NC
188
189/* Chars that can be used to separate mant
190 from exp in floating point numbers. */
05d2d07e 191const char EXP_CHARS[] = "eE";
b99bd4ef
NC
192
193/* Chars that mean this number is a floating point constant. */
194/* As in 0f12.456 */
195/* or 0d1.2345e12 */
196
05d2d07e 197const char FLT_CHARS[] = "rRsSfFdDxXeEpP";
b99bd4ef
NC
198
199/* Prefix characters that indicate the start of an immediate
200 value. */
201#define is_immediate_prefix(C) ((C) == '#' || (C) == '$')
202
203#ifdef OBJ_ELF
204/* Pre-defined "_GLOBAL_OFFSET_TABLE_" */
205symbolS * GOT_symbol;
206#endif
207
208/* Size of relocation record. */
05d2d07e 209const int md_reloc_size = 8;
b99bd4ef
NC
210
211/* 0: assemble for ARM,
212 1: assemble for Thumb,
213 2: assemble for Thumb even though target CPU does not support thumb
214 instructions. */
215static int thumb_mode = 0;
216
217typedef struct arm_fix
218{
219 int thumb_mode;
220} arm_fix_data;
221
222struct arm_it
223{
05d2d07e 224 const char * error;
b99bd4ef 225 unsigned long instruction;
b99bd4ef
NC
226 int size;
227 struct
228 {
229 bfd_reloc_code_real_type type;
230 expressionS exp;
231 int pc_rel;
232 } reloc;
233};
234
235struct arm_it inst;
236
237enum asm_shift_index
238{
239 SHIFT_LSL = 0,
240 SHIFT_LSR,
241 SHIFT_ASR,
242 SHIFT_ROR,
243 SHIFT_RRX
244};
245
246struct asm_shift_properties
247{
248 enum asm_shift_index index;
249 unsigned long bit_field;
250 unsigned int allows_0 : 1;
251 unsigned int allows_32 : 1;
252};
253
254static const struct asm_shift_properties shift_properties [] =
255{
256 { SHIFT_LSL, 0, 1, 0},
257 { SHIFT_LSR, 0x20, 0, 1},
258 { SHIFT_ASR, 0x40, 0, 1},
259 { SHIFT_ROR, 0x60, 0, 0},
260 { SHIFT_RRX, 0x60, 0, 0}
261};
262
263struct asm_shift_name
264{
265 const char * name;
266 const struct asm_shift_properties * properties;
267};
268
269static const struct asm_shift_name shift_names [] =
270{
271 { "asl", shift_properties + SHIFT_LSL },
272 { "lsl", shift_properties + SHIFT_LSL },
273 { "lsr", shift_properties + SHIFT_LSR },
274 { "asr", shift_properties + SHIFT_ASR },
275 { "ror", shift_properties + SHIFT_ROR },
276 { "rrx", shift_properties + SHIFT_RRX },
277 { "ASL", shift_properties + SHIFT_LSL },
278 { "LSL", shift_properties + SHIFT_LSL },
279 { "LSR", shift_properties + SHIFT_LSR },
280 { "ASR", shift_properties + SHIFT_ASR },
281 { "ROR", shift_properties + SHIFT_ROR },
282 { "RRX", shift_properties + SHIFT_RRX }
283};
284
09d92015 285/* Any kind of shift is accepted. */
b99bd4ef 286#define NO_SHIFT_RESTRICT 1
09d92015
MM
287/* The shift operand must be an immediate value, not a register. */
288#define SHIFT_IMMEDIATE 0
289/* The shift must be LSL or ASR and the operand must be an immediate. */
290#define SHIFT_LSL_OR_ASR_IMMEDIATE 2
291/* The shift must be ASR and the operand must be an immediate. */
292#define SHIFT_ASR_IMMEDIATE 3
293/* The shift must be LSL and the operand must be an immediate. */
294#define SHIFT_LSL_IMMEDIATE 4
b99bd4ef
NC
295
296#define NUM_FLOAT_VALS 8
297
05d2d07e 298const char * fp_const[] =
b99bd4ef
NC
299{
300 "0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0", 0
301};
302
303/* Number of littlenums required to hold an extended precision number. */
304#define MAX_LITTLENUMS 6
305
306LITTLENUM_TYPE fp_values[NUM_FLOAT_VALS][MAX_LITTLENUMS];
307
308#define FAIL (-1)
309#define SUCCESS (0)
310
bfae80f2
RE
311/* Whether a Co-processor load/store operation accepts write-back forms. */
312#define CP_WB_OK 1
313#define CP_NO_WB 0
314
b99bd4ef
NC
315#define SUFF_S 1
316#define SUFF_D 2
317#define SUFF_E 3
318#define SUFF_P 4
319
320#define CP_T_X 0x00008000
321#define CP_T_Y 0x00400000
322#define CP_T_Pre 0x01000000
323#define CP_T_UD 0x00800000
324#define CP_T_WB 0x00200000
325
326#define CONDS_BIT 0x00100000
327#define LOAD_BIT 0x00100000
b99bd4ef
NC
328
329#define DOUBLE_LOAD_FLAG 0x00000001
330
331struct asm_cond
332{
05d2d07e 333 const char * template;
b99bd4ef
NC
334 unsigned long value;
335};
336
b99bd4ef 337#define COND_ALWAYS 0xe0000000
90e4755a 338#define COND_MASK 0xf0000000
b99bd4ef 339
05d2d07e 340static const struct asm_cond conds[] =
b99bd4ef
NC
341{
342 {"eq", 0x00000000},
343 {"ne", 0x10000000},
344 {"cs", 0x20000000}, {"hs", 0x20000000},
345 {"cc", 0x30000000}, {"ul", 0x30000000}, {"lo", 0x30000000},
346 {"mi", 0x40000000},
347 {"pl", 0x50000000},
348 {"vs", 0x60000000},
349 {"vc", 0x70000000},
350 {"hi", 0x80000000},
351 {"ls", 0x90000000},
352 {"ge", 0xa0000000},
353 {"lt", 0xb0000000},
354 {"gt", 0xc0000000},
355 {"le", 0xd0000000},
356 {"al", 0xe0000000},
357 {"nv", 0xf0000000}
358};
359
b99bd4ef
NC
360struct asm_psr
361{
b34976b6
AM
362 const char *template;
363 bfd_boolean cpsr;
b99bd4ef
NC
364 unsigned long field;
365};
366
2d2255b5 367/* The bit that distinguishes CPSR and SPSR. */
b99bd4ef
NC
368#define SPSR_BIT (1 << 22)
369
370/* How many bits to shift the PSR_xxx bits up by. */
371#define PSR_SHIFT 16
372
373#define PSR_c (1 << 0)
374#define PSR_x (1 << 1)
375#define PSR_s (1 << 2)
376#define PSR_f (1 << 3)
377
05d2d07e 378static const struct asm_psr psrs[] =
b99bd4ef 379{
b34976b6
AM
380 {"CPSR", TRUE, PSR_c | PSR_f},
381 {"CPSR_all", TRUE, PSR_c | PSR_f},
382 {"SPSR", FALSE, PSR_c | PSR_f},
383 {"SPSR_all", FALSE, PSR_c | PSR_f},
384 {"CPSR_flg", TRUE, PSR_f},
385 {"CPSR_f", TRUE, PSR_f},
386 {"SPSR_flg", FALSE, PSR_f},
387 {"SPSR_f", FALSE, PSR_f},
388 {"CPSR_c", TRUE, PSR_c},
389 {"CPSR_ctl", TRUE, PSR_c},
390 {"SPSR_c", FALSE, PSR_c},
391 {"SPSR_ctl", FALSE, PSR_c},
392 {"CPSR_x", TRUE, PSR_x},
393 {"CPSR_s", TRUE, PSR_s},
394 {"SPSR_x", FALSE, PSR_x},
395 {"SPSR_s", FALSE, PSR_s},
b99bd4ef 396 /* Combinations of flags. */
b34976b6
AM
397 {"CPSR_fs", TRUE, PSR_f | PSR_s},
398 {"CPSR_fx", TRUE, PSR_f | PSR_x},
399 {"CPSR_fc", TRUE, PSR_f | PSR_c},
400 {"CPSR_sf", TRUE, PSR_s | PSR_f},
401 {"CPSR_sx", TRUE, PSR_s | PSR_x},
402 {"CPSR_sc", TRUE, PSR_s | PSR_c},
403 {"CPSR_xf", TRUE, PSR_x | PSR_f},
404 {"CPSR_xs", TRUE, PSR_x | PSR_s},
405 {"CPSR_xc", TRUE, PSR_x | PSR_c},
406 {"CPSR_cf", TRUE, PSR_c | PSR_f},
407 {"CPSR_cs", TRUE, PSR_c | PSR_s},
408 {"CPSR_cx", TRUE, PSR_c | PSR_x},
409 {"CPSR_fsx", TRUE, PSR_f | PSR_s | PSR_x},
410 {"CPSR_fsc", TRUE, PSR_f | PSR_s | PSR_c},
411 {"CPSR_fxs", TRUE, PSR_f | PSR_x | PSR_s},
412 {"CPSR_fxc", TRUE, PSR_f | PSR_x | PSR_c},
413 {"CPSR_fcs", TRUE, PSR_f | PSR_c | PSR_s},
414 {"CPSR_fcx", TRUE, PSR_f | PSR_c | PSR_x},
415 {"CPSR_sfx", TRUE, PSR_s | PSR_f | PSR_x},
416 {"CPSR_sfc", TRUE, PSR_s | PSR_f | PSR_c},
417 {"CPSR_sxf", TRUE, PSR_s | PSR_x | PSR_f},
418 {"CPSR_sxc", TRUE, PSR_s | PSR_x | PSR_c},
419 {"CPSR_scf", TRUE, PSR_s | PSR_c | PSR_f},
420 {"CPSR_scx", TRUE, PSR_s | PSR_c | PSR_x},
421 {"CPSR_xfs", TRUE, PSR_x | PSR_f | PSR_s},
422 {"CPSR_xfc", TRUE, PSR_x | PSR_f | PSR_c},
423 {"CPSR_xsf", TRUE, PSR_x | PSR_s | PSR_f},
424 {"CPSR_xsc", TRUE, PSR_x | PSR_s | PSR_c},
425 {"CPSR_xcf", TRUE, PSR_x | PSR_c | PSR_f},
426 {"CPSR_xcs", TRUE, PSR_x | PSR_c | PSR_s},
427 {"CPSR_cfs", TRUE, PSR_c | PSR_f | PSR_s},
428 {"CPSR_cfx", TRUE, PSR_c | PSR_f | PSR_x},
429 {"CPSR_csf", TRUE, PSR_c | PSR_s | PSR_f},
430 {"CPSR_csx", TRUE, PSR_c | PSR_s | PSR_x},
431 {"CPSR_cxf", TRUE, PSR_c | PSR_x | PSR_f},
432 {"CPSR_cxs", TRUE, PSR_c | PSR_x | PSR_s},
433 {"CPSR_fsxc", TRUE, PSR_f | PSR_s | PSR_x | PSR_c},
434 {"CPSR_fscx", TRUE, PSR_f | PSR_s | PSR_c | PSR_x},
435 {"CPSR_fxsc", TRUE, PSR_f | PSR_x | PSR_s | PSR_c},
436 {"CPSR_fxcs", TRUE, PSR_f | PSR_x | PSR_c | PSR_s},
437 {"CPSR_fcsx", TRUE, PSR_f | PSR_c | PSR_s | PSR_x},
438 {"CPSR_fcxs", TRUE, PSR_f | PSR_c | PSR_x | PSR_s},
439 {"CPSR_sfxc", TRUE, PSR_s | PSR_f | PSR_x | PSR_c},
440 {"CPSR_sfcx", TRUE, PSR_s | PSR_f | PSR_c | PSR_x},
441 {"CPSR_sxfc", TRUE, PSR_s | PSR_x | PSR_f | PSR_c},
442 {"CPSR_sxcf", TRUE, PSR_s | PSR_x | PSR_c | PSR_f},
443 {"CPSR_scfx", TRUE, PSR_s | PSR_c | PSR_f | PSR_x},
444 {"CPSR_scxf", TRUE, PSR_s | PSR_c | PSR_x | PSR_f},
445 {"CPSR_xfsc", TRUE, PSR_x | PSR_f | PSR_s | PSR_c},
446 {"CPSR_xfcs", TRUE, PSR_x | PSR_f | PSR_c | PSR_s},
447 {"CPSR_xsfc", TRUE, PSR_x | PSR_s | PSR_f | PSR_c},
448 {"CPSR_xscf", TRUE, PSR_x | PSR_s | PSR_c | PSR_f},
449 {"CPSR_xcfs", TRUE, PSR_x | PSR_c | PSR_f | PSR_s},
450 {"CPSR_xcsf", TRUE, PSR_x | PSR_c | PSR_s | PSR_f},
451 {"CPSR_cfsx", TRUE, PSR_c | PSR_f | PSR_s | PSR_x},
452 {"CPSR_cfxs", TRUE, PSR_c | PSR_f | PSR_x | PSR_s},
453 {"CPSR_csfx", TRUE, PSR_c | PSR_s | PSR_f | PSR_x},
454 {"CPSR_csxf", TRUE, PSR_c | PSR_s | PSR_x | PSR_f},
455 {"CPSR_cxfs", TRUE, PSR_c | PSR_x | PSR_f | PSR_s},
456 {"CPSR_cxsf", TRUE, PSR_c | PSR_x | PSR_s | PSR_f},
457 {"SPSR_fs", FALSE, PSR_f | PSR_s},
458 {"SPSR_fx", FALSE, PSR_f | PSR_x},
459 {"SPSR_fc", FALSE, PSR_f | PSR_c},
460 {"SPSR_sf", FALSE, PSR_s | PSR_f},
461 {"SPSR_sx", FALSE, PSR_s | PSR_x},
462 {"SPSR_sc", FALSE, PSR_s | PSR_c},
463 {"SPSR_xf", FALSE, PSR_x | PSR_f},
464 {"SPSR_xs", FALSE, PSR_x | PSR_s},
465 {"SPSR_xc", FALSE, PSR_x | PSR_c},
466 {"SPSR_cf", FALSE, PSR_c | PSR_f},
467 {"SPSR_cs", FALSE, PSR_c | PSR_s},
468 {"SPSR_cx", FALSE, PSR_c | PSR_x},
469 {"SPSR_fsx", FALSE, PSR_f | PSR_s | PSR_x},
470 {"SPSR_fsc", FALSE, PSR_f | PSR_s | PSR_c},
471 {"SPSR_fxs", FALSE, PSR_f | PSR_x | PSR_s},
472 {"SPSR_fxc", FALSE, PSR_f | PSR_x | PSR_c},
473 {"SPSR_fcs", FALSE, PSR_f | PSR_c | PSR_s},
474 {"SPSR_fcx", FALSE, PSR_f | PSR_c | PSR_x},
475 {"SPSR_sfx", FALSE, PSR_s | PSR_f | PSR_x},
476 {"SPSR_sfc", FALSE, PSR_s | PSR_f | PSR_c},
477 {"SPSR_sxf", FALSE, PSR_s | PSR_x | PSR_f},
478 {"SPSR_sxc", FALSE, PSR_s | PSR_x | PSR_c},
479 {"SPSR_scf", FALSE, PSR_s | PSR_c | PSR_f},
480 {"SPSR_scx", FALSE, PSR_s | PSR_c | PSR_x},
481 {"SPSR_xfs", FALSE, PSR_x | PSR_f | PSR_s},
482 {"SPSR_xfc", FALSE, PSR_x | PSR_f | PSR_c},
483 {"SPSR_xsf", FALSE, PSR_x | PSR_s | PSR_f},
484 {"SPSR_xsc", FALSE, PSR_x | PSR_s | PSR_c},
485 {"SPSR_xcf", FALSE, PSR_x | PSR_c | PSR_f},
486 {"SPSR_xcs", FALSE, PSR_x | PSR_c | PSR_s},
487 {"SPSR_cfs", FALSE, PSR_c | PSR_f | PSR_s},
488 {"SPSR_cfx", FALSE, PSR_c | PSR_f | PSR_x},
489 {"SPSR_csf", FALSE, PSR_c | PSR_s | PSR_f},
490 {"SPSR_csx", FALSE, PSR_c | PSR_s | PSR_x},
491 {"SPSR_cxf", FALSE, PSR_c | PSR_x | PSR_f},
492 {"SPSR_cxs", FALSE, PSR_c | PSR_x | PSR_s},
493 {"SPSR_fsxc", FALSE, PSR_f | PSR_s | PSR_x | PSR_c},
494 {"SPSR_fscx", FALSE, PSR_f | PSR_s | PSR_c | PSR_x},
495 {"SPSR_fxsc", FALSE, PSR_f | PSR_x | PSR_s | PSR_c},
496 {"SPSR_fxcs", FALSE, PSR_f | PSR_x | PSR_c | PSR_s},
497 {"SPSR_fcsx", FALSE, PSR_f | PSR_c | PSR_s | PSR_x},
498 {"SPSR_fcxs", FALSE, PSR_f | PSR_c | PSR_x | PSR_s},
499 {"SPSR_sfxc", FALSE, PSR_s | PSR_f | PSR_x | PSR_c},
500 {"SPSR_sfcx", FALSE, PSR_s | PSR_f | PSR_c | PSR_x},
501 {"SPSR_sxfc", FALSE, PSR_s | PSR_x | PSR_f | PSR_c},
502 {"SPSR_sxcf", FALSE, PSR_s | PSR_x | PSR_c | PSR_f},
503 {"SPSR_scfx", FALSE, PSR_s | PSR_c | PSR_f | PSR_x},
504 {"SPSR_scxf", FALSE, PSR_s | PSR_c | PSR_x | PSR_f},
505 {"SPSR_xfsc", FALSE, PSR_x | PSR_f | PSR_s | PSR_c},
506 {"SPSR_xfcs", FALSE, PSR_x | PSR_f | PSR_c | PSR_s},
507 {"SPSR_xsfc", FALSE, PSR_x | PSR_s | PSR_f | PSR_c},
508 {"SPSR_xscf", FALSE, PSR_x | PSR_s | PSR_c | PSR_f},
509 {"SPSR_xcfs", FALSE, PSR_x | PSR_c | PSR_f | PSR_s},
510 {"SPSR_xcsf", FALSE, PSR_x | PSR_c | PSR_s | PSR_f},
511 {"SPSR_cfsx", FALSE, PSR_c | PSR_f | PSR_s | PSR_x},
512 {"SPSR_cfxs", FALSE, PSR_c | PSR_f | PSR_x | PSR_s},
513 {"SPSR_csfx", FALSE, PSR_c | PSR_s | PSR_f | PSR_x},
514 {"SPSR_csxf", FALSE, PSR_c | PSR_s | PSR_x | PSR_f},
515 {"SPSR_cxfs", FALSE, PSR_c | PSR_x | PSR_f | PSR_s},
516 {"SPSR_cxsf", FALSE, PSR_c | PSR_x | PSR_s | PSR_f},
b99bd4ef
NC
517};
518
e16bb312
NC
519enum wreg_type
520 {
521 IWMMXT_REG_WR = 0,
522 IWMMXT_REG_WC = 1,
523 IWMMXT_REG_WR_OR_WC = 2,
524 IWMMXT_REG_WCG
525 };
526
527enum iwmmxt_insn_type
528{
529 check_rd,
530 check_wr,
531 check_wrwr,
532 check_wrwrwr,
533 check_wrwrwcg,
534 check_tbcst,
535 check_tmovmsk,
536 check_tmia,
537 check_tmcrr,
538 check_tmrrc,
539 check_tmcr,
540 check_tmrc,
541 check_tinsr,
542 check_textrc,
543 check_waligni,
544 check_textrm,
545 check_wshufh
546};
547
bfae80f2
RE
548enum vfp_dp_reg_pos
549{
550 VFP_REG_Dd, VFP_REG_Dm, VFP_REG_Dn
551};
552
553enum vfp_sp_reg_pos
554{
555 VFP_REG_Sd, VFP_REG_Sm, VFP_REG_Sn
556};
557
558enum vfp_ldstm_type
559{
560 VFP_LDSTMIA, VFP_LDSTMDB, VFP_LDSTMIAX, VFP_LDSTMDBX
561};
562
563/* VFP system registers. */
564struct vfp_reg
565{
566 const char *name;
567 unsigned long regno;
568};
569
cc8a6dd0 570static const struct vfp_reg vfp_regs[] =
bfae80f2
RE
571{
572 {"fpsid", 0x00000000},
573 {"FPSID", 0x00000000},
574 {"fpscr", 0x00010000},
575 {"FPSCR", 0x00010000},
576 {"fpexc", 0x00080000},
577 {"FPEXC", 0x00080000}
578};
579
6c43fab6
RE
580/* Structure for a hash table entry for a register. */
581struct reg_entry
582{
583 const char * name;
584 int number;
0bbf2aa4 585 bfd_boolean builtin;
6c43fab6
RE
586};
587
e28cd48c 588/* Some well known registers that we refer to directly elsewhere. */
6c43fab6
RE
589#define REG_SP 13
590#define REG_LR 14
591#define REG_PC 15
592
e16bb312
NC
593#define wr_register(reg) ((reg ^ WR_PREFIX) >= 0 && (reg ^ WR_PREFIX) <= 15)
594#define wc_register(reg) ((reg ^ WC_PREFIX) >= 0 && (reg ^ WC_PREFIX) <= 15)
595#define wcg_register(reg) ((reg ^ WC_PREFIX) >= 8 && (reg ^ WC_PREFIX) <= 11)
596
0bbf2aa4
NC
597/* These are the standard names. Users can add aliases with .req.
598 and delete them with .unreq. */
599
6c43fab6
RE
600/* Integer Register Numbers. */
601static const struct reg_entry rn_table[] =
602{
0bbf2aa4
NC
603 {"r0", 0, TRUE}, {"r1", 1, TRUE}, {"r2", 2, TRUE}, {"r3", 3, TRUE},
604 {"r4", 4, TRUE}, {"r5", 5, TRUE}, {"r6", 6, TRUE}, {"r7", 7, TRUE},
605 {"r8", 8, TRUE}, {"r9", 9, TRUE}, {"r10", 10, TRUE}, {"r11", 11, TRUE},
606 {"r12", 12, TRUE}, {"r13", REG_SP, TRUE}, {"r14", REG_LR, TRUE}, {"r15", REG_PC, TRUE},
6c43fab6 607 /* ATPCS Synonyms. */
0bbf2aa4
NC
608 {"a1", 0, TRUE}, {"a2", 1, TRUE}, {"a3", 2, TRUE}, {"a4", 3, TRUE},
609 {"v1", 4, TRUE}, {"v2", 5, TRUE}, {"v3", 6, TRUE}, {"v4", 7, TRUE},
610 {"v5", 8, TRUE}, {"v6", 9, TRUE}, {"v7", 10, TRUE}, {"v8", 11, TRUE},
6c43fab6 611 /* Well-known aliases. */
0bbf2aa4
NC
612 {"wr", 7, TRUE}, {"sb", 9, TRUE}, {"sl", 10, TRUE}, {"fp", 11, TRUE},
613 {"ip", 12, TRUE}, {"sp", REG_SP, TRUE}, {"lr", REG_LR, TRUE}, {"pc", REG_PC, TRUE},
614 {NULL, 0, TRUE}
6c43fab6
RE
615};
616
e16bb312
NC
617#define WR_PREFIX 0x200
618#define WC_PREFIX 0x400
619
620static const struct reg_entry iwmmxt_table[] =
621{
5a6c6817 622 /* Intel Wireless MMX technology register names. */
0bbf2aa4
NC
623 { "wr0", 0x0 | WR_PREFIX, TRUE}, {"wr1", 0x1 | WR_PREFIX, TRUE},
624 { "wr2", 0x2 | WR_PREFIX, TRUE}, {"wr3", 0x3 | WR_PREFIX, TRUE},
625 { "wr4", 0x4 | WR_PREFIX, TRUE}, {"wr5", 0x5 | WR_PREFIX, TRUE},
626 { "wr6", 0x6 | WR_PREFIX, TRUE}, {"wr7", 0x7 | WR_PREFIX, TRUE},
627 { "wr8", 0x8 | WR_PREFIX, TRUE}, {"wr9", 0x9 | WR_PREFIX, TRUE},
628 { "wr10", 0xa | WR_PREFIX, TRUE}, {"wr11", 0xb | WR_PREFIX, TRUE},
629 { "wr12", 0xc | WR_PREFIX, TRUE}, {"wr13", 0xd | WR_PREFIX, TRUE},
630 { "wr14", 0xe | WR_PREFIX, TRUE}, {"wr15", 0xf | WR_PREFIX, TRUE},
631 { "wcid", 0x0 | WC_PREFIX, TRUE}, {"wcon", 0x1 | WC_PREFIX, TRUE},
632 {"wcssf", 0x2 | WC_PREFIX, TRUE}, {"wcasf", 0x3 | WC_PREFIX, TRUE},
633 {"wcgr0", 0x8 | WC_PREFIX, TRUE}, {"wcgr1", 0x9 | WC_PREFIX, TRUE},
634 {"wcgr2", 0xa | WC_PREFIX, TRUE}, {"wcgr3", 0xb | WC_PREFIX, TRUE},
635
636 { "wR0", 0x0 | WR_PREFIX, TRUE}, {"wR1", 0x1 | WR_PREFIX, TRUE},
637 { "wR2", 0x2 | WR_PREFIX, TRUE}, {"wR3", 0x3 | WR_PREFIX, TRUE},
638 { "wR4", 0x4 | WR_PREFIX, TRUE}, {"wR5", 0x5 | WR_PREFIX, TRUE},
639 { "wR6", 0x6 | WR_PREFIX, TRUE}, {"wR7", 0x7 | WR_PREFIX, TRUE},
640 { "wR8", 0x8 | WR_PREFIX, TRUE}, {"wR9", 0x9 | WR_PREFIX, TRUE},
641 { "wR10", 0xa | WR_PREFIX, TRUE}, {"wR11", 0xb | WR_PREFIX, TRUE},
642 { "wR12", 0xc | WR_PREFIX, TRUE}, {"wR13", 0xd | WR_PREFIX, TRUE},
643 { "wR14", 0xe | WR_PREFIX, TRUE}, {"wR15", 0xf | WR_PREFIX, TRUE},
644 { "wCID", 0x0 | WC_PREFIX, TRUE}, {"wCon", 0x1 | WC_PREFIX, TRUE},
645 {"wCSSF", 0x2 | WC_PREFIX, TRUE}, {"wCASF", 0x3 | WC_PREFIX, TRUE},
646 {"wCGR0", 0x8 | WC_PREFIX, TRUE}, {"wCGR1", 0x9 | WC_PREFIX, TRUE},
647 {"wCGR2", 0xa | WC_PREFIX, TRUE}, {"wCGR3", 0xb | WC_PREFIX, TRUE},
648 {NULL, 0, TRUE}
e16bb312
NC
649};
650
6c43fab6
RE
651/* Co-processor Numbers. */
652static const struct reg_entry cp_table[] =
653{
0bbf2aa4
NC
654 {"p0", 0, TRUE}, {"p1", 1, TRUE}, {"p2", 2, TRUE}, {"p3", 3, TRUE},
655 {"p4", 4, TRUE}, {"p5", 5, TRUE}, {"p6", 6, TRUE}, {"p7", 7, TRUE},
656 {"p8", 8, TRUE}, {"p9", 9, TRUE}, {"p10", 10, TRUE}, {"p11", 11, TRUE},
657 {"p12", 12, TRUE}, {"p13", 13, TRUE}, {"p14", 14, TRUE}, {"p15", 15, TRUE},
658 {NULL, 0, TRUE}
6c43fab6
RE
659};
660
661/* Co-processor Register Numbers. */
662static const struct reg_entry cn_table[] =
663{
0bbf2aa4
NC
664 {"c0", 0, TRUE}, {"c1", 1, TRUE}, {"c2", 2, TRUE}, {"c3", 3, TRUE},
665 {"c4", 4, TRUE}, {"c5", 5, TRUE}, {"c6", 6, TRUE}, {"c7", 7, TRUE},
666 {"c8", 8, TRUE}, {"c9", 9, TRUE}, {"c10", 10, TRUE}, {"c11", 11, TRUE},
667 {"c12", 12, TRUE}, {"c13", 13, TRUE}, {"c14", 14, TRUE}, {"c15", 15, TRUE},
6c43fab6 668 /* Not really valid, but kept for back-wards compatibility. */
0bbf2aa4
NC
669 {"cr0", 0, TRUE}, {"cr1", 1, TRUE}, {"cr2", 2, TRUE}, {"cr3", 3, TRUE},
670 {"cr4", 4, TRUE}, {"cr5", 5, TRUE}, {"cr6", 6, TRUE}, {"cr7", 7, TRUE},
671 {"cr8", 8, TRUE}, {"cr9", 9, TRUE}, {"cr10", 10, TRUE}, {"cr11", 11, TRUE},
672 {"cr12", 12, TRUE}, {"cr13", 13, TRUE}, {"cr14", 14, TRUE}, {"cr15", 15, TRUE},
673 {NULL, 0, TRUE}
6c43fab6
RE
674};
675
676/* FPA Registers. */
677static const struct reg_entry fn_table[] =
678{
0bbf2aa4
NC
679 {"f0", 0, TRUE}, {"f1", 1, TRUE}, {"f2", 2, TRUE}, {"f3", 3, TRUE},
680 {"f4", 4, TRUE}, {"f5", 5, TRUE}, {"f6", 6, TRUE}, {"f7", 7, TRUE},
681 {NULL, 0, TRUE}
6c43fab6
RE
682};
683
bfae80f2
RE
684/* VFP SP Registers. */
685static const struct reg_entry sn_table[] =
686{
0bbf2aa4
NC
687 {"s0", 0, TRUE}, {"s1", 1, TRUE}, {"s2", 2, TRUE}, {"s3", 3, TRUE},
688 {"s4", 4, TRUE}, {"s5", 5, TRUE}, {"s6", 6, TRUE}, {"s7", 7, TRUE},
689 {"s8", 8, TRUE}, {"s9", 9, TRUE}, {"s10", 10, TRUE}, {"s11", 11, TRUE},
690 {"s12", 12, TRUE}, {"s13", 13, TRUE}, {"s14", 14, TRUE}, {"s15", 15, TRUE},
691 {"s16", 16, TRUE}, {"s17", 17, TRUE}, {"s18", 18, TRUE}, {"s19", 19, TRUE},
692 {"s20", 20, TRUE}, {"s21", 21, TRUE}, {"s22", 22, TRUE}, {"s23", 23, TRUE},
693 {"s24", 24, TRUE}, {"s25", 25, TRUE}, {"s26", 26, TRUE}, {"s27", 27, TRUE},
694 {"s28", 28, TRUE}, {"s29", 29, TRUE}, {"s30", 30, TRUE}, {"s31", 31, TRUE},
695 {NULL, 0, TRUE}
bfae80f2
RE
696};
697
698/* VFP DP Registers. */
699static const struct reg_entry dn_table[] =
700{
0bbf2aa4
NC
701 {"d0", 0, TRUE}, {"d1", 1, TRUE}, {"d2", 2, TRUE}, {"d3", 3, TRUE},
702 {"d4", 4, TRUE}, {"d5", 5, TRUE}, {"d6", 6, TRUE}, {"d7", 7, TRUE},
703 {"d8", 8, TRUE}, {"d9", 9, TRUE}, {"d10", 10, TRUE}, {"d11", 11, TRUE},
704 {"d12", 12, TRUE}, {"d13", 13, TRUE}, {"d14", 14, TRUE}, {"d15", 15, TRUE},
705 {NULL, 0, TRUE}
bfae80f2
RE
706};
707
63e63b07 708/* Maverick DSP coprocessor registers. */
6c43fab6
RE
709static const struct reg_entry mav_mvf_table[] =
710{
0bbf2aa4
NC
711 {"mvf0", 0, TRUE}, {"mvf1", 1, TRUE}, {"mvf2", 2, TRUE}, {"mvf3", 3, TRUE},
712 {"mvf4", 4, TRUE}, {"mvf5", 5, TRUE}, {"mvf6", 6, TRUE}, {"mvf7", 7, TRUE},
713 {"mvf8", 8, TRUE}, {"mvf9", 9, TRUE}, {"mvf10", 10, TRUE}, {"mvf11", 11, TRUE},
714 {"mvf12", 12, TRUE}, {"mvf13", 13, TRUE}, {"mvf14", 14, TRUE}, {"mvf15", 15, TRUE},
715 {NULL, 0, TRUE}
6c43fab6
RE
716};
717
718static const struct reg_entry mav_mvd_table[] =
719{
0bbf2aa4
NC
720 {"mvd0", 0, TRUE}, {"mvd1", 1, TRUE}, {"mvd2", 2, TRUE}, {"mvd3", 3, TRUE},
721 {"mvd4", 4, TRUE}, {"mvd5", 5, TRUE}, {"mvd6", 6, TRUE}, {"mvd7", 7, TRUE},
722 {"mvd8", 8, TRUE}, {"mvd9", 9, TRUE}, {"mvd10", 10, TRUE}, {"mvd11", 11, TRUE},
723 {"mvd12", 12, TRUE}, {"mvd13", 13, TRUE}, {"mvd14", 14, TRUE}, {"mvd15", 15, TRUE},
724 {NULL, 0, TRUE}
6c43fab6
RE
725};
726
727static const struct reg_entry mav_mvfx_table[] =
728{
0bbf2aa4
NC
729 {"mvfx0", 0, TRUE}, {"mvfx1", 1, TRUE}, {"mvfx2", 2, TRUE}, {"mvfx3", 3, TRUE},
730 {"mvfx4", 4, TRUE}, {"mvfx5", 5, TRUE}, {"mvfx6", 6, TRUE}, {"mvfx7", 7, TRUE},
731 {"mvfx8", 8, TRUE}, {"mvfx9", 9, TRUE}, {"mvfx10", 10, TRUE}, {"mvfx11", 11, TRUE},
732 {"mvfx12", 12, TRUE}, {"mvfx13", 13, TRUE}, {"mvfx14", 14, TRUE}, {"mvfx15", 15, TRUE},
733 {NULL, 0, TRUE}
6c43fab6
RE
734};
735
736static const struct reg_entry mav_mvdx_table[] =
737{
0bbf2aa4
NC
738 {"mvdx0", 0, TRUE}, {"mvdx1", 1, TRUE}, {"mvdx2", 2, TRUE}, {"mvdx3", 3, TRUE},
739 {"mvdx4", 4, TRUE}, {"mvdx5", 5, TRUE}, {"mvdx6", 6, TRUE}, {"mvdx7", 7, TRUE},
740 {"mvdx8", 8, TRUE}, {"mvdx9", 9, TRUE}, {"mvdx10", 10, TRUE}, {"mvdx11", 11, TRUE},
741 {"mvdx12", 12, TRUE}, {"mvdx13", 13, TRUE}, {"mvdx14", 14, TRUE}, {"mvdx15", 15, TRUE},
742 {NULL, 0, TRUE}
6c43fab6
RE
743};
744
745static const struct reg_entry mav_mvax_table[] =
746{
0bbf2aa4
NC
747 {"mvax0", 0, TRUE}, {"mvax1", 1, TRUE}, {"mvax2", 2, TRUE}, {"mvax3", 3, TRUE},
748 {NULL, 0, TRUE}
6c43fab6
RE
749};
750
751static const struct reg_entry mav_dspsc_table[] =
752{
0bbf2aa4
NC
753 {"dspsc", 0, TRUE},
754 {NULL, 0, TRUE}
6c43fab6
RE
755};
756
757struct reg_map
758{
a737bd4d
NC
759 const struct reg_entry * names;
760 int max_regno;
761 struct hash_control * htab;
762 const char * expected;
6c43fab6
RE
763};
764
765struct reg_map all_reg_maps[] =
766{
767 {rn_table, 15, NULL, N_("ARM register expected")},
f03698e6
RE
768 {cp_table, 15, NULL, N_("bad or missing co-processor number")},
769 {cn_table, 15, NULL, N_("co-processor register expected")},
6c43fab6 770 {fn_table, 7, NULL, N_("FPA register expected")},
bfae80f2
RE
771 {sn_table, 31, NULL, N_("VFP single precision register expected")},
772 {dn_table, 15, NULL, N_("VFP double precision register expected")},
6c43fab6
RE
773 {mav_mvf_table, 15, NULL, N_("Maverick MVF register expected")},
774 {mav_mvd_table, 15, NULL, N_("Maverick MVD register expected")},
775 {mav_mvfx_table, 15, NULL, N_("Maverick MVFX register expected")},
5a21e886 776 {mav_mvdx_table, 15, NULL, N_("Maverick MVDX register expected")},
6c43fab6
RE
777 {mav_mvax_table, 3, NULL, N_("Maverick MVAX register expected")},
778 {mav_dspsc_table, 0, NULL, N_("Maverick DSPSC register expected")},
5a6c6817 779 {iwmmxt_table, 23, NULL, N_("Intel Wireless MMX technology register expected")},
6c43fab6
RE
780};
781
782/* Enumeration matching entries in table above. */
783enum arm_reg_type
784{
785 REG_TYPE_RN = 0,
786#define REG_TYPE_FIRST REG_TYPE_RN
787 REG_TYPE_CP = 1,
788 REG_TYPE_CN = 2,
789 REG_TYPE_FN = 3,
bfae80f2
RE
790 REG_TYPE_SN = 4,
791 REG_TYPE_DN = 5,
792 REG_TYPE_MVF = 6,
793 REG_TYPE_MVD = 7,
794 REG_TYPE_MVFX = 8,
795 REG_TYPE_MVDX = 9,
796 REG_TYPE_MVAX = 10,
797 REG_TYPE_DSPSC = 11,
e16bb312 798 REG_TYPE_IWMMXT = 12,
bfae80f2 799
e16bb312 800 REG_TYPE_MAX = 13
6c43fab6 801};
404ff6b5 802
b99bd4ef
NC
803/* ARM instructions take 4bytes in the object file, Thumb instructions
804 take 2: */
805#define INSN_SIZE 4
806
404ff6b5 807/* "INSN<cond> X,Y" where X:bit12, Y:bit16. */
63e63b07 808#define MAV_MODE1 0x100c
404ff6b5
AH
809
810/* "INSN<cond> X,Y" where X:bit16, Y:bit12. */
63e63b07 811#define MAV_MODE2 0x0c10
404ff6b5 812
34920d91
NC
813/* "INSN<cond> X,Y" where X:bit12, Y:bit16. */
814#define MAV_MODE3 0x100c
404ff6b5
AH
815
816/* "INSN<cond> X,Y,Z" where X:16, Y:0, Z:12. */
63e63b07 817#define MAV_MODE4 0x0c0010
404ff6b5
AH
818
819/* "INSN<cond> X,Y,Z" where X:12, Y:16, Z:0. */
63e63b07 820#define MAV_MODE5 0x00100c
404ff6b5
AH
821
822/* "INSN<cond> W,X,Y,Z" where W:5, X:12, Y:16, Z:0. */
63e63b07 823#define MAV_MODE6 0x00100c05
b99bd4ef
NC
824
825struct asm_opcode
826{
827 /* Basic string to match. */
05d2d07e 828 const char * template;
b99bd4ef
NC
829
830 /* Basic instruction code. */
831 unsigned long value;
832
90e4755a
RE
833 /* Offset into the template where the condition code (if any) will be.
834 If zero, then the instruction is never conditional. */
835 unsigned cond_offset;
b99bd4ef 836
90e4755a
RE
837 /* Which architecture variant provides this instruction. */
838 unsigned long variant;
b99bd4ef
NC
839
840 /* Function to call to parse args. */
a737bd4d 841 void (* parms) (char *);
b99bd4ef
NC
842};
843
a737bd4d
NC
844/* Defines for various bits that we will want to toggle. */
845#define INST_IMMEDIATE 0x02000000
846#define OFFSET_REG 0x02000000
847#define HWOFFSET_IMM 0x00400000
848#define SHIFT_BY_REG 0x00000010
849#define PRE_INDEX 0x01000000
850#define INDEX_UP 0x00800000
851#define WRITE_BACK 0x00200000
852#define LDM_TYPE_2_OR_3 0x00400000
90e4755a 853
a737bd4d
NC
854#define LITERAL_MASK 0xf000f000
855#define OPCODE_MASK 0xfe1fffff
856#define V4_STR_BIT 0x00000020
90e4755a 857
a737bd4d 858#define DATA_OP_SHIFT 21
90e4755a 859
a737bd4d
NC
860/* Codes to distinguish the arithmetic instructions. */
861#define OPCODE_AND 0
862#define OPCODE_EOR 1
863#define OPCODE_SUB 2
864#define OPCODE_RSB 3
865#define OPCODE_ADD 4
866#define OPCODE_ADC 5
867#define OPCODE_SBC 6
868#define OPCODE_RSC 7
869#define OPCODE_TST 8
870#define OPCODE_TEQ 9
871#define OPCODE_CMP 10
872#define OPCODE_CMN 11
873#define OPCODE_ORR 12
874#define OPCODE_MOV 13
875#define OPCODE_BIC 14
876#define OPCODE_MVN 15
90e4755a 877
a737bd4d
NC
878#define T_OPCODE_MUL 0x4340
879#define T_OPCODE_TST 0x4200
880#define T_OPCODE_CMN 0x42c0
881#define T_OPCODE_NEG 0x4240
882#define T_OPCODE_MVN 0x43c0
90e4755a 883
a737bd4d
NC
884#define T_OPCODE_ADD_R3 0x1800
885#define T_OPCODE_SUB_R3 0x1a00
886#define T_OPCODE_ADD_HI 0x4400
887#define T_OPCODE_ADD_ST 0xb000
888#define T_OPCODE_SUB_ST 0xb080
889#define T_OPCODE_ADD_SP 0xa800
890#define T_OPCODE_ADD_PC 0xa000
891#define T_OPCODE_ADD_I8 0x3000
892#define T_OPCODE_SUB_I8 0x3800
893#define T_OPCODE_ADD_I3 0x1c00
894#define T_OPCODE_SUB_I3 0x1e00
b99bd4ef 895
a737bd4d
NC
896#define T_OPCODE_ASR_R 0x4100
897#define T_OPCODE_LSL_R 0x4080
898#define T_OPCODE_LSR_R 0x40c0
899#define T_OPCODE_ASR_I 0x1000
900#define T_OPCODE_LSL_I 0x0000
901#define T_OPCODE_LSR_I 0x0800
b99bd4ef 902
a737bd4d
NC
903#define T_OPCODE_MOV_I8 0x2000
904#define T_OPCODE_CMP_I8 0x2800
905#define T_OPCODE_CMP_LR 0x4280
906#define T_OPCODE_MOV_HR 0x4600
907#define T_OPCODE_CMP_HR 0x4500
b99bd4ef 908
a737bd4d
NC
909#define T_OPCODE_LDR_PC 0x4800
910#define T_OPCODE_LDR_SP 0x9800
911#define T_OPCODE_STR_SP 0x9000
912#define T_OPCODE_LDR_IW 0x6800
913#define T_OPCODE_STR_IW 0x6000
914#define T_OPCODE_LDR_IH 0x8800
915#define T_OPCODE_STR_IH 0x8000
916#define T_OPCODE_LDR_IB 0x7800
917#define T_OPCODE_STR_IB 0x7000
918#define T_OPCODE_LDR_RW 0x5800
919#define T_OPCODE_STR_RW 0x5000
920#define T_OPCODE_LDR_RH 0x5a00
921#define T_OPCODE_STR_RH 0x5200
922#define T_OPCODE_LDR_RB 0x5c00
923#define T_OPCODE_STR_RB 0x5400
c9b604bd 924
a737bd4d
NC
925#define T_OPCODE_PUSH 0xb400
926#define T_OPCODE_POP 0xbc00
b99bd4ef 927
a737bd4d 928#define T_OPCODE_BRANCH 0xe7fe
b99bd4ef 929
a737bd4d
NC
930#define THUMB_SIZE 2 /* Size of thumb instruction. */
931#define THUMB_REG_LO 0x1
932#define THUMB_REG_HI 0x2
933#define THUMB_REG_ANY 0x3
90e4755a 934
a737bd4d
NC
935#define THUMB_H1 0x0080
936#define THUMB_H2 0x0040
b99bd4ef 937
a737bd4d
NC
938#define THUMB_ASR 0
939#define THUMB_LSL 1
940#define THUMB_LSR 2
90e4755a 941
a737bd4d
NC
942#define THUMB_MOVE 0
943#define THUMB_COMPARE 1
944#define THUMB_CPY 2
90e4755a 945
a737bd4d
NC
946#define THUMB_LOAD 0
947#define THUMB_STORE 1
90e4755a 948
a737bd4d 949#define THUMB_PP_PC_LR 0x0100
90e4755a 950
a737bd4d
NC
951/* These three are used for immediate shifts, do not alter. */
952#define THUMB_WORD 2
953#define THUMB_HALFWORD 1
954#define THUMB_BYTE 0
90e4755a 955
a737bd4d
NC
956struct thumb_opcode
957{
958 /* Basic string to match. */
959 const char * template;
90e4755a 960
a737bd4d
NC
961 /* Basic instruction code. */
962 unsigned long value;
90e4755a 963
a737bd4d 964 int size;
b99bd4ef
NC
965
966 /* Which CPU variants this exists for. */
90e4755a 967 unsigned long variant;
b99bd4ef
NC
968
969 /* Function to call to parse args. */
a737bd4d 970 void (* parms) (char *);
b99bd4ef
NC
971};
972
f03698e6 973#define BAD_ARGS _("bad arguments to instruction")
b99bd4ef 974#define BAD_PC _("r15 not allowed here")
f03698e6 975#define BAD_COND _("instruction is not conditional")
b99bd4ef
NC
976#define ERR_NO_ACCUM _("acc0 expected")
977
978static struct hash_control * arm_ops_hsh = NULL;
979static struct hash_control * arm_tops_hsh = NULL;
980static struct hash_control * arm_cond_hsh = NULL;
981static struct hash_control * arm_shift_hsh = NULL;
b99bd4ef
NC
982static struct hash_control * arm_psr_hsh = NULL;
983
b99bd4ef
NC
984/* Stuff needed to resolve the label ambiguity
985 As:
986 ...
987 label: <insn>
988 may differ from:
989 ...
990 label:
991 <insn>
992*/
993
994symbolS * last_label_seen;
b34976b6 995static int label_is_thumb_function_name = FALSE;
a737bd4d 996\f
3d0c9500 997/* Literal Pool stuff. */
b99bd4ef
NC
998
999#define MAX_LITERAL_POOL_SIZE 1024
1000
3d0c9500
NC
1001/* Literal pool structure. Held on a per-section
1002 and per-sub-section basis. */
a737bd4d 1003
3d0c9500 1004typedef struct literal_pool
b99bd4ef 1005{
3d0c9500
NC
1006 expressionS literals [MAX_LITERAL_POOL_SIZE];
1007 unsigned int next_free_entry;
1008 unsigned int id;
1009 symbolS * symbol;
1010 segT section;
1011 subsegT sub_section;
61b5f74b 1012 struct literal_pool * next;
3d0c9500 1013} literal_pool;
b99bd4ef 1014
3d0c9500
NC
1015/* Pointer to a linked list of literal pools. */
1016literal_pool * list_of_pools = NULL;
b99bd4ef 1017
3d0c9500 1018static literal_pool *
a737bd4d 1019find_literal_pool (void)
3d0c9500
NC
1020{
1021 literal_pool * pool;
1022
1023 for (pool = list_of_pools; pool != NULL; pool = pool->next)
1024 {
1025 if (pool->section == now_seg
1026 && pool->sub_section == now_subseg)
1027 break;
1028 }
1029
1030 return pool;
1031}
b99bd4ef 1032
3d0c9500 1033static literal_pool *
a737bd4d 1034find_or_make_literal_pool (void)
3d0c9500
NC
1035{
1036 /* Next literal pool ID number. */
1037 static unsigned int latest_pool_num = 1;
1038 literal_pool * pool;
1039
1040 pool = find_literal_pool ();
b99bd4ef 1041
3d0c9500
NC
1042 if (pool == NULL)
1043 {
1044 /* Create a new pool. */
a737bd4d 1045 pool = xmalloc (sizeof (* pool));
3d0c9500
NC
1046 if (! pool)
1047 return NULL;
1048
1049 pool->next_free_entry = 0;
1050 pool->section = now_seg;
1051 pool->sub_section = now_subseg;
1052 pool->next = list_of_pools;
1053 pool->symbol = NULL;
1054
1055 /* Add it to the list. */
1056 list_of_pools = pool;
1057 }
1058
1059 /* New pools, and emptied pools, will have a NULL symbol. */
1060 if (pool->symbol == NULL)
1061 {
1062 pool->symbol = symbol_create (FAKE_LABEL_NAME, undefined_section,
1063 (valueT) 0, &zero_address_frag);
1064 pool->id = latest_pool_num ++;
1065 }
1066
1067 /* Done. */
1068 return pool;
1069}
1070
1071/* Add the literal in the global 'inst'
1072 structure to the relevent literal pool. */
a737bd4d 1073
b99bd4ef 1074static int
a737bd4d 1075add_to_lit_pool (void)
b99bd4ef 1076{
61b5f74b 1077 literal_pool * pool;
3d0c9500 1078 unsigned int entry;
b99bd4ef 1079
3d0c9500 1080 pool = find_or_make_literal_pool ();
b99bd4ef 1081
3d0c9500
NC
1082 /* Check if this literal value is already in the pool. */
1083 for (entry = 0; entry < pool->next_free_entry; entry ++)
b99bd4ef 1084 {
3d0c9500
NC
1085 if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
1086 && (inst.reloc.exp.X_op == O_constant)
1087 && (pool->literals[entry].X_add_number
b99bd4ef 1088 == inst.reloc.exp.X_add_number)
3d0c9500
NC
1089 && (pool->literals[entry].X_unsigned
1090 == inst.reloc.exp.X_unsigned))
b99bd4ef
NC
1091 break;
1092
3d0c9500
NC
1093 if ((pool->literals[entry].X_op == inst.reloc.exp.X_op)
1094 && (inst.reloc.exp.X_op == O_symbol)
1095 && (pool->literals[entry].X_add_number
b99bd4ef 1096 == inst.reloc.exp.X_add_number)
3d0c9500 1097 && (pool->literals[entry].X_add_symbol
b99bd4ef 1098 == inst.reloc.exp.X_add_symbol)
3d0c9500 1099 && (pool->literals[entry].X_op_symbol
b99bd4ef 1100 == inst.reloc.exp.X_op_symbol))
3d0c9500 1101 break;
b99bd4ef
NC
1102 }
1103
3d0c9500
NC
1104 /* Do we need to create a new entry? */
1105 if (entry == pool->next_free_entry)
b99bd4ef 1106 {
3d0c9500 1107 if (entry >= MAX_LITERAL_POOL_SIZE)
b99bd4ef 1108 {
ed71e111 1109 inst.error = _("literal pool overflow");
b99bd4ef
NC
1110 return FAIL;
1111 }
1112
3d0c9500
NC
1113 pool->literals[entry] = inst.reloc.exp;
1114 pool->next_free_entry += 1;
b99bd4ef
NC
1115 }
1116
3d0c9500 1117 inst.reloc.exp.X_op = O_symbol;
08df2379 1118 inst.reloc.exp.X_add_number = ((int) entry) * 4 - 8;
3d0c9500 1119 inst.reloc.exp.X_add_symbol = pool->symbol;
b99bd4ef
NC
1120
1121 return SUCCESS;
1122}
1123
1124/* Can't use symbol_new here, so have to create a symbol and then at
1125 a later date assign it a value. Thats what these functions do. */
1126
1127static void
a737bd4d
NC
1128symbol_locate (symbolS * symbolP,
1129 const char * name, /* It is copied, the caller can modify. */
1130 segT segment, /* Segment identifier (SEG_<something>). */
1131 valueT valu, /* Symbol value. */
1132 fragS * frag) /* Associated fragment. */
b99bd4ef
NC
1133{
1134 unsigned int name_length;
1135 char * preserved_copy_of_name;
1136
1137 name_length = strlen (name) + 1; /* +1 for \0. */
1138 obstack_grow (&notes, name, name_length);
1139 preserved_copy_of_name = obstack_finish (&notes);
b99bd4ef
NC
1140
1141#ifdef tc_canonicalize_symbol_name
1142 preserved_copy_of_name =
1143 tc_canonicalize_symbol_name (preserved_copy_of_name);
1144#endif
1145
1146 S_SET_NAME (symbolP, preserved_copy_of_name);
1147
1148 S_SET_SEGMENT (symbolP, segment);
1149 S_SET_VALUE (symbolP, valu);
c62e1cc3 1150 symbol_clear_list_pointers (symbolP);
b99bd4ef
NC
1151
1152 symbol_set_frag (symbolP, frag);
1153
1154 /* Link to end of symbol chain. */
1155 {
1156 extern int symbol_table_frozen;
a737bd4d 1157
b99bd4ef
NC
1158 if (symbol_table_frozen)
1159 abort ();
1160 }
1161
1162 symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
1163
1164 obj_symbol_new_hook (symbolP);
1165
1166#ifdef tc_symbol_new_hook
1167 tc_symbol_new_hook (symbolP);
1168#endif
1169
1170#ifdef DEBUG_SYMS
1171 verify_symbol_chain (symbol_rootP, symbol_lastP);
1172#endif /* DEBUG_SYMS */
1173}
1174
1175/* Check that an immediate is valid.
1176 If so, convert it to the right format. */
1177
1178static unsigned int
a737bd4d 1179validate_immediate (unsigned int val)
b99bd4ef
NC
1180{
1181 unsigned int a;
1182 unsigned int i;
1183
1184#define rotate_left(v, n) (v << n | v >> (32 - n))
1185
1186 for (i = 0; i < 32; i += 2)
1187 if ((a = rotate_left (val, i)) <= 0xff)
1188 return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */
1189
1190 return FAIL;
1191}
1192
2d2255b5 1193/* Check to see if an immediate can be computed as two separate immediate
b99bd4ef
NC
1194 values, added together. We already know that this value cannot be
1195 computed by just one ARM instruction. */
1196
1197static unsigned int
a737bd4d
NC
1198validate_immediate_twopart (unsigned int val,
1199 unsigned int * highpart)
b99bd4ef
NC
1200{
1201 unsigned int a;
1202 unsigned int i;
1203
1204 for (i = 0; i < 32; i += 2)
1205 if (((a = rotate_left (val, i)) & 0xff) != 0)
1206 {
1207 if (a & 0xff00)
1208 {
1209 if (a & ~ 0xffff)
1210 continue;
1211 * highpart = (a >> 8) | ((i + 24) << 7);
1212 }
1213 else if (a & 0xff0000)
1214 {
1215 if (a & 0xff000000)
1216 continue;
1217 * highpart = (a >> 16) | ((i + 16) << 7);
1218 }
1219 else
1220 {
1221 assert (a & 0xff000000);
1222 * highpart = (a >> 24) | ((i + 8) << 7);
1223 }
1224
1225 return (a & 0xff) | (i << 7);
1226 }
1227
1228 return FAIL;
1229}
1230
1231static int
a737bd4d 1232validate_offset_imm (unsigned int val, int hwse)
b99bd4ef
NC
1233{
1234 if ((hwse && val > 255) || val > 4095)
1235 return FAIL;
1236 return val;
1237}
1238
6057a28f
NC
1239\f
1240#ifdef OBJ_ELF
6057a28f 1241/* This code is to handle mapping symbols as defined in the ARM ELF spec.
9d2da7ca
JB
1242 (See "Mapping symbols", section 4.5.5, ARM AAELF version 1.0).
1243 Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
1244 and $d has type STT_OBJECT (BSF_OBJECT flag). Now all three are untyped. */
6057a28f 1245
69b97547
NC
1246static enum mstate mapstate = MAP_UNDEFINED;
1247
6057a28f
NC
1248static void
1249mapping_state (enum mstate state)
1250{
6057a28f
NC
1251 symbolS * symbolP;
1252 const char * symname;
1253 int type;
1254
1255 if (mapstate == state)
1256 /* The mapping symbol has already been emitted.
1257 There is nothing else to do. */
1258 return;
1259
1260 mapstate = state;
1261
1262 switch (state)
1263 {
1264 case MAP_DATA:
1265 symname = "$d";
9d2da7ca 1266 type = BSF_NO_FLAGS;
6057a28f
NC
1267 break;
1268 case MAP_ARM:
1269 symname = "$a";
9d2da7ca 1270 type = BSF_NO_FLAGS;
6057a28f
NC
1271 break;
1272 case MAP_THUMB:
1273 symname = "$t";
9d2da7ca 1274 type = BSF_NO_FLAGS;
6057a28f 1275 break;
69b97547 1276 case MAP_UNDEFINED:
a737bd4d 1277 return;
6057a28f
NC
1278 default:
1279 abort ();
1280 }
1281
84798bd6 1282 seg_info (now_seg)->tc_segment_info_data.mapstate = state;
69b97547 1283
6057a28f
NC
1284 symbolP = symbol_new (symname, now_seg, (valueT) frag_now_fix (), frag_now);
1285 symbol_table_insert (symbolP);
1286 symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
a737bd4d 1287
6057a28f
NC
1288 switch (state)
1289 {
1290 case MAP_ARM:
1291 THUMB_SET_FUNC (symbolP, 0);
1292 ARM_SET_THUMB (symbolP, 0);
1293 ARM_SET_INTERWORK (symbolP, support_interwork);
1294 break;
a737bd4d 1295
6057a28f
NC
1296 case MAP_THUMB:
1297 THUMB_SET_FUNC (symbolP, 1);
1298 ARM_SET_THUMB (symbolP, 1);
1299 ARM_SET_INTERWORK (symbolP, support_interwork);
1300 break;
a737bd4d 1301
6057a28f
NC
1302 case MAP_DATA:
1303 default:
1304 return;
1305 }
1306}
1307
a737bd4d
NC
1308/* When we change sections we need to issue a new mapping symbol. */
1309
1310void
1311arm_elf_change_section (void)
1312{
1313 flagword flags;
84798bd6 1314 segment_info_type *seginfo;
a737bd4d 1315
40a18ebd
NC
1316 /* Link an unlinked unwind index table section to the .text section. */
1317 if (elf_section_type (now_seg) == SHT_ARM_EXIDX
1318 && elf_linked_to_section (now_seg) == NULL)
1319 elf_linked_to_section (now_seg) = text_section;
1320
a737bd4d
NC
1321 if (!SEG_NORMAL (now_seg))
1322 return;
1323
1324 flags = bfd_get_section_flags (stdoutput, now_seg);
1325
1326 /* We can ignore sections that only contain debug info. */
1327 if ((flags & SEC_ALLOC) == 0)
1328 return;
1329
84798bd6
JB
1330 seginfo = seg_info (now_seg);
1331 mapstate = seginfo->tc_segment_info_data.mapstate;
1332 marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency;
a737bd4d 1333}
40a18ebd
NC
1334
1335int
1336arm_elf_section_type (const char * str, size_t len)
1337{
1338 if (len == 5 && strncmp (str, "exidx", 5) == 0)
1339 return SHT_ARM_EXIDX;
1340
1341 return -1;
1342}
a737bd4d
NC
1343#else
1344#define mapping_state(a)
1345#endif /* OBJ_ELF */
1346\f
1347/* arm_reg_parse () := if it looks like a register, return its token and
1348 advance the pointer. */
1349
1350static int
1351arm_reg_parse (char ** ccp, struct hash_control * htab)
1352{
1353 char * start = * ccp;
1354 char c;
1355 char * p;
1356 struct reg_entry * reg;
1357
1358#ifdef REGISTER_PREFIX
1359 if (*start != REGISTER_PREFIX)
1360 return FAIL;
1361 p = start + 1;
1362#else
1363 p = start;
1364#ifdef OPTIONAL_REGISTER_PREFIX
1365 if (*p == OPTIONAL_REGISTER_PREFIX)
1366 p++, start++;
1367#endif
1368#endif
1369 if (!ISALPHA (*p) || !is_name_beginner (*p))
1370 return FAIL;
1371
1372 c = *p++;
1373 while (ISALPHA (c) || ISDIGIT (c) || c == '_')
1374 c = *p++;
1375
1376 *--p = 0;
1377 reg = (struct reg_entry *) hash_find (htab, start);
1378 *p = c;
1379
1380 if (reg)
1381 {
1382 *ccp = p;
1383 return reg->number;
1384 }
1385
1386 return FAIL;
1387}
1388
1389/* Search for the following register name in each of the possible reg name
1390 tables. Return the classification if found, or REG_TYPE_MAX if not
1391 present. */
6057a28f 1392
a737bd4d
NC
1393static enum arm_reg_type
1394arm_reg_parse_any (char *cp)
6057a28f 1395{
a737bd4d 1396 int i;
6057a28f 1397
a737bd4d
NC
1398 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
1399 if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL)
1400 return (enum arm_reg_type) i;
6057a28f 1401
a737bd4d
NC
1402 return REG_TYPE_MAX;
1403}
6057a28f 1404
a737bd4d
NC
1405static void
1406opcode_select (int width)
1407{
1408 switch (width)
1409 {
1410 case 16:
1411 if (! thumb_mode)
1412 {
1413 if (! (cpu_variant & ARM_EXT_V4T))
1414 as_bad (_("selected processor does not support THUMB opcodes"));
6057a28f 1415
a737bd4d
NC
1416 thumb_mode = 1;
1417 /* No need to force the alignment, since we will have been
1418 coming from ARM mode, which is word-aligned. */
1419 record_alignment (now_seg, 1);
1420 }
1421 mapping_state (MAP_THUMB);
1422 break;
1423
1424 case 32:
1425 if (thumb_mode)
1426 {
1427 if ((cpu_variant & ARM_ALL) == ARM_EXT_V4T)
1428 as_bad (_("selected processor does not support ARM opcodes"));
1429
1430 thumb_mode = 0;
1431
1432 if (!need_pass_2)
1433 frag_align (2, 0, 0);
1434
1435 record_alignment (now_seg, 1);
1436 }
1437 mapping_state (MAP_ARM);
1438 break;
1439
1440 default:
1441 as_bad (_("invalid instruction size selected (%d)"), width);
1442 }
6057a28f 1443}
6057a28f 1444
b99bd4ef 1445static void
a737bd4d 1446s_req (int a ATTRIBUTE_UNUSED)
b99bd4ef 1447{
f03698e6 1448 as_bad (_("invalid syntax for .req directive"));
b99bd4ef
NC
1449}
1450
0bbf2aa4
NC
1451/* The .unreq directive deletes an alias which was previously defined
1452 by .req. For example:
1453
1454 my_alias .req r11
1455 .unreq my_alias */
1456
1457static void
1458s_unreq (int a ATTRIBUTE_UNUSED)
1459{
a737bd4d 1460 char * name;
0bbf2aa4
NC
1461 char saved_char;
1462
1463 skip_whitespace (input_line_pointer);
1464 name = input_line_pointer;
1465
1466 while (*input_line_pointer != 0
1467 && *input_line_pointer != ' '
1468 && *input_line_pointer != '\n')
1469 ++input_line_pointer;
1470
1471 saved_char = *input_line_pointer;
1472 *input_line_pointer = 0;
1473
1474 if (*name)
1475 {
1476 enum arm_reg_type req_type = arm_reg_parse_any (name);
1477
1478 if (req_type != REG_TYPE_MAX)
1479 {
1480 char *temp_name = name;
1481 int req_no = arm_reg_parse (&temp_name, all_reg_maps[req_type].htab);
1482
1483 if (req_no != FAIL)
1484 {
1485 struct reg_entry *req_entry;
1486
1487 /* Check to see if this alias is a builtin one. */
1488 req_entry = hash_delete (all_reg_maps[req_type].htab, name);
1489
1490 if (!req_entry)
1491 as_bad (_("unreq: missing hash entry for \"%s\""), name);
1492 else if (req_entry->builtin)
67c1ffbe 1493 /* FIXME: We are deleting a built in register alias which
0bbf2aa4
NC
1494 points to a const data structure, so we only need to
1495 free up the memory used by the key in the hash table.
1496 Unfortunately we have not recorded this value, so this
1497 is a memory leak. */
1498 /* FIXME: Should we issue a warning message ? */
1499 ;
1500 else
1501 {
67c1ffbe 1502 /* Deleting a user defined alias. We need to free the
0bbf2aa4
NC
1503 key and the value, but fortunately the key is the same
1504 as the value->name field. */
1505 free ((char *) req_entry->name);
1506 free (req_entry);
1507 }
1508 }
1509 else
1510 as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
1511 }
1512 else
1513 as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
1514 }
1515 else
1516 as_bad (_("invalid syntax for .unreq directive"));
1517
1518 *input_line_pointer = saved_char;
1519 demand_empty_rest_of_line ();
1520}
1521
b99bd4ef 1522static void
a737bd4d 1523s_bss (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1524{
1525 /* We don't support putting frags in the BSS segment, we fake it by
1526 marking in_bss, then looking at s_skip for clues. */
1527 subseg_set (bss_section, 0);
1528 demand_empty_rest_of_line ();
6057a28f 1529 mapping_state (MAP_DATA);
b99bd4ef
NC
1530}
1531
1532static void
a737bd4d 1533s_even (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1534{
1535 /* Never make frag if expect extra pass. */
1536 if (!need_pass_2)
1537 frag_align (1, 0, 0);
1538
1539 record_alignment (now_seg, 1);
1540
1541 demand_empty_rest_of_line ();
1542}
1543
1544static void
a737bd4d 1545s_ltorg (int ignored ATTRIBUTE_UNUSED)
b99bd4ef 1546{
3d0c9500
NC
1547 unsigned int entry;
1548 literal_pool * pool;
b99bd4ef
NC
1549 char sym_name[20];
1550
3d0c9500
NC
1551 pool = find_literal_pool ();
1552 if (pool == NULL
1553 || pool->symbol == NULL
1554 || pool->next_free_entry == 0)
b99bd4ef
NC
1555 return;
1556
69b97547
NC
1557 mapping_state (MAP_DATA);
1558
b99bd4ef
NC
1559 /* Align pool as you have word accesses.
1560 Only make a frag if we have to. */
1561 if (!need_pass_2)
1562 frag_align (2, 0, 0);
1563
1564 record_alignment (now_seg, 2);
1565
3d0c9500 1566 sprintf (sym_name, "$$lit_\002%x", pool->id);
b99bd4ef 1567
3d0c9500 1568 symbol_locate (pool->symbol, sym_name, now_seg,
b99bd4ef 1569 (valueT) frag_now_fix (), frag_now);
3d0c9500 1570 symbol_table_insert (pool->symbol);
b99bd4ef 1571
3d0c9500 1572 ARM_SET_THUMB (pool->symbol, thumb_mode);
b99bd4ef
NC
1573
1574#if defined OBJ_COFF || defined OBJ_ELF
3d0c9500 1575 ARM_SET_INTERWORK (pool->symbol, support_interwork);
b99bd4ef
NC
1576#endif
1577
3d0c9500 1578 for (entry = 0; entry < pool->next_free_entry; entry ++)
b99bd4ef 1579 /* First output the expression in the instruction to the pool. */
3d0c9500 1580 emit_expr (&(pool->literals[entry]), 4); /* .word */
b99bd4ef 1581
3d0c9500
NC
1582 /* Mark the pool as empty. */
1583 pool->next_free_entry = 0;
1584 pool->symbol = NULL;
b99bd4ef
NC
1585}
1586
1587/* Same as s_align_ptwo but align 0 => align 2. */
1588
1589static void
a737bd4d 1590s_align (int unused ATTRIBUTE_UNUSED)
b99bd4ef 1591{
a737bd4d
NC
1592 int temp;
1593 long temp_fill;
b99bd4ef
NC
1594 long max_alignment = 15;
1595
1596 temp = get_absolute_expression ();
1597 if (temp > max_alignment)
f03698e6 1598 as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
b99bd4ef
NC
1599 else if (temp < 0)
1600 {
f03698e6 1601 as_bad (_("alignment negative. 0 assumed."));
b99bd4ef
NC
1602 temp = 0;
1603 }
1604
1605 if (*input_line_pointer == ',')
1606 {
1607 input_line_pointer++;
1608 temp_fill = get_absolute_expression ();
1609 }
1610 else
1611 temp_fill = 0;
1612
1613 if (!temp)
1614 temp = 2;
1615
1616 /* Only make a frag if we HAVE to. */
1617 if (temp && !need_pass_2)
1618 frag_align (temp, (int) temp_fill, 0);
1619 demand_empty_rest_of_line ();
1620
1621 record_alignment (now_seg, temp);
1622}
1623
1624static void
a737bd4d 1625s_force_thumb (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1626{
1627 /* If we are not already in thumb mode go into it, EVEN if
1628 the target processor does not support thumb instructions.
1629 This is used by gcc/config/arm/lib1funcs.asm for example
1630 to compile interworking support functions even if the
1631 target processor should not support interworking. */
1632 if (! thumb_mode)
1633 {
1634 thumb_mode = 2;
1635
1636 record_alignment (now_seg, 1);
1637 }
1638
1639 demand_empty_rest_of_line ();
1640}
1641
1642static void
a737bd4d 1643s_thumb_func (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1644{
1645 if (! thumb_mode)
1646 opcode_select (16);
1647
1648 /* The following label is the name/address of the start of a Thumb function.
1649 We need to know this for the interworking support. */
b34976b6 1650 label_is_thumb_function_name = TRUE;
b99bd4ef
NC
1651
1652 demand_empty_rest_of_line ();
1653}
1654
1655/* Perform a .set directive, but also mark the alias as
1656 being a thumb function. */
1657
1658static void
a737bd4d 1659s_thumb_set (int equiv)
b99bd4ef
NC
1660{
1661 /* XXX the following is a duplicate of the code for s_set() in read.c
1662 We cannot just call that code as we need to get at the symbol that
1663 is created. */
a737bd4d
NC
1664 char * name;
1665 char delim;
1666 char * end_name;
1667 symbolS * symbolP;
b99bd4ef
NC
1668
1669 /* Especial apologies for the random logic:
1670 This just grew, and could be parsed much more simply!
1671 Dean - in haste. */
1672 name = input_line_pointer;
1673 delim = get_symbol_end ();
1674 end_name = input_line_pointer;
1675 *end_name = delim;
1676
1677 SKIP_WHITESPACE ();
1678
1679 if (*input_line_pointer != ',')
1680 {
1681 *end_name = 0;
f03698e6 1682 as_bad (_("expected comma after name \"%s\""), name);
b99bd4ef
NC
1683 *end_name = delim;
1684 ignore_rest_of_line ();
1685 return;
1686 }
1687
1688 input_line_pointer++;
1689 *end_name = 0;
1690
1691 if (name[0] == '.' && name[1] == '\0')
1692 {
1693 /* XXX - this should not happen to .thumb_set. */
1694 abort ();
1695 }
1696
1697 if ((symbolP = symbol_find (name)) == NULL
1698 && (symbolP = md_undefined_symbol (name)) == NULL)
1699 {
1700#ifndef NO_LISTING
1701 /* When doing symbol listings, play games with dummy fragments living
1702 outside the normal fragment chain to record the file and line info
1703 for this symbol. */
1704 if (listing & LISTING_SYMBOLS)
1705 {
1706 extern struct list_info_struct * listing_tail;
a737bd4d 1707 fragS * dummy_frag = xmalloc (sizeof (fragS));
b99bd4ef
NC
1708
1709 memset (dummy_frag, 0, sizeof (fragS));
1710 dummy_frag->fr_type = rs_fill;
1711 dummy_frag->line = listing_tail;
1712 symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
1713 dummy_frag->fr_symbol = symbolP;
1714 }
1715 else
1716#endif
1717 symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
1718
1719#ifdef OBJ_COFF
1720 /* "set" symbols are local unless otherwise specified. */
1721 SF_SET_LOCAL (symbolP);
1722#endif /* OBJ_COFF */
1723 } /* Make a new symbol. */
1724
1725 symbol_table_insert (symbolP);
1726
1727 * end_name = delim;
1728
1729 if (equiv
1730 && S_IS_DEFINED (symbolP)
1731 && S_GET_SEGMENT (symbolP) != reg_section)
1732 as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
1733
1734 pseudo_set (symbolP);
1735
1736 demand_empty_rest_of_line ();
1737
1738 /* XXX Now we come to the Thumb specific bit of code. */
1739
1740 THUMB_SET_FUNC (symbolP, 1);
1741 ARM_SET_THUMB (symbolP, 1);
1742#if defined OBJ_ELF || defined OBJ_COFF
1743 ARM_SET_INTERWORK (symbolP, support_interwork);
1744#endif
1745}
1746
b99bd4ef 1747static void
a737bd4d 1748s_arm (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1749{
1750 opcode_select (32);
1751 demand_empty_rest_of_line ();
1752}
1753
1754static void
a737bd4d 1755s_thumb (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1756{
1757 opcode_select (16);
1758 demand_empty_rest_of_line ();
1759}
1760
1761static void
a737bd4d 1762s_code (int unused ATTRIBUTE_UNUSED)
b99bd4ef 1763{
a737bd4d 1764 int temp;
b99bd4ef
NC
1765
1766 temp = get_absolute_expression ();
1767 switch (temp)
1768 {
1769 case 16:
1770 case 32:
1771 opcode_select (temp);
1772 break;
1773
1774 default:
1775 as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
1776 }
1777}
1778
1779static void
a737bd4d 1780end_of_line (char * str)
b99bd4ef
NC
1781{
1782 skip_whitespace (str);
1783
f03698e6
RE
1784 if (*str != '\0' && !inst.error)
1785 inst.error = _("garbage following instruction");
b99bd4ef
NC
1786}
1787
1788static int
a737bd4d 1789skip_past_comma (char ** str)
b99bd4ef
NC
1790{
1791 char * p = * str, c;
1792 int comma = 0;
1793
1794 while ((c = *p) == ' ' || c == ',')
1795 {
1796 p++;
1797 if (c == ',' && comma++)
1798 return FAIL;
1799 }
1800
1801 if (c == '\0')
1802 return FAIL;
1803
1804 *str = p;
1805 return comma ? SUCCESS : FAIL;
1806}
1807
a737bd4d
NC
1808/* Return TRUE if anything in the expression is a bignum. */
1809
1810static int
1811walk_no_bignums (symbolS * sp)
1812{
1813 if (symbol_get_value_expression (sp)->X_op == O_big)
1814 return 1;
1815
1816 if (symbol_get_value_expression (sp)->X_add_symbol)
1817 {
1818 return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
1819 || (symbol_get_value_expression (sp)->X_op_symbol
1820 && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
1821 }
1822
1823 return 0;
1824}
1825
1826static int in_my_get_expression = 0;
1827
1828static int
1829my_get_expression (expressionS * ep, char ** str)
1830{
1831 char * save_in;
1832 segT seg;
1833
1834 save_in = input_line_pointer;
1835 input_line_pointer = *str;
1836 in_my_get_expression = 1;
1837 seg = expression (ep);
1838 in_my_get_expression = 0;
1839
1840 if (ep->X_op == O_illegal)
1841 {
1842 /* We found a bad expression in md_operand(). */
1843 *str = input_line_pointer;
1844 input_line_pointer = save_in;
1845 return 1;
1846 }
1847
1848#ifdef OBJ_AOUT
1849 if (seg != absolute_section
1850 && seg != text_section
1851 && seg != data_section
1852 && seg != bss_section
1853 && seg != undefined_section)
1854 {
1855 inst.error = _("bad_segment");
1856 *str = input_line_pointer;
1857 input_line_pointer = save_in;
1858 return 1;
1859 }
1860#endif
1861
1862 /* Get rid of any bignums now, so that we don't generate an error for which
1863 we can't establish a line number later on. Big numbers are never valid
1864 in instructions, which is where this routine is always called. */
1865 if (ep->X_op == O_big
1866 || (ep->X_add_symbol
1867 && (walk_no_bignums (ep->X_add_symbol)
1868 || (ep->X_op_symbol
1869 && walk_no_bignums (ep->X_op_symbol)))))
1870 {
1871 inst.error = _("invalid constant");
1872 *str = input_line_pointer;
1873 input_line_pointer = save_in;
1874 return 1;
1875 }
1876
1877 *str = input_line_pointer;
1878 input_line_pointer = save_in;
1879 return 0;
1880}
1881
b99bd4ef
NC
1882/* A standard register must be given at this point.
1883 SHIFT is the place to put it in inst.instruction.
1884 Restores input start point on error.
1885 Returns the reg#, or FAIL. */
1886
1887static int
a737bd4d 1888reg_required_here (char ** str, int shift)
b99bd4ef
NC
1889{
1890 static char buff [128]; /* XXX */
1891 int reg;
1892 char * start = * str;
1893
6c43fab6 1894 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL)
b99bd4ef
NC
1895 {
1896 if (shift >= 0)
1897 inst.instruction |= reg << shift;
1898 return reg;
1899 }
1900
1901 /* Restore the start point, we may have got a reg of the wrong class. */
1902 *str = start;
1903
1904 /* In the few cases where we might be able to accept something else
1905 this error can be overridden. */
f03698e6 1906 sprintf (buff, _("register expected, not '%.100s'"), start);
b99bd4ef
NC
1907 inst.error = buff;
1908
1909 return FAIL;
1910}
1911
5a6c6817 1912/* A Intel Wireless MMX technology register
e16bb312
NC
1913 must be given at this point.
1914 Shift is the place to put it in inst.instruction.
1915 Restores input start point on err.
1916 Returns the reg#, or FAIL. */
1917
1918static int
a737bd4d
NC
1919wreg_required_here (char ** str,
1920 int shift,
1921 enum wreg_type reg_type)
e16bb312
NC
1922{
1923 static char buff [128];
1924 int reg;
1925 char * start = *str;
1926
1927 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_IWMMXT].htab)) != FAIL)
1928 {
1929 if (wr_register (reg)
1930 && (reg_type == IWMMXT_REG_WR || reg_type == IWMMXT_REG_WR_OR_WC))
1931 {
1932 if (shift >= 0)
1933 inst.instruction |= (reg ^ WR_PREFIX) << shift;
1934 return reg;
1935 }
1936 else if (wc_register (reg)
1937 && (reg_type == IWMMXT_REG_WC || reg_type == IWMMXT_REG_WR_OR_WC))
1938 {
1939 if (shift >= 0)
1940 inst.instruction |= (reg ^ WC_PREFIX) << shift;
1941 return reg;
1942 }
1943 else if ((wcg_register (reg) && reg_type == IWMMXT_REG_WCG))
1944 {
1945 if (shift >= 0)
1946 inst.instruction |= ((reg ^ WC_PREFIX) - 8) << shift;
1947 return reg;
1948 }
1949 }
1950
1951 /* Restore the start point, we may have got a reg of the wrong class. */
1952 *str = start;
1953
1954 /* In the few cases where we might be able to accept
1955 something else this error can be overridden. */
5a6c6817 1956 sprintf (buff, _("Intel Wireless MMX technology register expected, not '%.100s'"), start);
e16bb312
NC
1957 inst.error = buff;
1958
1959 return FAIL;
1960}
1961
05d2d07e 1962static const struct asm_psr *
a737bd4d 1963arm_psr_parse (char ** ccp)
b99bd4ef
NC
1964{
1965 char * start = * ccp;
1966 char c;
1967 char * p;
05d2d07e 1968 const struct asm_psr * psr;
b99bd4ef
NC
1969
1970 p = start;
1971
1972 /* Skip to the end of the next word in the input stream. */
1973 do
1974 {
1975 c = *p++;
1976 }
3882b010 1977 while (ISALPHA (c) || c == '_');
b99bd4ef
NC
1978
1979 /* Terminate the word. */
1980 *--p = 0;
1981
1982 /* CPSR's and SPSR's can now be lowercase. This is just a convenience
1983 feature for ease of use and backwards compatibility. */
1984 if (!strncmp (start, "cpsr", 4))
1985 strncpy (start, "CPSR", 4);
1986 else if (!strncmp (start, "spsr", 4))
1987 strncpy (start, "SPSR", 4);
1988
1989 /* Now locate the word in the psr hash table. */
05d2d07e 1990 psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start);
b99bd4ef
NC
1991
1992 /* Restore the input stream. */
1993 *p = c;
1994
1995 /* If we found a valid match, advance the
1996 stream pointer past the end of the word. */
1997 *ccp = p;
1998
1999 return psr;
2000}
2001
2002/* Parse the input looking for a PSR flag. */
2003
2004static int
a737bd4d 2005psr_required_here (char ** str)
b99bd4ef
NC
2006{
2007 char * start = * str;
05d2d07e 2008 const struct asm_psr * psr;
b99bd4ef
NC
2009
2010 psr = arm_psr_parse (str);
2011
2012 if (psr)
2013 {
2014 /* If this is the SPSR that is being modified, set the R bit. */
2015 if (! psr->cpsr)
2016 inst.instruction |= SPSR_BIT;
2017
2018 /* Set the psr flags in the MSR instruction. */
2019 inst.instruction |= psr->field << PSR_SHIFT;
2020
2021 return SUCCESS;
2022 }
2023
2024 /* In the few cases where we might be able to accept
2025 something else this error can be overridden. */
2026 inst.error = _("flag for {c}psr instruction expected");
2027
2028 /* Restore the start point. */
2029 *str = start;
2030 return FAIL;
2031}
2032
2033static int
a737bd4d 2034co_proc_number (char ** str)
b99bd4ef
NC
2035{
2036 int processor, pchar;
6c43fab6 2037 char *start;
b99bd4ef 2038
6c43fab6
RE
2039 skip_whitespace (*str);
2040 start = *str;
b99bd4ef
NC
2041
2042 /* The data sheet seems to imply that just a number on its own is valid
2043 here, but the RISC iX assembler seems to accept a prefix 'p'. We will
2044 accept either. */
6c43fab6
RE
2045 if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab))
2046 == FAIL)
b99bd4ef 2047 {
6c43fab6
RE
2048 *str = start;
2049
2050 pchar = *(*str)++;
2051 if (pchar >= '0' && pchar <= '9')
b99bd4ef 2052 {
6c43fab6
RE
2053 processor = pchar - '0';
2054 if (**str >= '0' && **str <= '9')
b99bd4ef 2055 {
6c43fab6
RE
2056 processor = processor * 10 + *(*str)++ - '0';
2057 if (processor > 15)
2058 {
f03698e6 2059 inst.error = _("illegal co-processor number");
6c43fab6
RE
2060 return FAIL;
2061 }
b99bd4ef
NC
2062 }
2063 }
6c43fab6
RE
2064 else
2065 {
376eb240 2066 inst.error = all_reg_maps[REG_TYPE_CP].expected;
6c43fab6
RE
2067 return FAIL;
2068 }
b99bd4ef
NC
2069 }
2070
2071 inst.instruction |= processor << 8;
2072 return SUCCESS;
2073}
2074
2075static int
a737bd4d 2076cp_opc_expr (char ** str, int where, int length)
b99bd4ef
NC
2077{
2078 expressionS expr;
2079
2080 skip_whitespace (* str);
2081
2082 memset (&expr, '\0', sizeof (expr));
2083
2084 if (my_get_expression (&expr, str))
2085 return FAIL;
2086 if (expr.X_op != O_constant)
2087 {
2088 inst.error = _("bad or missing expression");
2089 return FAIL;
2090 }
2091
2092 if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
2093 {
2094 inst.error = _("immediate co-processor expression too large");
2095 return FAIL;
2096 }
2097
2098 inst.instruction |= expr.X_add_number << where;
2099 return SUCCESS;
2100}
2101
2102static int
a737bd4d 2103cp_reg_required_here (char ** str, int where)
b99bd4ef
NC
2104{
2105 int reg;
2106 char * start = *str;
2107
6c43fab6 2108 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
b99bd4ef 2109 {
b99bd4ef
NC
2110 inst.instruction |= reg << where;
2111 return reg;
2112 }
2113
2114 /* In the few cases where we might be able to accept something else
2115 this error can be overridden. */
376eb240 2116 inst.error = all_reg_maps[REG_TYPE_CN].expected;
b99bd4ef
NC
2117
2118 /* Restore the start point. */
2119 *str = start;
2120 return FAIL;
2121}
2122
2123static int
a737bd4d 2124fp_reg_required_here (char ** str, int where)
b99bd4ef
NC
2125{
2126 int reg;
2127 char * start = * str;
2128
6c43fab6 2129 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL)
b99bd4ef 2130 {
b99bd4ef
NC
2131 inst.instruction |= reg << where;
2132 return reg;
2133 }
2134
2135 /* In the few cases where we might be able to accept something else
2136 this error can be overridden. */
376eb240 2137 inst.error = all_reg_maps[REG_TYPE_FN].expected;
b99bd4ef
NC
2138
2139 /* Restore the start point. */
2140 *str = start;
2141 return FAIL;
2142}
2143
2144static int
a737bd4d 2145cp_address_offset (char ** str)
b99bd4ef
NC
2146{
2147 int offset;
2148
2149 skip_whitespace (* str);
2150
2151 if (! is_immediate_prefix (**str))
2152 {
2153 inst.error = _("immediate expression expected");
2154 return FAIL;
2155 }
2156
2157 (*str)++;
2158
2159 if (my_get_expression (& inst.reloc.exp, str))
2160 return FAIL;
2161
2162 if (inst.reloc.exp.X_op == O_constant)
2163 {
2164 offset = inst.reloc.exp.X_add_number;
2165
2166 if (offset & 3)
2167 {
2168 inst.error = _("co-processor address must be word aligned");
2169 return FAIL;
2170 }
2171
2172 if (offset > 1023 || offset < -1023)
2173 {
2174 inst.error = _("offset too large");
2175 return FAIL;
2176 }
2177
2178 if (offset >= 0)
2179 inst.instruction |= INDEX_UP;
2180 else
2181 offset = -offset;
2182
2183 inst.instruction |= offset >> 2;
2184 }
2185 else
2186 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
2187
2188 return SUCCESS;
2189}
2190
2191static int
a737bd4d 2192cp_address_required_here (char ** str, int wb_ok)
b99bd4ef
NC
2193{
2194 char * p = * str;
2195 int pre_inc = 0;
2196 int write_back = 0;
2197
2198 if (*p == '[')
2199 {
2200 int reg;
2201
2202 p++;
2203 skip_whitespace (p);
2204
2205 if ((reg = reg_required_here (& p, 16)) == FAIL)
2206 return FAIL;
2207
2208 skip_whitespace (p);
2209
2210 if (*p == ']')
2211 {
2212 p++;
2213
f02232aa
NC
2214 skip_whitespace (p);
2215
2216 if (*p == '\0')
b99bd4ef 2217 {
f02232aa 2218 /* As an extension to the official ARM syntax we allow:
f02232aa 2219 [Rn]
f02232aa 2220 as a short hand for:
f02232aa
NC
2221 [Rn,#0] */
2222 inst.instruction |= PRE_INDEX | INDEX_UP;
2223 *str = p;
2224 return SUCCESS;
2225 }
a737bd4d 2226
f02232aa
NC
2227 if (skip_past_comma (& p) == FAIL)
2228 {
2229 inst.error = _("comma expected after closing square bracket");
2230 return FAIL;
2231 }
b99bd4ef 2232
f02232aa
NC
2233 skip_whitespace (p);
2234
2235 if (*p == '#')
2236 {
2237 if (wb_ok)
b99bd4ef 2238 {
f02232aa
NC
2239 /* [Rn], #expr */
2240 write_back = WRITE_BACK;
2241
2242 if (reg == REG_PC)
2243 {
2244 inst.error = _("pc may not be used in post-increment");
2245 return FAIL;
2246 }
2247
2248 if (cp_address_offset (& p) == FAIL)
2249 return FAIL;
b99bd4ef 2250 }
f02232aa
NC
2251 else
2252 pre_inc = PRE_INDEX | INDEX_UP;
2253 }
2254 else if (*p == '{')
2255 {
2256 int option;
b99bd4ef 2257
f02232aa
NC
2258 /* [Rn], {<expr>} */
2259 p++;
2260
2261 skip_whitespace (p);
2262
2263 if (my_get_expression (& inst.reloc.exp, & p))
b99bd4ef 2264 return FAIL;
f02232aa
NC
2265
2266 if (inst.reloc.exp.X_op == O_constant)
2267 {
2268 option = inst.reloc.exp.X_add_number;
2269
2270 if (option > 255 || option < 0)
2271 {
2272 inst.error = _("'option' field too large");
2273 return FAIL;
2274 }
2275
2276 skip_whitespace (p);
2277
2278 if (*p != '}')
2279 {
2280 inst.error = _("'}' expected at end of 'option' field");
2281 return FAIL;
2282 }
2283 else
2284 {
2285 p++;
2286 inst.instruction |= option;
2287 inst.instruction |= INDEX_UP;
2288 }
2289 }
2290 else
2291 {
2292 inst.error = _("non-constant expressions for 'option' field not supported");
2293 return FAIL;
2294 }
b99bd4ef
NC
2295 }
2296 else
f02232aa
NC
2297 {
2298 inst.error = _("# or { expected after comma");
a737bd4d 2299 return FAIL;
f02232aa 2300 }
b99bd4ef
NC
2301 }
2302 else
2303 {
2304 /* '['Rn, #expr']'[!] */
2305
2306 if (skip_past_comma (& p) == FAIL)
2307 {
2308 inst.error = _("pre-indexed expression expected");
2309 return FAIL;
2310 }
2311
2312 pre_inc = PRE_INDEX;
2313
2314 if (cp_address_offset (& p) == FAIL)
2315 return FAIL;
2316
2317 skip_whitespace (p);
2318
2319 if (*p++ != ']')
2320 {
2321 inst.error = _("missing ]");
2322 return FAIL;
2323 }
2324
2325 skip_whitespace (p);
2326
bfae80f2 2327 if (wb_ok && *p == '!')
b99bd4ef
NC
2328 {
2329 if (reg == REG_PC)
2330 {
2331 inst.error = _("pc may not be used with write-back");
2332 return FAIL;
2333 }
2334
2335 p++;
2336 write_back = WRITE_BACK;
2337 }
2338 }
2339 }
2340 else
2341 {
2342 if (my_get_expression (&inst.reloc.exp, &p))
2343 return FAIL;
2344
2345 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
2346 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
2347 inst.reloc.pc_rel = 1;
2348 inst.instruction |= (REG_PC << 16);
2349 pre_inc = PRE_INDEX;
2350 }
2351
2352 inst.instruction |= write_back | pre_inc;
2353 *str = p;
2354 return SUCCESS;
2355}
2356
e16bb312 2357static int
a737bd4d 2358cp_byte_address_offset (char ** str)
e16bb312
NC
2359{
2360 int offset;
2361
2362 skip_whitespace (* str);
2363
2364 if (! is_immediate_prefix (**str))
2365 {
2366 inst.error = _("immediate expression expected");
2367 return FAIL;
2368 }
2369
2370 (*str)++;
a737bd4d 2371
e16bb312
NC
2372 if (my_get_expression (& inst.reloc.exp, str))
2373 return FAIL;
a737bd4d 2374
e16bb312
NC
2375 if (inst.reloc.exp.X_op == O_constant)
2376 {
2377 offset = inst.reloc.exp.X_add_number;
a737bd4d 2378
e16bb312
NC
2379 if (offset > 255 || offset < -255)
2380 {
2381 inst.error = _("offset too large");
2382 return FAIL;
2383 }
2384
2385 if (offset >= 0)
2386 inst.instruction |= INDEX_UP;
2387 else
2388 offset = -offset;
2389
2390 inst.instruction |= offset;
2391 }
2392 else
2393 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
2394
2395 return SUCCESS;
2396}
2397
2398static int
a737bd4d 2399cp_byte_address_required_here (char ** str)
e16bb312
NC
2400{
2401 char * p = * str;
2402 int pre_inc = 0;
2403 int write_back = 0;
2404
2405 if (*p == '[')
2406 {
2407 int reg;
2408
2409 p++;
2410 skip_whitespace (p);
2411
2412 if ((reg = reg_required_here (& p, 16)) == FAIL)
2413 return FAIL;
2414
2415 skip_whitespace (p);
2416
2417 if (*p == ']')
2418 {
2419 p++;
a737bd4d 2420
e16bb312
NC
2421 if (skip_past_comma (& p) == SUCCESS)
2422 {
2423 /* [Rn], #expr */
2424 write_back = WRITE_BACK;
a737bd4d 2425
e16bb312
NC
2426 if (reg == REG_PC)
2427 {
2428 inst.error = _("pc may not be used in post-increment");
2429 return FAIL;
2430 }
2431
2432 if (cp_byte_address_offset (& p) == FAIL)
2433 return FAIL;
2434 }
2435 else
2436 pre_inc = PRE_INDEX | INDEX_UP;
2437 }
2438 else
2439 {
2440 /* '['Rn, #expr']'[!] */
2441
2442 if (skip_past_comma (& p) == FAIL)
2443 {
2444 inst.error = _("pre-indexed expression expected");
2445 return FAIL;
2446 }
2447
2448 pre_inc = PRE_INDEX;
a737bd4d 2449
e16bb312
NC
2450 if (cp_byte_address_offset (& p) == FAIL)
2451 return FAIL;
2452
2453 skip_whitespace (p);
2454
2455 if (*p++ != ']')
2456 {
2457 inst.error = _("missing ]");
2458 return FAIL;
2459 }
2460
2461 skip_whitespace (p);
2462
2463 if (*p == '!')
2464 {
2465 if (reg == REG_PC)
2466 {
2467 inst.error = _("pc may not be used with write-back");
2468 return FAIL;
2469 }
2470
2471 p++;
2472 write_back = WRITE_BACK;
2473 }
2474 }
2475 }
2476 else
2477 {
2478 if (my_get_expression (&inst.reloc.exp, &p))
2479 return FAIL;
2480
2481 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
2482 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
2483 inst.reloc.pc_rel = 1;
2484 inst.instruction |= (REG_PC << 16);
2485 pre_inc = PRE_INDEX;
2486 }
2487
2488 inst.instruction |= write_back | pre_inc;
2489 *str = p;
2490 return SUCCESS;
2491}
2492
0dd132b6
NC
2493static void
2494do_nop (char * str)
2495{
2496 skip_whitespace (str);
2497 if (*str == '{')
2498 {
2499 str++;
2500
2501 if (my_get_expression (&inst.reloc.exp, &str))
2502 inst.reloc.exp.X_op = O_illegal;
2503 else
2504 {
2505 skip_whitespace (str);
2506 if (*str == '}')
2507 str++;
2508 else
2509 inst.reloc.exp.X_op = O_illegal;
2510 }
2511
2512 if (inst.reloc.exp.X_op != O_constant
2513 || inst.reloc.exp.X_add_number > 255
2514 || inst.reloc.exp.X_add_number < 0)
2515 {
2516 inst.error = _("Invalid NOP hint");
2517 return;
2518 }
2519
2520 /* Arcitectural NOP hints are CPSR sets with no bits selected. */
2521 inst.instruction &= 0xf0000000;
2522 inst.instruction |= 0x0320f000 + inst.reloc.exp.X_add_number;
2523 }
2524
2525 end_of_line (str);
2526}
2527
b99bd4ef 2528static void
a737bd4d 2529do_empty (char * str)
b99bd4ef
NC
2530{
2531 /* Do nothing really. */
b99bd4ef 2532 end_of_line (str);
b99bd4ef
NC
2533}
2534
2535static void
a737bd4d 2536do_mrs (char * str)
b99bd4ef
NC
2537{
2538 int skip = 0;
2539
2540 /* Only one syntax. */
2541 skip_whitespace (str);
2542
2543 if (reg_required_here (&str, 12) == FAIL)
2544 {
2545 inst.error = BAD_ARGS;
2546 return;
2547 }
2548
2549 if (skip_past_comma (&str) == FAIL)
2550 {
2551 inst.error = _("comma expected after register name");
2552 return;
2553 }
2554
2555 skip_whitespace (str);
2556
a737bd4d
NC
2557 if ( streq (str, "CPSR")
2558 || streq (str, "SPSR")
2d2255b5 2559 /* Lower case versions for backwards compatibility. */
a737bd4d
NC
2560 || streq (str, "cpsr")
2561 || streq (str, "spsr"))
b99bd4ef
NC
2562 skip = 4;
2563
2d2255b5 2564 /* This is for backwards compatibility with older toolchains. */
a737bd4d
NC
2565 else if ( streq (str, "cpsr_all")
2566 || streq (str, "spsr_all"))
b99bd4ef
NC
2567 skip = 8;
2568 else
2569 {
f03698e6 2570 inst.error = _("CPSR or SPSR expected");
b99bd4ef
NC
2571 return;
2572 }
2573
2574 if (* str == 's' || * str == 'S')
2575 inst.instruction |= SPSR_BIT;
2576 str += skip;
2577
b99bd4ef
NC
2578 end_of_line (str);
2579}
2580
2581/* Two possible forms:
2582 "{C|S}PSR_<field>, Rm",
2583 "{C|S}PSR_f, #expression". */
2584
2585static void
a737bd4d 2586do_msr (char * str)
b99bd4ef
NC
2587{
2588 skip_whitespace (str);
2589
2590 if (psr_required_here (& str) == FAIL)
2591 return;
2592
2593 if (skip_past_comma (& str) == FAIL)
2594 {
2595 inst.error = _("comma missing after psr flags");
2596 return;
2597 }
2598
2599 skip_whitespace (str);
2600
2601 if (reg_required_here (& str, 0) != FAIL)
2602 {
2603 inst.error = NULL;
b99bd4ef
NC
2604 end_of_line (str);
2605 return;
2606 }
2607
2608 if (! is_immediate_prefix (* str))
2609 {
2610 inst.error =
2611 _("only a register or immediate value can follow a psr flag");
2612 return;
2613 }
2614
2615 str ++;
2616 inst.error = NULL;
2617
2618 if (my_get_expression (& inst.reloc.exp, & str))
2619 {
2620 inst.error =
2621 _("only a register or immediate value can follow a psr flag");
2622 return;
2623 }
2624
f2b7cb0a 2625 inst.instruction |= INST_IMMEDIATE;
b99bd4ef
NC
2626
2627 if (inst.reloc.exp.X_add_symbol)
2628 {
2629 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
2630 inst.reloc.pc_rel = 0;
2631 }
2632 else
2633 {
2634 unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
2635
2636 if (value == (unsigned) FAIL)
2637 {
f03698e6 2638 inst.error = _("invalid constant");
b99bd4ef
NC
2639 return;
2640 }
2641
2642 inst.instruction |= value;
2643 }
2644
2645 inst.error = NULL;
b99bd4ef
NC
2646 end_of_line (str);
2647}
2648
2649/* Long Multiply Parser
2650 UMULL RdLo, RdHi, Rm, Rs
2651 SMULL RdLo, RdHi, Rm, Rs
2652 UMLAL RdLo, RdHi, Rm, Rs
2653 SMLAL RdLo, RdHi, Rm, Rs. */
2654
2655static void
a737bd4d 2656do_mull (char * str)
b99bd4ef
NC
2657{
2658 int rdlo, rdhi, rm, rs;
2659
2660 /* Only one format "rdlo, rdhi, rm, rs". */
2661 skip_whitespace (str);
2662
2663 if ((rdlo = reg_required_here (&str, 12)) == FAIL)
2664 {
2665 inst.error = BAD_ARGS;
2666 return;
2667 }
2668
2669 if (skip_past_comma (&str) == FAIL
2670 || (rdhi = reg_required_here (&str, 16)) == FAIL)
2671 {
2672 inst.error = BAD_ARGS;
2673 return;
2674 }
2675
2676 if (skip_past_comma (&str) == FAIL
2677 || (rm = reg_required_here (&str, 0)) == FAIL)
2678 {
2679 inst.error = BAD_ARGS;
2680 return;
2681 }
2682
2683 /* rdhi, rdlo and rm must all be different. */
2684 if (rdlo == rdhi || rdlo == rm || rdhi == rm)
2685 as_tsktsk (_("rdhi, rdlo and rm must all be different"));
2686
2687 if (skip_past_comma (&str) == FAIL
2688 || (rs = reg_required_here (&str, 8)) == FAIL)
2689 {
2690 inst.error = BAD_ARGS;
2691 return;
2692 }
2693
2694 if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
2695 {
2696 inst.error = BAD_PC;
2697 return;
2698 }
2699
b99bd4ef 2700 end_of_line (str);
b99bd4ef
NC
2701}
2702
2703static void
a737bd4d 2704do_mul (char * str)
b99bd4ef
NC
2705{
2706 int rd, rm;
2707
2708 /* Only one format "rd, rm, rs". */
2709 skip_whitespace (str);
2710
2711 if ((rd = reg_required_here (&str, 16)) == FAIL)
2712 {
2713 inst.error = BAD_ARGS;
2714 return;
2715 }
2716
2717 if (rd == REG_PC)
2718 {
2719 inst.error = BAD_PC;
2720 return;
2721 }
2722
2723 if (skip_past_comma (&str) == FAIL
2724 || (rm = reg_required_here (&str, 0)) == FAIL)
2725 {
2726 inst.error = BAD_ARGS;
2727 return;
2728 }
2729
2730 if (rm == REG_PC)
2731 {
2732 inst.error = BAD_PC;
2733 return;
2734 }
2735
2736 if (rm == rd)
2737 as_tsktsk (_("rd and rm should be different in mul"));
2738
2739 if (skip_past_comma (&str) == FAIL
2740 || (rm = reg_required_here (&str, 8)) == FAIL)
2741 {
2742 inst.error = BAD_ARGS;
2743 return;
2744 }
2745
2746 if (rm == REG_PC)
2747 {
2748 inst.error = BAD_PC;
2749 return;
2750 }
2751
b99bd4ef 2752 end_of_line (str);
b99bd4ef
NC
2753}
2754
2755static void
b05fe5cf 2756do_mlas (char * str, bfd_boolean is_mls)
b99bd4ef
NC
2757{
2758 int rd, rm;
2759
2760 /* Only one format "rd, rm, rs, rn". */
2761 skip_whitespace (str);
2762
2763 if ((rd = reg_required_here (&str, 16)) == FAIL)
2764 {
2765 inst.error = BAD_ARGS;
2766 return;
2767 }
2768
2769 if (rd == REG_PC)
2770 {
2771 inst.error = BAD_PC;
2772 return;
2773 }
2774
2775 if (skip_past_comma (&str) == FAIL
2776 || (rm = reg_required_here (&str, 0)) == FAIL)
2777 {
2778 inst.error = BAD_ARGS;
2779 return;
2780 }
2781
2782 if (rm == REG_PC)
2783 {
2784 inst.error = BAD_PC;
2785 return;
2786 }
2787
b05fe5cf
ZW
2788 /* This restriction does not apply to mls (nor to mla in v6, but
2789 that's hard to detect at present). */
2790 if (rm == rd && !is_mls)
b99bd4ef
NC
2791 as_tsktsk (_("rd and rm should be different in mla"));
2792
2793 if (skip_past_comma (&str) == FAIL
2794 || (rd = reg_required_here (&str, 8)) == FAIL
2795 || skip_past_comma (&str) == FAIL
2796 || (rm = reg_required_here (&str, 12)) == FAIL)
2797 {
2798 inst.error = BAD_ARGS;
2799 return;
2800 }
2801
2802 if (rd == REG_PC || rm == REG_PC)
2803 {
2804 inst.error = BAD_PC;
2805 return;
2806 }
2807
b99bd4ef 2808 end_of_line (str);
b99bd4ef
NC
2809}
2810
b05fe5cf
ZW
2811static void
2812do_mla (char *str)
2813{
2814 do_mlas (str, FALSE);
2815}
2816
2817static void
2818do_mls (char *str)
2819{
2820 do_mlas (str, TRUE);
2821}
2822
b99bd4ef
NC
2823/* Expects *str -> the characters "acc0", possibly with leading blanks.
2824 Advances *str to the next non-alphanumeric.
2825 Returns 0, or else FAIL (in which case sets inst.error).
2826
2827 (In a future XScale, there may be accumulators other than zero.
2828 At that time this routine and its callers can be upgraded to suit.) */
2829
2830static int
a737bd4d 2831accum0_required_here (char ** str)
b99bd4ef
NC
2832{
2833 static char buff [128]; /* Note the address is taken. Hence, static. */
2834 char * p = * str;
2835 char c;
2836 int result = 0; /* The accum number. */
2837
2838 skip_whitespace (p);
2839
a737bd4d
NC
2840 *str = p; /* Advance caller's string pointer too. */
2841 c = *p++;
2842 while (ISALNUM (c))
2843 c = *p++;
2844
2845 *--p = 0; /* Aap nul into input buffer at non-alnum. */
2846
2847 if (! ( streq (*str, "acc0") || streq (*str, "ACC0")))
2848 {
2849 sprintf (buff, _("acc0 expected, not '%.100s'"), *str);
2850 inst.error = buff;
2851 result = FAIL;
2852 }
2853
2854 *p = c; /* Unzap. */
2855 *str = p; /* Caller's string pointer to after match. */
2856 return result;
2857}
2858
2859static int
2860ldst_extend_v4 (char ** str)
2861{
2862 int add = INDEX_UP;
2863
2864 switch (**str)
2865 {
2866 case '#':
2867 case '$':
2868 (*str)++;
2869 if (my_get_expression (& inst.reloc.exp, str))
2870 return FAIL;
2871
2872 if (inst.reloc.exp.X_op == O_constant)
2873 {
2874 int value = inst.reloc.exp.X_add_number;
2875
2876 if (value < -255 || value > 255)
2877 {
2878 inst.error = _("address offset too large");
2879 return FAIL;
2880 }
2881
2882 if (value < 0)
2883 {
2884 value = -value;
2885 add = 0;
2886 }
2887
2888 /* Halfword and signextension instructions have the
2889 immediate value split across bits 11..8 and bits 3..0. */
2890 inst.instruction |= (add | HWOFFSET_IMM
2891 | ((value >> 4) << 8) | (value & 0xF));
2892 }
2893 else
2894 {
2895 inst.instruction |= HWOFFSET_IMM;
2896 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
2897 inst.reloc.pc_rel = 0;
2898 }
2899 return SUCCESS;
2900
2901 case '-':
2902 add = 0;
2903 /* Fall through. */
2904
2905 case '+':
2906 (*str)++;
2907 /* Fall through. */
b99bd4ef 2908
a737bd4d
NC
2909 default:
2910 if (reg_required_here (str, 0) == FAIL)
2911 return FAIL;
b99bd4ef 2912
a737bd4d
NC
2913 inst.instruction |= add;
2914 return SUCCESS;
b99bd4ef 2915 }
b99bd4ef
NC
2916}
2917
2918/* Expects **str -> after a comma. May be leading blanks.
2919 Advances *str, recognizing a load mode, and setting inst.instruction.
2920 Returns rn, or else FAIL (in which case may set inst.error
2921 and not advance str)
2922
2923 Note: doesn't know Rd, so no err checks that require such knowledge. */
2924
2925static int
a737bd4d 2926ld_mode_required_here (char ** string)
b99bd4ef
NC
2927{
2928 char * str = * string;
2929 int rn;
2930 int pre_inc = 0;
2931
2932 skip_whitespace (str);
2933
2934 if (* str == '[')
2935 {
2936 str++;
2937
2938 skip_whitespace (str);
2939
2940 if ((rn = reg_required_here (& str, 16)) == FAIL)
2941 return FAIL;
2942
2943 skip_whitespace (str);
2944
2945 if (* str == ']')
2946 {
2947 str ++;
2948
2949 if (skip_past_comma (& str) == SUCCESS)
2950 {
2951 /* [Rn],... (post inc) */
90e4755a 2952 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
2953 return FAIL;
2954 }
2955 else /* [Rn] */
2956 {
cc8a6dd0 2957 skip_whitespace (str);
b99bd4ef 2958
cc8a6dd0
KH
2959 if (* str == '!')
2960 {
2961 str ++;
2962 inst.instruction |= WRITE_BACK;
2963 }
b99bd4ef
NC
2964
2965 inst.instruction |= INDEX_UP | HWOFFSET_IMM;
2966 pre_inc = 1;
2967 }
2968 }
2969 else /* [Rn,...] */
2970 {
2971 if (skip_past_comma (& str) == FAIL)
2972 {
2973 inst.error = _("pre-indexed expression expected");
2974 return FAIL;
2975 }
2976
2977 pre_inc = 1;
2978
90e4755a 2979 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
2980 return FAIL;
2981
2982 skip_whitespace (str);
2983
2984 if (* str ++ != ']')
2985 {
2986 inst.error = _("missing ]");
2987 return FAIL;
2988 }
2989
2990 skip_whitespace (str);
2991
2992 if (* str == '!')
2993 {
2994 str ++;
2995 inst.instruction |= WRITE_BACK;
2996 }
2997 }
2998 }
2999 else if (* str == '=') /* ldr's "r,=label" syntax */
3000 /* We should never reach here, because <text> = <expression> is
3001 caught gas/read.c read_a_source_file() as a .set operation. */
3002 return FAIL;
3003 else /* PC +- 8 bit immediate offset. */
3004 {
3005 if (my_get_expression (& inst.reloc.exp, & str))
3006 return FAIL;
3007
3008 inst.instruction |= HWOFFSET_IMM; /* The I bit. */
3009 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
3010 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
3011 inst.reloc.pc_rel = 1;
3012 inst.instruction |= (REG_PC << 16);
3013
3014 rn = REG_PC;
3015 pre_inc = 1;
3016 }
3017
3018 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
3019 * string = str;
3020
3021 return rn;
3022}
3023
3024/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
3025 SMLAxy{cond} Rd,Rm,Rs,Rn
3026 SMLAWy{cond} Rd,Rm,Rs,Rn
3027 Error if any register is R15. */
3028
3029static void
a737bd4d 3030do_smla (char * str)
b99bd4ef
NC
3031{
3032 int rd, rm, rs, rn;
3033
3034 skip_whitespace (str);
3035
3036 if ((rd = reg_required_here (& str, 16)) == FAIL
3037 || skip_past_comma (& str) == FAIL
3038 || (rm = reg_required_here (& str, 0)) == FAIL
3039 || skip_past_comma (& str) == FAIL
3040 || (rs = reg_required_here (& str, 8)) == FAIL
3041 || skip_past_comma (& str) == FAIL
3042 || (rn = reg_required_here (& str, 12)) == FAIL)
3043 inst.error = BAD_ARGS;
3044
3045 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC)
3046 inst.error = BAD_PC;
3047
b99bd4ef
NC
3048 else
3049 end_of_line (str);
3050}
3051
3052/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
3053 SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
3054 Error if any register is R15.
3055 Warning if Rdlo == Rdhi. */
3056
3057static void
a737bd4d 3058do_smlal (char * str)
b99bd4ef
NC
3059{
3060 int rdlo, rdhi, rm, rs;
3061
3062 skip_whitespace (str);
3063
3064 if ((rdlo = reg_required_here (& str, 12)) == FAIL
3065 || skip_past_comma (& str) == FAIL
3066 || (rdhi = reg_required_here (& str, 16)) == FAIL
3067 || skip_past_comma (& str) == FAIL
3068 || (rm = reg_required_here (& str, 0)) == FAIL
3069 || skip_past_comma (& str) == FAIL
3070 || (rs = reg_required_here (& str, 8)) == FAIL)
3071 {
3072 inst.error = BAD_ARGS;
3073 return;
3074 }
3075
3076 if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
3077 {
3078 inst.error = BAD_PC;
3079 return;
3080 }
3081
3082 if (rdlo == rdhi)
3083 as_tsktsk (_("rdhi and rdlo must be different"));
3084
f2b7cb0a 3085 end_of_line (str);
b99bd4ef
NC
3086}
3087
3088/* ARM V5E (El Segundo) signed-multiply (argument parse)
3089 SMULxy{cond} Rd,Rm,Rs
3090 Error if any register is R15. */
3091
3092static void
a737bd4d 3093do_smul (char * str)
b99bd4ef
NC
3094{
3095 int rd, rm, rs;
3096
3097 skip_whitespace (str);
3098
3099 if ((rd = reg_required_here (& str, 16)) == FAIL
3100 || skip_past_comma (& str) == FAIL
3101 || (rm = reg_required_here (& str, 0)) == FAIL
3102 || skip_past_comma (& str) == FAIL
3103 || (rs = reg_required_here (& str, 8)) == FAIL)
3104 inst.error = BAD_ARGS;
3105
3106 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC)
3107 inst.error = BAD_PC;
3108
b99bd4ef
NC
3109 else
3110 end_of_line (str);
3111}
3112
3113/* ARM V5E (El Segundo) saturating-add/subtract (argument parse)
3114 Q[D]{ADD,SUB}{cond} Rd,Rm,Rn
3115 Error if any register is R15. */
3116
3117static void
a737bd4d 3118do_qadd (char * str)
b99bd4ef
NC
3119{
3120 int rd, rm, rn;
3121
3122 skip_whitespace (str);
3123
3124 if ((rd = reg_required_here (& str, 12)) == FAIL
3125 || skip_past_comma (& str) == FAIL
3126 || (rm = reg_required_here (& str, 0)) == FAIL
3127 || skip_past_comma (& str) == FAIL
3128 || (rn = reg_required_here (& str, 16)) == FAIL)
3129 inst.error = BAD_ARGS;
3130
3131 else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
3132 inst.error = BAD_PC;
3133
b99bd4ef
NC
3134 else
3135 end_of_line (str);
3136}
3137
3138/* ARM V5E (el Segundo)
3139 MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
3140 MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
3141
3142 These are equivalent to the XScale instructions MAR and MRA,
3143 respectively, when coproc == 0, opcode == 0, and CRm == 0.
3144
3145 Result unpredicatable if Rd or Rn is R15. */
3146
3147static void
a737bd4d 3148do_co_reg2c (char * str)
b99bd4ef
NC
3149{
3150 int rd, rn;
3151
3152 skip_whitespace (str);
3153
3154 if (co_proc_number (& str) == FAIL)
3155 {
3156 if (!inst.error)
3157 inst.error = BAD_ARGS;
3158 return;
3159 }
3160
3161 if (skip_past_comma (& str) == FAIL
3162 || cp_opc_expr (& str, 4, 4) == FAIL)
3163 {
3164 if (!inst.error)
3165 inst.error = BAD_ARGS;
3166 return;
3167 }
3168
3169 if (skip_past_comma (& str) == FAIL
3170 || (rd = reg_required_here (& str, 12)) == FAIL)
3171 {
3172 if (!inst.error)
3173 inst.error = BAD_ARGS;
3174 return;
3175 }
3176
3177 if (skip_past_comma (& str) == FAIL
3178 || (rn = reg_required_here (& str, 16)) == FAIL)
3179 {
3180 if (!inst.error)
3181 inst.error = BAD_ARGS;
3182 return;
3183 }
3184
09d92015
MM
3185 /* Unpredictable result if rd or rn is R15. */
3186 if (rd == REG_PC || rn == REG_PC)
3187 as_tsktsk
3188 (_("Warning: instruction unpredictable when using r15"));
3189
3190 if (skip_past_comma (& str) == FAIL
3191 || cp_reg_required_here (& str, 0) == FAIL)
3192 {
3193 if (!inst.error)
3194 inst.error = BAD_ARGS;
3195 return;
3196 }
3197
3198 end_of_line (str);
3199}
3200
3201/* ARM V5 count-leading-zeroes instruction (argument parse)
3202 CLZ{<cond>} <Rd>, <Rm>
3203 Condition defaults to COND_ALWAYS.
3204 Error if Rd or Rm are R15. */
3205
3206static void
a737bd4d 3207do_clz (char * str)
09d92015
MM
3208{
3209 int rd, rm;
3210
3211 skip_whitespace (str);
3212
3213 if (((rd = reg_required_here (& str, 12)) == FAIL)
3214 || (skip_past_comma (& str) == FAIL)
3215 || ((rm = reg_required_here (& str, 0)) == FAIL))
3216 inst.error = BAD_ARGS;
3217
3218 else if (rd == REG_PC || rm == REG_PC )
3219 inst.error = BAD_PC;
3220
3221 else
3222 end_of_line (str);
3223}
3224
3225/* ARM V5 (argument parse)
3226 LDC2{L} <coproc>, <CRd>, <addressing mode>
3227 STC2{L} <coproc>, <CRd>, <addressing mode>
3228 Instruction is not conditional, and has 0xf in the condition field.
3229 Otherwise, it's the same as LDC/STC. */
3230
3231static void
a737bd4d 3232do_lstc2 (char * str)
09d92015
MM
3233{
3234 skip_whitespace (str);
3235
3236 if (co_proc_number (& str) == FAIL)
3237 {
3238 if (!inst.error)
3239 inst.error = BAD_ARGS;
3240 }
3241 else if (skip_past_comma (& str) == FAIL
3242 || cp_reg_required_here (& str, 12) == FAIL)
3243 {
3244 if (!inst.error)
3245 inst.error = BAD_ARGS;
3246 }
3247 else if (skip_past_comma (& str) == FAIL
3248 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
3249 {
3250 if (! inst.error)
3251 inst.error = BAD_ARGS;
3252 }
3253 else
3254 end_of_line (str);
3255}
3256
3257/* ARM V5 (argument parse)
3258 CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
3259 Instruction is not conditional, and has 0xf in the condition field.
3260 Otherwise, it's the same as CDP. */
3261
3262static void
a737bd4d 3263do_cdp2 (char * str)
09d92015
MM
3264{
3265 skip_whitespace (str);
3266
3267 if (co_proc_number (& str) == FAIL)
3268 {
3269 if (!inst.error)
3270 inst.error = BAD_ARGS;
3271 return;
3272 }
3273
3274 if (skip_past_comma (& str) == FAIL
3275 || cp_opc_expr (& str, 20,4) == FAIL)
3276 {
3277 if (!inst.error)
3278 inst.error = BAD_ARGS;
3279 return;
3280 }
3281
3282 if (skip_past_comma (& str) == FAIL
3283 || cp_reg_required_here (& str, 12) == FAIL)
3284 {
3285 if (!inst.error)
3286 inst.error = BAD_ARGS;
3287 return;
3288 }
3289
3290 if (skip_past_comma (& str) == FAIL
3291 || cp_reg_required_here (& str, 16) == FAIL)
3292 {
3293 if (!inst.error)
3294 inst.error = BAD_ARGS;
3295 return;
3296 }
3297
3298 if (skip_past_comma (& str) == FAIL
3299 || cp_reg_required_here (& str, 0) == FAIL)
3300 {
3301 if (!inst.error)
3302 inst.error = BAD_ARGS;
3303 return;
3304 }
3305
3306 if (skip_past_comma (& str) == SUCCESS)
3307 {
3308 if (cp_opc_expr (& str, 5, 3) == FAIL)
3309 {
3310 if (!inst.error)
3311 inst.error = BAD_ARGS;
3312 return;
3313 }
3314 }
3315
3316 end_of_line (str);
3317}
3318
3319/* ARM V5 (argument parse)
3320 MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
3321 MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
3322 Instruction is not conditional, and has 0xf in the condition field.
3323 Otherwise, it's the same as MCR/MRC. */
3324
3325static void
a737bd4d 3326do_co_reg2 (char * str)
09d92015
MM
3327{
3328 skip_whitespace (str);
3329
3330 if (co_proc_number (& str) == FAIL)
3331 {
3332 if (!inst.error)
3333 inst.error = BAD_ARGS;
3334 return;
3335 }
3336
3337 if (skip_past_comma (& str) == FAIL
3338 || cp_opc_expr (& str, 21, 3) == FAIL)
3339 {
3340 if (!inst.error)
3341 inst.error = BAD_ARGS;
3342 return;
3343 }
3344
3345 if (skip_past_comma (& str) == FAIL
3346 || reg_required_here (& str, 12) == FAIL)
3347 {
3348 if (!inst.error)
3349 inst.error = BAD_ARGS;
3350 return;
3351 }
3352
3353 if (skip_past_comma (& str) == FAIL
3354 || cp_reg_required_here (& str, 16) == FAIL)
3355 {
3356 if (!inst.error)
3357 inst.error = BAD_ARGS;
3358 return;
3359 }
3360
3361 if (skip_past_comma (& str) == FAIL
3362 || cp_reg_required_here (& str, 0) == FAIL)
3363 {
3364 if (!inst.error)
3365 inst.error = BAD_ARGS;
3366 return;
3367 }
3368
3369 if (skip_past_comma (& str) == SUCCESS)
3370 {
3371 if (cp_opc_expr (& str, 5, 3) == FAIL)
3372 {
3373 if (!inst.error)
3374 inst.error = BAD_ARGS;
3375 return;
3376 }
3377 }
3378
3379 end_of_line (str);
3380}
3381
a737bd4d
NC
3382static void
3383do_bx (char * str)
3384{
3385 int reg;
3386
3387 skip_whitespace (str);
3388
3389 if ((reg = reg_required_here (&str, 0)) == FAIL)
3390 {
3391 inst.error = BAD_ARGS;
3392 return;
3393 }
3394
3395 /* Note - it is not illegal to do a "bx pc". Useless, but not illegal. */
3396 if (reg == REG_PC)
3397 as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
3398
3399 end_of_line (str);
3400}
3401
09d92015 3402/* ARM v5TEJ. Jump to Jazelle code. */
a737bd4d 3403
09d92015 3404static void
a737bd4d 3405do_bxj (char * str)
09d92015
MM
3406{
3407 int reg;
3408
3409 skip_whitespace (str);
3410
3411 if ((reg = reg_required_here (&str, 0)) == FAIL)
3412 {
3413 inst.error = BAD_ARGS;
3414 return;
3415 }
3416
a737bd4d
NC
3417 /* Note - it is not illegal to do a "bxj pc". Useless, but not illegal. */
3418 if (reg == REG_PC)
3419 as_tsktsk (_("use of r15 in bxj is not really useful"));
3420
3421 end_of_line (str);
3422}
3423
3424/* ARM V6 umaal (argument parse). */
3425
3426static void
3427do_umaal (char * str)
3428{
3429 int rdlo, rdhi, rm, rs;
3430
3431 skip_whitespace (str);
3432 if ((rdlo = reg_required_here (& str, 12)) == FAIL
3433 || skip_past_comma (& str) == FAIL
3434 || (rdhi = reg_required_here (& str, 16)) == FAIL
3435 || skip_past_comma (& str) == FAIL
3436 || (rm = reg_required_here (& str, 0)) == FAIL
3437 || skip_past_comma (& str) == FAIL
3438 || (rs = reg_required_here (& str, 8)) == FAIL)
3439 {
3440 inst.error = BAD_ARGS;
3441 return;
3442 }
3443
3444 if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
3445 {
3446 inst.error = BAD_PC;
3447 return;
3448 }
3449
3450 end_of_line (str);
3451}
3452
3453/* ARM V6 strex (argument parse). */
3454
3455static void
3456do_strex (char * str)
3457{
3458 int rd, rm, rn;
3459
3460 /* Parse Rd, Rm,. */
3461 skip_whitespace (str);
3462 if ((rd = reg_required_here (& str, 12)) == FAIL
3463 || skip_past_comma (& str) == FAIL
3464 || (rm = reg_required_here (& str, 0)) == FAIL
3465 || skip_past_comma (& str) == FAIL)
3466 {
3467 inst.error = BAD_ARGS;
3468 return;
3469 }
3470 if (rd == REG_PC || rm == REG_PC)
3471 {
3472 inst.error = BAD_PC;
3473 return;
3474 }
3475 if (rd == rm)
3476 {
3477 inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
3478 return;
3479 }
3480
3481 /* Skip past '['. */
3482 if ((strlen (str) >= 1)
3483 && strncmp (str, "[", 1) == 0)
3484 str += 1;
3485
3486 skip_whitespace (str);
3487
3488 /* Parse Rn. */
3489 if ((rn = reg_required_here (& str, 16)) == FAIL)
3490 {
3491 inst.error = BAD_ARGS;
3492 return;
3493 }
3494 else if (rn == REG_PC)
3495 {
3496 inst.error = BAD_PC;
3497 return;
3498 }
3499 if (rd == rn)
3500 {
3501 inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
3502 return;
3503 }
3504 skip_whitespace (str);
3505
3506 /* Skip past ']'. */
3507 if ((strlen (str) >= 1)
3508 && strncmp (str, "]", 1) == 0)
3509 str += 1;
3510
3511 end_of_line (str);
3512}
3513
3514/* KIND indicates what kind of shifts are accepted. */
3515
3516static int
3517decode_shift (char ** str, int kind)
3518{
3519 const struct asm_shift_name * shift;
3520 char * p;
3521 char c;
3522
3523 skip_whitespace (* str);
3524
3525 for (p = * str; ISALPHA (* p); p ++)
3526 ;
3527
3528 if (p == * str)
3529 {
3530 inst.error = _("shift expression expected");
3531 return FAIL;
3532 }
3533
3534 c = * p;
3535 * p = '\0';
3536 shift = (const struct asm_shift_name *) hash_find (arm_shift_hsh, * str);
3537 * p = c;
3538
3539 if (shift == NULL)
3540 {
3541 inst.error = _("shift expression expected");
3542 return FAIL;
3543 }
3544
3545 assert (shift->properties->index == shift_properties[shift->properties->index].index);
3546
3547 if (kind == SHIFT_LSL_OR_ASR_IMMEDIATE
3548 && shift->properties->index != SHIFT_LSL
3549 && shift->properties->index != SHIFT_ASR)
3550 {
3551 inst.error = _("'LSL' or 'ASR' required");
3552 return FAIL;
3553 }
3554 else if (kind == SHIFT_LSL_IMMEDIATE
3555 && shift->properties->index != SHIFT_LSL)
3556 {
3557 inst.error = _("'LSL' required");
3558 return FAIL;
3559 }
3560 else if (kind == SHIFT_ASR_IMMEDIATE
3561 && shift->properties->index != SHIFT_ASR)
3562 {
3563 inst.error = _("'ASR' required");
3564 return FAIL;
3565 }
3566
3567 if (shift->properties->index == SHIFT_RRX)
3568 {
3569 * str = p;
3570 inst.instruction |= shift->properties->bit_field;
3571 return SUCCESS;
3572 }
3573
3574 skip_whitespace (p);
3575
3576 if (kind == NO_SHIFT_RESTRICT && reg_required_here (& p, 8) != FAIL)
3577 {
3578 inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG;
3579 * str = p;
3580 return SUCCESS;
3581 }
3582 else if (! is_immediate_prefix (* p))
3583 {
3584 inst.error = (NO_SHIFT_RESTRICT
3585 ? _("shift requires register or #expression")
3586 : _("shift requires #expression"));
3587 * str = p;
3588 return FAIL;
3589 }
3590
3591 inst.error = NULL;
3592 p ++;
3593
3594 if (my_get_expression (& inst.reloc.exp, & p))
3595 return FAIL;
3596
3597 /* Validate some simple #expressions. */
3598 if (inst.reloc.exp.X_op == O_constant)
3599 {
3600 unsigned num = inst.reloc.exp.X_add_number;
3601
3602 /* Reject operations greater than 32. */
3603 if (num > 32
3604 /* Reject a shift of 0 unless the mode allows it. */
3605 || (num == 0 && shift->properties->allows_0 == 0)
3606 /* Reject a shift of 32 unless the mode allows it. */
3607 || (num == 32 && shift->properties->allows_32 == 0)
3608 )
3609 {
3610 /* As a special case we allow a shift of zero for
3611 modes that do not support it to be recoded as an
3612 logical shift left of zero (ie nothing). We warn
3613 about this though. */
3614 if (num == 0)
3615 {
3616 as_warn (_("shift of 0 ignored."));
3617 shift = & shift_names[0];
3618 assert (shift->properties->index == SHIFT_LSL);
3619 }
3620 else
3621 {
3622 inst.error = _("invalid immediate shift");
3623 return FAIL;
3624 }
3625 }
3626
3627 /* Shifts of 32 are encoded as 0, for those shifts that
3628 support it. */
3629 if (num == 32)
3630 num = 0;
3631
3632 inst.instruction |= (num << 7) | shift->properties->bit_field;
3633 }
3634 else
3635 {
3636 inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
3637 inst.reloc.pc_rel = 0;
3638 inst.instruction |= shift->properties->bit_field;
3639 }
3640
3641 * str = p;
3642 return SUCCESS;
09d92015
MM
3643}
3644
09d92015 3645static void
a737bd4d 3646do_sat (char ** str, int bias)
09d92015 3647{
a737bd4d
NC
3648 int rd, rm;
3649 expressionS expr;
09d92015 3650
a737bd4d 3651 skip_whitespace (*str);
09d92015 3652
a737bd4d
NC
3653 /* Parse <Rd>, field. */
3654 if ((rd = reg_required_here (str, 12)) == FAIL
3655 || skip_past_comma (str) == FAIL)
09d92015
MM
3656 {
3657 inst.error = BAD_ARGS;
a737bd4d 3658 return;
09d92015 3659 }
a737bd4d 3660 if (rd == REG_PC)
09d92015
MM
3661 {
3662 inst.error = BAD_PC;
3663 return;
3664 }
3665
a737bd4d
NC
3666 /* Parse #<immed>, field. */
3667 if (is_immediate_prefix (**str))
3668 (*str)++;
3669 else
09d92015 3670 {
a737bd4d 3671 inst.error = _("immediate expression expected");
09d92015
MM
3672 return;
3673 }
a737bd4d 3674 if (my_get_expression (&expr, str))
09d92015 3675 {
a737bd4d 3676 inst.error = _("bad expression");
09d92015
MM
3677 return;
3678 }
a737bd4d 3679 if (expr.X_op != O_constant)
09d92015 3680 {
a737bd4d 3681 inst.error = _("constant expression expected");
09d92015
MM
3682 return;
3683 }
a737bd4d
NC
3684 if (expr.X_add_number + bias < 0
3685 || expr.X_add_number + bias > 31)
3686 {
3687 inst.error = _("immediate value out of range");
3688 return;
3689 }
3690 inst.instruction |= (expr.X_add_number + bias) << 16;
3691 if (skip_past_comma (str) == FAIL)
09d92015
MM
3692 {
3693 inst.error = BAD_ARGS;
3694 return;
3695 }
a737bd4d
NC
3696
3697 /* Parse <Rm> field. */
3698 if ((rm = reg_required_here (str, 0)) == FAIL)
09d92015 3699 {
a737bd4d 3700 inst.error = BAD_ARGS;
09d92015
MM
3701 return;
3702 }
a737bd4d 3703 if (rm == REG_PC)
09d92015 3704 {
a737bd4d 3705 inst.error = BAD_PC;
09d92015
MM
3706 return;
3707 }
09d92015 3708
a737bd4d
NC
3709 if (skip_past_comma (str) == SUCCESS)
3710 decode_shift (str, SHIFT_LSL_OR_ASR_IMMEDIATE);
09d92015
MM
3711}
3712
a737bd4d 3713/* ARM V6 ssat (argument parse). */
09d92015
MM
3714
3715static void
a737bd4d 3716do_ssat (char * str)
09d92015
MM
3717{
3718 do_sat (&str, /*bias=*/-1);
3719 end_of_line (str);
3720}
3721
a737bd4d 3722/* ARM V6 usat (argument parse). */
09d92015
MM
3723
3724static void
a737bd4d 3725do_usat (char * str)
09d92015
MM
3726{
3727 do_sat (&str, /*bias=*/0);
3728 end_of_line (str);
3729}
3730
3731static void
a737bd4d 3732do_sat16 (char ** str, int bias)
09d92015
MM
3733{
3734 int rd, rm;
3735 expressionS expr;
3736
3737 skip_whitespace (*str);
a737bd4d
NC
3738
3739 /* Parse the <Rd> field. */
09d92015
MM
3740 if ((rd = reg_required_here (str, 12)) == FAIL
3741 || skip_past_comma (str) == FAIL)
3742 {
3743 inst.error = BAD_ARGS;
3744 return;
3745 }
3746 if (rd == REG_PC)
3747 {
3748 inst.error = BAD_PC;
3749 return;
3750 }
3751
a737bd4d 3752 /* Parse #<immed>, field. */
09d92015
MM
3753 if (is_immediate_prefix (**str))
3754 (*str)++;
3755 else
3756 {
3757 inst.error = _("immediate expression expected");
3758 return;
3759 }
3760 if (my_get_expression (&expr, str))
3761 {
3762 inst.error = _("bad expression");
3763 return;
3764 }
3765 if (expr.X_op != O_constant)
3766 {
3767 inst.error = _("constant expression expected");
3768 return;
3769 }
3770 if (expr.X_add_number + bias < 0
a737bd4d 3771 || expr.X_add_number + bias > 15)
09d92015
MM
3772 {
3773 inst.error = _("immediate value out of range");
3774 return;
3775 }
3776 inst.instruction |= (expr.X_add_number + bias) << 16;
3777 if (skip_past_comma (str) == FAIL)
3778 {
3779 inst.error = BAD_ARGS;
3780 return;
3781 }
3782
a737bd4d 3783 /* Parse <Rm> field. */
09d92015
MM
3784 if ((rm = reg_required_here (str, 0)) == FAIL)
3785 {
3786 inst.error = BAD_ARGS;
3787 return;
3788 }
3789 if (rm == REG_PC)
3790 {
3791 inst.error = BAD_PC;
3792 return;
3793 }
09d92015
MM
3794}
3795
a737bd4d 3796/* ARM V6 ssat16 (argument parse). */
09d92015
MM
3797
3798static void
a737bd4d 3799do_ssat16 (char * str)
09d92015
MM
3800{
3801 do_sat16 (&str, /*bias=*/-1);
3802 end_of_line (str);
3803}
3804
3805static void
a737bd4d 3806do_usat16 (char * str)
09d92015
MM
3807{
3808 do_sat16 (&str, /*bias=*/0);
3809 end_of_line (str);
3810}
3811
3812static void
a737bd4d 3813do_cps_mode (char ** str)
09d92015 3814{
09d92015
MM
3815 expressionS expr;
3816
3817 skip_whitespace (*str);
3818
a737bd4d 3819 if (! is_immediate_prefix (**str))
09d92015
MM
3820 {
3821 inst.error = _("immediate expression expected");
3822 return;
3823 }
a737bd4d
NC
3824
3825 (*str)++; /* Strip off the immediate signifier. */
09d92015
MM
3826 if (my_get_expression (&expr, str))
3827 {
3828 inst.error = _("bad expression");
3829 return;
3830 }
a737bd4d 3831
09d92015
MM
3832 if (expr.X_op != O_constant)
3833 {
3834 inst.error = _("constant expression expected");
3835 return;
3836 }
09d92015 3837
a737bd4d
NC
3838 /* The mode is a 5 bit field. Valid values are 0-31. */
3839 if (((unsigned) expr.X_add_number) > 31
3840 || (inst.reloc.exp.X_add_number) < 0)
09d92015 3841 {
a737bd4d 3842 inst.error = _("invalid constant");
09d92015
MM
3843 return;
3844 }
a737bd4d
NC
3845
3846 inst.instruction |= expr.X_add_number;
09d92015
MM
3847}
3848
a737bd4d 3849/* ARM V6 srs (argument parse). */
09d92015
MM
3850
3851static void
a737bd4d 3852do_srs (char * str)
09d92015
MM
3853{
3854 char *exclam;
3855 skip_whitespace (str);
3856 exclam = strchr (str, '!');
3857 if (exclam)
3858 *exclam = '\0';
3859 do_cps_mode (&str);
3860 if (exclam)
3861 *exclam = '!';
a737bd4d 3862 if (*str == '!')
09d92015
MM
3863 {
3864 inst.instruction |= WRITE_BACK;
3865 str++;
3866 }
3867 end_of_line (str);
3868}
3869
a737bd4d 3870/* ARM V6 SMMUL (argument parse). */
09d92015
MM
3871
3872static void
a737bd4d 3873do_smmul (char * str)
09d92015
MM
3874{
3875 int rd, rm, rs;
a737bd4d 3876
09d92015
MM
3877 skip_whitespace (str);
3878 if ((rd = reg_required_here (&str, 16)) == FAIL
3879 || skip_past_comma (&str) == FAIL
3880 || (rm = reg_required_here (&str, 0)) == FAIL
3881 || skip_past_comma (&str) == FAIL
3882 || (rs = reg_required_here (&str, 8)) == FAIL)
3883 {
3884 inst.error = BAD_ARGS;
3885 return;
3886 }
3887
a737bd4d 3888 if ( rd == REG_PC
09d92015
MM
3889 || rm == REG_PC
3890 || rs == REG_PC)
3891 {
3892 inst.error = BAD_PC;
3893 return;
3894 }
3895
3896 end_of_line (str);
09d92015
MM
3897}
3898
a737bd4d 3899/* ARM V6 SMLALD (argument parse). */
09d92015
MM
3900
3901static void
a737bd4d 3902do_smlald (char * str)
09d92015
MM
3903{
3904 int rdlo, rdhi, rm, rs;
a737bd4d 3905
09d92015
MM
3906 skip_whitespace (str);
3907 if ((rdlo = reg_required_here (&str, 12)) == FAIL
3908 || skip_past_comma (&str) == FAIL
3909 || (rdhi = reg_required_here (&str, 16)) == FAIL
3910 || skip_past_comma (&str) == FAIL
3911 || (rm = reg_required_here (&str, 0)) == FAIL
3912 || skip_past_comma (&str) == FAIL
3913 || (rs = reg_required_here (&str, 8)) == FAIL)
3914 {
3915 inst.error = BAD_ARGS;
3916 return;
3917 }
3918
a737bd4d
NC
3919 if ( rdlo == REG_PC
3920 || rdhi == REG_PC
09d92015
MM
3921 || rm == REG_PC
3922 || rs == REG_PC)
3923 {
3924 inst.error = BAD_PC;
3925 return;
3926 }
3927
3928 end_of_line (str);
3929}
3930
a737bd4d 3931/* ARM V6 SMLAD (argument parse). Signed multiply accumulate dual.
09d92015
MM
3932 smlad{x}{<cond>} Rd, Rm, Rs, Rn */
3933
a737bd4d
NC
3934static void
3935do_smlad (char * str)
09d92015
MM
3936{
3937 int rd, rm, rs, rn;
a737bd4d 3938
09d92015
MM
3939 skip_whitespace (str);
3940 if ((rd = reg_required_here (&str, 16)) == FAIL
3941 || skip_past_comma (&str) == FAIL
3942 || (rm = reg_required_here (&str, 0)) == FAIL
3943 || skip_past_comma (&str) == FAIL
3944 || (rs = reg_required_here (&str, 8)) == FAIL
3945 || skip_past_comma (&str) == FAIL
3946 || (rn = reg_required_here (&str, 12)) == FAIL)
3947 {
3948 inst.error = BAD_ARGS;
3949 return;
3950 }
a737bd4d
NC
3951
3952 if ( rd == REG_PC
3953 || rn == REG_PC
09d92015
MM
3954 || rs == REG_PC
3955 || rm == REG_PC)
3956 {
3957 inst.error = BAD_PC;
3958 return;
3959 }
3960
3961 end_of_line (str);
09d92015
MM
3962}
3963
3964/* Returns true if the endian-specifier indicates big-endianness. */
3965
3966static int
a737bd4d 3967do_endian_specifier (char * str)
09d92015
MM
3968{
3969 int big_endian = 0;
3970
3971 skip_whitespace (str);
3972 if (strlen (str) < 2)
3973 inst.error = _("missing endian specifier");
3974 else if (strncasecmp (str, "BE", 2) == 0)
3975 {
3976 str += 2;
3977 big_endian = 1;
3978 }
3979 else if (strncasecmp (str, "LE", 2) == 0)
3980 str += 2;
3981 else
3982 inst.error = _("valid endian specifiers are be or le");
3983
3984 end_of_line (str);
3985
3986 return big_endian;
3987}
3988
a737bd4d
NC
3989/* ARM V6 SETEND (argument parse). Sets the E bit in the CPSR while
3990 preserving the other bits.
3991
3992 setend <endian_specifier>, where <endian_specifier> is either
3993 BE or LE. */
3994
3995static void
3996do_setend (char * str)
3997{
3998 if (do_endian_specifier (str))
3999 inst.instruction |= 0x200;
4000}
4001
09d92015
MM
4002/* ARM V6 SXTH.
4003
4004 SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
4005 Condition defaults to COND_ALWAYS.
a737bd4d 4006 Error if any register uses R15. */
09d92015 4007
a737bd4d
NC
4008static void
4009do_sxth (char * str)
09d92015
MM
4010{
4011 int rd, rm;
4012 expressionS expr;
4013 int rotation_clear_mask = 0xfffff3ff;
4014 int rotation_eight_mask = 0x00000400;
4015 int rotation_sixteen_mask = 0x00000800;
4016 int rotation_twenty_four_mask = 0x00000c00;
a737bd4d 4017
09d92015
MM
4018 skip_whitespace (str);
4019 if ((rd = reg_required_here (&str, 12)) == FAIL
4020 || skip_past_comma (&str) == FAIL
4021 || (rm = reg_required_here (&str, 0)) == FAIL)
4022 {
4023 inst.error = BAD_ARGS;
4024 return;
4025 }
4026
4027 else if (rd == REG_PC || rm == REG_PC)
4028 {
4029 inst.error = BAD_PC;
4030 return;
4031 }
a737bd4d
NC
4032
4033 /* Zero out the rotation field. */
09d92015 4034 inst.instruction &= rotation_clear_mask;
a737bd4d
NC
4035
4036 /* Check for lack of optional rotation field. */
09d92015
MM
4037 if (skip_past_comma (&str) == FAIL)
4038 {
4039 end_of_line (str);
4040 return;
4041 }
a737bd4d
NC
4042
4043 /* Move past 'ROR'. */
09d92015
MM
4044 skip_whitespace (str);
4045 if (strncasecmp (str, "ROR", 3) == 0)
a737bd4d 4046 str += 3;
09d92015
MM
4047 else
4048 {
4049 inst.error = _("missing rotation field after comma");
4050 return;
4051 }
a737bd4d
NC
4052
4053 /* Get the immediate constant. */
09d92015
MM
4054 skip_whitespace (str);
4055 if (is_immediate_prefix (* str))
4056 str++;
4057 else
4058 {
4059 inst.error = _("immediate expression expected");
4060 return;
4061 }
a737bd4d 4062
09d92015
MM
4063 if (my_get_expression (&expr, &str))
4064 {
4065 inst.error = _("bad expression");
4066 return;
4067 }
4068
4069 if (expr.X_op != O_constant)
4070 {
4071 inst.error = _("constant expression expected");
4072 return;
4073 }
a737bd4d
NC
4074
4075 switch (expr.X_add_number)
09d92015
MM
4076 {
4077 case 0:
a737bd4d 4078 /* Rotation field has already been zeroed. */
09d92015
MM
4079 break;
4080 case 8:
4081 inst.instruction |= rotation_eight_mask;
4082 break;
4083
4084 case 16:
4085 inst.instruction |= rotation_sixteen_mask;
4086 break;
a737bd4d 4087
09d92015
MM
4088 case 24:
4089 inst.instruction |= rotation_twenty_four_mask;
4090 break;
4091
4092 default:
4093 inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited");
4094 break;
4095 }
4096
4097 end_of_line (str);
09d92015
MM
4098}
4099
4100/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
4101 extends it to 32-bits, and adds the result to a value in another
4102 register. You can specify a rotation by 0, 8, 16, or 24 bits
4103 before extracting the 16-bit value.
4104 SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
4105 Condition defaults to COND_ALWAYS.
a737bd4d 4106 Error if any register uses R15. */
09d92015 4107
a737bd4d
NC
4108static void
4109do_sxtah (char * str)
09d92015
MM
4110{
4111 int rd, rn, rm;
4112 expressionS expr;
4113 int rotation_clear_mask = 0xfffff3ff;
4114 int rotation_eight_mask = 0x00000400;
4115 int rotation_sixteen_mask = 0x00000800;
4116 int rotation_twenty_four_mask = 0x00000c00;
a737bd4d 4117
09d92015
MM
4118 skip_whitespace (str);
4119 if ((rd = reg_required_here (&str, 12)) == FAIL
4120 || skip_past_comma (&str) == FAIL
4121 || (rn = reg_required_here (&str, 16)) == FAIL
4122 || skip_past_comma (&str) == FAIL
4123 || (rm = reg_required_here (&str, 0)) == FAIL)
4124 {
4125 inst.error = BAD_ARGS;
4126 return;
4127 }
4128
4129 else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
4130 {
4131 inst.error = BAD_PC;
4132 return;
4133 }
a737bd4d
NC
4134
4135 /* Zero out the rotation field. */
09d92015 4136 inst.instruction &= rotation_clear_mask;
a737bd4d
NC
4137
4138 /* Check for lack of optional rotation field. */
09d92015
MM
4139 if (skip_past_comma (&str) == FAIL)
4140 {
4141 end_of_line (str);
4142 return;
4143 }
a737bd4d
NC
4144
4145 /* Move past 'ROR'. */
09d92015
MM
4146 skip_whitespace (str);
4147 if (strncasecmp (str, "ROR", 3) == 0)
a737bd4d 4148 str += 3;
09d92015
MM
4149 else
4150 {
4151 inst.error = _("missing rotation field after comma");
4152 return;
4153 }
a737bd4d
NC
4154
4155 /* Get the immediate constant. */
09d92015
MM
4156 skip_whitespace (str);
4157 if (is_immediate_prefix (* str))
4158 str++;
4159 else
4160 {
4161 inst.error = _("immediate expression expected");
4162 return;
4163 }
a737bd4d 4164
09d92015
MM
4165 if (my_get_expression (&expr, &str))
4166 {
4167 inst.error = _("bad expression");
4168 return;
4169 }
4170
4171 if (expr.X_op != O_constant)
4172 {
4173 inst.error = _("constant expression expected");
4174 return;
4175 }
a737bd4d
NC
4176
4177 switch (expr.X_add_number)
09d92015
MM
4178 {
4179 case 0:
a737bd4d 4180 /* Rotation field has already been zeroed. */
09d92015
MM
4181 break;
4182
4183 case 8:
4184 inst.instruction |= rotation_eight_mask;
4185 break;
4186
4187 case 16:
4188 inst.instruction |= rotation_sixteen_mask;
4189 break;
a737bd4d 4190
09d92015
MM
4191 case 24:
4192 inst.instruction |= rotation_twenty_four_mask;
4193 break;
4194
4195 default:
4196 inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited");
4197 break;
4198 }
4199
4200 end_of_line (str);
09d92015 4201}
a737bd4d 4202
09d92015
MM
4203
4204/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
4205 word at the specified address and the following word
a737bd4d 4206 respectively.
09d92015 4207 Unconditionally executed.
a737bd4d 4208 Error if Rn is R15. */
09d92015
MM
4209
4210static void
a737bd4d 4211do_rfe (char * str)
09d92015
MM
4212{
4213 int rn;
4214
4215 skip_whitespace (str);
a737bd4d 4216
09d92015
MM
4217 if ((rn = reg_required_here (&str, 16)) == FAIL)
4218 return;
b99bd4ef 4219
09d92015 4220 if (rn == REG_PC)
b99bd4ef 4221 {
09d92015 4222 inst.error = BAD_PC;
b99bd4ef
NC
4223 return;
4224 }
4225
09d92015 4226 skip_whitespace (str);
a737bd4d 4227
09d92015
MM
4228 if (*str == '!')
4229 {
4230 inst.instruction |= WRITE_BACK;
4231 str++;
4232 }
b99bd4ef
NC
4233 end_of_line (str);
4234}
4235
09d92015
MM
4236/* ARM V6 REV (Byte Reverse Word) reverses the byte order in a 32-bit
4237 register (argument parse).
4238 REV{<cond>} Rd, Rm.
4239 Condition defaults to COND_ALWAYS.
a737bd4d 4240 Error if Rd or Rm are R15. */
b99bd4ef
NC
4241
4242static void
a737bd4d 4243do_rev (char * str)
b99bd4ef
NC
4244{
4245 int rd, rm;
4246
b99bd4ef
NC
4247 skip_whitespace (str);
4248
09d92015
MM
4249 if ((rd = reg_required_here (&str, 12)) == FAIL
4250 || skip_past_comma (&str) == FAIL
4251 || (rm = reg_required_here (&str, 0)) == FAIL)
b99bd4ef
NC
4252 inst.error = BAD_ARGS;
4253
09d92015 4254 else if (rd == REG_PC || rm == REG_PC)
b99bd4ef
NC
4255 inst.error = BAD_PC;
4256
4257 else
4258 end_of_line (str);
4259}
4260
09d92015 4261/* ARM V6 Perform Two Sixteen Bit Integer Additions. (argument parse).
a737bd4d 4262 QADD16{<cond>} <Rd>, <Rn>, <Rm>
09d92015
MM
4263 Condition defaults to COND_ALWAYS.
4264 Error if Rd, Rn or Rm are R15. */
b99bd4ef
NC
4265
4266static void
a737bd4d 4267do_qadd16 (char * str)
b99bd4ef 4268{
09d92015
MM
4269 int rd, rm, rn;
4270
b99bd4ef
NC
4271 skip_whitespace (str);
4272
09d92015
MM
4273 if ((rd = reg_required_here (&str, 12)) == FAIL
4274 || skip_past_comma (&str) == FAIL
4275 || (rn = reg_required_here (&str, 16)) == FAIL
4276 || skip_past_comma (&str) == FAIL
4277 || (rm = reg_required_here (&str, 0)) == FAIL)
4278 inst.error = BAD_ARGS;
4279
4280 else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
4281 inst.error = BAD_PC;
4282
b99bd4ef
NC
4283 else
4284 end_of_line (str);
4285}
4286
b99bd4ef 4287static void
a737bd4d 4288do_pkh_core (char * str, int shift)
b99bd4ef 4289{
09d92015 4290 int rd, rn, rm;
b99bd4ef 4291
09d92015
MM
4292 skip_whitespace (str);
4293 if (((rd = reg_required_here (&str, 12)) == FAIL)
4294 || (skip_past_comma (&str) == FAIL)
4295 || ((rn = reg_required_here (&str, 16)) == FAIL)
4296 || (skip_past_comma (&str) == FAIL)
4297 || ((rm = reg_required_here (&str, 0)) == FAIL))
b99bd4ef 4298 {
09d92015 4299 inst.error = BAD_ARGS;
b99bd4ef
NC
4300 return;
4301 }
4302
09d92015 4303 else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
b99bd4ef 4304 {
09d92015 4305 inst.error = BAD_PC;
b99bd4ef
NC
4306 return;
4307 }
4308
a737bd4d
NC
4309 /* Check for optional shift immediate constant. */
4310 if (skip_past_comma (&str) == FAIL)
b99bd4ef 4311 {
09d92015
MM
4312 if (shift == SHIFT_ASR_IMMEDIATE)
4313 {
4314 /* If the shift specifier is ommited, turn the instruction
4315 into pkhbt rd, rm, rn. First, switch the instruction
4316 code, and clear the rn and rm fields. */
4317 inst.instruction &= 0xfff0f010;
4318 /* Now, re-encode the registers. */
4319 inst.instruction |= (rm << 16) | rn;
4320 }
b99bd4ef
NC
4321 return;
4322 }
4323
09d92015
MM
4324 decode_shift (&str, shift);
4325}
4326
a737bd4d
NC
4327/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
4328 PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
4329 Condition defaults to COND_ALWAYS.
4330 Error if Rd, Rn or Rm are R15. */
4331
4332static void
4333do_pkhbt (char * str)
4334{
4335 do_pkh_core (str, SHIFT_LSL_IMMEDIATE);
4336}
4337
4338/* ARM V6 PKHTB (Argument Parse). */
4339
4340static void
4341do_pkhtb (char * str)
4342{
4343 do_pkh_core (str, SHIFT_ASR_IMMEDIATE);
4344}
4345
09d92015 4346/* ARM V6 Load Register Exclusive instruction (argument parse).
0dd132b6 4347 LDREX{,B,D,H}{<cond>} <Rd, [<Rn>]
09d92015 4348 Condition defaults to COND_ALWAYS.
a737bd4d
NC
4349 Error if Rd or Rn are R15.
4350 See ARMARMv6 A4.1.27: LDREX. */
09d92015
MM
4351
4352static void
a737bd4d 4353do_ldrex (char * str)
09d92015
MM
4354{
4355 int rd, rn;
4356
4357 skip_whitespace (str);
4358
a737bd4d 4359 /* Parse Rd. */
09d92015
MM
4360 if (((rd = reg_required_here (&str, 12)) == FAIL)
4361 || (skip_past_comma (&str) == FAIL))
b99bd4ef 4362 {
09d92015 4363 inst.error = BAD_ARGS;
b99bd4ef
NC
4364 return;
4365 }
09d92015 4366 else if (rd == REG_PC)
b99bd4ef 4367 {
09d92015 4368 inst.error = BAD_PC;
b99bd4ef
NC
4369 return;
4370 }
a737bd4d 4371 skip_whitespace (str);
b99bd4ef 4372
a737bd4d
NC
4373 /* Skip past '['. */
4374 if ((strlen (str) >= 1)
09d92015 4375 &&strncmp (str, "[", 1) == 0)
a737bd4d
NC
4376 str += 1;
4377 skip_whitespace (str);
09d92015 4378
a737bd4d 4379 /* Parse Rn. */
09d92015 4380 if ((rn = reg_required_here (&str, 16)) == FAIL)
b99bd4ef 4381 {
09d92015
MM
4382 inst.error = BAD_ARGS;
4383 return;
b99bd4ef 4384 }
09d92015
MM
4385 else if (rn == REG_PC)
4386 {
4387 inst.error = BAD_PC;
4388 return;
4389 }
a737bd4d 4390 skip_whitespace (str);
b99bd4ef 4391
a737bd4d
NC
4392 /* Skip past ']'. */
4393 if ((strlen (str) >= 1)
09d92015 4394 && strncmp (str, "]", 1) == 0)
a737bd4d
NC
4395 str += 1;
4396
b99bd4ef
NC
4397 end_of_line (str);
4398}
4399
09d92015 4400/* ARM V6 change processor state instruction (argument parse)
a737bd4d 4401 CPS, CPSIE, CSPID . */
b99bd4ef
NC
4402
4403static void
a737bd4d 4404do_cps (char * str)
b99bd4ef 4405{
09d92015
MM
4406 do_cps_mode (&str);
4407 end_of_line (str);
4408}
b99bd4ef 4409
09d92015 4410static void
a737bd4d 4411do_cps_flags (char ** str, int thumb_p)
ea6ef066 4412{
a737bd4d
NC
4413 struct cps_flag
4414 {
09d92015
MM
4415 char character;
4416 unsigned long arm_value;
4417 unsigned long thumb_value;
4418 };
a737bd4d
NC
4419 static struct cps_flag flag_table[] =
4420 {
09d92015
MM
4421 {'a', 0x100, 0x4 },
4422 {'i', 0x080, 0x2 },
4423 {'f', 0x040, 0x1 }
4424 };
ea6ef066 4425
09d92015 4426 int saw_a_flag = 0;
ea6ef066 4427
09d92015
MM
4428 skip_whitespace (*str);
4429
a737bd4d 4430 /* Get the a, f and i flags. */
09d92015 4431 while (**str && **str != ',')
ea6ef066 4432 {
09d92015
MM
4433 struct cps_flag *p;
4434 struct cps_flag *q = flag_table + sizeof (flag_table)/sizeof (*p);
a737bd4d 4435
09d92015
MM
4436 for (p = flag_table; p < q; ++p)
4437 if (strncasecmp (*str, &p->character, 1) == 0)
4438 {
4439 inst.instruction |= (thumb_p ? p->thumb_value : p->arm_value);
4440 saw_a_flag = 1;
4441 break;
4442 }
4443 if (p == q)
4444 {
4445 inst.error = _("unrecognized flag");
4446 return;
4447 }
4448 (*str)++;
ea6ef066 4449 }
a737bd4d
NC
4450
4451 if (!saw_a_flag)
4452 inst.error = _("no 'a', 'i', or 'f' flags for 'cps'");
4453}
4454
4455static void
4456do_cpsi (char * str)
4457{
4458 do_cps_flags (&str, /*thumb_p=*/0);
4459
4460 if (skip_past_comma (&str) == SUCCESS)
4461 {
4462 skip_whitespace (str);
4463 do_cps_mode (&str);
4464 }
4465 end_of_line (str);
ea6ef066
RE
4466}
4467
b05fe5cf
ZW
4468/* ARM V6T2 bitfield manipulation instructions. */
4469
4470static int
4471five_bit_unsigned_immediate (char **str)
4472{
4473 expressionS expr;
4474
4475 skip_whitespace (*str);
4476 if (!is_immediate_prefix (**str))
4477 {
4478 inst.error = _("immediate expression expected");
4479 return -1;
4480 }
4481 (*str)++;
4482 if (my_get_expression (&expr, str))
4483 {
4484 inst.error = _("bad expression");
4485 return -1;
4486 }
4487 if (expr.X_op != O_constant)
4488 {
4489 inst.error = _("constant expression expected");
4490 return -1;
4491 }
4492 if (expr.X_add_number < 0 || expr.X_add_number > 32)
4493 {
4494 inst.error = _("immediate value out of range");
4495 return -1;
4496 }
4497
4498 return expr.X_add_number;
4499}
4500
4501static void
4502bfci_lsb_and_width (char *str)
4503{
4504 int lsb, width;
4505
4506 if ((lsb = five_bit_unsigned_immediate (&str)) == -1)
4507 return;
4508
4509 if (skip_past_comma (&str) == FAIL)
4510 {
4511 inst.error = BAD_ARGS;
4512 return;
4513 }
4514 if ((width = five_bit_unsigned_immediate (&str)) == -1)
4515 return;
4516
4517 end_of_line (str);
4518
4519 if (width == 0 || lsb == 32)
4520 {
4521 inst.error = _("immediate value out of range");
4522 return;
4523 }
4524 else if (width + lsb > 32)
4525 {
4526 inst.error = _("bit-field extends past end of register");
4527 return;
4528 }
4529
4530 /* Convert to LSB/MSB and write to register. */
4531 inst.instruction |= lsb << 7;
4532 inst.instruction |= (width + lsb - 1) << 16;
4533}
4534
4535static void
4536do_bfc (char *str)
4537{
4538 int rd;
4539
4540 /* Rd. */
4541 skip_whitespace (str);
4542 if (((rd = reg_required_here (&str, 12)) == FAIL)
4543 || (skip_past_comma (&str) == FAIL))
4544 {
4545 inst.error = BAD_ARGS;
4546 return;
4547 }
4548 else if (rd == REG_PC)
4549 {
4550 inst.error = BAD_PC;
4551 return;
4552 }
4553
4554 bfci_lsb_and_width (str);
4555}
4556
4557static void
4558do_bfi (char *str)
4559{
4560 int rd, rm;
4561
4562 /* Rd. */
4563 skip_whitespace (str);
4564 if (((rd = reg_required_here (&str, 12)) == FAIL)
4565 || (skip_past_comma (&str) == FAIL))
4566 {
4567 inst.error = BAD_ARGS;
4568 return;
4569 }
4570 else if (rd == REG_PC)
4571 {
4572 inst.error = BAD_PC;
4573 return;
4574 }
4575
4576 /* Rm. Accept #0 in this position as an alternative syntax for bfc. */
4577 skip_whitespace (str);
4578 if (is_immediate_prefix (*str))
4579 {
4580 expressionS expr;
4581 str++;
4582 if (my_get_expression (&expr, &str))
4583 {
4584 inst.error = _("bad expression");
4585 return;
4586 }
4587 if (expr.X_op != O_constant)
4588 {
4589 inst.error = _("constant expression expected");
4590 return;
4591 }
4592 if (expr.X_add_number != 0)
4593 {
4594 inst.error = _("immediate value out of range");
4595 return;
4596 }
4597 inst.instruction |= 0x0000000f; /* Rm = PC -> bfc, not bfi. */
4598 }
4599 else
4600 {
4601 if ((rm = reg_required_here (&str, 0)) == FAIL)
4602 {
4603 inst.error = BAD_ARGS;
4604 return;
4605 }
4606 else if (rm == REG_PC)
4607 {
4608 inst.error = BAD_PC;
4609 return;
4610 }
4611 }
4612 if (skip_past_comma (&str) == FAIL)
4613 {
4614 inst.error = BAD_ARGS;
4615 return;
4616 }
4617
4618 bfci_lsb_and_width (str);
4619}
4620
4621static void
4622do_bfx (char *str)
4623{
4624 int lsb, width;
4625
4626 /* Rd. */
4627 skip_whitespace (str);
4628 if (reg_required_here (&str, 12) == FAIL
4629 || skip_past_comma (&str) == FAIL)
4630 {
4631 inst.error = BAD_ARGS;
4632 return;
4633 }
4634
4635 /* Rm. */
4636 skip_whitespace (str);
4637 if (reg_required_here (&str, 0) == FAIL
4638 || skip_past_comma (&str) == FAIL)
4639 {
4640 inst.error = BAD_ARGS;
4641 return;
4642 }
4643
4644 if ((lsb = five_bit_unsigned_immediate (&str)) == -1)
4645 return;
4646
4647 if (skip_past_comma (&str) == FAIL)
4648 {
4649 inst.error = BAD_ARGS;
4650 return;
4651 }
4652 if ((width = five_bit_unsigned_immediate (&str)) == -1)
4653 return;
4654
4655 end_of_line (str);
4656
4657 if (width == 0 || lsb == 32)
4658 {
4659 inst.error = _("immediate value out of range");
4660 return;
4661 }
4662 else if (width + lsb > 32)
4663 {
4664 inst.error = _("bit-field extends past end of register");
4665 return;
4666 }
4667
4668 inst.instruction |= lsb << 7;
4669 inst.instruction |= (width - 1) << 16;
4670}
4671
4672static void
4673do_rbit (char *str)
4674{
4675 /* Rd. */
4676 skip_whitespace (str);
4677 if (reg_required_here (&str, 12) == FAIL
4678 || skip_past_comma (&str) == FAIL)
4679 {
4680 inst.error = BAD_ARGS;
4681 return;
4682 }
4683
4684 /* Rm. */
4685 skip_whitespace (str);
4686 if (reg_required_here (&str, 0) == FAIL)
4687 {
4688 inst.error = BAD_ARGS;
4689 return;
4690 }
4691
4692 end_of_line (str);
4693}
4694
4695/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>. */
4696static void
4697do_mov16 (char *str)
4698{
4699 int rd;
4700 expressionS expr;
4701
4702 /* Rd. */
4703 skip_whitespace (str);
4704 if (((rd = reg_required_here (&str, 12)) == FAIL)
4705 || (skip_past_comma (&str) == FAIL))
4706 {
4707 inst.error = BAD_ARGS;
4708 return;
4709 }
4710 else if (rd == REG_PC)
4711 {
4712 inst.error = BAD_PC;
4713 return;
4714 }
4715
4716 /* Imm16. */
4717 skip_whitespace (str);
4718 if (!is_immediate_prefix (*str))
4719 {
4720 inst.error = _("immediate expression expected");
4721 return;
4722 }
4723 str++;
4724 if (my_get_expression (&expr, &str))
4725 {
4726 inst.error = _("bad expression");
4727 return;
4728 }
4729 if (expr.X_op != O_constant)
4730 {
4731 inst.error = _("constant expression expected");
4732 return;
4733 }
4734 if (expr.X_add_number < 0 || expr.X_add_number > 65535)
4735 {
4736 inst.error = _("immediate value out of range");
4737 return;
4738 }
4739
4740 end_of_line (str);
4741
4742 /* The value is in two pieces: 0:11, 16:19. */
4743 inst.instruction |= (expr.X_add_number & 0x00000fff);
4744 inst.instruction |= (expr.X_add_number & 0x0000f000) << 4;
4745}
4746
4747
b99bd4ef
NC
4748/* THUMB V5 breakpoint instruction (argument parse)
4749 BKPT <immed_8>. */
4750
4751static void
a737bd4d 4752do_t_bkpt (char * str)
b99bd4ef
NC
4753{
4754 expressionS expr;
4755 unsigned long number;
4756
4757 skip_whitespace (str);
4758
4759 /* Allow optional leading '#'. */
4760 if (is_immediate_prefix (*str))
4761 str ++;
4762
4763 memset (& expr, '\0', sizeof (expr));
143c8e19
NC
4764 if (my_get_expression (& expr, & str)
4765 || (expr.X_op != O_constant
4766 /* As a convenience we allow 'bkpt' without an operand. */
4767 && expr.X_op != O_absent))
b99bd4ef 4768 {
143c8e19 4769 inst.error = _("bad expression");
b99bd4ef
NC
4770 return;
4771 }
4772
4773 number = expr.X_add_number;
4774
4775 /* Check it fits an 8 bit unsigned. */
4776 if (number != (number & 0xff))
4777 {
4778 inst.error = _("immediate value out of range");
4779 return;
4780 }
4781
4782 inst.instruction |= number;
4783
4784 end_of_line (str);
4785}
4786
f17c130b 4787#ifdef OBJ_ELF
a737bd4d
NC
4788static bfd_reloc_code_real_type
4789arm_parse_reloc (void)
4790{
4791 char id [16];
4792 char * ip;
4793 unsigned int i;
4794 static struct
4795 {
4796 char * str;
4797 int len;
4798 bfd_reloc_code_real_type reloc;
4799 }
4800 reloc_map[] =
4801 {
4802#define MAP(str,reloc) { str, sizeof (str) - 1, reloc }
4803 MAP ("(got)", BFD_RELOC_ARM_GOT32),
4804 MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
4805 /* ScottB: Jan 30, 1998 - Added support for parsing "var(PLT)"
4806 branch instructions generated by GCC for PLT relocs. */
4807 MAP ("(plt)", BFD_RELOC_ARM_PLT32),
4808 MAP ("(target1)", BFD_RELOC_ARM_TARGET1),
4809 MAP ("(sbrel)", BFD_RELOC_ARM_SBREL32),
4810 MAP ("(target2)", BFD_RELOC_ARM_TARGET2),
ba93b8ac
DJ
4811 MAP ("(tlsgd)", BFD_RELOC_ARM_TLS_GD32),
4812 MAP ("(tlsldm)", BFD_RELOC_ARM_TLS_LDM32),
4813 MAP ("(tlsldo)", BFD_RELOC_ARM_TLS_LDO32),
4814 MAP ("(gottpoff)", BFD_RELOC_ARM_TLS_IE32),
4815 MAP ("(tpoff)", BFD_RELOC_ARM_TLS_LE32),
a737bd4d
NC
4816 { NULL, 0, BFD_RELOC_UNUSED }
4817#undef MAP
4818 };
4819
4820 for (i = 0, ip = input_line_pointer;
4821 i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip));
4822 i++, ip++)
4823 id[i] = TOLOWER (*ip);
4824
4825 for (i = 0; reloc_map[i].str; i++)
4826 if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
4827 break;
4828
4829 input_line_pointer += reloc_map[i].len;
4830
4831 return reloc_map[i].reloc;
4832}
f17c130b 4833#endif
a737bd4d 4834
b99bd4ef
NC
4835/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
4836 Expects inst.instruction is set for BLX(1).
4837 Note: this is cloned from do_branch, and the reloc changed to be a
4838 new one that can cope with setting one extra bit (the H bit). */
4839
4840static void
a737bd4d 4841do_branch25 (char * str)
b99bd4ef
NC
4842{
4843 if (my_get_expression (& inst.reloc.exp, & str))
4844 return;
4845
4846#ifdef OBJ_ELF
4847 {
4848 char * save_in;
4849
4850 /* ScottB: February 5, 1998 */
4851 /* Check to see of PLT32 reloc required for the instruction. */
4852
4853 /* arm_parse_reloc() works on input_line_pointer.
4854 We actually want to parse the operands to the branch instruction
4855 passed in 'str'. Save the input pointer and restore it later. */
4856 save_in = input_line_pointer;
4857 input_line_pointer = str;
4858
4859 if (inst.reloc.exp.X_op == O_symbol
4860 && *str == '('
4861 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
4862 {
4863 inst.reloc.type = BFD_RELOC_ARM_PLT32;
4864 inst.reloc.pc_rel = 0;
4865 /* Modify str to point to after parsed operands, otherwise
4866 end_of_line() will complain about the (PLT) left in str. */
4867 str = input_line_pointer;
4868 }
4869 else
4870 {
4871 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4872 inst.reloc.pc_rel = 1;
4873 }
4874
4875 input_line_pointer = save_in;
4876 }
4877#else
4878 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4879 inst.reloc.pc_rel = 1;
4880#endif /* OBJ_ELF */
4881
4882 end_of_line (str);
4883}
4884
4885/* ARM V5 branch-link-exchange instruction (argument parse)
4886 BLX <target_addr> ie BLX(1)
4887 BLX{<condition>} <Rm> ie BLX(2)
4888 Unfortunately, there are two different opcodes for this mnemonic.
4889 So, the insns[].value is not used, and the code here zaps values
4890 into inst.instruction.
4891 Also, the <target_addr> can be 25 bits, hence has its own reloc. */
4892
4893static void
a737bd4d 4894do_blx (char * str)
b99bd4ef
NC
4895{
4896 char * mystr = str;
4897 int rm;
4898
b99bd4ef
NC
4899 skip_whitespace (mystr);
4900 rm = reg_required_here (& mystr, 0);
4901
4902 /* The above may set inst.error. Ignore his opinion. */
4903 inst.error = 0;
4904
4905 if (rm != FAIL)
4906 {
4907 /* Arg is a register.
4908 Use the condition code our caller put in inst.instruction.
4909 Pass ourselves off as a BX with a funny opcode. */
4910 inst.instruction |= 0x012fff30;
f2b7cb0a 4911 do_bx (str);
b99bd4ef
NC
4912 }
4913 else
4914 {
4915 /* This must be is BLX <target address>, no condition allowed. */
4916 if (inst.instruction != COND_ALWAYS)
cc8a6dd0
KH
4917 {
4918 inst.error = BAD_COND;
b99bd4ef 4919 return;
cc8a6dd0 4920 }
b99bd4ef
NC
4921
4922 inst.instruction = 0xfafffffe;
4923
4924 /* Process like a B/BL, but with a different reloc.
4925 Note that B/BL expecte fffffe, not 0, offset in the opcode table. */
f2b7cb0a 4926 do_branch25 (str);
b99bd4ef
NC
4927 }
4928}
4929
4930/* ARM V5 Thumb BLX (argument parse)
4931 BLX <target_addr> which is BLX(1)
4932 BLX <Rm> which is BLX(2)
4933 Unfortunately, there are two different opcodes for this mnemonic.
4934 So, the tinsns[].value is not used, and the code here zaps values
4935 into inst.instruction. */
4936
4937static void
a737bd4d 4938do_t_blx (char * str)
b99bd4ef
NC
4939{
4940 char * mystr = str;
4941 int rm;
4942
4943 skip_whitespace (mystr);
4944 inst.instruction = 0x4780;
4945
4946 /* Note that this call is to the ARM register recognizer. BLX(2)
4947 uses the ARM register space, not the Thumb one, so a call to
4948 thumb_reg() would be wrong. */
4949 rm = reg_required_here (& mystr, 3);
4950 inst.error = 0;
4951
4952 if (rm != FAIL)
4953 {
4954 /* It's BLX(2). The .instruction was zapped with rm & is final. */
4955 inst.size = 2;
4956 }
4957 else
4958 {
4959 /* No ARM register. This must be BLX(1). Change the .instruction. */
4960 inst.instruction = 0xf7ffeffe;
4961 inst.size = 4;
4962
4963 if (my_get_expression (& inst.reloc.exp, & mystr))
4964 return;
4965
4966 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
4967 inst.reloc.pc_rel = 1;
4968 }
4969
4970 end_of_line (mystr);
4971}
4972
4973/* ARM V5 breakpoint instruction (argument parse)
4974 BKPT <16 bit unsigned immediate>
4975 Instruction is not conditional.
4976 The bit pattern given in insns[] has the COND_ALWAYS condition,
cc8a6dd0 4977 and it is an error if the caller tried to override that. */
b99bd4ef
NC
4978
4979static void
a737bd4d 4980do_bkpt (char * str)
b99bd4ef
NC
4981{
4982 expressionS expr;
4983 unsigned long number;
4984
4985 skip_whitespace (str);
4986
4987 /* Allow optional leading '#'. */
4988 if (is_immediate_prefix (* str))
4989 str++;
4990
4991 memset (& expr, '\0', sizeof (expr));
4992
143c8e19
NC
4993 if (my_get_expression (& expr, & str)
4994 || (expr.X_op != O_constant
4995 /* As a convenience we allow 'bkpt' without an operand. */
4996 && expr.X_op != O_absent))
b99bd4ef 4997 {
143c8e19 4998 inst.error = _("bad expression");
b99bd4ef
NC
4999 return;
5000 }
5001
5002 number = expr.X_add_number;
5003
5004 /* Check it fits a 16 bit unsigned. */
5005 if (number != (number & 0xffff))
5006 {
5007 inst.error = _("immediate value out of range");
5008 return;
5009 }
5010
5011 /* Top 12 of 16 bits to bits 19:8. */
5012 inst.instruction |= (number & 0xfff0) << 4;
5013
5014 /* Bottom 4 of 16 bits to bits 3:0. */
5015 inst.instruction |= number & 0xf;
5016
5017 end_of_line (str);
b99bd4ef
NC
5018}
5019
09d92015
MM
5020/* THUMB CPS instruction (argument parse). */
5021
5022static void
a737bd4d 5023do_t_cps (char * str)
09d92015
MM
5024{
5025 do_cps_flags (&str, /*thumb_p=*/1);
5026 end_of_line (str);
5027}
5028
a737bd4d
NC
5029/* Parse and validate that a register is of the right form, this saves
5030 repeated checking of this information in many similar cases.
5031 Unlike the 32-bit case we do not insert the register into the opcode
5032 here, since the position is often unknown until the full instruction
5033 has been parsed. */
5034
5035static int
5036thumb_reg (char ** strp, int hi_lo)
5037{
5038 int reg;
5039
5040 if ((reg = reg_required_here (strp, -1)) == FAIL)
5041 return FAIL;
5042
5043 switch (hi_lo)
5044 {
5045 case THUMB_REG_LO:
5046 if (reg > 7)
5047 {
5048 inst.error = _("lo register required");
5049 return FAIL;
5050 }
5051 break;
5052
5053 case THUMB_REG_HI:
5054 if (reg < 8)
5055 {
5056 inst.error = _("hi register required");
5057 return FAIL;
5058 }
5059 break;
5060
5061 default:
5062 break;
5063 }
5064
5065 return reg;
5066}
5067
5068static void
5069thumb_mov_compare (char * str, int move)
5070{
5071 int Rd, Rs = FAIL;
5072
5073 skip_whitespace (str);
5074
5075 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
5076 || skip_past_comma (&str) == FAIL)
5077 {
5078 if (! inst.error)
5079 inst.error = BAD_ARGS;
5080 return;
5081 }
5082
5083 if (move != THUMB_CPY && is_immediate_prefix (*str))
5084 {
5085 str++;
5086 if (my_get_expression (&inst.reloc.exp, &str))
5087 return;
5088 }
5089 else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
5090 return;
5091
5092 if (Rs != FAIL)
5093 {
5094 if (move != THUMB_CPY && Rs < 8 && Rd < 8)
5095 {
5096 if (move == THUMB_MOVE)
5097 /* A move of two lowregs is encoded as ADD Rd, Rs, #0
5098 since a MOV instruction produces unpredictable results. */
5099 inst.instruction = T_OPCODE_ADD_I3;
5100 else
5101 inst.instruction = T_OPCODE_CMP_LR;
5102 inst.instruction |= Rd | (Rs << 3);
5103 }
5104 else
5105 {
5106 if (move == THUMB_MOVE)
5107 inst.instruction = T_OPCODE_MOV_HR;
5108 else if (move != THUMB_CPY)
5109 inst.instruction = T_OPCODE_CMP_HR;
5110
5111 if (Rd > 7)
5112 inst.instruction |= THUMB_H1;
5113
5114 if (Rs > 7)
5115 inst.instruction |= THUMB_H2;
5116
5117 inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
5118 }
5119 }
5120 else
5121 {
5122 if (Rd > 7)
5123 {
5124 inst.error = _("only lo regs allowed with immediate");
5125 return;
5126 }
5127
5128 if (move == THUMB_MOVE)
5129 inst.instruction = T_OPCODE_MOV_I8;
5130 else
5131 inst.instruction = T_OPCODE_CMP_I8;
5132
5133 inst.instruction |= Rd << 8;
5134
5135 if (inst.reloc.exp.X_op != O_constant)
5136 inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
5137 else
5138 {
5139 unsigned value = inst.reloc.exp.X_add_number;
5140
5141 if (value > 255)
5142 {
5143 inst.error = _("invalid immediate");
5144 return;
5145 }
5146
5147 inst.instruction |= value;
5148 }
5149 }
5150
5151 end_of_line (str);
5152}
5153
09d92015
MM
5154/* THUMB CPY instruction (argument parse). */
5155
5156static void
a737bd4d 5157do_t_cpy (char * str)
09d92015
MM
5158{
5159 thumb_mov_compare (str, THUMB_CPY);
5160}
5161
5162/* THUMB SETEND instruction (argument parse). */
5163
5164static void
a737bd4d 5165do_t_setend (char * str)
09d92015
MM
5166{
5167 if (do_endian_specifier (str))
5168 inst.instruction |= 0x8;
5169}
5170
e16bb312
NC
5171/* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate. */
5172
5173static unsigned long
a737bd4d
NC
5174check_iwmmxt_insn (char * str,
5175 enum iwmmxt_insn_type insn_type,
5176 int immediate_size)
e16bb312
NC
5177{
5178 int reg = 0;
5179 const char * inst_error;
5180 expressionS expr;
5181 unsigned long number;
5182
5183 inst_error = inst.error;
5184 if (!inst.error)
5185 inst.error = BAD_ARGS;
5186 skip_whitespace (str);
5187
5188 switch (insn_type)
5189 {
5190 case check_rd:
5191 if ((reg = reg_required_here (&str, 12)) == FAIL)
5192 return FAIL;
5193 break;
a737bd4d 5194
e16bb312
NC
5195 case check_wr:
5196 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR)) == FAIL)
5197 return FAIL;
5198 break;
a737bd4d 5199
e16bb312
NC
5200 case check_wrwr:
5201 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5202 || skip_past_comma (&str) == FAIL
5203 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
5204 return FAIL;
5205 break;
a737bd4d 5206
e16bb312
NC
5207 case check_wrwrwr:
5208 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5209 || skip_past_comma (&str) == FAIL
5210 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5211 || skip_past_comma (&str) == FAIL
5212 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
5213 return FAIL;
5214 break;
a737bd4d 5215
e16bb312
NC
5216 case check_wrwrwcg:
5217 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5218 || skip_past_comma (&str) == FAIL
5219 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5220 || skip_past_comma (&str) == FAIL
5221 || wreg_required_here (&str, 0, IWMMXT_REG_WCG) == FAIL))
5222 return FAIL;
5223 break;
a737bd4d 5224
e16bb312
NC
5225 case check_tbcst:
5226 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5227 || skip_past_comma (&str) == FAIL
5228 || reg_required_here (&str, 12) == FAIL))
5229 return FAIL;
5230 break;
a737bd4d 5231
e16bb312
NC
5232 case check_tmovmsk:
5233 if ((reg_required_here (&str, 12) == FAIL
5234 || skip_past_comma (&str) == FAIL
5235 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
5236 return FAIL;
5237 break;
a737bd4d 5238
e16bb312
NC
5239 case check_tmia:
5240 if ((wreg_required_here (&str, 5, IWMMXT_REG_WR) == FAIL
5241 || skip_past_comma (&str) == FAIL
5242 || reg_required_here (&str, 0) == FAIL
5243 || skip_past_comma (&str) == FAIL
5244 || reg_required_here (&str, 12) == FAIL))
5245 return FAIL;
5246 break;
a737bd4d 5247
e16bb312
NC
5248 case check_tmcrr:
5249 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
5250 || skip_past_comma (&str) == FAIL
5251 || reg_required_here (&str, 12) == FAIL
5252 || skip_past_comma (&str) == FAIL
5253 || reg_required_here (&str, 16) == FAIL))
5254 return FAIL;
5255 break;
a737bd4d 5256
e16bb312
NC
5257 case check_tmrrc:
5258 if ((reg_required_here (&str, 12) == FAIL
5259 || skip_past_comma (&str) == FAIL
5260 || reg_required_here (&str, 16) == FAIL
5261 || skip_past_comma (&str) == FAIL
5262 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
5263 return FAIL;
5264 break;
a737bd4d 5265
e16bb312
NC
5266 case check_tmcr:
5267 if ((wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL
5268 || skip_past_comma (&str) == FAIL
5269 || reg_required_here (&str, 12) == FAIL))
5270 return FAIL;
5271 break;
a737bd4d 5272
e16bb312
NC
5273 case check_tmrc:
5274 if ((reg_required_here (&str, 12) == FAIL
5275 || skip_past_comma (&str) == FAIL
5276 || wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL))
5277 return FAIL;
5278 break;
a737bd4d 5279
e16bb312
NC
5280 case check_tinsr:
5281 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5282 || skip_past_comma (&str) == FAIL
5283 || reg_required_here (&str, 12) == FAIL
5284 || skip_past_comma (&str) == FAIL))
5285 return FAIL;
5286 break;
a737bd4d 5287
e16bb312
NC
5288 case check_textrc:
5289 if ((reg_required_here (&str, 12) == FAIL
5290 || skip_past_comma (&str) == FAIL))
5291 return FAIL;
5292 break;
a737bd4d 5293
e16bb312
NC
5294 case check_waligni:
5295 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5296 || skip_past_comma (&str) == FAIL
5297 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5298 || skip_past_comma (&str) == FAIL
5299 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
5300 || skip_past_comma (&str) == FAIL))
5301 return FAIL;
5302 break;
a737bd4d 5303
e16bb312
NC
5304 case check_textrm:
5305 if ((reg_required_here (&str, 12) == FAIL
5306 || skip_past_comma (&str) == FAIL
5307 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5308 || skip_past_comma (&str) == FAIL))
5309 return FAIL;
5310 break;
a737bd4d 5311
e16bb312
NC
5312 case check_wshufh:
5313 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5314 || skip_past_comma (&str) == FAIL
5315 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5316 || skip_past_comma (&str) == FAIL))
5317 return FAIL;
5318 break;
5319 }
a737bd4d 5320
e16bb312
NC
5321 if (immediate_size == 0)
5322 {
5323 end_of_line (str);
5324 inst.error = inst_error;
5325 return reg;
5326 }
5327 else
5328 {
a737bd4d
NC
5329 skip_whitespace (str);
5330
5331 /* Allow optional leading '#'. */
e16bb312
NC
5332 if (is_immediate_prefix (* str))
5333 str++;
5334
5335 memset (& expr, '\0', sizeof (expr));
a737bd4d 5336
e16bb312
NC
5337 if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
5338 {
5339 inst.error = _("bad or missing expression");
5340 return FAIL;
5341 }
a737bd4d 5342
e16bb312 5343 number = expr.X_add_number;
a737bd4d 5344
e16bb312
NC
5345 if (number != (number & immediate_size))
5346 {
5347 inst.error = _("immediate value out of range");
5348 return FAIL;
5349 }
5350 end_of_line (str);
5351 inst.error = inst_error;
5352 return number;
5353 }
5354}
5355
5356static void
a737bd4d 5357do_iwmmxt_byte_addr (char * str)
e16bb312
NC
5358{
5359 int op = (inst.instruction & 0x300) >> 8;
5360 int reg;
5361
5362 inst.instruction &= ~0x300;
a737bd4d 5363 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
e16bb312
NC
5364
5365 skip_whitespace (str);
5366
5367 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
5368 || skip_past_comma (& str) == FAIL
5369 || cp_byte_address_required_here (&str) == FAIL)
5370 {
5371 if (! inst.error)
5372 inst.error = BAD_ARGS;
5373 }
5374 else
5375 end_of_line (str);
5376
5377 if (wc_register (reg))
5378 {
ece01a63 5379 as_bad (_("non-word size not supported with control register"));
e16bb312
NC
5380 inst.instruction |= 0xf0000100;
5381 inst.instruction &= ~0x00400000;
5382 }
5383}
5384
5385static void
a737bd4d 5386do_iwmmxt_tandc (char * str)
e16bb312
NC
5387{
5388 int reg;
5389
5390 reg = check_iwmmxt_insn (str, check_rd, 0);
5391
5392 if (reg != REG_PC && !inst.error)
5393 inst.error = _("only r15 allowed here");
e16bb312
NC
5394}
5395
5396static void
a737bd4d 5397do_iwmmxt_tbcst (char * str)
e16bb312
NC
5398{
5399 check_iwmmxt_insn (str, check_tbcst, 0);
e16bb312
NC
5400}
5401
5402static void
a737bd4d 5403do_iwmmxt_textrc (char * str)
e16bb312
NC
5404{
5405 unsigned long number;
5406
5407 if ((number = check_iwmmxt_insn (str, check_textrc, 7)) == (unsigned long) FAIL)
5408 return;
5409
5410 inst.instruction |= number & 0x7;
e16bb312
NC
5411}
5412
5413static void
a737bd4d 5414do_iwmmxt_textrm (char * str)
e16bb312
NC
5415{
5416 unsigned long number;
5417
5418 if ((number = check_iwmmxt_insn (str, check_textrm, 7)) == (unsigned long) FAIL)
5419 return;
5420
5421 inst.instruction |= number & 0x7;
5422}
5423
5424static void
a737bd4d 5425do_iwmmxt_tinsr (char * str)
e16bb312
NC
5426{
5427 unsigned long number;
5428
5429 if ((number = check_iwmmxt_insn (str, check_tinsr, 7)) == (unsigned long) FAIL)
5430 return;
5431
5432 inst.instruction |= number & 0x7;
e16bb312
NC
5433}
5434
5435static void
a737bd4d 5436do_iwmmxt_tmcr (char * str)
e16bb312
NC
5437{
5438 check_iwmmxt_insn (str, check_tmcr, 0);
e16bb312
NC
5439}
5440
5441static void
a737bd4d 5442do_iwmmxt_tmcrr (char * str)
e16bb312
NC
5443{
5444 check_iwmmxt_insn (str, check_tmcrr, 0);
e16bb312
NC
5445}
5446
5447static void
a737bd4d 5448do_iwmmxt_tmia (char * str)
e16bb312
NC
5449{
5450 check_iwmmxt_insn (str, check_tmia, 0);
e16bb312
NC
5451}
5452
5453static void
a737bd4d 5454do_iwmmxt_tmovmsk (char * str)
e16bb312
NC
5455{
5456 check_iwmmxt_insn (str, check_tmovmsk, 0);
e16bb312
NC
5457}
5458
5459static void
a737bd4d 5460do_iwmmxt_tmrc (char * str)
e16bb312
NC
5461{
5462 check_iwmmxt_insn (str, check_tmrc, 0);
e16bb312
NC
5463}
5464
5465static void
a737bd4d 5466do_iwmmxt_tmrrc (char * str)
e16bb312
NC
5467{
5468 check_iwmmxt_insn (str, check_tmrrc, 0);
e16bb312
NC
5469}
5470
5471static void
a737bd4d 5472do_iwmmxt_torc (char * str)
e16bb312
NC
5473{
5474 check_iwmmxt_insn (str, check_rd, 0);
e16bb312
NC
5475}
5476
5477static void
a737bd4d 5478do_iwmmxt_waligni (char * str)
e16bb312
NC
5479{
5480 unsigned long number;
5481
5482 if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL)
5483 return;
5484
5485 inst.instruction |= ((number & 0x7) << 20);
e16bb312
NC
5486}
5487
5488static void
a737bd4d 5489do_iwmmxt_wmov (char * str)
e16bb312
NC
5490{
5491 if (check_iwmmxt_insn (str, check_wrwr, 0) == (unsigned long) FAIL)
5492 return;
a737bd4d 5493
e16bb312 5494 inst.instruction |= ((inst.instruction >> 16) & 0xf);
e16bb312
NC
5495}
5496
5497static void
a737bd4d 5498do_iwmmxt_word_addr (char * str)
e16bb312
NC
5499{
5500 int op = (inst.instruction & 0x300) >> 8;
5501 int reg;
5502
5503 inst.instruction &= ~0x300;
a737bd4d 5504 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
e16bb312
NC
5505
5506 skip_whitespace (str);
5507
5508 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
5509 || skip_past_comma (& str) == FAIL
5510 || cp_address_required_here (& str, CP_WB_OK) == FAIL)
5511 {
5512 if (! inst.error)
5513 inst.error = BAD_ARGS;
5514 }
5515 else
5516 end_of_line (str);
5517
5518 if (wc_register (reg))
5519 {
ece01a63
ILT
5520 if ((inst.instruction & COND_MASK) != COND_ALWAYS)
5521 as_bad (_("conditional execution not supported with control register"));
5522 if (op != 2)
5523 as_bad (_("non-word size not supported with control register"));
e16bb312
NC
5524 inst.instruction |= 0xf0000100;
5525 inst.instruction &= ~0x00400000;
5526 }
5527}
5528
5529static void
a737bd4d 5530do_iwmmxt_wrwr (char * str)
e16bb312
NC
5531{
5532 check_iwmmxt_insn (str, check_wrwr, 0);
e16bb312
NC
5533}
5534
5535static void
a737bd4d 5536do_iwmmxt_wrwrwcg (char * str)
e16bb312
NC
5537{
5538 check_iwmmxt_insn (str, check_wrwrwcg, 0);
e16bb312
NC
5539}
5540
5541static void
a737bd4d 5542do_iwmmxt_wrwrwr (char * str)
e16bb312
NC
5543{
5544 check_iwmmxt_insn (str, check_wrwrwr, 0);
e16bb312
NC
5545}
5546
5547static void
a737bd4d 5548do_iwmmxt_wshufh (char * str)
e16bb312
NC
5549{
5550 unsigned long number;
5551
5552 if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL)
5553 return;
5554
5555 inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf);
e16bb312
NC
5556}
5557
5558static void
a737bd4d 5559do_iwmmxt_wzero (char * str)
e16bb312
NC
5560{
5561 if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL)
5562 return;
5563
5564 inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16);
e16bb312
NC
5565}
5566
b99bd4ef
NC
5567/* Xscale multiply-accumulate (argument parse)
5568 MIAcc acc0,Rm,Rs
5569 MIAPHcc acc0,Rm,Rs
5570 MIAxycc acc0,Rm,Rs. */
5571
5572static void
a737bd4d 5573do_xsc_mia (char * str)
b99bd4ef
NC
5574{
5575 int rs;
5576 int rm;
5577
f2b7cb0a 5578 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5579 inst.error = ERR_NO_ACCUM;
5580
5581 else if (skip_past_comma (& str) == FAIL
5582 || (rm = reg_required_here (& str, 0)) == FAIL)
5583 inst.error = BAD_ARGS;
5584
5585 else if (skip_past_comma (& str) == FAIL
5586 || (rs = reg_required_here (& str, 12)) == FAIL)
5587 inst.error = BAD_ARGS;
5588
5589 /* inst.instruction has now been zapped with both rm and rs. */
5590 else if (rm == REG_PC || rs == REG_PC)
5591 inst.error = BAD_PC; /* Undefined result if rm or rs is R15. */
5592
5593 else
5594 end_of_line (str);
5595}
5596
5597/* Xscale move-accumulator-register (argument parse)
5598
5599 MARcc acc0,RdLo,RdHi. */
5600
5601static void
a737bd4d 5602do_xsc_mar (char * str)
b99bd4ef
NC
5603{
5604 int rdlo, rdhi;
5605
f2b7cb0a 5606 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5607 inst.error = ERR_NO_ACCUM;
5608
5609 else if (skip_past_comma (& str) == FAIL
5610 || (rdlo = reg_required_here (& str, 12)) == FAIL)
5611 inst.error = BAD_ARGS;
5612
5613 else if (skip_past_comma (& str) == FAIL
5614 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5615 inst.error = BAD_ARGS;
5616
5617 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5618 else if (rdlo == REG_PC || rdhi == REG_PC)
5619 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5620
5621 else
5622 end_of_line (str);
5623}
5624
5625/* Xscale move-register-accumulator (argument parse)
5626
5627 MRAcc RdLo,RdHi,acc0. */
5628
5629static void
a737bd4d 5630do_xsc_mra (char * str)
b99bd4ef
NC
5631{
5632 int rdlo;
5633 int rdhi;
5634
b99bd4ef
NC
5635 skip_whitespace (str);
5636
5637 if ((rdlo = reg_required_here (& str, 12)) == FAIL)
5638 inst.error = BAD_ARGS;
5639
5640 else if (skip_past_comma (& str) == FAIL
5641 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5642 inst.error = BAD_ARGS;
5643
5644 else if (skip_past_comma (& str) == FAIL
5645 || accum0_required_here (& str) == FAIL)
5646 inst.error = ERR_NO_ACCUM;
5647
a737bd4d
NC
5648 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5649 else if (rdlo == rdhi)
5650 inst.error = BAD_ARGS; /* Undefined result if 2 writes to same reg. */
5651
5652 else if (rdlo == REG_PC || rdhi == REG_PC)
5653 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5654 else
5655 end_of_line (str);
5656}
5657
5658static int
5659ldst_extend (char ** str)
5660{
5661 int add = INDEX_UP;
5662
5663 switch (**str)
5664 {
5665 case '#':
5666 case '$':
5667 (*str)++;
5668 if (my_get_expression (& inst.reloc.exp, str))
5669 return FAIL;
5670
5671 if (inst.reloc.exp.X_op == O_constant)
5672 {
5673 int value = inst.reloc.exp.X_add_number;
5674
5675 if (value < -4095 || value > 4095)
5676 {
5677 inst.error = _("address offset too large");
5678 return FAIL;
5679 }
5680
5681 if (value < 0)
5682 {
5683 value = -value;
5684 add = 0;
5685 }
5686
5687 inst.instruction |= add | value;
5688 }
5689 else
5690 {
5691 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
5692 inst.reloc.pc_rel = 0;
5693 }
5694 return SUCCESS;
5695
5696 case '-':
5697 add = 0;
5698 /* Fall through. */
5699
5700 case '+':
5701 (*str)++;
5702 /* Fall through. */
5703
5704 default:
5705 if (reg_required_here (str, 0) == FAIL)
5706 return FAIL;
5707
5708 inst.instruction |= add | OFFSET_REG;
5709 if (skip_past_comma (str) == SUCCESS)
5710 return decode_shift (str, SHIFT_IMMEDIATE);
b99bd4ef 5711
a737bd4d
NC
5712 return SUCCESS;
5713 }
b99bd4ef
NC
5714}
5715
c9b604bd 5716/* ARMv5TE: Preload-Cache
b99bd4ef
NC
5717
5718 PLD <addr_mode>
5719
5720 Syntactically, like LDR with B=1, W=0, L=1. */
5721
5722static void
a737bd4d 5723do_pld (char * str)
b99bd4ef
NC
5724{
5725 int rd;
5726
b99bd4ef
NC
5727 skip_whitespace (str);
5728
5729 if (* str != '[')
5730 {
5731 inst.error = _("'[' expected after PLD mnemonic");
5732 return;
5733 }
5734
90e4755a 5735 ++str;
b99bd4ef
NC
5736 skip_whitespace (str);
5737
5738 if ((rd = reg_required_here (& str, 16)) == FAIL)
5739 return;
5740
5741 skip_whitespace (str);
5742
90e4755a 5743 if (*str == ']')
b99bd4ef
NC
5744 {
5745 /* [Rn], ... ? */
90e4755a 5746 ++str;
b99bd4ef
NC
5747 skip_whitespace (str);
5748
90e4755a
RE
5749 /* Post-indexed addressing is not allowed with PLD. */
5750 if (skip_past_comma (&str) == SUCCESS)
b99bd4ef 5751 {
90e4755a
RE
5752 inst.error
5753 = _("post-indexed expression used in preload instruction");
5754 return;
b99bd4ef 5755 }
90e4755a 5756 else if (*str == '!') /* [Rn]! */
b99bd4ef
NC
5757 {
5758 inst.error = _("writeback used in preload instruction");
90e4755a 5759 ++str;
b99bd4ef
NC
5760 }
5761 else /* [Rn] */
5762 inst.instruction |= INDEX_UP | PRE_INDEX;
5763 }
5764 else /* [Rn, ...] */
5765 {
5766 if (skip_past_comma (& str) == FAIL)
5767 {
5768 inst.error = _("pre-indexed expression expected");
5769 return;
5770 }
5771
90e4755a 5772 if (ldst_extend (&str) == FAIL)
b99bd4ef
NC
5773 return;
5774
5775 skip_whitespace (str);
5776
5777 if (* str != ']')
5778 {
5779 inst.error = _("missing ]");
5780 return;
5781 }
5782
5783 ++ str;
5784 skip_whitespace (str);
5785
5786 if (* str == '!') /* [Rn]! */
5787 {
5788 inst.error = _("writeback used in preload instruction");
5789 ++ str;
5790 }
5791
5792 inst.instruction |= PRE_INDEX;
5793 }
5794
5795 end_of_line (str);
5796}
5797
c9b604bd 5798/* ARMv5TE load-consecutive (argument parse)
b99bd4ef
NC
5799 Mode is like LDRH.
5800
5801 LDRccD R, mode
5802 STRccD R, mode. */
5803
5804static void
a737bd4d 5805do_ldrd (char * str)
b99bd4ef
NC
5806{
5807 int rd;
5808 int rn;
5809
b99bd4ef
NC
5810 skip_whitespace (str);
5811
5812 if ((rd = reg_required_here (& str, 12)) == FAIL)
5813 {
5814 inst.error = BAD_ARGS;
5815 return;
5816 }
5817
5818 if (skip_past_comma (& str) == FAIL
5819 || (rn = ld_mode_required_here (& str)) == FAIL)
5820 {
5821 if (!inst.error)
cc8a6dd0 5822 inst.error = BAD_ARGS;
a737bd4d 5823 return;
b99bd4ef
NC
5824 }
5825
a737bd4d
NC
5826 /* inst.instruction has now been zapped with Rd and the addressing mode. */
5827 if (rd & 1) /* Unpredictable result if Rd is odd. */
5828 {
5829 inst.error = _("destination register must be even");
5830 return;
5831 }
b99bd4ef 5832
a737bd4d 5833 if (rd == REG_LR)
b99bd4ef 5834 {
a737bd4d
NC
5835 inst.error = _("r14 not allowed here");
5836 return;
b99bd4ef 5837 }
a737bd4d
NC
5838
5839 if (((rd == rn) || (rd + 1 == rn))
5840 && ((inst.instruction & WRITE_BACK)
5841 || (!(inst.instruction & PRE_INDEX))))
5842 as_warn (_("pre/post-indexing used when modified address register is destination"));
5843
5844 /* For an index-register load, the index register must not overlap the
5845 destination (even if not write-back). */
5846 if ((inst.instruction & V4_STR_BIT) == 0
5847 && (inst.instruction & HWOFFSET_IMM) == 0)
b99bd4ef 5848 {
a737bd4d
NC
5849 int rm = inst.instruction & 0x0000000f;
5850
5851 if (rm == rd || (rm == rd + 1))
5852 as_warn (_("ldrd destination registers must not overlap index register"));
b99bd4ef
NC
5853 }
5854
a737bd4d
NC
5855 end_of_line (str);
5856}
b99bd4ef 5857
a737bd4d
NC
5858/* Returns the index into fp_values of a floating point number,
5859 or -1 if not in the table. */
b99bd4ef 5860
a737bd4d
NC
5861static int
5862my_get_float_expression (char ** str)
5863{
5864 LITTLENUM_TYPE words[MAX_LITTLENUMS];
5865 char * save_in;
5866 expressionS exp;
5867 int i;
5868 int j;
b99bd4ef 5869
a737bd4d
NC
5870 memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
5871
5872 /* Look for a raw floating point number. */
5873 if ((save_in = atof_ieee (*str, 'x', words)) != NULL
5874 && is_end_of_line[(unsigned char) *save_in])
5875 {
5876 for (i = 0; i < NUM_FLOAT_VALS; i++)
b99bd4ef 5877 {
a737bd4d 5878 for (j = 0; j < MAX_LITTLENUMS; j++)
b99bd4ef 5879 {
a737bd4d
NC
5880 if (words[j] != fp_values[i][j])
5881 break;
b99bd4ef 5882 }
a737bd4d
NC
5883
5884 if (j == MAX_LITTLENUMS)
b99bd4ef 5885 {
a737bd4d
NC
5886 *str = save_in;
5887 return i;
b99bd4ef
NC
5888 }
5889 }
a737bd4d 5890 }
b99bd4ef 5891
a737bd4d
NC
5892 /* Try and parse a more complex expression, this will probably fail
5893 unless the code uses a floating point prefix (eg "0f"). */
5894 save_in = input_line_pointer;
5895 input_line_pointer = *str;
5896 if (expression (&exp) == absolute_section
5897 && exp.X_op == O_big
5898 && exp.X_add_number < 0)
5899 {
5900 /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
5901 Ditto for 15. */
5902 if (gen_to_words (words, 5, (long) 15) == 0)
5903 {
5904 for (i = 0; i < NUM_FLOAT_VALS; i++)
5905 {
5906 for (j = 0; j < MAX_LITTLENUMS; j++)
5907 {
5908 if (words[j] != fp_values[i][j])
5909 break;
5910 }
b99bd4ef 5911
a737bd4d
NC
5912 if (j == MAX_LITTLENUMS)
5913 {
5914 *str = input_line_pointer;
5915 input_line_pointer = save_in;
5916 return i;
5917 }
5918 }
5919 }
b99bd4ef 5920 }
a737bd4d
NC
5921
5922 *str = input_line_pointer;
5923 input_line_pointer = save_in;
5924 return -1;
5925}
5926
5927/* We handle all bad expressions here, so that we can report the faulty
5928 instruction in the error message. */
5929void
5930md_operand (expressionS * expr)
5931{
5932 if (in_my_get_expression)
b99bd4ef 5933 {
a737bd4d
NC
5934 expr->X_op = O_illegal;
5935 if (inst.error == NULL)
5936 inst.error = _("bad expression");
b99bd4ef 5937 }
b99bd4ef
NC
5938}
5939
5940/* Do those data_ops which can take a negative immediate constant
2d2255b5 5941 by altering the instruction. A bit of a hack really.
b99bd4ef
NC
5942 MOV <-> MVN
5943 AND <-> BIC
5944 ADC <-> SBC
5945 by inverting the second operand, and
5946 ADD <-> SUB
5947 CMP <-> CMN
5948 by negating the second operand. */
5949
5950static int
a737bd4d
NC
5951negate_data_op (unsigned long * instruction,
5952 unsigned long value)
b99bd4ef
NC
5953{
5954 int op, new_inst;
5955 unsigned long negated, inverted;
5956
5957 negated = validate_immediate (-value);
5958 inverted = validate_immediate (~value);
5959
5960 op = (*instruction >> DATA_OP_SHIFT) & 0xf;
5961 switch (op)
5962 {
5963 /* First negates. */
5964 case OPCODE_SUB: /* ADD <-> SUB */
5965 new_inst = OPCODE_ADD;
5966 value = negated;
5967 break;
5968
5969 case OPCODE_ADD:
5970 new_inst = OPCODE_SUB;
5971 value = negated;
5972 break;
5973
5974 case OPCODE_CMP: /* CMP <-> CMN */
5975 new_inst = OPCODE_CMN;
5976 value = negated;
5977 break;
5978
5979 case OPCODE_CMN:
5980 new_inst = OPCODE_CMP;
5981 value = negated;
5982 break;
5983
5984 /* Now Inverted ops. */
5985 case OPCODE_MOV: /* MOV <-> MVN */
5986 new_inst = OPCODE_MVN;
5987 value = inverted;
5988 break;
5989
5990 case OPCODE_MVN:
5991 new_inst = OPCODE_MOV;
5992 value = inverted;
5993 break;
5994
5995 case OPCODE_AND: /* AND <-> BIC */
5996 new_inst = OPCODE_BIC;
5997 value = inverted;
5998 break;
5999
6000 case OPCODE_BIC:
6001 new_inst = OPCODE_AND;
6002 value = inverted;
6003 break;
6004
6005 case OPCODE_ADC: /* ADC <-> SBC */
6006 new_inst = OPCODE_SBC;
6007 value = inverted;
6008 break;
6009
6010 case OPCODE_SBC:
6011 new_inst = OPCODE_ADC;
6012 value = inverted;
6013 break;
6014
6015 /* We cannot do anything. */
6016 default:
6017 return FAIL;
6018 }
6019
6020 if (value == (unsigned) FAIL)
6021 return FAIL;
6022
6023 *instruction &= OPCODE_MASK;
6024 *instruction |= new_inst << DATA_OP_SHIFT;
6025 return value;
6026}
6027
6028static int
a737bd4d 6029data_op2 (char ** str)
b99bd4ef
NC
6030{
6031 int value;
6032 expressionS expr;
6033
6034 skip_whitespace (* str);
6035
6036 if (reg_required_here (str, 0) != FAIL)
6037 {
6038 if (skip_past_comma (str) == SUCCESS)
6039 /* Shift operation on register. */
6040 return decode_shift (str, NO_SHIFT_RESTRICT);
6041
6042 return SUCCESS;
6043 }
6044 else
6045 {
6046 /* Immediate expression. */
6047 if (is_immediate_prefix (**str))
6048 {
6049 (*str)++;
6050 inst.error = NULL;
6051
6052 if (my_get_expression (&inst.reloc.exp, str))
6053 return FAIL;
6054
6055 if (inst.reloc.exp.X_add_symbol)
6056 {
6057 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
6058 inst.reloc.pc_rel = 0;
6059 }
6060 else
6061 {
6062 if (skip_past_comma (str) == SUCCESS)
6063 {
6064 /* #x, y -- ie explicit rotation by Y. */
6065 if (my_get_expression (&expr, str))
6066 return FAIL;
6067
6068 if (expr.X_op != O_constant)
6069 {
f03698e6 6070 inst.error = _("constant expression expected");
b99bd4ef
NC
6071 return FAIL;
6072 }
6073
6074 /* Rotate must be a multiple of 2. */
6075 if (((unsigned) expr.X_add_number) > 30
6076 || (expr.X_add_number & 1) != 0
6077 || ((unsigned) inst.reloc.exp.X_add_number) > 255)
6078 {
f03698e6 6079 inst.error = _("invalid constant");
b99bd4ef
NC
6080 return FAIL;
6081 }
6082 inst.instruction |= INST_IMMEDIATE;
6083 inst.instruction |= inst.reloc.exp.X_add_number;
6084 inst.instruction |= expr.X_add_number << 7;
6085 return SUCCESS;
6086 }
6087
6088 /* Implicit rotation, select a suitable one. */
6089 value = validate_immediate (inst.reloc.exp.X_add_number);
6090
6091 if (value == FAIL)
6092 {
6093 /* Can't be done. Perhaps the code reads something like
6094 "add Rd, Rn, #-n", where "sub Rd, Rn, #n" would be OK. */
6095 if ((value = negate_data_op (&inst.instruction,
6096 inst.reloc.exp.X_add_number))
6097 == FAIL)
6098 {
f03698e6 6099 inst.error = _("invalid constant");
b99bd4ef
NC
6100 return FAIL;
6101 }
6102 }
6103
6104 inst.instruction |= value;
6105 }
6106
6107 inst.instruction |= INST_IMMEDIATE;
6108 return SUCCESS;
6109 }
6110
6111 (*str)++;
f03698e6 6112 inst.error = _("register or shift expression expected");
b99bd4ef
NC
6113 return FAIL;
6114 }
6115}
6116
6117static int
a737bd4d 6118fp_op2 (char ** str)
b99bd4ef
NC
6119{
6120 skip_whitespace (* str);
6121
6122 if (fp_reg_required_here (str, 0) != FAIL)
6123 return SUCCESS;
6124 else
6125 {
6126 /* Immediate expression. */
6127 if (*((*str)++) == '#')
6128 {
6129 int i;
6130
6131 inst.error = NULL;
6132
6133 skip_whitespace (* str);
6134
6135 /* First try and match exact strings, this is to guarantee
6136 that some formats will work even for cross assembly. */
6137
6138 for (i = 0; fp_const[i]; i++)
6139 {
6140 if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
6141 {
6142 char *start = *str;
6143
6144 *str += strlen (fp_const[i]);
6145 if (is_end_of_line[(unsigned char) **str])
6146 {
6147 inst.instruction |= i + 8;
6148 return SUCCESS;
6149 }
6150 *str = start;
6151 }
6152 }
6153
6154 /* Just because we didn't get a match doesn't mean that the
6155 constant isn't valid, just that it is in a format that we
6156 don't automatically recognize. Try parsing it with
6157 the standard expression routines. */
6158 if ((i = my_get_float_expression (str)) >= 0)
6159 {
6160 inst.instruction |= i + 8;
6161 return SUCCESS;
6162 }
6163
f03698e6 6164 inst.error = _("invalid floating point immediate expression");
b99bd4ef
NC
6165 return FAIL;
6166 }
6167 inst.error =
f03698e6 6168 _("floating point register or immediate expression expected");
b99bd4ef
NC
6169 return FAIL;
6170 }
6171}
6172
6173static void
a737bd4d 6174do_arit (char * str)
b99bd4ef
NC
6175{
6176 skip_whitespace (str);
6177
6178 if (reg_required_here (&str, 12) == FAIL
6179 || skip_past_comma (&str) == FAIL
6180 || reg_required_here (&str, 16) == FAIL
6181 || skip_past_comma (&str) == FAIL
6182 || data_op2 (&str) == FAIL)
6183 {
6184 if (!inst.error)
6185 inst.error = BAD_ARGS;
6186 return;
6187 }
6188
b99bd4ef 6189 end_of_line (str);
b99bd4ef
NC
6190}
6191
6192static void
a737bd4d 6193do_adr (char * str)
b99bd4ef 6194{
90e4755a
RE
6195 /* This is a pseudo-op of the form "adr rd, label" to be converted
6196 into a relative address of the form "add rd, pc, #label-.-8". */
6197 skip_whitespace (str);
6198
6199 if (reg_required_here (&str, 12) == FAIL
6200 || skip_past_comma (&str) == FAIL
6201 || my_get_expression (&inst.reloc.exp, &str))
6202 {
6203 if (!inst.error)
6204 inst.error = BAD_ARGS;
6205 return;
6206 }
6207
6208 /* Frag hacking will turn this into a sub instruction if the offset turns
6209 out to be negative. */
6210 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
250355db 6211#ifndef TE_WINCE
90e4755a 6212 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust. */
250355db 6213#endif
90e4755a
RE
6214 inst.reloc.pc_rel = 1;
6215
6216 end_of_line (str);
6217}
6218
6219static void
a737bd4d 6220do_adrl (char * str)
90e4755a
RE
6221{
6222 /* This is a pseudo-op of the form "adrl rd, label" to be converted
6223 into a relative address of the form:
6224 add rd, pc, #low(label-.-8)"
6225 add rd, rd, #high(label-.-8)" */
6226
6227 skip_whitespace (str);
6228
6229 if (reg_required_here (&str, 12) == FAIL
6230 || skip_past_comma (&str) == FAIL
6231 || my_get_expression (&inst.reloc.exp, &str))
6232 {
6233 if (!inst.error)
6234 inst.error = BAD_ARGS;
6235
6236 return;
6237 }
6238
6239 end_of_line (str);
6240 /* Frag hacking will turn this into a sub instruction if the offset turns
6241 out to be negative. */
6242 inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
a737bd4d 6243#ifndef TE_WINCE
90e4755a 6244 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
250355db 6245#endif
90e4755a
RE
6246 inst.reloc.pc_rel = 1;
6247 inst.size = INSN_SIZE * 2;
90e4755a
RE
6248}
6249
6250static void
a737bd4d 6251do_cmp (char * str)
90e4755a
RE
6252{
6253 skip_whitespace (str);
6254
6255 if (reg_required_here (&str, 16) == FAIL)
6256 {
6257 if (!inst.error)
6258 inst.error = BAD_ARGS;
6259 return;
6260 }
6261
6262 if (skip_past_comma (&str) == FAIL
6263 || data_op2 (&str) == FAIL)
6264 {
6265 if (!inst.error)
6266 inst.error = BAD_ARGS;
6267 return;
6268 }
6269
90e4755a 6270 end_of_line (str);
90e4755a
RE
6271}
6272
6273static void
a737bd4d 6274do_mov (char * str)
90e4755a
RE
6275{
6276 skip_whitespace (str);
6277
6278 if (reg_required_here (&str, 12) == FAIL)
6279 {
6280 if (!inst.error)
6281 inst.error = BAD_ARGS;
6282 return;
6283 }
6284
6285 if (skip_past_comma (&str) == FAIL
6286 || data_op2 (&str) == FAIL)
6287 {
6288 if (!inst.error)
6289 inst.error = BAD_ARGS;
6290 return;
6291 }
6292
90e4755a 6293 end_of_line (str);
90e4755a
RE
6294}
6295
90e4755a 6296static void
a737bd4d 6297do_ldst (char * str)
90e4755a
RE
6298{
6299 int pre_inc = 0;
6300 int conflict_reg;
6301 int value;
6302
b99bd4ef
NC
6303 skip_whitespace (str);
6304
90e4755a
RE
6305 if ((conflict_reg = reg_required_here (&str, 12)) == FAIL)
6306 {
6307 if (!inst.error)
6308 inst.error = BAD_ARGS;
6309 return;
6310 }
6311
6312 if (skip_past_comma (&str) == FAIL)
6313 {
f03698e6 6314 inst.error = _("address expected");
90e4755a
RE
6315 return;
6316 }
6317
90e4755a
RE
6318 if (*str == '[')
6319 {
6320 int reg;
6321
6322 str++;
6323
6324 skip_whitespace (str);
6325
6326 if ((reg = reg_required_here (&str, 16)) == FAIL)
6327 return;
6328
6329 /* Conflicts can occur on stores as well as loads. */
6330 conflict_reg = (conflict_reg == reg);
6331
6332 skip_whitespace (str);
6333
6334 if (*str == ']')
6335 {
6336 str ++;
6337
6338 if (skip_past_comma (&str) == SUCCESS)
6339 {
6340 /* [Rn],... (post inc) */
6341 if (ldst_extend (&str) == FAIL)
6342 return;
6343 if (conflict_reg)
6344 as_warn (_("%s register same as write-back base"),
6345 ((inst.instruction & LOAD_BIT)
6346 ? _("destination") : _("source")));
6347 }
6348 else
6349 {
6350 /* [Rn] */
6351 skip_whitespace (str);
6352
6353 if (*str == '!')
6354 {
6355 if (conflict_reg)
6356 as_warn (_("%s register same as write-back base"),
6357 ((inst.instruction & LOAD_BIT)
6358 ? _("destination") : _("source")));
6359 str++;
6360 inst.instruction |= WRITE_BACK;
6361 }
6362
6363 inst.instruction |= INDEX_UP;
6364 pre_inc = 1;
6365 }
6366 }
6367 else
6368 {
6369 /* [Rn,...] */
6370 if (skip_past_comma (&str) == FAIL)
6371 {
6372 inst.error = _("pre-indexed expression expected");
6373 return;
6374 }
6375
6376 pre_inc = 1;
6377 if (ldst_extend (&str) == FAIL)
6378 return;
6379
6380 skip_whitespace (str);
6381
6382 if (*str++ != ']')
6383 {
6384 inst.error = _("missing ]");
6385 return;
6386 }
6387
6388 skip_whitespace (str);
6389
6390 if (*str == '!')
6391 {
6392 if (conflict_reg)
6393 as_warn (_("%s register same as write-back base"),
6394 ((inst.instruction & LOAD_BIT)
6395 ? _("destination") : _("source")));
6396 str++;
6397 inst.instruction |= WRITE_BACK;
6398 }
6399 }
6400 }
6401 else if (*str == '=')
6402 {
f03698e6
RE
6403 if ((inst.instruction & LOAD_BIT) == 0)
6404 {
6405 inst.error = _("invalid pseudo operation");
6406 return;
6407 }
6408
90e4755a
RE
6409 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6410 str++;
6411
6412 skip_whitespace (str);
6413
6414 if (my_get_expression (&inst.reloc.exp, &str))
6415 return;
6416
6417 if (inst.reloc.exp.X_op != O_constant
6418 && inst.reloc.exp.X_op != O_symbol)
6419 {
f03698e6 6420 inst.error = _("constant expression expected");
90e4755a
RE
6421 return;
6422 }
6423
e28cd48c 6424 if (inst.reloc.exp.X_op == O_constant)
90e4755a 6425 {
e28cd48c
RE
6426 value = validate_immediate (inst.reloc.exp.X_add_number);
6427
6428 if (value != FAIL)
90e4755a 6429 {
e28cd48c
RE
6430 /* This can be done with a mov instruction. */
6431 inst.instruction &= LITERAL_MASK;
6432 inst.instruction |= (INST_IMMEDIATE
6433 | (OPCODE_MOV << DATA_OP_SHIFT));
6434 inst.instruction |= value & 0xfff;
6435 end_of_line (str);
90e4755a
RE
6436 return;
6437 }
b99bd4ef 6438
e28cd48c
RE
6439 value = validate_immediate (~inst.reloc.exp.X_add_number);
6440
6441 if (value != FAIL)
6442 {
6443 /* This can be done with a mvn instruction. */
6444 inst.instruction &= LITERAL_MASK;
6445 inst.instruction |= (INST_IMMEDIATE
6446 | (OPCODE_MVN << DATA_OP_SHIFT));
6447 inst.instruction |= value & 0xfff;
6448 end_of_line (str);
6449 return;
6450 }
90e4755a 6451 }
e28cd48c
RE
6452
6453 /* Insert into literal pool. */
6454 if (add_to_lit_pool () == FAIL)
6455 {
6456 if (!inst.error)
6457 inst.error = _("literal pool insertion failed");
6458 return;
6459 }
6460
6461 /* Change the instruction exp to point to the pool. */
6462 inst.reloc.type = BFD_RELOC_ARM_LITERAL;
6463 inst.reloc.pc_rel = 1;
6464 inst.instruction |= (REG_PC << 16);
6465 pre_inc = 1;
1cac9012
NC
6466 }
6467 else
6468 {
90e4755a
RE
6469 if (my_get_expression (&inst.reloc.exp, &str))
6470 return;
6471
6472 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6473#ifndef TE_WINCE
6474 /* PC rel adjust. */
6475 inst.reloc.exp.X_add_number -= 8;
6476#endif
1cac9012 6477 inst.reloc.pc_rel = 1;
90e4755a
RE
6478 inst.instruction |= (REG_PC << 16);
6479 pre_inc = 1;
b99bd4ef
NC
6480 }
6481
90e4755a 6482 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef 6483 end_of_line (str);
b99bd4ef
NC
6484}
6485
6486static void
a737bd4d 6487do_ldstt (char * str)
b99bd4ef 6488{
90e4755a
RE
6489 int conflict_reg;
6490
b99bd4ef
NC
6491 skip_whitespace (str);
6492
90e4755a 6493 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
b99bd4ef
NC
6494 {
6495 if (!inst.error)
6496 inst.error = BAD_ARGS;
6497 return;
6498 }
6499
90e4755a 6500 if (skip_past_comma (& str) == FAIL)
b99bd4ef 6501 {
f03698e6 6502 inst.error = _("address expected");
b99bd4ef
NC
6503 return;
6504 }
6505
90e4755a
RE
6506 if (*str == '[')
6507 {
6508 int reg;
b99bd4ef 6509
90e4755a 6510 str++;
b99bd4ef 6511
90e4755a 6512 skip_whitespace (str);
b99bd4ef 6513
90e4755a
RE
6514 if ((reg = reg_required_here (&str, 16)) == FAIL)
6515 return;
b99bd4ef 6516
90e4755a
RE
6517 /* ldrt/strt always use post-indexed addressing, so if the base is
6518 the same as Rd, we warn. */
6519 if (conflict_reg == reg)
6520 as_warn (_("%s register same as write-back base"),
6521 ((inst.instruction & LOAD_BIT)
6522 ? _("destination") : _("source")));
6523
6524 skip_whitespace (str);
6525
6526 if (*str == ']')
6527 {
6528 str ++;
6529
6530 if (skip_past_comma (&str) == SUCCESS)
6531 {
6532 /* [Rn],... (post inc) */
6533 if (ldst_extend (&str) == FAIL)
6534 return;
6535 }
6536 else
6537 {
6538 /* [Rn] */
6539 skip_whitespace (str);
6540
6541 /* Skip a write-back '!'. */
6542 if (*str == '!')
6543 str++;
6544
6545 inst.instruction |= INDEX_UP;
6546 }
6547 }
6548 else
6549 {
6550 inst.error = _("post-indexed expression expected");
6551 return;
6552 }
6553 }
6554 else
b99bd4ef 6555 {
90e4755a 6556 inst.error = _("post-indexed expression expected");
b99bd4ef
NC
6557 return;
6558 }
6559
b99bd4ef 6560 end_of_line (str);
b99bd4ef
NC
6561}
6562
90e4755a 6563/* Halfword and signed-byte load/store operations. */
a737bd4d 6564
b99bd4ef 6565static void
a737bd4d 6566do_ldstv4 (char * str)
b99bd4ef 6567{
b99bd4ef
NC
6568 int pre_inc = 0;
6569 int conflict_reg;
6570 int value;
6571
b99bd4ef
NC
6572 skip_whitespace (str);
6573
6574 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
6575 {
6576 if (!inst.error)
6577 inst.error = BAD_ARGS;
6578 return;
6579 }
6580
6581 if (skip_past_comma (& str) == FAIL)
6582 {
f03698e6 6583 inst.error = _("address expected");
b99bd4ef
NC
6584 return;
6585 }
6586
6587 if (*str == '[')
6588 {
6589 int reg;
6590
6591 str++;
6592
6593 skip_whitespace (str);
6594
6595 if ((reg = reg_required_here (&str, 16)) == FAIL)
6596 return;
6597
6598 /* Conflicts can occur on stores as well as loads. */
6599 conflict_reg = (conflict_reg == reg);
6600
6601 skip_whitespace (str);
6602
6603 if (*str == ']')
6604 {
6605 str ++;
6606
6607 if (skip_past_comma (&str) == SUCCESS)
6608 {
6609 /* [Rn],... (post inc) */
90e4755a 6610 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6611 return;
6612 if (conflict_reg)
90e4755a
RE
6613 as_warn (_("%s register same as write-back base"),
6614 ((inst.instruction & LOAD_BIT)
6615 ? _("destination") : _("source")));
b99bd4ef
NC
6616 }
6617 else
6618 {
6619 /* [Rn] */
90e4755a 6620 inst.instruction |= HWOFFSET_IMM;
b99bd4ef
NC
6621
6622 skip_whitespace (str);
6623
6624 if (*str == '!')
6625 {
6626 if (conflict_reg)
6627 as_warn (_("%s register same as write-back base"),
6628 ((inst.instruction & LOAD_BIT)
6629 ? _("destination") : _("source")));
6630 str++;
6631 inst.instruction |= WRITE_BACK;
6632 }
6633
90e4755a
RE
6634 inst.instruction |= INDEX_UP;
6635 pre_inc = 1;
b99bd4ef
NC
6636 }
6637 }
6638 else
6639 {
6640 /* [Rn,...] */
6641 if (skip_past_comma (&str) == FAIL)
6642 {
6643 inst.error = _("pre-indexed expression expected");
6644 return;
6645 }
6646
6647 pre_inc = 1;
90e4755a 6648 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6649 return;
6650
6651 skip_whitespace (str);
6652
6653 if (*str++ != ']')
6654 {
6655 inst.error = _("missing ]");
6656 return;
6657 }
6658
6659 skip_whitespace (str);
6660
6661 if (*str == '!')
6662 {
6663 if (conflict_reg)
6664 as_warn (_("%s register same as write-back base"),
6665 ((inst.instruction & LOAD_BIT)
6666 ? _("destination") : _("source")));
6667 str++;
6668 inst.instruction |= WRITE_BACK;
6669 }
6670 }
6671 }
6672 else if (*str == '=')
6673 {
f03698e6
RE
6674 if ((inst.instruction & LOAD_BIT) == 0)
6675 {
6676 inst.error = _("invalid pseudo operation");
6677 return;
6678 }
6679
90e4755a 6680 /* XXX Does this work correctly for half-word/byte ops? */
b99bd4ef
NC
6681 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6682 str++;
6683
6684 skip_whitespace (str);
6685
6686 if (my_get_expression (&inst.reloc.exp, &str))
6687 return;
6688
6689 if (inst.reloc.exp.X_op != O_constant
6690 && inst.reloc.exp.X_op != O_symbol)
6691 {
f03698e6 6692 inst.error = _("constant expression expected");
b99bd4ef
NC
6693 return;
6694 }
6695
d8273442 6696 if (inst.reloc.exp.X_op == O_constant)
b99bd4ef 6697 {
d8273442
NC
6698 value = validate_immediate (inst.reloc.exp.X_add_number);
6699
6700 if (value != FAIL)
b99bd4ef 6701 {
d8273442
NC
6702 /* This can be done with a mov instruction. */
6703 inst.instruction &= LITERAL_MASK;
6704 inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
90e4755a 6705 inst.instruction |= value & 0xfff;
d8273442 6706 end_of_line (str);
b99bd4ef
NC
6707 return;
6708 }
cc8a6dd0 6709
d8273442 6710 value = validate_immediate (~ inst.reloc.exp.X_add_number);
b99bd4ef 6711
d8273442 6712 if (value != FAIL)
b99bd4ef 6713 {
d8273442
NC
6714 /* This can be done with a mvn instruction. */
6715 inst.instruction &= LITERAL_MASK;
6716 inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
90e4755a 6717 inst.instruction |= value & 0xfff;
d8273442
NC
6718 end_of_line (str);
6719 return;
b99bd4ef 6720 }
b99bd4ef 6721 }
d8273442
NC
6722
6723 /* Insert into literal pool. */
6724 if (add_to_lit_pool () == FAIL)
6725 {
6726 if (!inst.error)
6727 inst.error = _("literal pool insertion failed");
6728 return;
6729 }
6730
6731 /* Change the instruction exp to point to the pool. */
90e4755a
RE
6732 inst.instruction |= HWOFFSET_IMM;
6733 inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
d8273442
NC
6734 inst.reloc.pc_rel = 1;
6735 inst.instruction |= (REG_PC << 16);
6736 pre_inc = 1;
b99bd4ef
NC
6737 }
6738 else
6739 {
6740 if (my_get_expression (&inst.reloc.exp, &str))
6741 return;
6742
90e4755a
RE
6743 inst.instruction |= HWOFFSET_IMM;
6744 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
b99bd4ef
NC
6745#ifndef TE_WINCE
6746 /* PC rel adjust. */
6747 inst.reloc.exp.X_add_number -= 8;
6748#endif
6749 inst.reloc.pc_rel = 1;
6750 inst.instruction |= (REG_PC << 16);
6751 pre_inc = 1;
6752 }
6753
90e4755a 6754 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef 6755 end_of_line (str);
b99bd4ef
NC
6756}
6757
b05fe5cf
ZW
6758static void
6759do_ldsttv4 (char * str)
6760{
6761 int conflict_reg;
6762
6763 skip_whitespace (str);
6764
6765 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
6766 {
6767 if (!inst.error)
6768 inst.error = BAD_ARGS;
6769 return;
6770 }
6771
6772 if (skip_past_comma (& str) == FAIL)
6773 {
6774 inst.error = _("address expected");
6775 return;
6776 }
6777
6778 if (*str == '[')
6779 {
6780 int reg;
6781
6782 str++;
6783
6784 skip_whitespace (str);
6785
6786 if ((reg = reg_required_here (&str, 16)) == FAIL)
6787 return;
6788
6789 /* ldrt/strt always use post-indexed addressing, so if the base is
6790 the same as Rd, we warn. */
6791 if (conflict_reg == reg)
6792 as_warn (_("%s register same as write-back base"),
6793 ((inst.instruction & LOAD_BIT)
6794 ? _("destination") : _("source")));
6795
6796 skip_whitespace (str);
6797
6798 if (*str == ']')
6799 {
6800 str ++;
6801
6802 if (skip_past_comma (&str) == SUCCESS)
6803 {
6804 /* [Rn],... (post inc) */
6805 if (ldst_extend_v4 (&str) == FAIL)
6806 return;
6807 }
6808 else
6809 {
6810 /* [Rn] */
6811 skip_whitespace (str);
6812
6813 /* Skip a write-back '!'. */
6814 if (*str == '!')
6815 str++;
6816
6817 inst.instruction |= (INDEX_UP|HWOFFSET_IMM);
6818 }
6819 }
6820 else
6821 {
6822 inst.error = _("post-indexed expression expected");
6823 return;
6824 }
6825 }
6826 else
6827 {
6828 inst.error = _("post-indexed expression expected");
6829 return;
6830 }
6831
6832 end_of_line (str);
6833}
6834
6835
b99bd4ef 6836static long
a737bd4d 6837reg_list (char ** strp)
b99bd4ef
NC
6838{
6839 char * str = * strp;
6840 long range = 0;
6841 int another_range;
6842
6843 /* We come back here if we get ranges concatenated by '+' or '|'. */
6844 do
6845 {
6846 another_range = 0;
6847
6848 if (*str == '{')
6849 {
6850 int in_range = 0;
6851 int cur_reg = -1;
6852
6853 str++;
6854 do
6855 {
6856 int reg;
6857
6858 skip_whitespace (str);
6859
6860 if ((reg = reg_required_here (& str, -1)) == FAIL)
6861 return FAIL;
6862
6863 if (in_range)
6864 {
6865 int i;
6866
6867 if (reg <= cur_reg)
6868 {
f03698e6 6869 inst.error = _("bad range in register list");
b99bd4ef
NC
6870 return FAIL;
6871 }
6872
6873 for (i = cur_reg + 1; i < reg; i++)
6874 {
6875 if (range & (1 << i))
6876 as_tsktsk
f03698e6 6877 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6878 i);
6879 else
6880 range |= 1 << i;
6881 }
6882 in_range = 0;
6883 }
6884
6885 if (range & (1 << reg))
f03698e6 6886 as_tsktsk (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6887 reg);
6888 else if (reg <= cur_reg)
f03698e6 6889 as_tsktsk (_("Warning: register range not in ascending order"));
b99bd4ef
NC
6890
6891 range |= 1 << reg;
6892 cur_reg = reg;
6893 }
6894 while (skip_past_comma (&str) != FAIL
6895 || (in_range = 1, *str++ == '-'));
6896 str--;
6897 skip_whitespace (str);
6898
6899 if (*str++ != '}')
6900 {
f03698e6 6901 inst.error = _("missing `}'");
b99bd4ef
NC
6902 return FAIL;
6903 }
6904 }
6905 else
6906 {
6907 expressionS expr;
6908
6909 if (my_get_expression (&expr, &str))
6910 return FAIL;
6911
6912 if (expr.X_op == O_constant)
6913 {
6914 if (expr.X_add_number
6915 != (expr.X_add_number & 0x0000ffff))
6916 {
6917 inst.error = _("invalid register mask");
6918 return FAIL;
6919 }
6920
6921 if ((range & expr.X_add_number) != 0)
6922 {
6923 int regno = range & expr.X_add_number;
6924
6925 regno &= -regno;
6926 regno = (1 << regno) - 1;
6927 as_tsktsk
f03698e6 6928 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6929 regno);
6930 }
6931
6932 range |= expr.X_add_number;
6933 }
6934 else
6935 {
6936 if (inst.reloc.type != 0)
6937 {
6938 inst.error = _("expression too complex");
6939 return FAIL;
6940 }
6941
6942 memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
6943 inst.reloc.type = BFD_RELOC_ARM_MULTI;
6944 inst.reloc.pc_rel = 0;
6945 }
6946 }
6947
6948 skip_whitespace (str);
6949
6950 if (*str == '|' || *str == '+')
6951 {
6952 str++;
6953 another_range = 1;
6954 }
6955 }
6956 while (another_range);
6957
6958 *strp = str;
6959 return range;
6960}
6961
6962static void
a737bd4d 6963do_ldmstm (char * str)
b99bd4ef
NC
6964{
6965 int base_reg;
6966 long range;
6967
6968 skip_whitespace (str);
6969
6970 if ((base_reg = reg_required_here (&str, 16)) == FAIL)
6971 return;
6972
6973 if (base_reg == REG_PC)
6974 {
6975 inst.error = _("r15 not allowed as base register");
6976 return;
6977 }
6978
6979 skip_whitespace (str);
6980
6981 if (*str == '!')
6982 {
90e4755a 6983 inst.instruction |= WRITE_BACK;
b99bd4ef
NC
6984 str++;
6985 }
6986
6987 if (skip_past_comma (&str) == FAIL
6988 || (range = reg_list (&str)) == FAIL)
6989 {
6990 if (! inst.error)
6991 inst.error = BAD_ARGS;
6992 return;
6993 }
6994
6995 if (*str == '^')
6996 {
6997 str++;
90e4755a 6998 inst.instruction |= LDM_TYPE_2_OR_3;
b99bd4ef
NC
6999 }
7000
6189168b
NC
7001 if (inst.instruction & WRITE_BACK)
7002 {
7003 /* Check for unpredictable uses of writeback. */
7004 if (inst.instruction & LOAD_BIT)
7005 {
7006 /* Not allowed in LDM type 2. */
7007 if ((inst.instruction & LDM_TYPE_2_OR_3)
7008 && ((range & (1 << REG_PC)) == 0))
7009 as_warn (_("writeback of base register is UNPREDICTABLE"));
7010 /* Only allowed if base reg not in list for other types. */
7011 else if (range & (1 << base_reg))
7012 as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
7013 }
7014 else /* STM. */
7015 {
7016 /* Not allowed for type 2. */
7017 if (inst.instruction & LDM_TYPE_2_OR_3)
7018 as_warn (_("writeback of base register is UNPREDICTABLE"));
7019 /* Only allowed if base reg not in list, or first in list. */
7020 else if ((range & (1 << base_reg))
7021 && (range & ((1 << base_reg) - 1)))
7022 as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
7023 }
7024 }
61b5f74b 7025
f2b7cb0a 7026 inst.instruction |= range;
b99bd4ef 7027 end_of_line (str);
b99bd4ef
NC
7028}
7029
0dd132b6
NC
7030static void
7031do_smi (char * str)
7032{
7033 skip_whitespace (str);
7034
7035 /* Allow optional leading '#'. */
7036 if (is_immediate_prefix (*str))
7037 str++;
7038
7039 if (my_get_expression (& inst.reloc.exp, & str))
7040 return;
7041
7042 inst.reloc.type = BFD_RELOC_ARM_SMI;
7043 inst.reloc.pc_rel = 0;
7044 end_of_line (str);
7045}
7046
b99bd4ef 7047static void
a737bd4d 7048do_swi (char * str)
b99bd4ef
NC
7049{
7050 skip_whitespace (str);
7051
7052 /* Allow optional leading '#'. */
7053 if (is_immediate_prefix (*str))
7054 str++;
7055
7056 if (my_get_expression (& inst.reloc.exp, & str))
7057 return;
7058
7059 inst.reloc.type = BFD_RELOC_ARM_SWI;
7060 inst.reloc.pc_rel = 0;
b99bd4ef 7061 end_of_line (str);
b99bd4ef
NC
7062}
7063
7064static void
a737bd4d 7065do_swap (char * str)
b99bd4ef
NC
7066{
7067 int reg;
7068
7069 skip_whitespace (str);
7070
7071 if ((reg = reg_required_here (&str, 12)) == FAIL)
7072 return;
7073
7074 if (reg == REG_PC)
7075 {
7076 inst.error = _("r15 not allowed in swap");
7077 return;
7078 }
7079
7080 if (skip_past_comma (&str) == FAIL
7081 || (reg = reg_required_here (&str, 0)) == FAIL)
7082 {
7083 if (!inst.error)
7084 inst.error = BAD_ARGS;
7085 return;
7086 }
7087
7088 if (reg == REG_PC)
7089 {
7090 inst.error = _("r15 not allowed in swap");
7091 return;
7092 }
7093
7094 if (skip_past_comma (&str) == FAIL
7095 || *str++ != '[')
7096 {
7097 inst.error = BAD_ARGS;
7098 return;
7099 }
7100
7101 skip_whitespace (str);
7102
7103 if ((reg = reg_required_here (&str, 16)) == FAIL)
7104 return;
7105
7106 if (reg == REG_PC)
7107 {
7108 inst.error = BAD_PC;
7109 return;
7110 }
7111
7112 skip_whitespace (str);
7113
7114 if (*str++ != ']')
7115 {
7116 inst.error = _("missing ]");
7117 return;
7118 }
7119
b99bd4ef 7120 end_of_line (str);
b99bd4ef
NC
7121}
7122
7123static void
a737bd4d 7124do_branch (char * str)
b99bd4ef
NC
7125{
7126 if (my_get_expression (&inst.reloc.exp, &str))
7127 return;
7128
7129#ifdef OBJ_ELF
7130 {
7131 char * save_in;
7132
7133 /* ScottB: February 5, 1998 - Check to see of PLT32 reloc
7134 required for the instruction. */
7135
7136 /* arm_parse_reloc () works on input_line_pointer.
7137 We actually want to parse the operands to the branch instruction
7138 passed in 'str'. Save the input pointer and restore it later. */
7139 save_in = input_line_pointer;
7140 input_line_pointer = str;
7141 if (inst.reloc.exp.X_op == O_symbol
7142 && *str == '('
7143 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
7144 {
7145 inst.reloc.type = BFD_RELOC_ARM_PLT32;
7146 inst.reloc.pc_rel = 0;
7147 /* Modify str to point to after parsed operands, otherwise
7148 end_of_line() will complain about the (PLT) left in str. */
7149 str = input_line_pointer;
7150 }
7151 else
7152 {
7153 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
7154 inst.reloc.pc_rel = 1;
7155 }
7156 input_line_pointer = save_in;
7157 }
7158#else
7159 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
7160 inst.reloc.pc_rel = 1;
7161#endif /* OBJ_ELF */
7162
7163 end_of_line (str);
b99bd4ef
NC
7164}
7165
7166static void
a737bd4d 7167do_cdp (char * str)
b99bd4ef
NC
7168{
7169 /* Co-processor data operation.
7170 Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */
7171 skip_whitespace (str);
7172
7173 if (co_proc_number (&str) == FAIL)
7174 {
7175 if (!inst.error)
7176 inst.error = BAD_ARGS;
7177 return;
7178 }
7179
7180 if (skip_past_comma (&str) == FAIL
7181 || cp_opc_expr (&str, 20,4) == FAIL)
7182 {
7183 if (!inst.error)
7184 inst.error = BAD_ARGS;
7185 return;
7186 }
7187
7188 if (skip_past_comma (&str) == FAIL
7189 || cp_reg_required_here (&str, 12) == FAIL)
7190 {
7191 if (!inst.error)
7192 inst.error = BAD_ARGS;
7193 return;
7194 }
7195
7196 if (skip_past_comma (&str) == FAIL
7197 || cp_reg_required_here (&str, 16) == FAIL)
7198 {
7199 if (!inst.error)
7200 inst.error = BAD_ARGS;
7201 return;
7202 }
7203
7204 if (skip_past_comma (&str) == FAIL
7205 || cp_reg_required_here (&str, 0) == FAIL)
7206 {
7207 if (!inst.error)
7208 inst.error = BAD_ARGS;
7209 return;
7210 }
7211
7212 if (skip_past_comma (&str) == SUCCESS)
7213 {
7214 if (cp_opc_expr (&str, 5, 3) == FAIL)
7215 {
7216 if (!inst.error)
7217 inst.error = BAD_ARGS;
7218 return;
7219 }
7220 }
7221
7222 end_of_line (str);
b99bd4ef
NC
7223}
7224
7225static void
a737bd4d 7226do_lstc (char * str)
b99bd4ef
NC
7227{
7228 /* Co-processor register load/store.
7229 Format: <LDC|STC{cond}[L] CP#,CRd,<address> */
7230
7231 skip_whitespace (str);
7232
7233 if (co_proc_number (&str) == FAIL)
7234 {
7235 if (!inst.error)
7236 inst.error = BAD_ARGS;
7237 return;
7238 }
7239
7240 if (skip_past_comma (&str) == FAIL
7241 || cp_reg_required_here (&str, 12) == FAIL)
7242 {
7243 if (!inst.error)
7244 inst.error = BAD_ARGS;
7245 return;
7246 }
7247
7248 if (skip_past_comma (&str) == FAIL
bfae80f2 7249 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7250 {
7251 if (! inst.error)
7252 inst.error = BAD_ARGS;
7253 return;
7254 }
7255
b99bd4ef 7256 end_of_line (str);
b99bd4ef
NC
7257}
7258
7259static void
a737bd4d 7260do_co_reg (char * str)
b99bd4ef
NC
7261{
7262 /* Co-processor register transfer.
7263 Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */
7264
7265 skip_whitespace (str);
7266
7267 if (co_proc_number (&str) == FAIL)
7268 {
7269 if (!inst.error)
7270 inst.error = BAD_ARGS;
7271 return;
7272 }
7273
7274 if (skip_past_comma (&str) == FAIL
7275 || cp_opc_expr (&str, 21, 3) == FAIL)
7276 {
7277 if (!inst.error)
7278 inst.error = BAD_ARGS;
7279 return;
7280 }
7281
7282 if (skip_past_comma (&str) == FAIL
7283 || reg_required_here (&str, 12) == FAIL)
7284 {
7285 if (!inst.error)
7286 inst.error = BAD_ARGS;
7287 return;
7288 }
7289
7290 if (skip_past_comma (&str) == FAIL
7291 || cp_reg_required_here (&str, 16) == FAIL)
7292 {
7293 if (!inst.error)
7294 inst.error = BAD_ARGS;
7295 return;
7296 }
7297
7298 if (skip_past_comma (&str) == FAIL
7299 || cp_reg_required_here (&str, 0) == FAIL)
7300 {
7301 if (!inst.error)
7302 inst.error = BAD_ARGS;
7303 return;
7304 }
7305
7306 if (skip_past_comma (&str) == SUCCESS)
7307 {
7308 if (cp_opc_expr (&str, 5, 3) == FAIL)
7309 {
7310 if (!inst.error)
7311 inst.error = BAD_ARGS;
7312 return;
7313 }
7314 }
b99bd4ef
NC
7315
7316 end_of_line (str);
b99bd4ef
NC
7317}
7318
7319static void
a737bd4d 7320do_fpa_ctrl (char * str)
b99bd4ef
NC
7321{
7322 /* FP control registers.
7323 Format: <WFS|RFS|WFC|RFC>{cond} Rn */
7324
7325 skip_whitespace (str);
7326
7327 if (reg_required_here (&str, 12) == FAIL)
7328 {
7329 if (!inst.error)
7330 inst.error = BAD_ARGS;
7331 return;
7332 }
7333
7334 end_of_line (str);
b99bd4ef
NC
7335}
7336
7337static void
a737bd4d 7338do_fpa_ldst (char * str)
b99bd4ef
NC
7339{
7340 skip_whitespace (str);
7341
b99bd4ef
NC
7342 if (fp_reg_required_here (&str, 12) == FAIL)
7343 {
7344 if (!inst.error)
7345 inst.error = BAD_ARGS;
7346 return;
7347 }
7348
7349 if (skip_past_comma (&str) == FAIL
bfae80f2 7350 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7351 {
7352 if (!inst.error)
7353 inst.error = BAD_ARGS;
7354 return;
7355 }
7356
7357 end_of_line (str);
7358}
7359
7360static void
a737bd4d 7361do_fpa_ldmstm (char * str)
b99bd4ef
NC
7362{
7363 int num_regs;
7364
7365 skip_whitespace (str);
7366
7367 if (fp_reg_required_here (&str, 12) == FAIL)
7368 {
7369 if (! inst.error)
7370 inst.error = BAD_ARGS;
7371 return;
7372 }
7373
7374 /* Get Number of registers to transfer. */
7375 if (skip_past_comma (&str) == FAIL
7376 || my_get_expression (&inst.reloc.exp, &str))
7377 {
7378 if (! inst.error)
7379 inst.error = _("constant expression expected");
7380 return;
7381 }
7382
7383 if (inst.reloc.exp.X_op != O_constant)
7384 {
f03698e6 7385 inst.error = _("constant value required for number of registers");
b99bd4ef
NC
7386 return;
7387 }
7388
7389 num_regs = inst.reloc.exp.X_add_number;
7390
7391 if (num_regs < 1 || num_regs > 4)
7392 {
7393 inst.error = _("number of registers must be in the range [1:4]");
7394 return;
7395 }
7396
7397 switch (num_regs)
7398 {
7399 case 1:
7400 inst.instruction |= CP_T_X;
7401 break;
7402 case 2:
7403 inst.instruction |= CP_T_Y;
7404 break;
7405 case 3:
7406 inst.instruction |= CP_T_Y | CP_T_X;
7407 break;
7408 case 4:
7409 break;
7410 default:
7411 abort ();
7412 }
7413
e28cd48c 7414 if (inst.instruction & (CP_T_Pre | CP_T_UD)) /* ea/fd format. */
b99bd4ef
NC
7415 {
7416 int reg;
7417 int write_back;
7418 int offset;
7419
7420 /* The instruction specified "ea" or "fd", so we can only accept
7421 [Rn]{!}. The instruction does not really support stacking or
7422 unstacking, so we have to emulate these by setting appropriate
7423 bits and offsets. */
7424 if (skip_past_comma (&str) == FAIL
7425 || *str != '[')
7426 {
7427 if (! inst.error)
7428 inst.error = BAD_ARGS;
7429 return;
7430 }
7431
7432 str++;
7433 skip_whitespace (str);
7434
7435 if ((reg = reg_required_here (&str, 16)) == FAIL)
7436 return;
7437
7438 skip_whitespace (str);
7439
7440 if (*str != ']')
7441 {
7442 inst.error = BAD_ARGS;
7443 return;
7444 }
7445
7446 str++;
7447 if (*str == '!')
7448 {
7449 write_back = 1;
7450 str++;
7451 if (reg == REG_PC)
7452 {
7453 inst.error =
f03698e6 7454 _("r15 not allowed as base register with write-back");
b99bd4ef
NC
7455 return;
7456 }
7457 }
7458 else
7459 write_back = 0;
7460
90e4755a 7461 if (inst.instruction & CP_T_Pre)
b99bd4ef
NC
7462 {
7463 /* Pre-decrement. */
7464 offset = 3 * num_regs;
7465 if (write_back)
90e4755a 7466 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7467 }
7468 else
7469 {
7470 /* Post-increment. */
7471 if (write_back)
7472 {
90e4755a 7473 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7474 offset = 3 * num_regs;
7475 }
7476 else
7477 {
7478 /* No write-back, so convert this into a standard pre-increment
7479 instruction -- aesthetically more pleasing. */
90e4755a 7480 inst.instruction |= CP_T_Pre | CP_T_UD;
b99bd4ef
NC
7481 offset = 0;
7482 }
7483 }
7484
f2b7cb0a 7485 inst.instruction |= offset;
b99bd4ef
NC
7486 }
7487 else if (skip_past_comma (&str) == FAIL
bfae80f2 7488 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7489 {
7490 if (! inst.error)
7491 inst.error = BAD_ARGS;
7492 return;
7493 }
7494
7495 end_of_line (str);
7496}
7497
7498static void
a737bd4d 7499do_fpa_dyadic (char * str)
b99bd4ef
NC
7500{
7501 skip_whitespace (str);
7502
b99bd4ef
NC
7503 if (fp_reg_required_here (&str, 12) == FAIL)
7504 {
7505 if (! inst.error)
7506 inst.error = BAD_ARGS;
7507 return;
7508 }
7509
7510 if (skip_past_comma (&str) == FAIL
7511 || fp_reg_required_here (&str, 16) == FAIL)
7512 {
7513 if (! inst.error)
7514 inst.error = BAD_ARGS;
7515 return;
7516 }
7517
7518 if (skip_past_comma (&str) == FAIL
7519 || fp_op2 (&str) == FAIL)
7520 {
7521 if (! inst.error)
7522 inst.error = BAD_ARGS;
7523 return;
7524 }
7525
b99bd4ef 7526 end_of_line (str);
b99bd4ef
NC
7527}
7528
7529static void
a737bd4d 7530do_fpa_monadic (char * str)
b99bd4ef
NC
7531{
7532 skip_whitespace (str);
7533
b99bd4ef
NC
7534 if (fp_reg_required_here (&str, 12) == FAIL)
7535 {
7536 if (! inst.error)
7537 inst.error = BAD_ARGS;
7538 return;
7539 }
7540
7541 if (skip_past_comma (&str) == FAIL
7542 || fp_op2 (&str) == FAIL)
7543 {
7544 if (! inst.error)
7545 inst.error = BAD_ARGS;
7546 return;
7547 }
7548
b99bd4ef 7549 end_of_line (str);
b99bd4ef
NC
7550}
7551
7552static void
a737bd4d 7553do_fpa_cmp (char * str)
b99bd4ef
NC
7554{
7555 skip_whitespace (str);
7556
7557 if (fp_reg_required_here (&str, 16) == FAIL)
7558 {
7559 if (! inst.error)
7560 inst.error = BAD_ARGS;
7561 return;
7562 }
7563
7564 if (skip_past_comma (&str) == FAIL
7565 || fp_op2 (&str) == FAIL)
7566 {
7567 if (! inst.error)
7568 inst.error = BAD_ARGS;
7569 return;
7570 }
7571
b99bd4ef 7572 end_of_line (str);
b99bd4ef
NC
7573}
7574
7575static void
a737bd4d 7576do_fpa_from_reg (char * str)
b99bd4ef
NC
7577{
7578 skip_whitespace (str);
7579
b99bd4ef
NC
7580 if (fp_reg_required_here (&str, 16) == FAIL)
7581 {
7582 if (! inst.error)
7583 inst.error = BAD_ARGS;
7584 return;
7585 }
7586
7587 if (skip_past_comma (&str) == FAIL
7588 || reg_required_here (&str, 12) == FAIL)
7589 {
7590 if (! inst.error)
7591 inst.error = BAD_ARGS;
7592 return;
7593 }
7594
b99bd4ef 7595 end_of_line (str);
b99bd4ef
NC
7596}
7597
7598static void
a737bd4d 7599do_fpa_to_reg (char * str)
b99bd4ef
NC
7600{
7601 skip_whitespace (str);
7602
7603 if (reg_required_here (&str, 12) == FAIL)
7604 return;
7605
7606 if (skip_past_comma (&str) == FAIL
7607 || fp_reg_required_here (&str, 0) == FAIL)
7608 {
7609 if (! inst.error)
7610 inst.error = BAD_ARGS;
7611 return;
7612 }
7613
b99bd4ef 7614 end_of_line (str);
b99bd4ef
NC
7615}
7616
7ed4c4c5
NC
7617/* Encode a VFP SP register number. */
7618
7619static void
7620vfp_sp_encode_reg (int reg, enum vfp_sp_reg_pos pos)
7621{
7622 switch (pos)
7623 {
7624 case VFP_REG_Sd:
7625 inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
7626 break;
7627
7628 case VFP_REG_Sn:
7629 inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
7630 break;
7631
7632 case VFP_REG_Sm:
7633 inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
7634 break;
7635
7636 default:
7637 abort ();
7638 }
7639}
7640
b99bd4ef 7641static int
a737bd4d
NC
7642vfp_sp_reg_required_here (char ** str,
7643 enum vfp_sp_reg_pos pos)
b99bd4ef 7644{
bfae80f2 7645 int reg;
7ed4c4c5 7646 char * start = *str;
b99bd4ef 7647
bfae80f2 7648 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab)) != FAIL)
b99bd4ef 7649 {
7ed4c4c5 7650 vfp_sp_encode_reg (reg, pos);
bfae80f2
RE
7651 return reg;
7652 }
b99bd4ef 7653
bfae80f2
RE
7654 /* In the few cases where we might be able to accept something else
7655 this error can be overridden. */
7656 inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
7657
7658 /* Restore the start point. */
7659 *str = start;
7660 return FAIL;
7661}
7662
7663static int
a737bd4d
NC
7664vfp_dp_reg_required_here (char ** str,
7665 enum vfp_dp_reg_pos pos)
bfae80f2 7666{
a737bd4d
NC
7667 int reg;
7668 char * start = *str;
bfae80f2
RE
7669
7670 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL)
7671 {
7672 switch (pos)
b99bd4ef 7673 {
bfae80f2
RE
7674 case VFP_REG_Dd:
7675 inst.instruction |= reg << 12;
7676 break;
b99bd4ef 7677
bfae80f2
RE
7678 case VFP_REG_Dn:
7679 inst.instruction |= reg << 16;
7680 break;
7681
7682 case VFP_REG_Dm:
7683 inst.instruction |= reg << 0;
7684 break;
7685
7686 default:
7687 abort ();
7688 }
7689 return reg;
b99bd4ef
NC
7690 }
7691
bfae80f2
RE
7692 /* In the few cases where we might be able to accept something else
7693 this error can be overridden. */
7694 inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
b99bd4ef 7695
bfae80f2
RE
7696 /* Restore the start point. */
7697 *str = start;
7698 return FAIL;
7699}
b99bd4ef
NC
7700
7701static void
a737bd4d 7702do_vfp_sp_monadic (char * str)
b99bd4ef 7703{
b99bd4ef
NC
7704 skip_whitespace (str);
7705
bfae80f2
RE
7706 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7707 return;
7708
7709 if (skip_past_comma (&str) == FAIL
7710 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef
NC
7711 {
7712 if (! inst.error)
7713 inst.error = BAD_ARGS;
7714 return;
7715 }
7716
bfae80f2 7717 end_of_line (str);
bfae80f2
RE
7718}
7719
7720static void
a737bd4d 7721do_vfp_dp_monadic (char * str)
bfae80f2
RE
7722{
7723 skip_whitespace (str);
7724
7725 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7726 return;
7727
7728 if (skip_past_comma (&str) == FAIL
7729 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
b99bd4ef 7730 {
bfae80f2
RE
7731 if (! inst.error)
7732 inst.error = BAD_ARGS;
7733 return;
b99bd4ef 7734 }
b99bd4ef 7735
bfae80f2 7736 end_of_line (str);
bfae80f2 7737}
b99bd4ef 7738
bfae80f2 7739static void
a737bd4d 7740do_vfp_sp_dyadic (char * str)
bfae80f2
RE
7741{
7742 skip_whitespace (str);
b99bd4ef 7743
bfae80f2
RE
7744 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7745 return;
b99bd4ef 7746
bfae80f2
RE
7747 if (skip_past_comma (&str) == FAIL
7748 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL
7749 || skip_past_comma (&str) == FAIL
7750 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef 7751 {
bfae80f2
RE
7752 if (! inst.error)
7753 inst.error = BAD_ARGS;
7754 return;
7755 }
b99bd4ef 7756
bfae80f2 7757 end_of_line (str);
bfae80f2 7758}
b99bd4ef 7759
bfae80f2 7760static void
a737bd4d 7761do_vfp_dp_dyadic (char * str)
bfae80f2
RE
7762{
7763 skip_whitespace (str);
b99bd4ef 7764
bfae80f2
RE
7765 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7766 return;
b99bd4ef 7767
bfae80f2
RE
7768 if (skip_past_comma (&str) == FAIL
7769 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL
7770 || skip_past_comma (&str) == FAIL
7771 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7772 {
7773 if (! inst.error)
7774 inst.error = BAD_ARGS;
7775 return;
7776 }
b99bd4ef 7777
bfae80f2 7778 end_of_line (str);
bfae80f2 7779}
b99bd4ef 7780
bfae80f2 7781static void
a737bd4d 7782do_vfp_reg_from_sp (char * str)
bfae80f2
RE
7783{
7784 skip_whitespace (str);
7785
7786 if (reg_required_here (&str, 12) == FAIL)
7787 return;
7788
7789 if (skip_past_comma (&str) == FAIL
7790 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7791 {
7792 if (! inst.error)
7793 inst.error = BAD_ARGS;
7794 return;
7795 }
7796
7797 end_of_line (str);
bfae80f2
RE
7798}
7799
7ed4c4c5
NC
7800/* Parse a VFP register list. If the string is invalid return FAIL.
7801 Otherwise return the number of registers, and set PBASE to the first
7802 register. Double precision registers are matched if DP is nonzero. */
a737bd4d 7803
7ed4c4c5
NC
7804static int
7805vfp_parse_reg_list (char **str, int *pbase, int dp)
a737bd4d 7806{
7ed4c4c5 7807 int base_reg;
a737bd4d 7808 int new_base;
7ed4c4c5
NC
7809 int regtype;
7810 int max_regs;
a737bd4d 7811 int count = 0;
a737bd4d 7812 int warned = 0;
7ed4c4c5
NC
7813 unsigned long mask = 0;
7814 int i;
a737bd4d
NC
7815
7816 if (**str != '{')
7817 return FAIL;
7818
7819 (*str)++;
7820 skip_whitespace (*str);
7821
7ed4c4c5 7822 if (dp)
a737bd4d 7823 {
7ed4c4c5
NC
7824 regtype = REG_TYPE_DN;
7825 max_regs = 16;
7826 }
7827 else
7828 {
7829 regtype = REG_TYPE_SN;
7830 max_regs = 32;
7831 }
a737bd4d 7832
7ed4c4c5 7833 base_reg = max_regs;
a737bd4d 7834
7ed4c4c5
NC
7835 do
7836 {
7837 new_base = arm_reg_parse (str, all_reg_maps[regtype].htab);
7838 if (new_base == FAIL)
a737bd4d 7839 {
7ed4c4c5
NC
7840 inst.error = _(all_reg_maps[regtype].expected);
7841 return FAIL;
a737bd4d
NC
7842 }
7843
7ed4c4c5
NC
7844 if (new_base < base_reg)
7845 base_reg = new_base;
7846
a737bd4d
NC
7847 if (mask & (1 << new_base))
7848 {
7849 inst.error = _("invalid register list");
7850 return FAIL;
7851 }
7852
7853 if ((mask >> new_base) != 0 && ! warned)
7854 {
7855 as_tsktsk (_("register list not in ascending order"));
7856 warned = 1;
7857 }
7858
7859 mask |= 1 << new_base;
7860 count++;
7861
7862 skip_whitespace (*str);
7863
7864 if (**str == '-') /* We have the start of a range expression */
7865 {
7866 int high_range;
7867
7868 (*str)++;
7869
7870 if ((high_range
7ed4c4c5 7871 = arm_reg_parse (str, all_reg_maps[regtype].htab))
a737bd4d
NC
7872 == FAIL)
7873 {
7ed4c4c5 7874 inst.error = _(all_reg_maps[regtype].expected);
a737bd4d
NC
7875 return FAIL;
7876 }
7877
7878 if (high_range <= new_base)
7879 {
7880 inst.error = _("register range not in ascending order");
7881 return FAIL;
7882 }
7883
7884 for (new_base++; new_base <= high_range; new_base++)
7885 {
7886 if (mask & (1 << new_base))
7887 {
7888 inst.error = _("invalid register list");
7889 return FAIL;
7890 }
7891
7892 mask |= 1 << new_base;
7893 count++;
7894 }
7895 }
7896 }
7897 while (skip_past_comma (str) != FAIL);
7898
a737bd4d
NC
7899 (*str)++;
7900
a737bd4d 7901 /* Sanity check -- should have raised a parse error above. */
7ed4c4c5 7902 if (count == 0 || count > max_regs)
a737bd4d
NC
7903 abort ();
7904
7ed4c4c5
NC
7905 *pbase = base_reg;
7906
a737bd4d 7907 /* Final test -- the registers must be consecutive. */
7ed4c4c5
NC
7908 mask >>= base_reg;
7909 for (i = 0; i < count; i++)
a737bd4d 7910 {
7ed4c4c5 7911 if ((mask & (1u << i)) == 0)
a737bd4d
NC
7912 {
7913 inst.error = _("non-contiguous register range");
7914 return FAIL;
7915 }
7916 }
7917
7ed4c4c5 7918 return count;
a737bd4d
NC
7919}
7920
bfae80f2 7921static void
a737bd4d 7922do_vfp_reg2_from_sp2 (char * str)
bfae80f2 7923{
7ed4c4c5
NC
7924 int reg;
7925
bfae80f2
RE
7926 skip_whitespace (str);
7927
e45d0630
PB
7928 if (reg_required_here (&str, 12) == FAIL
7929 || skip_past_comma (&str) == FAIL
bfae80f2
RE
7930 || reg_required_here (&str, 16) == FAIL
7931 || skip_past_comma (&str) == FAIL)
7932 {
7933 if (! inst.error)
7934 inst.error = BAD_ARGS;
7935 return;
7936 }
7937
7938 /* We require exactly two consecutive SP registers. */
7ed4c4c5 7939 if (vfp_parse_reg_list (&str, &reg, 0) != 2)
bfae80f2
RE
7940 {
7941 if (! inst.error)
7942 inst.error = _("only two consecutive VFP SP registers allowed here");
7943 }
7ed4c4c5 7944 vfp_sp_encode_reg (reg, VFP_REG_Sm);
bfae80f2
RE
7945
7946 end_of_line (str);
bfae80f2
RE
7947}
7948
7949static void
a737bd4d 7950do_vfp_sp_from_reg (char * str)
bfae80f2
RE
7951{
7952 skip_whitespace (str);
7953
7954 if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7955 return;
7956
7957 if (skip_past_comma (&str) == FAIL
7958 || reg_required_here (&str, 12) == FAIL)
7959 {
7960 if (! inst.error)
7961 inst.error = BAD_ARGS;
7962 return;
7963 }
7964
7965 end_of_line (str);
bfae80f2
RE
7966}
7967
e45d0630 7968static void
a737bd4d 7969do_vfp_sp2_from_reg2 (char * str)
e45d0630 7970{
7ed4c4c5
NC
7971 int reg;
7972
e45d0630
PB
7973 skip_whitespace (str);
7974
7975 /* We require exactly two consecutive SP registers. */
7ed4c4c5 7976 if (vfp_parse_reg_list (&str, &reg, 0) != 2)
e45d0630
PB
7977 {
7978 if (! inst.error)
7979 inst.error = _("only two consecutive VFP SP registers allowed here");
7980 }
7ed4c4c5 7981 vfp_sp_encode_reg (reg, VFP_REG_Sm);
e45d0630
PB
7982
7983 if (skip_past_comma (&str) == FAIL
7984 || reg_required_here (&str, 12) == FAIL
7985 || skip_past_comma (&str) == FAIL
7986 || reg_required_here (&str, 16) == FAIL)
7987 {
7988 if (! inst.error)
7989 inst.error = BAD_ARGS;
7990 return;
7991 }
7992
7993 end_of_line (str);
7994}
7995
bfae80f2 7996static void
a737bd4d 7997do_vfp_reg_from_dp (char * str)
bfae80f2
RE
7998{
7999 skip_whitespace (str);
8000
8001 if (reg_required_here (&str, 12) == FAIL)
8002 return;
8003
8004 if (skip_past_comma (&str) == FAIL
8005 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
8006 {
8007 if (! inst.error)
8008 inst.error = BAD_ARGS;
8009 return;
8010 }
8011
8012 end_of_line (str);
bfae80f2
RE
8013}
8014
8015static void
a737bd4d 8016do_vfp_reg2_from_dp (char * str)
bfae80f2
RE
8017{
8018 skip_whitespace (str);
8019
8020 if (reg_required_here (&str, 12) == FAIL)
8021 return;
8022
8023 if (skip_past_comma (&str) == FAIL
8024 || reg_required_here (&str, 16) == FAIL
8025 || skip_past_comma (&str) == FAIL
8026 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8027 {
8028 if (! inst.error)
8029 inst.error = BAD_ARGS;
8030 return;
8031 }
8032
8033 end_of_line (str);
bfae80f2
RE
8034}
8035
8036static void
a737bd4d 8037do_vfp_dp_from_reg (char * str)
bfae80f2
RE
8038{
8039 skip_whitespace (str);
8040
8041 if (vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
8042 return;
8043
8044 if (skip_past_comma (&str) == FAIL
8045 || reg_required_here (&str, 12) == FAIL)
8046 {
8047 if (! inst.error)
8048 inst.error = BAD_ARGS;
8049 return;
8050 }
8051
8052 end_of_line (str);
bfae80f2
RE
8053}
8054
8055static void
a737bd4d 8056do_vfp_dp_from_reg2 (char * str)
bfae80f2
RE
8057{
8058 skip_whitespace (str);
8059
8060 if (vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8061 return;
8062
8063 if (skip_past_comma (&str) == FAIL
8064 || reg_required_here (&str, 12) == FAIL
8065 || skip_past_comma (&str) == FAIL
e45d0630 8066 || reg_required_here (&str, 16) == FAIL)
bfae80f2
RE
8067 {
8068 if (! inst.error)
8069 inst.error = BAD_ARGS;
8070 return;
8071 }
8072
8073 end_of_line (str);
bfae80f2
RE
8074}
8075
8076static const struct vfp_reg *
a737bd4d 8077vfp_psr_parse (char ** str)
bfae80f2
RE
8078{
8079 char *start = *str;
8080 char c;
8081 char *p;
8082 const struct vfp_reg *vreg;
8083
8084 p = start;
8085
8086 /* Find the end of the current token. */
8087 do
8088 {
8089 c = *p++;
8090 }
8091 while (ISALPHA (c));
8092
8093 /* Mark it. */
8094 *--p = 0;
8095
cc8a6dd0 8096 for (vreg = vfp_regs + 0;
bfae80f2
RE
8097 vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg);
8098 vreg++)
8099 {
a737bd4d 8100 if (streq (start, vreg->name))
bfae80f2
RE
8101 {
8102 *p = c;
8103 *str = p;
8104 return vreg;
8105 }
8106 }
8107
8108 *p = c;
8109 return NULL;
8110}
8111
8112static int
a737bd4d 8113vfp_psr_required_here (char ** str)
bfae80f2
RE
8114{
8115 char *start = *str;
8116 const struct vfp_reg *vreg;
8117
8118 vreg = vfp_psr_parse (str);
8119
8120 if (vreg)
8121 {
8122 inst.instruction |= vreg->regno;
8123 return SUCCESS;
8124 }
8125
8126 inst.error = _("VFP system register expected");
8127
8128 *str = start;
8129 return FAIL;
8130}
8131
8132static void
a737bd4d 8133do_vfp_reg_from_ctrl (char * str)
bfae80f2
RE
8134{
8135 skip_whitespace (str);
8136
8137 if (reg_required_here (&str, 12) == FAIL)
8138 return;
8139
8140 if (skip_past_comma (&str) == FAIL
8141 || vfp_psr_required_here (&str) == FAIL)
8142 {
8143 if (! inst.error)
8144 inst.error = BAD_ARGS;
8145 return;
8146 }
8147
8148 end_of_line (str);
bfae80f2
RE
8149}
8150
8151static void
a737bd4d 8152do_vfp_ctrl_from_reg (char * str)
bfae80f2
RE
8153{
8154 skip_whitespace (str);
8155
8156 if (vfp_psr_required_here (&str) == FAIL)
8157 return;
8158
8159 if (skip_past_comma (&str) == FAIL
8160 || reg_required_here (&str, 12) == FAIL)
8161 {
8162 if (! inst.error)
8163 inst.error = BAD_ARGS;
8164 return;
8165 }
8166
8167 end_of_line (str);
bfae80f2
RE
8168}
8169
8170static void
a737bd4d 8171do_vfp_sp_ldst (char * str)
bfae80f2
RE
8172{
8173 skip_whitespace (str);
8174
8175 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8176 {
8177 if (!inst.error)
8178 inst.error = BAD_ARGS;
8179 return;
8180 }
8181
8182 if (skip_past_comma (&str) == FAIL
8183 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
8184 {
8185 if (!inst.error)
8186 inst.error = BAD_ARGS;
8187 return;
8188 }
8189
8190 end_of_line (str);
bfae80f2
RE
8191}
8192
8193static void
a737bd4d 8194do_vfp_dp_ldst (char * str)
bfae80f2
RE
8195{
8196 skip_whitespace (str);
8197
8198 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8199 {
8200 if (!inst.error)
8201 inst.error = BAD_ARGS;
8202 return;
8203 }
8204
8205 if (skip_past_comma (&str) == FAIL
8206 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
8207 {
8208 if (!inst.error)
a737bd4d
NC
8209 inst.error = BAD_ARGS;
8210 return;
bfae80f2
RE
8211 }
8212
a737bd4d 8213 end_of_line (str);
bfae80f2
RE
8214}
8215
bfae80f2
RE
8216
8217static void
a737bd4d 8218vfp_sp_ldstm (char * str, enum vfp_ldstm_type ldstm_type)
bfae80f2 8219{
7ed4c4c5
NC
8220 int count;
8221 int reg;
bfae80f2
RE
8222
8223 skip_whitespace (str);
8224
8225 if (reg_required_here (&str, 16) == FAIL)
8226 return;
8227
8228 skip_whitespace (str);
8229
8230 if (*str == '!')
8231 {
8232 inst.instruction |= WRITE_BACK;
8233 str++;
8234 }
8235 else if (ldstm_type != VFP_LDSTMIA)
8236 {
8237 inst.error = _("this addressing mode requires base-register writeback");
8238 return;
8239 }
8240
8241 if (skip_past_comma (&str) == FAIL
7ed4c4c5 8242 || (count = vfp_parse_reg_list (&str, &reg, 0)) == FAIL)
bfae80f2
RE
8243 {
8244 if (!inst.error)
8245 inst.error = BAD_ARGS;
8246 return;
8247 }
7ed4c4c5 8248 vfp_sp_encode_reg (reg, VFP_REG_Sd);
bfae80f2 8249
7ed4c4c5 8250 inst.instruction |= count;
bfae80f2
RE
8251 end_of_line (str);
8252}
8253
8254static void
a737bd4d 8255vfp_dp_ldstm (char * str, enum vfp_ldstm_type ldstm_type)
bfae80f2 8256{
7ed4c4c5
NC
8257 int count;
8258 int reg;
bfae80f2
RE
8259
8260 skip_whitespace (str);
8261
8262 if (reg_required_here (&str, 16) == FAIL)
8263 return;
8264
8265 skip_whitespace (str);
8266
8267 if (*str == '!')
8268 {
8269 inst.instruction |= WRITE_BACK;
8270 str++;
8271 }
8272 else if (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX)
8273 {
8274 inst.error = _("this addressing mode requires base-register writeback");
8275 return;
8276 }
8277
8278 if (skip_past_comma (&str) == FAIL
7ed4c4c5 8279 || (count = vfp_parse_reg_list (&str, &reg, 1)) == FAIL)
bfae80f2
RE
8280 {
8281 if (!inst.error)
8282 inst.error = BAD_ARGS;
8283 return;
8284 }
8285
7ed4c4c5 8286 count <<= 1;
bfae80f2 8287 if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
7ed4c4c5 8288 count += 1;
bfae80f2 8289
7ed4c4c5 8290 inst.instruction |= (reg << 12) | count;
bfae80f2
RE
8291 end_of_line (str);
8292}
8293
8294static void
a737bd4d 8295do_vfp_sp_ldstmia (char * str)
bfae80f2
RE
8296{
8297 vfp_sp_ldstm (str, VFP_LDSTMIA);
8298}
8299
8300static void
a737bd4d 8301do_vfp_sp_ldstmdb (char * str)
bfae80f2
RE
8302{
8303 vfp_sp_ldstm (str, VFP_LDSTMDB);
8304}
8305
8306static void
a737bd4d 8307do_vfp_dp_ldstmia (char * str)
bfae80f2
RE
8308{
8309 vfp_dp_ldstm (str, VFP_LDSTMIA);
8310}
8311
8312static void
a737bd4d 8313do_vfp_dp_ldstmdb (char * str)
bfae80f2
RE
8314{
8315 vfp_dp_ldstm (str, VFP_LDSTMDB);
8316}
8317
8318static void
a737bd4d 8319do_vfp_xp_ldstmia (char *str)
bfae80f2
RE
8320{
8321 vfp_dp_ldstm (str, VFP_LDSTMIAX);
8322}
8323
8324static void
a737bd4d 8325do_vfp_xp_ldstmdb (char * str)
bfae80f2
RE
8326{
8327 vfp_dp_ldstm (str, VFP_LDSTMDBX);
8328}
8329
8330static void
a737bd4d 8331do_vfp_sp_compare_z (char * str)
bfae80f2
RE
8332{
8333 skip_whitespace (str);
8334
8335 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8336 {
8337 if (!inst.error)
8338 inst.error = BAD_ARGS;
8339 return;
8340 }
8341
8342 end_of_line (str);
bfae80f2
RE
8343}
8344
8345static void
a737bd4d 8346do_vfp_dp_compare_z (char * str)
bfae80f2
RE
8347{
8348 skip_whitespace (str);
8349
8350 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8351 {
8352 if (!inst.error)
8353 inst.error = BAD_ARGS;
8354 return;
8355 }
8356
8357 end_of_line (str);
bfae80f2
RE
8358}
8359
8360static void
a737bd4d 8361do_vfp_dp_sp_cvt (char * str)
bfae80f2
RE
8362{
8363 skip_whitespace (str);
8364
8365 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8366 return;
8367
8368 if (skip_past_comma (&str) == FAIL
8369 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
8370 {
8371 if (! inst.error)
8372 inst.error = BAD_ARGS;
8373 return;
8374 }
8375
8376 end_of_line (str);
bfae80f2
RE
8377}
8378
8379static void
a737bd4d 8380do_vfp_sp_dp_cvt (char * str)
bfae80f2
RE
8381{
8382 skip_whitespace (str);
8383
8384 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8385 return;
8386
8387 if (skip_past_comma (&str) == FAIL
8388 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8389 {
8390 if (! inst.error)
8391 inst.error = BAD_ARGS;
8392 return;
8393 }
8394
8395 end_of_line (str);
bfae80f2
RE
8396}
8397
8398/* Thumb specific routines. */
8399
bfae80f2
RE
8400/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
8401 was SUB. */
8402
8403static void
a737bd4d 8404thumb_add_sub (char * str, int subtract)
bfae80f2
RE
8405{
8406 int Rd, Rs, Rn = FAIL;
8407
8408 skip_whitespace (str);
8409
8410 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
8411 || skip_past_comma (&str) == FAIL)
8412 {
8413 if (! inst.error)
8414 inst.error = BAD_ARGS;
8415 return;
8416 }
8417
8418 if (is_immediate_prefix (*str))
8419 {
8420 Rs = Rd;
8421 str++;
8422 if (my_get_expression (&inst.reloc.exp, &str))
8423 return;
8424 }
8425 else
8426 {
8427 if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8428 return;
8429
8430 if (skip_past_comma (&str) == FAIL)
8431 {
8432 /* Two operand format, shuffle the registers
8433 and pretend there are 3. */
8434 Rn = Rs;
8435 Rs = Rd;
8436 }
8437 else if (is_immediate_prefix (*str))
8438 {
8439 str++;
8440 if (my_get_expression (&inst.reloc.exp, &str))
8441 return;
8442 }
8443 else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8444 return;
8445 }
8446
8447 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8448 for the latter case, EXPR contains the immediate that was found. */
8449 if (Rn != FAIL)
8450 {
8451 /* All register format. */
8452 if (Rd > 7 || Rs > 7 || Rn > 7)
8453 {
8454 if (Rs != Rd)
8455 {
8456 inst.error = _("dest and source1 must be the same register");
8457 return;
8458 }
8459
8460 /* Can't do this for SUB. */
8461 if (subtract)
8462 {
8463 inst.error = _("subtract valid only on lo regs");
8464 return;
8465 }
8466
8467 inst.instruction = (T_OPCODE_ADD_HI
8468 | (Rd > 7 ? THUMB_H1 : 0)
8469 | (Rn > 7 ? THUMB_H2 : 0));
8470 inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
8471 }
8472 else
8473 {
8474 inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
8475 inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8476 }
8477 }
8478 else
8479 {
8480 /* Immediate expression, now things start to get nasty. */
8481
8482 /* First deal with HI regs, only very restricted cases allowed:
8483 Adjusting SP, and using PC or SP to get an address. */
8484 if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8485 || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
8486 {
8487 inst.error = _("invalid Hi register with immediate");
8488 return;
8489 }
8490
8491 if (inst.reloc.exp.X_op != O_constant)
8492 {
8493 /* Value isn't known yet, all we can do is store all the fragments
8494 we know about in the instruction and let the reloc hacking
8495 work it all out. */
8496 inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
8497 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8498 }
8499 else
8500 {
8501 int offset = inst.reloc.exp.X_add_number;
8502
8503 if (subtract)
358b94bd 8504 offset = - offset;
bfae80f2
RE
8505
8506 if (offset < 0)
8507 {
358b94bd 8508 offset = - offset;
bfae80f2
RE
8509 subtract = 1;
8510
8511 /* Quick check, in case offset is MIN_INT. */
8512 if (offset < 0)
8513 {
8514 inst.error = _("immediate value out of range");
8515 return;
8516 }
8517 }
358b94bd
NC
8518 /* Note - you cannot convert a subtract of 0 into an
8519 add of 0 because the carry flag is set differently. */
8520 else if (offset > 0)
bfae80f2
RE
8521 subtract = 0;
8522
8523 if (Rd == REG_SP)
8524 {
8525 if (offset & ~0x1fc)
8526 {
8527 inst.error = _("invalid immediate value for stack adjust");
8528 return;
b99bd4ef
NC
8529 }
8530 inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
8531 inst.instruction |= offset >> 2;
8532 }
8533 else if (Rs == REG_PC || Rs == REG_SP)
8534 {
8535 if (subtract
8536 || (offset & ~0x3fc))
8537 {
8538 inst.error = _("invalid immediate for address calculation");
8539 return;
8540 }
8541 inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
8542 : T_OPCODE_ADD_SP);
8543 inst.instruction |= (Rd << 8) | (offset >> 2);
8544 }
8545 else if (Rs == Rd)
8546 {
8547 if (offset & ~0xff)
8548 {
8549 inst.error = _("immediate value out of range");
8550 return;
8551 }
8552 inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
8553 inst.instruction |= (Rd << 8) | offset;
8554 }
8555 else
8556 {
8557 if (offset & ~0x7)
8558 {
8559 inst.error = _("immediate value out of range");
8560 return;
8561 }
8562 inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
8563 inst.instruction |= Rd | (Rs << 3) | (offset << 6);
8564 }
8565 }
8566 }
8567
8568 end_of_line (str);
8569}
8570
8571static void
a737bd4d 8572thumb_shift (char * str, int shift)
b99bd4ef
NC
8573{
8574 int Rd, Rs, Rn = FAIL;
8575
8576 skip_whitespace (str);
8577
8578 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8579 || skip_past_comma (&str) == FAIL)
8580 {
8581 if (! inst.error)
8582 inst.error = BAD_ARGS;
8583 return;
8584 }
8585
8586 if (is_immediate_prefix (*str))
8587 {
8588 /* Two operand immediate format, set Rs to Rd. */
8589 Rs = Rd;
8590 str ++;
8591 if (my_get_expression (&inst.reloc.exp, &str))
8592 return;
8593 }
8594 else
8595 {
8596 if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8597 return;
8598
8599 if (skip_past_comma (&str) == FAIL)
8600 {
8601 /* Two operand format, shuffle the registers
8602 and pretend there are 3. */
8603 Rn = Rs;
8604 Rs = Rd;
8605 }
8606 else if (is_immediate_prefix (*str))
8607 {
8608 str++;
8609 if (my_get_expression (&inst.reloc.exp, &str))
8610 return;
8611 }
8612 else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8613 return;
8614 }
8615
8616 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8617 for the latter case, EXPR contains the immediate that was found. */
8618
8619 if (Rn != FAIL)
8620 {
8621 if (Rs != Rd)
8622 {
8623 inst.error = _("source1 and dest must be same register");
8624 return;
8625 }
8626
8627 switch (shift)
8628 {
8629 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
8630 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
8631 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
8632 }
8633
8634 inst.instruction |= Rd | (Rn << 3);
8635 }
8636 else
8637 {
8638 switch (shift)
8639 {
8640 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
8641 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
8642 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
8643 }
8644
8645 if (inst.reloc.exp.X_op != O_constant)
8646 {
8647 /* Value isn't known yet, create a dummy reloc and let reloc
8648 hacking fix it up. */
8649 inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
8650 }
8651 else
8652 {
8653 unsigned shift_value = inst.reloc.exp.X_add_number;
8654
8655 if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
8656 {
f03698e6 8657 inst.error = _("invalid immediate for shift");
b99bd4ef
NC
8658 return;
8659 }
8660
8661 /* Shifts of zero are handled by converting to LSL. */
8662 if (shift_value == 0)
8663 inst.instruction = T_OPCODE_LSL_I;
8664
8665 /* Shifts of 32 are encoded as a shift of zero. */
8666 if (shift_value == 32)
8667 shift_value = 0;
8668
8669 inst.instruction |= shift_value << 6;
8670 }
8671
8672 inst.instruction |= Rd | (Rs << 3);
8673 }
8674
8675 end_of_line (str);
8676}
8677
8678static void
a737bd4d 8679thumb_load_store (char * str, int load_store, int size)
b99bd4ef
NC
8680{
8681 int Rd, Rb, Ro = FAIL;
8682
8683 skip_whitespace (str);
8684
8685 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8686 || skip_past_comma (&str) == FAIL)
8687 {
8688 if (! inst.error)
8689 inst.error = BAD_ARGS;
8690 return;
8691 }
8692
8693 if (*str == '[')
8694 {
8695 str++;
8696 if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8697 return;
8698
8699 if (skip_past_comma (&str) != FAIL)
8700 {
8701 if (is_immediate_prefix (*str))
8702 {
8703 str++;
8704 if (my_get_expression (&inst.reloc.exp, &str))
8705 return;
8706 }
8707 else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8708 return;
8709 }
8710 else
8711 {
8712 inst.reloc.exp.X_op = O_constant;
8713 inst.reloc.exp.X_add_number = 0;
8714 }
8715
8716 if (*str != ']')
8717 {
8718 inst.error = _("expected ']'");
8719 return;
8720 }
8721 str++;
8722 }
8723 else if (*str == '=')
8724 {
f03698e6
RE
8725 if (load_store != THUMB_LOAD)
8726 {
8727 inst.error = _("invalid pseudo operation");
8728 return;
8729 }
8730
b99bd4ef
NC
8731 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
8732 str++;
8733
8734 skip_whitespace (str);
8735
8736 if (my_get_expression (& inst.reloc.exp, & str))
8737 return;
8738
8739 end_of_line (str);
8740
8741 if ( inst.reloc.exp.X_op != O_constant
8742 && inst.reloc.exp.X_op != O_symbol)
8743 {
8744 inst.error = "Constant expression expected";
8745 return;
8746 }
8747
8748 if (inst.reloc.exp.X_op == O_constant
8749 && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
8750 {
8751 /* This can be done with a mov instruction. */
8752
8753 inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8);
8754 inst.instruction |= inst.reloc.exp.X_add_number;
8755 return;
8756 }
8757
8758 /* Insert into literal pool. */
8759 if (add_to_lit_pool () == FAIL)
8760 {
8761 if (!inst.error)
8762 inst.error = "literal pool insertion failed";
8763 return;
8764 }
8765
8766 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8767 inst.reloc.pc_rel = 1;
8768 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8769 /* Adjust ARM pipeline offset to Thumb. */
8770 inst.reloc.exp.X_add_number += 4;
8771
8772 return;
8773 }
8774 else
8775 {
8776 if (my_get_expression (&inst.reloc.exp, &str))
8777 return;
8778
8779 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8780 inst.reloc.pc_rel = 1;
8781 inst.reloc.exp.X_add_number -= 4; /* Pipeline offset. */
8782 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8783 end_of_line (str);
8784 return;
8785 }
8786
8787 if (Rb == REG_PC || Rb == REG_SP)
8788 {
8789 if (size != THUMB_WORD)
8790 {
8791 inst.error = _("byte or halfword not valid for base register");
8792 return;
8793 }
8794 else if (Rb == REG_PC && load_store != THUMB_LOAD)
8795 {
f03698e6 8796 inst.error = _("r15 based store not allowed");
b99bd4ef
NC
8797 return;
8798 }
8799 else if (Ro != FAIL)
8800 {
f03698e6 8801 inst.error = _("invalid base register for register offset");
b99bd4ef
NC
8802 return;
8803 }
8804
8805 if (Rb == REG_PC)
8806 inst.instruction = T_OPCODE_LDR_PC;
8807 else if (load_store == THUMB_LOAD)
8808 inst.instruction = T_OPCODE_LDR_SP;
8809 else
8810 inst.instruction = T_OPCODE_STR_SP;
8811
8812 inst.instruction |= Rd << 8;
8813 if (inst.reloc.exp.X_op == O_constant)
8814 {
8815 unsigned offset = inst.reloc.exp.X_add_number;
8816
8817 if (offset & ~0x3fc)
8818 {
8819 inst.error = _("invalid offset");
8820 return;
8821 }
8822
8823 inst.instruction |= offset >> 2;
8824 }
8825 else
8826 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8827 }
8828 else if (Rb > 7)
8829 {
8830 inst.error = _("invalid base register in load/store");
8831 return;
8832 }
8833 else if (Ro == FAIL)
8834 {
8835 /* Immediate offset. */
8836 if (size == THUMB_WORD)
8837 inst.instruction = (load_store == THUMB_LOAD
8838 ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
8839 else if (size == THUMB_HALFWORD)
8840 inst.instruction = (load_store == THUMB_LOAD
8841 ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
8842 else
8843 inst.instruction = (load_store == THUMB_LOAD
8844 ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
8845
8846 inst.instruction |= Rd | (Rb << 3);
8847
8848 if (inst.reloc.exp.X_op == O_constant)
8849 {
8850 unsigned offset = inst.reloc.exp.X_add_number;
8851
8852 if (offset & ~(0x1f << size))
8853 {
f03698e6 8854 inst.error = _("invalid offset");
b99bd4ef
NC
8855 return;
8856 }
8857 inst.instruction |= (offset >> size) << 6;
8858 }
8859 else
8860 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8861 }
8862 else
8863 {
8864 /* Register offset. */
8865 if (size == THUMB_WORD)
8866 inst.instruction = (load_store == THUMB_LOAD
8867 ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
8868 else if (size == THUMB_HALFWORD)
8869 inst.instruction = (load_store == THUMB_LOAD
8870 ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
8871 else
8872 inst.instruction = (load_store == THUMB_LOAD
8873 ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
8874
8875 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
8876 }
8877
8878 end_of_line (str);
8879}
8880
404ff6b5
AH
8881/* A register must be given at this point.
8882
404ff6b5
AH
8883 Shift is the place to put it in inst.instruction.
8884
404ff6b5
AH
8885 Restores input start point on err.
8886 Returns the reg#, or FAIL. */
8887
8888static int
a737bd4d 8889mav_reg_required_here (char ** str, int shift, enum arm_reg_type regtype)
404ff6b5 8890{
6c43fab6
RE
8891 int reg;
8892 char *start = *str;
404ff6b5 8893
6c43fab6 8894 if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL)
404ff6b5 8895 {
404ff6b5
AH
8896 if (shift >= 0)
8897 inst.instruction |= reg << shift;
8898
6c43fab6 8899 return reg;
404ff6b5
AH
8900 }
8901
6c43fab6 8902 /* Restore the start point. */
404ff6b5 8903 *str = start;
cc8a6dd0 8904
3631a3c8
NC
8905 /* Try generic coprocessor name if applicable. */
8906 if (regtype == REG_TYPE_MVF ||
8907 regtype == REG_TYPE_MVD ||
8908 regtype == REG_TYPE_MVFX ||
8909 regtype == REG_TYPE_MVDX)
8910 {
8911 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
8912 {
8913 if (shift >= 0)
8914 inst.instruction |= reg << shift;
8915
8916 return reg;
8917 }
8918
8919 /* Restore the start point. */
8920 *str = start;
8921 }
8922
404ff6b5
AH
8923 /* In the few cases where we might be able to accept something else
8924 this error can be overridden. */
6c43fab6 8925 inst.error = _(all_reg_maps[regtype].expected);
cc8a6dd0 8926
404ff6b5
AH
8927 return FAIL;
8928}
8929
a737bd4d
NC
8930/* Cirrus Maverick Instructions. */
8931
8932/* Isnsn like "foo X,Y". */
8933
8934static void
8935do_mav_binops (char * str,
8936 int mode,
8937 enum arm_reg_type reg0,
8938 enum arm_reg_type reg1)
8939{
8940 int shift0, shift1;
8941
8942 shift0 = mode & 0xff;
8943 shift1 = (mode >> 8) & 0xff;
8944
8945 skip_whitespace (str);
8946
8947 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
8948 || skip_past_comma (&str) == FAIL
8949 || mav_reg_required_here (&str, shift1, reg1) == FAIL)
8950 {
8951 if (!inst.error)
8952 inst.error = BAD_ARGS;
8953 }
8954 else
8955 end_of_line (str);
8956}
8957
8958/* Isnsn like "foo X,Y,Z". */
8959
8960static void
8961do_mav_triple (char * str,
8962 int mode,
8963 enum arm_reg_type reg0,
8964 enum arm_reg_type reg1,
8965 enum arm_reg_type reg2)
8966{
8967 int shift0, shift1, shift2;
8968
8969 shift0 = mode & 0xff;
8970 shift1 = (mode >> 8) & 0xff;
8971 shift2 = (mode >> 16) & 0xff;
8972
8973 skip_whitespace (str);
8974
8975 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
8976 || skip_past_comma (&str) == FAIL
8977 || mav_reg_required_here (&str, shift1, reg1) == FAIL
8978 || skip_past_comma (&str) == FAIL
8979 || mav_reg_required_here (&str, shift2, reg2) == FAIL)
8980 {
8981 if (!inst.error)
8982 inst.error = BAD_ARGS;
8983 }
8984 else
8985 end_of_line (str);
8986}
8987
8988/* Wrapper functions. */
8989
8990static void
8991do_mav_binops_1a (char * str)
8992{
8993 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF);
8994}
8995
8996static void
8997do_mav_binops_1b (char * str)
8998{
8999 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD);
9000}
9001
9002static void
9003do_mav_binops_1c (char * str)
9004{
9005 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX);
9006}
9007
9008static void
9009do_mav_binops_1d (char * str)
9010{
9011 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF);
9012}
9013
9014static void
9015do_mav_binops_1e (char * str)
9016{
9017 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD);
9018}
9019
9020static void
9021do_mav_binops_1f (char * str)
9022{
9023 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF);
9024}
9025
9026static void
9027do_mav_binops_1g (char * str)
9028{
9029 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD);
9030}
9031
9032static void
9033do_mav_binops_1h (char * str)
9034{
9035 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX);
9036}
9037
9038static void
9039do_mav_binops_1i (char * str)
9040{
9041 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX);
9042}
9043
9044static void
9045do_mav_binops_1j (char * str)
9046{
9047 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX);
9048}
9049
9050static void
9051do_mav_binops_1k (char * str)
9052{
9053 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX);
9054}
9055
9056static void
9057do_mav_binops_1l (char * str)
9058{
9059 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF);
9060}
9061
9062static void
9063do_mav_binops_1m (char * str)
9064{
9065 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD);
9066}
9067
9068static void
9069do_mav_binops_1n (char * str)
9070{
9071 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX);
9072}
9073
9074static void
9075do_mav_binops_1o (char * str)
9076{
9077 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX);
9078}
9079
9080static void
9081do_mav_binops_2a (char * str)
9082{
9083 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN);
9084}
9085
9086static void
9087do_mav_binops_2b (char * str)
9088{
9089 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN);
9090}
404ff6b5 9091
a737bd4d
NC
9092static void
9093do_mav_binops_2c (char * str)
9094{
9095 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN);
9096}
404ff6b5
AH
9097
9098static void
a737bd4d 9099do_mav_binops_3a (char * str)
6c43fab6 9100{
a737bd4d 9101 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX);
6c43fab6
RE
9102}
9103
9104static void
a737bd4d 9105do_mav_binops_3b (char * str)
6c43fab6 9106{
a737bd4d 9107 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX);
6c43fab6
RE
9108}
9109
9110static void
a737bd4d 9111do_mav_binops_3c (char * str)
404ff6b5 9112{
a737bd4d 9113 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX);
404ff6b5
AH
9114}
9115
9116static void
a737bd4d 9117do_mav_binops_3d (char * str)
404ff6b5 9118{
a737bd4d 9119 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX);
404ff6b5
AH
9120}
9121
9122static void
a737bd4d 9123do_mav_triple_4a (char * str)
404ff6b5 9124{
a737bd4d 9125 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN);
404ff6b5
AH
9126}
9127
9128static void
a737bd4d 9129do_mav_triple_4b (char * str)
404ff6b5 9130{
a737bd4d 9131 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN);
404ff6b5
AH
9132}
9133
9134static void
a737bd4d 9135do_mav_triple_5a (char * str)
404ff6b5 9136{
a737bd4d 9137 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF);
404ff6b5
AH
9138}
9139
9140static void
a737bd4d 9141do_mav_triple_5b (char * str)
404ff6b5 9142{
a737bd4d 9143 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD);
404ff6b5
AH
9144}
9145
6c43fab6 9146static void
a737bd4d 9147do_mav_triple_5c (char * str)
6c43fab6 9148{
a737bd4d 9149 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9150}
9151
9152static void
a737bd4d 9153do_mav_triple_5d (char * str)
6c43fab6 9154{
a737bd4d 9155 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9156}
9157
9158static void
a737bd4d 9159do_mav_triple_5e (char * str)
6c43fab6 9160{
a737bd4d 9161 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF);
6c43fab6
RE
9162}
9163
9164static void
a737bd4d 9165do_mav_triple_5f (char * str)
6c43fab6 9166{
a737bd4d 9167 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD);
6c43fab6
RE
9168}
9169
9170static void
a737bd4d 9171do_mav_triple_5g (char * str)
6c43fab6 9172{
a737bd4d 9173 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9174}
9175
9176static void
a737bd4d 9177do_mav_triple_5h (char * str)
6c43fab6 9178{
a737bd4d 9179 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9180}
9181
a737bd4d
NC
9182/* Isnsn like "foo W,X,Y,Z".
9183 where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */
9184
6c43fab6 9185static void
a737bd4d
NC
9186do_mav_quad (char * str,
9187 int mode,
9188 enum arm_reg_type reg0,
9189 enum arm_reg_type reg1,
9190 enum arm_reg_type reg2,
9191 enum arm_reg_type reg3)
6c43fab6 9192{
a737bd4d
NC
9193 int shift0, shift1, shift2, shift3;
9194
9195 shift0= mode & 0xff;
9196 shift1 = (mode >> 8) & 0xff;
9197 shift2 = (mode >> 16) & 0xff;
9198 shift3 = (mode >> 24) & 0xff;
9199
9200 skip_whitespace (str);
9201
9202 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
9203 || skip_past_comma (&str) == FAIL
9204 || mav_reg_required_here (&str, shift1, reg1) == FAIL
9205 || skip_past_comma (&str) == FAIL
9206 || mav_reg_required_here (&str, shift2, reg2) == FAIL
9207 || skip_past_comma (&str) == FAIL
9208 || mav_reg_required_here (&str, shift3, reg3) == FAIL)
9209 {
9210 if (!inst.error)
9211 inst.error = BAD_ARGS;
9212 }
9213 else
9214 end_of_line (str);
6c43fab6
RE
9215}
9216
9217static void
a737bd4d 9218do_mav_quad_6a (char * str)
6c43fab6 9219{
a737bd4d
NC
9220 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX,
9221 REG_TYPE_MVFX);
6c43fab6
RE
9222}
9223
9224static void
a737bd4d 9225do_mav_quad_6b (char * str)
6c43fab6 9226{
a737bd4d
NC
9227 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX,
9228 REG_TYPE_MVFX);
6c43fab6
RE
9229}
9230
a737bd4d 9231/* cfmvsc32<cond> DSPSC,MVDX[15:0]. */
6c43fab6 9232static void
a737bd4d 9233do_mav_dspsc_1 (char * str)
6c43fab6 9234{
a737bd4d
NC
9235 skip_whitespace (str);
9236
9237 /* cfmvsc32. */
9238 if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL
9239 || skip_past_comma (&str) == FAIL
9240 || mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL)
9241 {
9242 if (!inst.error)
9243 inst.error = BAD_ARGS;
9244
9245 return;
9246 }
9247
9248 end_of_line (str);
6c43fab6
RE
9249}
9250
a737bd4d 9251/* cfmv32sc<cond> MVDX[15:0],DSPSC. */
6c43fab6 9252static void
a737bd4d 9253do_mav_dspsc_2 (char * str)
6c43fab6 9254{
a737bd4d
NC
9255 skip_whitespace (str);
9256
9257 /* cfmv32sc. */
9258 if (mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL
9259 || skip_past_comma (&str) == FAIL
9260 || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL)
9261 {
9262 if (!inst.error)
9263 inst.error = BAD_ARGS;
9264
9265 return;
9266 }
9267
9268 end_of_line (str);
6c43fab6
RE
9269}
9270
a737bd4d
NC
9271/* Maverick shift immediate instructions.
9272 cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
9273 cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */
9274
6c43fab6 9275static void
a737bd4d
NC
9276do_mav_shift (char * str,
9277 enum arm_reg_type reg0,
9278 enum arm_reg_type reg1)
6c43fab6 9279{
a737bd4d
NC
9280 int error;
9281 int imm, neg = 0;
9282
9283 skip_whitespace (str);
9284
9285 error = 0;
9286
9287 if (mav_reg_required_here (&str, 12, reg0) == FAIL
9288 || skip_past_comma (&str) == FAIL
9289 || mav_reg_required_here (&str, 16, reg1) == FAIL
9290 || skip_past_comma (&str) == FAIL)
9291 {
9292 if (!inst.error)
9293 inst.error = BAD_ARGS;
9294 return;
9295 }
9296
9297 /* Calculate the immediate operand.
9298 The operand is a 7bit signed number. */
9299 skip_whitespace (str);
9300
9301 if (*str == '#')
9302 ++str;
9303
9304 if (!ISDIGIT (*str) && *str != '-')
9305 {
9306 inst.error = _("expecting immediate, 7bit operand");
9307 return;
9308 }
9309
9310 if (*str == '-')
9311 {
9312 neg = 1;
9313 ++str;
9314 }
9315
9316 for (imm = 0; *str && ISDIGIT (*str); ++str)
9317 imm = imm * 10 + *str - '0';
9318
9319 if (imm > 64)
9320 {
9321 inst.error = _("immediate out of range");
9322 return;
9323 }
9324
9325 /* Make negative imm's into 7bit signed numbers. */
9326 if (neg)
9327 {
9328 imm = -imm;
9329 imm &= 0x0000007f;
9330 }
9331
9332 /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
9333 Bits 5-7 of the insn should have bits 4-6 of the immediate.
9334 Bit 4 should be 0. */
9335 imm = (imm & 0xf) | ((imm & 0x70) << 1);
9336
9337 inst.instruction |= imm;
9338 end_of_line (str);
6c43fab6
RE
9339}
9340
9341static void
a737bd4d 9342do_mav_shift_1 (char * str)
6c43fab6 9343{
a737bd4d 9344 do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9345}
9346
9347static void
a737bd4d 9348do_mav_shift_2 (char * str)
6c43fab6 9349{
a737bd4d
NC
9350 do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX);
9351}
9352
9353static int
9354mav_parse_offset (char ** str, int * negative)
9355{
9356 char * p = *str;
9357 int offset;
9358
9359 *negative = 0;
9360
9361 skip_whitespace (p);
9362
9363 if (*p == '#')
9364 ++p;
9365
9366 if (*p == '-')
9367 {
9368 *negative = 1;
9369 ++p;
9370 }
9371
9372 if (!ISDIGIT (*p))
9373 {
9374 inst.error = _("offset expected");
9375 return 0;
9376 }
9377
9378 for (offset = 0; *p && ISDIGIT (*p); ++p)
9379 offset = offset * 10 + *p - '0';
9380
9381 if (offset > 0x3fc)
9382 {
9383 inst.error = _("offset out of range");
9384 return 0;
9385 }
9386 if (offset & 0x3)
9387 {
9388 inst.error = _("offset not a multiple of 4");
9389 return 0;
9390 }
9391
9392 *str = p;
9393
9394 return *negative ? -offset : offset;
6c43fab6
RE
9395}
9396
a737bd4d
NC
9397/* Maverick load/store instructions.
9398 <insn><cond> CRd,[Rn,<offset>]{!}.
9399 <insn><cond> CRd,[Rn],<offset>. */
9400
9401static void
9402do_mav_ldst (char * str, enum arm_reg_type reg0)
9403{
9404 int offset, negative;
9405
9406 skip_whitespace (str);
9407
9408 if (mav_reg_required_here (&str, 12, reg0) == FAIL
9409 || skip_past_comma (&str) == FAIL
9410 || *str++ != '['
9411 || reg_required_here (&str, 16) == FAIL)
9412 goto fail_ldst;
9413
9414 if (skip_past_comma (&str) == SUCCESS)
9415 {
9416 /* You are here: "<offset>]{!}". */
9417 inst.instruction |= PRE_INDEX;
9418
9419 offset = mav_parse_offset (&str, &negative);
9420
9421 if (inst.error)
9422 return;
9423
9424 if (*str++ != ']')
9425 {
9426 inst.error = _("missing ]");
9427 return;
9428 }
9429
9430 if (*str == '!')
9431 {
9432 inst.instruction |= WRITE_BACK;
9433 ++str;
9434 }
9435 }
9436 else
9437 {
9438 /* You are here: "], <offset>". */
9439 if (*str++ != ']')
9440 {
9441 inst.error = _("missing ]");
9442 return;
9443 }
9444
9445 if (skip_past_comma (&str) == FAIL
9446 || (offset = mav_parse_offset (&str, &negative), inst.error))
9447 goto fail_ldst;
6c43fab6 9448
a737bd4d
NC
9449 inst.instruction |= CP_T_WB; /* Post indexed, set bit W. */
9450 }
6c43fab6 9451
a737bd4d
NC
9452 if (negative)
9453 offset = -offset;
9454 else
9455 inst.instruction |= CP_T_UD; /* Positive, so set bit U. */
6c43fab6 9456
a737bd4d
NC
9457 inst.instruction |= offset >> 2;
9458 end_of_line (str);
9459 return;
6c43fab6 9460
a737bd4d
NC
9461fail_ldst:
9462 if (!inst.error)
9463 inst.error = BAD_ARGS;
6c43fab6
RE
9464}
9465
9466static void
a737bd4d 9467do_mav_ldst_1 (char * str)
6c43fab6 9468{
a737bd4d 9469 do_mav_ldst (str, REG_TYPE_MVF);
6c43fab6
RE
9470}
9471
9472static void
a737bd4d 9473do_mav_ldst_2 (char * str)
6c43fab6 9474{
a737bd4d 9475 do_mav_ldst (str, REG_TYPE_MVD);
6c43fab6
RE
9476}
9477
9478static void
a737bd4d 9479do_mav_ldst_3 (char * str)
6c43fab6 9480{
a737bd4d 9481 do_mav_ldst (str, REG_TYPE_MVFX);
6c43fab6
RE
9482}
9483
9484static void
a737bd4d 9485do_mav_ldst_4 (char * str)
6c43fab6 9486{
a737bd4d 9487 do_mav_ldst (str, REG_TYPE_MVDX);
6c43fab6
RE
9488}
9489
9490static void
a737bd4d 9491do_t_nop (char * str)
6c43fab6 9492{
a737bd4d
NC
9493 /* Do nothing. */
9494 end_of_line (str);
6c43fab6
RE
9495}
9496
a737bd4d
NC
9497/* Handle the Format 4 instructions that do not have equivalents in other
9498 formats. That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
9499 BIC and MVN. */
6c43fab6
RE
9500
9501static void
a737bd4d 9502do_t_arit (char * str)
6c43fab6 9503{
a737bd4d 9504 int Rd, Rs, Rn;
6c43fab6 9505
6c43fab6
RE
9506 skip_whitespace (str);
9507
a737bd4d 9508 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
6c43fab6 9509 || skip_past_comma (&str) == FAIL
a737bd4d 9510 || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
6c43fab6 9511 {
a737bd4d 9512 inst.error = BAD_ARGS;
6c43fab6
RE
9513 return;
9514 }
9515
a737bd4d 9516 if (skip_past_comma (&str) != FAIL)
6c43fab6 9517 {
a737bd4d
NC
9518 /* Three operand format not allowed for TST, CMN, NEG and MVN.
9519 (It isn't allowed for CMP either, but that isn't handled by this
9520 function.) */
9521 if (inst.instruction == T_OPCODE_TST
9522 || inst.instruction == T_OPCODE_CMN
9523 || inst.instruction == T_OPCODE_NEG
9524 || inst.instruction == T_OPCODE_MVN)
9525 {
9526 inst.error = BAD_ARGS;
9527 return;
9528 }
6c43fab6 9529
a737bd4d
NC
9530 if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9531 return;
9532
9533 if (Rs != Rd)
9534 {
9535 inst.error = _("dest and source1 must be the same register");
9536 return;
9537 }
9538 Rs = Rn;
6c43fab6
RE
9539 }
9540
a737bd4d
NC
9541 if (inst.instruction == T_OPCODE_MUL
9542 && Rs == Rd)
9543 as_tsktsk (_("Rs and Rd must be different in MUL"));
9544
9545 inst.instruction |= Rd | (Rs << 3);
6c43fab6 9546 end_of_line (str);
404ff6b5
AH
9547}
9548
9549static void
a737bd4d 9550do_t_add (char * str)
404ff6b5 9551{
a737bd4d 9552 thumb_add_sub (str, 0);
404ff6b5
AH
9553}
9554
9555static void
a737bd4d 9556do_t_asr (char * str)
404ff6b5 9557{
a737bd4d 9558 thumb_shift (str, THUMB_ASR);
404ff6b5
AH
9559}
9560
9561static void
a737bd4d 9562do_t_branch9 (char * str)
404ff6b5 9563{
a737bd4d
NC
9564 if (my_get_expression (&inst.reloc.exp, &str))
9565 return;
9566 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
9567 inst.reloc.pc_rel = 1;
9568 end_of_line (str);
404ff6b5
AH
9569}
9570
9571static void
a737bd4d 9572do_t_branch12 (char * str)
404ff6b5 9573{
a737bd4d
NC
9574 if (my_get_expression (&inst.reloc.exp, &str))
9575 return;
9576 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
9577 inst.reloc.pc_rel = 1;
9578 end_of_line (str);
404ff6b5
AH
9579}
9580
a737bd4d 9581/* Find the real, Thumb encoded start of a Thumb function. */
404ff6b5 9582
a737bd4d
NC
9583static symbolS *
9584find_real_start (symbolS * symbolP)
404ff6b5 9585{
a737bd4d
NC
9586 char * real_start;
9587 const char * name = S_GET_NAME (symbolP);
9588 symbolS * new_target;
404ff6b5 9589
a737bd4d
NC
9590 /* This definition must agree with the one in gcc/config/arm/thumb.c. */
9591#define STUB_NAME ".real_start_of"
404ff6b5 9592
a737bd4d
NC
9593 if (name == NULL)
9594 abort ();
404ff6b5 9595
a737bd4d
NC
9596 /* Names that start with '.' are local labels, not function entry points.
9597 The compiler may generate BL instructions to these labels because it
9598 needs to perform a branch to a far away location. */
9599 if (name[0] == '.')
9600 return symbolP;
404ff6b5 9601
a737bd4d
NC
9602 real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1);
9603 sprintf (real_start, "%s%s", STUB_NAME, name);
404ff6b5 9604
a737bd4d
NC
9605 new_target = symbol_find (real_start);
9606
9607 if (new_target == NULL)
404ff6b5 9608 {
a737bd4d
NC
9609 as_warn ("Failed to find real start of function: %s\n", name);
9610 new_target = symbolP;
404ff6b5 9611 }
404ff6b5 9612
a737bd4d
NC
9613 free (real_start);
9614
9615 return new_target;
9616}
404ff6b5
AH
9617
9618static void
a737bd4d 9619do_t_branch23 (char * str)
404ff6b5 9620{
a737bd4d
NC
9621 if (my_get_expression (& inst.reloc.exp, & str))
9622 return;
404ff6b5 9623
a737bd4d
NC
9624 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
9625 inst.reloc.pc_rel = 1;
9626 end_of_line (str);
404ff6b5 9627
a737bd4d
NC
9628 /* If the destination of the branch is a defined symbol which does not have
9629 the THUMB_FUNC attribute, then we must be calling a function which has
9630 the (interfacearm) attribute. We look for the Thumb entry point to that
9631 function and change the branch to refer to that function instead. */
9632 if ( inst.reloc.exp.X_op == O_symbol
9633 && inst.reloc.exp.X_add_symbol != NULL
9634 && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
9635 && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
9636 inst.reloc.exp.X_add_symbol =
9637 find_real_start (inst.reloc.exp.X_add_symbol);
404ff6b5
AH
9638}
9639
404ff6b5 9640static void
a737bd4d 9641do_t_bx (char * str)
404ff6b5 9642{
a737bd4d 9643 int reg;
404ff6b5
AH
9644
9645 skip_whitespace (str);
9646
a737bd4d
NC
9647 if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
9648 return;
9649
9650 /* This sets THUMB_H2 from the top bit of reg. */
9651 inst.instruction |= reg << 3;
9652
9653 /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc
9654 should cause the alignment to be checked once it is known. This is
9655 because BX PC only works if the instruction is word aligned. */
9656
9657 end_of_line (str);
404ff6b5
AH
9658}
9659
a737bd4d
NC
9660static void
9661do_t_compare (char * str)
9662{
9663 thumb_mov_compare (str, THUMB_COMPARE);
9664}
404ff6b5
AH
9665
9666static void
a737bd4d 9667do_t_ldmstm (char * str)
404ff6b5 9668{
a737bd4d
NC
9669 int Rb;
9670 long range;
404ff6b5
AH
9671
9672 skip_whitespace (str);
9673
a737bd4d
NC
9674 if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9675 return;
404ff6b5 9676
a737bd4d
NC
9677 if (*str != '!')
9678 as_warn (_("inserted missing '!': load/store multiple always writes back base register"));
9679 else
9680 str++;
9681
9682 if (skip_past_comma (&str) == FAIL
9683 || (range = reg_list (&str)) == FAIL)
404ff6b5 9684 {
a737bd4d 9685 if (! inst.error)
404ff6b5
AH
9686 inst.error = BAD_ARGS;
9687 return;
9688 }
9689
620b81c1 9690 if (inst.reloc.type != BFD_RELOC_UNUSED)
404ff6b5 9691 {
a737bd4d 9692 /* This really doesn't seem worth it. */
620b81c1 9693 inst.reloc.type = BFD_RELOC_UNUSED;
a737bd4d 9694 inst.error = _("expression too complex");
404ff6b5
AH
9695 return;
9696 }
9697
a737bd4d 9698 if (range & ~0xff)
404ff6b5 9699 {
a737bd4d 9700 inst.error = _("only lo-regs valid in load/store multiple");
404ff6b5
AH
9701 return;
9702 }
9703
a737bd4d 9704 inst.instruction |= (Rb << 8) | range;
404ff6b5 9705 end_of_line (str);
404ff6b5
AH
9706}
9707
a737bd4d
NC
9708static void
9709do_t_ldr (char * str)
404ff6b5 9710{
a737bd4d
NC
9711 thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
9712}
404ff6b5 9713
a737bd4d
NC
9714static void
9715do_t_ldrb (char * str)
9716{
9717 thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
9718}
404ff6b5 9719
a737bd4d
NC
9720static void
9721do_t_ldrh (char * str)
9722{
9723 thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
9724}
404ff6b5 9725
a737bd4d
NC
9726static void
9727do_t_lds (char * str)
9728{
9729 int Rd, Rb, Ro;
404ff6b5 9730
a737bd4d 9731 skip_whitespace (str);
404ff6b5 9732
a737bd4d
NC
9733 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9734 || skip_past_comma (&str) == FAIL
9735 || *str++ != '['
9736 || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9737 || skip_past_comma (&str) == FAIL
9738 || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9739 || *str++ != ']')
404ff6b5 9740 {
a737bd4d
NC
9741 if (! inst.error)
9742 inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]");
9743 return;
404ff6b5
AH
9744 }
9745
a737bd4d
NC
9746 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
9747 end_of_line (str);
9748}
404ff6b5 9749
a737bd4d
NC
9750static void
9751do_t_lsl (char * str)
9752{
9753 thumb_shift (str, THUMB_LSL);
9754}
404ff6b5 9755
a737bd4d
NC
9756static void
9757do_t_lsr (char * str)
9758{
9759 thumb_shift (str, THUMB_LSR);
404ff6b5
AH
9760}
9761
a737bd4d
NC
9762static void
9763do_t_mov (char * str)
9764{
9765 thumb_mov_compare (str, THUMB_MOVE);
9766}
404ff6b5
AH
9767
9768static void
a737bd4d 9769do_t_push_pop (char * str)
404ff6b5 9770{
a737bd4d 9771 long range;
404ff6b5
AH
9772
9773 skip_whitespace (str);
9774
a737bd4d 9775 if ((range = reg_list (&str)) == FAIL)
404ff6b5 9776 {
a737bd4d
NC
9777 if (! inst.error)
9778 inst.error = BAD_ARGS;
9779 return;
9780 }
404ff6b5 9781
620b81c1 9782 if (inst.reloc.type != BFD_RELOC_UNUSED)
a737bd4d
NC
9783 {
9784 /* This really doesn't seem worth it. */
620b81c1 9785 inst.reloc.type = BFD_RELOC_UNUSED;
a737bd4d
NC
9786 inst.error = _("expression too complex");
9787 return;
9788 }
404ff6b5 9789
a737bd4d
NC
9790 if (range & ~0xff)
9791 {
9792 if ((inst.instruction == T_OPCODE_PUSH
9793 && (range & ~0xff) == 1 << REG_LR)
9794 || (inst.instruction == T_OPCODE_POP
9795 && (range & ~0xff) == 1 << REG_PC))
404ff6b5 9796 {
a737bd4d
NC
9797 inst.instruction |= THUMB_PP_PC_LR;
9798 range &= 0xff;
404ff6b5 9799 }
a737bd4d 9800 else
404ff6b5 9801 {
a737bd4d 9802 inst.error = _("invalid register list to push/pop instruction");
404ff6b5
AH
9803 return;
9804 }
404ff6b5
AH
9805 }
9806
a737bd4d 9807 inst.instruction |= range;
404ff6b5 9808 end_of_line (str);
a737bd4d 9809}
404ff6b5 9810
a737bd4d
NC
9811static void
9812do_t_str (char * str)
9813{
9814 thumb_load_store (str, THUMB_STORE, THUMB_WORD);
404ff6b5
AH
9815}
9816
b99bd4ef 9817static void
a737bd4d 9818do_t_strb (char * str)
b99bd4ef 9819{
a737bd4d 9820 thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
b99bd4ef
NC
9821}
9822
a737bd4d
NC
9823static void
9824do_t_strh (char * str)
9825{
9826 thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
9827}
b99bd4ef
NC
9828
9829static void
a737bd4d 9830do_t_sub (char * str)
b99bd4ef 9831{
a737bd4d
NC
9832 thumb_add_sub (str, 1);
9833}
b99bd4ef 9834
a737bd4d
NC
9835static void
9836do_t_swi (char * str)
9837{
b99bd4ef
NC
9838 skip_whitespace (str);
9839
a737bd4d
NC
9840 if (my_get_expression (&inst.reloc.exp, &str))
9841 return;
b99bd4ef 9842
a737bd4d
NC
9843 inst.reloc.type = BFD_RELOC_ARM_SWI;
9844 end_of_line (str);
9845}
b99bd4ef 9846
a737bd4d
NC
9847static void
9848do_t_adr (char * str)
9849{
9850 int reg;
b99bd4ef 9851
a737bd4d
NC
9852 /* This is a pseudo-op of the form "adr rd, label" to be converted
9853 into a relative address of the form "add rd, pc, #label-.-4". */
9854 skip_whitespace (str);
9855
9856 /* Store Rd in temporary location inside instruction. */
9857 if ((reg = reg_required_here (&str, 4)) == FAIL
9858 || (reg > 7) /* For Thumb reg must be r0..r7. */
9859 || skip_past_comma (&str) == FAIL
9860 || my_get_expression (&inst.reloc.exp, &str))
9861 {
9862 if (!inst.error)
9863 inst.error = BAD_ARGS;
9864 return;
b99bd4ef
NC
9865 }
9866
a737bd4d
NC
9867 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
9868 inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */
9869 inst.reloc.pc_rel = 1;
9870 inst.instruction |= REG_PC; /* Rd is already placed into the instruction. */
b99bd4ef 9871
b99bd4ef
NC
9872 end_of_line (str);
9873}
9874
9875static void
a737bd4d
NC
9876insert_reg (const struct reg_entry * r,
9877 struct hash_control * htab)
b99bd4ef 9878{
a737bd4d
NC
9879 int len = strlen (r->name) + 2;
9880 char * buf = xmalloc (len);
9881 char * buf2 = xmalloc (len);
9882 int i = 0;
b99bd4ef 9883
a737bd4d
NC
9884#ifdef REGISTER_PREFIX
9885 buf[i++] = REGISTER_PREFIX;
9886#endif
9887
9888 strcpy (buf + i, r->name);
9889
9890 for (i = 0; buf[i]; i++)
9891 buf2[i] = TOUPPER (buf[i]);
9892
9893 buf2[i] = '\0';
9894
9895 hash_insert (htab, buf, (PTR) r);
9896 hash_insert (htab, buf2, (PTR) r);
b99bd4ef
NC
9897}
9898
9899static void
a737bd4d 9900build_reg_hsh (struct reg_map * map)
b99bd4ef 9901{
a737bd4d
NC
9902 const struct reg_entry *r;
9903
9904 if ((map->htab = hash_new ()) == NULL)
9905 as_fatal (_("virtual memory exhausted"));
9906
9907 for (r = map->names; r->name != NULL; r++)
9908 insert_reg (r, map->htab);
b99bd4ef
NC
9909}
9910
9911static void
a737bd4d
NC
9912insert_reg_alias (char * str,
9913 int regnum,
9914 struct hash_control *htab)
b99bd4ef 9915{
a737bd4d
NC
9916 const char * error;
9917 struct reg_entry * new = xmalloc (sizeof (struct reg_entry));
9918 const char * name = xmalloc (strlen (str) + 1);
9919
9920 strcpy ((char *) name, str);
9921
9922 new->name = name;
9923 new->number = regnum;
9924 new->builtin = FALSE;
9925
9926 error = hash_insert (htab, name, (PTR) new);
9927 if (error)
9928 {
9929 as_bad (_("failed to create an alias for %s, reason: %s"),
9930 str, error);
9931 free ((char *) name);
9932 free (new);
9933 }
b99bd4ef
NC
9934}
9935
a737bd4d 9936/* Look for the .req directive. This is of the form:
b99bd4ef 9937
a737bd4d
NC
9938 new_register_name .req existing_register_name
9939
9940 If we find one, or if it looks sufficiently like one that we want to
9941 handle any error here, return non-zero. Otherwise return zero. */
9942
9943static int
9944create_register_alias (char * newname, char * p)
b99bd4ef 9945{
a737bd4d
NC
9946 char * q;
9947 char c;
b99bd4ef 9948
a737bd4d
NC
9949 q = p;
9950 skip_whitespace (q);
b99bd4ef 9951
a737bd4d
NC
9952 c = *p;
9953 *p = '\0';
b99bd4ef 9954
a737bd4d
NC
9955 if (*q && !strncmp (q, ".req ", 5))
9956 {
9957 char *copy_of_str;
9958 char *r;
b99bd4ef 9959
a737bd4d
NC
9960#ifndef IGNORE_OPCODE_CASE
9961 newname = original_case_string;
9962#endif
9963 copy_of_str = newname;
b99bd4ef 9964
a737bd4d
NC
9965 q += 4;
9966 skip_whitespace (q);
b99bd4ef 9967
a737bd4d
NC
9968 for (r = q; *r != '\0'; r++)
9969 if (*r == ' ')
9970 break;
b99bd4ef 9971
a737bd4d
NC
9972 if (r != q)
9973 {
9974 enum arm_reg_type new_type, old_type;
9975 int old_regno;
9976 char d = *r;
b99bd4ef 9977
a737bd4d
NC
9978 *r = '\0';
9979 old_type = arm_reg_parse_any (q);
9980 *r = d;
9981
9982 new_type = arm_reg_parse_any (newname);
9983
9984 if (new_type == REG_TYPE_MAX)
9985 {
9986 if (old_type != REG_TYPE_MAX)
9987 {
9988 old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab);
9989 insert_reg_alias (newname, old_regno,
9990 all_reg_maps[old_type].htab);
9991 }
9992 else
9993 as_warn (_("register '%s' does not exist\n"), q);
9994 }
9995 else if (old_type == REG_TYPE_MAX)
9996 {
9997 as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
9998 copy_of_str, q);
9999 }
10000 else
10001 {
10002 /* Do not warn about redefinitions to the same alias. */
10003 if (new_type != old_type
10004 || (arm_reg_parse (&q, all_reg_maps[old_type].htab)
10005 != arm_reg_parse (&q, all_reg_maps[new_type].htab)))
10006 as_warn (_("ignoring redefinition of register alias '%s'"),
10007 copy_of_str);
10008
10009 }
10010 }
10011 else
10012 as_warn (_("ignoring incomplete .req pseuso op"));
10013
10014 *p = c;
10015 return 1;
10016 }
10017
10018 *p = c;
10019 return 0;
b99bd4ef
NC
10020}
10021
10022static void
a737bd4d 10023set_constant_flonums (void)
b99bd4ef 10024{
a737bd4d 10025 int i;
b99bd4ef 10026
a737bd4d
NC
10027 for (i = 0; i < NUM_FLOAT_VALS; i++)
10028 if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
10029 abort ();
b99bd4ef
NC
10030}
10031
a737bd4d
NC
10032\f
10033static const struct asm_opcode insns[] =
b99bd4ef 10034{
a737bd4d
NC
10035 /* Core ARM Instructions. */
10036 {"and", 0xe0000000, 3, ARM_EXT_V1, do_arit},
10037 {"ands", 0xe0100000, 3, ARM_EXT_V1, do_arit},
10038 {"eor", 0xe0200000, 3, ARM_EXT_V1, do_arit},
10039 {"eors", 0xe0300000, 3, ARM_EXT_V1, do_arit},
10040 {"sub", 0xe0400000, 3, ARM_EXT_V1, do_arit},
10041 {"subs", 0xe0500000, 3, ARM_EXT_V1, do_arit},
10042 {"rsb", 0xe0600000, 3, ARM_EXT_V1, do_arit},
10043 {"rsbs", 0xe0700000, 3, ARM_EXT_V1, do_arit},
10044 {"add", 0xe0800000, 3, ARM_EXT_V1, do_arit},
10045 {"adds", 0xe0900000, 3, ARM_EXT_V1, do_arit},
10046 {"adc", 0xe0a00000, 3, ARM_EXT_V1, do_arit},
10047 {"adcs", 0xe0b00000, 3, ARM_EXT_V1, do_arit},
10048 {"sbc", 0xe0c00000, 3, ARM_EXT_V1, do_arit},
10049 {"sbcs", 0xe0d00000, 3, ARM_EXT_V1, do_arit},
10050 {"rsc", 0xe0e00000, 3, ARM_EXT_V1, do_arit},
10051 {"rscs", 0xe0f00000, 3, ARM_EXT_V1, do_arit},
10052 {"orr", 0xe1800000, 3, ARM_EXT_V1, do_arit},
10053 {"orrs", 0xe1900000, 3, ARM_EXT_V1, do_arit},
10054 {"bic", 0xe1c00000, 3, ARM_EXT_V1, do_arit},
10055 {"bics", 0xe1d00000, 3, ARM_EXT_V1, do_arit},
10056
10057 {"tst", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
10058 {"tsts", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
10059 {"tstp", 0xe110f000, 3, ARM_EXT_V1, do_cmp},
10060 {"teq", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
10061 {"teqs", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
10062 {"teqp", 0xe130f000, 3, ARM_EXT_V1, do_cmp},
10063 {"cmp", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
10064 {"cmps", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
10065 {"cmpp", 0xe150f000, 3, ARM_EXT_V1, do_cmp},
10066 {"cmn", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
10067 {"cmns", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
10068 {"cmnp", 0xe170f000, 3, ARM_EXT_V1, do_cmp},
10069
10070 {"mov", 0xe1a00000, 3, ARM_EXT_V1, do_mov},
10071 {"movs", 0xe1b00000, 3, ARM_EXT_V1, do_mov},
10072 {"mvn", 0xe1e00000, 3, ARM_EXT_V1, do_mov},
10073 {"mvns", 0xe1f00000, 3, ARM_EXT_V1, do_mov},
10074
10075 {"ldr", 0xe4100000, 3, ARM_EXT_V1, do_ldst},
10076 {"ldrb", 0xe4500000, 3, ARM_EXT_V1, do_ldst},
10077 {"ldrt", 0xe4300000, 3, ARM_EXT_V1, do_ldstt},
10078 {"ldrbt", 0xe4700000, 3, ARM_EXT_V1, do_ldstt},
10079 {"str", 0xe4000000, 3, ARM_EXT_V1, do_ldst},
10080 {"strb", 0xe4400000, 3, ARM_EXT_V1, do_ldst},
10081 {"strt", 0xe4200000, 3, ARM_EXT_V1, do_ldstt},
10082 {"strbt", 0xe4600000, 3, ARM_EXT_V1, do_ldstt},
10083
10084 {"stmia", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
10085 {"stmib", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
10086 {"stmda", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
10087 {"stmdb", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
10088 {"stmfd", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
10089 {"stmfa", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
10090 {"stmea", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
10091 {"stmed", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
10092
10093 {"ldmia", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
10094 {"ldmib", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
10095 {"ldmda", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
10096 {"ldmdb", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
10097 {"ldmfd", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
10098 {"ldmfa", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
10099 {"ldmea", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
10100 {"ldmed", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
b99bd4ef 10101
a737bd4d
NC
10102 {"swi", 0xef000000, 3, ARM_EXT_V1, do_swi},
10103#ifdef TE_WINCE
10104 /* XXX This is the wrong place to do this. Think multi-arch. */
10105 {"bl", 0xeb000000, 2, ARM_EXT_V1, do_branch},
10106 {"b", 0xea000000, 1, ARM_EXT_V1, do_branch},
10107#else
10108 {"bl", 0xebfffffe, 2, ARM_EXT_V1, do_branch},
10109 {"b", 0xeafffffe, 1, ARM_EXT_V1, do_branch},
10110#endif
b99bd4ef 10111
a737bd4d
NC
10112 /* Pseudo ops. */
10113 {"adr", 0xe28f0000, 3, ARM_EXT_V1, do_adr},
10114 {"adrl", 0xe28f0000, 3, ARM_EXT_V1, do_adrl},
0dd132b6 10115 {"nop", 0xe1a00000, 3, ARM_EXT_V1, do_nop},
b99bd4ef 10116
a737bd4d
NC
10117 /* ARM 2 multiplies. */
10118 {"mul", 0xe0000090, 3, ARM_EXT_V2, do_mul},
10119 {"muls", 0xe0100090, 3, ARM_EXT_V2, do_mul},
10120 {"mla", 0xe0200090, 3, ARM_EXT_V2, do_mla},
10121 {"mlas", 0xe0300090, 3, ARM_EXT_V2, do_mla},
b99bd4ef 10122
a737bd4d
NC
10123 /* Generic coprocessor instructions. */
10124 {"cdp", 0xee000000, 3, ARM_EXT_V2, do_cdp},
10125 {"ldc", 0xec100000, 3, ARM_EXT_V2, do_lstc},
10126 {"ldcl", 0xec500000, 3, ARM_EXT_V2, do_lstc},
10127 {"stc", 0xec000000, 3, ARM_EXT_V2, do_lstc},
10128 {"stcl", 0xec400000, 3, ARM_EXT_V2, do_lstc},
10129 {"mcr", 0xee000010, 3, ARM_EXT_V2, do_co_reg},
10130 {"mrc", 0xee100010, 3, ARM_EXT_V2, do_co_reg},
b99bd4ef 10131
a737bd4d
NC
10132 /* ARM 3 - swp instructions. */
10133 {"swp", 0xe1000090, 3, ARM_EXT_V2S, do_swap},
10134 {"swpb", 0xe1400090, 3, ARM_EXT_V2S, do_swap},
b99bd4ef 10135
a737bd4d
NC
10136 /* ARM 6 Status register instructions. */
10137 {"mrs", 0xe10f0000, 3, ARM_EXT_V3, do_mrs},
10138 {"msr", 0xe120f000, 3, ARM_EXT_V3, do_msr},
10139 /* ScottB: our code uses 0xe128f000 for msr.
10140 NickC: but this is wrong because the bits 16 through 19 are
10141 handled by the PSR_xxx defines above. */
b99bd4ef 10142
a737bd4d
NC
10143 /* ARM 7M long multiplies. */
10144 {"smull", 0xe0c00090, 5, ARM_EXT_V3M, do_mull},
10145 {"smulls", 0xe0d00090, 5, ARM_EXT_V3M, do_mull},
10146 {"umull", 0xe0800090, 5, ARM_EXT_V3M, do_mull},
10147 {"umulls", 0xe0900090, 5, ARM_EXT_V3M, do_mull},
10148 {"smlal", 0xe0e00090, 5, ARM_EXT_V3M, do_mull},
10149 {"smlals", 0xe0f00090, 5, ARM_EXT_V3M, do_mull},
10150 {"umlal", 0xe0a00090, 5, ARM_EXT_V3M, do_mull},
10151 {"umlals", 0xe0b00090, 5, ARM_EXT_V3M, do_mull},
b99bd4ef 10152
a737bd4d
NC
10153 /* ARM Architecture 4. */
10154 {"ldrh", 0xe01000b0, 3, ARM_EXT_V4, do_ldstv4},
10155 {"ldrsh", 0xe01000f0, 3, ARM_EXT_V4, do_ldstv4},
10156 {"ldrsb", 0xe01000d0, 3, ARM_EXT_V4, do_ldstv4},
10157 {"strh", 0xe00000b0, 3, ARM_EXT_V4, do_ldstv4},
b99bd4ef 10158
a737bd4d
NC
10159 /* ARM Architecture 4T. */
10160 /* Note: bx (and blx) are required on V5, even if the processor does
10161 not support Thumb. */
10162 {"bx", 0xe12fff10, 2, ARM_EXT_V4T | ARM_EXT_V5, do_bx},
b99bd4ef 10163
a737bd4d
NC
10164 /* ARM Architecture 5T. */
10165 /* Note: blx has 2 variants, so the .value is set dynamically.
10166 Only one of the variants has conditional execution. */
10167 {"blx", 0xe0000000, 3, ARM_EXT_V5, do_blx},
10168 {"clz", 0xe16f0f10, 3, ARM_EXT_V5, do_clz},
10169 {"bkpt", 0xe1200070, 0, ARM_EXT_V5, do_bkpt},
10170 {"ldc2", 0xfc100000, 0, ARM_EXT_V5, do_lstc2},
10171 {"ldc2l", 0xfc500000, 0, ARM_EXT_V5, do_lstc2},
10172 {"stc2", 0xfc000000, 0, ARM_EXT_V5, do_lstc2},
10173 {"stc2l", 0xfc400000, 0, ARM_EXT_V5, do_lstc2},
10174 {"cdp2", 0xfe000000, 0, ARM_EXT_V5, do_cdp2},
10175 {"mcr2", 0xfe000010, 0, ARM_EXT_V5, do_co_reg2},
10176 {"mrc2", 0xfe100010, 0, ARM_EXT_V5, do_co_reg2},
b99bd4ef 10177
a737bd4d
NC
10178 /* ARM Architecture 5TExP. */
10179 {"smlabb", 0xe1000080, 6, ARM_EXT_V5ExP, do_smla},
10180 {"smlatb", 0xe10000a0, 6, ARM_EXT_V5ExP, do_smla},
10181 {"smlabt", 0xe10000c0, 6, ARM_EXT_V5ExP, do_smla},
10182 {"smlatt", 0xe10000e0, 6, ARM_EXT_V5ExP, do_smla},
b99bd4ef 10183
a737bd4d
NC
10184 {"smlawb", 0xe1200080, 6, ARM_EXT_V5ExP, do_smla},
10185 {"smlawt", 0xe12000c0, 6, ARM_EXT_V5ExP, do_smla},
b99bd4ef 10186
a737bd4d
NC
10187 {"smlalbb", 0xe1400080, 7, ARM_EXT_V5ExP, do_smlal},
10188 {"smlaltb", 0xe14000a0, 7, ARM_EXT_V5ExP, do_smlal},
10189 {"smlalbt", 0xe14000c0, 7, ARM_EXT_V5ExP, do_smlal},
10190 {"smlaltt", 0xe14000e0, 7, ARM_EXT_V5ExP, do_smlal},
b99bd4ef 10191
a737bd4d
NC
10192 {"smulbb", 0xe1600080, 6, ARM_EXT_V5ExP, do_smul},
10193 {"smultb", 0xe16000a0, 6, ARM_EXT_V5ExP, do_smul},
10194 {"smulbt", 0xe16000c0, 6, ARM_EXT_V5ExP, do_smul},
10195 {"smultt", 0xe16000e0, 6, ARM_EXT_V5ExP, do_smul},
b99bd4ef 10196
a737bd4d
NC
10197 {"smulwb", 0xe12000a0, 6, ARM_EXT_V5ExP, do_smul},
10198 {"smulwt", 0xe12000e0, 6, ARM_EXT_V5ExP, do_smul},
b99bd4ef 10199
a737bd4d
NC
10200 {"qadd", 0xe1000050, 4, ARM_EXT_V5ExP, do_qadd},
10201 {"qdadd", 0xe1400050, 5, ARM_EXT_V5ExP, do_qadd},
10202 {"qsub", 0xe1200050, 4, ARM_EXT_V5ExP, do_qadd},
10203 {"qdsub", 0xe1600050, 5, ARM_EXT_V5ExP, do_qadd},
b99bd4ef 10204
a737bd4d
NC
10205 /* ARM Architecture 5TE. */
10206 {"pld", 0xf450f000, 0, ARM_EXT_V5E, do_pld},
10207 {"ldrd", 0xe00000d0, 3, ARM_EXT_V5E, do_ldrd},
10208 {"strd", 0xe00000f0, 3, ARM_EXT_V5E, do_ldrd},
b99bd4ef 10209
a737bd4d
NC
10210 {"mcrr", 0xec400000, 4, ARM_EXT_V5E, do_co_reg2c},
10211 {"mrrc", 0xec500000, 4, ARM_EXT_V5E, do_co_reg2c},
b99bd4ef 10212
a737bd4d
NC
10213 /* ARM Architecture 5TEJ. */
10214 {"bxj", 0xe12fff20, 3, ARM_EXT_V5J, do_bxj},
b99bd4ef 10215
a737bd4d
NC
10216 /* ARM V6. */
10217 { "cps", 0xf1020000, 0, ARM_EXT_V6, do_cps},
10218 { "cpsie", 0xf1080000, 0, ARM_EXT_V6, do_cpsi},
10219 { "cpsid", 0xf10C0000, 0, ARM_EXT_V6, do_cpsi},
10220 { "ldrex", 0xe1900f9f, 5, ARM_EXT_V6, do_ldrex},
10221 { "mcrr2", 0xfc400000, 0, ARM_EXT_V6, do_co_reg2c},
10222 { "mrrc2", 0xfc500000, 0, ARM_EXT_V6, do_co_reg2c},
10223 { "pkhbt", 0xe6800010, 5, ARM_EXT_V6, do_pkhbt},
10224 { "pkhtb", 0xe6800050, 5, ARM_EXT_V6, do_pkhtb},
10225 { "qadd16", 0xe6200f10, 6, ARM_EXT_V6, do_qadd16},
10226 { "qadd8", 0xe6200f90, 5, ARM_EXT_V6, do_qadd16},
10227 { "qaddsubx", 0xe6200f30, 8, ARM_EXT_V6, do_qadd16},
10228 { "qsub16", 0xe6200f70, 6, ARM_EXT_V6, do_qadd16},
10229 { "qsub8", 0xe6200ff0, 5, ARM_EXT_V6, do_qadd16},
10230 { "qsubaddx", 0xe6200f50, 8, ARM_EXT_V6, do_qadd16},
10231 { "sadd16", 0xe6100f10, 6, ARM_EXT_V6, do_qadd16},
10232 { "sadd8", 0xe6100f90, 5, ARM_EXT_V6, do_qadd16},
10233 { "saddsubx", 0xe6100f30, 8, ARM_EXT_V6, do_qadd16},
10234 { "shadd16", 0xe6300f10, 7, ARM_EXT_V6, do_qadd16},
10235 { "shadd8", 0xe6300f90, 6, ARM_EXT_V6, do_qadd16},
10236 { "shaddsubx", 0xe6300f30, 9, ARM_EXT_V6, do_qadd16},
10237 { "shsub16", 0xe6300f70, 7, ARM_EXT_V6, do_qadd16},
10238 { "shsub8", 0xe6300ff0, 6, ARM_EXT_V6, do_qadd16},
10239 { "shsubaddx", 0xe6300f50, 9, ARM_EXT_V6, do_qadd16},
10240 { "ssub16", 0xe6100f70, 6, ARM_EXT_V6, do_qadd16},
10241 { "ssub8", 0xe6100ff0, 5, ARM_EXT_V6, do_qadd16},
10242 { "ssubaddx", 0xe6100f50, 8, ARM_EXT_V6, do_qadd16},
10243 { "uadd16", 0xe6500f10, 6, ARM_EXT_V6, do_qadd16},
10244 { "uadd8", 0xe6500f90, 5, ARM_EXT_V6, do_qadd16},
10245 { "uaddsubx", 0xe6500f30, 8, ARM_EXT_V6, do_qadd16},
10246 { "uhadd16", 0xe6700f10, 7, ARM_EXT_V6, do_qadd16},
10247 { "uhadd8", 0xe6700f90, 6, ARM_EXT_V6, do_qadd16},
10248 { "uhaddsubx", 0xe6700f30, 9, ARM_EXT_V6, do_qadd16},
10249 { "uhsub16", 0xe6700f70, 7, ARM_EXT_V6, do_qadd16},
10250 { "uhsub8", 0xe6700ff0, 6, ARM_EXT_V6, do_qadd16},
10251 { "uhsubaddx", 0xe6700f50, 9, ARM_EXT_V6, do_qadd16},
10252 { "uqadd16", 0xe6600f10, 7, ARM_EXT_V6, do_qadd16},
10253 { "uqadd8", 0xe6600f90, 6, ARM_EXT_V6, do_qadd16},
10254 { "uqaddsubx", 0xe6600f30, 9, ARM_EXT_V6, do_qadd16},
10255 { "uqsub16", 0xe6600f70, 7, ARM_EXT_V6, do_qadd16},
10256 { "uqsub8", 0xe6600ff0, 6, ARM_EXT_V6, do_qadd16},
10257 { "uqsubaddx", 0xe6600f50, 9, ARM_EXT_V6, do_qadd16},
10258 { "usub16", 0xe6500f70, 6, ARM_EXT_V6, do_qadd16},
10259 { "usub8", 0xe6500ff0, 5, ARM_EXT_V6, do_qadd16},
10260 { "usubaddx", 0xe6500f50, 8, ARM_EXT_V6, do_qadd16},
10261 { "rev", 0xe6bf0f30, 3, ARM_EXT_V6, do_rev},
10262 { "rev16", 0xe6bf0fb0, 5, ARM_EXT_V6, do_rev},
10263 { "revsh", 0xe6ff0fb0, 5, ARM_EXT_V6, do_rev},
10264 { "rfeia", 0xf8900a00, 0, ARM_EXT_V6, do_rfe},
10265 { "rfeib", 0xf9900a00, 0, ARM_EXT_V6, do_rfe},
10266 { "rfeda", 0xf8100a00, 0, ARM_EXT_V6, do_rfe},
10267 { "rfedb", 0xf9100a00, 0, ARM_EXT_V6, do_rfe},
10268 { "rfefd", 0xf8900a00, 0, ARM_EXT_V6, do_rfe},
10269 { "rfefa", 0xf9900a00, 0, ARM_EXT_V6, do_rfe},
10270 { "rfeea", 0xf8100a00, 0, ARM_EXT_V6, do_rfe},
10271 { "rfeed", 0xf9100a00, 0, ARM_EXT_V6, do_rfe},
10272 { "sxtah", 0xe6b00070, 5, ARM_EXT_V6, do_sxtah},
10273 { "sxtab16", 0xe6800070, 7, ARM_EXT_V6, do_sxtah},
10274 { "sxtab", 0xe6a00070, 5, ARM_EXT_V6, do_sxtah},
10275 { "sxth", 0xe6bf0070, 4, ARM_EXT_V6, do_sxth},
10276 { "sxtb16", 0xe68f0070, 6, ARM_EXT_V6, do_sxth},
10277 { "sxtb", 0xe6af0070, 4, ARM_EXT_V6, do_sxth},
10278 { "uxtah", 0xe6f00070, 5, ARM_EXT_V6, do_sxtah},
10279 { "uxtab16", 0xe6c00070, 7, ARM_EXT_V6, do_sxtah},
10280 { "uxtab", 0xe6e00070, 5, ARM_EXT_V6, do_sxtah},
10281 { "uxth", 0xe6ff0070, 4, ARM_EXT_V6, do_sxth},
10282 { "uxtb16", 0xe6cf0070, 6, ARM_EXT_V6, do_sxth},
10283 { "uxtb", 0xe6ef0070, 4, ARM_EXT_V6, do_sxth},
10284 { "sel", 0xe68000b0, 3, ARM_EXT_V6, do_qadd16},
10285 { "setend", 0xf1010000, 0, ARM_EXT_V6, do_setend},
10286 { "smlad", 0xe7000010, 5, ARM_EXT_V6, do_smlad},
10287 { "smladx", 0xe7000030, 6, ARM_EXT_V6, do_smlad},
10288 { "smlald", 0xe7400010, 6, ARM_EXT_V6, do_smlald},
10289 { "smlaldx", 0xe7400030, 7, ARM_EXT_V6, do_smlald},
10290 { "smlsd", 0xe7000050, 5, ARM_EXT_V6, do_smlad},
10291 { "smlsdx", 0xe7000070, 6, ARM_EXT_V6, do_smlad},
10292 { "smlsld", 0xe7400050, 6, ARM_EXT_V6, do_smlald},
10293 { "smlsldx", 0xe7400070, 7, ARM_EXT_V6, do_smlald},
10294 { "smmla", 0xe7500010, 5, ARM_EXT_V6, do_smlad},
10295 { "smmlar", 0xe7500030, 6, ARM_EXT_V6, do_smlad},
10296 { "smmls", 0xe75000d0, 5, ARM_EXT_V6, do_smlad},
10297 { "smmlsr", 0xe75000f0, 6, ARM_EXT_V6, do_smlad},
10298 { "smmul", 0xe750f010, 5, ARM_EXT_V6, do_smmul},
10299 { "smmulr", 0xe750f030, 6, ARM_EXT_V6, do_smmul},
10300 { "smuad", 0xe700f010, 5, ARM_EXT_V6, do_smmul},
10301 { "smuadx", 0xe700f030, 6, ARM_EXT_V6, do_smmul},
10302 { "smusd", 0xe700f050, 5, ARM_EXT_V6, do_smmul},
10303 { "smusdx", 0xe700f070, 6, ARM_EXT_V6, do_smmul},
10304 { "srsia", 0xf8cd0500, 0, ARM_EXT_V6, do_srs},
10305 { "srsib", 0xf9cd0500, 0, ARM_EXT_V6, do_srs},
10306 { "srsda", 0xf84d0500, 0, ARM_EXT_V6, do_srs},
10307 { "srsdb", 0xf94d0500, 0, ARM_EXT_V6, do_srs},
10308 { "ssat", 0xe6a00010, 4, ARM_EXT_V6, do_ssat},
10309 { "ssat16", 0xe6a00f30, 6, ARM_EXT_V6, do_ssat16},
10310 { "strex", 0xe1800f90, 5, ARM_EXT_V6, do_strex},
10311 { "umaal", 0xe0400090, 5, ARM_EXT_V6, do_umaal},
10312 { "usad8", 0xe780f010, 5, ARM_EXT_V6, do_smmul},
10313 { "usada8", 0xe7800010, 6, ARM_EXT_V6, do_smlad},
10314 { "usat", 0xe6e00010, 4, ARM_EXT_V6, do_usat},
10315 { "usat16", 0xe6e00f30, 6, ARM_EXT_V6, do_usat16},
b99bd4ef 10316
0dd132b6
NC
10317 /* ARM V6K. */
10318 { "clrex", 0xf57ff01f, 0, ARM_EXT_V6K, do_empty},
10319 { "ldrexb", 0xe1d00f9f, 6, ARM_EXT_V6K, do_ldrex},
10320 { "ldrexd", 0xe1b00f9f, 6, ARM_EXT_V6K, do_ldrex},
10321 { "ldrexh", 0xe1f00f9f, 6, ARM_EXT_V6K, do_ldrex},
10322 { "sev", 0xe320f004, 3, ARM_EXT_V6K, do_empty},
10323 { "strexb", 0xe1c00f90, 6, ARM_EXT_V6K, do_strex},
10324 { "strexd", 0xe1a00f90, 6, ARM_EXT_V6K, do_strex},
10325 { "strexh", 0xe1e00f90, 6, ARM_EXT_V6K, do_strex},
10326 { "wfe", 0xe320f002, 3, ARM_EXT_V6K, do_empty},
10327 { "wfi", 0xe320f003, 3, ARM_EXT_V6K, do_empty},
10328 { "yield", 0xe320f001, 5, ARM_EXT_V6K, do_empty},
7ed4c4c5 10329
0dd132b6
NC
10330 /* ARM V6Z. */
10331 { "smi", 0xe1600070, 3, ARM_EXT_V6Z, do_smi},
10332
b05fe5cf
ZW
10333 /* ARM V6T2. */
10334 { "bfc", 0xe7c0001f, 3, ARM_EXT_V6T2, do_bfc},
10335 { "bfi", 0xe7c00010, 3, ARM_EXT_V6T2, do_bfi},
10336 { "mls", 0xe0600090, 3, ARM_EXT_V6T2, do_mls},
10337 { "movw", 0xe3000000, 4, ARM_EXT_V6T2, do_mov16},
10338 { "movt", 0xe3400000, 4, ARM_EXT_V6T2, do_mov16},
10339 { "rbit", 0xe3ff0f30, 4, ARM_EXT_V6T2, do_rbit},
10340 { "sbfx", 0xe7a00050, 4, ARM_EXT_V6T2, do_bfx},
10341 { "ubfx", 0xe7e00050, 4, ARM_EXT_V6T2, do_bfx},
10342
10343 { "ldrht", 0xe03000b0, 3, ARM_EXT_V6T2, do_ldsttv4},
10344 { "ldrsht", 0xe03000f0, 3, ARM_EXT_V6T2, do_ldsttv4},
10345 { "ldrsbt", 0xe03000d0, 3, ARM_EXT_V6T2, do_ldsttv4},
10346 { "strht", 0xe02000b0, 3, ARM_EXT_V6T2, do_ldsttv4},
10347
a737bd4d
NC
10348 /* Core FPA instruction set (V1). */
10349 {"wfs", 0xee200110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
10350 {"rfs", 0xee300110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
10351 {"wfc", 0xee400110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
10352 {"rfc", 0xee500110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
b99bd4ef 10353
a737bd4d
NC
10354 {"ldfs", 0xec100100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10355 {"ldfd", 0xec108100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10356 {"ldfe", 0xec500100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10357 {"ldfp", 0xec508100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
b99bd4ef 10358
a737bd4d
NC
10359 {"stfs", 0xec000100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10360 {"stfd", 0xec008100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10361 {"stfe", 0xec400100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10362 {"stfp", 0xec408100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
b99bd4ef 10363
a737bd4d
NC
10364 {"mvfs", 0xee008100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10365 {"mvfsp", 0xee008120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10366 {"mvfsm", 0xee008140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10367 {"mvfsz", 0xee008160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10368 {"mvfd", 0xee008180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10369 {"mvfdp", 0xee0081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10370 {"mvfdm", 0xee0081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10371 {"mvfdz", 0xee0081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10372 {"mvfe", 0xee088100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10373 {"mvfep", 0xee088120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10374 {"mvfem", 0xee088140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10375 {"mvfez", 0xee088160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10376
a737bd4d
NC
10377 {"mnfs", 0xee108100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10378 {"mnfsp", 0xee108120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10379 {"mnfsm", 0xee108140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10380 {"mnfsz", 0xee108160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10381 {"mnfd", 0xee108180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10382 {"mnfdp", 0xee1081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10383 {"mnfdm", 0xee1081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10384 {"mnfdz", 0xee1081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10385 {"mnfe", 0xee188100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10386 {"mnfep", 0xee188120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10387 {"mnfem", 0xee188140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10388 {"mnfez", 0xee188160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10389
a737bd4d
NC
10390 {"abss", 0xee208100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10391 {"abssp", 0xee208120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10392 {"abssm", 0xee208140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10393 {"abssz", 0xee208160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10394 {"absd", 0xee208180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10395 {"absdp", 0xee2081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10396 {"absdm", 0xee2081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10397 {"absdz", 0xee2081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10398 {"abse", 0xee288100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10399 {"absep", 0xee288120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10400 {"absem", 0xee288140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10401 {"absez", 0xee288160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10402
a737bd4d
NC
10403 {"rnds", 0xee308100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10404 {"rndsp", 0xee308120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10405 {"rndsm", 0xee308140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10406 {"rndsz", 0xee308160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10407 {"rndd", 0xee308180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10408 {"rnddp", 0xee3081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10409 {"rnddm", 0xee3081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10410 {"rnddz", 0xee3081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10411 {"rnde", 0xee388100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10412 {"rndep", 0xee388120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10413 {"rndem", 0xee388140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10414 {"rndez", 0xee388160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10415
a737bd4d
NC
10416 {"sqts", 0xee408100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10417 {"sqtsp", 0xee408120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10418 {"sqtsm", 0xee408140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10419 {"sqtsz", 0xee408160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10420 {"sqtd", 0xee408180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10421 {"sqtdp", 0xee4081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10422 {"sqtdm", 0xee4081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10423 {"sqtdz", 0xee4081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10424 {"sqte", 0xee488100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10425 {"sqtep", 0xee488120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10426 {"sqtem", 0xee488140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10427 {"sqtez", 0xee488160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10428
a737bd4d
NC
10429 {"logs", 0xee508100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10430 {"logsp", 0xee508120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10431 {"logsm", 0xee508140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10432 {"logsz", 0xee508160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10433 {"logd", 0xee508180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10434 {"logdp", 0xee5081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10435 {"logdm", 0xee5081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10436 {"logdz", 0xee5081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10437 {"loge", 0xee588100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10438 {"logep", 0xee588120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10439 {"logem", 0xee588140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10440 {"logez", 0xee588160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10441
a737bd4d
NC
10442 {"lgns", 0xee608100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10443 {"lgnsp", 0xee608120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10444 {"lgnsm", 0xee608140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10445 {"lgnsz", 0xee608160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10446 {"lgnd", 0xee608180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10447 {"lgndp", 0xee6081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10448 {"lgndm", 0xee6081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10449 {"lgndz", 0xee6081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10450 {"lgne", 0xee688100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10451 {"lgnep", 0xee688120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10452 {"lgnem", 0xee688140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10453 {"lgnez", 0xee688160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10454
a737bd4d
NC
10455 {"exps", 0xee708100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10456 {"expsp", 0xee708120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10457 {"expsm", 0xee708140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10458 {"expsz", 0xee708160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10459 {"expd", 0xee708180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10460 {"expdp", 0xee7081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10461 {"expdm", 0xee7081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10462 {"expdz", 0xee7081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10463 {"expe", 0xee788100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10464 {"expep", 0xee788120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10465 {"expem", 0xee788140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10466 {"expdz", 0xee788160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10467
a737bd4d
NC
10468 {"sins", 0xee808100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10469 {"sinsp", 0xee808120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10470 {"sinsm", 0xee808140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10471 {"sinsz", 0xee808160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10472 {"sind", 0xee808180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10473 {"sindp", 0xee8081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10474 {"sindm", 0xee8081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10475 {"sindz", 0xee8081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10476 {"sine", 0xee888100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10477 {"sinep", 0xee888120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10478 {"sinem", 0xee888140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10479 {"sinez", 0xee888160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10480
a737bd4d
NC
10481 {"coss", 0xee908100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10482 {"cossp", 0xee908120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10483 {"cossm", 0xee908140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10484 {"cossz", 0xee908160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10485 {"cosd", 0xee908180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10486 {"cosdp", 0xee9081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10487 {"cosdm", 0xee9081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10488 {"cosdz", 0xee9081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10489 {"cose", 0xee988100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10490 {"cosep", 0xee988120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10491 {"cosem", 0xee988140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10492 {"cosez", 0xee988160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10493
a737bd4d
NC
10494 {"tans", 0xeea08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10495 {"tansp", 0xeea08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10496 {"tansm", 0xeea08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10497 {"tansz", 0xeea08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10498 {"tand", 0xeea08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10499 {"tandp", 0xeea081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10500 {"tandm", 0xeea081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10501 {"tandz", 0xeea081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10502 {"tane", 0xeea88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10503 {"tanep", 0xeea88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10504 {"tanem", 0xeea88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10505 {"tanez", 0xeea88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10506
a737bd4d
NC
10507 {"asns", 0xeeb08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10508 {"asnsp", 0xeeb08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10509 {"asnsm", 0xeeb08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10510 {"asnsz", 0xeeb08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10511 {"asnd", 0xeeb08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10512 {"asndp", 0xeeb081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10513 {"asndm", 0xeeb081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10514 {"asndz", 0xeeb081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10515 {"asne", 0xeeb88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10516 {"asnep", 0xeeb88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10517 {"asnem", 0xeeb88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10518 {"asnez", 0xeeb88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10519
a737bd4d
NC
10520 {"acss", 0xeec08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10521 {"acssp", 0xeec08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10522 {"acssm", 0xeec08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10523 {"acssz", 0xeec08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10524 {"acsd", 0xeec08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10525 {"acsdp", 0xeec081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10526 {"acsdm", 0xeec081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10527 {"acsdz", 0xeec081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10528 {"acse", 0xeec88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10529 {"acsep", 0xeec88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10530 {"acsem", 0xeec88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10531 {"acsez", 0xeec88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10532
a737bd4d
NC
10533 {"atns", 0xeed08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10534 {"atnsp", 0xeed08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10535 {"atnsm", 0xeed08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10536 {"atnsz", 0xeed08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10537 {"atnd", 0xeed08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10538 {"atndp", 0xeed081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10539 {"atndm", 0xeed081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10540 {"atndz", 0xeed081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10541 {"atne", 0xeed88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10542 {"atnep", 0xeed88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10543 {"atnem", 0xeed88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10544 {"atnez", 0xeed88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10545
a737bd4d
NC
10546 {"urds", 0xeee08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10547 {"urdsp", 0xeee08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10548 {"urdsm", 0xeee08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10549 {"urdsz", 0xeee08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10550 {"urdd", 0xeee08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10551 {"urddp", 0xeee081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10552 {"urddm", 0xeee081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10553 {"urddz", 0xeee081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10554 {"urde", 0xeee88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10555 {"urdep", 0xeee88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10556 {"urdem", 0xeee88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10557 {"urdez", 0xeee88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10558
a737bd4d
NC
10559 {"nrms", 0xeef08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10560 {"nrmsp", 0xeef08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10561 {"nrmsm", 0xeef08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10562 {"nrmsz", 0xeef08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10563 {"nrmd", 0xeef08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10564 {"nrmdp", 0xeef081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10565 {"nrmdm", 0xeef081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10566 {"nrmdz", 0xeef081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10567 {"nrme", 0xeef88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10568 {"nrmep", 0xeef88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10569 {"nrmem", 0xeef88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10570 {"nrmez", 0xeef88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10571
a737bd4d
NC
10572 {"adfs", 0xee000100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10573 {"adfsp", 0xee000120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10574 {"adfsm", 0xee000140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10575 {"adfsz", 0xee000160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10576 {"adfd", 0xee000180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10577 {"adfdp", 0xee0001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10578 {"adfdm", 0xee0001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10579 {"adfdz", 0xee0001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10580 {"adfe", 0xee080100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10581 {"adfep", 0xee080120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10582 {"adfem", 0xee080140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10583 {"adfez", 0xee080160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10584
a737bd4d
NC
10585 {"sufs", 0xee200100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10586 {"sufsp", 0xee200120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10587 {"sufsm", 0xee200140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10588 {"sufsz", 0xee200160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10589 {"sufd", 0xee200180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10590 {"sufdp", 0xee2001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10591 {"sufdm", 0xee2001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10592 {"sufdz", 0xee2001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10593 {"sufe", 0xee280100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10594 {"sufep", 0xee280120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10595 {"sufem", 0xee280140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10596 {"sufez", 0xee280160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10597
a737bd4d
NC
10598 {"rsfs", 0xee300100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10599 {"rsfsp", 0xee300120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10600 {"rsfsm", 0xee300140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10601 {"rsfsz", 0xee300160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10602 {"rsfd", 0xee300180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10603 {"rsfdp", 0xee3001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10604 {"rsfdm", 0xee3001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10605 {"rsfdz", 0xee3001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10606 {"rsfe", 0xee380100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10607 {"rsfep", 0xee380120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10608 {"rsfem", 0xee380140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10609 {"rsfez", 0xee380160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10610
a737bd4d
NC
10611 {"mufs", 0xee100100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10612 {"mufsp", 0xee100120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10613 {"mufsm", 0xee100140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10614 {"mufsz", 0xee100160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10615 {"mufd", 0xee100180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10616 {"mufdp", 0xee1001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10617 {"mufdm", 0xee1001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10618 {"mufdz", 0xee1001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10619 {"mufe", 0xee180100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10620 {"mufep", 0xee180120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10621 {"mufem", 0xee180140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10622 {"mufez", 0xee180160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10623
a737bd4d
NC
10624 {"dvfs", 0xee400100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10625 {"dvfsp", 0xee400120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10626 {"dvfsm", 0xee400140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10627 {"dvfsz", 0xee400160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10628 {"dvfd", 0xee400180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10629 {"dvfdp", 0xee4001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10630 {"dvfdm", 0xee4001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10631 {"dvfdz", 0xee4001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10632 {"dvfe", 0xee480100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10633 {"dvfep", 0xee480120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10634 {"dvfem", 0xee480140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10635 {"dvfez", 0xee480160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10636
a737bd4d
NC
10637 {"rdfs", 0xee500100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10638 {"rdfsp", 0xee500120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10639 {"rdfsm", 0xee500140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10640 {"rdfsz", 0xee500160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10641 {"rdfd", 0xee500180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10642 {"rdfdp", 0xee5001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10643 {"rdfdm", 0xee5001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10644 {"rdfdz", 0xee5001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10645 {"rdfe", 0xee580100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10646 {"rdfep", 0xee580120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10647 {"rdfem", 0xee580140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10648 {"rdfez", 0xee580160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10649
a737bd4d
NC
10650 {"pows", 0xee600100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10651 {"powsp", 0xee600120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10652 {"powsm", 0xee600140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10653 {"powsz", 0xee600160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10654 {"powd", 0xee600180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10655 {"powdp", 0xee6001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10656 {"powdm", 0xee6001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10657 {"powdz", 0xee6001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10658 {"powe", 0xee680100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10659 {"powep", 0xee680120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10660 {"powem", 0xee680140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10661 {"powez", 0xee680160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10662
a737bd4d
NC
10663 {"rpws", 0xee700100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10664 {"rpwsp", 0xee700120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10665 {"rpwsm", 0xee700140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10666 {"rpwsz", 0xee700160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10667 {"rpwd", 0xee700180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10668 {"rpwdp", 0xee7001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10669 {"rpwdm", 0xee7001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10670 {"rpwdz", 0xee7001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10671 {"rpwe", 0xee780100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10672 {"rpwep", 0xee780120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10673 {"rpwem", 0xee780140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10674 {"rpwez", 0xee780160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10675
a737bd4d
NC
10676 {"rmfs", 0xee800100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10677 {"rmfsp", 0xee800120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10678 {"rmfsm", 0xee800140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10679 {"rmfsz", 0xee800160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10680 {"rmfd", 0xee800180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10681 {"rmfdp", 0xee8001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10682 {"rmfdm", 0xee8001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10683 {"rmfdz", 0xee8001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10684 {"rmfe", 0xee880100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10685 {"rmfep", 0xee880120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10686 {"rmfem", 0xee880140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10687 {"rmfez", 0xee880160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10688
a737bd4d
NC
10689 {"fmls", 0xee900100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10690 {"fmlsp", 0xee900120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10691 {"fmlsm", 0xee900140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10692 {"fmlsz", 0xee900160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10693 {"fmld", 0xee900180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10694 {"fmldp", 0xee9001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10695 {"fmldm", 0xee9001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10696 {"fmldz", 0xee9001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10697 {"fmle", 0xee980100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10698 {"fmlep", 0xee980120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10699 {"fmlem", 0xee980140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10700 {"fmlez", 0xee980160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
6c43fab6 10701
a737bd4d
NC
10702 {"fdvs", 0xeea00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10703 {"fdvsp", 0xeea00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10704 {"fdvsm", 0xeea00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10705 {"fdvsz", 0xeea00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10706 {"fdvd", 0xeea00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10707 {"fdvdp", 0xeea001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10708 {"fdvdm", 0xeea001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10709 {"fdvdz", 0xeea001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10710 {"fdve", 0xeea80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10711 {"fdvep", 0xeea80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10712 {"fdvem", 0xeea80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10713 {"fdvez", 0xeea80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
6c43fab6 10714
a737bd4d
NC
10715 {"frds", 0xeeb00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10716 {"frdsp", 0xeeb00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10717 {"frdsm", 0xeeb00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10718 {"frdsz", 0xeeb00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10719 {"frdd", 0xeeb00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10720 {"frddp", 0xeeb001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10721 {"frddm", 0xeeb001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10722 {"frddz", 0xeeb001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10723 {"frde", 0xeeb80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10724 {"frdep", 0xeeb80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10725 {"frdem", 0xeeb80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10726 {"frdez", 0xeeb80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
6c43fab6 10727
a737bd4d
NC
10728 {"pols", 0xeec00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10729 {"polsp", 0xeec00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10730 {"polsm", 0xeec00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10731 {"polsz", 0xeec00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10732 {"pold", 0xeec00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10733 {"poldp", 0xeec001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10734 {"poldm", 0xeec001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10735 {"poldz", 0xeec001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10736 {"pole", 0xeec80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10737 {"polep", 0xeec80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10738 {"polem", 0xeec80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10739 {"polez", 0xeec80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10740
a737bd4d
NC
10741 {"cmf", 0xee90f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10742 {"cmfe", 0xeed0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10743 {"cnf", 0xeeb0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10744 {"cnfe", 0xeef0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10745 /* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should
10746 not be an optional suffix, but part of the instruction. To be
10747 compatible, we accept either. */
10748 {"cmfe", 0xeed0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
10749 {"cnfe", 0xeef0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
b99bd4ef 10750
a737bd4d
NC
10751 {"flts", 0xee000110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10752 {"fltsp", 0xee000130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10753 {"fltsm", 0xee000150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10754 {"fltsz", 0xee000170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10755 {"fltd", 0xee000190, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10756 {"fltdp", 0xee0001b0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10757 {"fltdm", 0xee0001d0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10758 {"fltdz", 0xee0001f0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10759 {"flte", 0xee080110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10760 {"fltep", 0xee080130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10761 {"fltem", 0xee080150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10762 {"fltez", 0xee080170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
6c43fab6 10763
a737bd4d
NC
10764 /* The implementation of the FIX instruction is broken on some
10765 assemblers, in that it accepts a precision specifier as well as a
10766 rounding specifier, despite the fact that this is meaningless.
10767 To be more compatible, we accept it as well, though of course it
10768 does not set any bits. */
10769 {"fix", 0xee100110, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10770 {"fixp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10771 {"fixm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10772 {"fixz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10773 {"fixsp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10774 {"fixsm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10775 {"fixsz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10776 {"fixdp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10777 {"fixdm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10778 {"fixdz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10779 {"fixep", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10780 {"fixem", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10781 {"fixez", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
6c43fab6 10782
a737bd4d
NC
10783 /* Instructions that were new with the real FPA, call them V2. */
10784 {"lfm", 0xec100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10785 {"lfmfd", 0xec900200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10786 {"lfmea", 0xed100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10787 {"sfm", 0xec000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10788 {"sfmfd", 0xed000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10789 {"sfmea", 0xec800200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
6c43fab6 10790
a737bd4d
NC
10791 /* VFP V1xD (single precision). */
10792 /* Moves and type conversions. */
10793 {"fcpys", 0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10794 {"fmrs", 0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp},
10795 {"fmsr", 0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg},
10796 {"fmstat", 0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty},
10797 {"fsitos", 0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10798 {"fuitos", 0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10799 {"ftosis", 0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10800 {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10801 {"ftouis", 0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10802 {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10803 {"fmrx", 0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl},
10804 {"fmxr", 0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg},
6c43fab6 10805
a737bd4d
NC
10806 /* Memory operations. */
10807 {"flds", 0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
10808 {"fsts", 0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
10809 {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10810 {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10811 {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10812 {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10813 {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10814 {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10815 {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
10816 {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
10817 {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10818 {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10819 {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10820 {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10821 {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10822 {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10823 {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
10824 {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
6c43fab6 10825
a737bd4d
NC
10826 /* Monadic operations. */
10827 {"fabss", 0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10828 {"fnegs", 0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10829 {"fsqrts", 0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
6c43fab6 10830
a737bd4d
NC
10831 /* Dyadic operations. */
10832 {"fadds", 0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10833 {"fsubs", 0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10834 {"fmuls", 0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10835 {"fdivs", 0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10836 {"fmacs", 0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10837 {"fmscs", 0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10838 {"fnmuls", 0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10839 {"fnmacs", 0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10840 {"fnmscs", 0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
6c43fab6 10841
a737bd4d
NC
10842 /* Comparisons. */
10843 {"fcmps", 0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10844 {"fcmpzs", 0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
10845 {"fcmpes", 0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10846 {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
6c43fab6 10847
a737bd4d
NC
10848 /* VFP V1 (Double precision). */
10849 /* Moves and type conversions. */
10850 {"fcpyd", 0xeeb00b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10851 {"fcvtds", 0xeeb70ac0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
10852 {"fcvtsd", 0xeeb70bc0, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10853 {"fmdhr", 0xee200b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
10854 {"fmdlr", 0xee000b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
10855 {"fmrdh", 0xee300b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
10856 {"fmrdl", 0xee100b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
10857 {"fsitod", 0xeeb80bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
10858 {"fuitod", 0xeeb80b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
10859 {"ftosid", 0xeebd0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10860 {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10861 {"ftouid", 0xeebc0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10862 {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
6c43fab6 10863
a737bd4d
NC
10864 /* Memory operations. */
10865 {"fldd", 0xed100b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
10866 {"fstd", 0xed000b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
10867 {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10868 {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10869 {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
10870 {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
10871 {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10872 {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10873 {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
10874 {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
6c43fab6 10875
a737bd4d
NC
10876 /* Monadic operations. */
10877 {"fabsd", 0xeeb00bc0, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10878 {"fnegd", 0xeeb10b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10879 {"fsqrtd", 0xeeb10bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
6c43fab6 10880
a737bd4d
NC
10881 /* Dyadic operations. */
10882 {"faddd", 0xee300b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10883 {"fsubd", 0xee300b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10884 {"fmuld", 0xee200b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10885 {"fdivd", 0xee800b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10886 {"fmacd", 0xee000b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10887 {"fmscd", 0xee100b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10888 {"fnmuld", 0xee200b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10889 {"fnmacd", 0xee000b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10890 {"fnmscd", 0xee100b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
6c43fab6 10891
a737bd4d
NC
10892 /* Comparisons. */
10893 {"fcmpd", 0xeeb40b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10894 {"fcmpzd", 0xeeb50b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
10895 {"fcmped", 0xeeb40bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10896 {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
6c43fab6 10897
a737bd4d
NC
10898 /* VFP V2. */
10899 {"fmsrr", 0xec400a10, 5, FPU_VFP_EXT_V2, do_vfp_sp2_from_reg2},
10900 {"fmrrs", 0xec500a10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_sp2},
10901 {"fmdrr", 0xec400b10, 5, FPU_VFP_EXT_V2, do_vfp_dp_from_reg2},
10902 {"fmrrd", 0xec500b10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_dp},
6c43fab6 10903
a737bd4d
NC
10904 /* Intel XScale extensions to ARM V5 ISA. (All use CP0). */
10905 {"mia", 0xee200010, 3, ARM_CEXT_XSCALE, do_xsc_mia},
10906 {"miaph", 0xee280010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10907 {"miabb", 0xee2c0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10908 {"miabt", 0xee2d0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10909 {"miatb", 0xee2e0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10910 {"miatt", 0xee2f0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10911 {"mar", 0xec400000, 3, ARM_CEXT_XSCALE, do_xsc_mar},
10912 {"mra", 0xec500000, 3, ARM_CEXT_XSCALE, do_xsc_mra},
cc8a6dd0 10913
a737bd4d
NC
10914 /* Intel Wireless MMX technology instructions. */
10915 {"tandcb", 0xee130130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
10916 {"tandch", 0xee530130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
10917 {"tandcw", 0xee930130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
10918 {"tbcstb", 0xee400010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
10919 {"tbcsth", 0xee400050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
10920 {"tbcstw", 0xee400090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
10921 {"textrcb", 0xee130170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
10922 {"textrch", 0xee530170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
10923 {"textrcw", 0xee930170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
10924 {"textrmub", 0xee100070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10925 {"textrmuh", 0xee500070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10926 {"textrmuw", 0xee900070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10927 {"textrmsb", 0xee100078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10928 {"textrmsh", 0xee500078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10929 {"textrmsw", 0xee900078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10930 {"tinsrb", 0xee600010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
10931 {"tinsrh", 0xee600050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
10932 {"tinsrw", 0xee600090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
10933 {"tmcr", 0xee000110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmcr},
10934 {"tmcrr", 0xec400000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmcrr},
10935 {"tmia", 0xee200010, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10936 {"tmiaph", 0xee280010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10937 {"tmiabb", 0xee2c0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10938 {"tmiabt", 0xee2d0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10939 {"tmiatb", 0xee2e0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10940 {"tmiatt", 0xee2f0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10941 {"tmovmskb", 0xee100030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
10942 {"tmovmskh", 0xee500030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
10943 {"tmovmskw", 0xee900030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
10944 {"tmrc", 0xee100110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmrc},
10945 {"tmrrc", 0xec500000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmrrc},
10946 {"torcb", 0xee130150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
10947 {"torch", 0xee530150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
10948 {"torcw", 0xee930150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
10949 {"waccb", 0xee0001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
10950 {"wacch", 0xee4001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
10951 {"waccw", 0xee8001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
10952 {"waddbss", 0xee300180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10953 {"waddb", 0xee000180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10954 {"waddbus", 0xee100180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10955 {"waddhss", 0xee700180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10956 {"waddh", 0xee400180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10957 {"waddhus", 0xee500180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10958 {"waddwss", 0xeeb00180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10959 {"waddw", 0xee800180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10960 {"waddwus", 0xee900180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10961 {"waligni", 0xee000020, 7, ARM_CEXT_IWMMXT, do_iwmmxt_waligni},
10962 {"walignr0", 0xee800020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10963 {"walignr1", 0xee900020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10964 {"walignr2", 0xeea00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10965 {"walignr3", 0xeeb00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10966 {"wand", 0xee200000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10967 {"wandn", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10968 {"wavg2b", 0xee800000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10969 {"wavg2br", 0xee900000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10970 {"wavg2h", 0xeec00000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10971 {"wavg2hr", 0xeed00000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10972 {"wcmpeqb", 0xee000060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10973 {"wcmpeqh", 0xee400060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10974 {"wcmpeqw", 0xee800060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10975 {"wcmpgtub", 0xee100060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10976 {"wcmpgtuh", 0xee500060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10977 {"wcmpgtuw", 0xee900060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10978 {"wcmpgtsb", 0xee300060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10979 {"wcmpgtsh", 0xee700060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10980 {"wcmpgtsw", 0xeeb00060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10981 {"wldrb", 0xec100000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
10982 {"wldrh", 0xec100100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
10983 {"wldrw", 0xec100200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
10984 {"wldrd", 0xec100300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
10985 {"wmacs", 0xee600100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10986 {"wmacsz", 0xee700100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10987 {"wmacu", 0xee400100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10988 {"wmacuz", 0xee500100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10989 {"wmadds", 0xeea00100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10990 {"wmaddu", 0xee800100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10991 {"wmaxsb", 0xee200160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10992 {"wmaxsh", 0xee600160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10993 {"wmaxsw", 0xeea00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10994 {"wmaxub", 0xee000160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10995 {"wmaxuh", 0xee400160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10996 {"wmaxuw", 0xee800160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10997 {"wminsb", 0xee300160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10998 {"wminsh", 0xee700160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10999 {"wminsw", 0xeeb00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11000 {"wminub", 0xee100160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11001 {"wminuh", 0xee500160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11002 {"wminuw", 0xee900160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11003 {"wmov", 0xee000000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wmov},
11004 {"wmulsm", 0xee300100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11005 {"wmulsl", 0xee200100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11006 {"wmulum", 0xee100100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11007 {"wmulul", 0xee000100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11008 {"wor", 0xee000000, 3, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11009 {"wpackhss", 0xee700080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11010 {"wpackhus", 0xee500080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11011 {"wpackwss", 0xeeb00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11012 {"wpackwus", 0xee900080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11013 {"wpackdss", 0xeef00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11014 {"wpackdus", 0xeed00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11015 {"wrorh", 0xee700040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11016 {"wrorhg", 0xee700148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11017 {"wrorw", 0xeeb00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11018 {"wrorwg", 0xeeb00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11019 {"wrord", 0xeef00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11020 {"wrordg", 0xeef00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11021 {"wsadb", 0xee000120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11022 {"wsadbz", 0xee100120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11023 {"wsadh", 0xee400120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11024 {"wsadhz", 0xee500120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11025 {"wshufh", 0xee0001e0, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wshufh},
11026 {"wsllh", 0xee500040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11027 {"wsllhg", 0xee500148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11028 {"wsllw", 0xee900040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11029 {"wsllwg", 0xee900148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11030 {"wslld", 0xeed00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11031 {"wslldg", 0xeed00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11032 {"wsrah", 0xee400040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11033 {"wsrahg", 0xee400148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11034 {"wsraw", 0xee800040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11035 {"wsrawg", 0xee800148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11036 {"wsrad", 0xeec00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11037 {"wsradg", 0xeec00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11038 {"wsrlh", 0xee600040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11039 {"wsrlhg", 0xee600148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11040 {"wsrlw", 0xeea00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11041 {"wsrlwg", 0xeea00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11042 {"wsrld", 0xeee00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11043 {"wsrldg", 0xeee00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11044 {"wstrb", 0xec000000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
11045 {"wstrh", 0xec000100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
11046 {"wstrw", 0xec000200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
11047 {"wstrd", 0xec000300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
11048 {"wsubbss", 0xee3001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11049 {"wsubb", 0xee0001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11050 {"wsubbus", 0xee1001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11051 {"wsubhss", 0xee7001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11052 {"wsubh", 0xee4001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11053 {"wsubhus", 0xee5001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11054 {"wsubwss", 0xeeb001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11055 {"wsubw", 0xee8001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11056 {"wsubwus", 0xee9001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11057 {"wunpckehub", 0xee0000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11058 {"wunpckehuh", 0xee4000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11059 {"wunpckehuw", 0xee8000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11060 {"wunpckehsb", 0xee2000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11061 {"wunpckehsh", 0xee6000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11062 {"wunpckehsw", 0xeea000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11063 {"wunpckihb", 0xee1000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11064 {"wunpckihh", 0xee5000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11065 {"wunpckihw", 0xee9000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11066 {"wunpckelub", 0xee0000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11067 {"wunpckeluh", 0xee4000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11068 {"wunpckeluw", 0xee8000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11069 {"wunpckelsb", 0xee2000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11070 {"wunpckelsh", 0xee6000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11071 {"wunpckelsw", 0xeea000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11072 {"wunpckilb", 0xee1000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11073 {"wunpckilh", 0xee5000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11074 {"wunpckilw", 0xee9000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11075 {"wxor", 0xee100000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11076 {"wzero", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wzero},
b99bd4ef 11077
a737bd4d
NC
11078 /* Cirrus Maverick instructions. */
11079 {"cfldrs", 0xec100400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
11080 {"cfldrd", 0xec500400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
11081 {"cfldr32", 0xec100500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
11082 {"cfldr64", 0xec500500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
11083 {"cfstrs", 0xec000400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
11084 {"cfstrd", 0xec400400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
11085 {"cfstr32", 0xec000500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
11086 {"cfstr64", 0xec400500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
11087 {"cfmvsr", 0xee000450, 6, ARM_CEXT_MAVERICK, do_mav_binops_2a},
11088 {"cfmvrs", 0xee100450, 6, ARM_CEXT_MAVERICK, do_mav_binops_1a},
11089 {"cfmvdlr", 0xee000410, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
11090 {"cfmvrdl", 0xee100410, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
11091 {"cfmvdhr", 0xee000430, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
11092 {"cfmvrdh", 0xee100430, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
11093 {"cfmv64lr", 0xee000510, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
11094 {"cfmvr64l", 0xee100510, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
11095 {"cfmv64hr", 0xee000530, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
11096 {"cfmvr64h", 0xee100530, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
11097 {"cfmval32", 0xee200440, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11098 {"cfmv32al", 0xee100440, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11099 {"cfmvam32", 0xee200460, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11100 {"cfmv32am", 0xee100460, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11101 {"cfmvah32", 0xee200480, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11102 {"cfmv32ah", 0xee100480, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11103 {"cfmva32", 0xee2004a0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11104 {"cfmv32a", 0xee1004a0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11105 {"cfmva64", 0xee2004c0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3c},
11106 {"cfmv64a", 0xee1004c0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3d},
11107 {"cfmvsc32", 0xee2004e0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_1},
11108 {"cfmv32sc", 0xee1004e0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_2},
11109 {"cfcpys", 0xee000400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
11110 {"cfcpyd", 0xee000420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
11111 {"cfcvtsd", 0xee000460, 7, ARM_CEXT_MAVERICK, do_mav_binops_1f},
11112 {"cfcvtds", 0xee000440, 7, ARM_CEXT_MAVERICK, do_mav_binops_1g},
11113 {"cfcvt32s", 0xee000480, 8, ARM_CEXT_MAVERICK, do_mav_binops_1h},
11114 {"cfcvt32d", 0xee0004a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1i},
11115 {"cfcvt64s", 0xee0004c0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1j},
11116 {"cfcvt64d", 0xee0004e0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1k},
11117 {"cfcvts32", 0xee100580, 8, ARM_CEXT_MAVERICK, do_mav_binops_1l},
11118 {"cfcvtd32", 0xee1005a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1m},
11119 {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l},
11120 {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m},
11121 {"cfrshl32", 0xee000550, 8, ARM_CEXT_MAVERICK, do_mav_triple_4a},
11122 {"cfrshl64", 0xee000570, 8, ARM_CEXT_MAVERICK, do_mav_triple_4b},
11123 {"cfsh32", 0xee000500, 6, ARM_CEXT_MAVERICK, do_mav_shift_1},
11124 {"cfsh64", 0xee200500, 6, ARM_CEXT_MAVERICK, do_mav_shift_2},
11125 {"cfcmps", 0xee100490, 6, ARM_CEXT_MAVERICK, do_mav_triple_5a},
11126 {"cfcmpd", 0xee1004b0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5b},
11127 {"cfcmp32", 0xee100590, 7, ARM_CEXT_MAVERICK, do_mav_triple_5c},
11128 {"cfcmp64", 0xee1005b0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5d},
11129 {"cfabss", 0xee300400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
11130 {"cfabsd", 0xee300420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
11131 {"cfnegs", 0xee300440, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
11132 {"cfnegd", 0xee300460, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
11133 {"cfadds", 0xee300480, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
11134 {"cfaddd", 0xee3004a0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
11135 {"cfsubs", 0xee3004c0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
11136 {"cfsubd", 0xee3004e0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
11137 {"cfmuls", 0xee100400, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
11138 {"cfmuld", 0xee100420, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
11139 {"cfabs32", 0xee300500, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
11140 {"cfabs64", 0xee300520, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
11141 {"cfneg32", 0xee300540, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
11142 {"cfneg64", 0xee300560, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
11143 {"cfadd32", 0xee300580, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11144 {"cfadd64", 0xee3005a0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
11145 {"cfsub32", 0xee3005c0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11146 {"cfsub64", 0xee3005e0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
11147 {"cfmul32", 0xee100500, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11148 {"cfmul64", 0xee100520, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
11149 {"cfmac32", 0xee100540, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11150 {"cfmsc32", 0xee100560, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11151 {"cfmadd32", 0xee000600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
11152 {"cfmsub32", 0xee100600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
11153 {"cfmadda32", 0xee200600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
11154 {"cfmsuba32", 0xee300600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
11155};
b99bd4ef 11156
90e4755a 11157/* Iterate over the base tables to create the instruction patterns. */
a737bd4d 11158
90e4755a 11159static void
a737bd4d 11160build_arm_ops_hsh (void)
90e4755a
RE
11161{
11162 unsigned int i;
11163 unsigned int j;
11164 static struct obstack insn_obstack;
11165
11166 obstack_begin (&insn_obstack, 4000);
11167
11168 for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
11169 {
6c43fab6 11170 const struct asm_opcode *insn = insns + i;
90e4755a
RE
11171
11172 if (insn->cond_offset != 0)
11173 {
11174 /* Insn supports conditional execution. Build the varaints
11175 and insert them in the hash table. */
11176 for (j = 0; j < sizeof (conds) / sizeof (struct asm_cond); j++)
11177 {
11178 unsigned len = strlen (insn->template);
11179 struct asm_opcode *new;
11180 char *template;
11181
11182 new = obstack_alloc (&insn_obstack, sizeof (struct asm_opcode));
11183 /* All condition codes are two characters. */
11184 template = obstack_alloc (&insn_obstack, len + 3);
11185
11186 strncpy (template, insn->template, insn->cond_offset);
11187 strcpy (template + insn->cond_offset, conds[j].template);
11188 if (len > insn->cond_offset)
11189 strcpy (template + insn->cond_offset + 2,
11190 insn->template + insn->cond_offset);
11191 new->template = template;
11192 new->cond_offset = 0;
11193 new->variant = insn->variant;
11194 new->parms = insn->parms;
11195 new->value = (insn->value & ~COND_MASK) | conds[j].value;
11196
11197 hash_insert (arm_ops_hsh, new->template, (PTR) new);
11198 }
11199 }
11200 /* Finally, insert the unconditional insn in the table directly;
11201 no need to build a copy. */
11202 hash_insert (arm_ops_hsh, insn->template, (PTR) insn);
11203 }
11204}
11205
a737bd4d
NC
11206\f
11207static const struct thumb_opcode tinsns[] =
11208{
11209 /* Thumb v1 (ARMv4T). */
11210 {"adc", 0x4140, 2, ARM_EXT_V4T, do_t_arit},
11211 {"add", 0x0000, 2, ARM_EXT_V4T, do_t_add},
11212 {"and", 0x4000, 2, ARM_EXT_V4T, do_t_arit},
11213 {"asr", 0x0000, 2, ARM_EXT_V4T, do_t_asr},
11214 {"b", T_OPCODE_BRANCH, 2, ARM_EXT_V4T, do_t_branch12},
11215 {"beq", 0xd0fe, 2, ARM_EXT_V4T, do_t_branch9},
11216 {"bne", 0xd1fe, 2, ARM_EXT_V4T, do_t_branch9},
11217 {"bcs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
11218 {"bhs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
11219 {"bcc", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
11220 {"bul", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
11221 {"blo", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
11222 {"bmi", 0xd4fe, 2, ARM_EXT_V4T, do_t_branch9},
11223 {"bpl", 0xd5fe, 2, ARM_EXT_V4T, do_t_branch9},
11224 {"bvs", 0xd6fe, 2, ARM_EXT_V4T, do_t_branch9},
11225 {"bvc", 0xd7fe, 2, ARM_EXT_V4T, do_t_branch9},
11226 {"bhi", 0xd8fe, 2, ARM_EXT_V4T, do_t_branch9},
11227 {"bls", 0xd9fe, 2, ARM_EXT_V4T, do_t_branch9},
11228 {"bge", 0xdafe, 2, ARM_EXT_V4T, do_t_branch9},
11229 {"blt", 0xdbfe, 2, ARM_EXT_V4T, do_t_branch9},
11230 {"bgt", 0xdcfe, 2, ARM_EXT_V4T, do_t_branch9},
11231 {"ble", 0xddfe, 2, ARM_EXT_V4T, do_t_branch9},
11232 {"bal", 0xdefe, 2, ARM_EXT_V4T, do_t_branch9},
11233 {"bic", 0x4380, 2, ARM_EXT_V4T, do_t_arit},
11234 {"bl", 0xf7fffffe, 4, ARM_EXT_V4T, do_t_branch23},
11235 {"bx", 0x4700, 2, ARM_EXT_V4T, do_t_bx},
11236 {"cmn", T_OPCODE_CMN, 2, ARM_EXT_V4T, do_t_arit},
11237 {"cmp", 0x0000, 2, ARM_EXT_V4T, do_t_compare},
11238 {"eor", 0x4040, 2, ARM_EXT_V4T, do_t_arit},
11239 {"ldmia", 0xc800, 2, ARM_EXT_V4T, do_t_ldmstm},
11240 {"ldr", 0x0000, 2, ARM_EXT_V4T, do_t_ldr},
11241 {"ldrb", 0x0000, 2, ARM_EXT_V4T, do_t_ldrb},
11242 {"ldrh", 0x0000, 2, ARM_EXT_V4T, do_t_ldrh},
11243 {"ldrsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
11244 {"ldrsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
11245 {"ldsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
11246 {"ldsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
11247 {"lsl", 0x0000, 2, ARM_EXT_V4T, do_t_lsl},
11248 {"lsr", 0x0000, 2, ARM_EXT_V4T, do_t_lsr},
11249 {"mov", 0x0000, 2, ARM_EXT_V4T, do_t_mov},
11250 {"mul", T_OPCODE_MUL, 2, ARM_EXT_V4T, do_t_arit},
11251 {"mvn", T_OPCODE_MVN, 2, ARM_EXT_V4T, do_t_arit},
11252 {"neg", T_OPCODE_NEG, 2, ARM_EXT_V4T, do_t_arit},
11253 {"orr", 0x4300, 2, ARM_EXT_V4T, do_t_arit},
11254 {"pop", 0xbc00, 2, ARM_EXT_V4T, do_t_push_pop},
11255 {"push", 0xb400, 2, ARM_EXT_V4T, do_t_push_pop},
11256 {"ror", 0x41c0, 2, ARM_EXT_V4T, do_t_arit},
11257 {"sbc", 0x4180, 2, ARM_EXT_V4T, do_t_arit},
11258 {"stmia", 0xc000, 2, ARM_EXT_V4T, do_t_ldmstm},
11259 {"str", 0x0000, 2, ARM_EXT_V4T, do_t_str},
11260 {"strb", 0x0000, 2, ARM_EXT_V4T, do_t_strb},
11261 {"strh", 0x0000, 2, ARM_EXT_V4T, do_t_strh},
11262 {"swi", 0xdf00, 2, ARM_EXT_V4T, do_t_swi},
11263 {"sub", 0x0000, 2, ARM_EXT_V4T, do_t_sub},
11264 {"tst", T_OPCODE_TST, 2, ARM_EXT_V4T, do_t_arit},
11265 /* Pseudo ops: */
11266 {"adr", 0x0000, 2, ARM_EXT_V4T, do_t_adr},
11267 {"nop", 0x46C0, 2, ARM_EXT_V4T, do_t_nop}, /* mov r8,r8 */
11268 /* Thumb v2 (ARMv5T). */
11269 {"blx", 0, 0, ARM_EXT_V5T, do_t_blx},
11270 {"bkpt", 0xbe00, 2, ARM_EXT_V5T, do_t_bkpt},
11271
11272 /* ARM V6. */
11273 {"cpsie", 0xb660, 2, ARM_EXT_V6, do_t_cps},
11274 {"cpsid", 0xb670, 2, ARM_EXT_V6, do_t_cps},
11275 {"cpy", 0x4600, 2, ARM_EXT_V6, do_t_cpy},
11276 {"rev", 0xba00, 2, ARM_EXT_V6, do_t_arit},
11277 {"rev16", 0xba40, 2, ARM_EXT_V6, do_t_arit},
11278 {"revsh", 0xbac0, 2, ARM_EXT_V6, do_t_arit},
11279 {"setend", 0xb650, 2, ARM_EXT_V6, do_t_setend},
11280 {"sxth", 0xb200, 2, ARM_EXT_V6, do_t_arit},
11281 {"sxtb", 0xb240, 2, ARM_EXT_V6, do_t_arit},
11282 {"uxth", 0xb280, 2, ARM_EXT_V6, do_t_arit},
11283 {"uxtb", 0xb2c0, 2, ARM_EXT_V6, do_t_arit},
885fc257
ZW
11284
11285 /* ARM V6K. */
11286 {"sev", 0xbf40, 2, ARM_EXT_V6K, do_empty},
11287 {"wfe", 0xbf20, 2, ARM_EXT_V6K, do_empty},
11288 {"wfi", 0xbf30, 2, ARM_EXT_V6K, do_empty},
11289 {"yield", 0xbf10, 2, ARM_EXT_V6K, do_empty},
a737bd4d 11290};
5a6c6817 11291
b99bd4ef 11292void
a737bd4d 11293md_begin (void)
b99bd4ef
NC
11294{
11295 unsigned mach;
11296 unsigned int i;
11297
11298 if ( (arm_ops_hsh = hash_new ()) == NULL
11299 || (arm_tops_hsh = hash_new ()) == NULL
11300 || (arm_cond_hsh = hash_new ()) == NULL
11301 || (arm_shift_hsh = hash_new ()) == NULL
b99bd4ef 11302 || (arm_psr_hsh = hash_new ()) == NULL)
f03698e6 11303 as_fatal (_("virtual memory exhausted"));
b99bd4ef 11304
90e4755a 11305 build_arm_ops_hsh ();
b99bd4ef
NC
11306 for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++)
11307 hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i));
11308 for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
11309 hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
11310 for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
11311 hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
11312 for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
11313 hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
11314
6c43fab6
RE
11315 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
11316 build_reg_hsh (all_reg_maps + i);
b99bd4ef
NC
11317
11318 set_constant_flonums ();
11319
03b1477f
RE
11320 /* Set the cpu variant based on the command-line options. We prefer
11321 -mcpu= over -march= if both are set (as for GCC); and we prefer
11322 -mfpu= over any other way of setting the floating point unit.
11323 Use of legacy options with new options are faulted. */
11324 if (legacy_cpu != -1)
11325 {
11326 if (mcpu_cpu_opt != -1 || march_cpu_opt != -1)
11327 as_bad (_("use of old and new-style options to set CPU type"));
11328
11329 mcpu_cpu_opt = legacy_cpu;
11330 }
11331 else if (mcpu_cpu_opt == -1)
11332 mcpu_cpu_opt = march_cpu_opt;
11333
11334 if (legacy_fpu != -1)
11335 {
11336 if (mfpu_opt != -1)
11337 as_bad (_("use of old and new-style options to set FPU type"));
11338
11339 mfpu_opt = legacy_fpu;
11340 }
11341 else if (mfpu_opt == -1)
11342 {
4e7fd91e 11343#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS))
39c2da32
RE
11344 /* Some environments specify a default FPU. If they don't, infer it
11345 from the processor. */
03b1477f
RE
11346 if (mcpu_fpu_opt != -1)
11347 mfpu_opt = mcpu_fpu_opt;
11348 else
11349 mfpu_opt = march_fpu_opt;
39c2da32
RE
11350#else
11351 mfpu_opt = FPU_DEFAULT;
11352#endif
03b1477f
RE
11353 }
11354
11355 if (mfpu_opt == -1)
11356 {
11357 if (mcpu_cpu_opt == -1)
11358 mfpu_opt = FPU_DEFAULT;
11359 else if (mcpu_cpu_opt & ARM_EXT_V5)
11360 mfpu_opt = FPU_ARCH_VFP_V2;
11361 else
11362 mfpu_opt = FPU_ARCH_FPA;
11363 }
11364
11365 if (mcpu_cpu_opt == -1)
11366 mcpu_cpu_opt = CPU_DEFAULT;
11367
11368 cpu_variant = mcpu_cpu_opt | mfpu_opt;
11369
f17c130b 11370#if defined OBJ_COFF || defined OBJ_ELF
b99bd4ef 11371 {
7cc69913
NC
11372 unsigned int flags = 0;
11373
11374#if defined OBJ_ELF
11375 flags = meabi_flags;
d507cf36
PB
11376
11377 switch (meabi_flags)
33a392fb 11378 {
d507cf36 11379 case EF_ARM_EABI_UNKNOWN:
7cc69913 11380#endif
d507cf36
PB
11381 /* Set the flags in the private structure. */
11382 if (uses_apcs_26) flags |= F_APCS26;
11383 if (support_interwork) flags |= F_INTERWORK;
11384 if (uses_apcs_float) flags |= F_APCS_FLOAT;
11385 if (pic_code) flags |= F_PIC;
11386 if ((cpu_variant & FPU_ANY) == FPU_NONE
11387 || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only. */
7cc69913
NC
11388 flags |= F_SOFT_FLOAT;
11389
d507cf36
PB
11390 switch (mfloat_abi_opt)
11391 {
11392 case ARM_FLOAT_ABI_SOFT:
11393 case ARM_FLOAT_ABI_SOFTFP:
11394 flags |= F_SOFT_FLOAT;
11395 break;
33a392fb 11396
d507cf36
PB
11397 case ARM_FLOAT_ABI_HARD:
11398 if (flags & F_SOFT_FLOAT)
11399 as_bad (_("hard-float conflicts with specified fpu"));
11400 break;
11401 }
03b1477f 11402
7cc69913
NC
11403 /* Using VFP conventions (even if soft-float). */
11404 if (cpu_variant & FPU_VFP_EXT_NONE)
11405 flags |= F_VFP_FLOAT;
f17c130b 11406
fde78edd 11407#if defined OBJ_ELF
d507cf36
PB
11408 if (cpu_variant & FPU_ARCH_MAVERICK)
11409 flags |= EF_ARM_MAVERICK_FLOAT;
d507cf36
PB
11410 break;
11411
8cb51566 11412 case EF_ARM_EABI_VER4:
d507cf36
PB
11413 /* No additional flags to set. */
11414 break;
11415
11416 default:
11417 abort ();
11418 }
7cc69913 11419#endif
b99bd4ef
NC
11420 bfd_set_private_flags (stdoutput, flags);
11421
11422 /* We have run out flags in the COFF header to encode the
11423 status of ATPCS support, so instead we create a dummy,
11424 empty, debug section called .arm.atpcs. */
11425 if (atpcs)
11426 {
11427 asection * sec;
11428
11429 sec = bfd_make_section (stdoutput, ".arm.atpcs");
11430
11431 if (sec != NULL)
11432 {
11433 bfd_set_section_flags
11434 (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
11435 bfd_set_section_size (stdoutput, sec, 0);
11436 bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
11437 }
11438 }
7cc69913 11439 }
f17c130b 11440#endif
b99bd4ef
NC
11441
11442 /* Record the CPU type as well. */
11443 switch (cpu_variant & ARM_CPU_MASK)
11444 {
11445 case ARM_2:
11446 mach = bfd_mach_arm_2;
11447 break;
11448
11449 case ARM_3: /* Also ARM_250. */
11450 mach = bfd_mach_arm_2a;
11451 break;
11452
b89dddec
RE
11453 case ARM_6: /* Also ARM_7. */
11454 mach = bfd_mach_arm_3;
11455 break;
11456
b99bd4ef 11457 default:
5a6c6817 11458 mach = bfd_mach_arm_unknown;
b99bd4ef 11459 break;
b99bd4ef
NC
11460 }
11461
11462 /* Catch special cases. */
e16bb312
NC
11463 if (cpu_variant & ARM_CEXT_IWMMXT)
11464 mach = bfd_mach_arm_iWMMXt;
11465 else if (cpu_variant & ARM_CEXT_XSCALE)
b99bd4ef 11466 mach = bfd_mach_arm_XScale;
fde78edd
NC
11467 else if (cpu_variant & ARM_CEXT_MAVERICK)
11468 mach = bfd_mach_arm_ep9312;
b99bd4ef
NC
11469 else if (cpu_variant & ARM_EXT_V5E)
11470 mach = bfd_mach_arm_5TE;
11471 else if (cpu_variant & ARM_EXT_V5)
11472 {
b89dddec 11473 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
11474 mach = bfd_mach_arm_5T;
11475 else
11476 mach = bfd_mach_arm_5;
11477 }
b89dddec 11478 else if (cpu_variant & ARM_EXT_V4)
b99bd4ef 11479 {
b89dddec 11480 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
11481 mach = bfd_mach_arm_4T;
11482 else
11483 mach = bfd_mach_arm_4;
11484 }
b89dddec 11485 else if (cpu_variant & ARM_EXT_V3M)
b99bd4ef
NC
11486 mach = bfd_mach_arm_3M;
11487
11488 bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
11489}
11490
11491/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
11492 for use in the a.out file, and stores them in the array pointed to by buf.
11493 This knows about the endian-ness of the target machine and does
11494 THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
11495 2 (short) and 4 (long) Floating numbers are put out as a series of
11496 LITTLENUMS (shorts, here at least). */
11497
11498void
a737bd4d 11499md_number_to_chars (char * buf, valueT val, int n)
b99bd4ef
NC
11500{
11501 if (target_big_endian)
11502 number_to_chars_bigendian (buf, val, n);
11503 else
11504 number_to_chars_littleendian (buf, val, n);
11505}
11506
11507static valueT
a737bd4d 11508md_chars_to_number (char * buf, int n)
b99bd4ef
NC
11509{
11510 valueT result = 0;
11511 unsigned char * where = (unsigned char *) buf;
11512
11513 if (target_big_endian)
11514 {
11515 while (n--)
11516 {
11517 result <<= 8;
11518 result |= (*where++ & 255);
11519 }
11520 }
11521 else
11522 {
11523 while (n--)
11524 {
11525 result <<= 8;
11526 result |= (where[n] & 255);
11527 }
11528 }
11529
11530 return result;
11531}
11532
11533/* Turn a string in input_line_pointer into a floating point constant
11534 of type TYPE, and store the appropriate bytes in *LITP. The number
11535 of LITTLENUMS emitted is stored in *SIZEP. An error message is
11536 returned, or NULL on OK.
11537
11538 Note that fp constants aren't represent in the normal way on the ARM.
11539 In big endian mode, things are as expected. However, in little endian
11540 mode fp constants are big-endian word-wise, and little-endian byte-wise
11541 within the words. For example, (double) 1.1 in big endian mode is
11542 the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
11543 the byte sequence 99 99 f1 3f 9a 99 99 99.
11544
11545 ??? The format of 12 byte floats is uncertain according to gcc's arm.h. */
11546
11547char *
a737bd4d 11548md_atof (int type, char * litP, int * sizeP)
b99bd4ef
NC
11549{
11550 int prec;
11551 LITTLENUM_TYPE words[MAX_LITTLENUMS];
11552 char *t;
11553 int i;
11554
11555 switch (type)
11556 {
11557 case 'f':
11558 case 'F':
11559 case 's':
11560 case 'S':
11561 prec = 2;
11562 break;
11563
11564 case 'd':
11565 case 'D':
11566 case 'r':
11567 case 'R':
11568 prec = 4;
11569 break;
11570
11571 case 'x':
11572 case 'X':
11573 prec = 6;
11574 break;
11575
11576 case 'p':
11577 case 'P':
11578 prec = 6;
11579 break;
11580
11581 default:
11582 *sizeP = 0;
f03698e6 11583 return _("bad call to MD_ATOF()");
b99bd4ef
NC
11584 }
11585
11586 t = atof_ieee (input_line_pointer, type, words);
11587 if (t)
11588 input_line_pointer = t;
11589 *sizeP = prec * 2;
11590
11591 if (target_big_endian)
11592 {
11593 for (i = 0; i < prec; i++)
11594 {
11595 md_number_to_chars (litP, (valueT) words[i], 2);
11596 litP += 2;
11597 }
11598 }
11599 else
11600 {
bfae80f2
RE
11601 if (cpu_variant & FPU_ARCH_VFP)
11602 for (i = prec - 1; i >= 0; i--)
11603 {
11604 md_number_to_chars (litP, (valueT) words[i], 2);
11605 litP += 2;
11606 }
11607 else
11608 /* For a 4 byte float the order of elements in `words' is 1 0.
11609 For an 8 byte float the order is 1 0 3 2. */
11610 for (i = 0; i < prec; i += 2)
11611 {
11612 md_number_to_chars (litP, (valueT) words[i + 1], 2);
11613 md_number_to_chars (litP + 2, (valueT) words[i], 2);
11614 litP += 4;
11615 }
b99bd4ef
NC
11616 }
11617
11618 return 0;
11619}
11620
11621/* The knowledge of the PC's pipeline offset is built into the insns
11622 themselves. */
11623
11624long
a737bd4d 11625md_pcrel_from (fixS * fixP)
b99bd4ef
NC
11626{
11627 if (fixP->fx_addsy
11628 && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
11629 && fixP->fx_subsy == NULL)
11630 return 0;
11631
11632 if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD))
11633 {
11634 /* PC relative addressing on the Thumb is slightly odd
11635 as the bottom two bits of the PC are forced to zero
11636 for the calculation. */
11637 return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
11638 }
11639
11640#ifdef TE_WINCE
2d2255b5
KH
11641 /* The pattern was adjusted to accommodate CE's off-by-one fixups,
11642 so we un-adjust here to compensate for the accommodation. */
b99bd4ef
NC
11643 return fixP->fx_where + fixP->fx_frag->fr_address + 8;
11644#else
11645 return fixP->fx_where + fixP->fx_frag->fr_address;
11646#endif
11647}
11648
11649/* Round up a section size to the appropriate boundary. */
11650
11651valueT
a737bd4d
NC
11652md_section_align (segT segment ATTRIBUTE_UNUSED,
11653 valueT size)
b99bd4ef
NC
11654{
11655#ifdef OBJ_ELF
11656 return size;
11657#else
11658 /* Round all sects to multiple of 4. */
11659 return (size + 3) & ~3;
11660#endif
11661}
11662
11663/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
11664 Otherwise we have no need to default values of symbols. */
11665
11666symbolS *
a737bd4d 11667md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
b99bd4ef
NC
11668{
11669#ifdef OBJ_ELF
11670 if (name[0] == '_' && name[1] == 'G'
11671 && streq (name, GLOBAL_OFFSET_TABLE_NAME))
11672 {
11673 if (!GOT_symbol)
11674 {
11675 if (symbol_find (name))
11676 as_bad ("GOT already in the symbol table");
11677
11678 GOT_symbol = symbol_new (name, undefined_section,
11679 (valueT) 0, & zero_address_frag);
11680 }
11681
11682 return GOT_symbol;
11683 }
11684#endif
11685
11686 return 0;
11687}
11688
94f592af 11689void
a737bd4d
NC
11690md_apply_fix3 (fixS * fixP,
11691 valueT * valP,
11692 segT seg)
b99bd4ef 11693{
94f592af 11694 offsetT value = * valP;
b99bd4ef
NC
11695 offsetT newval;
11696 unsigned int newimm;
11697 unsigned long temp;
11698 int sign;
11699 char * buf = fixP->fx_where + fixP->fx_frag->fr_literal;
11700 arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data;
11701
620b81c1 11702 assert (fixP->fx_r_type <= BFD_RELOC_UNUSED);
b99bd4ef
NC
11703
11704 /* Note whether this will delete the relocation. */
b99bd4ef 11705 if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
b99bd4ef
NC
11706 fixP->fx_done = 1;
11707
11708 /* If this symbol is in a different section then we need to leave it for
11709 the linker to deal with. Unfortunately, md_pcrel_from can't tell,
11710 so we have to undo it's effects here. */
11711 if (fixP->fx_pcrel)
11712 {
11713 if (fixP->fx_addsy != NULL
11714 && S_IS_DEFINED (fixP->fx_addsy)
11715 && S_GET_SEGMENT (fixP->fx_addsy) != seg)
7f266840 11716 value += md_pcrel_from (fixP);
b99bd4ef
NC
11717 }
11718
11719 /* Remember value for emit_reloc. */
11720 fixP->fx_addnumber = value;
11721
11722 switch (fixP->fx_r_type)
11723 {
620b81c1
JB
11724 case BFD_RELOC_NONE:
11725 /* This will need to go in the object file. */
11726 fixP->fx_done = 0;
11727 break;
11728
b99bd4ef 11729 case BFD_RELOC_ARM_IMMEDIATE:
310ea308
NC
11730 /* We claim that this fixup has been processed here,
11731 even if in fact we generate an error because we do
11732 not have a reloc for it, so tc_gen_reloc will reject it. */
11733 fixP->fx_done = 1;
11734
11735 if (fixP->fx_addsy
11736 && ! S_IS_DEFINED (fixP->fx_addsy))
11737 {
11738 as_bad_where (fixP->fx_file, fixP->fx_line,
11739 _("undefined symbol %s used as an immediate value"),
11740 S_GET_NAME (fixP->fx_addsy));
11741 break;
11742 }
11743
b99bd4ef
NC
11744 newimm = validate_immediate (value);
11745 temp = md_chars_to_number (buf, INSN_SIZE);
11746
11747 /* If the instruction will fail, see if we can fix things up by
11748 changing the opcode. */
11749 if (newimm == (unsigned int) FAIL
11750 && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
11751 {
11752 as_bad_where (fixP->fx_file, fixP->fx_line,
11753 _("invalid constant (%lx) after fixup"),
11754 (unsigned long) value);
11755 break;
11756 }
11757
11758 newimm |= (temp & 0xfffff000);
11759 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
11760 break;
11761
11762 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
11763 {
11764 unsigned int highpart = 0;
11765 unsigned int newinsn = 0xe1a00000; /* nop. */
6189168b 11766
b99bd4ef
NC
11767 newimm = validate_immediate (value);
11768 temp = md_chars_to_number (buf, INSN_SIZE);
11769
11770 /* If the instruction will fail, see if we can fix things up by
11771 changing the opcode. */
11772 if (newimm == (unsigned int) FAIL
11773 && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
11774 {
11775 /* No ? OK - try using two ADD instructions to generate
11776 the value. */
11777 newimm = validate_immediate_twopart (value, & highpart);
11778
11779 /* Yes - then make sure that the second instruction is
11780 also an add. */
11781 if (newimm != (unsigned int) FAIL)
11782 newinsn = temp;
11783 /* Still No ? Try using a negated value. */
11784 else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
11785 temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
11786 /* Otherwise - give up. */
11787 else
11788 {
11789 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11790 _("unable to compute ADRL instructions for PC offset of 0x%lx"),
08df2379 11791 (long) value);
b99bd4ef
NC
11792 break;
11793 }
11794
11795 /* Replace the first operand in the 2nd instruction (which
11796 is the PC) with the destination register. We have
11797 already added in the PC in the first instruction and we
11798 do not want to do it again. */
11799 newinsn &= ~ 0xf0000;
11800 newinsn |= ((newinsn & 0x0f000) << 4);
11801 }
11802
11803 newimm |= (temp & 0xfffff000);
11804 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
11805
11806 highpart |= (newinsn & 0xfffff000);
11807 md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
11808 }
11809 break;
11810
11811 case BFD_RELOC_ARM_OFFSET_IMM:
11812 sign = value >= 0;
11813
11814 if (value < 0)
11815 value = - value;
11816
11817 if (validate_offset_imm (value, 0) == FAIL)
11818 {
11819 as_bad_where (fixP->fx_file, fixP->fx_line,
11820 _("bad immediate value for offset (%ld)"),
11821 (long) value);
11822 break;
11823 }
11824
11825 newval = md_chars_to_number (buf, INSN_SIZE);
11826 newval &= 0xff7ff000;
11827 newval |= value | (sign ? INDEX_UP : 0);
11828 md_number_to_chars (buf, newval, INSN_SIZE);
11829 break;
11830
11831 case BFD_RELOC_ARM_OFFSET_IMM8:
11832 case BFD_RELOC_ARM_HWLITERAL:
11833 sign = value >= 0;
11834
11835 if (value < 0)
11836 value = - value;
11837
11838 if (validate_offset_imm (value, 1) == FAIL)
11839 {
11840 if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
11841 as_bad_where (fixP->fx_file, fixP->fx_line,
11842 _("invalid literal constant: pool needs to be closer"));
11843 else
11844 as_bad (_("bad immediate value for half-word offset (%ld)"),
11845 (long) value);
11846 break;
11847 }
11848
11849 newval = md_chars_to_number (buf, INSN_SIZE);
11850 newval &= 0xff7ff0f0;
11851 newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
11852 md_number_to_chars (buf, newval, INSN_SIZE);
11853 break;
11854
11855 case BFD_RELOC_ARM_LITERAL:
11856 sign = value >= 0;
11857
11858 if (value < 0)
11859 value = - value;
11860
11861 if (validate_offset_imm (value, 0) == FAIL)
11862 {
11863 as_bad_where (fixP->fx_file, fixP->fx_line,
11864 _("invalid literal constant: pool needs to be closer"));
11865 break;
11866 }
11867
11868 newval = md_chars_to_number (buf, INSN_SIZE);
11869 newval &= 0xff7ff000;
11870 newval |= value | (sign ? INDEX_UP : 0);
11871 md_number_to_chars (buf, newval, INSN_SIZE);
11872 break;
11873
11874 case BFD_RELOC_ARM_SHIFT_IMM:
11875 newval = md_chars_to_number (buf, INSN_SIZE);
11876 if (((unsigned long) value) > 32
11877 || (value == 32
11878 && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
11879 {
11880 as_bad_where (fixP->fx_file, fixP->fx_line,
11881 _("shift expression is too large"));
11882 break;
11883 }
11884
11885 if (value == 0)
11886 /* Shifts of zero must be done as lsl. */
11887 newval &= ~0x60;
11888 else if (value == 32)
11889 value = 0;
11890 newval &= 0xfffff07f;
11891 newval |= (value & 0x1f) << 7;
11892 md_number_to_chars (buf, newval, INSN_SIZE);
11893 break;
11894
0dd132b6
NC
11895 case BFD_RELOC_ARM_SMI:
11896 if (((unsigned long) value) > 0xffff)
11897 as_bad_where (fixP->fx_file, fixP->fx_line,
11898 _("invalid smi expression"));
11899 newval = md_chars_to_number (buf, INSN_SIZE) & 0xfff000f0;
11900 newval |= (value & 0xf) | ((value & 0xfff0) << 4);
11901 md_number_to_chars (buf, newval, INSN_SIZE);
11902 break;
11903
b99bd4ef
NC
11904 case BFD_RELOC_ARM_SWI:
11905 if (arm_data->thumb_mode)
11906 {
11907 if (((unsigned long) value) > 0xff)
11908 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11909 _("invalid swi expression"));
b99bd4ef
NC
11910 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
11911 newval |= value;
11912 md_number_to_chars (buf, newval, THUMB_SIZE);
11913 }
11914 else
11915 {
11916 if (((unsigned long) value) > 0x00ffffff)
11917 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11918 _("invalid swi expression"));
b99bd4ef
NC
11919 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
11920 newval |= value;
11921 md_number_to_chars (buf, newval, INSN_SIZE);
11922 }
11923 break;
11924
11925 case BFD_RELOC_ARM_MULTI:
11926 if (((unsigned long) value) > 0xffff)
11927 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11928 _("invalid expression in load/store multiple"));
b99bd4ef
NC
11929 newval = value | md_chars_to_number (buf, INSN_SIZE);
11930 md_number_to_chars (buf, newval, INSN_SIZE);
11931 break;
11932
11933 case BFD_RELOC_ARM_PCREL_BRANCH:
11934 newval = md_chars_to_number (buf, INSN_SIZE);
11935
11936 /* Sign-extend a 24-bit number. */
11937#define SEXT24(x) ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
11938
11939#ifdef OBJ_ELF
7f266840 11940 value = fixP->fx_offset;
b99bd4ef
NC
11941#endif
11942
11943 /* We are going to store value (shifted right by two) in the
11944 instruction, in a 24 bit, signed field. Thus we need to check
11945 that none of the top 8 bits of the shifted value (top 7 bits of
11946 the unshifted, unsigned value) are set, or that they are all set. */
11947 if ((value & ~ ((offsetT) 0x1ffffff)) != 0
11948 && ((value & ~ ((offsetT) 0x1ffffff)) != ~ ((offsetT) 0x1ffffff)))
11949 {
11950#ifdef OBJ_ELF
11951 /* Normally we would be stuck at this point, since we cannot store
11952 the absolute address that is the destination of the branch in the
11953 24 bits of the branch instruction. If however, we happen to know
11954 that the destination of the branch is in the same section as the
2d2255b5 11955 branch instruction itself, then we can compute the relocation for
b99bd4ef
NC
11956 ourselves and not have to bother the linker with it.
11957
7f266840
DJ
11958 FIXME: The test for OBJ_ELF is only here because I have not
11959 worked out how to do this for OBJ_COFF. */
11960 if (fixP->fx_addsy != NULL
b99bd4ef
NC
11961 && S_IS_DEFINED (fixP->fx_addsy)
11962 && S_GET_SEGMENT (fixP->fx_addsy) == seg)
11963 {
11964 /* Get pc relative value to go into the branch. */
94f592af 11965 value = * valP;
b99bd4ef
NC
11966
11967 /* Permit a backward branch provided that enough bits
11968 are set. Allow a forwards branch, provided that
11969 enough bits are clear. */
11970 if ( (value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff)
11971 || (value & ~ ((offsetT) 0x1ffffff)) == 0)
11972 fixP->fx_done = 1;
11973 }
11974
11975 if (! fixP->fx_done)
11976#endif
11977 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11978 _("GAS can't handle same-section branch dest >= 0x04000000"));
b99bd4ef
NC
11979 }
11980
11981 value >>= 2;
11982 value += SEXT24 (newval);
11983
11984 if ( (value & ~ ((offsetT) 0xffffff)) != 0
11985 && ((value & ~ ((offsetT) 0xffffff)) != ~ ((offsetT) 0xffffff)))
11986 as_bad_where (fixP->fx_file, fixP->fx_line,
11987 _("out of range branch"));
11988
4e7fd91e
PB
11989 if (seg->use_rela_p && !fixP->fx_done)
11990 {
11991 /* Must unshift the value before storing it in the addend. */
11992 value <<= 2;
11993#ifdef OBJ_ELF
11994 fixP->fx_offset = value;
11995#endif
11996 fixP->fx_addnumber = value;
11997 newval = newval & 0xff000000;
11998 }
11999 else
12000 newval = (value & 0x00ffffff) | (newval & 0xff000000);
b99bd4ef
NC
12001 md_number_to_chars (buf, newval, INSN_SIZE);
12002 break;
12003
12004 case BFD_RELOC_ARM_PCREL_BLX:
12005 {
12006 offsetT hbit;
12007 newval = md_chars_to_number (buf, INSN_SIZE);
12008
12009#ifdef OBJ_ELF
7f266840 12010 value = fixP->fx_offset;
b99bd4ef
NC
12011#endif
12012 hbit = (value >> 1) & 1;
12013 value = (value >> 2) & 0x00ffffff;
12014 value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
4e7fd91e
PB
12015
12016 if (seg->use_rela_p && !fixP->fx_done)
12017 {
12018 /* Must sign-extend and unshift the value before storing
12019 it in the addend. */
12020 value = SEXT24 (value);
12021 value = (value << 2) | hbit;
12022#ifdef OBJ_ELF
12023 fixP->fx_offset = value;
12024#endif
12025 fixP->fx_addnumber = value;
12026 newval = newval & 0xfe000000;
12027 }
12028 else
12029 newval = value | (newval & 0xfe000000) | (hbit << 24);
b99bd4ef
NC
12030 md_number_to_chars (buf, newval, INSN_SIZE);
12031 }
12032 break;
12033
12034 case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
12035 newval = md_chars_to_number (buf, THUMB_SIZE);
12036 {
12037 addressT diff = (newval & 0xff) << 1;
12038 if (diff & 0x100)
12039 diff |= ~0xff;
12040
12041 value += diff;
12042 if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
12043 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12044 _("branch out of range"));
4e7fd91e
PB
12045 if (seg->use_rela_p && !fixP->fx_done)
12046 {
12047#ifdef OBJ_ELF
12048 fixP->fx_offset = value;
12049#endif
12050 fixP->fx_addnumber = value;
12051 newval = newval & 0xff00;
12052 }
12053 else
12054 newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
b99bd4ef
NC
12055 }
12056 md_number_to_chars (buf, newval, THUMB_SIZE);
12057 break;
12058
12059 case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch. */
12060 newval = md_chars_to_number (buf, THUMB_SIZE);
12061 {
12062 addressT diff = (newval & 0x7ff) << 1;
12063 if (diff & 0x800)
12064 diff |= ~0x7ff;
12065
12066 value += diff;
12067 if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
12068 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12069 _("branch out of range"));
4e7fd91e
PB
12070 if (seg->use_rela_p && !fixP->fx_done)
12071 {
12072#ifdef OBJ_ELF
12073 fixP->fx_offset = value;
12074#endif
12075 fixP->fx_addnumber = value;
12076 newval = newval & 0xf800;
12077 }
12078 else
12079 newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
b99bd4ef
NC
12080 }
12081 md_number_to_chars (buf, newval, THUMB_SIZE);
12082 break;
12083
12084 case BFD_RELOC_THUMB_PCREL_BLX:
12085 case BFD_RELOC_THUMB_PCREL_BRANCH23:
12086 {
12087 offsetT newval2;
12088 addressT diff;
12089
12090 newval = md_chars_to_number (buf, THUMB_SIZE);
12091 newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
12092 diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
12093 if (diff & 0x400000)
12094 diff |= ~0x3fffff;
12095#ifdef OBJ_ELF
12096 value = fixP->fx_offset;
12097#endif
12098 value += diff;
c62e1cc3 12099
b99bd4ef
NC
12100 if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
12101 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12102 _("branch with link out of range"));
b99bd4ef 12103
b99bd4ef 12104 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
c62e1cc3
NC
12105 /* For a BLX instruction, make sure that the relocation is rounded up
12106 to a word boundary. This follows the semantics of the instruction
12107 which specifies that bit 1 of the target address will come from bit
12108 1 of the base address. */
4e7fd91e
PB
12109 value = (value + 1) & ~ 1;
12110
12111 if (seg->use_rela_p && !fixP->fx_done)
12112 {
12113#ifdef OBJ_ELF
12114 fixP->fx_offset = value;
12115#endif
12116 fixP->fx_addnumber = value;
12117 newval = newval & 0xf800;
12118 newval2 = newval2 & 0xf800;
12119 }
12120 else
12121 {
12122 newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
12123 newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
12124 }
b99bd4ef
NC
12125 md_number_to_chars (buf, newval, THUMB_SIZE);
12126 md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
12127 }
12128 break;
12129
12130 case BFD_RELOC_8:
4e7fd91e
PB
12131 if (seg->use_rela_p && !fixP->fx_done)
12132 break;
b99bd4ef
NC
12133 if (fixP->fx_done || fixP->fx_pcrel)
12134 md_number_to_chars (buf, value, 1);
12135#ifdef OBJ_ELF
7f266840 12136 else
b99bd4ef
NC
12137 {
12138 value = fixP->fx_offset;
12139 md_number_to_chars (buf, value, 1);
12140 }
12141#endif
12142 break;
12143
12144 case BFD_RELOC_16:
4e7fd91e
PB
12145 if (seg->use_rela_p && !fixP->fx_done)
12146 break;
b99bd4ef
NC
12147 if (fixP->fx_done || fixP->fx_pcrel)
12148 md_number_to_chars (buf, value, 2);
12149#ifdef OBJ_ELF
7f266840 12150 else
b99bd4ef
NC
12151 {
12152 value = fixP->fx_offset;
12153 md_number_to_chars (buf, value, 2);
12154 }
12155#endif
12156 break;
12157
12158#ifdef OBJ_ELF
ba93b8ac
DJ
12159 case BFD_RELOC_ARM_TLS_GD32:
12160 case BFD_RELOC_ARM_TLS_LE32:
12161 case BFD_RELOC_ARM_TLS_IE32:
12162 case BFD_RELOC_ARM_TLS_LDM32:
12163 case BFD_RELOC_ARM_TLS_LDO32:
12164 S_SET_THREAD_LOCAL (fixP->fx_addsy);
12165 /* fall through */
12166
b99bd4ef
NC
12167 case BFD_RELOC_ARM_GOT32:
12168 case BFD_RELOC_ARM_GOTOFF:
eb043451 12169 case BFD_RELOC_ARM_TARGET2:
4e7fd91e
PB
12170 if (seg->use_rela_p && !fixP->fx_done)
12171 break;
b99bd4ef
NC
12172 md_number_to_chars (buf, 0, 4);
12173 break;
12174#endif
12175
12176 case BFD_RELOC_RVA:
12177 case BFD_RELOC_32:
9c504268 12178 case BFD_RELOC_ARM_TARGET1:
db6579d4
PB
12179 case BFD_RELOC_ARM_ROSEGREL32:
12180 case BFD_RELOC_ARM_SBREL32:
eb043451 12181 case BFD_RELOC_32_PCREL:
4e7fd91e
PB
12182 if (seg->use_rela_p && !fixP->fx_done)
12183 break;
b99bd4ef
NC
12184 if (fixP->fx_done || fixP->fx_pcrel)
12185 md_number_to_chars (buf, value, 4);
12186#ifdef OBJ_ELF
7f266840 12187 else
b99bd4ef
NC
12188 {
12189 value = fixP->fx_offset;
12190 md_number_to_chars (buf, value, 4);
12191 }
12192#endif
12193 break;
12194
12195#ifdef OBJ_ELF
eb043451
PB
12196 case BFD_RELOC_ARM_PREL31:
12197 if (fixP->fx_done || fixP->fx_pcrel)
12198 {
12199 newval = md_chars_to_number (buf, 4) & 0x80000000;
12200 if ((value ^ (value >> 1)) & 0x40000000)
12201 {
12202 as_bad_where (fixP->fx_file, fixP->fx_line,
12203 _("rel31 relocation overflow"));
12204 }
12205 newval |= value & 0x7fffffff;
12206 md_number_to_chars (buf, newval, 4);
12207 }
12208 break;
12209
b99bd4ef
NC
12210 case BFD_RELOC_ARM_PLT32:
12211 /* It appears the instruction is fully prepared at this point. */
12212 break;
12213#endif
12214
b99bd4ef
NC
12215 case BFD_RELOC_ARM_CP_OFF_IMM:
12216 sign = value >= 0;
12217 if (value < -1023 || value > 1023 || (value & 3))
12218 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12219 _("illegal value for co-processor offset"));
b99bd4ef
NC
12220 if (value < 0)
12221 value = -value;
12222 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
12223 newval |= (value >> 2) | (sign ? INDEX_UP : 0);
12224 md_number_to_chars (buf, newval, INSN_SIZE);
12225 break;
12226
e16bb312
NC
12227 case BFD_RELOC_ARM_CP_OFF_IMM_S2:
12228 sign = value >= 0;
12229 if (value < -255 || value > 255)
12230 as_bad_where (fixP->fx_file, fixP->fx_line,
12231 _("Illegal value for co-processor offset"));
12232 if (value < 0)
12233 value = -value;
12234 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
12235 newval |= value | (sign ? INDEX_UP : 0);
12236 md_number_to_chars (buf, newval , INSN_SIZE);
12237 break;
12238
b99bd4ef
NC
12239 case BFD_RELOC_ARM_THUMB_OFFSET:
12240 newval = md_chars_to_number (buf, THUMB_SIZE);
12241 /* Exactly what ranges, and where the offset is inserted depends
12242 on the type of instruction, we can establish this from the
12243 top 4 bits. */
12244 switch (newval >> 12)
12245 {
12246 case 4: /* PC load. */
12247 /* Thumb PC loads are somewhat odd, bit 1 of the PC is
12248 forced to zero for these loads, so we will need to round
12249 up the offset if the instruction address is not word
12250 aligned (since the final address produced must be, and
12251 we can only describe word-aligned immediate offsets). */
12252
12253 if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3)
12254 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12255 _("invalid offset, target not word aligned (0x%08X)"),
b99bd4ef
NC
12256 (unsigned int) (fixP->fx_frag->fr_address
12257 + fixP->fx_where + value));
12258
12259 if ((value + 2) & ~0x3fe)
12260 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12261 _("invalid offset, value too big (0x%08lX)"),
12262 (long) value);
b99bd4ef
NC
12263
12264 /* Round up, since pc will be rounded down. */
12265 newval |= (value + 2) >> 2;
12266 break;
12267
12268 case 9: /* SP load/store. */
12269 if (value & ~0x3fc)
12270 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12271 _("invalid offset, value too big (0x%08lX)"),
12272 (long) value);
b99bd4ef
NC
12273 newval |= value >> 2;
12274 break;
12275
12276 case 6: /* Word load/store. */
12277 if (value & ~0x7c)
12278 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12279 _("invalid offset, value too big (0x%08lX)"),
12280 (long) value);
b99bd4ef
NC
12281 newval |= value << 4; /* 6 - 2. */
12282 break;
12283
12284 case 7: /* Byte load/store. */
12285 if (value & ~0x1f)
12286 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12287 _("invalid offset, value too big (0x%08lX)"),
12288 (long) value);
b99bd4ef
NC
12289 newval |= value << 6;
12290 break;
12291
12292 case 8: /* Halfword load/store. */
12293 if (value & ~0x3e)
12294 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12295 _("invalid offset, value too big (0x%08lX)"),
12296 (long) value);
b99bd4ef
NC
12297 newval |= value << 5; /* 6 - 1. */
12298 break;
12299
12300 default:
12301 as_bad_where (fixP->fx_file, fixP->fx_line,
12302 "Unable to process relocation for thumb opcode: %lx",
12303 (unsigned long) newval);
12304 break;
12305 }
12306 md_number_to_chars (buf, newval, THUMB_SIZE);
12307 break;
12308
12309 case BFD_RELOC_ARM_THUMB_ADD:
12310 /* This is a complicated relocation, since we use it for all of
12311 the following immediate relocations:
12312
12313 3bit ADD/SUB
12314 8bit ADD/SUB
12315 9bit ADD/SUB SP word-aligned
12316 10bit ADD PC/SP word-aligned
12317
12318 The type of instruction being processed is encoded in the
12319 instruction field:
12320
12321 0x8000 SUB
12322 0x00F0 Rd
12323 0x000F Rs
12324 */
12325 newval = md_chars_to_number (buf, THUMB_SIZE);
12326 {
12327 int rd = (newval >> 4) & 0xf;
12328 int rs = newval & 0xf;
12329 int subtract = newval & 0x8000;
12330
12331 if (rd == REG_SP)
12332 {
12333 if (value & ~0x1fc)
12334 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12335 _("invalid immediate for stack address calculation"));
b99bd4ef
NC
12336 newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
12337 newval |= value >> 2;
12338 }
12339 else if (rs == REG_PC || rs == REG_SP)
12340 {
12341 if (subtract ||
12342 value & ~0x3fc)
12343 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12344 _("invalid immediate for address calculation (value = 0x%08lX)"),
b99bd4ef
NC
12345 (unsigned long) value);
12346 newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
12347 newval |= rd << 8;
12348 newval |= value >> 2;
12349 }
12350 else if (rs == rd)
12351 {
12352 if (value & ~0xff)
12353 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12354 _("invalid 8bit immediate"));
b99bd4ef
NC
12355 newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
12356 newval |= (rd << 8) | value;
12357 }
12358 else
12359 {
12360 if (value & ~0x7)
12361 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12362 _("invalid 3bit immediate"));
b99bd4ef
NC
12363 newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
12364 newval |= rd | (rs << 3) | (value << 6);
12365 }
12366 }
12367 md_number_to_chars (buf, newval, THUMB_SIZE);
12368 break;
12369
12370 case BFD_RELOC_ARM_THUMB_IMM:
12371 newval = md_chars_to_number (buf, THUMB_SIZE);
12372 switch (newval >> 11)
12373 {
12374 case 0x04: /* 8bit immediate MOV. */
12375 case 0x05: /* 8bit immediate CMP. */
12376 if (value < 0 || value > 255)
12377 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12378 _("invalid immediate: %ld is too large"),
b99bd4ef
NC
12379 (long) value);
12380 newval |= value;
12381 break;
12382
12383 default:
12384 abort ();
12385 }
12386 md_number_to_chars (buf, newval, THUMB_SIZE);
12387 break;
12388
12389 case BFD_RELOC_ARM_THUMB_SHIFT:
12390 /* 5bit shift value (0..31). */
12391 if (value < 0 || value > 31)
12392 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12393 _("illegal Thumb shift value: %ld"), (long) value);
b99bd4ef
NC
12394 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
12395 newval |= value << 6;
12396 md_number_to_chars (buf, newval, THUMB_SIZE);
12397 break;
12398
12399 case BFD_RELOC_VTABLE_INHERIT:
12400 case BFD_RELOC_VTABLE_ENTRY:
12401 fixP->fx_done = 0;
94f592af 12402 return;
b99bd4ef 12403
620b81c1 12404 case BFD_RELOC_UNUSED:
b99bd4ef
NC
12405 default:
12406 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12407 _("bad relocation fixup type (%d)"), fixP->fx_r_type);
b99bd4ef 12408 }
b99bd4ef
NC
12409}
12410
12411/* Translate internal representation of relocation info to BFD target
12412 format. */
12413
12414arelent *
a737bd4d
NC
12415tc_gen_reloc (asection * section ATTRIBUTE_UNUSED,
12416 fixS * fixp)
b99bd4ef
NC
12417{
12418 arelent * reloc;
12419 bfd_reloc_code_real_type code;
12420
a737bd4d 12421 reloc = xmalloc (sizeof (arelent));
b99bd4ef 12422
a737bd4d 12423 reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
b99bd4ef
NC
12424 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
12425 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
12426
12427 /* @@ Why fx_addnumber sometimes and fx_offset other times? */
12428#ifndef OBJ_ELF
12429 if (fixp->fx_pcrel == 0)
12430 reloc->addend = fixp->fx_offset;
12431 else
12432 reloc->addend = fixp->fx_offset = reloc->address;
12433#else /* OBJ_ELF */
12434 reloc->addend = fixp->fx_offset;
12435#endif
12436
12437 switch (fixp->fx_r_type)
12438 {
12439 case BFD_RELOC_8:
12440 if (fixp->fx_pcrel)
12441 {
12442 code = BFD_RELOC_8_PCREL;
12443 break;
12444 }
12445
12446 case BFD_RELOC_16:
12447 if (fixp->fx_pcrel)
12448 {
12449 code = BFD_RELOC_16_PCREL;
12450 break;
12451 }
12452
12453 case BFD_RELOC_32:
12454 if (fixp->fx_pcrel)
12455 {
12456 code = BFD_RELOC_32_PCREL;
12457 break;
12458 }
12459
620b81c1 12460 case BFD_RELOC_NONE:
b99bd4ef
NC
12461 case BFD_RELOC_ARM_PCREL_BRANCH:
12462 case BFD_RELOC_ARM_PCREL_BLX:
12463 case BFD_RELOC_RVA:
12464 case BFD_RELOC_THUMB_PCREL_BRANCH9:
12465 case BFD_RELOC_THUMB_PCREL_BRANCH12:
12466 case BFD_RELOC_THUMB_PCREL_BRANCH23:
12467 case BFD_RELOC_THUMB_PCREL_BLX:
12468 case BFD_RELOC_VTABLE_ENTRY:
12469 case BFD_RELOC_VTABLE_INHERIT:
12470 code = fixp->fx_r_type;
12471 break;
12472
12473 case BFD_RELOC_ARM_LITERAL:
12474 case BFD_RELOC_ARM_HWLITERAL:
3d0c9500
NC
12475 /* If this is called then the a literal has
12476 been referenced across a section boundary. */
b99bd4ef 12477 as_bad_where (fixp->fx_file, fixp->fx_line,
61b5f74b 12478 _("literal referenced across section boundary"));
b99bd4ef
NC
12479 return NULL;
12480
12481#ifdef OBJ_ELF
12482 case BFD_RELOC_ARM_GOT32:
12483 case BFD_RELOC_ARM_GOTOFF:
12484 case BFD_RELOC_ARM_PLT32:
9c504268 12485 case BFD_RELOC_ARM_TARGET1:
db6579d4
PB
12486 case BFD_RELOC_ARM_ROSEGREL32:
12487 case BFD_RELOC_ARM_SBREL32:
eb043451
PB
12488 case BFD_RELOC_ARM_PREL31:
12489 case BFD_RELOC_ARM_TARGET2:
ba93b8ac
DJ
12490 case BFD_RELOC_ARM_TLS_LE32:
12491 case BFD_RELOC_ARM_TLS_LDO32:
12492 code = fixp->fx_r_type;
12493 break;
12494
12495 case BFD_RELOC_ARM_TLS_GD32:
12496 case BFD_RELOC_ARM_TLS_IE32:
12497 case BFD_RELOC_ARM_TLS_LDM32:
12498 /* BFD will include the symbol's address in the addend.
12499 But we don't want that, so subtract it out again here. */
12500 if (!S_IS_COMMON (fixp->fx_addsy))
12501 reloc->addend -= (*reloc->sym_ptr_ptr)->value;
b99bd4ef
NC
12502 code = fixp->fx_r_type;
12503 break;
12504#endif
12505
12506 case BFD_RELOC_ARM_IMMEDIATE:
12507 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 12508 _("internal relocation (type: IMMEDIATE) not fixed up"));
b99bd4ef
NC
12509 return NULL;
12510
12511 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
12512 as_bad_where (fixp->fx_file, fixp->fx_line,
12513 _("ADRL used for a symbol not defined in the same file"));
12514 return NULL;
12515
12516 case BFD_RELOC_ARM_OFFSET_IMM:
c3ba240c
DJ
12517 if (fixp->fx_addsy != NULL
12518 && !S_IS_DEFINED (fixp->fx_addsy)
12519 && S_IS_LOCAL (fixp->fx_addsy))
12520 {
12521 as_bad_where (fixp->fx_file, fixp->fx_line,
12522 _("undefined local label `%s'"),
12523 S_GET_NAME (fixp->fx_addsy));
12524 return NULL;
12525 }
12526
b99bd4ef 12527 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 12528 _("internal_relocation (type: OFFSET_IMM) not fixed up"));
b99bd4ef
NC
12529 return NULL;
12530
12531 default:
12532 {
12533 char * type;
12534
12535 switch (fixp->fx_r_type)
12536 {
620b81c1 12537 case BFD_RELOC_NONE: type = "NONE"; break;
b99bd4ef
NC
12538 case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break;
12539 case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break;
0dd132b6 12540 case BFD_RELOC_ARM_SMI: type = "SMI"; break;
b99bd4ef
NC
12541 case BFD_RELOC_ARM_SWI: type = "SWI"; break;
12542 case BFD_RELOC_ARM_MULTI: type = "MULTI"; break;
12543 case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break;
12544 case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break;
12545 case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break;
12546 case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break;
12547 case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
12548 default: type = _("<unknown>"); break;
12549 }
12550 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 12551 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
12552 type);
12553 return NULL;
12554 }
12555 }
12556
12557#ifdef OBJ_ELF
8df7094c 12558 if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
b99bd4ef
NC
12559 && GOT_symbol
12560 && fixp->fx_addsy == GOT_symbol)
12561 {
12562 code = BFD_RELOC_ARM_GOTPC;
12563 reloc->addend = fixp->fx_offset = reloc->address;
12564 }
12565#endif
12566
12567 reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
12568
12569 if (reloc->howto == NULL)
12570 {
12571 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 12572 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
12573 bfd_get_reloc_code_name (code));
12574 return NULL;
12575 }
12576
12577 /* HACK: Since arm ELF uses Rel instead of Rela, encode the
12578 vtable entry to be used in the relocation's section offset. */
12579 if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
12580 reloc->address = fixp->fx_offset;
12581
12582 return reloc;
12583}
12584
12585int
a737bd4d
NC
12586md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
12587 segT segtype ATTRIBUTE_UNUSED)
b99bd4ef
NC
12588{
12589 as_fatal (_("md_estimate_size_before_relax\n"));
12590 return 1;
12591}
12592
a737bd4d
NC
12593/* We need to be able to fix up arbitrary expressions in some statements.
12594 This is so that we can handle symbols that are an arbitrary distance from
12595 the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
12596 which returns part of an address in a form which will be valid for
12597 a data instruction. We do this by pushing the expression into a symbol
12598 in the expr_section, and creating a fix for that. */
12599
12600static void
12601fix_new_arm (fragS * frag,
12602 int where,
12603 short int size,
12604 expressionS * exp,
12605 int pc_rel,
12606 int reloc)
12607{
12608 fixS * new_fix;
12609 arm_fix_data * arm_data;
12610
12611 switch (exp->X_op)
12612 {
12613 case O_constant:
12614 case O_symbol:
12615 case O_add:
12616 case O_subtract:
12617 new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
12618 break;
12619
12620 default:
12621 new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
12622 pc_rel, reloc);
12623 break;
12624 }
12625
12626 /* Mark whether the fix is to a THUMB instruction, or an ARM
12627 instruction. */
12628 arm_data = obstack_alloc (& notes, sizeof (arm_fix_data));
12629 new_fix->tc_fix_data = (PTR) arm_data;
12630 arm_data->thumb_mode = thumb_mode;
12631}
12632
b99bd4ef 12633static void
a737bd4d 12634output_inst (const char * str)
b99bd4ef
NC
12635{
12636 char * to = NULL;
12637
12638 if (inst.error)
12639 {
f03698e6 12640 as_bad ("%s -- `%s'", inst.error, str);
b99bd4ef
NC
12641 return;
12642 }
12643
12644 to = frag_more (inst.size);
12645
12646 if (thumb_mode && (inst.size > THUMB_SIZE))
12647 {
12648 assert (inst.size == (2 * THUMB_SIZE));
12649 md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE);
12650 md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE);
12651 }
12652 else if (inst.size > INSN_SIZE)
12653 {
12654 assert (inst.size == (2 * INSN_SIZE));
12655 md_number_to_chars (to, inst.instruction, INSN_SIZE);
12656 md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
12657 }
12658 else
12659 md_number_to_chars (to, inst.instruction, inst.size);
12660
620b81c1 12661 if (inst.reloc.type != BFD_RELOC_UNUSED)
b99bd4ef
NC
12662 fix_new_arm (frag_now, to - frag_now->fr_literal,
12663 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
12664 inst.reloc.type);
12665
12666#ifdef OBJ_ELF
12667 dwarf2_emit_insn (inst.size);
12668#endif
12669}
12670
12671void
a737bd4d 12672md_assemble (char * str)
b99bd4ef 12673{
6c43fab6
RE
12674 char c;
12675 char *p;
12676 char *start;
b99bd4ef 12677
b99bd4ef
NC
12678 /* Align the previous label if needed. */
12679 if (last_label_seen != NULL)
12680 {
12681 symbol_set_frag (last_label_seen, frag_now);
12682 S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
12683 S_SET_SEGMENT (last_label_seen, now_seg);
12684 }
12685
12686 memset (&inst, '\0', sizeof (inst));
620b81c1 12687 inst.reloc.type = BFD_RELOC_UNUSED;
b99bd4ef
NC
12688
12689 skip_whitespace (str);
12690
12691 /* Scan up to the end of the op-code, which must end in white space or
12692 end of string. */
12693 for (start = p = str; *p != '\0'; p++)
12694 if (*p == ' ')
12695 break;
12696
12697 if (p == str)
12698 {
f03698e6 12699 as_bad (_("no operator -- statement `%s'\n"), str);
b99bd4ef
NC
12700 return;
12701 }
12702
12703 if (thumb_mode)
12704 {
05d2d07e 12705 const struct thumb_opcode * opcode;
b99bd4ef
NC
12706
12707 c = *p;
12708 *p = '\0';
05d2d07e 12709 opcode = (const struct thumb_opcode *) hash_find (arm_tops_hsh, str);
b99bd4ef
NC
12710 *p = c;
12711
12712 if (opcode)
12713 {
12714 /* Check that this instruction is supported for this CPU. */
90e4755a 12715 if (thumb_mode == 1 && (opcode->variant & cpu_variant) == 0)
b99bd4ef 12716 {
f03698e6 12717 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
12718 return;
12719 }
12720
6057a28f 12721 mapping_state (MAP_THUMB);
b99bd4ef
NC
12722 inst.instruction = opcode->value;
12723 inst.size = opcode->size;
a737bd4d 12724 opcode->parms (p);
f03698e6 12725 output_inst (str);
b99bd4ef
NC
12726 return;
12727 }
12728 }
12729 else
12730 {
05d2d07e 12731 const struct asm_opcode * opcode;
b99bd4ef 12732
90e4755a
RE
12733 c = *p;
12734 *p = '\0';
6c43fab6 12735 opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, str);
90e4755a 12736 *p = c;
b99bd4ef 12737
90e4755a 12738 if (opcode)
b99bd4ef 12739 {
90e4755a
RE
12740 /* Check that this instruction is supported for this CPU. */
12741 if ((opcode->variant & cpu_variant) == 0)
b99bd4ef 12742 {
f03698e6 12743 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
12744 return;
12745 }
12746
6057a28f 12747 mapping_state (MAP_ARM);
90e4755a
RE
12748 inst.instruction = opcode->value;
12749 inst.size = INSN_SIZE;
a737bd4d 12750 opcode->parms (p);
f03698e6 12751 output_inst (str);
90e4755a 12752 return;
b99bd4ef
NC
12753 }
12754 }
12755
12756 /* It wasn't an instruction, but it might be a register alias of the form
12757 alias .req reg. */
6c43fab6
RE
12758 if (create_register_alias (str, p))
12759 return;
b99bd4ef 12760
b99bd4ef
NC
12761 as_bad (_("bad instruction `%s'"), start);
12762}
12763
12764/* md_parse_option
12765 Invocation line includes a switch not recognized by the base assembler.
cc8a6dd0 12766 See if it's a processor-specific option.
03b1477f
RE
12767
12768 This routine is somewhat complicated by the need for backwards
12769 compatibility (since older releases of gcc can't be changed).
12770 The new options try to make the interface as compatible as
12771 possible with GCC.
12772
12773 New options (supported) are:
12774
12775 -mcpu=<cpu name> Assemble for selected processor
12776 -march=<architecture name> Assemble for selected architecture
12777 -mfpu=<fpu architecture> Assemble for selected FPU.
12778 -EB/-mbig-endian Big-endian
12779 -EL/-mlittle-endian Little-endian
12780 -k Generate PIC code
12781 -mthumb Start in Thumb mode
12782 -mthumb-interwork Code supports ARM/Thumb interworking
12783
3d0c9500 12784 For now we will also provide support for:
03b1477f
RE
12785
12786 -mapcs-32 32-bit Program counter
12787 -mapcs-26 26-bit Program counter
12788 -macps-float Floats passed in FP registers
12789 -mapcs-reentrant Reentrant code
12790 -matpcs
12791 (sometime these will probably be replaced with -mapcs=<list of options>
12792 and -matpcs=<list of options>)
12793
12794 The remaining options are only supported for back-wards compatibility.
b99bd4ef
NC
12795 Cpu variants, the arm part is optional:
12796 -m[arm]1 Currently not supported.
12797 -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor
12798 -m[arm]3 Arm 3 processor
12799 -m[arm]6[xx], Arm 6 processors
12800 -m[arm]7[xx][t][[d]m] Arm 7 processors
12801 -m[arm]8[10] Arm 8 processors
12802 -m[arm]9[20][tdmi] Arm 9 processors
12803 -mstrongarm[110[0]] StrongARM processors
12804 -mxscale XScale processors
12805 -m[arm]v[2345[t[e]]] Arm architectures
12806 -mall All (except the ARM1)
12807 FP variants:
12808 -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
12809 -mfpe-old (No float load/store multiples)
bfae80f2
RE
12810 -mvfpxd VFP Single precision
12811 -mvfp All VFP
b99bd4ef 12812 -mno-fpu Disable all floating point instructions
b99bd4ef 12813
03b1477f
RE
12814 The following CPU names are recognized:
12815 arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
12816 arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
12817 arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
12818 arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
12819 arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
12820 arm10t arm10e, arm1020t, arm1020e, arm10200e,
12821 strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
12822
12823 */
12824
5a38dc70 12825const char * md_shortopts = "m:k";
03b1477f 12826
b99bd4ef
NC
12827#ifdef ARM_BI_ENDIAN
12828#define OPTION_EB (OPTION_MD_BASE + 0)
b99bd4ef 12829#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 12830#else
21f0f23a
RE
12831#if TARGET_BYTES_BIG_ENDIAN
12832#define OPTION_EB (OPTION_MD_BASE + 0)
21f0f23a
RE
12833#else
12834#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 12835#endif
ce058b6c 12836#endif
03b1477f
RE
12837
12838struct option md_longopts[] =
12839{
12840#ifdef OPTION_EB
12841 {"EB", no_argument, NULL, OPTION_EB},
12842#endif
12843#ifdef OPTION_EL
12844 {"EL", no_argument, NULL, OPTION_EL},
b99bd4ef
NC
12845#endif
12846 {NULL, no_argument, NULL, 0}
12847};
12848
12849size_t md_longopts_size = sizeof (md_longopts);
12850
03b1477f 12851struct arm_option_table
b99bd4ef 12852{
03b1477f
RE
12853 char *option; /* Option name to match. */
12854 char *help; /* Help information. */
12855 int *var; /* Variable to change. */
12856 int value; /* What to change it to. */
12857 char *deprecated; /* If non-null, print this message. */
12858};
b99bd4ef 12859
cc8a6dd0 12860struct arm_option_table arm_opts[] =
03b1477f
RE
12861{
12862 {"k", N_("generate PIC code"), &pic_code, 1, NULL},
12863 {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL},
12864 {"mthumb-interwork", N_("support ARM/Thumb interworking"),
12865 &support_interwork, 1, NULL},
03b1477f
RE
12866 {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
12867 {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
12868 {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
12869 1, NULL},
12870 {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
12871 {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
12872 {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
699d2810 12873 {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 0,
03b1477f
RE
12874 NULL},
12875
12876 /* These are recognized by the assembler, but have no affect on code. */
12877 {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
12878 {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
12879
12880 /* DON'T add any new processors to this list -- we want the whole list
12881 to go away... Add them to the processors table instead. */
12882 {"marm1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
12883 {"m1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
12884 {"marm2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
12885 {"m2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
12886 {"marm250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
12887 {"m250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
12888 {"marm3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
12889 {"m3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
12890 {"marm6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
12891 {"m6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
12892 {"marm600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
12893 {"m600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
12894 {"marm610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
12895 {"m610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
12896 {"marm620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
12897 {"m620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
12898 {"marm7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
12899 {"m7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
12900 {"marm70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
12901 {"m70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
12902 {"marm700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
12903 {"m700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
12904 {"marm700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
12905 {"m700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
12906 {"marm710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
12907 {"m710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
12908 {"marm710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
12909 {"m710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
12910 {"marm720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
12911 {"m720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
12912 {"marm7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
12913 {"m7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
12914 {"marm7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
12915 {"m7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
12916 {"marm7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
12917 {"m7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
12918 {"marm7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
12919 {"m7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
12920 {"marm7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
12921 {"m7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
12922 {"marm7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
12923 {"m7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
12924 {"marm7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
12925 {"m7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
12926 {"marm7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
12927 {"m7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
12928 {"marm7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12929 {"m7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12930 {"marm7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12931 {"m7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12932 {"marm710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
12933 {"m710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
12934 {"marm720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
12935 {"m720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
12936 {"marm740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
12937 {"m740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
12938 {"marm8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
12939 {"m8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
12940 {"marm810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
12941 {"m810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
12942 {"marm9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
12943 {"m9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
12944 {"marm9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
12945 {"m9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
12946 {"marm920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
12947 {"m920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
12948 {"marm940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
12949 {"m940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
12950 {"mstrongarm", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=strongarm")},
12951 {"mstrongarm110", NULL, &legacy_cpu, ARM_ARCH_V4,
12952 N_("use -mcpu=strongarm110")},
12953 {"mstrongarm1100", NULL, &legacy_cpu, ARM_ARCH_V4,
12954 N_("use -mcpu=strongarm1100")},
12955 {"mstrongarm1110", NULL, &legacy_cpu, ARM_ARCH_V4,
12956 N_("use -mcpu=strongarm1110")},
12957 {"mxscale", NULL, &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
e16bb312 12958 {"miwmmxt", NULL, &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
03b1477f
RE
12959 {"mall", NULL, &legacy_cpu, ARM_ANY, N_("use -mcpu=all")},
12960
12961 /* Architecture variants -- don't add any more to this list either. */
12962 {"mv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
12963 {"marmv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
12964 {"mv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
12965 {"marmv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
12966 {"mv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
12967 {"marmv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
12968 {"mv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
12969 {"marmv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
12970 {"mv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
12971 {"marmv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
12972 {"mv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
12973 {"marmv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
12974 {"mv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
12975 {"marmv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
12976 {"mv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
12977 {"marmv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
12978 {"mv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
12979 {"marmv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
12980
12981 /* Floating point variants -- don't add any more to this list either. */
12982 {"mfpe-old", NULL, &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
12983 {"mfpa10", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
12984 {"mfpa11", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
12985 {"mno-fpu", NULL, &legacy_fpu, 0,
12986 N_("use either -mfpu=softfpa or -mfpu=softvfp")},
12987
12988 {NULL, NULL, NULL, 0, NULL}
12989};
21f0f23a 12990
03b1477f
RE
12991struct arm_cpu_option_table
12992{
12993 char *name;
12994 int value;
12995 /* For some CPUs we assume an FPU unless the user explicitly sets
12996 -mfpu=... */
12997 int default_fpu;
12998};
12999
13000/* This list should, at a minimum, contain all the cpu names
13001 recognized by GCC. */
13002static struct arm_cpu_option_table arm_cpus[] =
13003{
13004 {"all", ARM_ANY, FPU_ARCH_FPA},
13005 {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA},
13006 {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA},
13007 {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA},
13008 {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA},
13009 {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA},
13010 {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA},
13011 {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA},
13012 {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA},
13013 {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA},
13014 {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA},
13015 {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA},
13016 {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA},
13017 {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA},
13018 {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA},
13019 {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA},
13020 {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA},
13021 {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA},
13022 {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA},
13023 {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA},
13024 {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13025 {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA},
13026 {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13027 {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13028 {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA},
13029 {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA},
13030 {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA},
13031 {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA},
13032 {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13033 {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
8783612f 13034 {"arm7tdmi-s", ARM_ARCH_V4T, FPU_ARCH_FPA},
03b1477f
RE
13035 {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA},
13036 {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA},
13037 {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA},
13038 {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA},
13039 {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA},
13040 {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA},
13041 {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA},
13042 {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA},
13043 {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA},
13044 {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13045 {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13046 {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13047 {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
13048 /* For V5 or later processors we default to using VFP; but the user
13049 should really set the FPU type explicitly. */
13050 {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
13051 {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
ea6ef066 13052 {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
7de9afa2 13053 {"arm926ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
8783612f 13054 {"arm926ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
03b1477f
RE
13055 {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
13056 {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13057 {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
13058 {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13059 {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
13060 {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13061 {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13062 {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
13063 {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
5dc1606f
PB
13064 {"arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
13065 {"arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
09d92015 13066 {"arm1136js", ARM_ARCH_V6, FPU_NONE},
9166bcd7 13067 {"arm1136j-s", ARM_ARCH_V6, FPU_NONE},
09d92015 13068 {"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2},
8783612f 13069 {"arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2},
0dd132b6
NC
13070 {"mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2},
13071 {"mpcorenovfp", ARM_ARCH_V6K, FPU_NONE},
13072 {"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE},
13073 {"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2},
03b1477f
RE
13074 /* ??? XSCALE is really an architecture. */
13075 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
5a6c6817 13076 /* ??? iwmmxt is not a processor. */
e16bb312 13077 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2},
03b1477f
RE
13078 {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
13079 /* Maverick */
33a392fb 13080 {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_ARCH_MAVERICK},
03b1477f
RE
13081 {NULL, 0, 0}
13082};
cc8a6dd0 13083
03b1477f
RE
13084struct arm_arch_option_table
13085{
13086 char *name;
13087 int value;
13088 int default_fpu;
13089};
13090
13091/* This list should, at a minimum, contain all the architecture names
13092 recognized by GCC. */
13093static struct arm_arch_option_table arm_archs[] =
13094{
13095 {"all", ARM_ANY, FPU_ARCH_FPA},
13096 {"armv1", ARM_ARCH_V1, FPU_ARCH_FPA},
13097 {"armv2", ARM_ARCH_V2, FPU_ARCH_FPA},
13098 {"armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA},
13099 {"armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA},
13100 {"armv3", ARM_ARCH_V3, FPU_ARCH_FPA},
13101 {"armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA},
13102 {"armv4", ARM_ARCH_V4, FPU_ARCH_FPA},
13103 {"armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA},
13104 {"armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13105 {"armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA},
13106 {"armv5", ARM_ARCH_V5, FPU_ARCH_VFP},
13107 {"armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP},
13108 {"armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP},
13109 {"armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP},
13110 {"armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP},
ea6ef066 13111 {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP},
84255574 13112 {"armv6", ARM_ARCH_V6, FPU_ARCH_VFP},
1ddd7f43 13113 {"armv6j", ARM_ARCH_V6, FPU_ARCH_VFP},
0dd132b6
NC
13114 {"armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP},
13115 {"armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP},
13116 {"armv6zk", ARM_ARCH_V6ZK, FPU_ARCH_VFP},
b05fe5cf
ZW
13117 {"armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP},
13118 {"armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP},
13119 {"armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP},
13120 {"armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
03b1477f 13121 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP},
8266886e 13122 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
03b1477f
RE
13123 {NULL, 0, 0}
13124};
13125
13126/* ISA extensions in the co-processor space. */
13127struct arm_arch_extension_table
13128{
13129 char *name;
13130 int value;
13131};
13132
13133static struct arm_arch_extension_table arm_extensions[] =
13134{
13135 {"maverick", ARM_CEXT_MAVERICK},
13136 {"xscale", ARM_CEXT_XSCALE},
e16bb312 13137 {"iwmmxt", ARM_CEXT_IWMMXT},
03b1477f
RE
13138 {NULL, 0}
13139};
b99bd4ef 13140
03b1477f
RE
13141struct arm_fpu_option_table
13142{
13143 char *name;
13144 int value;
13145};
13146
13147/* This list should, at a minimum, contain all the fpu names
13148 recognized by GCC. */
13149static struct arm_fpu_option_table arm_fpus[] =
13150{
13151 {"softfpa", FPU_NONE},
13152 {"fpe", FPU_ARCH_FPE},
d193a22a
RE
13153 {"fpe2", FPU_ARCH_FPE},
13154 {"fpe3", FPU_ARCH_FPA}, /* Third release supports LFM/SFM. */
03b1477f
RE
13155 {"fpa", FPU_ARCH_FPA},
13156 {"fpa10", FPU_ARCH_FPA},
13157 {"fpa11", FPU_ARCH_FPA},
13158 {"arm7500fe", FPU_ARCH_FPA},
13159 {"softvfp", FPU_ARCH_VFP},
13160 {"softvfp+vfp", FPU_ARCH_VFP_V2},
13161 {"vfp", FPU_ARCH_VFP_V2},
13162 {"vfp9", FPU_ARCH_VFP_V2},
13163 {"vfp10", FPU_ARCH_VFP_V2},
13164 {"vfp10-r0", FPU_ARCH_VFP_V1},
13165 {"vfpxd", FPU_ARCH_VFP_V1xD},
13166 {"arm1020t", FPU_ARCH_VFP_V1},
13167 {"arm1020e", FPU_ARCH_VFP_V2},
09d92015 13168 {"arm1136jfs", FPU_ARCH_VFP_V2},
8783612f 13169 {"arm1136jf-s", FPU_ARCH_VFP_V2},
33a392fb
PB
13170 {"maverick", FPU_ARCH_MAVERICK},
13171 {NULL, 0}
13172};
13173
13174struct arm_float_abi_option_table
13175{
13176 char *name;
13177 int value;
13178};
13179
13180static struct arm_float_abi_option_table arm_float_abis[] =
13181{
13182 {"hard", ARM_FLOAT_ABI_HARD},
13183 {"softfp", ARM_FLOAT_ABI_SOFTFP},
13184 {"soft", ARM_FLOAT_ABI_SOFT},
03b1477f
RE
13185 {NULL, 0}
13186};
13187
d507cf36
PB
13188struct arm_eabi_option_table
13189{
13190 char *name;
13191 unsigned int value;
13192};
13193
7cc69913 13194#ifdef OBJ_ELF
8cb51566 13195/* We only know how to output GNU and ver 4 (AAELF) formats. */
d507cf36
PB
13196static struct arm_eabi_option_table arm_eabis[] =
13197{
13198 {"gnu", EF_ARM_EABI_UNKNOWN},
8cb51566 13199 {"4", EF_ARM_EABI_VER4},
d507cf36
PB
13200 {NULL, 0}
13201};
7cc69913 13202#endif
d507cf36 13203
03b1477f
RE
13204struct arm_long_option_table
13205{
a737bd4d
NC
13206 char * option; /* Substring to match. */
13207 char * help; /* Help information. */
13208 int (* func) (char * subopt); /* Function to decode sub-option. */
13209 char * deprecated; /* If non-null, print this message. */
03b1477f
RE
13210};
13211
13212static int
a737bd4d 13213arm_parse_extension (char * str, int * opt_p)
03b1477f
RE
13214{
13215 while (str != NULL && *str != 0)
13216 {
a737bd4d
NC
13217 struct arm_arch_extension_table * opt;
13218 char * ext;
03b1477f
RE
13219 int optlen;
13220
13221 if (*str != '+')
b99bd4ef 13222 {
03b1477f
RE
13223 as_bad (_("invalid architectural extension"));
13224 return 0;
13225 }
b99bd4ef 13226
03b1477f
RE
13227 str++;
13228 ext = strchr (str, '+');
b99bd4ef 13229
03b1477f
RE
13230 if (ext != NULL)
13231 optlen = ext - str;
13232 else
13233 optlen = strlen (str);
b99bd4ef 13234
03b1477f
RE
13235 if (optlen == 0)
13236 {
13237 as_bad (_("missing architectural extension"));
13238 return 0;
13239 }
b99bd4ef 13240
03b1477f
RE
13241 for (opt = arm_extensions; opt->name != NULL; opt++)
13242 if (strncmp (opt->name, str, optlen) == 0)
13243 {
13244 *opt_p |= opt->value;
13245 break;
13246 }
bfae80f2 13247
03b1477f
RE
13248 if (opt->name == NULL)
13249 {
13250 as_bad (_("unknown architectural extnsion `%s'"), str);
13251 return 0;
13252 }
b99bd4ef 13253
03b1477f
RE
13254 str = ext;
13255 };
b99bd4ef 13256
03b1477f
RE
13257 return 1;
13258}
b99bd4ef 13259
03b1477f 13260static int
a737bd4d 13261arm_parse_cpu (char * str)
03b1477f 13262{
a737bd4d
NC
13263 struct arm_cpu_option_table * opt;
13264 char * ext = strchr (str, '+');
03b1477f 13265 int optlen;
b99bd4ef 13266
03b1477f
RE
13267 if (ext != NULL)
13268 optlen = ext - str;
13269 else
13270 optlen = strlen (str);
b99bd4ef 13271
03b1477f
RE
13272 if (optlen == 0)
13273 {
13274 as_bad (_("missing cpu name `%s'"), str);
13275 return 0;
13276 }
b99bd4ef 13277
03b1477f
RE
13278 for (opt = arm_cpus; opt->name != NULL; opt++)
13279 if (strncmp (opt->name, str, optlen) == 0)
13280 {
13281 mcpu_cpu_opt = opt->value;
13282 mcpu_fpu_opt = opt->default_fpu;
b99bd4ef 13283
03b1477f
RE
13284 if (ext != NULL)
13285 return arm_parse_extension (ext, &mcpu_cpu_opt);
b99bd4ef 13286
03b1477f
RE
13287 return 1;
13288 }
b99bd4ef 13289
03b1477f
RE
13290 as_bad (_("unknown cpu `%s'"), str);
13291 return 0;
13292}
b99bd4ef 13293
03b1477f 13294static int
a737bd4d 13295arm_parse_arch (char * str)
03b1477f
RE
13296{
13297 struct arm_arch_option_table *opt;
13298 char *ext = strchr (str, '+');
13299 int optlen;
b99bd4ef 13300
03b1477f
RE
13301 if (ext != NULL)
13302 optlen = ext - str;
13303 else
13304 optlen = strlen (str);
b99bd4ef 13305
03b1477f
RE
13306 if (optlen == 0)
13307 {
13308 as_bad (_("missing architecture name `%s'"), str);
13309 return 0;
13310 }
b99bd4ef 13311
b99bd4ef 13312
03b1477f 13313 for (opt = arm_archs; opt->name != NULL; opt++)
a737bd4d 13314 if (streq (opt->name, str))
03b1477f
RE
13315 {
13316 march_cpu_opt = opt->value;
13317 march_fpu_opt = opt->default_fpu;
b99bd4ef 13318
03b1477f
RE
13319 if (ext != NULL)
13320 return arm_parse_extension (ext, &march_cpu_opt);
b99bd4ef 13321
03b1477f
RE
13322 return 1;
13323 }
b99bd4ef 13324
03b1477f
RE
13325 as_bad (_("unknown architecture `%s'\n"), str);
13326 return 0;
13327}
13328
13329static int
a737bd4d 13330arm_parse_fpu (char * str)
03b1477f 13331{
a737bd4d 13332 struct arm_fpu_option_table * opt;
b99bd4ef 13333
03b1477f 13334 for (opt = arm_fpus; opt->name != NULL; opt++)
a737bd4d 13335 if (streq (opt->name, str))
03b1477f
RE
13336 {
13337 mfpu_opt = opt->value;
13338 return 1;
13339 }
b99bd4ef 13340
03b1477f
RE
13341 as_bad (_("unknown floating point format `%s'\n"), str);
13342 return 0;
13343}
b99bd4ef 13344
33a392fb 13345static int
a737bd4d 13346arm_parse_float_abi (char * str)
33a392fb 13347{
a737bd4d 13348 struct arm_float_abi_option_table * opt;
33a392fb
PB
13349
13350 for (opt = arm_float_abis; opt->name != NULL; opt++)
a737bd4d 13351 if (streq (opt->name, str))
33a392fb
PB
13352 {
13353 mfloat_abi_opt = opt->value;
13354 return 1;
13355 }
13356
13357 as_bad (_("unknown floating point abi `%s'\n"), str);
13358 return 0;
13359}
13360
7cc69913 13361#ifdef OBJ_ELF
d507cf36 13362static int
a737bd4d 13363arm_parse_eabi (char * str)
d507cf36
PB
13364{
13365 struct arm_eabi_option_table *opt;
13366
13367 for (opt = arm_eabis; opt->name != NULL; opt++)
a737bd4d 13368 if (streq (opt->name, str))
d507cf36
PB
13369 {
13370 meabi_flags = opt->value;
13371 return 1;
13372 }
13373 as_bad (_("unknown EABI `%s'\n"), str);
13374 return 0;
13375}
7cc69913 13376#endif
d507cf36 13377
03b1477f
RE
13378struct arm_long_option_table arm_long_opts[] =
13379{
13380 {"mcpu=", N_("<cpu name>\t assemble for CPU <cpu name>"),
13381 arm_parse_cpu, NULL},
13382 {"march=", N_("<arch name>\t assemble for architecture <arch name>"),
13383 arm_parse_arch, NULL},
13384 {"mfpu=", N_("<fpu name>\t assemble for FPU architecture <fpu name>"),
13385 arm_parse_fpu, NULL},
33a392fb
PB
13386 {"mfloat-abi=", N_("<abi>\t assemble for floating point ABI <abi>"),
13387 arm_parse_float_abi, NULL},
7cc69913 13388#ifdef OBJ_ELF
d507cf36
PB
13389 {"meabi=", N_("<ver>\t assemble for eabi version <ver>"),
13390 arm_parse_eabi, NULL},
7cc69913 13391#endif
03b1477f
RE
13392 {NULL, NULL, 0, NULL}
13393};
b99bd4ef 13394
03b1477f 13395int
a737bd4d 13396md_parse_option (int c, char * arg)
03b1477f
RE
13397{
13398 struct arm_option_table *opt;
13399 struct arm_long_option_table *lopt;
b99bd4ef 13400
03b1477f
RE
13401 switch (c)
13402 {
13403#ifdef OPTION_EB
13404 case OPTION_EB:
13405 target_big_endian = 1;
b99bd4ef 13406 break;
03b1477f 13407#endif
b99bd4ef 13408
03b1477f
RE
13409#ifdef OPTION_EL
13410 case OPTION_EL:
13411 target_big_endian = 0;
b99bd4ef
NC
13412 break;
13413#endif
13414
03b1477f 13415 case 'a':
cc8a6dd0 13416 /* Listing option. Just ignore these, we don't support additional
03b1477f
RE
13417 ones. */
13418 return 0;
13419
b99bd4ef 13420 default:
03b1477f
RE
13421 for (opt = arm_opts; opt->option != NULL; opt++)
13422 {
13423 if (c == opt->option[0]
13424 && ((arg == NULL && opt->option[1] == 0)
a737bd4d 13425 || streq (arg, opt->option + 1)))
03b1477f
RE
13426 {
13427#if WARN_DEPRECATED
13428 /* If the option is deprecated, tell the user. */
13429 if (opt->deprecated != NULL)
13430 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
13431 arg ? arg : "", _(opt->deprecated));
13432#endif
13433
13434 if (opt->var != NULL)
13435 *opt->var = opt->value;
13436
13437 return 1;
13438 }
13439 }
13440
13441 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
13442 {
cc8a6dd0 13443 /* These options are expected to have an argument. */
03b1477f
RE
13444 if (c == lopt->option[0]
13445 && arg != NULL
cc8a6dd0 13446 && strncmp (arg, lopt->option + 1,
03b1477f
RE
13447 strlen (lopt->option + 1)) == 0)
13448 {
13449#if WARN_DEPRECATED
13450 /* If the option is deprecated, tell the user. */
13451 if (lopt->deprecated != NULL)
13452 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
13453 _(lopt->deprecated));
13454#endif
13455
13456 /* Call the sup-option parser. */
a737bd4d 13457 return lopt->func (arg + strlen (lopt->option) - 1);
03b1477f
RE
13458 }
13459 }
13460
b99bd4ef
NC
13461 return 0;
13462 }
13463
13464 return 1;
13465}
13466
13467void
a737bd4d 13468md_show_usage (FILE * fp)
b99bd4ef 13469{
03b1477f
RE
13470 struct arm_option_table *opt;
13471 struct arm_long_option_table *lopt;
13472
13473 fprintf (fp, _(" ARM-specific assembler options:\n"));
13474
13475 for (opt = arm_opts; opt->option != NULL; opt++)
13476 if (opt->help != NULL)
13477 fprintf (fp, " -%-23s%s\n", opt->option, _(opt->help));
13478
13479 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
13480 if (lopt->help != NULL)
13481 fprintf (fp, " -%s%s\n", lopt->option, _(lopt->help));
13482
13483#ifdef OPTION_EB
b99bd4ef 13484 fprintf (fp, _("\
03b1477f 13485 -EB assemble code for a big-endian cpu\n"));
b99bd4ef 13486#endif
03b1477f
RE
13487
13488#ifdef OPTION_EL
b99bd4ef 13489 fprintf (fp, _("\
03b1477f 13490 -EL assemble code for a little-endian cpu\n"));
b99bd4ef
NC
13491#endif
13492}
13493
b99bd4ef
NC
13494/* This fix_new is called by cons via TC_CONS_FIX_NEW. */
13495
13496void
a737bd4d
NC
13497cons_fix_new_arm (fragS * frag,
13498 int where,
13499 int size,
13500 expressionS * exp)
b99bd4ef
NC
13501{
13502 bfd_reloc_code_real_type type;
13503 int pcrel = 0;
13504
13505 /* Pick a reloc.
13506 FIXME: @@ Should look at CPU word size. */
13507 switch (size)
13508 {
13509 case 1:
13510 type = BFD_RELOC_8;
13511 break;
13512 case 2:
13513 type = BFD_RELOC_16;
13514 break;
13515 case 4:
13516 default:
13517 type = BFD_RELOC_32;
13518 break;
13519 case 8:
13520 type = BFD_RELOC_64;
13521 break;
13522 }
13523
13524 fix_new_exp (frag, where, (int) size, exp, pcrel, type);
13525}
13526
13527/* A good place to do this, although this was probably not intended
13528 for this kind of use. We need to dump the literal pool before
13529 references are made to a null symbol pointer. */
13530
13531void
a737bd4d 13532arm_cleanup (void)
b99bd4ef 13533{
3d0c9500 13534 literal_pool * pool;
b99bd4ef 13535
3d0c9500
NC
13536 for (pool = list_of_pools; pool; pool = pool->next)
13537 {
13538 /* Put it at the end of the relevent section. */
13539 subseg_set (pool->section, pool->sub_section);
69b97547
NC
13540#ifdef OBJ_ELF
13541 arm_elf_change_section ();
13542#endif
3d0c9500
NC
13543 s_ltorg (0);
13544 }
b99bd4ef
NC
13545}
13546
13547void
a737bd4d 13548arm_start_line_hook (void)
b99bd4ef
NC
13549{
13550 last_label_seen = NULL;
13551}
13552
13553void
a737bd4d 13554arm_frob_label (symbolS * sym)
b99bd4ef
NC
13555{
13556 last_label_seen = sym;
13557
13558 ARM_SET_THUMB (sym, thumb_mode);
13559
13560#if defined OBJ_COFF || defined OBJ_ELF
13561 ARM_SET_INTERWORK (sym, support_interwork);
13562#endif
13563
13564 /* Note - do not allow local symbols (.Lxxx) to be labeled
13565 as Thumb functions. This is because these labels, whilst
13566 they exist inside Thumb code, are not the entry points for
13567 possible ARM->Thumb calls. Also, these labels can be used
13568 as part of a computed goto or switch statement. eg gcc
13569 can generate code that looks like this:
13570
13571 ldr r2, [pc, .Laaa]
13572 lsl r3, r3, #2
13573 ldr r2, [r3, r2]
13574 mov pc, r2
cc8a6dd0 13575
b99bd4ef
NC
13576 .Lbbb: .word .Lxxx
13577 .Lccc: .word .Lyyy
13578 ..etc...
13579 .Laaa: .word Lbbb
13580
13581 The first instruction loads the address of the jump table.
13582 The second instruction converts a table index into a byte offset.
13583 The third instruction gets the jump address out of the table.
13584 The fourth instruction performs the jump.
cc8a6dd0 13585
b99bd4ef
NC
13586 If the address stored at .Laaa is that of a symbol which has the
13587 Thumb_Func bit set, then the linker will arrange for this address
13588 to have the bottom bit set, which in turn would mean that the
13589 address computation performed by the third instruction would end
13590 up with the bottom bit set. Since the ARM is capable of unaligned
13591 word loads, the instruction would then load the incorrect address
13592 out of the jump table, and chaos would ensue. */
13593 if (label_is_thumb_function_name
13594 && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
13595 && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
13596 {
13597 /* When the address of a Thumb function is taken the bottom
13598 bit of that address should be set. This will allow
13599 interworking between Arm and Thumb functions to work
13600 correctly. */
13601
13602 THUMB_SET_FUNC (sym, 1);
13603
b34976b6 13604 label_is_thumb_function_name = FALSE;
b99bd4ef
NC
13605 }
13606}
13607
13608/* Adjust the symbol table. This marks Thumb symbols as distinct from
13609 ARM ones. */
13610
13611void
a737bd4d 13612arm_adjust_symtab (void)
b99bd4ef
NC
13613{
13614#ifdef OBJ_COFF
13615 symbolS * sym;
13616
13617 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
13618 {
13619 if (ARM_IS_THUMB (sym))
13620 {
13621 if (THUMB_IS_FUNC (sym))
13622 {
13623 /* Mark the symbol as a Thumb function. */
13624 if ( S_GET_STORAGE_CLASS (sym) == C_STAT
13625 || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */
13626 S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
13627
13628 else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
13629 S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
13630 else
13631 as_bad (_("%s: unexpected function type: %d"),
13632 S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
13633 }
cc8a6dd0 13634 else switch (S_GET_STORAGE_CLASS (sym))
b99bd4ef
NC
13635 {
13636 case C_EXT:
13637 S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
13638 break;
13639 case C_STAT:
13640 S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
13641 break;
13642 case C_LABEL:
13643 S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
13644 break;
13645 default:
13646 /* Do nothing. */
13647 break;
13648 }
13649 }
13650
13651 if (ARM_IS_INTERWORK (sym))
13652 coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
13653 }
13654#endif
13655#ifdef OBJ_ELF
13656 symbolS * sym;
13657 char bind;
13658
13659 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
13660 {
13661 if (ARM_IS_THUMB (sym))
13662 {
13663 elf_symbol_type * elf_sym;
13664
13665 elf_sym = elf_symbol (symbol_get_bfdsym (sym));
d110d6a2 13666 bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
b99bd4ef 13667
05ea83ed 13668 if (! bfd_is_arm_mapping_symbol_name (elf_sym->symbol.name))
9d2da7ca
JB
13669 {
13670 /* If it's a .thumb_func, declare it as so,
13671 otherwise tag label as .code 16. */
13672 if (THUMB_IS_FUNC (sym))
13673 elf_sym->internal_elf_sym.st_info =
13674 ELF_ST_INFO (bind, STT_ARM_TFUNC);
13675 else
13676 elf_sym->internal_elf_sym.st_info =
13677 ELF_ST_INFO (bind, STT_ARM_16BIT);
13678 }
b99bd4ef
NC
13679 }
13680 }
13681#endif
13682}
13683
13684int
a737bd4d 13685arm_data_in_code (void)
b99bd4ef
NC
13686{
13687 if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
13688 {
13689 *input_line_pointer = '/';
13690 input_line_pointer += 5;
13691 *input_line_pointer = 0;
13692 return 1;
13693 }
13694
13695 return 0;
13696}
13697
13698char *
a737bd4d 13699arm_canonicalize_symbol_name (char * name)
b99bd4ef
NC
13700{
13701 int len;
13702
13703 if (thumb_mode && (len = strlen (name)) > 5
13704 && streq (name + len - 5, "/data"))
13705 *(name + len - 5) = 0;
13706
13707 return name;
13708}
13709
bfc866a6 13710#if defined OBJ_COFF || defined OBJ_ELF
a161fe53 13711void
a737bd4d 13712arm_validate_fix (fixS * fixP)
b99bd4ef
NC
13713{
13714 /* If the destination of the branch is a defined symbol which does not have
13715 the THUMB_FUNC attribute, then we must be calling a function which has
13716 the (interfacearm) attribute. We look for the Thumb entry point to that
13717 function and change the branch to refer to that function instead. */
13718 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
13719 && fixP->fx_addsy != NULL
13720 && S_IS_DEFINED (fixP->fx_addsy)
13721 && ! THUMB_IS_FUNC (fixP->fx_addsy))
13722 {
13723 fixP->fx_addsy = find_real_start (fixP->fx_addsy);
b99bd4ef 13724 }
b99bd4ef 13725}
bfc866a6 13726#endif
b99bd4ef 13727
114424c6 13728int
a737bd4d 13729arm_force_relocation (struct fix * fixp)
114424c6
AM
13730{
13731#if defined (OBJ_COFF) && defined (TE_PE)
13732 if (fixp->fx_r_type == BFD_RELOC_RVA)
13733 return 1;
13734#endif
13735#ifdef OBJ_ELF
ae6063d4 13736 if (fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
114424c6
AM
13737 || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
13738 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
13739 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
13740 return 1;
13741#endif
13742
13743 /* Resolve these relocations even if the symbol is extern or weak. */
13744 if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
47281638 13745 || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
114424c6
AM
13746 || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
13747 return 0;
13748
ae6063d4 13749 return generic_force_reloc (fixp);
114424c6
AM
13750}
13751
b99bd4ef
NC
13752#ifdef OBJ_COFF
13753/* This is a little hack to help the gas/arm/adrl.s test. It prevents
13754 local labels from being added to the output symbol table when they
13755 are used with the ADRL pseudo op. The ADRL relocation should always
13756 be resolved before the binbary is emitted, so it is safe to say that
13757 it is adjustable. */
13758
b34976b6 13759bfd_boolean
a737bd4d 13760arm_fix_adjustable (fixS * fixP)
b99bd4ef
NC
13761{
13762 if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
13763 return 1;
13764 return 0;
13765}
13766#endif
114424c6 13767
b99bd4ef
NC
13768#ifdef OBJ_ELF
13769/* Relocations against Thumb function names must be left unadjusted,
13770 so that the linker can use this information to correctly set the
13771 bottom bit of their addresses. The MIPS version of this function
13772 also prevents relocations that are mips-16 specific, but I do not
13773 know why it does this.
13774
13775 FIXME:
13776 There is one other problem that ought to be addressed here, but
13777 which currently is not: Taking the address of a label (rather
13778 than a function) and then later jumping to that address. Such
13779 addresses also ought to have their bottom bit set (assuming that
13780 they reside in Thumb code), but at the moment they will not. */
13781
b34976b6 13782bfd_boolean
a737bd4d 13783arm_fix_adjustable (fixS * fixP)
b99bd4ef
NC
13784{
13785 if (fixP->fx_addsy == NULL)
13786 return 1;
13787
b99bd4ef
NC
13788 if (THUMB_IS_FUNC (fixP->fx_addsy)
13789 && fixP->fx_subsy == NULL)
13790 return 0;
13791
13792 /* We need the symbol name for the VTABLE entries. */
13793 if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
13794 || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
13795 return 0;
13796
a161fe53
AM
13797 /* Don't allow symbols to be discarded on GOT related relocs. */
13798 if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
13799 || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
eb043451 13800 || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
ba93b8ac
DJ
13801 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
13802 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
13803 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
13804 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
13805 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
eb043451 13806 || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
a161fe53
AM
13807 return 0;
13808
b99bd4ef
NC
13809 return 1;
13810}
13811
13812const char *
a737bd4d 13813elf32_arm_target_format (void)
b99bd4ef 13814{
e5a52504
MM
13815#ifdef TE_SYMBIAN
13816 return (target_big_endian
13817 ? "elf32-bigarm-symbian"
13818 : "elf32-littlearm-symbian");
4e7fd91e
PB
13819#elif defined (TE_VXWORKS)
13820 return (target_big_endian
13821 ? "elf32-bigarm-vxworks"
13822 : "elf32-littlearm-vxworks");
a737bd4d 13823#else
b99bd4ef 13824 if (target_big_endian)
7f266840 13825 return "elf32-bigarm";
b99bd4ef 13826 else
7f266840 13827 return "elf32-littlearm";
e5a52504 13828#endif
b99bd4ef
NC
13829}
13830
13831void
a737bd4d
NC
13832armelf_frob_symbol (symbolS * symp,
13833 int * puntp)
b99bd4ef
NC
13834{
13835 elf_frob_symbol (symp, puntp);
13836}
13837
b99bd4ef 13838static void
a737bd4d 13839s_arm_elf_cons (int nbytes)
b99bd4ef
NC
13840{
13841 expressionS exp;
13842
13843#ifdef md_flush_pending_output
13844 md_flush_pending_output ();
13845#endif
13846
13847 if (is_it_end_of_statement ())
13848 {
13849 demand_empty_rest_of_line ();
13850 return;
13851 }
13852
13853#ifdef md_cons_align
13854 md_cons_align (nbytes);
13855#endif
13856
6057a28f 13857 mapping_state (MAP_DATA);
b99bd4ef
NC
13858 do
13859 {
13860 bfd_reloc_code_real_type reloc;
ba93b8ac
DJ
13861 char *sym_start;
13862 int sym_len;
b99bd4ef 13863
ba93b8ac 13864 sym_start = input_line_pointer;
b99bd4ef 13865 expression (& exp);
ba93b8ac 13866 sym_len = input_line_pointer - sym_start;
b99bd4ef
NC
13867
13868 if (exp.X_op == O_symbol
13869 && * input_line_pointer == '('
13870 && (reloc = arm_parse_reloc ()) != BFD_RELOC_UNUSED)
13871 {
13872 reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
13873 int size = bfd_get_reloc_size (howto);
13874
13875 if (size > nbytes)
13876 as_bad ("%s relocations do not fit in %d bytes",
13877 howto->name, nbytes);
13878 else
13879 {
ba93b8ac 13880 char *p;
b99bd4ef 13881 int offset = nbytes - size;
ba93b8ac
DJ
13882 char *saved_buf = alloca (sym_len), *saved_input;
13883
13884 /* We've parsed an expression stopping at O_symbol. But there
13885 may be more expression left now that we have parsed the
13886 relocation marker. Parse it again. */
13887 saved_input = input_line_pointer - sym_len;
13888 memcpy (saved_buf, saved_input, sym_len);
13889 memmove (saved_input, sym_start, sym_len);
13890 input_line_pointer = saved_input;
13891 expression (& exp);
13892 memcpy (saved_input, saved_buf, sym_len);
13893 assert (input_line_pointer >= saved_input + sym_len);
13894
13895 p = frag_more ((int) nbytes);
b99bd4ef
NC
13896 fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
13897 &exp, 0, reloc);
13898 }
13899 }
13900 else
13901 emit_expr (&exp, (unsigned int) nbytes);
13902 }
13903 while (*input_line_pointer++ == ',');
13904
13905 /* Put terminator back into stream. */
13906 input_line_pointer --;
13907 demand_empty_rest_of_line ();
13908}
13909
eb043451
PB
13910
13911/* Parse a .rel31 directive. */
13912
13913static void
13914s_arm_rel31 (int ignored ATTRIBUTE_UNUSED)
13915{
13916 expressionS exp;
13917 char *p;
13918 valueT highbit;
a737bd4d 13919
eb043451
PB
13920 SKIP_WHITESPACE ();
13921
13922 highbit = 0;
13923 if (*input_line_pointer == '1')
13924 highbit = 0x80000000;
13925 else if (*input_line_pointer != '0')
13926 as_bad (_("expected 0 or 1"));
13927
13928 input_line_pointer++;
13929 SKIP_WHITESPACE ();
13930 if (*input_line_pointer != ',')
13931 as_bad (_("missing comma"));
13932 input_line_pointer++;
13933
13934#ifdef md_flush_pending_output
13935 md_flush_pending_output ();
13936#endif
13937
13938#ifdef md_cons_align
13939 md_cons_align (4);
13940#endif
13941
13942 mapping_state (MAP_DATA);
13943
13944 expression (&exp);
13945
13946 p = frag_more (4);
13947 md_number_to_chars (p, highbit, 4);
13948 fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1,
13949 BFD_RELOC_ARM_PREL31);
13950
13951 demand_empty_rest_of_line ();
13952}
7ed4c4c5
NC
13953\f
13954/* Code to deal with unwinding tables. */
13955
13956static void add_unwind_adjustsp (offsetT);
13957
13958/* Switch to section NAME and create section if necessary. It's
13959 rather ugly that we have to manipulate input_line_pointer but I
13960 don't see any other way to accomplish the same thing without
13961 changing obj-elf.c (which may be the Right Thing, in the end).
13962 Copied from tc-ia64.c. */
13963
13964static void
13965set_section (char *name)
13966{
13967 char *saved_input_line_pointer;
13968
13969 saved_input_line_pointer = input_line_pointer;
13970 input_line_pointer = name;
13971 obj_elf_section (0);
13972 input_line_pointer = saved_input_line_pointer;
13973}
13974
13975/* Cenerate and deferred unwind frame offset. */
13976
13977static void
13978flush_pending_unwind (void)
13979{
13980 offsetT offset;
13981
13982 offset = unwind.pending_offset;
13983 unwind.pending_offset = 0;
13984 if (offset != 0)
13985 add_unwind_adjustsp (offset);
13986}
13987
13988/* Add an opcode to this list for this function. Two-byte opcodes should
13989 be passed as op[0] << 8 | op[1]. The list of opcodes is built in reverse
13990 order. */
13991
13992static void
13993add_unwind_opcode (valueT op, int length)
13994{
13995 /* Add any deferred stack adjustment. */
13996 if (unwind.pending_offset)
13997 flush_pending_unwind ();
13998
13999 unwind.sp_restored = 0;
14000
14001 if (unwind.opcode_count + length > unwind.opcode_alloc)
14002 {
14003 unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
14004 if (unwind.opcodes)
14005 unwind.opcodes = xrealloc (unwind.opcodes,
14006 unwind.opcode_alloc);
14007 else
14008 unwind.opcodes = xmalloc (unwind.opcode_alloc);
14009 }
14010 while (length > 0)
14011 {
14012 length--;
14013 unwind.opcodes[unwind.opcode_count] = op & 0xff;
14014 op >>= 8;
14015 unwind.opcode_count++;
14016 }
14017}
14018
14019/* Add unwind opcodes to adjust the stack pointer. */
14020
14021static void
14022add_unwind_adjustsp (offsetT offset)
14023{
14024 valueT op;
14025
14026 if (offset > 0x200)
14027 {
14028 /* We need at most 5 bytes to hold a 32-bit value in a uleb128. */
14029 char bytes[5];
14030 int n;
14031 valueT o;
14032
14033 /* Long form: 0xb2, uleb128. */
14034 /* This might not fit in a word so add the individual bytes,
14035 remembering the list is built in reverse order. */
14036 o = (valueT) ((offset - 0x204) >> 2);
14037 if (o == 0)
14038 add_unwind_opcode (0, 1);
14039
14040 /* Calculate the uleb128 encoding of the offset. */
14041 n = 0;
14042 while (o)
14043 {
14044 bytes[n] = o & 0x7f;
14045 o >>= 7;
14046 if (o)
14047 bytes[n] |= 0x80;
14048 n++;
14049 }
14050 /* Add the insn. */
14051 for (; n; n--)
14052 add_unwind_opcode (bytes[n - 1], 1);
14053 add_unwind_opcode (0xb2, 1);
14054 }
14055 else if (offset > 0x100)
14056 {
14057 /* Two short opcodes. */
14058 add_unwind_opcode (0x3f, 1);
14059 op = (offset - 0x104) >> 2;
14060 add_unwind_opcode (op, 1);
14061 }
14062 else if (offset > 0)
14063 {
14064 /* Short opcode. */
14065 op = (offset - 4) >> 2;
14066 add_unwind_opcode (op, 1);
14067 }
14068 else if (offset < 0)
14069 {
14070 offset = -offset;
14071 while (offset > 0x100)
14072 {
14073 add_unwind_opcode (0x7f, 1);
14074 offset -= 0x100;
14075 }
14076 op = ((offset - 4) >> 2) | 0x40;
14077 add_unwind_opcode (op, 1);
14078 }
14079}
14080
14081/* Finish the list of unwind opcodes for this function. */
14082static void
14083finish_unwind_opcodes (void)
14084{
14085 valueT op;
14086
14087 if (unwind.fp_used)
14088 {
14089 /* Adjust sp as neccessary. */
14090 unwind.pending_offset += unwind.fp_offset - unwind.frame_size;
14091 flush_pending_unwind ();
14092
14093 /* After restoring sp from the frame pointer. */
14094 op = 0x90 | unwind.fp_reg;
14095 add_unwind_opcode (op, 1);
14096 }
14097 else
14098 flush_pending_unwind ();
14099}
14100
14101
14102/* Start an exception table entry. If idx is nonzero this is an index table
14103 entry. */
14104
14105static void
14106start_unwind_section (const segT text_seg, int idx)
14107{
14108 const char * text_name;
14109 const char * prefix;
14110 const char * prefix_once;
14111 size_t prefix_len;
14112 size_t text_len;
14113 char * sec_name;
14114 size_t sec_name_len;
14115
14116 if (idx)
14117 {
14118 prefix = ELF_STRING_ARM_unwind;
14119 prefix_once = ELF_STRING_ARM_unwind_once;
14120 }
14121 else
14122 {
14123 prefix = ELF_STRING_ARM_unwind_info;
14124 prefix_once = ELF_STRING_ARM_unwind_info_once;
14125 }
14126
14127 text_name = segment_name (text_seg);
14128 if (streq (text_name, ".text"))
14129 text_name = "";
14130
14131 if (strncmp (text_name, ".gnu.linkonce.t.",
14132 strlen (".gnu.linkonce.t.")) == 0)
14133 {
14134 prefix = prefix_once;
14135 text_name += strlen (".gnu.linkonce.t.");
14136 }
14137
14138 prefix_len = strlen (prefix);
14139 text_len = strlen (text_name);
14140 sec_name_len = prefix_len + text_len;
14141 sec_name = alloca (sec_name_len + 1);
14142 memcpy (sec_name, prefix, prefix_len);
14143 memcpy (sec_name + prefix_len, text_name, text_len);
14144 sec_name[prefix_len + text_len] = '\0';
14145
14146 /* Handle COMDAT group. */
14147 if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0)
14148 {
14149 char *section;
14150 size_t len, group_name_len;
14151 const char *group_name = elf_group_name (text_seg);
14152
14153 if (group_name == NULL)
14154 {
14155 as_bad ("Group section `%s' has no group signature",
14156 segment_name (text_seg));
14157 ignore_rest_of_line ();
14158 return;
14159 }
14160 /* We have to construct a fake section directive. */
14161 group_name_len = strlen (group_name);
14162 if (idx)
14163 prefix_len = 13;
14164 else
14165 prefix_len = 16;
14166
14167 len = (sec_name_len
14168 + prefix_len /* ,"aG",%sectiontype, */
14169 + group_name_len /* ,group_name */
14170 + 7); /* ,comdat */
14171
14172 section = alloca (len + 1);
14173 memcpy (section, sec_name, sec_name_len);
14174 if (idx)
14175 memcpy (section + sec_name_len, ",\"aG\",%exidx,", 13);
14176 else
14177 memcpy (section + sec_name_len, ",\"aG\",%progbits,", 16);
14178 memcpy (section + sec_name_len + prefix_len, group_name, group_name_len);
14179 memcpy (section + len - 7, ",comdat", 7);
14180 section [len] = '\0';
14181 set_section (section);
14182 }
14183 else
14184 {
14185 set_section (sec_name);
14186 bfd_set_section_flags (stdoutput, now_seg,
14187 SEC_LOAD | SEC_ALLOC | SEC_READONLY);
14188 }
14189
14190 /* Set the setion link for index tables. */
14191 if (idx)
14192 elf_linked_to_section (now_seg) = text_seg;
14193}
14194
14195
14196/* Start an unwind table entry. HAVE_DATA is nonzero if we have additional
14197 personality routine data. Returns zero, or the index table value for
14198 and inline entry. */
14199
14200static valueT
14201create_unwind_entry (int have_data)
14202{
14203 int size;
14204 addressT where;
2132e3a3 14205 char *ptr;
7ed4c4c5
NC
14206 /* The current word of data. */
14207 valueT data;
14208 /* The number of bytes left in this word. */
14209 int n;
14210
14211 finish_unwind_opcodes ();
14212
14213 /* Remember the current text section. */
14214 unwind.saved_seg = now_seg;
14215 unwind.saved_subseg = now_subseg;
14216
14217 start_unwind_section (now_seg, 0);
14218
14219 if (unwind.personality_routine == NULL)
14220 {
14221 if (unwind.personality_index == -2)
14222 {
14223 if (have_data)
14224 as_bad (_("handerdata in cantunwind frame"));
14225 return 1; /* EXIDX_CANTUNWIND. */
14226 }
14227
14228 /* Use a default personality routine if none is specified. */
14229 if (unwind.personality_index == -1)
14230 {
14231 if (unwind.opcode_count > 3)
14232 unwind.personality_index = 1;
14233 else
14234 unwind.personality_index = 0;
14235 }
14236
14237 /* Space for the personality routine entry. */
14238 if (unwind.personality_index == 0)
14239 {
14240 if (unwind.opcode_count > 3)
14241 as_bad (_("too many unwind opcodes for personality routine 0"));
14242
14243 if (!have_data)
14244 {
14245 /* All the data is inline in the index table. */
14246 data = 0x80;
14247 n = 3;
14248 while (unwind.opcode_count > 0)
14249 {
14250 unwind.opcode_count--;
14251 data = (data << 8) | unwind.opcodes[unwind.opcode_count];
14252 n--;
14253 }
14254
14255 /* Pad with "finish" opcodes. */
14256 while (n--)
14257 data = (data << 8) | 0xb0;
14258
14259 return data;
14260 }
14261 size = 0;
14262 }
14263 else
14264 /* We get two opcodes "free" in the first word. */
14265 size = unwind.opcode_count - 2;
14266 }
14267 else
14268 /* An extra byte is required for the opcode count. */
14269 size = unwind.opcode_count + 1;
14270
14271 size = (size + 3) >> 2;
14272 if (size > 0xff)
14273 as_bad (_("too many unwind opcodes"));
14274
14275 frag_align (2, 0, 0);
14276 record_alignment (now_seg, 2);
14277 unwind.table_entry = expr_build_dot ();
14278
14279 /* Allocate the table entry. */
14280 ptr = frag_more ((size << 2) + 4);
14281 where = frag_now_fix () - ((size << 2) + 4);
14282
14283 switch (unwind.personality_index)
14284 {
14285 case -1:
14286 /* ??? Should this be a PLT generating relocation? */
14287 /* Custom personality routine. */
14288 fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1,
14289 BFD_RELOC_ARM_PREL31);
620b81c1 14290
7ed4c4c5
NC
14291 where += 4;
14292 ptr += 4;
14293
14294 /* Set the first byte to the number of additional words. */
14295 data = size - 1;
14296 n = 3;
14297 break;
14298
14299 /* ABI defined personality routines. */
7ed4c4c5
NC
14300 case 0:
14301 /* Three opcodes bytes are packed into the first word. */
14302 data = 0x80;
14303 n = 3;
84798bd6 14304 break;
7ed4c4c5
NC
14305
14306 case 1:
14307 case 2:
14308 /* The size and first two opcode bytes go in the first word. */
14309 data = ((0x80 + unwind.personality_index) << 8) | size;
14310 n = 2;
14311 break;
14312
14313 default:
14314 /* Should never happen. */
14315 abort ();
14316 }
14317
14318 /* Pack the opcodes into words (MSB first), reversing the list at the same
14319 time. */
14320 while (unwind.opcode_count > 0)
14321 {
14322 if (n == 0)
14323 {
14324 md_number_to_chars (ptr, data, 4);
14325 ptr += 4;
14326 n = 4;
14327 data = 0;
14328 }
14329 unwind.opcode_count--;
14330 n--;
14331 data = (data << 8) | unwind.opcodes[unwind.opcode_count];
14332 }
14333
14334 /* Finish off the last word. */
14335 if (n < 4)
14336 {
14337 /* Pad with "finish" opcodes. */
14338 while (n--)
14339 data = (data << 8) | 0xb0;
14340
14341 md_number_to_chars (ptr, data, 4);
14342 }
14343
14344 if (!have_data)
14345 {
14346 /* Add an empty descriptor if there is no user-specified data. */
14347 ptr = frag_more (4);
14348 md_number_to_chars (ptr, 0, 4);
14349 }
14350
14351 return 0;
14352}
14353
14354
14355/* Parse an unwind_fnstart directive. Simply records the current location. */
14356
14357static void
14358s_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED)
14359{
14360 demand_empty_rest_of_line ();
14361 /* Mark the start of the function. */
14362 unwind.proc_start = expr_build_dot ();
14363
14364 /* Reset the rest of the unwind info. */
14365 unwind.opcode_count = 0;
14366 unwind.table_entry = NULL;
14367 unwind.personality_routine = NULL;
14368 unwind.personality_index = -1;
14369 unwind.frame_size = 0;
14370 unwind.fp_offset = 0;
14371 unwind.fp_reg = 13;
14372 unwind.fp_used = 0;
14373 unwind.sp_restored = 0;
14374}
14375
14376
14377/* Parse a handlerdata directive. Creates the exception handling table entry
14378 for the function. */
14379
14380static void
14381s_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED)
14382{
14383 demand_empty_rest_of_line ();
14384 if (unwind.table_entry)
14385 as_bad (_("dupicate .handlerdata directive"));
14386
14387 create_unwind_entry (1);
14388}
14389
14390/* Parse an unwind_fnend directive. Generates the index table entry. */
14391
14392static void
14393s_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
14394{
14395 long where;
2132e3a3 14396 char *ptr;
7ed4c4c5
NC
14397 valueT val;
14398
14399 demand_empty_rest_of_line ();
14400
14401 /* Add eh table entry. */
14402 if (unwind.table_entry == NULL)
14403 val = create_unwind_entry (0);
14404 else
14405 val = 0;
14406
14407 /* Add index table entry. This is two words. */
14408 start_unwind_section (unwind.saved_seg, 1);
14409 frag_align (2, 0, 0);
14410 record_alignment (now_seg, 2);
14411
14412 ptr = frag_more (8);
14413 where = frag_now_fix () - 8;
14414
14415 /* Self relative offset of the function start. */
14416 fix_new (frag_now, where, 4, unwind.proc_start, 0, 1,
be1b2b4b 14417 BFD_RELOC_ARM_PREL31);
7ed4c4c5 14418
84798bd6
JB
14419 /* Indicate dependency on EHABI-defined personality routines to the
14420 linker, if it hasn't been done already. */
14421 if (unwind.personality_index >= 0 && unwind.personality_index < 3)
14422 {
14423 char *name[] = { "__aeabi_unwind_cpp_pr0",
14424 "__aeabi_unwind_cpp_pr1",
14425 "__aeabi_unwind_cpp_pr2" };
14426 if (!(marked_pr_dependency & (1 << unwind.personality_index)))
14427 {
14428 symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
14429 fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE);
14430 marked_pr_dependency |= 1 << unwind.personality_index;
14431 seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency
14432 = marked_pr_dependency;
14433 }
14434 }
14435
7ed4c4c5
NC
14436 if (val)
14437 /* Inline exception table entry. */
14438 md_number_to_chars (ptr + 4, val, 4);
14439 else
14440 /* Self relative offset of the table entry. */
14441 fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1,
14442 BFD_RELOC_ARM_PREL31);
14443
14444 /* Restore the original section. */
14445 subseg_set (unwind.saved_seg, unwind.saved_subseg);
14446}
14447
14448
14449/* Parse an unwind_cantunwind directive. */
14450
14451static void
14452s_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED)
14453{
14454 demand_empty_rest_of_line ();
14455 if (unwind.personality_routine || unwind.personality_index != -1)
14456 as_bad (_("personality routine specified for cantunwind frame"));
14457
14458 unwind.personality_index = -2;
14459}
14460
14461
14462/* Parse a personalityindex directive. */
14463
14464static void
14465s_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED)
14466{
14467 expressionS exp;
14468
14469 if (unwind.personality_routine || unwind.personality_index != -1)
14470 as_bad (_("duplicate .personalityindex directive"));
14471
14472 SKIP_WHITESPACE ();
14473
14474 expression (&exp);
14475
14476 if (exp.X_op != O_constant
14477 || exp.X_add_number < 0 || exp.X_add_number > 15)
14478 {
14479 as_bad (_("bad personality routine number"));
14480 ignore_rest_of_line ();
14481 return;
14482 }
14483
14484 unwind.personality_index = exp.X_add_number;
14485
14486 demand_empty_rest_of_line ();
14487}
14488
14489
14490/* Parse a personality directive. */
14491
14492static void
14493s_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
14494{
14495 char *name, *p, c;
14496
14497 if (unwind.personality_routine || unwind.personality_index != -1)
14498 as_bad (_("duplicate .personality directive"));
14499
14500 SKIP_WHITESPACE ();
14501 name = input_line_pointer;
14502 c = get_symbol_end ();
14503 p = input_line_pointer;
14504 unwind.personality_routine = symbol_find_or_make (name);
14505 *p = c;
14506 SKIP_WHITESPACE ();
14507 demand_empty_rest_of_line ();
14508}
14509
14510
14511/* Parse a directive saving core registers. */
14512
14513static void
14514s_arm_unwind_save_core (void)
14515{
14516 valueT op;
14517 long range;
14518 int n;
14519
14520 SKIP_WHITESPACE ();
14521 range = reg_list (&input_line_pointer);
14522 if (range == FAIL)
14523 {
14524 as_bad (_("expected register list"));
14525 ignore_rest_of_line ();
14526 return;
14527 }
14528
14529 demand_empty_rest_of_line ();
14530
14531 /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...}
14532 into .unwind_save {..., sp...}. We aren't bothered about the value of
14533 ip because it is clobbered by calls. */
14534 if (unwind.sp_restored && unwind.fp_reg == 12
14535 && (range & 0x3000) == 0x1000)
14536 {
14537 unwind.opcode_count--;
14538 unwind.sp_restored = 0;
14539 range = (range | 0x2000) & ~0x1000;
14540 unwind.pending_offset = 0;
14541 }
14542
14543 /* See if we can use the short opcodes. These pop a block of upto 8
14544 registers starting with r4, plus maybe r14. */
14545 for (n = 0; n < 8; n++)
14546 {
14547 /* Break at the first non-saved register. */
14548 if ((range & (1 << (n + 4))) == 0)
14549 break;
14550 }
14551 /* See if there are any other bits set. */
14552 if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0)
14553 {
14554 /* Use the long form. */
14555 op = 0x8000 | ((range >> 4) & 0xfff);
14556 add_unwind_opcode (op, 2);
14557 }
14558 else
14559 {
14560 /* Use the short form. */
14561 if (range & 0x4000)
14562 op = 0xa8; /* Pop r14. */
14563 else
14564 op = 0xa0; /* Do not pop r14. */
14565 op |= (n - 1);
14566 add_unwind_opcode (op, 1);
14567 }
14568
14569 /* Pop r0-r3. */
14570 if (range & 0xf)
14571 {
14572 op = 0xb100 | (range & 0xf);
14573 add_unwind_opcode (op, 2);
14574 }
14575
14576 /* Record the number of bytes pushed. */
14577 for (n = 0; n < 16; n++)
14578 {
14579 if (range & (1 << n))
14580 unwind.frame_size += 4;
14581 }
14582}
14583
14584
14585/* Parse a directive saving FPA registers. */
14586
14587static void
14588s_arm_unwind_save_fpa (int reg)
14589{
14590 expressionS exp;
14591 int num_regs;
14592 valueT op;
14593
14594 /* Get Number of registers to transfer. */
14595 if (skip_past_comma (&input_line_pointer) != FAIL)
14596 expression (&exp);
14597 else
14598 exp.X_op = O_illegal;
14599
14600 if (exp.X_op != O_constant)
14601 {
14602 as_bad (_("expected , <constant>"));
14603 ignore_rest_of_line ();
14604 return;
14605 }
14606
14607 num_regs = exp.X_add_number;
14608
14609 if (num_regs < 1 || num_regs > 4)
14610 {
14611 as_bad (_("number of registers must be in the range [1:4]"));
14612 ignore_rest_of_line ();
14613 return;
14614 }
14615
14616 demand_empty_rest_of_line ();
14617
14618 if (reg == 4)
14619 {
14620 /* Short form. */
14621 op = 0xb4 | (num_regs - 1);
14622 add_unwind_opcode (op, 1);
14623 }
14624 else
14625 {
14626 /* Long form. */
14627 op = 0xc800 | (reg << 4) | (num_regs - 1);
14628 add_unwind_opcode (op, 2);
14629 }
14630 unwind.frame_size += num_regs * 12;
14631}
14632
14633
14634/* Parse a directive saving VFP registers. */
14635
14636static void
14637s_arm_unwind_save_vfp (void)
14638{
14639 int count;
14640 int reg;
14641 valueT op;
14642
14643 count = vfp_parse_reg_list (&input_line_pointer, &reg, 1);
14644 if (count == FAIL)
14645 {
14646 as_bad (_("expected register list"));
14647 ignore_rest_of_line ();
14648 return;
14649 }
14650
14651 demand_empty_rest_of_line ();
14652
14653 if (reg == 8)
14654 {
14655 /* Short form. */
14656 op = 0xb8 | (count - 1);
14657 add_unwind_opcode (op, 1);
14658 }
14659 else
14660 {
14661 /* Long form. */
14662 op = 0xb300 | (reg << 4) | (count - 1);
14663 add_unwind_opcode (op, 2);
14664 }
14665 unwind.frame_size += count * 8 + 4;
14666}
14667
14668
14669/* Parse a directive saving iWMMXt registers. */
14670
14671static void
14672s_arm_unwind_save_wmmx (void)
14673{
14674 int reg;
14675 int hi_reg;
14676 int i;
14677 unsigned wcg_mask;
14678 unsigned wr_mask;
14679 valueT op;
14680
14681 if (*input_line_pointer == '{')
14682 input_line_pointer++;
14683
14684 wcg_mask = 0;
14685 wr_mask = 0;
14686 do
14687 {
14688 reg = arm_reg_parse (&input_line_pointer,
14689 all_reg_maps[REG_TYPE_IWMMXT].htab);
14690
14691 if (wr_register (reg))
14692 {
14693 i = reg & ~WR_PREFIX;
14694 if (wr_mask >> i)
14695 as_tsktsk (_("register list not in ascending order"));
14696 wr_mask |= 1 << i;
14697 }
14698 else if (wcg_register (reg))
14699 {
14700 i = (reg & ~WC_PREFIX) - 8;
14701 if (wcg_mask >> i)
14702 as_tsktsk (_("register list not in ascending order"));
14703 wcg_mask |= 1 << i;
14704 }
14705 else
14706 {
14707 as_bad (_("expected wr or wcgr"));
14708 goto error;
14709 }
14710
14711 SKIP_WHITESPACE ();
14712 if (*input_line_pointer == '-')
14713 {
14714 hi_reg = arm_reg_parse (&input_line_pointer,
14715 all_reg_maps[REG_TYPE_IWMMXT].htab);
14716 if (wr_register (reg) && wr_register (hi_reg))
14717 {
14718 for (; reg < hi_reg; reg++)
14719 wr_mask |= 1 << (reg & ~WR_PREFIX);
14720 }
14721 else if (wcg_register (reg) && wcg_register (hi_reg))
14722 {
14723 for (; reg < hi_reg; reg++)
14724 wcg_mask |= 1 << ((reg & ~WC_PREFIX) - 8);
14725 }
14726 else
14727 {
14728 as_bad (_("bad register range"));
14729 goto error;
14730 }
14731 }
14732 }
14733 while (skip_past_comma (&input_line_pointer) != FAIL);
14734
14735 SKIP_WHITESPACE ();
14736 if (*input_line_pointer == '}')
14737 input_line_pointer++;
14738
14739 demand_empty_rest_of_line ();
14740
14741 if (wr_mask && wcg_mask)
14742 {
14743 as_bad (_("inconsistent register types"));
14744 goto error;
14745 }
14746
14747 /* Generate any deferred opcodes becuuse we're going to be looking at
14748 the list. */
14749 flush_pending_unwind ();
14750
14751 if (wcg_mask)
14752 {
14753 for (i = 0; i < 16; i++)
14754 {
14755 if (wcg_mask & (1 << i))
14756 unwind.frame_size += 4;
14757 }
14758 op = 0xc700 | wcg_mask;
14759 add_unwind_opcode (op, 2);
14760 }
14761 else
14762 {
14763 for (i = 0; i < 16; i++)
14764 {
14765 if (wr_mask & (1 << i))
14766 unwind.frame_size += 8;
14767 }
14768 /* Attempt to combine with a previous opcode. We do this because gcc
14769 likes to output separate unwind directives for a single block of
14770 registers. */
14771 if (unwind.opcode_count > 0)
14772 {
14773 i = unwind.opcodes[unwind.opcode_count - 1];
14774 if ((i & 0xf8) == 0xc0)
14775 {
14776 i &= 7;
14777 /* Only merge if the blocks are contiguous. */
14778 if (i < 6)
14779 {
14780 if ((wr_mask & 0xfe00) == (1 << 9))
14781 {
14782 wr_mask |= ((1 << (i + 11)) - 1) & 0xfc00;
14783 unwind.opcode_count--;
14784 }
14785 }
14786 else if (i == 6 && unwind.opcode_count >= 2)
14787 {
14788 i = unwind.opcodes[unwind.opcode_count - 2];
14789 reg = i >> 4;
14790 i &= 0xf;
14791
14792 op = 0xffff << (reg - 1);
14793 if (reg > 0
14794 || ((wr_mask & op) == (1u << (reg - 1))))
14795 {
14796 op = (1 << (reg + i + 1)) - 1;
14797 op &= ~((1 << reg) - 1);
14798 wr_mask |= op;
14799 unwind.opcode_count -= 2;
14800 }
14801 }
14802 }
14803 }
14804
14805 hi_reg = 15;
14806 /* We want to generate opcodes in the order the registers have been
14807 saved, ie. descending order. */
14808 for (reg = 15; reg >= -1; reg--)
14809 {
14810 /* Save registers in blocks. */
14811 if (reg < 0
14812 || !(wr_mask & (1 << reg)))
14813 {
14814 /* We found an unsaved reg. Generate opcodes to save the
14815 preceeding block. */
14816 if (reg != hi_reg)
14817 {
14818 if (reg == 9)
14819 {
14820 /* Short form. */
14821 op = 0xc0 | (hi_reg - 10);
14822 add_unwind_opcode (op, 1);
14823 }
14824 else
14825 {
14826 /* Long form. */
14827 op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
14828 add_unwind_opcode (op, 2);
14829 }
14830 }
14831 hi_reg = reg - 1;
14832 }
14833 }
14834 }
14835 return;
14836error:
14837 ignore_rest_of_line ();
14838}
14839
14840
14841/* Parse an unwind_save directive. */
14842
14843static void
14844s_arm_unwind_save (int ignored ATTRIBUTE_UNUSED)
14845{
14846 char *saved_ptr;
14847 int reg;
14848
14849 /* Figure out what sort of save we have. */
14850 SKIP_WHITESPACE ();
14851 saved_ptr = input_line_pointer;
14852
14853 reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_FN].htab);
14854 if (reg != FAIL)
14855 {
14856 s_arm_unwind_save_fpa (reg);
14857 return;
14858 }
14859
14860 if (*input_line_pointer == '{')
14861 input_line_pointer++;
14862
14863 SKIP_WHITESPACE ();
14864
14865 reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_RN].htab);
14866 if (reg != FAIL)
14867 {
14868 input_line_pointer = saved_ptr;
14869 s_arm_unwind_save_core ();
14870 return;
14871 }
14872
14873 reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_DN].htab);
14874 if (reg != FAIL)
14875 {
14876 input_line_pointer = saved_ptr;
14877 s_arm_unwind_save_vfp ();
14878 return;
14879 }
14880
14881 reg = arm_reg_parse (&input_line_pointer,
14882 all_reg_maps[REG_TYPE_IWMMXT].htab);
14883 if (reg != FAIL)
14884 {
14885 input_line_pointer = saved_ptr;
14886 s_arm_unwind_save_wmmx ();
14887 return;
14888 }
14889
14890 /* TODO: Maverick registers. */
14891 as_bad (_("unrecognised register"));
14892}
14893
14894
14895/* Parse an unwind_movsp directive. */
14896
14897static void
14898s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
14899{
14900 int reg;
14901 valueT op;
14902
14903 SKIP_WHITESPACE ();
14904 reg = reg_required_here (&input_line_pointer, -1);
14905 if (reg == FAIL)
14906 {
14907 as_bad (_("ARM register expected"));
14908 ignore_rest_of_line ();
14909 return;
14910 }
14911
14912 if (reg == 13 || reg == 15)
14913 {
14914 as_bad (_("r%d not permitted in .unwind_movsp directive"), reg);
14915 ignore_rest_of_line ();
14916 return;
14917 }
14918
14919 if (unwind.fp_reg != 13)
14920 as_bad (_("unexpected .unwind_movsp directive"));
14921
14922 /* Generate opcode to restore the value. */
14923 op = 0x90 | reg;
14924 add_unwind_opcode (op, 1);
14925
14926 /* Record the information for later. */
14927 unwind.fp_reg = reg;
14928 unwind.fp_offset = unwind.frame_size;
14929 unwind.sp_restored = 1;
14930 demand_empty_rest_of_line ();
14931}
14932
14933
14934/* Parse #<number>. */
14935
14936static int
14937require_hashconst (int * val)
14938{
14939 expressionS exp;
14940
14941 SKIP_WHITESPACE ();
14942 if (*input_line_pointer == '#')
14943 {
14944 input_line_pointer++;
14945 expression (&exp);
14946 }
14947 else
14948 exp.X_op = O_illegal;
14949
14950 if (exp.X_op != O_constant)
14951 {
14952 as_bad (_("expected #constant"));
14953 ignore_rest_of_line ();
14954 return FAIL;
14955 }
14956 *val = exp.X_add_number;
14957 return SUCCESS;
14958}
14959
14960/* Parse an unwind_pad directive. */
14961
14962static void
14963s_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED)
14964{
14965 int offset;
14966
14967 if (require_hashconst (&offset) == FAIL)
14968 return;
14969
14970 if (offset & 3)
14971 {
14972 as_bad (_("stack increment must be multiple of 4"));
14973 ignore_rest_of_line ();
14974 return;
14975 }
14976
14977 /* Don't generate any opcodes, just record the details for later. */
14978 unwind.frame_size += offset;
14979 unwind.pending_offset += offset;
14980
14981 demand_empty_rest_of_line ();
14982}
14983
14984/* Parse an unwind_setfp directive. */
14985
14986static void
14987s_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED)
14988{
14989 int sp_reg;
14990 int fp_reg;
14991 int offset;
14992
14993 fp_reg = reg_required_here (&input_line_pointer, -1);
14994 if (skip_past_comma (&input_line_pointer) == FAIL)
14995 sp_reg = FAIL;
14996 else
14997 sp_reg = reg_required_here (&input_line_pointer, -1);
14998
14999 if (fp_reg == FAIL || sp_reg == FAIL)
15000 {
15001 as_bad (_("expected <reg>, <reg>"));
15002 ignore_rest_of_line ();
15003 return;
15004 }
15005
15006 /* Optonal constant. */
15007 if (skip_past_comma (&input_line_pointer) != FAIL)
15008 {
15009 if (require_hashconst (&offset) == FAIL)
15010 return;
15011 }
15012 else
15013 offset = 0;
15014
15015 demand_empty_rest_of_line ();
15016
15017 if (sp_reg != 13 && sp_reg != unwind.fp_reg)
15018 {
15019 as_bad (_("register must be either sp or set by a previous"
15020 "unwind_movsp directive"));
15021 return;
15022 }
15023
15024 /* Don't generate any opcodes, just record the information for later. */
15025 unwind.fp_reg = fp_reg;
15026 unwind.fp_used = 1;
15027 if (sp_reg == 13)
15028 unwind.fp_offset = unwind.frame_size - offset;
15029 else
15030 unwind.fp_offset -= offset;
15031}
15032
15033/* Parse an unwind_raw directive. */
15034
15035static void
15036s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
15037{
15038 expressionS exp;
15039 /* This is an arbitary limit. */
15040 unsigned char op[16];
15041 int count;
15042
15043 SKIP_WHITESPACE ();
15044 expression (&exp);
15045 if (exp.X_op == O_constant
15046 && skip_past_comma (&input_line_pointer) != FAIL)
15047 {
15048 unwind.frame_size += exp.X_add_number;
15049 expression (&exp);
15050 }
15051 else
15052 exp.X_op = O_illegal;
15053
15054 if (exp.X_op != O_constant)
15055 {
15056 as_bad (_("expected <offset>, <opcode>"));
15057 ignore_rest_of_line ();
15058 return;
15059 }
15060
15061 count = 0;
15062
15063 /* Parse the opcode. */
15064 for (;;)
15065 {
15066 if (count >= 16)
15067 {
15068 as_bad (_("unwind opcode too long"));
15069 ignore_rest_of_line ();
15070 }
15071 if (exp.X_op != O_constant || exp.X_add_number & ~0xff)
15072 {
15073 as_bad (_("invalid unwind opcode"));
15074 ignore_rest_of_line ();
15075 return;
15076 }
15077 op[count++] = exp.X_add_number;
15078
15079 /* Parse the next byte. */
15080 if (skip_past_comma (&input_line_pointer) == FAIL)
15081 break;
15082
15083 expression (&exp);
15084 }
15085
15086 /* Add the opcode bytes in reverse order. */
15087 while (count--)
15088 add_unwind_opcode (op[count], 1);
15089
15090 demand_empty_rest_of_line ();
15091}
eb043451 15092
b99bd4ef
NC
15093#endif /* OBJ_ELF */
15094
15095/* This is called from HANDLE_ALIGN in write.c. Fill in the contents
15096 of an rs_align_code fragment. */
15097
15098void
a737bd4d 15099arm_handle_align (fragS * fragP)
b99bd4ef
NC
15100{
15101 static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
15102 static char const thumb_noop[2] = { 0xc0, 0x46 };
15103 static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
15104 static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
15105
15106 int bytes, fix, noop_size;
15107 char * p;
15108 const char * noop;
cc8a6dd0 15109
b99bd4ef
NC
15110 if (fragP->fr_type != rs_align_code)
15111 return;
15112
15113 bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
15114 p = fragP->fr_literal + fragP->fr_fix;
15115 fix = 0;
cc8a6dd0 15116
b99bd4ef
NC
15117 if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
15118 bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
cc8a6dd0 15119
b99bd4ef
NC
15120 if (fragP->tc_frag_data)
15121 {
15122 if (target_big_endian)
15123 noop = thumb_bigend_noop;
15124 else
15125 noop = thumb_noop;
15126 noop_size = sizeof (thumb_noop);
15127 }
15128 else
15129 {
15130 if (target_big_endian)
15131 noop = arm_bigend_noop;
15132 else
15133 noop = arm_noop;
15134 noop_size = sizeof (arm_noop);
15135 }
cc8a6dd0 15136
b99bd4ef
NC
15137 if (bytes & (noop_size - 1))
15138 {
15139 fix = bytes & (noop_size - 1);
15140 memset (p, 0, fix);
15141 p += fix;
15142 bytes -= fix;
15143 }
15144
15145 while (bytes >= noop_size)
15146 {
15147 memcpy (p, noop, noop_size);
15148 p += noop_size;
15149 bytes -= noop_size;
15150 fix += noop_size;
15151 }
cc8a6dd0 15152
b99bd4ef
NC
15153 fragP->fr_fix += fix;
15154 fragP->fr_var = noop_size;
15155}
15156
15157/* Called from md_do_align. Used to create an alignment
15158 frag in a code section. */
15159
15160void
a737bd4d 15161arm_frag_align_code (int n, int max)
b99bd4ef
NC
15162{
15163 char * p;
15164
2d2255b5 15165 /* We assume that there will never be a requirement
b99bd4ef
NC
15166 to support alignments greater than 32 bytes. */
15167 if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
15168 as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
cc8a6dd0 15169
b99bd4ef
NC
15170 p = frag_var (rs_align_code,
15171 MAX_MEM_FOR_RS_ALIGN_CODE,
15172 1,
15173 (relax_substateT) max,
15174 (symbolS *) NULL,
15175 (offsetT) n,
15176 (char *) NULL);
15177 *p = 0;
b99bd4ef
NC
15178}
15179
15180/* Perform target specific initialisation of a frag. */
15181
15182void
a737bd4d 15183arm_init_frag (fragS * fragP)
b99bd4ef
NC
15184{
15185 /* Record whether this frag is in an ARM or a THUMB area. */
15186 fragP->tc_frag_data = thumb_mode;
15187}
a737bd4d 15188
a394c00f
NC
15189#ifdef OBJ_ELF
15190
15191/* Convert REGNAME to a DWARF-2 register number. */
15192
15193int
15194tc_arm_regname_to_dw2regnum (const char *regname)
15195{
15196 unsigned int i;
15197
15198 for (i = 0; rn_table[i].name; i++)
15199 if (streq (regname, rn_table[i].name))
15200 return rn_table[i].number;
15201
15202 return -1;
15203}
15204
15205/* Initialize the DWARF-2 unwind information for this procedure. */
15206
15207void
15208tc_arm_frame_initial_instructions (void)
15209{
15210 cfi_add_CFA_def_cfa (REG_SP, 0);
15211}
15212#endif
15213
a737bd4d
NC
15214/* This table describes all the machine specific pseudo-ops the assembler
15215 has to support. The fields are:
15216 pseudo-op name without dot
15217 function to call to execute this pseudo-op
15218 Integer arg to pass to the function. */
15219
15220const pseudo_typeS md_pseudo_table[] =
15221{
15222 /* Never called because '.req' does not start a line. */
15223 { "req", s_req, 0 },
15224 { "unreq", s_unreq, 0 },
15225 { "bss", s_bss, 0 },
15226 { "align", s_align, 0 },
15227 { "arm", s_arm, 0 },
15228 { "thumb", s_thumb, 0 },
15229 { "code", s_code, 0 },
15230 { "force_thumb", s_force_thumb, 0 },
15231 { "thumb_func", s_thumb_func, 0 },
15232 { "thumb_set", s_thumb_set, 0 },
15233 { "even", s_even, 0 },
15234 { "ltorg", s_ltorg, 0 },
15235 { "pool", s_ltorg, 0 },
15236#ifdef OBJ_ELF
15237 { "word", s_arm_elf_cons, 4 },
15238 { "long", s_arm_elf_cons, 4 },
15239 { "rel31", s_arm_rel31, 0 },
7ed4c4c5
NC
15240 { "fnstart", s_arm_unwind_fnstart, 0 },
15241 { "fnend", s_arm_unwind_fnend, 0 },
15242 { "cantunwind", s_arm_unwind_cantunwind, 0 },
15243 { "personality", s_arm_unwind_personality, 0 },
15244 { "personalityindex", s_arm_unwind_personalityindex, 0 },
15245 { "handlerdata", s_arm_unwind_handlerdata, 0 },
15246 { "save", s_arm_unwind_save, 0 },
15247 { "movsp", s_arm_unwind_movsp, 0 },
15248 { "pad", s_arm_unwind_pad, 0 },
15249 { "setfp", s_arm_unwind_setfp, 0 },
15250 { "unwind_raw", s_arm_unwind_raw, 0 },
a737bd4d
NC
15251#else
15252 { "word", cons, 4},
15253#endif
15254 { "extend", float_cons, 'x' },
15255 { "ldouble", float_cons, 'x' },
15256 { "packed", float_cons, 'p' },
15257 { 0, 0, 0 }
15258};