* bfd/bfd-in.h (bfd_is_arm_mapping_symbol_name): Rename from
[deliverable/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
25 Software Foundation, 59 Temple Place - Suite 330, Boston, MA
26 02111-1307, USA. */
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);
1140#ifdef STRIP_UNDERSCORE
1141 if (preserved_copy_of_name[0] == '_')
1142 preserved_copy_of_name++;
1143#endif
1144
1145#ifdef tc_canonicalize_symbol_name
1146 preserved_copy_of_name =
1147 tc_canonicalize_symbol_name (preserved_copy_of_name);
1148#endif
1149
1150 S_SET_NAME (symbolP, preserved_copy_of_name);
1151
1152 S_SET_SEGMENT (symbolP, segment);
1153 S_SET_VALUE (symbolP, valu);
c62e1cc3 1154 symbol_clear_list_pointers (symbolP);
b99bd4ef
NC
1155
1156 symbol_set_frag (symbolP, frag);
1157
1158 /* Link to end of symbol chain. */
1159 {
1160 extern int symbol_table_frozen;
a737bd4d 1161
b99bd4ef
NC
1162 if (symbol_table_frozen)
1163 abort ();
1164 }
1165
1166 symbol_append (symbolP, symbol_lastP, & symbol_rootP, & symbol_lastP);
1167
1168 obj_symbol_new_hook (symbolP);
1169
1170#ifdef tc_symbol_new_hook
1171 tc_symbol_new_hook (symbolP);
1172#endif
1173
1174#ifdef DEBUG_SYMS
1175 verify_symbol_chain (symbol_rootP, symbol_lastP);
1176#endif /* DEBUG_SYMS */
1177}
1178
1179/* Check that an immediate is valid.
1180 If so, convert it to the right format. */
1181
1182static unsigned int
a737bd4d 1183validate_immediate (unsigned int val)
b99bd4ef
NC
1184{
1185 unsigned int a;
1186 unsigned int i;
1187
1188#define rotate_left(v, n) (v << n | v >> (32 - n))
1189
1190 for (i = 0; i < 32; i += 2)
1191 if ((a = rotate_left (val, i)) <= 0xff)
1192 return a | (i << 7); /* 12-bit pack: [shift-cnt,const]. */
1193
1194 return FAIL;
1195}
1196
2d2255b5 1197/* Check to see if an immediate can be computed as two separate immediate
b99bd4ef
NC
1198 values, added together. We already know that this value cannot be
1199 computed by just one ARM instruction. */
1200
1201static unsigned int
a737bd4d
NC
1202validate_immediate_twopart (unsigned int val,
1203 unsigned int * highpart)
b99bd4ef
NC
1204{
1205 unsigned int a;
1206 unsigned int i;
1207
1208 for (i = 0; i < 32; i += 2)
1209 if (((a = rotate_left (val, i)) & 0xff) != 0)
1210 {
1211 if (a & 0xff00)
1212 {
1213 if (a & ~ 0xffff)
1214 continue;
1215 * highpart = (a >> 8) | ((i + 24) << 7);
1216 }
1217 else if (a & 0xff0000)
1218 {
1219 if (a & 0xff000000)
1220 continue;
1221 * highpart = (a >> 16) | ((i + 16) << 7);
1222 }
1223 else
1224 {
1225 assert (a & 0xff000000);
1226 * highpart = (a >> 24) | ((i + 8) << 7);
1227 }
1228
1229 return (a & 0xff) | (i << 7);
1230 }
1231
1232 return FAIL;
1233}
1234
1235static int
a737bd4d 1236validate_offset_imm (unsigned int val, int hwse)
b99bd4ef
NC
1237{
1238 if ((hwse && val > 255) || val > 4095)
1239 return FAIL;
1240 return val;
1241}
1242
6057a28f
NC
1243\f
1244#ifdef OBJ_ELF
6057a28f 1245/* This code is to handle mapping symbols as defined in the ARM ELF spec.
9d2da7ca
JB
1246 (See "Mapping symbols", section 4.5.5, ARM AAELF version 1.0).
1247 Note that previously, $a and $t has type STT_FUNC (BSF_OBJECT flag),
1248 and $d has type STT_OBJECT (BSF_OBJECT flag). Now all three are untyped. */
6057a28f 1249
69b97547
NC
1250static enum mstate mapstate = MAP_UNDEFINED;
1251
6057a28f
NC
1252static void
1253mapping_state (enum mstate state)
1254{
6057a28f
NC
1255 symbolS * symbolP;
1256 const char * symname;
1257 int type;
1258
1259 if (mapstate == state)
1260 /* The mapping symbol has already been emitted.
1261 There is nothing else to do. */
1262 return;
1263
1264 mapstate = state;
1265
1266 switch (state)
1267 {
1268 case MAP_DATA:
1269 symname = "$d";
9d2da7ca 1270 type = BSF_NO_FLAGS;
6057a28f
NC
1271 break;
1272 case MAP_ARM:
1273 symname = "$a";
9d2da7ca 1274 type = BSF_NO_FLAGS;
6057a28f
NC
1275 break;
1276 case MAP_THUMB:
1277 symname = "$t";
9d2da7ca 1278 type = BSF_NO_FLAGS;
6057a28f 1279 break;
69b97547 1280 case MAP_UNDEFINED:
a737bd4d 1281 return;
6057a28f
NC
1282 default:
1283 abort ();
1284 }
1285
84798bd6 1286 seg_info (now_seg)->tc_segment_info_data.mapstate = state;
69b97547 1287
6057a28f
NC
1288 symbolP = symbol_new (symname, now_seg, (valueT) frag_now_fix (), frag_now);
1289 symbol_table_insert (symbolP);
1290 symbol_get_bfdsym (symbolP)->flags |= type | BSF_LOCAL;
a737bd4d 1291
6057a28f
NC
1292 switch (state)
1293 {
1294 case MAP_ARM:
1295 THUMB_SET_FUNC (symbolP, 0);
1296 ARM_SET_THUMB (symbolP, 0);
1297 ARM_SET_INTERWORK (symbolP, support_interwork);
1298 break;
a737bd4d 1299
6057a28f
NC
1300 case MAP_THUMB:
1301 THUMB_SET_FUNC (symbolP, 1);
1302 ARM_SET_THUMB (symbolP, 1);
1303 ARM_SET_INTERWORK (symbolP, support_interwork);
1304 break;
a737bd4d 1305
6057a28f
NC
1306 case MAP_DATA:
1307 default:
1308 return;
1309 }
1310}
1311
a737bd4d
NC
1312/* When we change sections we need to issue a new mapping symbol. */
1313
1314void
1315arm_elf_change_section (void)
1316{
1317 flagword flags;
84798bd6 1318 segment_info_type *seginfo;
a737bd4d 1319
40a18ebd
NC
1320 /* Link an unlinked unwind index table section to the .text section. */
1321 if (elf_section_type (now_seg) == SHT_ARM_EXIDX
1322 && elf_linked_to_section (now_seg) == NULL)
1323 elf_linked_to_section (now_seg) = text_section;
1324
a737bd4d
NC
1325 if (!SEG_NORMAL (now_seg))
1326 return;
1327
1328 flags = bfd_get_section_flags (stdoutput, now_seg);
1329
1330 /* We can ignore sections that only contain debug info. */
1331 if ((flags & SEC_ALLOC) == 0)
1332 return;
1333
84798bd6
JB
1334 seginfo = seg_info (now_seg);
1335 mapstate = seginfo->tc_segment_info_data.mapstate;
1336 marked_pr_dependency = seginfo->tc_segment_info_data.marked_pr_dependency;
a737bd4d 1337}
40a18ebd
NC
1338
1339int
1340arm_elf_section_type (const char * str, size_t len)
1341{
1342 if (len == 5 && strncmp (str, "exidx", 5) == 0)
1343 return SHT_ARM_EXIDX;
1344
1345 return -1;
1346}
a737bd4d
NC
1347#else
1348#define mapping_state(a)
1349#endif /* OBJ_ELF */
1350\f
1351/* arm_reg_parse () := if it looks like a register, return its token and
1352 advance the pointer. */
1353
1354static int
1355arm_reg_parse (char ** ccp, struct hash_control * htab)
1356{
1357 char * start = * ccp;
1358 char c;
1359 char * p;
1360 struct reg_entry * reg;
1361
1362#ifdef REGISTER_PREFIX
1363 if (*start != REGISTER_PREFIX)
1364 return FAIL;
1365 p = start + 1;
1366#else
1367 p = start;
1368#ifdef OPTIONAL_REGISTER_PREFIX
1369 if (*p == OPTIONAL_REGISTER_PREFIX)
1370 p++, start++;
1371#endif
1372#endif
1373 if (!ISALPHA (*p) || !is_name_beginner (*p))
1374 return FAIL;
1375
1376 c = *p++;
1377 while (ISALPHA (c) || ISDIGIT (c) || c == '_')
1378 c = *p++;
1379
1380 *--p = 0;
1381 reg = (struct reg_entry *) hash_find (htab, start);
1382 *p = c;
1383
1384 if (reg)
1385 {
1386 *ccp = p;
1387 return reg->number;
1388 }
1389
1390 return FAIL;
1391}
1392
1393/* Search for the following register name in each of the possible reg name
1394 tables. Return the classification if found, or REG_TYPE_MAX if not
1395 present. */
6057a28f 1396
a737bd4d
NC
1397static enum arm_reg_type
1398arm_reg_parse_any (char *cp)
6057a28f 1399{
a737bd4d 1400 int i;
6057a28f 1401
a737bd4d
NC
1402 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
1403 if (arm_reg_parse (&cp, all_reg_maps[i].htab) != FAIL)
1404 return (enum arm_reg_type) i;
6057a28f 1405
a737bd4d
NC
1406 return REG_TYPE_MAX;
1407}
6057a28f 1408
a737bd4d
NC
1409static void
1410opcode_select (int width)
1411{
1412 switch (width)
1413 {
1414 case 16:
1415 if (! thumb_mode)
1416 {
1417 if (! (cpu_variant & ARM_EXT_V4T))
1418 as_bad (_("selected processor does not support THUMB opcodes"));
6057a28f 1419
a737bd4d
NC
1420 thumb_mode = 1;
1421 /* No need to force the alignment, since we will have been
1422 coming from ARM mode, which is word-aligned. */
1423 record_alignment (now_seg, 1);
1424 }
1425 mapping_state (MAP_THUMB);
1426 break;
1427
1428 case 32:
1429 if (thumb_mode)
1430 {
1431 if ((cpu_variant & ARM_ALL) == ARM_EXT_V4T)
1432 as_bad (_("selected processor does not support ARM opcodes"));
1433
1434 thumb_mode = 0;
1435
1436 if (!need_pass_2)
1437 frag_align (2, 0, 0);
1438
1439 record_alignment (now_seg, 1);
1440 }
1441 mapping_state (MAP_ARM);
1442 break;
1443
1444 default:
1445 as_bad (_("invalid instruction size selected (%d)"), width);
1446 }
6057a28f 1447}
6057a28f 1448
b99bd4ef 1449static void
a737bd4d 1450s_req (int a ATTRIBUTE_UNUSED)
b99bd4ef 1451{
f03698e6 1452 as_bad (_("invalid syntax for .req directive"));
b99bd4ef
NC
1453}
1454
0bbf2aa4
NC
1455/* The .unreq directive deletes an alias which was previously defined
1456 by .req. For example:
1457
1458 my_alias .req r11
1459 .unreq my_alias */
1460
1461static void
1462s_unreq (int a ATTRIBUTE_UNUSED)
1463{
a737bd4d 1464 char * name;
0bbf2aa4
NC
1465 char saved_char;
1466
1467 skip_whitespace (input_line_pointer);
1468 name = input_line_pointer;
1469
1470 while (*input_line_pointer != 0
1471 && *input_line_pointer != ' '
1472 && *input_line_pointer != '\n')
1473 ++input_line_pointer;
1474
1475 saved_char = *input_line_pointer;
1476 *input_line_pointer = 0;
1477
1478 if (*name)
1479 {
1480 enum arm_reg_type req_type = arm_reg_parse_any (name);
1481
1482 if (req_type != REG_TYPE_MAX)
1483 {
1484 char *temp_name = name;
1485 int req_no = arm_reg_parse (&temp_name, all_reg_maps[req_type].htab);
1486
1487 if (req_no != FAIL)
1488 {
1489 struct reg_entry *req_entry;
1490
1491 /* Check to see if this alias is a builtin one. */
1492 req_entry = hash_delete (all_reg_maps[req_type].htab, name);
1493
1494 if (!req_entry)
1495 as_bad (_("unreq: missing hash entry for \"%s\""), name);
1496 else if (req_entry->builtin)
67c1ffbe 1497 /* FIXME: We are deleting a built in register alias which
0bbf2aa4
NC
1498 points to a const data structure, so we only need to
1499 free up the memory used by the key in the hash table.
1500 Unfortunately we have not recorded this value, so this
1501 is a memory leak. */
1502 /* FIXME: Should we issue a warning message ? */
1503 ;
1504 else
1505 {
67c1ffbe 1506 /* Deleting a user defined alias. We need to free the
0bbf2aa4
NC
1507 key and the value, but fortunately the key is the same
1508 as the value->name field. */
1509 free ((char *) req_entry->name);
1510 free (req_entry);
1511 }
1512 }
1513 else
1514 as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
1515 }
1516 else
1517 as_bad (_(".unreq: unrecognized symbol \"%s\""), name);
1518 }
1519 else
1520 as_bad (_("invalid syntax for .unreq directive"));
1521
1522 *input_line_pointer = saved_char;
1523 demand_empty_rest_of_line ();
1524}
1525
b99bd4ef 1526static void
a737bd4d 1527s_bss (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1528{
1529 /* We don't support putting frags in the BSS segment, we fake it by
1530 marking in_bss, then looking at s_skip for clues. */
1531 subseg_set (bss_section, 0);
1532 demand_empty_rest_of_line ();
6057a28f 1533 mapping_state (MAP_DATA);
b99bd4ef
NC
1534}
1535
1536static void
a737bd4d 1537s_even (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1538{
1539 /* Never make frag if expect extra pass. */
1540 if (!need_pass_2)
1541 frag_align (1, 0, 0);
1542
1543 record_alignment (now_seg, 1);
1544
1545 demand_empty_rest_of_line ();
1546}
1547
1548static void
a737bd4d 1549s_ltorg (int ignored ATTRIBUTE_UNUSED)
b99bd4ef 1550{
3d0c9500
NC
1551 unsigned int entry;
1552 literal_pool * pool;
b99bd4ef
NC
1553 char sym_name[20];
1554
3d0c9500
NC
1555 pool = find_literal_pool ();
1556 if (pool == NULL
1557 || pool->symbol == NULL
1558 || pool->next_free_entry == 0)
b99bd4ef
NC
1559 return;
1560
69b97547
NC
1561 mapping_state (MAP_DATA);
1562
b99bd4ef
NC
1563 /* Align pool as you have word accesses.
1564 Only make a frag if we have to. */
1565 if (!need_pass_2)
1566 frag_align (2, 0, 0);
1567
1568 record_alignment (now_seg, 2);
1569
3d0c9500 1570 sprintf (sym_name, "$$lit_\002%x", pool->id);
b99bd4ef 1571
3d0c9500 1572 symbol_locate (pool->symbol, sym_name, now_seg,
b99bd4ef 1573 (valueT) frag_now_fix (), frag_now);
3d0c9500 1574 symbol_table_insert (pool->symbol);
b99bd4ef 1575
3d0c9500 1576 ARM_SET_THUMB (pool->symbol, thumb_mode);
b99bd4ef
NC
1577
1578#if defined OBJ_COFF || defined OBJ_ELF
3d0c9500 1579 ARM_SET_INTERWORK (pool->symbol, support_interwork);
b99bd4ef
NC
1580#endif
1581
3d0c9500 1582 for (entry = 0; entry < pool->next_free_entry; entry ++)
b99bd4ef 1583 /* First output the expression in the instruction to the pool. */
3d0c9500 1584 emit_expr (&(pool->literals[entry]), 4); /* .word */
b99bd4ef 1585
3d0c9500
NC
1586 /* Mark the pool as empty. */
1587 pool->next_free_entry = 0;
1588 pool->symbol = NULL;
b99bd4ef
NC
1589}
1590
1591/* Same as s_align_ptwo but align 0 => align 2. */
1592
1593static void
a737bd4d 1594s_align (int unused ATTRIBUTE_UNUSED)
b99bd4ef 1595{
a737bd4d
NC
1596 int temp;
1597 long temp_fill;
b99bd4ef
NC
1598 long max_alignment = 15;
1599
1600 temp = get_absolute_expression ();
1601 if (temp > max_alignment)
f03698e6 1602 as_bad (_("alignment too large: %d assumed"), temp = max_alignment);
b99bd4ef
NC
1603 else if (temp < 0)
1604 {
f03698e6 1605 as_bad (_("alignment negative. 0 assumed."));
b99bd4ef
NC
1606 temp = 0;
1607 }
1608
1609 if (*input_line_pointer == ',')
1610 {
1611 input_line_pointer++;
1612 temp_fill = get_absolute_expression ();
1613 }
1614 else
1615 temp_fill = 0;
1616
1617 if (!temp)
1618 temp = 2;
1619
1620 /* Only make a frag if we HAVE to. */
1621 if (temp && !need_pass_2)
1622 frag_align (temp, (int) temp_fill, 0);
1623 demand_empty_rest_of_line ();
1624
1625 record_alignment (now_seg, temp);
1626}
1627
1628static void
a737bd4d 1629s_force_thumb (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1630{
1631 /* If we are not already in thumb mode go into it, EVEN if
1632 the target processor does not support thumb instructions.
1633 This is used by gcc/config/arm/lib1funcs.asm for example
1634 to compile interworking support functions even if the
1635 target processor should not support interworking. */
1636 if (! thumb_mode)
1637 {
1638 thumb_mode = 2;
1639
1640 record_alignment (now_seg, 1);
1641 }
1642
1643 demand_empty_rest_of_line ();
1644}
1645
1646static void
a737bd4d 1647s_thumb_func (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1648{
1649 if (! thumb_mode)
1650 opcode_select (16);
1651
1652 /* The following label is the name/address of the start of a Thumb function.
1653 We need to know this for the interworking support. */
b34976b6 1654 label_is_thumb_function_name = TRUE;
b99bd4ef
NC
1655
1656 demand_empty_rest_of_line ();
1657}
1658
1659/* Perform a .set directive, but also mark the alias as
1660 being a thumb function. */
1661
1662static void
a737bd4d 1663s_thumb_set (int equiv)
b99bd4ef
NC
1664{
1665 /* XXX the following is a duplicate of the code for s_set() in read.c
1666 We cannot just call that code as we need to get at the symbol that
1667 is created. */
a737bd4d
NC
1668 char * name;
1669 char delim;
1670 char * end_name;
1671 symbolS * symbolP;
b99bd4ef
NC
1672
1673 /* Especial apologies for the random logic:
1674 This just grew, and could be parsed much more simply!
1675 Dean - in haste. */
1676 name = input_line_pointer;
1677 delim = get_symbol_end ();
1678 end_name = input_line_pointer;
1679 *end_name = delim;
1680
1681 SKIP_WHITESPACE ();
1682
1683 if (*input_line_pointer != ',')
1684 {
1685 *end_name = 0;
f03698e6 1686 as_bad (_("expected comma after name \"%s\""), name);
b99bd4ef
NC
1687 *end_name = delim;
1688 ignore_rest_of_line ();
1689 return;
1690 }
1691
1692 input_line_pointer++;
1693 *end_name = 0;
1694
1695 if (name[0] == '.' && name[1] == '\0')
1696 {
1697 /* XXX - this should not happen to .thumb_set. */
1698 abort ();
1699 }
1700
1701 if ((symbolP = symbol_find (name)) == NULL
1702 && (symbolP = md_undefined_symbol (name)) == NULL)
1703 {
1704#ifndef NO_LISTING
1705 /* When doing symbol listings, play games with dummy fragments living
1706 outside the normal fragment chain to record the file and line info
1707 for this symbol. */
1708 if (listing & LISTING_SYMBOLS)
1709 {
1710 extern struct list_info_struct * listing_tail;
a737bd4d 1711 fragS * dummy_frag = xmalloc (sizeof (fragS));
b99bd4ef
NC
1712
1713 memset (dummy_frag, 0, sizeof (fragS));
1714 dummy_frag->fr_type = rs_fill;
1715 dummy_frag->line = listing_tail;
1716 symbolP = symbol_new (name, undefined_section, 0, dummy_frag);
1717 dummy_frag->fr_symbol = symbolP;
1718 }
1719 else
1720#endif
1721 symbolP = symbol_new (name, undefined_section, 0, &zero_address_frag);
1722
1723#ifdef OBJ_COFF
1724 /* "set" symbols are local unless otherwise specified. */
1725 SF_SET_LOCAL (symbolP);
1726#endif /* OBJ_COFF */
1727 } /* Make a new symbol. */
1728
1729 symbol_table_insert (symbolP);
1730
1731 * end_name = delim;
1732
1733 if (equiv
1734 && S_IS_DEFINED (symbolP)
1735 && S_GET_SEGMENT (symbolP) != reg_section)
1736 as_bad (_("symbol `%s' already defined"), S_GET_NAME (symbolP));
1737
1738 pseudo_set (symbolP);
1739
1740 demand_empty_rest_of_line ();
1741
1742 /* XXX Now we come to the Thumb specific bit of code. */
1743
1744 THUMB_SET_FUNC (symbolP, 1);
1745 ARM_SET_THUMB (symbolP, 1);
1746#if defined OBJ_ELF || defined OBJ_COFF
1747 ARM_SET_INTERWORK (symbolP, support_interwork);
1748#endif
1749}
1750
b99bd4ef 1751static void
a737bd4d 1752s_arm (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1753{
1754 opcode_select (32);
1755 demand_empty_rest_of_line ();
1756}
1757
1758static void
a737bd4d 1759s_thumb (int ignore ATTRIBUTE_UNUSED)
b99bd4ef
NC
1760{
1761 opcode_select (16);
1762 demand_empty_rest_of_line ();
1763}
1764
1765static void
a737bd4d 1766s_code (int unused ATTRIBUTE_UNUSED)
b99bd4ef 1767{
a737bd4d 1768 int temp;
b99bd4ef
NC
1769
1770 temp = get_absolute_expression ();
1771 switch (temp)
1772 {
1773 case 16:
1774 case 32:
1775 opcode_select (temp);
1776 break;
1777
1778 default:
1779 as_bad (_("invalid operand to .code directive (%d) (expecting 16 or 32)"), temp);
1780 }
1781}
1782
1783static void
a737bd4d 1784end_of_line (char * str)
b99bd4ef
NC
1785{
1786 skip_whitespace (str);
1787
f03698e6
RE
1788 if (*str != '\0' && !inst.error)
1789 inst.error = _("garbage following instruction");
b99bd4ef
NC
1790}
1791
1792static int
a737bd4d 1793skip_past_comma (char ** str)
b99bd4ef
NC
1794{
1795 char * p = * str, c;
1796 int comma = 0;
1797
1798 while ((c = *p) == ' ' || c == ',')
1799 {
1800 p++;
1801 if (c == ',' && comma++)
1802 return FAIL;
1803 }
1804
1805 if (c == '\0')
1806 return FAIL;
1807
1808 *str = p;
1809 return comma ? SUCCESS : FAIL;
1810}
1811
a737bd4d
NC
1812/* Return TRUE if anything in the expression is a bignum. */
1813
1814static int
1815walk_no_bignums (symbolS * sp)
1816{
1817 if (symbol_get_value_expression (sp)->X_op == O_big)
1818 return 1;
1819
1820 if (symbol_get_value_expression (sp)->X_add_symbol)
1821 {
1822 return (walk_no_bignums (symbol_get_value_expression (sp)->X_add_symbol)
1823 || (symbol_get_value_expression (sp)->X_op_symbol
1824 && walk_no_bignums (symbol_get_value_expression (sp)->X_op_symbol)));
1825 }
1826
1827 return 0;
1828}
1829
1830static int in_my_get_expression = 0;
1831
1832static int
1833my_get_expression (expressionS * ep, char ** str)
1834{
1835 char * save_in;
1836 segT seg;
1837
1838 save_in = input_line_pointer;
1839 input_line_pointer = *str;
1840 in_my_get_expression = 1;
1841 seg = expression (ep);
1842 in_my_get_expression = 0;
1843
1844 if (ep->X_op == O_illegal)
1845 {
1846 /* We found a bad expression in md_operand(). */
1847 *str = input_line_pointer;
1848 input_line_pointer = save_in;
1849 return 1;
1850 }
1851
1852#ifdef OBJ_AOUT
1853 if (seg != absolute_section
1854 && seg != text_section
1855 && seg != data_section
1856 && seg != bss_section
1857 && seg != undefined_section)
1858 {
1859 inst.error = _("bad_segment");
1860 *str = input_line_pointer;
1861 input_line_pointer = save_in;
1862 return 1;
1863 }
1864#endif
1865
1866 /* Get rid of any bignums now, so that we don't generate an error for which
1867 we can't establish a line number later on. Big numbers are never valid
1868 in instructions, which is where this routine is always called. */
1869 if (ep->X_op == O_big
1870 || (ep->X_add_symbol
1871 && (walk_no_bignums (ep->X_add_symbol)
1872 || (ep->X_op_symbol
1873 && walk_no_bignums (ep->X_op_symbol)))))
1874 {
1875 inst.error = _("invalid constant");
1876 *str = input_line_pointer;
1877 input_line_pointer = save_in;
1878 return 1;
1879 }
1880
1881 *str = input_line_pointer;
1882 input_line_pointer = save_in;
1883 return 0;
1884}
1885
b99bd4ef
NC
1886/* A standard register must be given at this point.
1887 SHIFT is the place to put it in inst.instruction.
1888 Restores input start point on error.
1889 Returns the reg#, or FAIL. */
1890
1891static int
a737bd4d 1892reg_required_here (char ** str, int shift)
b99bd4ef
NC
1893{
1894 static char buff [128]; /* XXX */
1895 int reg;
1896 char * start = * str;
1897
6c43fab6 1898 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_RN].htab)) != FAIL)
b99bd4ef
NC
1899 {
1900 if (shift >= 0)
1901 inst.instruction |= reg << shift;
1902 return reg;
1903 }
1904
1905 /* Restore the start point, we may have got a reg of the wrong class. */
1906 *str = start;
1907
1908 /* In the few cases where we might be able to accept something else
1909 this error can be overridden. */
f03698e6 1910 sprintf (buff, _("register expected, not '%.100s'"), start);
b99bd4ef
NC
1911 inst.error = buff;
1912
1913 return FAIL;
1914}
1915
5a6c6817 1916/* A Intel Wireless MMX technology register
e16bb312
NC
1917 must be given at this point.
1918 Shift is the place to put it in inst.instruction.
1919 Restores input start point on err.
1920 Returns the reg#, or FAIL. */
1921
1922static int
a737bd4d
NC
1923wreg_required_here (char ** str,
1924 int shift,
1925 enum wreg_type reg_type)
e16bb312
NC
1926{
1927 static char buff [128];
1928 int reg;
1929 char * start = *str;
1930
1931 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_IWMMXT].htab)) != FAIL)
1932 {
1933 if (wr_register (reg)
1934 && (reg_type == IWMMXT_REG_WR || reg_type == IWMMXT_REG_WR_OR_WC))
1935 {
1936 if (shift >= 0)
1937 inst.instruction |= (reg ^ WR_PREFIX) << shift;
1938 return reg;
1939 }
1940 else if (wc_register (reg)
1941 && (reg_type == IWMMXT_REG_WC || reg_type == IWMMXT_REG_WR_OR_WC))
1942 {
1943 if (shift >= 0)
1944 inst.instruction |= (reg ^ WC_PREFIX) << shift;
1945 return reg;
1946 }
1947 else if ((wcg_register (reg) && reg_type == IWMMXT_REG_WCG))
1948 {
1949 if (shift >= 0)
1950 inst.instruction |= ((reg ^ WC_PREFIX) - 8) << shift;
1951 return reg;
1952 }
1953 }
1954
1955 /* Restore the start point, we may have got a reg of the wrong class. */
1956 *str = start;
1957
1958 /* In the few cases where we might be able to accept
1959 something else this error can be overridden. */
5a6c6817 1960 sprintf (buff, _("Intel Wireless MMX technology register expected, not '%.100s'"), start);
e16bb312
NC
1961 inst.error = buff;
1962
1963 return FAIL;
1964}
1965
05d2d07e 1966static const struct asm_psr *
a737bd4d 1967arm_psr_parse (char ** ccp)
b99bd4ef
NC
1968{
1969 char * start = * ccp;
1970 char c;
1971 char * p;
05d2d07e 1972 const struct asm_psr * psr;
b99bd4ef
NC
1973
1974 p = start;
1975
1976 /* Skip to the end of the next word in the input stream. */
1977 do
1978 {
1979 c = *p++;
1980 }
3882b010 1981 while (ISALPHA (c) || c == '_');
b99bd4ef
NC
1982
1983 /* Terminate the word. */
1984 *--p = 0;
1985
1986 /* CPSR's and SPSR's can now be lowercase. This is just a convenience
1987 feature for ease of use and backwards compatibility. */
1988 if (!strncmp (start, "cpsr", 4))
1989 strncpy (start, "CPSR", 4);
1990 else if (!strncmp (start, "spsr", 4))
1991 strncpy (start, "SPSR", 4);
1992
1993 /* Now locate the word in the psr hash table. */
05d2d07e 1994 psr = (const struct asm_psr *) hash_find (arm_psr_hsh, start);
b99bd4ef
NC
1995
1996 /* Restore the input stream. */
1997 *p = c;
1998
1999 /* If we found a valid match, advance the
2000 stream pointer past the end of the word. */
2001 *ccp = p;
2002
2003 return psr;
2004}
2005
2006/* Parse the input looking for a PSR flag. */
2007
2008static int
a737bd4d 2009psr_required_here (char ** str)
b99bd4ef
NC
2010{
2011 char * start = * str;
05d2d07e 2012 const struct asm_psr * psr;
b99bd4ef
NC
2013
2014 psr = arm_psr_parse (str);
2015
2016 if (psr)
2017 {
2018 /* If this is the SPSR that is being modified, set the R bit. */
2019 if (! psr->cpsr)
2020 inst.instruction |= SPSR_BIT;
2021
2022 /* Set the psr flags in the MSR instruction. */
2023 inst.instruction |= psr->field << PSR_SHIFT;
2024
2025 return SUCCESS;
2026 }
2027
2028 /* In the few cases where we might be able to accept
2029 something else this error can be overridden. */
2030 inst.error = _("flag for {c}psr instruction expected");
2031
2032 /* Restore the start point. */
2033 *str = start;
2034 return FAIL;
2035}
2036
2037static int
a737bd4d 2038co_proc_number (char ** str)
b99bd4ef
NC
2039{
2040 int processor, pchar;
6c43fab6 2041 char *start;
b99bd4ef 2042
6c43fab6
RE
2043 skip_whitespace (*str);
2044 start = *str;
b99bd4ef
NC
2045
2046 /* The data sheet seems to imply that just a number on its own is valid
2047 here, but the RISC iX assembler seems to accept a prefix 'p'. We will
2048 accept either. */
6c43fab6
RE
2049 if ((processor = arm_reg_parse (str, all_reg_maps[REG_TYPE_CP].htab))
2050 == FAIL)
b99bd4ef 2051 {
6c43fab6
RE
2052 *str = start;
2053
2054 pchar = *(*str)++;
2055 if (pchar >= '0' && pchar <= '9')
b99bd4ef 2056 {
6c43fab6
RE
2057 processor = pchar - '0';
2058 if (**str >= '0' && **str <= '9')
b99bd4ef 2059 {
6c43fab6
RE
2060 processor = processor * 10 + *(*str)++ - '0';
2061 if (processor > 15)
2062 {
f03698e6 2063 inst.error = _("illegal co-processor number");
6c43fab6
RE
2064 return FAIL;
2065 }
b99bd4ef
NC
2066 }
2067 }
6c43fab6
RE
2068 else
2069 {
376eb240 2070 inst.error = all_reg_maps[REG_TYPE_CP].expected;
6c43fab6
RE
2071 return FAIL;
2072 }
b99bd4ef
NC
2073 }
2074
2075 inst.instruction |= processor << 8;
2076 return SUCCESS;
2077}
2078
2079static int
a737bd4d 2080cp_opc_expr (char ** str, int where, int length)
b99bd4ef
NC
2081{
2082 expressionS expr;
2083
2084 skip_whitespace (* str);
2085
2086 memset (&expr, '\0', sizeof (expr));
2087
2088 if (my_get_expression (&expr, str))
2089 return FAIL;
2090 if (expr.X_op != O_constant)
2091 {
2092 inst.error = _("bad or missing expression");
2093 return FAIL;
2094 }
2095
2096 if ((expr.X_add_number & ((1 << length) - 1)) != expr.X_add_number)
2097 {
2098 inst.error = _("immediate co-processor expression too large");
2099 return FAIL;
2100 }
2101
2102 inst.instruction |= expr.X_add_number << where;
2103 return SUCCESS;
2104}
2105
2106static int
a737bd4d 2107cp_reg_required_here (char ** str, int where)
b99bd4ef
NC
2108{
2109 int reg;
2110 char * start = *str;
2111
6c43fab6 2112 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
b99bd4ef 2113 {
b99bd4ef
NC
2114 inst.instruction |= reg << where;
2115 return reg;
2116 }
2117
2118 /* In the few cases where we might be able to accept something else
2119 this error can be overridden. */
376eb240 2120 inst.error = all_reg_maps[REG_TYPE_CN].expected;
b99bd4ef
NC
2121
2122 /* Restore the start point. */
2123 *str = start;
2124 return FAIL;
2125}
2126
2127static int
a737bd4d 2128fp_reg_required_here (char ** str, int where)
b99bd4ef
NC
2129{
2130 int reg;
2131 char * start = * str;
2132
6c43fab6 2133 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_FN].htab)) != FAIL)
b99bd4ef 2134 {
b99bd4ef
NC
2135 inst.instruction |= reg << where;
2136 return reg;
2137 }
2138
2139 /* In the few cases where we might be able to accept something else
2140 this error can be overridden. */
376eb240 2141 inst.error = all_reg_maps[REG_TYPE_FN].expected;
b99bd4ef
NC
2142
2143 /* Restore the start point. */
2144 *str = start;
2145 return FAIL;
2146}
2147
2148static int
a737bd4d 2149cp_address_offset (char ** str)
b99bd4ef
NC
2150{
2151 int offset;
2152
2153 skip_whitespace (* str);
2154
2155 if (! is_immediate_prefix (**str))
2156 {
2157 inst.error = _("immediate expression expected");
2158 return FAIL;
2159 }
2160
2161 (*str)++;
2162
2163 if (my_get_expression (& inst.reloc.exp, str))
2164 return FAIL;
2165
2166 if (inst.reloc.exp.X_op == O_constant)
2167 {
2168 offset = inst.reloc.exp.X_add_number;
2169
2170 if (offset & 3)
2171 {
2172 inst.error = _("co-processor address must be word aligned");
2173 return FAIL;
2174 }
2175
2176 if (offset > 1023 || offset < -1023)
2177 {
2178 inst.error = _("offset too large");
2179 return FAIL;
2180 }
2181
2182 if (offset >= 0)
2183 inst.instruction |= INDEX_UP;
2184 else
2185 offset = -offset;
2186
2187 inst.instruction |= offset >> 2;
2188 }
2189 else
2190 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
2191
2192 return SUCCESS;
2193}
2194
2195static int
a737bd4d 2196cp_address_required_here (char ** str, int wb_ok)
b99bd4ef
NC
2197{
2198 char * p = * str;
2199 int pre_inc = 0;
2200 int write_back = 0;
2201
2202 if (*p == '[')
2203 {
2204 int reg;
2205
2206 p++;
2207 skip_whitespace (p);
2208
2209 if ((reg = reg_required_here (& p, 16)) == FAIL)
2210 return FAIL;
2211
2212 skip_whitespace (p);
2213
2214 if (*p == ']')
2215 {
2216 p++;
2217
f02232aa
NC
2218 skip_whitespace (p);
2219
2220 if (*p == '\0')
b99bd4ef 2221 {
f02232aa 2222 /* As an extension to the official ARM syntax we allow:
f02232aa 2223 [Rn]
f02232aa 2224 as a short hand for:
f02232aa
NC
2225 [Rn,#0] */
2226 inst.instruction |= PRE_INDEX | INDEX_UP;
2227 *str = p;
2228 return SUCCESS;
2229 }
a737bd4d 2230
f02232aa
NC
2231 if (skip_past_comma (& p) == FAIL)
2232 {
2233 inst.error = _("comma expected after closing square bracket");
2234 return FAIL;
2235 }
b99bd4ef 2236
f02232aa
NC
2237 skip_whitespace (p);
2238
2239 if (*p == '#')
2240 {
2241 if (wb_ok)
b99bd4ef 2242 {
f02232aa
NC
2243 /* [Rn], #expr */
2244 write_back = WRITE_BACK;
2245
2246 if (reg == REG_PC)
2247 {
2248 inst.error = _("pc may not be used in post-increment");
2249 return FAIL;
2250 }
2251
2252 if (cp_address_offset (& p) == FAIL)
2253 return FAIL;
b99bd4ef 2254 }
f02232aa
NC
2255 else
2256 pre_inc = PRE_INDEX | INDEX_UP;
2257 }
2258 else if (*p == '{')
2259 {
2260 int option;
b99bd4ef 2261
f02232aa
NC
2262 /* [Rn], {<expr>} */
2263 p++;
2264
2265 skip_whitespace (p);
2266
2267 if (my_get_expression (& inst.reloc.exp, & p))
b99bd4ef 2268 return FAIL;
f02232aa
NC
2269
2270 if (inst.reloc.exp.X_op == O_constant)
2271 {
2272 option = inst.reloc.exp.X_add_number;
2273
2274 if (option > 255 || option < 0)
2275 {
2276 inst.error = _("'option' field too large");
2277 return FAIL;
2278 }
2279
2280 skip_whitespace (p);
2281
2282 if (*p != '}')
2283 {
2284 inst.error = _("'}' expected at end of 'option' field");
2285 return FAIL;
2286 }
2287 else
2288 {
2289 p++;
2290 inst.instruction |= option;
2291 inst.instruction |= INDEX_UP;
2292 }
2293 }
2294 else
2295 {
2296 inst.error = _("non-constant expressions for 'option' field not supported");
2297 return FAIL;
2298 }
b99bd4ef
NC
2299 }
2300 else
f02232aa
NC
2301 {
2302 inst.error = _("# or { expected after comma");
a737bd4d 2303 return FAIL;
f02232aa 2304 }
b99bd4ef
NC
2305 }
2306 else
2307 {
2308 /* '['Rn, #expr']'[!] */
2309
2310 if (skip_past_comma (& p) == FAIL)
2311 {
2312 inst.error = _("pre-indexed expression expected");
2313 return FAIL;
2314 }
2315
2316 pre_inc = PRE_INDEX;
2317
2318 if (cp_address_offset (& p) == FAIL)
2319 return FAIL;
2320
2321 skip_whitespace (p);
2322
2323 if (*p++ != ']')
2324 {
2325 inst.error = _("missing ]");
2326 return FAIL;
2327 }
2328
2329 skip_whitespace (p);
2330
bfae80f2 2331 if (wb_ok && *p == '!')
b99bd4ef
NC
2332 {
2333 if (reg == REG_PC)
2334 {
2335 inst.error = _("pc may not be used with write-back");
2336 return FAIL;
2337 }
2338
2339 p++;
2340 write_back = WRITE_BACK;
2341 }
2342 }
2343 }
2344 else
2345 {
2346 if (my_get_expression (&inst.reloc.exp, &p))
2347 return FAIL;
2348
2349 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM;
2350 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
2351 inst.reloc.pc_rel = 1;
2352 inst.instruction |= (REG_PC << 16);
2353 pre_inc = PRE_INDEX;
2354 }
2355
2356 inst.instruction |= write_back | pre_inc;
2357 *str = p;
2358 return SUCCESS;
2359}
2360
e16bb312 2361static int
a737bd4d 2362cp_byte_address_offset (char ** str)
e16bb312
NC
2363{
2364 int offset;
2365
2366 skip_whitespace (* str);
2367
2368 if (! is_immediate_prefix (**str))
2369 {
2370 inst.error = _("immediate expression expected");
2371 return FAIL;
2372 }
2373
2374 (*str)++;
a737bd4d 2375
e16bb312
NC
2376 if (my_get_expression (& inst.reloc.exp, str))
2377 return FAIL;
a737bd4d 2378
e16bb312
NC
2379 if (inst.reloc.exp.X_op == O_constant)
2380 {
2381 offset = inst.reloc.exp.X_add_number;
a737bd4d 2382
e16bb312
NC
2383 if (offset > 255 || offset < -255)
2384 {
2385 inst.error = _("offset too large");
2386 return FAIL;
2387 }
2388
2389 if (offset >= 0)
2390 inst.instruction |= INDEX_UP;
2391 else
2392 offset = -offset;
2393
2394 inst.instruction |= offset;
2395 }
2396 else
2397 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
2398
2399 return SUCCESS;
2400}
2401
2402static int
a737bd4d 2403cp_byte_address_required_here (char ** str)
e16bb312
NC
2404{
2405 char * p = * str;
2406 int pre_inc = 0;
2407 int write_back = 0;
2408
2409 if (*p == '[')
2410 {
2411 int reg;
2412
2413 p++;
2414 skip_whitespace (p);
2415
2416 if ((reg = reg_required_here (& p, 16)) == FAIL)
2417 return FAIL;
2418
2419 skip_whitespace (p);
2420
2421 if (*p == ']')
2422 {
2423 p++;
a737bd4d 2424
e16bb312
NC
2425 if (skip_past_comma (& p) == SUCCESS)
2426 {
2427 /* [Rn], #expr */
2428 write_back = WRITE_BACK;
a737bd4d 2429
e16bb312
NC
2430 if (reg == REG_PC)
2431 {
2432 inst.error = _("pc may not be used in post-increment");
2433 return FAIL;
2434 }
2435
2436 if (cp_byte_address_offset (& p) == FAIL)
2437 return FAIL;
2438 }
2439 else
2440 pre_inc = PRE_INDEX | INDEX_UP;
2441 }
2442 else
2443 {
2444 /* '['Rn, #expr']'[!] */
2445
2446 if (skip_past_comma (& p) == FAIL)
2447 {
2448 inst.error = _("pre-indexed expression expected");
2449 return FAIL;
2450 }
2451
2452 pre_inc = PRE_INDEX;
a737bd4d 2453
e16bb312
NC
2454 if (cp_byte_address_offset (& p) == FAIL)
2455 return FAIL;
2456
2457 skip_whitespace (p);
2458
2459 if (*p++ != ']')
2460 {
2461 inst.error = _("missing ]");
2462 return FAIL;
2463 }
2464
2465 skip_whitespace (p);
2466
2467 if (*p == '!')
2468 {
2469 if (reg == REG_PC)
2470 {
2471 inst.error = _("pc may not be used with write-back");
2472 return FAIL;
2473 }
2474
2475 p++;
2476 write_back = WRITE_BACK;
2477 }
2478 }
2479 }
2480 else
2481 {
2482 if (my_get_expression (&inst.reloc.exp, &p))
2483 return FAIL;
2484
2485 inst.reloc.type = BFD_RELOC_ARM_CP_OFF_IMM_S2;
2486 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
2487 inst.reloc.pc_rel = 1;
2488 inst.instruction |= (REG_PC << 16);
2489 pre_inc = PRE_INDEX;
2490 }
2491
2492 inst.instruction |= write_back | pre_inc;
2493 *str = p;
2494 return SUCCESS;
2495}
2496
0dd132b6
NC
2497static void
2498do_nop (char * str)
2499{
2500 skip_whitespace (str);
2501 if (*str == '{')
2502 {
2503 str++;
2504
2505 if (my_get_expression (&inst.reloc.exp, &str))
2506 inst.reloc.exp.X_op = O_illegal;
2507 else
2508 {
2509 skip_whitespace (str);
2510 if (*str == '}')
2511 str++;
2512 else
2513 inst.reloc.exp.X_op = O_illegal;
2514 }
2515
2516 if (inst.reloc.exp.X_op != O_constant
2517 || inst.reloc.exp.X_add_number > 255
2518 || inst.reloc.exp.X_add_number < 0)
2519 {
2520 inst.error = _("Invalid NOP hint");
2521 return;
2522 }
2523
2524 /* Arcitectural NOP hints are CPSR sets with no bits selected. */
2525 inst.instruction &= 0xf0000000;
2526 inst.instruction |= 0x0320f000 + inst.reloc.exp.X_add_number;
2527 }
2528
2529 end_of_line (str);
2530}
2531
b99bd4ef 2532static void
a737bd4d 2533do_empty (char * str)
b99bd4ef
NC
2534{
2535 /* Do nothing really. */
b99bd4ef 2536 end_of_line (str);
b99bd4ef
NC
2537}
2538
2539static void
a737bd4d 2540do_mrs (char * str)
b99bd4ef
NC
2541{
2542 int skip = 0;
2543
2544 /* Only one syntax. */
2545 skip_whitespace (str);
2546
2547 if (reg_required_here (&str, 12) == FAIL)
2548 {
2549 inst.error = BAD_ARGS;
2550 return;
2551 }
2552
2553 if (skip_past_comma (&str) == FAIL)
2554 {
2555 inst.error = _("comma expected after register name");
2556 return;
2557 }
2558
2559 skip_whitespace (str);
2560
a737bd4d
NC
2561 if ( streq (str, "CPSR")
2562 || streq (str, "SPSR")
2d2255b5 2563 /* Lower case versions for backwards compatibility. */
a737bd4d
NC
2564 || streq (str, "cpsr")
2565 || streq (str, "spsr"))
b99bd4ef
NC
2566 skip = 4;
2567
2d2255b5 2568 /* This is for backwards compatibility with older toolchains. */
a737bd4d
NC
2569 else if ( streq (str, "cpsr_all")
2570 || streq (str, "spsr_all"))
b99bd4ef
NC
2571 skip = 8;
2572 else
2573 {
f03698e6 2574 inst.error = _("CPSR or SPSR expected");
b99bd4ef
NC
2575 return;
2576 }
2577
2578 if (* str == 's' || * str == 'S')
2579 inst.instruction |= SPSR_BIT;
2580 str += skip;
2581
b99bd4ef
NC
2582 end_of_line (str);
2583}
2584
2585/* Two possible forms:
2586 "{C|S}PSR_<field>, Rm",
2587 "{C|S}PSR_f, #expression". */
2588
2589static void
a737bd4d 2590do_msr (char * str)
b99bd4ef
NC
2591{
2592 skip_whitespace (str);
2593
2594 if (psr_required_here (& str) == FAIL)
2595 return;
2596
2597 if (skip_past_comma (& str) == FAIL)
2598 {
2599 inst.error = _("comma missing after psr flags");
2600 return;
2601 }
2602
2603 skip_whitespace (str);
2604
2605 if (reg_required_here (& str, 0) != FAIL)
2606 {
2607 inst.error = NULL;
b99bd4ef
NC
2608 end_of_line (str);
2609 return;
2610 }
2611
2612 if (! is_immediate_prefix (* str))
2613 {
2614 inst.error =
2615 _("only a register or immediate value can follow a psr flag");
2616 return;
2617 }
2618
2619 str ++;
2620 inst.error = NULL;
2621
2622 if (my_get_expression (& inst.reloc.exp, & str))
2623 {
2624 inst.error =
2625 _("only a register or immediate value can follow a psr flag");
2626 return;
2627 }
2628
f2b7cb0a 2629 inst.instruction |= INST_IMMEDIATE;
b99bd4ef
NC
2630
2631 if (inst.reloc.exp.X_add_symbol)
2632 {
2633 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
2634 inst.reloc.pc_rel = 0;
2635 }
2636 else
2637 {
2638 unsigned value = validate_immediate (inst.reloc.exp.X_add_number);
2639
2640 if (value == (unsigned) FAIL)
2641 {
f03698e6 2642 inst.error = _("invalid constant");
b99bd4ef
NC
2643 return;
2644 }
2645
2646 inst.instruction |= value;
2647 }
2648
2649 inst.error = NULL;
b99bd4ef
NC
2650 end_of_line (str);
2651}
2652
2653/* Long Multiply Parser
2654 UMULL RdLo, RdHi, Rm, Rs
2655 SMULL RdLo, RdHi, Rm, Rs
2656 UMLAL RdLo, RdHi, Rm, Rs
2657 SMLAL RdLo, RdHi, Rm, Rs. */
2658
2659static void
a737bd4d 2660do_mull (char * str)
b99bd4ef
NC
2661{
2662 int rdlo, rdhi, rm, rs;
2663
2664 /* Only one format "rdlo, rdhi, rm, rs". */
2665 skip_whitespace (str);
2666
2667 if ((rdlo = reg_required_here (&str, 12)) == FAIL)
2668 {
2669 inst.error = BAD_ARGS;
2670 return;
2671 }
2672
2673 if (skip_past_comma (&str) == FAIL
2674 || (rdhi = reg_required_here (&str, 16)) == FAIL)
2675 {
2676 inst.error = BAD_ARGS;
2677 return;
2678 }
2679
2680 if (skip_past_comma (&str) == FAIL
2681 || (rm = reg_required_here (&str, 0)) == FAIL)
2682 {
2683 inst.error = BAD_ARGS;
2684 return;
2685 }
2686
2687 /* rdhi, rdlo and rm must all be different. */
2688 if (rdlo == rdhi || rdlo == rm || rdhi == rm)
2689 as_tsktsk (_("rdhi, rdlo and rm must all be different"));
2690
2691 if (skip_past_comma (&str) == FAIL
2692 || (rs = reg_required_here (&str, 8)) == FAIL)
2693 {
2694 inst.error = BAD_ARGS;
2695 return;
2696 }
2697
2698 if (rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC || rdhi == REG_PC)
2699 {
2700 inst.error = BAD_PC;
2701 return;
2702 }
2703
b99bd4ef 2704 end_of_line (str);
b99bd4ef
NC
2705}
2706
2707static void
a737bd4d 2708do_mul (char * str)
b99bd4ef
NC
2709{
2710 int rd, rm;
2711
2712 /* Only one format "rd, rm, rs". */
2713 skip_whitespace (str);
2714
2715 if ((rd = reg_required_here (&str, 16)) == FAIL)
2716 {
2717 inst.error = BAD_ARGS;
2718 return;
2719 }
2720
2721 if (rd == REG_PC)
2722 {
2723 inst.error = BAD_PC;
2724 return;
2725 }
2726
2727 if (skip_past_comma (&str) == FAIL
2728 || (rm = reg_required_here (&str, 0)) == FAIL)
2729 {
2730 inst.error = BAD_ARGS;
2731 return;
2732 }
2733
2734 if (rm == REG_PC)
2735 {
2736 inst.error = BAD_PC;
2737 return;
2738 }
2739
2740 if (rm == rd)
2741 as_tsktsk (_("rd and rm should be different in mul"));
2742
2743 if (skip_past_comma (&str) == FAIL
2744 || (rm = reg_required_here (&str, 8)) == FAIL)
2745 {
2746 inst.error = BAD_ARGS;
2747 return;
2748 }
2749
2750 if (rm == REG_PC)
2751 {
2752 inst.error = BAD_PC;
2753 return;
2754 }
2755
b99bd4ef 2756 end_of_line (str);
b99bd4ef
NC
2757}
2758
2759static void
b05fe5cf 2760do_mlas (char * str, bfd_boolean is_mls)
b99bd4ef
NC
2761{
2762 int rd, rm;
2763
2764 /* Only one format "rd, rm, rs, rn". */
2765 skip_whitespace (str);
2766
2767 if ((rd = reg_required_here (&str, 16)) == FAIL)
2768 {
2769 inst.error = BAD_ARGS;
2770 return;
2771 }
2772
2773 if (rd == REG_PC)
2774 {
2775 inst.error = BAD_PC;
2776 return;
2777 }
2778
2779 if (skip_past_comma (&str) == FAIL
2780 || (rm = reg_required_here (&str, 0)) == FAIL)
2781 {
2782 inst.error = BAD_ARGS;
2783 return;
2784 }
2785
2786 if (rm == REG_PC)
2787 {
2788 inst.error = BAD_PC;
2789 return;
2790 }
2791
b05fe5cf
ZW
2792 /* This restriction does not apply to mls (nor to mla in v6, but
2793 that's hard to detect at present). */
2794 if (rm == rd && !is_mls)
b99bd4ef
NC
2795 as_tsktsk (_("rd and rm should be different in mla"));
2796
2797 if (skip_past_comma (&str) == FAIL
2798 || (rd = reg_required_here (&str, 8)) == FAIL
2799 || skip_past_comma (&str) == FAIL
2800 || (rm = reg_required_here (&str, 12)) == FAIL)
2801 {
2802 inst.error = BAD_ARGS;
2803 return;
2804 }
2805
2806 if (rd == REG_PC || rm == REG_PC)
2807 {
2808 inst.error = BAD_PC;
2809 return;
2810 }
2811
b99bd4ef 2812 end_of_line (str);
b99bd4ef
NC
2813}
2814
b05fe5cf
ZW
2815static void
2816do_mla (char *str)
2817{
2818 do_mlas (str, FALSE);
2819}
2820
2821static void
2822do_mls (char *str)
2823{
2824 do_mlas (str, TRUE);
2825}
2826
b99bd4ef
NC
2827/* Expects *str -> the characters "acc0", possibly with leading blanks.
2828 Advances *str to the next non-alphanumeric.
2829 Returns 0, or else FAIL (in which case sets inst.error).
2830
2831 (In a future XScale, there may be accumulators other than zero.
2832 At that time this routine and its callers can be upgraded to suit.) */
2833
2834static int
a737bd4d 2835accum0_required_here (char ** str)
b99bd4ef
NC
2836{
2837 static char buff [128]; /* Note the address is taken. Hence, static. */
2838 char * p = * str;
2839 char c;
2840 int result = 0; /* The accum number. */
2841
2842 skip_whitespace (p);
2843
a737bd4d
NC
2844 *str = p; /* Advance caller's string pointer too. */
2845 c = *p++;
2846 while (ISALNUM (c))
2847 c = *p++;
2848
2849 *--p = 0; /* Aap nul into input buffer at non-alnum. */
2850
2851 if (! ( streq (*str, "acc0") || streq (*str, "ACC0")))
2852 {
2853 sprintf (buff, _("acc0 expected, not '%.100s'"), *str);
2854 inst.error = buff;
2855 result = FAIL;
2856 }
2857
2858 *p = c; /* Unzap. */
2859 *str = p; /* Caller's string pointer to after match. */
2860 return result;
2861}
2862
2863static int
2864ldst_extend_v4 (char ** str)
2865{
2866 int add = INDEX_UP;
2867
2868 switch (**str)
2869 {
2870 case '#':
2871 case '$':
2872 (*str)++;
2873 if (my_get_expression (& inst.reloc.exp, str))
2874 return FAIL;
2875
2876 if (inst.reloc.exp.X_op == O_constant)
2877 {
2878 int value = inst.reloc.exp.X_add_number;
2879
2880 if (value < -255 || value > 255)
2881 {
2882 inst.error = _("address offset too large");
2883 return FAIL;
2884 }
2885
2886 if (value < 0)
2887 {
2888 value = -value;
2889 add = 0;
2890 }
2891
2892 /* Halfword and signextension instructions have the
2893 immediate value split across bits 11..8 and bits 3..0. */
2894 inst.instruction |= (add | HWOFFSET_IMM
2895 | ((value >> 4) << 8) | (value & 0xF));
2896 }
2897 else
2898 {
2899 inst.instruction |= HWOFFSET_IMM;
2900 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
2901 inst.reloc.pc_rel = 0;
2902 }
2903 return SUCCESS;
2904
2905 case '-':
2906 add = 0;
2907 /* Fall through. */
2908
2909 case '+':
2910 (*str)++;
2911 /* Fall through. */
b99bd4ef 2912
a737bd4d
NC
2913 default:
2914 if (reg_required_here (str, 0) == FAIL)
2915 return FAIL;
b99bd4ef 2916
a737bd4d
NC
2917 inst.instruction |= add;
2918 return SUCCESS;
b99bd4ef 2919 }
b99bd4ef
NC
2920}
2921
2922/* Expects **str -> after a comma. May be leading blanks.
2923 Advances *str, recognizing a load mode, and setting inst.instruction.
2924 Returns rn, or else FAIL (in which case may set inst.error
2925 and not advance str)
2926
2927 Note: doesn't know Rd, so no err checks that require such knowledge. */
2928
2929static int
a737bd4d 2930ld_mode_required_here (char ** string)
b99bd4ef
NC
2931{
2932 char * str = * string;
2933 int rn;
2934 int pre_inc = 0;
2935
2936 skip_whitespace (str);
2937
2938 if (* str == '[')
2939 {
2940 str++;
2941
2942 skip_whitespace (str);
2943
2944 if ((rn = reg_required_here (& str, 16)) == FAIL)
2945 return FAIL;
2946
2947 skip_whitespace (str);
2948
2949 if (* str == ']')
2950 {
2951 str ++;
2952
2953 if (skip_past_comma (& str) == SUCCESS)
2954 {
2955 /* [Rn],... (post inc) */
90e4755a 2956 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
2957 return FAIL;
2958 }
2959 else /* [Rn] */
2960 {
cc8a6dd0 2961 skip_whitespace (str);
b99bd4ef 2962
cc8a6dd0
KH
2963 if (* str == '!')
2964 {
2965 str ++;
2966 inst.instruction |= WRITE_BACK;
2967 }
b99bd4ef
NC
2968
2969 inst.instruction |= INDEX_UP | HWOFFSET_IMM;
2970 pre_inc = 1;
2971 }
2972 }
2973 else /* [Rn,...] */
2974 {
2975 if (skip_past_comma (& str) == FAIL)
2976 {
2977 inst.error = _("pre-indexed expression expected");
2978 return FAIL;
2979 }
2980
2981 pre_inc = 1;
2982
90e4755a 2983 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
2984 return FAIL;
2985
2986 skip_whitespace (str);
2987
2988 if (* str ++ != ']')
2989 {
2990 inst.error = _("missing ]");
2991 return FAIL;
2992 }
2993
2994 skip_whitespace (str);
2995
2996 if (* str == '!')
2997 {
2998 str ++;
2999 inst.instruction |= WRITE_BACK;
3000 }
3001 }
3002 }
3003 else if (* str == '=') /* ldr's "r,=label" syntax */
3004 /* We should never reach here, because <text> = <expression> is
3005 caught gas/read.c read_a_source_file() as a .set operation. */
3006 return FAIL;
3007 else /* PC +- 8 bit immediate offset. */
3008 {
3009 if (my_get_expression (& inst.reloc.exp, & str))
3010 return FAIL;
3011
3012 inst.instruction |= HWOFFSET_IMM; /* The I bit. */
3013 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
3014 inst.reloc.exp.X_add_number -= 8; /* PC rel adjust. */
3015 inst.reloc.pc_rel = 1;
3016 inst.instruction |= (REG_PC << 16);
3017
3018 rn = REG_PC;
3019 pre_inc = 1;
3020 }
3021
3022 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
3023 * string = str;
3024
3025 return rn;
3026}
3027
3028/* ARM V5E (El Segundo) signed-multiply-accumulate (argument parse)
3029 SMLAxy{cond} Rd,Rm,Rs,Rn
3030 SMLAWy{cond} Rd,Rm,Rs,Rn
3031 Error if any register is R15. */
3032
3033static void
a737bd4d 3034do_smla (char * str)
b99bd4ef
NC
3035{
3036 int rd, rm, rs, rn;
3037
3038 skip_whitespace (str);
3039
3040 if ((rd = reg_required_here (& str, 16)) == FAIL
3041 || skip_past_comma (& str) == FAIL
3042 || (rm = reg_required_here (& str, 0)) == FAIL
3043 || skip_past_comma (& str) == FAIL
3044 || (rs = reg_required_here (& str, 8)) == FAIL
3045 || skip_past_comma (& str) == FAIL
3046 || (rn = reg_required_here (& str, 12)) == FAIL)
3047 inst.error = BAD_ARGS;
3048
3049 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC || rn == REG_PC)
3050 inst.error = BAD_PC;
3051
b99bd4ef
NC
3052 else
3053 end_of_line (str);
3054}
3055
3056/* ARM V5E (El Segundo) signed-multiply-accumulate-long (argument parse)
3057 SMLALxy{cond} Rdlo,Rdhi,Rm,Rs
3058 Error if any register is R15.
3059 Warning if Rdlo == Rdhi. */
3060
3061static void
a737bd4d 3062do_smlal (char * str)
b99bd4ef
NC
3063{
3064 int rdlo, rdhi, rm, rs;
3065
3066 skip_whitespace (str);
3067
3068 if ((rdlo = reg_required_here (& str, 12)) == FAIL
3069 || skip_past_comma (& str) == FAIL
3070 || (rdhi = reg_required_here (& str, 16)) == FAIL
3071 || skip_past_comma (& str) == FAIL
3072 || (rm = reg_required_here (& str, 0)) == FAIL
3073 || skip_past_comma (& str) == FAIL
3074 || (rs = reg_required_here (& str, 8)) == FAIL)
3075 {
3076 inst.error = BAD_ARGS;
3077 return;
3078 }
3079
3080 if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
3081 {
3082 inst.error = BAD_PC;
3083 return;
3084 }
3085
3086 if (rdlo == rdhi)
3087 as_tsktsk (_("rdhi and rdlo must be different"));
3088
f2b7cb0a 3089 end_of_line (str);
b99bd4ef
NC
3090}
3091
3092/* ARM V5E (El Segundo) signed-multiply (argument parse)
3093 SMULxy{cond} Rd,Rm,Rs
3094 Error if any register is R15. */
3095
3096static void
a737bd4d 3097do_smul (char * str)
b99bd4ef
NC
3098{
3099 int rd, rm, rs;
3100
3101 skip_whitespace (str);
3102
3103 if ((rd = reg_required_here (& str, 16)) == FAIL
3104 || skip_past_comma (& str) == FAIL
3105 || (rm = reg_required_here (& str, 0)) == FAIL
3106 || skip_past_comma (& str) == FAIL
3107 || (rs = reg_required_here (& str, 8)) == FAIL)
3108 inst.error = BAD_ARGS;
3109
3110 else if (rd == REG_PC || rm == REG_PC || rs == REG_PC)
3111 inst.error = BAD_PC;
3112
b99bd4ef
NC
3113 else
3114 end_of_line (str);
3115}
3116
3117/* ARM V5E (El Segundo) saturating-add/subtract (argument parse)
3118 Q[D]{ADD,SUB}{cond} Rd,Rm,Rn
3119 Error if any register is R15. */
3120
3121static void
a737bd4d 3122do_qadd (char * str)
b99bd4ef
NC
3123{
3124 int rd, rm, rn;
3125
3126 skip_whitespace (str);
3127
3128 if ((rd = reg_required_here (& str, 12)) == FAIL
3129 || skip_past_comma (& str) == FAIL
3130 || (rm = reg_required_here (& str, 0)) == FAIL
3131 || skip_past_comma (& str) == FAIL
3132 || (rn = reg_required_here (& str, 16)) == FAIL)
3133 inst.error = BAD_ARGS;
3134
3135 else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
3136 inst.error = BAD_PC;
3137
b99bd4ef
NC
3138 else
3139 end_of_line (str);
3140}
3141
3142/* ARM V5E (el Segundo)
3143 MCRRcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
3144 MRRCcc <coproc>, <opcode>, <Rd>, <Rn>, <CRm>.
3145
3146 These are equivalent to the XScale instructions MAR and MRA,
3147 respectively, when coproc == 0, opcode == 0, and CRm == 0.
3148
3149 Result unpredicatable if Rd or Rn is R15. */
3150
3151static void
a737bd4d 3152do_co_reg2c (char * str)
b99bd4ef
NC
3153{
3154 int rd, rn;
3155
3156 skip_whitespace (str);
3157
3158 if (co_proc_number (& str) == FAIL)
3159 {
3160 if (!inst.error)
3161 inst.error = BAD_ARGS;
3162 return;
3163 }
3164
3165 if (skip_past_comma (& str) == FAIL
3166 || cp_opc_expr (& str, 4, 4) == FAIL)
3167 {
3168 if (!inst.error)
3169 inst.error = BAD_ARGS;
3170 return;
3171 }
3172
3173 if (skip_past_comma (& str) == FAIL
3174 || (rd = reg_required_here (& str, 12)) == FAIL)
3175 {
3176 if (!inst.error)
3177 inst.error = BAD_ARGS;
3178 return;
3179 }
3180
3181 if (skip_past_comma (& str) == FAIL
3182 || (rn = reg_required_here (& str, 16)) == FAIL)
3183 {
3184 if (!inst.error)
3185 inst.error = BAD_ARGS;
3186 return;
3187 }
3188
09d92015
MM
3189 /* Unpredictable result if rd or rn is R15. */
3190 if (rd == REG_PC || rn == REG_PC)
3191 as_tsktsk
3192 (_("Warning: instruction unpredictable when using r15"));
3193
3194 if (skip_past_comma (& str) == FAIL
3195 || cp_reg_required_here (& str, 0) == FAIL)
3196 {
3197 if (!inst.error)
3198 inst.error = BAD_ARGS;
3199 return;
3200 }
3201
3202 end_of_line (str);
3203}
3204
3205/* ARM V5 count-leading-zeroes instruction (argument parse)
3206 CLZ{<cond>} <Rd>, <Rm>
3207 Condition defaults to COND_ALWAYS.
3208 Error if Rd or Rm are R15. */
3209
3210static void
a737bd4d 3211do_clz (char * str)
09d92015
MM
3212{
3213 int rd, rm;
3214
3215 skip_whitespace (str);
3216
3217 if (((rd = reg_required_here (& str, 12)) == FAIL)
3218 || (skip_past_comma (& str) == FAIL)
3219 || ((rm = reg_required_here (& str, 0)) == FAIL))
3220 inst.error = BAD_ARGS;
3221
3222 else if (rd == REG_PC || rm == REG_PC )
3223 inst.error = BAD_PC;
3224
3225 else
3226 end_of_line (str);
3227}
3228
3229/* ARM V5 (argument parse)
3230 LDC2{L} <coproc>, <CRd>, <addressing mode>
3231 STC2{L} <coproc>, <CRd>, <addressing mode>
3232 Instruction is not conditional, and has 0xf in the condition field.
3233 Otherwise, it's the same as LDC/STC. */
3234
3235static void
a737bd4d 3236do_lstc2 (char * str)
09d92015
MM
3237{
3238 skip_whitespace (str);
3239
3240 if (co_proc_number (& str) == FAIL)
3241 {
3242 if (!inst.error)
3243 inst.error = BAD_ARGS;
3244 }
3245 else if (skip_past_comma (& str) == FAIL
3246 || cp_reg_required_here (& str, 12) == FAIL)
3247 {
3248 if (!inst.error)
3249 inst.error = BAD_ARGS;
3250 }
3251 else if (skip_past_comma (& str) == FAIL
3252 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
3253 {
3254 if (! inst.error)
3255 inst.error = BAD_ARGS;
3256 }
3257 else
3258 end_of_line (str);
3259}
3260
3261/* ARM V5 (argument parse)
3262 CDP2 <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
3263 Instruction is not conditional, and has 0xf in the condition field.
3264 Otherwise, it's the same as CDP. */
3265
3266static void
a737bd4d 3267do_cdp2 (char * str)
09d92015
MM
3268{
3269 skip_whitespace (str);
3270
3271 if (co_proc_number (& str) == FAIL)
3272 {
3273 if (!inst.error)
3274 inst.error = BAD_ARGS;
3275 return;
3276 }
3277
3278 if (skip_past_comma (& str) == FAIL
3279 || cp_opc_expr (& str, 20,4) == FAIL)
3280 {
3281 if (!inst.error)
3282 inst.error = BAD_ARGS;
3283 return;
3284 }
3285
3286 if (skip_past_comma (& str) == FAIL
3287 || cp_reg_required_here (& str, 12) == FAIL)
3288 {
3289 if (!inst.error)
3290 inst.error = BAD_ARGS;
3291 return;
3292 }
3293
3294 if (skip_past_comma (& str) == FAIL
3295 || cp_reg_required_here (& str, 16) == FAIL)
3296 {
3297 if (!inst.error)
3298 inst.error = BAD_ARGS;
3299 return;
3300 }
3301
3302 if (skip_past_comma (& str) == FAIL
3303 || cp_reg_required_here (& str, 0) == FAIL)
3304 {
3305 if (!inst.error)
3306 inst.error = BAD_ARGS;
3307 return;
3308 }
3309
3310 if (skip_past_comma (& str) == SUCCESS)
3311 {
3312 if (cp_opc_expr (& str, 5, 3) == FAIL)
3313 {
3314 if (!inst.error)
3315 inst.error = BAD_ARGS;
3316 return;
3317 }
3318 }
3319
3320 end_of_line (str);
3321}
3322
3323/* ARM V5 (argument parse)
3324 MCR2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
3325 MRC2 <coproc>, <opcode_1>, <Rd>, <CRn>, <CRm>, <opcode_2>
3326 Instruction is not conditional, and has 0xf in the condition field.
3327 Otherwise, it's the same as MCR/MRC. */
3328
3329static void
a737bd4d 3330do_co_reg2 (char * str)
09d92015
MM
3331{
3332 skip_whitespace (str);
3333
3334 if (co_proc_number (& str) == FAIL)
3335 {
3336 if (!inst.error)
3337 inst.error = BAD_ARGS;
3338 return;
3339 }
3340
3341 if (skip_past_comma (& str) == FAIL
3342 || cp_opc_expr (& str, 21, 3) == FAIL)
3343 {
3344 if (!inst.error)
3345 inst.error = BAD_ARGS;
3346 return;
3347 }
3348
3349 if (skip_past_comma (& str) == FAIL
3350 || reg_required_here (& str, 12) == FAIL)
3351 {
3352 if (!inst.error)
3353 inst.error = BAD_ARGS;
3354 return;
3355 }
3356
3357 if (skip_past_comma (& str) == FAIL
3358 || cp_reg_required_here (& str, 16) == FAIL)
3359 {
3360 if (!inst.error)
3361 inst.error = BAD_ARGS;
3362 return;
3363 }
3364
3365 if (skip_past_comma (& str) == FAIL
3366 || cp_reg_required_here (& str, 0) == FAIL)
3367 {
3368 if (!inst.error)
3369 inst.error = BAD_ARGS;
3370 return;
3371 }
3372
3373 if (skip_past_comma (& str) == SUCCESS)
3374 {
3375 if (cp_opc_expr (& str, 5, 3) == FAIL)
3376 {
3377 if (!inst.error)
3378 inst.error = BAD_ARGS;
3379 return;
3380 }
3381 }
3382
3383 end_of_line (str);
3384}
3385
a737bd4d
NC
3386static void
3387do_bx (char * str)
3388{
3389 int reg;
3390
3391 skip_whitespace (str);
3392
3393 if ((reg = reg_required_here (&str, 0)) == FAIL)
3394 {
3395 inst.error = BAD_ARGS;
3396 return;
3397 }
3398
3399 /* Note - it is not illegal to do a "bx pc". Useless, but not illegal. */
3400 if (reg == REG_PC)
3401 as_tsktsk (_("use of r15 in bx in ARM mode is not really useful"));
3402
3403 end_of_line (str);
3404}
3405
09d92015 3406/* ARM v5TEJ. Jump to Jazelle code. */
a737bd4d 3407
09d92015 3408static void
a737bd4d 3409do_bxj (char * str)
09d92015
MM
3410{
3411 int reg;
3412
3413 skip_whitespace (str);
3414
3415 if ((reg = reg_required_here (&str, 0)) == FAIL)
3416 {
3417 inst.error = BAD_ARGS;
3418 return;
3419 }
3420
a737bd4d
NC
3421 /* Note - it is not illegal to do a "bxj pc". Useless, but not illegal. */
3422 if (reg == REG_PC)
3423 as_tsktsk (_("use of r15 in bxj is not really useful"));
3424
3425 end_of_line (str);
3426}
3427
3428/* ARM V6 umaal (argument parse). */
3429
3430static void
3431do_umaal (char * str)
3432{
3433 int rdlo, rdhi, rm, rs;
3434
3435 skip_whitespace (str);
3436 if ((rdlo = reg_required_here (& str, 12)) == FAIL
3437 || skip_past_comma (& str) == FAIL
3438 || (rdhi = reg_required_here (& str, 16)) == FAIL
3439 || skip_past_comma (& str) == FAIL
3440 || (rm = reg_required_here (& str, 0)) == FAIL
3441 || skip_past_comma (& str) == FAIL
3442 || (rs = reg_required_here (& str, 8)) == FAIL)
3443 {
3444 inst.error = BAD_ARGS;
3445 return;
3446 }
3447
3448 if (rdlo == REG_PC || rdhi == REG_PC || rm == REG_PC || rs == REG_PC)
3449 {
3450 inst.error = BAD_PC;
3451 return;
3452 }
3453
3454 end_of_line (str);
3455}
3456
3457/* ARM V6 strex (argument parse). */
3458
3459static void
3460do_strex (char * str)
3461{
3462 int rd, rm, rn;
3463
3464 /* Parse Rd, Rm,. */
3465 skip_whitespace (str);
3466 if ((rd = reg_required_here (& str, 12)) == FAIL
3467 || skip_past_comma (& str) == FAIL
3468 || (rm = reg_required_here (& str, 0)) == FAIL
3469 || skip_past_comma (& str) == FAIL)
3470 {
3471 inst.error = BAD_ARGS;
3472 return;
3473 }
3474 if (rd == REG_PC || rm == REG_PC)
3475 {
3476 inst.error = BAD_PC;
3477 return;
3478 }
3479 if (rd == rm)
3480 {
3481 inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
3482 return;
3483 }
3484
3485 /* Skip past '['. */
3486 if ((strlen (str) >= 1)
3487 && strncmp (str, "[", 1) == 0)
3488 str += 1;
3489
3490 skip_whitespace (str);
3491
3492 /* Parse Rn. */
3493 if ((rn = reg_required_here (& str, 16)) == FAIL)
3494 {
3495 inst.error = BAD_ARGS;
3496 return;
3497 }
3498 else if (rn == REG_PC)
3499 {
3500 inst.error = BAD_PC;
3501 return;
3502 }
3503 if (rd == rn)
3504 {
3505 inst.error = _("Rd equal to Rm or Rn yields unpredictable results");
3506 return;
3507 }
3508 skip_whitespace (str);
3509
3510 /* Skip past ']'. */
3511 if ((strlen (str) >= 1)
3512 && strncmp (str, "]", 1) == 0)
3513 str += 1;
3514
3515 end_of_line (str);
3516}
3517
3518/* KIND indicates what kind of shifts are accepted. */
3519
3520static int
3521decode_shift (char ** str, int kind)
3522{
3523 const struct asm_shift_name * shift;
3524 char * p;
3525 char c;
3526
3527 skip_whitespace (* str);
3528
3529 for (p = * str; ISALPHA (* p); p ++)
3530 ;
3531
3532 if (p == * str)
3533 {
3534 inst.error = _("shift expression expected");
3535 return FAIL;
3536 }
3537
3538 c = * p;
3539 * p = '\0';
3540 shift = (const struct asm_shift_name *) hash_find (arm_shift_hsh, * str);
3541 * p = c;
3542
3543 if (shift == NULL)
3544 {
3545 inst.error = _("shift expression expected");
3546 return FAIL;
3547 }
3548
3549 assert (shift->properties->index == shift_properties[shift->properties->index].index);
3550
3551 if (kind == SHIFT_LSL_OR_ASR_IMMEDIATE
3552 && shift->properties->index != SHIFT_LSL
3553 && shift->properties->index != SHIFT_ASR)
3554 {
3555 inst.error = _("'LSL' or 'ASR' required");
3556 return FAIL;
3557 }
3558 else if (kind == SHIFT_LSL_IMMEDIATE
3559 && shift->properties->index != SHIFT_LSL)
3560 {
3561 inst.error = _("'LSL' required");
3562 return FAIL;
3563 }
3564 else if (kind == SHIFT_ASR_IMMEDIATE
3565 && shift->properties->index != SHIFT_ASR)
3566 {
3567 inst.error = _("'ASR' required");
3568 return FAIL;
3569 }
3570
3571 if (shift->properties->index == SHIFT_RRX)
3572 {
3573 * str = p;
3574 inst.instruction |= shift->properties->bit_field;
3575 return SUCCESS;
3576 }
3577
3578 skip_whitespace (p);
3579
3580 if (kind == NO_SHIFT_RESTRICT && reg_required_here (& p, 8) != FAIL)
3581 {
3582 inst.instruction |= shift->properties->bit_field | SHIFT_BY_REG;
3583 * str = p;
3584 return SUCCESS;
3585 }
3586 else if (! is_immediate_prefix (* p))
3587 {
3588 inst.error = (NO_SHIFT_RESTRICT
3589 ? _("shift requires register or #expression")
3590 : _("shift requires #expression"));
3591 * str = p;
3592 return FAIL;
3593 }
3594
3595 inst.error = NULL;
3596 p ++;
3597
3598 if (my_get_expression (& inst.reloc.exp, & p))
3599 return FAIL;
3600
3601 /* Validate some simple #expressions. */
3602 if (inst.reloc.exp.X_op == O_constant)
3603 {
3604 unsigned num = inst.reloc.exp.X_add_number;
3605
3606 /* Reject operations greater than 32. */
3607 if (num > 32
3608 /* Reject a shift of 0 unless the mode allows it. */
3609 || (num == 0 && shift->properties->allows_0 == 0)
3610 /* Reject a shift of 32 unless the mode allows it. */
3611 || (num == 32 && shift->properties->allows_32 == 0)
3612 )
3613 {
3614 /* As a special case we allow a shift of zero for
3615 modes that do not support it to be recoded as an
3616 logical shift left of zero (ie nothing). We warn
3617 about this though. */
3618 if (num == 0)
3619 {
3620 as_warn (_("shift of 0 ignored."));
3621 shift = & shift_names[0];
3622 assert (shift->properties->index == SHIFT_LSL);
3623 }
3624 else
3625 {
3626 inst.error = _("invalid immediate shift");
3627 return FAIL;
3628 }
3629 }
3630
3631 /* Shifts of 32 are encoded as 0, for those shifts that
3632 support it. */
3633 if (num == 32)
3634 num = 0;
3635
3636 inst.instruction |= (num << 7) | shift->properties->bit_field;
3637 }
3638 else
3639 {
3640 inst.reloc.type = BFD_RELOC_ARM_SHIFT_IMM;
3641 inst.reloc.pc_rel = 0;
3642 inst.instruction |= shift->properties->bit_field;
3643 }
3644
3645 * str = p;
3646 return SUCCESS;
09d92015
MM
3647}
3648
09d92015 3649static void
a737bd4d 3650do_sat (char ** str, int bias)
09d92015 3651{
a737bd4d
NC
3652 int rd, rm;
3653 expressionS expr;
09d92015 3654
a737bd4d 3655 skip_whitespace (*str);
09d92015 3656
a737bd4d
NC
3657 /* Parse <Rd>, field. */
3658 if ((rd = reg_required_here (str, 12)) == FAIL
3659 || skip_past_comma (str) == FAIL)
09d92015
MM
3660 {
3661 inst.error = BAD_ARGS;
a737bd4d 3662 return;
09d92015 3663 }
a737bd4d 3664 if (rd == REG_PC)
09d92015
MM
3665 {
3666 inst.error = BAD_PC;
3667 return;
3668 }
3669
a737bd4d
NC
3670 /* Parse #<immed>, field. */
3671 if (is_immediate_prefix (**str))
3672 (*str)++;
3673 else
09d92015 3674 {
a737bd4d 3675 inst.error = _("immediate expression expected");
09d92015
MM
3676 return;
3677 }
a737bd4d 3678 if (my_get_expression (&expr, str))
09d92015 3679 {
a737bd4d 3680 inst.error = _("bad expression");
09d92015
MM
3681 return;
3682 }
a737bd4d 3683 if (expr.X_op != O_constant)
09d92015 3684 {
a737bd4d 3685 inst.error = _("constant expression expected");
09d92015
MM
3686 return;
3687 }
a737bd4d
NC
3688 if (expr.X_add_number + bias < 0
3689 || expr.X_add_number + bias > 31)
3690 {
3691 inst.error = _("immediate value out of range");
3692 return;
3693 }
3694 inst.instruction |= (expr.X_add_number + bias) << 16;
3695 if (skip_past_comma (str) == FAIL)
09d92015
MM
3696 {
3697 inst.error = BAD_ARGS;
3698 return;
3699 }
a737bd4d
NC
3700
3701 /* Parse <Rm> field. */
3702 if ((rm = reg_required_here (str, 0)) == FAIL)
09d92015 3703 {
a737bd4d 3704 inst.error = BAD_ARGS;
09d92015
MM
3705 return;
3706 }
a737bd4d 3707 if (rm == REG_PC)
09d92015 3708 {
a737bd4d 3709 inst.error = BAD_PC;
09d92015
MM
3710 return;
3711 }
09d92015 3712
a737bd4d
NC
3713 if (skip_past_comma (str) == SUCCESS)
3714 decode_shift (str, SHIFT_LSL_OR_ASR_IMMEDIATE);
09d92015
MM
3715}
3716
a737bd4d 3717/* ARM V6 ssat (argument parse). */
09d92015
MM
3718
3719static void
a737bd4d 3720do_ssat (char * str)
09d92015
MM
3721{
3722 do_sat (&str, /*bias=*/-1);
3723 end_of_line (str);
3724}
3725
a737bd4d 3726/* ARM V6 usat (argument parse). */
09d92015
MM
3727
3728static void
a737bd4d 3729do_usat (char * str)
09d92015
MM
3730{
3731 do_sat (&str, /*bias=*/0);
3732 end_of_line (str);
3733}
3734
3735static void
a737bd4d 3736do_sat16 (char ** str, int bias)
09d92015
MM
3737{
3738 int rd, rm;
3739 expressionS expr;
3740
3741 skip_whitespace (*str);
a737bd4d
NC
3742
3743 /* Parse the <Rd> field. */
09d92015
MM
3744 if ((rd = reg_required_here (str, 12)) == FAIL
3745 || skip_past_comma (str) == FAIL)
3746 {
3747 inst.error = BAD_ARGS;
3748 return;
3749 }
3750 if (rd == REG_PC)
3751 {
3752 inst.error = BAD_PC;
3753 return;
3754 }
3755
a737bd4d 3756 /* Parse #<immed>, field. */
09d92015
MM
3757 if (is_immediate_prefix (**str))
3758 (*str)++;
3759 else
3760 {
3761 inst.error = _("immediate expression expected");
3762 return;
3763 }
3764 if (my_get_expression (&expr, str))
3765 {
3766 inst.error = _("bad expression");
3767 return;
3768 }
3769 if (expr.X_op != O_constant)
3770 {
3771 inst.error = _("constant expression expected");
3772 return;
3773 }
3774 if (expr.X_add_number + bias < 0
a737bd4d 3775 || expr.X_add_number + bias > 15)
09d92015
MM
3776 {
3777 inst.error = _("immediate value out of range");
3778 return;
3779 }
3780 inst.instruction |= (expr.X_add_number + bias) << 16;
3781 if (skip_past_comma (str) == FAIL)
3782 {
3783 inst.error = BAD_ARGS;
3784 return;
3785 }
3786
a737bd4d 3787 /* Parse <Rm> field. */
09d92015
MM
3788 if ((rm = reg_required_here (str, 0)) == FAIL)
3789 {
3790 inst.error = BAD_ARGS;
3791 return;
3792 }
3793 if (rm == REG_PC)
3794 {
3795 inst.error = BAD_PC;
3796 return;
3797 }
09d92015
MM
3798}
3799
a737bd4d 3800/* ARM V6 ssat16 (argument parse). */
09d92015
MM
3801
3802static void
a737bd4d 3803do_ssat16 (char * str)
09d92015
MM
3804{
3805 do_sat16 (&str, /*bias=*/-1);
3806 end_of_line (str);
3807}
3808
3809static void
a737bd4d 3810do_usat16 (char * str)
09d92015
MM
3811{
3812 do_sat16 (&str, /*bias=*/0);
3813 end_of_line (str);
3814}
3815
3816static void
a737bd4d 3817do_cps_mode (char ** str)
09d92015 3818{
09d92015
MM
3819 expressionS expr;
3820
3821 skip_whitespace (*str);
3822
a737bd4d 3823 if (! is_immediate_prefix (**str))
09d92015
MM
3824 {
3825 inst.error = _("immediate expression expected");
3826 return;
3827 }
a737bd4d
NC
3828
3829 (*str)++; /* Strip off the immediate signifier. */
09d92015
MM
3830 if (my_get_expression (&expr, str))
3831 {
3832 inst.error = _("bad expression");
3833 return;
3834 }
a737bd4d 3835
09d92015
MM
3836 if (expr.X_op != O_constant)
3837 {
3838 inst.error = _("constant expression expected");
3839 return;
3840 }
09d92015 3841
a737bd4d
NC
3842 /* The mode is a 5 bit field. Valid values are 0-31. */
3843 if (((unsigned) expr.X_add_number) > 31
3844 || (inst.reloc.exp.X_add_number) < 0)
09d92015 3845 {
a737bd4d 3846 inst.error = _("invalid constant");
09d92015
MM
3847 return;
3848 }
a737bd4d
NC
3849
3850 inst.instruction |= expr.X_add_number;
09d92015
MM
3851}
3852
a737bd4d 3853/* ARM V6 srs (argument parse). */
09d92015
MM
3854
3855static void
a737bd4d 3856do_srs (char * str)
09d92015
MM
3857{
3858 char *exclam;
3859 skip_whitespace (str);
3860 exclam = strchr (str, '!');
3861 if (exclam)
3862 *exclam = '\0';
3863 do_cps_mode (&str);
3864 if (exclam)
3865 *exclam = '!';
a737bd4d 3866 if (*str == '!')
09d92015
MM
3867 {
3868 inst.instruction |= WRITE_BACK;
3869 str++;
3870 }
3871 end_of_line (str);
3872}
3873
a737bd4d 3874/* ARM V6 SMMUL (argument parse). */
09d92015
MM
3875
3876static void
a737bd4d 3877do_smmul (char * str)
09d92015
MM
3878{
3879 int rd, rm, rs;
a737bd4d 3880
09d92015
MM
3881 skip_whitespace (str);
3882 if ((rd = reg_required_here (&str, 16)) == FAIL
3883 || skip_past_comma (&str) == FAIL
3884 || (rm = reg_required_here (&str, 0)) == FAIL
3885 || skip_past_comma (&str) == FAIL
3886 || (rs = reg_required_here (&str, 8)) == FAIL)
3887 {
3888 inst.error = BAD_ARGS;
3889 return;
3890 }
3891
a737bd4d 3892 if ( rd == REG_PC
09d92015
MM
3893 || rm == REG_PC
3894 || rs == REG_PC)
3895 {
3896 inst.error = BAD_PC;
3897 return;
3898 }
3899
3900 end_of_line (str);
09d92015
MM
3901}
3902
a737bd4d 3903/* ARM V6 SMLALD (argument parse). */
09d92015
MM
3904
3905static void
a737bd4d 3906do_smlald (char * str)
09d92015
MM
3907{
3908 int rdlo, rdhi, rm, rs;
a737bd4d 3909
09d92015
MM
3910 skip_whitespace (str);
3911 if ((rdlo = reg_required_here (&str, 12)) == FAIL
3912 || skip_past_comma (&str) == FAIL
3913 || (rdhi = reg_required_here (&str, 16)) == FAIL
3914 || skip_past_comma (&str) == FAIL
3915 || (rm = reg_required_here (&str, 0)) == FAIL
3916 || skip_past_comma (&str) == FAIL
3917 || (rs = reg_required_here (&str, 8)) == FAIL)
3918 {
3919 inst.error = BAD_ARGS;
3920 return;
3921 }
3922
a737bd4d
NC
3923 if ( rdlo == REG_PC
3924 || rdhi == REG_PC
09d92015
MM
3925 || rm == REG_PC
3926 || rs == REG_PC)
3927 {
3928 inst.error = BAD_PC;
3929 return;
3930 }
3931
3932 end_of_line (str);
3933}
3934
a737bd4d 3935/* ARM V6 SMLAD (argument parse). Signed multiply accumulate dual.
09d92015
MM
3936 smlad{x}{<cond>} Rd, Rm, Rs, Rn */
3937
a737bd4d
NC
3938static void
3939do_smlad (char * str)
09d92015
MM
3940{
3941 int rd, rm, rs, rn;
a737bd4d 3942
09d92015
MM
3943 skip_whitespace (str);
3944 if ((rd = reg_required_here (&str, 16)) == FAIL
3945 || skip_past_comma (&str) == FAIL
3946 || (rm = reg_required_here (&str, 0)) == FAIL
3947 || skip_past_comma (&str) == FAIL
3948 || (rs = reg_required_here (&str, 8)) == FAIL
3949 || skip_past_comma (&str) == FAIL
3950 || (rn = reg_required_here (&str, 12)) == FAIL)
3951 {
3952 inst.error = BAD_ARGS;
3953 return;
3954 }
a737bd4d
NC
3955
3956 if ( rd == REG_PC
3957 || rn == REG_PC
09d92015
MM
3958 || rs == REG_PC
3959 || rm == REG_PC)
3960 {
3961 inst.error = BAD_PC;
3962 return;
3963 }
3964
3965 end_of_line (str);
09d92015
MM
3966}
3967
3968/* Returns true if the endian-specifier indicates big-endianness. */
3969
3970static int
a737bd4d 3971do_endian_specifier (char * str)
09d92015
MM
3972{
3973 int big_endian = 0;
3974
3975 skip_whitespace (str);
3976 if (strlen (str) < 2)
3977 inst.error = _("missing endian specifier");
3978 else if (strncasecmp (str, "BE", 2) == 0)
3979 {
3980 str += 2;
3981 big_endian = 1;
3982 }
3983 else if (strncasecmp (str, "LE", 2) == 0)
3984 str += 2;
3985 else
3986 inst.error = _("valid endian specifiers are be or le");
3987
3988 end_of_line (str);
3989
3990 return big_endian;
3991}
3992
a737bd4d
NC
3993/* ARM V6 SETEND (argument parse). Sets the E bit in the CPSR while
3994 preserving the other bits.
3995
3996 setend <endian_specifier>, where <endian_specifier> is either
3997 BE or LE. */
3998
3999static void
4000do_setend (char * str)
4001{
4002 if (do_endian_specifier (str))
4003 inst.instruction |= 0x200;
4004}
4005
09d92015
MM
4006/* ARM V6 SXTH.
4007
4008 SXTH {<cond>} <Rd>, <Rm>{, <rotation>}
4009 Condition defaults to COND_ALWAYS.
a737bd4d 4010 Error if any register uses R15. */
09d92015 4011
a737bd4d
NC
4012static void
4013do_sxth (char * str)
09d92015
MM
4014{
4015 int rd, rm;
4016 expressionS expr;
4017 int rotation_clear_mask = 0xfffff3ff;
4018 int rotation_eight_mask = 0x00000400;
4019 int rotation_sixteen_mask = 0x00000800;
4020 int rotation_twenty_four_mask = 0x00000c00;
a737bd4d 4021
09d92015
MM
4022 skip_whitespace (str);
4023 if ((rd = reg_required_here (&str, 12)) == FAIL
4024 || skip_past_comma (&str) == FAIL
4025 || (rm = reg_required_here (&str, 0)) == FAIL)
4026 {
4027 inst.error = BAD_ARGS;
4028 return;
4029 }
4030
4031 else if (rd == REG_PC || rm == REG_PC)
4032 {
4033 inst.error = BAD_PC;
4034 return;
4035 }
a737bd4d
NC
4036
4037 /* Zero out the rotation field. */
09d92015 4038 inst.instruction &= rotation_clear_mask;
a737bd4d
NC
4039
4040 /* Check for lack of optional rotation field. */
09d92015
MM
4041 if (skip_past_comma (&str) == FAIL)
4042 {
4043 end_of_line (str);
4044 return;
4045 }
a737bd4d
NC
4046
4047 /* Move past 'ROR'. */
09d92015
MM
4048 skip_whitespace (str);
4049 if (strncasecmp (str, "ROR", 3) == 0)
a737bd4d 4050 str += 3;
09d92015
MM
4051 else
4052 {
4053 inst.error = _("missing rotation field after comma");
4054 return;
4055 }
a737bd4d
NC
4056
4057 /* Get the immediate constant. */
09d92015
MM
4058 skip_whitespace (str);
4059 if (is_immediate_prefix (* str))
4060 str++;
4061 else
4062 {
4063 inst.error = _("immediate expression expected");
4064 return;
4065 }
a737bd4d 4066
09d92015
MM
4067 if (my_get_expression (&expr, &str))
4068 {
4069 inst.error = _("bad expression");
4070 return;
4071 }
4072
4073 if (expr.X_op != O_constant)
4074 {
4075 inst.error = _("constant expression expected");
4076 return;
4077 }
a737bd4d
NC
4078
4079 switch (expr.X_add_number)
09d92015
MM
4080 {
4081 case 0:
a737bd4d 4082 /* Rotation field has already been zeroed. */
09d92015
MM
4083 break;
4084 case 8:
4085 inst.instruction |= rotation_eight_mask;
4086 break;
4087
4088 case 16:
4089 inst.instruction |= rotation_sixteen_mask;
4090 break;
a737bd4d 4091
09d92015
MM
4092 case 24:
4093 inst.instruction |= rotation_twenty_four_mask;
4094 break;
4095
4096 default:
4097 inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited");
4098 break;
4099 }
4100
4101 end_of_line (str);
09d92015
MM
4102}
4103
4104/* ARM V6 SXTAH extracts a 16-bit value from a register, sign
4105 extends it to 32-bits, and adds the result to a value in another
4106 register. You can specify a rotation by 0, 8, 16, or 24 bits
4107 before extracting the 16-bit value.
4108 SXTAH{<cond>} <Rd>, <Rn>, <Rm>{, <rotation>}
4109 Condition defaults to COND_ALWAYS.
a737bd4d 4110 Error if any register uses R15. */
09d92015 4111
a737bd4d
NC
4112static void
4113do_sxtah (char * str)
09d92015
MM
4114{
4115 int rd, rn, rm;
4116 expressionS expr;
4117 int rotation_clear_mask = 0xfffff3ff;
4118 int rotation_eight_mask = 0x00000400;
4119 int rotation_sixteen_mask = 0x00000800;
4120 int rotation_twenty_four_mask = 0x00000c00;
a737bd4d 4121
09d92015
MM
4122 skip_whitespace (str);
4123 if ((rd = reg_required_here (&str, 12)) == FAIL
4124 || skip_past_comma (&str) == FAIL
4125 || (rn = reg_required_here (&str, 16)) == FAIL
4126 || skip_past_comma (&str) == FAIL
4127 || (rm = reg_required_here (&str, 0)) == FAIL)
4128 {
4129 inst.error = BAD_ARGS;
4130 return;
4131 }
4132
4133 else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
4134 {
4135 inst.error = BAD_PC;
4136 return;
4137 }
a737bd4d
NC
4138
4139 /* Zero out the rotation field. */
09d92015 4140 inst.instruction &= rotation_clear_mask;
a737bd4d
NC
4141
4142 /* Check for lack of optional rotation field. */
09d92015
MM
4143 if (skip_past_comma (&str) == FAIL)
4144 {
4145 end_of_line (str);
4146 return;
4147 }
a737bd4d
NC
4148
4149 /* Move past 'ROR'. */
09d92015
MM
4150 skip_whitespace (str);
4151 if (strncasecmp (str, "ROR", 3) == 0)
a737bd4d 4152 str += 3;
09d92015
MM
4153 else
4154 {
4155 inst.error = _("missing rotation field after comma");
4156 return;
4157 }
a737bd4d
NC
4158
4159 /* Get the immediate constant. */
09d92015
MM
4160 skip_whitespace (str);
4161 if (is_immediate_prefix (* str))
4162 str++;
4163 else
4164 {
4165 inst.error = _("immediate expression expected");
4166 return;
4167 }
a737bd4d 4168
09d92015
MM
4169 if (my_get_expression (&expr, &str))
4170 {
4171 inst.error = _("bad expression");
4172 return;
4173 }
4174
4175 if (expr.X_op != O_constant)
4176 {
4177 inst.error = _("constant expression expected");
4178 return;
4179 }
a737bd4d
NC
4180
4181 switch (expr.X_add_number)
09d92015
MM
4182 {
4183 case 0:
a737bd4d 4184 /* Rotation field has already been zeroed. */
09d92015
MM
4185 break;
4186
4187 case 8:
4188 inst.instruction |= rotation_eight_mask;
4189 break;
4190
4191 case 16:
4192 inst.instruction |= rotation_sixteen_mask;
4193 break;
a737bd4d 4194
09d92015
MM
4195 case 24:
4196 inst.instruction |= rotation_twenty_four_mask;
4197 break;
4198
4199 default:
4200 inst.error = _("rotation can be 8, 16, 24 or 0 when field is ommited");
4201 break;
4202 }
4203
4204 end_of_line (str);
09d92015 4205}
a737bd4d 4206
09d92015
MM
4207
4208/* ARM V6 RFE (Return from Exception) loads the PC and CPSR from the
4209 word at the specified address and the following word
a737bd4d 4210 respectively.
09d92015 4211 Unconditionally executed.
a737bd4d 4212 Error if Rn is R15. */
09d92015
MM
4213
4214static void
a737bd4d 4215do_rfe (char * str)
09d92015
MM
4216{
4217 int rn;
4218
4219 skip_whitespace (str);
a737bd4d 4220
09d92015
MM
4221 if ((rn = reg_required_here (&str, 16)) == FAIL)
4222 return;
b99bd4ef 4223
09d92015 4224 if (rn == REG_PC)
b99bd4ef 4225 {
09d92015 4226 inst.error = BAD_PC;
b99bd4ef
NC
4227 return;
4228 }
4229
09d92015 4230 skip_whitespace (str);
a737bd4d 4231
09d92015
MM
4232 if (*str == '!')
4233 {
4234 inst.instruction |= WRITE_BACK;
4235 str++;
4236 }
b99bd4ef
NC
4237 end_of_line (str);
4238}
4239
09d92015
MM
4240/* ARM V6 REV (Byte Reverse Word) reverses the byte order in a 32-bit
4241 register (argument parse).
4242 REV{<cond>} Rd, Rm.
4243 Condition defaults to COND_ALWAYS.
a737bd4d 4244 Error if Rd or Rm are R15. */
b99bd4ef
NC
4245
4246static void
a737bd4d 4247do_rev (char * str)
b99bd4ef
NC
4248{
4249 int rd, rm;
4250
b99bd4ef
NC
4251 skip_whitespace (str);
4252
09d92015
MM
4253 if ((rd = reg_required_here (&str, 12)) == FAIL
4254 || skip_past_comma (&str) == FAIL
4255 || (rm = reg_required_here (&str, 0)) == FAIL)
b99bd4ef
NC
4256 inst.error = BAD_ARGS;
4257
09d92015 4258 else if (rd == REG_PC || rm == REG_PC)
b99bd4ef
NC
4259 inst.error = BAD_PC;
4260
4261 else
4262 end_of_line (str);
4263}
4264
09d92015 4265/* ARM V6 Perform Two Sixteen Bit Integer Additions. (argument parse).
a737bd4d 4266 QADD16{<cond>} <Rd>, <Rn>, <Rm>
09d92015
MM
4267 Condition defaults to COND_ALWAYS.
4268 Error if Rd, Rn or Rm are R15. */
b99bd4ef
NC
4269
4270static void
a737bd4d 4271do_qadd16 (char * str)
b99bd4ef 4272{
09d92015
MM
4273 int rd, rm, rn;
4274
b99bd4ef
NC
4275 skip_whitespace (str);
4276
09d92015
MM
4277 if ((rd = reg_required_here (&str, 12)) == FAIL
4278 || skip_past_comma (&str) == FAIL
4279 || (rn = reg_required_here (&str, 16)) == FAIL
4280 || skip_past_comma (&str) == FAIL
4281 || (rm = reg_required_here (&str, 0)) == FAIL)
4282 inst.error = BAD_ARGS;
4283
4284 else if (rd == REG_PC || rm == REG_PC || rn == REG_PC)
4285 inst.error = BAD_PC;
4286
b99bd4ef
NC
4287 else
4288 end_of_line (str);
4289}
4290
b99bd4ef 4291static void
a737bd4d 4292do_pkh_core (char * str, int shift)
b99bd4ef 4293{
09d92015 4294 int rd, rn, rm;
b99bd4ef 4295
09d92015
MM
4296 skip_whitespace (str);
4297 if (((rd = reg_required_here (&str, 12)) == FAIL)
4298 || (skip_past_comma (&str) == FAIL)
4299 || ((rn = reg_required_here (&str, 16)) == FAIL)
4300 || (skip_past_comma (&str) == FAIL)
4301 || ((rm = reg_required_here (&str, 0)) == FAIL))
b99bd4ef 4302 {
09d92015 4303 inst.error = BAD_ARGS;
b99bd4ef
NC
4304 return;
4305 }
4306
09d92015 4307 else if (rd == REG_PC || rn == REG_PC || rm == REG_PC)
b99bd4ef 4308 {
09d92015 4309 inst.error = BAD_PC;
b99bd4ef
NC
4310 return;
4311 }
4312
a737bd4d
NC
4313 /* Check for optional shift immediate constant. */
4314 if (skip_past_comma (&str) == FAIL)
b99bd4ef 4315 {
09d92015
MM
4316 if (shift == SHIFT_ASR_IMMEDIATE)
4317 {
4318 /* If the shift specifier is ommited, turn the instruction
4319 into pkhbt rd, rm, rn. First, switch the instruction
4320 code, and clear the rn and rm fields. */
4321 inst.instruction &= 0xfff0f010;
4322 /* Now, re-encode the registers. */
4323 inst.instruction |= (rm << 16) | rn;
4324 }
b99bd4ef
NC
4325 return;
4326 }
4327
09d92015
MM
4328 decode_shift (&str, shift);
4329}
4330
a737bd4d
NC
4331/* ARM V6 Pack Halfword Bottom Top instruction (argument parse).
4332 PKHBT {<cond>} <Rd>, <Rn>, <Rm> {, LSL #<shift_imm>}
4333 Condition defaults to COND_ALWAYS.
4334 Error if Rd, Rn or Rm are R15. */
4335
4336static void
4337do_pkhbt (char * str)
4338{
4339 do_pkh_core (str, SHIFT_LSL_IMMEDIATE);
4340}
4341
4342/* ARM V6 PKHTB (Argument Parse). */
4343
4344static void
4345do_pkhtb (char * str)
4346{
4347 do_pkh_core (str, SHIFT_ASR_IMMEDIATE);
4348}
4349
09d92015 4350/* ARM V6 Load Register Exclusive instruction (argument parse).
0dd132b6 4351 LDREX{,B,D,H}{<cond>} <Rd, [<Rn>]
09d92015 4352 Condition defaults to COND_ALWAYS.
a737bd4d
NC
4353 Error if Rd or Rn are R15.
4354 See ARMARMv6 A4.1.27: LDREX. */
09d92015
MM
4355
4356static void
a737bd4d 4357do_ldrex (char * str)
09d92015
MM
4358{
4359 int rd, rn;
4360
4361 skip_whitespace (str);
4362
a737bd4d 4363 /* Parse Rd. */
09d92015
MM
4364 if (((rd = reg_required_here (&str, 12)) == FAIL)
4365 || (skip_past_comma (&str) == FAIL))
b99bd4ef 4366 {
09d92015 4367 inst.error = BAD_ARGS;
b99bd4ef
NC
4368 return;
4369 }
09d92015 4370 else if (rd == REG_PC)
b99bd4ef 4371 {
09d92015 4372 inst.error = BAD_PC;
b99bd4ef
NC
4373 return;
4374 }
a737bd4d 4375 skip_whitespace (str);
b99bd4ef 4376
a737bd4d
NC
4377 /* Skip past '['. */
4378 if ((strlen (str) >= 1)
09d92015 4379 &&strncmp (str, "[", 1) == 0)
a737bd4d
NC
4380 str += 1;
4381 skip_whitespace (str);
09d92015 4382
a737bd4d 4383 /* Parse Rn. */
09d92015 4384 if ((rn = reg_required_here (&str, 16)) == FAIL)
b99bd4ef 4385 {
09d92015
MM
4386 inst.error = BAD_ARGS;
4387 return;
b99bd4ef 4388 }
09d92015
MM
4389 else if (rn == REG_PC)
4390 {
4391 inst.error = BAD_PC;
4392 return;
4393 }
a737bd4d 4394 skip_whitespace (str);
b99bd4ef 4395
a737bd4d
NC
4396 /* Skip past ']'. */
4397 if ((strlen (str) >= 1)
09d92015 4398 && strncmp (str, "]", 1) == 0)
a737bd4d
NC
4399 str += 1;
4400
b99bd4ef
NC
4401 end_of_line (str);
4402}
4403
09d92015 4404/* ARM V6 change processor state instruction (argument parse)
a737bd4d 4405 CPS, CPSIE, CSPID . */
b99bd4ef
NC
4406
4407static void
a737bd4d 4408do_cps (char * str)
b99bd4ef 4409{
09d92015
MM
4410 do_cps_mode (&str);
4411 end_of_line (str);
4412}
b99bd4ef 4413
09d92015 4414static void
a737bd4d 4415do_cps_flags (char ** str, int thumb_p)
ea6ef066 4416{
a737bd4d
NC
4417 struct cps_flag
4418 {
09d92015
MM
4419 char character;
4420 unsigned long arm_value;
4421 unsigned long thumb_value;
4422 };
a737bd4d
NC
4423 static struct cps_flag flag_table[] =
4424 {
09d92015
MM
4425 {'a', 0x100, 0x4 },
4426 {'i', 0x080, 0x2 },
4427 {'f', 0x040, 0x1 }
4428 };
ea6ef066 4429
09d92015 4430 int saw_a_flag = 0;
ea6ef066 4431
09d92015
MM
4432 skip_whitespace (*str);
4433
a737bd4d 4434 /* Get the a, f and i flags. */
09d92015 4435 while (**str && **str != ',')
ea6ef066 4436 {
09d92015
MM
4437 struct cps_flag *p;
4438 struct cps_flag *q = flag_table + sizeof (flag_table)/sizeof (*p);
a737bd4d 4439
09d92015
MM
4440 for (p = flag_table; p < q; ++p)
4441 if (strncasecmp (*str, &p->character, 1) == 0)
4442 {
4443 inst.instruction |= (thumb_p ? p->thumb_value : p->arm_value);
4444 saw_a_flag = 1;
4445 break;
4446 }
4447 if (p == q)
4448 {
4449 inst.error = _("unrecognized flag");
4450 return;
4451 }
4452 (*str)++;
ea6ef066 4453 }
a737bd4d
NC
4454
4455 if (!saw_a_flag)
4456 inst.error = _("no 'a', 'i', or 'f' flags for 'cps'");
4457}
4458
4459static void
4460do_cpsi (char * str)
4461{
4462 do_cps_flags (&str, /*thumb_p=*/0);
4463
4464 if (skip_past_comma (&str) == SUCCESS)
4465 {
4466 skip_whitespace (str);
4467 do_cps_mode (&str);
4468 }
4469 end_of_line (str);
ea6ef066
RE
4470}
4471
b05fe5cf
ZW
4472/* ARM V6T2 bitfield manipulation instructions. */
4473
4474static int
4475five_bit_unsigned_immediate (char **str)
4476{
4477 expressionS expr;
4478
4479 skip_whitespace (*str);
4480 if (!is_immediate_prefix (**str))
4481 {
4482 inst.error = _("immediate expression expected");
4483 return -1;
4484 }
4485 (*str)++;
4486 if (my_get_expression (&expr, str))
4487 {
4488 inst.error = _("bad expression");
4489 return -1;
4490 }
4491 if (expr.X_op != O_constant)
4492 {
4493 inst.error = _("constant expression expected");
4494 return -1;
4495 }
4496 if (expr.X_add_number < 0 || expr.X_add_number > 32)
4497 {
4498 inst.error = _("immediate value out of range");
4499 return -1;
4500 }
4501
4502 return expr.X_add_number;
4503}
4504
4505static void
4506bfci_lsb_and_width (char *str)
4507{
4508 int lsb, width;
4509
4510 if ((lsb = five_bit_unsigned_immediate (&str)) == -1)
4511 return;
4512
4513 if (skip_past_comma (&str) == FAIL)
4514 {
4515 inst.error = BAD_ARGS;
4516 return;
4517 }
4518 if ((width = five_bit_unsigned_immediate (&str)) == -1)
4519 return;
4520
4521 end_of_line (str);
4522
4523 if (width == 0 || lsb == 32)
4524 {
4525 inst.error = _("immediate value out of range");
4526 return;
4527 }
4528 else if (width + lsb > 32)
4529 {
4530 inst.error = _("bit-field extends past end of register");
4531 return;
4532 }
4533
4534 /* Convert to LSB/MSB and write to register. */
4535 inst.instruction |= lsb << 7;
4536 inst.instruction |= (width + lsb - 1) << 16;
4537}
4538
4539static void
4540do_bfc (char *str)
4541{
4542 int rd;
4543
4544 /* Rd. */
4545 skip_whitespace (str);
4546 if (((rd = reg_required_here (&str, 12)) == FAIL)
4547 || (skip_past_comma (&str) == FAIL))
4548 {
4549 inst.error = BAD_ARGS;
4550 return;
4551 }
4552 else if (rd == REG_PC)
4553 {
4554 inst.error = BAD_PC;
4555 return;
4556 }
4557
4558 bfci_lsb_and_width (str);
4559}
4560
4561static void
4562do_bfi (char *str)
4563{
4564 int rd, rm;
4565
4566 /* Rd. */
4567 skip_whitespace (str);
4568 if (((rd = reg_required_here (&str, 12)) == FAIL)
4569 || (skip_past_comma (&str) == FAIL))
4570 {
4571 inst.error = BAD_ARGS;
4572 return;
4573 }
4574 else if (rd == REG_PC)
4575 {
4576 inst.error = BAD_PC;
4577 return;
4578 }
4579
4580 /* Rm. Accept #0 in this position as an alternative syntax for bfc. */
4581 skip_whitespace (str);
4582 if (is_immediate_prefix (*str))
4583 {
4584 expressionS expr;
4585 str++;
4586 if (my_get_expression (&expr, &str))
4587 {
4588 inst.error = _("bad expression");
4589 return;
4590 }
4591 if (expr.X_op != O_constant)
4592 {
4593 inst.error = _("constant expression expected");
4594 return;
4595 }
4596 if (expr.X_add_number != 0)
4597 {
4598 inst.error = _("immediate value out of range");
4599 return;
4600 }
4601 inst.instruction |= 0x0000000f; /* Rm = PC -> bfc, not bfi. */
4602 }
4603 else
4604 {
4605 if ((rm = reg_required_here (&str, 0)) == FAIL)
4606 {
4607 inst.error = BAD_ARGS;
4608 return;
4609 }
4610 else if (rm == REG_PC)
4611 {
4612 inst.error = BAD_PC;
4613 return;
4614 }
4615 }
4616 if (skip_past_comma (&str) == FAIL)
4617 {
4618 inst.error = BAD_ARGS;
4619 return;
4620 }
4621
4622 bfci_lsb_and_width (str);
4623}
4624
4625static void
4626do_bfx (char *str)
4627{
4628 int lsb, width;
4629
4630 /* Rd. */
4631 skip_whitespace (str);
4632 if (reg_required_here (&str, 12) == FAIL
4633 || skip_past_comma (&str) == FAIL)
4634 {
4635 inst.error = BAD_ARGS;
4636 return;
4637 }
4638
4639 /* Rm. */
4640 skip_whitespace (str);
4641 if (reg_required_here (&str, 0) == FAIL
4642 || skip_past_comma (&str) == FAIL)
4643 {
4644 inst.error = BAD_ARGS;
4645 return;
4646 }
4647
4648 if ((lsb = five_bit_unsigned_immediate (&str)) == -1)
4649 return;
4650
4651 if (skip_past_comma (&str) == FAIL)
4652 {
4653 inst.error = BAD_ARGS;
4654 return;
4655 }
4656 if ((width = five_bit_unsigned_immediate (&str)) == -1)
4657 return;
4658
4659 end_of_line (str);
4660
4661 if (width == 0 || lsb == 32)
4662 {
4663 inst.error = _("immediate value out of range");
4664 return;
4665 }
4666 else if (width + lsb > 32)
4667 {
4668 inst.error = _("bit-field extends past end of register");
4669 return;
4670 }
4671
4672 inst.instruction |= lsb << 7;
4673 inst.instruction |= (width - 1) << 16;
4674}
4675
4676static void
4677do_rbit (char *str)
4678{
4679 /* Rd. */
4680 skip_whitespace (str);
4681 if (reg_required_here (&str, 12) == FAIL
4682 || skip_past_comma (&str) == FAIL)
4683 {
4684 inst.error = BAD_ARGS;
4685 return;
4686 }
4687
4688 /* Rm. */
4689 skip_whitespace (str);
4690 if (reg_required_here (&str, 0) == FAIL)
4691 {
4692 inst.error = BAD_ARGS;
4693 return;
4694 }
4695
4696 end_of_line (str);
4697}
4698
4699/* ARM V6T2 16-bit immediate register load: MOV[WT]{cond} Rd, #<imm16>. */
4700static void
4701do_mov16 (char *str)
4702{
4703 int rd;
4704 expressionS expr;
4705
4706 /* Rd. */
4707 skip_whitespace (str);
4708 if (((rd = reg_required_here (&str, 12)) == FAIL)
4709 || (skip_past_comma (&str) == FAIL))
4710 {
4711 inst.error = BAD_ARGS;
4712 return;
4713 }
4714 else if (rd == REG_PC)
4715 {
4716 inst.error = BAD_PC;
4717 return;
4718 }
4719
4720 /* Imm16. */
4721 skip_whitespace (str);
4722 if (!is_immediate_prefix (*str))
4723 {
4724 inst.error = _("immediate expression expected");
4725 return;
4726 }
4727 str++;
4728 if (my_get_expression (&expr, &str))
4729 {
4730 inst.error = _("bad expression");
4731 return;
4732 }
4733 if (expr.X_op != O_constant)
4734 {
4735 inst.error = _("constant expression expected");
4736 return;
4737 }
4738 if (expr.X_add_number < 0 || expr.X_add_number > 65535)
4739 {
4740 inst.error = _("immediate value out of range");
4741 return;
4742 }
4743
4744 end_of_line (str);
4745
4746 /* The value is in two pieces: 0:11, 16:19. */
4747 inst.instruction |= (expr.X_add_number & 0x00000fff);
4748 inst.instruction |= (expr.X_add_number & 0x0000f000) << 4;
4749}
4750
4751
b99bd4ef
NC
4752/* THUMB V5 breakpoint instruction (argument parse)
4753 BKPT <immed_8>. */
4754
4755static void
a737bd4d 4756do_t_bkpt (char * str)
b99bd4ef
NC
4757{
4758 expressionS expr;
4759 unsigned long number;
4760
4761 skip_whitespace (str);
4762
4763 /* Allow optional leading '#'. */
4764 if (is_immediate_prefix (*str))
4765 str ++;
4766
4767 memset (& expr, '\0', sizeof (expr));
143c8e19
NC
4768 if (my_get_expression (& expr, & str)
4769 || (expr.X_op != O_constant
4770 /* As a convenience we allow 'bkpt' without an operand. */
4771 && expr.X_op != O_absent))
b99bd4ef 4772 {
143c8e19 4773 inst.error = _("bad expression");
b99bd4ef
NC
4774 return;
4775 }
4776
4777 number = expr.X_add_number;
4778
4779 /* Check it fits an 8 bit unsigned. */
4780 if (number != (number & 0xff))
4781 {
4782 inst.error = _("immediate value out of range");
4783 return;
4784 }
4785
4786 inst.instruction |= number;
4787
4788 end_of_line (str);
4789}
4790
f17c130b 4791#ifdef OBJ_ELF
a737bd4d
NC
4792static bfd_reloc_code_real_type
4793arm_parse_reloc (void)
4794{
4795 char id [16];
4796 char * ip;
4797 unsigned int i;
4798 static struct
4799 {
4800 char * str;
4801 int len;
4802 bfd_reloc_code_real_type reloc;
4803 }
4804 reloc_map[] =
4805 {
4806#define MAP(str,reloc) { str, sizeof (str) - 1, reloc }
4807 MAP ("(got)", BFD_RELOC_ARM_GOT32),
4808 MAP ("(gotoff)", BFD_RELOC_ARM_GOTOFF),
4809 /* ScottB: Jan 30, 1998 - Added support for parsing "var(PLT)"
4810 branch instructions generated by GCC for PLT relocs. */
4811 MAP ("(plt)", BFD_RELOC_ARM_PLT32),
4812 MAP ("(target1)", BFD_RELOC_ARM_TARGET1),
4813 MAP ("(sbrel)", BFD_RELOC_ARM_SBREL32),
4814 MAP ("(target2)", BFD_RELOC_ARM_TARGET2),
ba93b8ac
DJ
4815 MAP ("(tlsgd)", BFD_RELOC_ARM_TLS_GD32),
4816 MAP ("(tlsldm)", BFD_RELOC_ARM_TLS_LDM32),
4817 MAP ("(tlsldo)", BFD_RELOC_ARM_TLS_LDO32),
4818 MAP ("(gottpoff)", BFD_RELOC_ARM_TLS_IE32),
4819 MAP ("(tpoff)", BFD_RELOC_ARM_TLS_LE32),
a737bd4d
NC
4820 { NULL, 0, BFD_RELOC_UNUSED }
4821#undef MAP
4822 };
4823
4824 for (i = 0, ip = input_line_pointer;
4825 i < sizeof (id) && (ISALNUM (*ip) || ISPUNCT (*ip));
4826 i++, ip++)
4827 id[i] = TOLOWER (*ip);
4828
4829 for (i = 0; reloc_map[i].str; i++)
4830 if (strncmp (id, reloc_map[i].str, reloc_map[i].len) == 0)
4831 break;
4832
4833 input_line_pointer += reloc_map[i].len;
4834
4835 return reloc_map[i].reloc;
4836}
f17c130b 4837#endif
a737bd4d 4838
b99bd4ef
NC
4839/* ARM V5 branch-link-exchange (argument parse) for BLX(1) only.
4840 Expects inst.instruction is set for BLX(1).
4841 Note: this is cloned from do_branch, and the reloc changed to be a
4842 new one that can cope with setting one extra bit (the H bit). */
4843
4844static void
a737bd4d 4845do_branch25 (char * str)
b99bd4ef
NC
4846{
4847 if (my_get_expression (& inst.reloc.exp, & str))
4848 return;
4849
4850#ifdef OBJ_ELF
4851 {
4852 char * save_in;
4853
4854 /* ScottB: February 5, 1998 */
4855 /* Check to see of PLT32 reloc required for the instruction. */
4856
4857 /* arm_parse_reloc() works on input_line_pointer.
4858 We actually want to parse the operands to the branch instruction
4859 passed in 'str'. Save the input pointer and restore it later. */
4860 save_in = input_line_pointer;
4861 input_line_pointer = str;
4862
4863 if (inst.reloc.exp.X_op == O_symbol
4864 && *str == '('
4865 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
4866 {
4867 inst.reloc.type = BFD_RELOC_ARM_PLT32;
4868 inst.reloc.pc_rel = 0;
4869 /* Modify str to point to after parsed operands, otherwise
4870 end_of_line() will complain about the (PLT) left in str. */
4871 str = input_line_pointer;
4872 }
4873 else
4874 {
4875 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4876 inst.reloc.pc_rel = 1;
4877 }
4878
4879 input_line_pointer = save_in;
4880 }
4881#else
4882 inst.reloc.type = BFD_RELOC_ARM_PCREL_BLX;
4883 inst.reloc.pc_rel = 1;
4884#endif /* OBJ_ELF */
4885
4886 end_of_line (str);
4887}
4888
4889/* ARM V5 branch-link-exchange instruction (argument parse)
4890 BLX <target_addr> ie BLX(1)
4891 BLX{<condition>} <Rm> ie BLX(2)
4892 Unfortunately, there are two different opcodes for this mnemonic.
4893 So, the insns[].value is not used, and the code here zaps values
4894 into inst.instruction.
4895 Also, the <target_addr> can be 25 bits, hence has its own reloc. */
4896
4897static void
a737bd4d 4898do_blx (char * str)
b99bd4ef
NC
4899{
4900 char * mystr = str;
4901 int rm;
4902
b99bd4ef
NC
4903 skip_whitespace (mystr);
4904 rm = reg_required_here (& mystr, 0);
4905
4906 /* The above may set inst.error. Ignore his opinion. */
4907 inst.error = 0;
4908
4909 if (rm != FAIL)
4910 {
4911 /* Arg is a register.
4912 Use the condition code our caller put in inst.instruction.
4913 Pass ourselves off as a BX with a funny opcode. */
4914 inst.instruction |= 0x012fff30;
f2b7cb0a 4915 do_bx (str);
b99bd4ef
NC
4916 }
4917 else
4918 {
4919 /* This must be is BLX <target address>, no condition allowed. */
4920 if (inst.instruction != COND_ALWAYS)
cc8a6dd0
KH
4921 {
4922 inst.error = BAD_COND;
b99bd4ef 4923 return;
cc8a6dd0 4924 }
b99bd4ef
NC
4925
4926 inst.instruction = 0xfafffffe;
4927
4928 /* Process like a B/BL, but with a different reloc.
4929 Note that B/BL expecte fffffe, not 0, offset in the opcode table. */
f2b7cb0a 4930 do_branch25 (str);
b99bd4ef
NC
4931 }
4932}
4933
4934/* ARM V5 Thumb BLX (argument parse)
4935 BLX <target_addr> which is BLX(1)
4936 BLX <Rm> which is BLX(2)
4937 Unfortunately, there are two different opcodes for this mnemonic.
4938 So, the tinsns[].value is not used, and the code here zaps values
4939 into inst.instruction. */
4940
4941static void
a737bd4d 4942do_t_blx (char * str)
b99bd4ef
NC
4943{
4944 char * mystr = str;
4945 int rm;
4946
4947 skip_whitespace (mystr);
4948 inst.instruction = 0x4780;
4949
4950 /* Note that this call is to the ARM register recognizer. BLX(2)
4951 uses the ARM register space, not the Thumb one, so a call to
4952 thumb_reg() would be wrong. */
4953 rm = reg_required_here (& mystr, 3);
4954 inst.error = 0;
4955
4956 if (rm != FAIL)
4957 {
4958 /* It's BLX(2). The .instruction was zapped with rm & is final. */
4959 inst.size = 2;
4960 }
4961 else
4962 {
4963 /* No ARM register. This must be BLX(1). Change the .instruction. */
4964 inst.instruction = 0xf7ffeffe;
4965 inst.size = 4;
4966
4967 if (my_get_expression (& inst.reloc.exp, & mystr))
4968 return;
4969
4970 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BLX;
4971 inst.reloc.pc_rel = 1;
4972 }
4973
4974 end_of_line (mystr);
4975}
4976
4977/* ARM V5 breakpoint instruction (argument parse)
4978 BKPT <16 bit unsigned immediate>
4979 Instruction is not conditional.
4980 The bit pattern given in insns[] has the COND_ALWAYS condition,
cc8a6dd0 4981 and it is an error if the caller tried to override that. */
b99bd4ef
NC
4982
4983static void
a737bd4d 4984do_bkpt (char * str)
b99bd4ef
NC
4985{
4986 expressionS expr;
4987 unsigned long number;
4988
4989 skip_whitespace (str);
4990
4991 /* Allow optional leading '#'. */
4992 if (is_immediate_prefix (* str))
4993 str++;
4994
4995 memset (& expr, '\0', sizeof (expr));
4996
143c8e19
NC
4997 if (my_get_expression (& expr, & str)
4998 || (expr.X_op != O_constant
4999 /* As a convenience we allow 'bkpt' without an operand. */
5000 && expr.X_op != O_absent))
b99bd4ef 5001 {
143c8e19 5002 inst.error = _("bad expression");
b99bd4ef
NC
5003 return;
5004 }
5005
5006 number = expr.X_add_number;
5007
5008 /* Check it fits a 16 bit unsigned. */
5009 if (number != (number & 0xffff))
5010 {
5011 inst.error = _("immediate value out of range");
5012 return;
5013 }
5014
5015 /* Top 12 of 16 bits to bits 19:8. */
5016 inst.instruction |= (number & 0xfff0) << 4;
5017
5018 /* Bottom 4 of 16 bits to bits 3:0. */
5019 inst.instruction |= number & 0xf;
5020
5021 end_of_line (str);
b99bd4ef
NC
5022}
5023
09d92015
MM
5024/* THUMB CPS instruction (argument parse). */
5025
5026static void
a737bd4d 5027do_t_cps (char * str)
09d92015
MM
5028{
5029 do_cps_flags (&str, /*thumb_p=*/1);
5030 end_of_line (str);
5031}
5032
a737bd4d
NC
5033/* Parse and validate that a register is of the right form, this saves
5034 repeated checking of this information in many similar cases.
5035 Unlike the 32-bit case we do not insert the register into the opcode
5036 here, since the position is often unknown until the full instruction
5037 has been parsed. */
5038
5039static int
5040thumb_reg (char ** strp, int hi_lo)
5041{
5042 int reg;
5043
5044 if ((reg = reg_required_here (strp, -1)) == FAIL)
5045 return FAIL;
5046
5047 switch (hi_lo)
5048 {
5049 case THUMB_REG_LO:
5050 if (reg > 7)
5051 {
5052 inst.error = _("lo register required");
5053 return FAIL;
5054 }
5055 break;
5056
5057 case THUMB_REG_HI:
5058 if (reg < 8)
5059 {
5060 inst.error = _("hi register required");
5061 return FAIL;
5062 }
5063 break;
5064
5065 default:
5066 break;
5067 }
5068
5069 return reg;
5070}
5071
5072static void
5073thumb_mov_compare (char * str, int move)
5074{
5075 int Rd, Rs = FAIL;
5076
5077 skip_whitespace (str);
5078
5079 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
5080 || skip_past_comma (&str) == FAIL)
5081 {
5082 if (! inst.error)
5083 inst.error = BAD_ARGS;
5084 return;
5085 }
5086
5087 if (move != THUMB_CPY && is_immediate_prefix (*str))
5088 {
5089 str++;
5090 if (my_get_expression (&inst.reloc.exp, &str))
5091 return;
5092 }
5093 else if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
5094 return;
5095
5096 if (Rs != FAIL)
5097 {
5098 if (move != THUMB_CPY && Rs < 8 && Rd < 8)
5099 {
5100 if (move == THUMB_MOVE)
5101 /* A move of two lowregs is encoded as ADD Rd, Rs, #0
5102 since a MOV instruction produces unpredictable results. */
5103 inst.instruction = T_OPCODE_ADD_I3;
5104 else
5105 inst.instruction = T_OPCODE_CMP_LR;
5106 inst.instruction |= Rd | (Rs << 3);
5107 }
5108 else
5109 {
5110 if (move == THUMB_MOVE)
5111 inst.instruction = T_OPCODE_MOV_HR;
5112 else if (move != THUMB_CPY)
5113 inst.instruction = T_OPCODE_CMP_HR;
5114
5115 if (Rd > 7)
5116 inst.instruction |= THUMB_H1;
5117
5118 if (Rs > 7)
5119 inst.instruction |= THUMB_H2;
5120
5121 inst.instruction |= (Rd & 7) | ((Rs & 7) << 3);
5122 }
5123 }
5124 else
5125 {
5126 if (Rd > 7)
5127 {
5128 inst.error = _("only lo regs allowed with immediate");
5129 return;
5130 }
5131
5132 if (move == THUMB_MOVE)
5133 inst.instruction = T_OPCODE_MOV_I8;
5134 else
5135 inst.instruction = T_OPCODE_CMP_I8;
5136
5137 inst.instruction |= Rd << 8;
5138
5139 if (inst.reloc.exp.X_op != O_constant)
5140 inst.reloc.type = BFD_RELOC_ARM_THUMB_IMM;
5141 else
5142 {
5143 unsigned value = inst.reloc.exp.X_add_number;
5144
5145 if (value > 255)
5146 {
5147 inst.error = _("invalid immediate");
5148 return;
5149 }
5150
5151 inst.instruction |= value;
5152 }
5153 }
5154
5155 end_of_line (str);
5156}
5157
09d92015
MM
5158/* THUMB CPY instruction (argument parse). */
5159
5160static void
a737bd4d 5161do_t_cpy (char * str)
09d92015
MM
5162{
5163 thumb_mov_compare (str, THUMB_CPY);
5164}
5165
5166/* THUMB SETEND instruction (argument parse). */
5167
5168static void
a737bd4d 5169do_t_setend (char * str)
09d92015
MM
5170{
5171 if (do_endian_specifier (str))
5172 inst.instruction |= 0x8;
5173}
5174
e16bb312
NC
5175/* Parse INSN_TYPE insn STR having a possible IMMEDIATE_SIZE immediate. */
5176
5177static unsigned long
a737bd4d
NC
5178check_iwmmxt_insn (char * str,
5179 enum iwmmxt_insn_type insn_type,
5180 int immediate_size)
e16bb312
NC
5181{
5182 int reg = 0;
5183 const char * inst_error;
5184 expressionS expr;
5185 unsigned long number;
5186
5187 inst_error = inst.error;
5188 if (!inst.error)
5189 inst.error = BAD_ARGS;
5190 skip_whitespace (str);
5191
5192 switch (insn_type)
5193 {
5194 case check_rd:
5195 if ((reg = reg_required_here (&str, 12)) == FAIL)
5196 return FAIL;
5197 break;
a737bd4d 5198
e16bb312
NC
5199 case check_wr:
5200 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR)) == FAIL)
5201 return FAIL;
5202 break;
a737bd4d 5203
e16bb312
NC
5204 case check_wrwr:
5205 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5206 || skip_past_comma (&str) == FAIL
5207 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
5208 return FAIL;
5209 break;
a737bd4d 5210
e16bb312
NC
5211 case check_wrwrwr:
5212 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5213 || skip_past_comma (&str) == FAIL
5214 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5215 || skip_past_comma (&str) == FAIL
5216 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
5217 return FAIL;
5218 break;
a737bd4d 5219
e16bb312
NC
5220 case check_wrwrwcg:
5221 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5222 || skip_past_comma (&str) == FAIL
5223 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5224 || skip_past_comma (&str) == FAIL
5225 || wreg_required_here (&str, 0, IWMMXT_REG_WCG) == FAIL))
5226 return FAIL;
5227 break;
a737bd4d 5228
e16bb312
NC
5229 case check_tbcst:
5230 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5231 || skip_past_comma (&str) == FAIL
5232 || reg_required_here (&str, 12) == FAIL))
5233 return FAIL;
5234 break;
a737bd4d 5235
e16bb312
NC
5236 case check_tmovmsk:
5237 if ((reg_required_here (&str, 12) == FAIL
5238 || skip_past_comma (&str) == FAIL
5239 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL))
5240 return FAIL;
5241 break;
a737bd4d 5242
e16bb312
NC
5243 case check_tmia:
5244 if ((wreg_required_here (&str, 5, IWMMXT_REG_WR) == FAIL
5245 || skip_past_comma (&str) == FAIL
5246 || reg_required_here (&str, 0) == FAIL
5247 || skip_past_comma (&str) == FAIL
5248 || reg_required_here (&str, 12) == FAIL))
5249 return FAIL;
5250 break;
a737bd4d 5251
e16bb312
NC
5252 case check_tmcrr:
5253 if ((wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
5254 || skip_past_comma (&str) == FAIL
5255 || reg_required_here (&str, 12) == FAIL
5256 || skip_past_comma (&str) == FAIL
5257 || reg_required_here (&str, 16) == FAIL))
5258 return FAIL;
5259 break;
a737bd4d 5260
e16bb312
NC
5261 case check_tmrrc:
5262 if ((reg_required_here (&str, 12) == FAIL
5263 || skip_past_comma (&str) == FAIL
5264 || reg_required_here (&str, 16) == FAIL
5265 || skip_past_comma (&str) == FAIL
5266 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL))
5267 return FAIL;
5268 break;
a737bd4d 5269
e16bb312
NC
5270 case check_tmcr:
5271 if ((wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL
5272 || skip_past_comma (&str) == FAIL
5273 || reg_required_here (&str, 12) == FAIL))
5274 return FAIL;
5275 break;
a737bd4d 5276
e16bb312
NC
5277 case check_tmrc:
5278 if ((reg_required_here (&str, 12) == FAIL
5279 || skip_past_comma (&str) == FAIL
5280 || wreg_required_here (&str, 16, IWMMXT_REG_WC) == FAIL))
5281 return FAIL;
5282 break;
a737bd4d 5283
e16bb312
NC
5284 case check_tinsr:
5285 if ((wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5286 || skip_past_comma (&str) == FAIL
5287 || reg_required_here (&str, 12) == FAIL
5288 || skip_past_comma (&str) == FAIL))
5289 return FAIL;
5290 break;
a737bd4d 5291
e16bb312
NC
5292 case check_textrc:
5293 if ((reg_required_here (&str, 12) == FAIL
5294 || skip_past_comma (&str) == FAIL))
5295 return FAIL;
5296 break;
a737bd4d 5297
e16bb312
NC
5298 case check_waligni:
5299 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5300 || skip_past_comma (&str) == FAIL
5301 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5302 || skip_past_comma (&str) == FAIL
5303 || wreg_required_here (&str, 0, IWMMXT_REG_WR) == FAIL
5304 || skip_past_comma (&str) == FAIL))
5305 return FAIL;
5306 break;
a737bd4d 5307
e16bb312
NC
5308 case check_textrm:
5309 if ((reg_required_here (&str, 12) == FAIL
5310 || skip_past_comma (&str) == FAIL
5311 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5312 || skip_past_comma (&str) == FAIL))
5313 return FAIL;
5314 break;
a737bd4d 5315
e16bb312
NC
5316 case check_wshufh:
5317 if ((wreg_required_here (&str, 12, IWMMXT_REG_WR) == FAIL
5318 || skip_past_comma (&str) == FAIL
5319 || wreg_required_here (&str, 16, IWMMXT_REG_WR) == FAIL
5320 || skip_past_comma (&str) == FAIL))
5321 return FAIL;
5322 break;
5323 }
a737bd4d 5324
e16bb312
NC
5325 if (immediate_size == 0)
5326 {
5327 end_of_line (str);
5328 inst.error = inst_error;
5329 return reg;
5330 }
5331 else
5332 {
a737bd4d
NC
5333 skip_whitespace (str);
5334
5335 /* Allow optional leading '#'. */
e16bb312
NC
5336 if (is_immediate_prefix (* str))
5337 str++;
5338
5339 memset (& expr, '\0', sizeof (expr));
a737bd4d 5340
e16bb312
NC
5341 if (my_get_expression (& expr, & str) || (expr.X_op != O_constant))
5342 {
5343 inst.error = _("bad or missing expression");
5344 return FAIL;
5345 }
a737bd4d 5346
e16bb312 5347 number = expr.X_add_number;
a737bd4d 5348
e16bb312
NC
5349 if (number != (number & immediate_size))
5350 {
5351 inst.error = _("immediate value out of range");
5352 return FAIL;
5353 }
5354 end_of_line (str);
5355 inst.error = inst_error;
5356 return number;
5357 }
5358}
5359
5360static void
a737bd4d 5361do_iwmmxt_byte_addr (char * str)
e16bb312
NC
5362{
5363 int op = (inst.instruction & 0x300) >> 8;
5364 int reg;
5365
5366 inst.instruction &= ~0x300;
a737bd4d 5367 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
e16bb312
NC
5368
5369 skip_whitespace (str);
5370
5371 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
5372 || skip_past_comma (& str) == FAIL
5373 || cp_byte_address_required_here (&str) == FAIL)
5374 {
5375 if (! inst.error)
5376 inst.error = BAD_ARGS;
5377 }
5378 else
5379 end_of_line (str);
5380
5381 if (wc_register (reg))
5382 {
ece01a63 5383 as_bad (_("non-word size not supported with control register"));
e16bb312
NC
5384 inst.instruction |= 0xf0000100;
5385 inst.instruction &= ~0x00400000;
5386 }
5387}
5388
5389static void
a737bd4d 5390do_iwmmxt_tandc (char * str)
e16bb312
NC
5391{
5392 int reg;
5393
5394 reg = check_iwmmxt_insn (str, check_rd, 0);
5395
5396 if (reg != REG_PC && !inst.error)
5397 inst.error = _("only r15 allowed here");
e16bb312
NC
5398}
5399
5400static void
a737bd4d 5401do_iwmmxt_tbcst (char * str)
e16bb312
NC
5402{
5403 check_iwmmxt_insn (str, check_tbcst, 0);
e16bb312
NC
5404}
5405
5406static void
a737bd4d 5407do_iwmmxt_textrc (char * str)
e16bb312
NC
5408{
5409 unsigned long number;
5410
5411 if ((number = check_iwmmxt_insn (str, check_textrc, 7)) == (unsigned long) FAIL)
5412 return;
5413
5414 inst.instruction |= number & 0x7;
e16bb312
NC
5415}
5416
5417static void
a737bd4d 5418do_iwmmxt_textrm (char * str)
e16bb312
NC
5419{
5420 unsigned long number;
5421
5422 if ((number = check_iwmmxt_insn (str, check_textrm, 7)) == (unsigned long) FAIL)
5423 return;
5424
5425 inst.instruction |= number & 0x7;
5426}
5427
5428static void
a737bd4d 5429do_iwmmxt_tinsr (char * str)
e16bb312
NC
5430{
5431 unsigned long number;
5432
5433 if ((number = check_iwmmxt_insn (str, check_tinsr, 7)) == (unsigned long) FAIL)
5434 return;
5435
5436 inst.instruction |= number & 0x7;
e16bb312
NC
5437}
5438
5439static void
a737bd4d 5440do_iwmmxt_tmcr (char * str)
e16bb312
NC
5441{
5442 check_iwmmxt_insn (str, check_tmcr, 0);
e16bb312
NC
5443}
5444
5445static void
a737bd4d 5446do_iwmmxt_tmcrr (char * str)
e16bb312
NC
5447{
5448 check_iwmmxt_insn (str, check_tmcrr, 0);
e16bb312
NC
5449}
5450
5451static void
a737bd4d 5452do_iwmmxt_tmia (char * str)
e16bb312
NC
5453{
5454 check_iwmmxt_insn (str, check_tmia, 0);
e16bb312
NC
5455}
5456
5457static void
a737bd4d 5458do_iwmmxt_tmovmsk (char * str)
e16bb312
NC
5459{
5460 check_iwmmxt_insn (str, check_tmovmsk, 0);
e16bb312
NC
5461}
5462
5463static void
a737bd4d 5464do_iwmmxt_tmrc (char * str)
e16bb312
NC
5465{
5466 check_iwmmxt_insn (str, check_tmrc, 0);
e16bb312
NC
5467}
5468
5469static void
a737bd4d 5470do_iwmmxt_tmrrc (char * str)
e16bb312
NC
5471{
5472 check_iwmmxt_insn (str, check_tmrrc, 0);
e16bb312
NC
5473}
5474
5475static void
a737bd4d 5476do_iwmmxt_torc (char * str)
e16bb312
NC
5477{
5478 check_iwmmxt_insn (str, check_rd, 0);
e16bb312
NC
5479}
5480
5481static void
a737bd4d 5482do_iwmmxt_waligni (char * str)
e16bb312
NC
5483{
5484 unsigned long number;
5485
5486 if ((number = check_iwmmxt_insn (str, check_waligni, 7)) == (unsigned long) FAIL)
5487 return;
5488
5489 inst.instruction |= ((number & 0x7) << 20);
e16bb312
NC
5490}
5491
5492static void
a737bd4d 5493do_iwmmxt_wmov (char * str)
e16bb312
NC
5494{
5495 if (check_iwmmxt_insn (str, check_wrwr, 0) == (unsigned long) FAIL)
5496 return;
a737bd4d 5497
e16bb312 5498 inst.instruction |= ((inst.instruction >> 16) & 0xf);
e16bb312
NC
5499}
5500
5501static void
a737bd4d 5502do_iwmmxt_word_addr (char * str)
e16bb312
NC
5503{
5504 int op = (inst.instruction & 0x300) >> 8;
5505 int reg;
5506
5507 inst.instruction &= ~0x300;
a737bd4d 5508 inst.instruction |= (op & 1) << 22 | (op & 2) << 7;
e16bb312
NC
5509
5510 skip_whitespace (str);
5511
5512 if ((reg = wreg_required_here (&str, 12, IWMMXT_REG_WR_OR_WC)) == FAIL
5513 || skip_past_comma (& str) == FAIL
5514 || cp_address_required_here (& str, CP_WB_OK) == FAIL)
5515 {
5516 if (! inst.error)
5517 inst.error = BAD_ARGS;
5518 }
5519 else
5520 end_of_line (str);
5521
5522 if (wc_register (reg))
5523 {
ece01a63
ILT
5524 if ((inst.instruction & COND_MASK) != COND_ALWAYS)
5525 as_bad (_("conditional execution not supported with control register"));
5526 if (op != 2)
5527 as_bad (_("non-word size not supported with control register"));
e16bb312
NC
5528 inst.instruction |= 0xf0000100;
5529 inst.instruction &= ~0x00400000;
5530 }
5531}
5532
5533static void
a737bd4d 5534do_iwmmxt_wrwr (char * str)
e16bb312
NC
5535{
5536 check_iwmmxt_insn (str, check_wrwr, 0);
e16bb312
NC
5537}
5538
5539static void
a737bd4d 5540do_iwmmxt_wrwrwcg (char * str)
e16bb312
NC
5541{
5542 check_iwmmxt_insn (str, check_wrwrwcg, 0);
e16bb312
NC
5543}
5544
5545static void
a737bd4d 5546do_iwmmxt_wrwrwr (char * str)
e16bb312
NC
5547{
5548 check_iwmmxt_insn (str, check_wrwrwr, 0);
e16bb312
NC
5549}
5550
5551static void
a737bd4d 5552do_iwmmxt_wshufh (char * str)
e16bb312
NC
5553{
5554 unsigned long number;
5555
5556 if ((number = check_iwmmxt_insn (str, check_wshufh, 0xff)) == (unsigned long) FAIL)
5557 return;
5558
5559 inst.instruction |= ((number & 0xf0) << 16) | (number & 0xf);
e16bb312
NC
5560}
5561
5562static void
a737bd4d 5563do_iwmmxt_wzero (char * str)
e16bb312
NC
5564{
5565 if (check_iwmmxt_insn (str, check_wr, 0) == (unsigned long) FAIL)
5566 return;
5567
5568 inst.instruction |= ((inst.instruction & 0xf) << 12) | ((inst.instruction & 0xf) << 16);
e16bb312
NC
5569}
5570
b99bd4ef
NC
5571/* Xscale multiply-accumulate (argument parse)
5572 MIAcc acc0,Rm,Rs
5573 MIAPHcc acc0,Rm,Rs
5574 MIAxycc acc0,Rm,Rs. */
5575
5576static void
a737bd4d 5577do_xsc_mia (char * str)
b99bd4ef
NC
5578{
5579 int rs;
5580 int rm;
5581
f2b7cb0a 5582 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5583 inst.error = ERR_NO_ACCUM;
5584
5585 else if (skip_past_comma (& str) == FAIL
5586 || (rm = reg_required_here (& str, 0)) == FAIL)
5587 inst.error = BAD_ARGS;
5588
5589 else if (skip_past_comma (& str) == FAIL
5590 || (rs = reg_required_here (& str, 12)) == FAIL)
5591 inst.error = BAD_ARGS;
5592
5593 /* inst.instruction has now been zapped with both rm and rs. */
5594 else if (rm == REG_PC || rs == REG_PC)
5595 inst.error = BAD_PC; /* Undefined result if rm or rs is R15. */
5596
5597 else
5598 end_of_line (str);
5599}
5600
5601/* Xscale move-accumulator-register (argument parse)
5602
5603 MARcc acc0,RdLo,RdHi. */
5604
5605static void
a737bd4d 5606do_xsc_mar (char * str)
b99bd4ef
NC
5607{
5608 int rdlo, rdhi;
5609
f2b7cb0a 5610 if (accum0_required_here (& str) == FAIL)
b99bd4ef
NC
5611 inst.error = ERR_NO_ACCUM;
5612
5613 else if (skip_past_comma (& str) == FAIL
5614 || (rdlo = reg_required_here (& str, 12)) == FAIL)
5615 inst.error = BAD_ARGS;
5616
5617 else if (skip_past_comma (& str) == FAIL
5618 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5619 inst.error = BAD_ARGS;
5620
5621 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5622 else if (rdlo == REG_PC || rdhi == REG_PC)
5623 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5624
5625 else
5626 end_of_line (str);
5627}
5628
5629/* Xscale move-register-accumulator (argument parse)
5630
5631 MRAcc RdLo,RdHi,acc0. */
5632
5633static void
a737bd4d 5634do_xsc_mra (char * str)
b99bd4ef
NC
5635{
5636 int rdlo;
5637 int rdhi;
5638
b99bd4ef
NC
5639 skip_whitespace (str);
5640
5641 if ((rdlo = reg_required_here (& str, 12)) == FAIL)
5642 inst.error = BAD_ARGS;
5643
5644 else if (skip_past_comma (& str) == FAIL
5645 || (rdhi = reg_required_here (& str, 16)) == FAIL)
5646 inst.error = BAD_ARGS;
5647
5648 else if (skip_past_comma (& str) == FAIL
5649 || accum0_required_here (& str) == FAIL)
5650 inst.error = ERR_NO_ACCUM;
5651
a737bd4d
NC
5652 /* inst.instruction has now been zapped with both rdlo and rdhi. */
5653 else if (rdlo == rdhi)
5654 inst.error = BAD_ARGS; /* Undefined result if 2 writes to same reg. */
5655
5656 else if (rdlo == REG_PC || rdhi == REG_PC)
5657 inst.error = BAD_PC; /* Undefined result if rdlo or rdhi is R15. */
5658 else
5659 end_of_line (str);
5660}
5661
5662static int
5663ldst_extend (char ** str)
5664{
5665 int add = INDEX_UP;
5666
5667 switch (**str)
5668 {
5669 case '#':
5670 case '$':
5671 (*str)++;
5672 if (my_get_expression (& inst.reloc.exp, str))
5673 return FAIL;
5674
5675 if (inst.reloc.exp.X_op == O_constant)
5676 {
5677 int value = inst.reloc.exp.X_add_number;
5678
5679 if (value < -4095 || value > 4095)
5680 {
5681 inst.error = _("address offset too large");
5682 return FAIL;
5683 }
5684
5685 if (value < 0)
5686 {
5687 value = -value;
5688 add = 0;
5689 }
5690
5691 inst.instruction |= add | value;
5692 }
5693 else
5694 {
5695 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
5696 inst.reloc.pc_rel = 0;
5697 }
5698 return SUCCESS;
5699
5700 case '-':
5701 add = 0;
5702 /* Fall through. */
5703
5704 case '+':
5705 (*str)++;
5706 /* Fall through. */
5707
5708 default:
5709 if (reg_required_here (str, 0) == FAIL)
5710 return FAIL;
5711
5712 inst.instruction |= add | OFFSET_REG;
5713 if (skip_past_comma (str) == SUCCESS)
5714 return decode_shift (str, SHIFT_IMMEDIATE);
b99bd4ef 5715
a737bd4d
NC
5716 return SUCCESS;
5717 }
b99bd4ef
NC
5718}
5719
c9b604bd 5720/* ARMv5TE: Preload-Cache
b99bd4ef
NC
5721
5722 PLD <addr_mode>
5723
5724 Syntactically, like LDR with B=1, W=0, L=1. */
5725
5726static void
a737bd4d 5727do_pld (char * str)
b99bd4ef
NC
5728{
5729 int rd;
5730
b99bd4ef
NC
5731 skip_whitespace (str);
5732
5733 if (* str != '[')
5734 {
5735 inst.error = _("'[' expected after PLD mnemonic");
5736 return;
5737 }
5738
90e4755a 5739 ++str;
b99bd4ef
NC
5740 skip_whitespace (str);
5741
5742 if ((rd = reg_required_here (& str, 16)) == FAIL)
5743 return;
5744
5745 skip_whitespace (str);
5746
90e4755a 5747 if (*str == ']')
b99bd4ef
NC
5748 {
5749 /* [Rn], ... ? */
90e4755a 5750 ++str;
b99bd4ef
NC
5751 skip_whitespace (str);
5752
90e4755a
RE
5753 /* Post-indexed addressing is not allowed with PLD. */
5754 if (skip_past_comma (&str) == SUCCESS)
b99bd4ef 5755 {
90e4755a
RE
5756 inst.error
5757 = _("post-indexed expression used in preload instruction");
5758 return;
b99bd4ef 5759 }
90e4755a 5760 else if (*str == '!') /* [Rn]! */
b99bd4ef
NC
5761 {
5762 inst.error = _("writeback used in preload instruction");
90e4755a 5763 ++str;
b99bd4ef
NC
5764 }
5765 else /* [Rn] */
5766 inst.instruction |= INDEX_UP | PRE_INDEX;
5767 }
5768 else /* [Rn, ...] */
5769 {
5770 if (skip_past_comma (& str) == FAIL)
5771 {
5772 inst.error = _("pre-indexed expression expected");
5773 return;
5774 }
5775
90e4755a 5776 if (ldst_extend (&str) == FAIL)
b99bd4ef
NC
5777 return;
5778
5779 skip_whitespace (str);
5780
5781 if (* str != ']')
5782 {
5783 inst.error = _("missing ]");
5784 return;
5785 }
5786
5787 ++ str;
5788 skip_whitespace (str);
5789
5790 if (* str == '!') /* [Rn]! */
5791 {
5792 inst.error = _("writeback used in preload instruction");
5793 ++ str;
5794 }
5795
5796 inst.instruction |= PRE_INDEX;
5797 }
5798
5799 end_of_line (str);
5800}
5801
c9b604bd 5802/* ARMv5TE load-consecutive (argument parse)
b99bd4ef
NC
5803 Mode is like LDRH.
5804
5805 LDRccD R, mode
5806 STRccD R, mode. */
5807
5808static void
a737bd4d 5809do_ldrd (char * str)
b99bd4ef
NC
5810{
5811 int rd;
5812 int rn;
5813
b99bd4ef
NC
5814 skip_whitespace (str);
5815
5816 if ((rd = reg_required_here (& str, 12)) == FAIL)
5817 {
5818 inst.error = BAD_ARGS;
5819 return;
5820 }
5821
5822 if (skip_past_comma (& str) == FAIL
5823 || (rn = ld_mode_required_here (& str)) == FAIL)
5824 {
5825 if (!inst.error)
cc8a6dd0 5826 inst.error = BAD_ARGS;
a737bd4d 5827 return;
b99bd4ef
NC
5828 }
5829
a737bd4d
NC
5830 /* inst.instruction has now been zapped with Rd and the addressing mode. */
5831 if (rd & 1) /* Unpredictable result if Rd is odd. */
5832 {
5833 inst.error = _("destination register must be even");
5834 return;
5835 }
b99bd4ef 5836
a737bd4d 5837 if (rd == REG_LR)
b99bd4ef 5838 {
a737bd4d
NC
5839 inst.error = _("r14 not allowed here");
5840 return;
b99bd4ef 5841 }
a737bd4d
NC
5842
5843 if (((rd == rn) || (rd + 1 == rn))
5844 && ((inst.instruction & WRITE_BACK)
5845 || (!(inst.instruction & PRE_INDEX))))
5846 as_warn (_("pre/post-indexing used when modified address register is destination"));
5847
5848 /* For an index-register load, the index register must not overlap the
5849 destination (even if not write-back). */
5850 if ((inst.instruction & V4_STR_BIT) == 0
5851 && (inst.instruction & HWOFFSET_IMM) == 0)
b99bd4ef 5852 {
a737bd4d
NC
5853 int rm = inst.instruction & 0x0000000f;
5854
5855 if (rm == rd || (rm == rd + 1))
5856 as_warn (_("ldrd destination registers must not overlap index register"));
b99bd4ef
NC
5857 }
5858
a737bd4d
NC
5859 end_of_line (str);
5860}
b99bd4ef 5861
a737bd4d
NC
5862/* Returns the index into fp_values of a floating point number,
5863 or -1 if not in the table. */
b99bd4ef 5864
a737bd4d
NC
5865static int
5866my_get_float_expression (char ** str)
5867{
5868 LITTLENUM_TYPE words[MAX_LITTLENUMS];
5869 char * save_in;
5870 expressionS exp;
5871 int i;
5872 int j;
b99bd4ef 5873
a737bd4d
NC
5874 memset (words, 0, MAX_LITTLENUMS * sizeof (LITTLENUM_TYPE));
5875
5876 /* Look for a raw floating point number. */
5877 if ((save_in = atof_ieee (*str, 'x', words)) != NULL
5878 && is_end_of_line[(unsigned char) *save_in])
5879 {
5880 for (i = 0; i < NUM_FLOAT_VALS; i++)
b99bd4ef 5881 {
a737bd4d 5882 for (j = 0; j < MAX_LITTLENUMS; j++)
b99bd4ef 5883 {
a737bd4d
NC
5884 if (words[j] != fp_values[i][j])
5885 break;
b99bd4ef 5886 }
a737bd4d
NC
5887
5888 if (j == MAX_LITTLENUMS)
b99bd4ef 5889 {
a737bd4d
NC
5890 *str = save_in;
5891 return i;
b99bd4ef
NC
5892 }
5893 }
a737bd4d 5894 }
b99bd4ef 5895
a737bd4d
NC
5896 /* Try and parse a more complex expression, this will probably fail
5897 unless the code uses a floating point prefix (eg "0f"). */
5898 save_in = input_line_pointer;
5899 input_line_pointer = *str;
5900 if (expression (&exp) == absolute_section
5901 && exp.X_op == O_big
5902 && exp.X_add_number < 0)
5903 {
5904 /* FIXME: 5 = X_PRECISION, should be #define'd where we can use it.
5905 Ditto for 15. */
5906 if (gen_to_words (words, 5, (long) 15) == 0)
5907 {
5908 for (i = 0; i < NUM_FLOAT_VALS; i++)
5909 {
5910 for (j = 0; j < MAX_LITTLENUMS; j++)
5911 {
5912 if (words[j] != fp_values[i][j])
5913 break;
5914 }
b99bd4ef 5915
a737bd4d
NC
5916 if (j == MAX_LITTLENUMS)
5917 {
5918 *str = input_line_pointer;
5919 input_line_pointer = save_in;
5920 return i;
5921 }
5922 }
5923 }
b99bd4ef 5924 }
a737bd4d
NC
5925
5926 *str = input_line_pointer;
5927 input_line_pointer = save_in;
5928 return -1;
5929}
5930
5931/* We handle all bad expressions here, so that we can report the faulty
5932 instruction in the error message. */
5933void
5934md_operand (expressionS * expr)
5935{
5936 if (in_my_get_expression)
b99bd4ef 5937 {
a737bd4d
NC
5938 expr->X_op = O_illegal;
5939 if (inst.error == NULL)
5940 inst.error = _("bad expression");
b99bd4ef 5941 }
b99bd4ef
NC
5942}
5943
5944/* Do those data_ops which can take a negative immediate constant
2d2255b5 5945 by altering the instruction. A bit of a hack really.
b99bd4ef
NC
5946 MOV <-> MVN
5947 AND <-> BIC
5948 ADC <-> SBC
5949 by inverting the second operand, and
5950 ADD <-> SUB
5951 CMP <-> CMN
5952 by negating the second operand. */
5953
5954static int
a737bd4d
NC
5955negate_data_op (unsigned long * instruction,
5956 unsigned long value)
b99bd4ef
NC
5957{
5958 int op, new_inst;
5959 unsigned long negated, inverted;
5960
5961 negated = validate_immediate (-value);
5962 inverted = validate_immediate (~value);
5963
5964 op = (*instruction >> DATA_OP_SHIFT) & 0xf;
5965 switch (op)
5966 {
5967 /* First negates. */
5968 case OPCODE_SUB: /* ADD <-> SUB */
5969 new_inst = OPCODE_ADD;
5970 value = negated;
5971 break;
5972
5973 case OPCODE_ADD:
5974 new_inst = OPCODE_SUB;
5975 value = negated;
5976 break;
5977
5978 case OPCODE_CMP: /* CMP <-> CMN */
5979 new_inst = OPCODE_CMN;
5980 value = negated;
5981 break;
5982
5983 case OPCODE_CMN:
5984 new_inst = OPCODE_CMP;
5985 value = negated;
5986 break;
5987
5988 /* Now Inverted ops. */
5989 case OPCODE_MOV: /* MOV <-> MVN */
5990 new_inst = OPCODE_MVN;
5991 value = inverted;
5992 break;
5993
5994 case OPCODE_MVN:
5995 new_inst = OPCODE_MOV;
5996 value = inverted;
5997 break;
5998
5999 case OPCODE_AND: /* AND <-> BIC */
6000 new_inst = OPCODE_BIC;
6001 value = inverted;
6002 break;
6003
6004 case OPCODE_BIC:
6005 new_inst = OPCODE_AND;
6006 value = inverted;
6007 break;
6008
6009 case OPCODE_ADC: /* ADC <-> SBC */
6010 new_inst = OPCODE_SBC;
6011 value = inverted;
6012 break;
6013
6014 case OPCODE_SBC:
6015 new_inst = OPCODE_ADC;
6016 value = inverted;
6017 break;
6018
6019 /* We cannot do anything. */
6020 default:
6021 return FAIL;
6022 }
6023
6024 if (value == (unsigned) FAIL)
6025 return FAIL;
6026
6027 *instruction &= OPCODE_MASK;
6028 *instruction |= new_inst << DATA_OP_SHIFT;
6029 return value;
6030}
6031
6032static int
a737bd4d 6033data_op2 (char ** str)
b99bd4ef
NC
6034{
6035 int value;
6036 expressionS expr;
6037
6038 skip_whitespace (* str);
6039
6040 if (reg_required_here (str, 0) != FAIL)
6041 {
6042 if (skip_past_comma (str) == SUCCESS)
6043 /* Shift operation on register. */
6044 return decode_shift (str, NO_SHIFT_RESTRICT);
6045
6046 return SUCCESS;
6047 }
6048 else
6049 {
6050 /* Immediate expression. */
6051 if (is_immediate_prefix (**str))
6052 {
6053 (*str)++;
6054 inst.error = NULL;
6055
6056 if (my_get_expression (&inst.reloc.exp, str))
6057 return FAIL;
6058
6059 if (inst.reloc.exp.X_add_symbol)
6060 {
6061 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
6062 inst.reloc.pc_rel = 0;
6063 }
6064 else
6065 {
6066 if (skip_past_comma (str) == SUCCESS)
6067 {
6068 /* #x, y -- ie explicit rotation by Y. */
6069 if (my_get_expression (&expr, str))
6070 return FAIL;
6071
6072 if (expr.X_op != O_constant)
6073 {
f03698e6 6074 inst.error = _("constant expression expected");
b99bd4ef
NC
6075 return FAIL;
6076 }
6077
6078 /* Rotate must be a multiple of 2. */
6079 if (((unsigned) expr.X_add_number) > 30
6080 || (expr.X_add_number & 1) != 0
6081 || ((unsigned) inst.reloc.exp.X_add_number) > 255)
6082 {
f03698e6 6083 inst.error = _("invalid constant");
b99bd4ef
NC
6084 return FAIL;
6085 }
6086 inst.instruction |= INST_IMMEDIATE;
6087 inst.instruction |= inst.reloc.exp.X_add_number;
6088 inst.instruction |= expr.X_add_number << 7;
6089 return SUCCESS;
6090 }
6091
6092 /* Implicit rotation, select a suitable one. */
6093 value = validate_immediate (inst.reloc.exp.X_add_number);
6094
6095 if (value == FAIL)
6096 {
6097 /* Can't be done. Perhaps the code reads something like
6098 "add Rd, Rn, #-n", where "sub Rd, Rn, #n" would be OK. */
6099 if ((value = negate_data_op (&inst.instruction,
6100 inst.reloc.exp.X_add_number))
6101 == FAIL)
6102 {
f03698e6 6103 inst.error = _("invalid constant");
b99bd4ef
NC
6104 return FAIL;
6105 }
6106 }
6107
6108 inst.instruction |= value;
6109 }
6110
6111 inst.instruction |= INST_IMMEDIATE;
6112 return SUCCESS;
6113 }
6114
6115 (*str)++;
f03698e6 6116 inst.error = _("register or shift expression expected");
b99bd4ef
NC
6117 return FAIL;
6118 }
6119}
6120
6121static int
a737bd4d 6122fp_op2 (char ** str)
b99bd4ef
NC
6123{
6124 skip_whitespace (* str);
6125
6126 if (fp_reg_required_here (str, 0) != FAIL)
6127 return SUCCESS;
6128 else
6129 {
6130 /* Immediate expression. */
6131 if (*((*str)++) == '#')
6132 {
6133 int i;
6134
6135 inst.error = NULL;
6136
6137 skip_whitespace (* str);
6138
6139 /* First try and match exact strings, this is to guarantee
6140 that some formats will work even for cross assembly. */
6141
6142 for (i = 0; fp_const[i]; i++)
6143 {
6144 if (strncmp (*str, fp_const[i], strlen (fp_const[i])) == 0)
6145 {
6146 char *start = *str;
6147
6148 *str += strlen (fp_const[i]);
6149 if (is_end_of_line[(unsigned char) **str])
6150 {
6151 inst.instruction |= i + 8;
6152 return SUCCESS;
6153 }
6154 *str = start;
6155 }
6156 }
6157
6158 /* Just because we didn't get a match doesn't mean that the
6159 constant isn't valid, just that it is in a format that we
6160 don't automatically recognize. Try parsing it with
6161 the standard expression routines. */
6162 if ((i = my_get_float_expression (str)) >= 0)
6163 {
6164 inst.instruction |= i + 8;
6165 return SUCCESS;
6166 }
6167
f03698e6 6168 inst.error = _("invalid floating point immediate expression");
b99bd4ef
NC
6169 return FAIL;
6170 }
6171 inst.error =
f03698e6 6172 _("floating point register or immediate expression expected");
b99bd4ef
NC
6173 return FAIL;
6174 }
6175}
6176
6177static void
a737bd4d 6178do_arit (char * str)
b99bd4ef
NC
6179{
6180 skip_whitespace (str);
6181
6182 if (reg_required_here (&str, 12) == FAIL
6183 || skip_past_comma (&str) == FAIL
6184 || reg_required_here (&str, 16) == FAIL
6185 || skip_past_comma (&str) == FAIL
6186 || data_op2 (&str) == FAIL)
6187 {
6188 if (!inst.error)
6189 inst.error = BAD_ARGS;
6190 return;
6191 }
6192
b99bd4ef 6193 end_of_line (str);
b99bd4ef
NC
6194}
6195
6196static void
a737bd4d 6197do_adr (char * str)
b99bd4ef 6198{
90e4755a
RE
6199 /* This is a pseudo-op of the form "adr rd, label" to be converted
6200 into a relative address of the form "add rd, pc, #label-.-8". */
6201 skip_whitespace (str);
6202
6203 if (reg_required_here (&str, 12) == FAIL
6204 || skip_past_comma (&str) == FAIL
6205 || my_get_expression (&inst.reloc.exp, &str))
6206 {
6207 if (!inst.error)
6208 inst.error = BAD_ARGS;
6209 return;
6210 }
6211
6212 /* Frag hacking will turn this into a sub instruction if the offset turns
6213 out to be negative. */
6214 inst.reloc.type = BFD_RELOC_ARM_IMMEDIATE;
250355db 6215#ifndef TE_WINCE
90e4755a 6216 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust. */
250355db 6217#endif
90e4755a
RE
6218 inst.reloc.pc_rel = 1;
6219
6220 end_of_line (str);
6221}
6222
6223static void
a737bd4d 6224do_adrl (char * str)
90e4755a
RE
6225{
6226 /* This is a pseudo-op of the form "adrl rd, label" to be converted
6227 into a relative address of the form:
6228 add rd, pc, #low(label-.-8)"
6229 add rd, rd, #high(label-.-8)" */
6230
6231 skip_whitespace (str);
6232
6233 if (reg_required_here (&str, 12) == FAIL
6234 || skip_past_comma (&str) == FAIL
6235 || my_get_expression (&inst.reloc.exp, &str))
6236 {
6237 if (!inst.error)
6238 inst.error = BAD_ARGS;
6239
6240 return;
6241 }
6242
6243 end_of_line (str);
6244 /* Frag hacking will turn this into a sub instruction if the offset turns
6245 out to be negative. */
6246 inst.reloc.type = BFD_RELOC_ARM_ADRL_IMMEDIATE;
a737bd4d 6247#ifndef TE_WINCE
90e4755a 6248 inst.reloc.exp.X_add_number -= 8; /* PC relative adjust */
250355db 6249#endif
90e4755a
RE
6250 inst.reloc.pc_rel = 1;
6251 inst.size = INSN_SIZE * 2;
90e4755a
RE
6252}
6253
6254static void
a737bd4d 6255do_cmp (char * str)
90e4755a
RE
6256{
6257 skip_whitespace (str);
6258
6259 if (reg_required_here (&str, 16) == FAIL)
6260 {
6261 if (!inst.error)
6262 inst.error = BAD_ARGS;
6263 return;
6264 }
6265
6266 if (skip_past_comma (&str) == FAIL
6267 || data_op2 (&str) == FAIL)
6268 {
6269 if (!inst.error)
6270 inst.error = BAD_ARGS;
6271 return;
6272 }
6273
90e4755a 6274 end_of_line (str);
90e4755a
RE
6275}
6276
6277static void
a737bd4d 6278do_mov (char * str)
90e4755a
RE
6279{
6280 skip_whitespace (str);
6281
6282 if (reg_required_here (&str, 12) == FAIL)
6283 {
6284 if (!inst.error)
6285 inst.error = BAD_ARGS;
6286 return;
6287 }
6288
6289 if (skip_past_comma (&str) == FAIL
6290 || data_op2 (&str) == FAIL)
6291 {
6292 if (!inst.error)
6293 inst.error = BAD_ARGS;
6294 return;
6295 }
6296
90e4755a 6297 end_of_line (str);
90e4755a
RE
6298}
6299
90e4755a 6300static void
a737bd4d 6301do_ldst (char * str)
90e4755a
RE
6302{
6303 int pre_inc = 0;
6304 int conflict_reg;
6305 int value;
6306
b99bd4ef
NC
6307 skip_whitespace (str);
6308
90e4755a
RE
6309 if ((conflict_reg = reg_required_here (&str, 12)) == FAIL)
6310 {
6311 if (!inst.error)
6312 inst.error = BAD_ARGS;
6313 return;
6314 }
6315
6316 if (skip_past_comma (&str) == FAIL)
6317 {
f03698e6 6318 inst.error = _("address expected");
90e4755a
RE
6319 return;
6320 }
6321
90e4755a
RE
6322 if (*str == '[')
6323 {
6324 int reg;
6325
6326 str++;
6327
6328 skip_whitespace (str);
6329
6330 if ((reg = reg_required_here (&str, 16)) == FAIL)
6331 return;
6332
6333 /* Conflicts can occur on stores as well as loads. */
6334 conflict_reg = (conflict_reg == reg);
6335
6336 skip_whitespace (str);
6337
6338 if (*str == ']')
6339 {
6340 str ++;
6341
6342 if (skip_past_comma (&str) == SUCCESS)
6343 {
6344 /* [Rn],... (post inc) */
6345 if (ldst_extend (&str) == FAIL)
6346 return;
6347 if (conflict_reg)
6348 as_warn (_("%s register same as write-back base"),
6349 ((inst.instruction & LOAD_BIT)
6350 ? _("destination") : _("source")));
6351 }
6352 else
6353 {
6354 /* [Rn] */
6355 skip_whitespace (str);
6356
6357 if (*str == '!')
6358 {
6359 if (conflict_reg)
6360 as_warn (_("%s register same as write-back base"),
6361 ((inst.instruction & LOAD_BIT)
6362 ? _("destination") : _("source")));
6363 str++;
6364 inst.instruction |= WRITE_BACK;
6365 }
6366
6367 inst.instruction |= INDEX_UP;
6368 pre_inc = 1;
6369 }
6370 }
6371 else
6372 {
6373 /* [Rn,...] */
6374 if (skip_past_comma (&str) == FAIL)
6375 {
6376 inst.error = _("pre-indexed expression expected");
6377 return;
6378 }
6379
6380 pre_inc = 1;
6381 if (ldst_extend (&str) == FAIL)
6382 return;
6383
6384 skip_whitespace (str);
6385
6386 if (*str++ != ']')
6387 {
6388 inst.error = _("missing ]");
6389 return;
6390 }
6391
6392 skip_whitespace (str);
6393
6394 if (*str == '!')
6395 {
6396 if (conflict_reg)
6397 as_warn (_("%s register same as write-back base"),
6398 ((inst.instruction & LOAD_BIT)
6399 ? _("destination") : _("source")));
6400 str++;
6401 inst.instruction |= WRITE_BACK;
6402 }
6403 }
6404 }
6405 else if (*str == '=')
6406 {
f03698e6
RE
6407 if ((inst.instruction & LOAD_BIT) == 0)
6408 {
6409 inst.error = _("invalid pseudo operation");
6410 return;
6411 }
6412
90e4755a
RE
6413 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6414 str++;
6415
6416 skip_whitespace (str);
6417
6418 if (my_get_expression (&inst.reloc.exp, &str))
6419 return;
6420
6421 if (inst.reloc.exp.X_op != O_constant
6422 && inst.reloc.exp.X_op != O_symbol)
6423 {
f03698e6 6424 inst.error = _("constant expression expected");
90e4755a
RE
6425 return;
6426 }
6427
e28cd48c 6428 if (inst.reloc.exp.X_op == O_constant)
90e4755a 6429 {
e28cd48c
RE
6430 value = validate_immediate (inst.reloc.exp.X_add_number);
6431
6432 if (value != FAIL)
90e4755a 6433 {
e28cd48c
RE
6434 /* This can be done with a mov instruction. */
6435 inst.instruction &= LITERAL_MASK;
6436 inst.instruction |= (INST_IMMEDIATE
6437 | (OPCODE_MOV << DATA_OP_SHIFT));
6438 inst.instruction |= value & 0xfff;
6439 end_of_line (str);
90e4755a
RE
6440 return;
6441 }
b99bd4ef 6442
e28cd48c
RE
6443 value = validate_immediate (~inst.reloc.exp.X_add_number);
6444
6445 if (value != FAIL)
6446 {
6447 /* This can be done with a mvn instruction. */
6448 inst.instruction &= LITERAL_MASK;
6449 inst.instruction |= (INST_IMMEDIATE
6450 | (OPCODE_MVN << DATA_OP_SHIFT));
6451 inst.instruction |= value & 0xfff;
6452 end_of_line (str);
6453 return;
6454 }
90e4755a 6455 }
e28cd48c
RE
6456
6457 /* Insert into literal pool. */
6458 if (add_to_lit_pool () == FAIL)
6459 {
6460 if (!inst.error)
6461 inst.error = _("literal pool insertion failed");
6462 return;
6463 }
6464
6465 /* Change the instruction exp to point to the pool. */
6466 inst.reloc.type = BFD_RELOC_ARM_LITERAL;
6467 inst.reloc.pc_rel = 1;
6468 inst.instruction |= (REG_PC << 16);
6469 pre_inc = 1;
1cac9012
NC
6470 }
6471 else
6472 {
90e4755a
RE
6473 if (my_get_expression (&inst.reloc.exp, &str))
6474 return;
6475
6476 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM;
6477#ifndef TE_WINCE
6478 /* PC rel adjust. */
6479 inst.reloc.exp.X_add_number -= 8;
6480#endif
1cac9012 6481 inst.reloc.pc_rel = 1;
90e4755a
RE
6482 inst.instruction |= (REG_PC << 16);
6483 pre_inc = 1;
b99bd4ef
NC
6484 }
6485
90e4755a 6486 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef 6487 end_of_line (str);
b99bd4ef
NC
6488}
6489
6490static void
a737bd4d 6491do_ldstt (char * str)
b99bd4ef 6492{
90e4755a
RE
6493 int conflict_reg;
6494
b99bd4ef
NC
6495 skip_whitespace (str);
6496
90e4755a 6497 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
b99bd4ef
NC
6498 {
6499 if (!inst.error)
6500 inst.error = BAD_ARGS;
6501 return;
6502 }
6503
90e4755a 6504 if (skip_past_comma (& str) == FAIL)
b99bd4ef 6505 {
f03698e6 6506 inst.error = _("address expected");
b99bd4ef
NC
6507 return;
6508 }
6509
90e4755a
RE
6510 if (*str == '[')
6511 {
6512 int reg;
b99bd4ef 6513
90e4755a 6514 str++;
b99bd4ef 6515
90e4755a 6516 skip_whitespace (str);
b99bd4ef 6517
90e4755a
RE
6518 if ((reg = reg_required_here (&str, 16)) == FAIL)
6519 return;
b99bd4ef 6520
90e4755a
RE
6521 /* ldrt/strt always use post-indexed addressing, so if the base is
6522 the same as Rd, we warn. */
6523 if (conflict_reg == reg)
6524 as_warn (_("%s register same as write-back base"),
6525 ((inst.instruction & LOAD_BIT)
6526 ? _("destination") : _("source")));
6527
6528 skip_whitespace (str);
6529
6530 if (*str == ']')
6531 {
6532 str ++;
6533
6534 if (skip_past_comma (&str) == SUCCESS)
6535 {
6536 /* [Rn],... (post inc) */
6537 if (ldst_extend (&str) == FAIL)
6538 return;
6539 }
6540 else
6541 {
6542 /* [Rn] */
6543 skip_whitespace (str);
6544
6545 /* Skip a write-back '!'. */
6546 if (*str == '!')
6547 str++;
6548
6549 inst.instruction |= INDEX_UP;
6550 }
6551 }
6552 else
6553 {
6554 inst.error = _("post-indexed expression expected");
6555 return;
6556 }
6557 }
6558 else
b99bd4ef 6559 {
90e4755a 6560 inst.error = _("post-indexed expression expected");
b99bd4ef
NC
6561 return;
6562 }
6563
b99bd4ef 6564 end_of_line (str);
b99bd4ef
NC
6565}
6566
90e4755a 6567/* Halfword and signed-byte load/store operations. */
a737bd4d 6568
b99bd4ef 6569static void
a737bd4d 6570do_ldstv4 (char * str)
b99bd4ef 6571{
b99bd4ef
NC
6572 int pre_inc = 0;
6573 int conflict_reg;
6574 int value;
6575
b99bd4ef
NC
6576 skip_whitespace (str);
6577
6578 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
6579 {
6580 if (!inst.error)
6581 inst.error = BAD_ARGS;
6582 return;
6583 }
6584
6585 if (skip_past_comma (& str) == FAIL)
6586 {
f03698e6 6587 inst.error = _("address expected");
b99bd4ef
NC
6588 return;
6589 }
6590
6591 if (*str == '[')
6592 {
6593 int reg;
6594
6595 str++;
6596
6597 skip_whitespace (str);
6598
6599 if ((reg = reg_required_here (&str, 16)) == FAIL)
6600 return;
6601
6602 /* Conflicts can occur on stores as well as loads. */
6603 conflict_reg = (conflict_reg == reg);
6604
6605 skip_whitespace (str);
6606
6607 if (*str == ']')
6608 {
6609 str ++;
6610
6611 if (skip_past_comma (&str) == SUCCESS)
6612 {
6613 /* [Rn],... (post inc) */
90e4755a 6614 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6615 return;
6616 if (conflict_reg)
90e4755a
RE
6617 as_warn (_("%s register same as write-back base"),
6618 ((inst.instruction & LOAD_BIT)
6619 ? _("destination") : _("source")));
b99bd4ef
NC
6620 }
6621 else
6622 {
6623 /* [Rn] */
90e4755a 6624 inst.instruction |= HWOFFSET_IMM;
b99bd4ef
NC
6625
6626 skip_whitespace (str);
6627
6628 if (*str == '!')
6629 {
6630 if (conflict_reg)
6631 as_warn (_("%s register same as write-back base"),
6632 ((inst.instruction & LOAD_BIT)
6633 ? _("destination") : _("source")));
6634 str++;
6635 inst.instruction |= WRITE_BACK;
6636 }
6637
90e4755a
RE
6638 inst.instruction |= INDEX_UP;
6639 pre_inc = 1;
b99bd4ef
NC
6640 }
6641 }
6642 else
6643 {
6644 /* [Rn,...] */
6645 if (skip_past_comma (&str) == FAIL)
6646 {
6647 inst.error = _("pre-indexed expression expected");
6648 return;
6649 }
6650
6651 pre_inc = 1;
90e4755a 6652 if (ldst_extend_v4 (&str) == FAIL)
b99bd4ef
NC
6653 return;
6654
6655 skip_whitespace (str);
6656
6657 if (*str++ != ']')
6658 {
6659 inst.error = _("missing ]");
6660 return;
6661 }
6662
6663 skip_whitespace (str);
6664
6665 if (*str == '!')
6666 {
6667 if (conflict_reg)
6668 as_warn (_("%s register same as write-back base"),
6669 ((inst.instruction & LOAD_BIT)
6670 ? _("destination") : _("source")));
6671 str++;
6672 inst.instruction |= WRITE_BACK;
6673 }
6674 }
6675 }
6676 else if (*str == '=')
6677 {
f03698e6
RE
6678 if ((inst.instruction & LOAD_BIT) == 0)
6679 {
6680 inst.error = _("invalid pseudo operation");
6681 return;
6682 }
6683
90e4755a 6684 /* XXX Does this work correctly for half-word/byte ops? */
b99bd4ef
NC
6685 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
6686 str++;
6687
6688 skip_whitespace (str);
6689
6690 if (my_get_expression (&inst.reloc.exp, &str))
6691 return;
6692
6693 if (inst.reloc.exp.X_op != O_constant
6694 && inst.reloc.exp.X_op != O_symbol)
6695 {
f03698e6 6696 inst.error = _("constant expression expected");
b99bd4ef
NC
6697 return;
6698 }
6699
d8273442 6700 if (inst.reloc.exp.X_op == O_constant)
b99bd4ef 6701 {
d8273442
NC
6702 value = validate_immediate (inst.reloc.exp.X_add_number);
6703
6704 if (value != FAIL)
b99bd4ef 6705 {
d8273442
NC
6706 /* This can be done with a mov instruction. */
6707 inst.instruction &= LITERAL_MASK;
6708 inst.instruction |= INST_IMMEDIATE | (OPCODE_MOV << DATA_OP_SHIFT);
90e4755a 6709 inst.instruction |= value & 0xfff;
d8273442 6710 end_of_line (str);
b99bd4ef
NC
6711 return;
6712 }
cc8a6dd0 6713
d8273442 6714 value = validate_immediate (~ inst.reloc.exp.X_add_number);
b99bd4ef 6715
d8273442 6716 if (value != FAIL)
b99bd4ef 6717 {
d8273442
NC
6718 /* This can be done with a mvn instruction. */
6719 inst.instruction &= LITERAL_MASK;
6720 inst.instruction |= INST_IMMEDIATE | (OPCODE_MVN << DATA_OP_SHIFT);
90e4755a 6721 inst.instruction |= value & 0xfff;
d8273442
NC
6722 end_of_line (str);
6723 return;
b99bd4ef 6724 }
b99bd4ef 6725 }
d8273442
NC
6726
6727 /* Insert into literal pool. */
6728 if (add_to_lit_pool () == FAIL)
6729 {
6730 if (!inst.error)
6731 inst.error = _("literal pool insertion failed");
6732 return;
6733 }
6734
6735 /* Change the instruction exp to point to the pool. */
90e4755a
RE
6736 inst.instruction |= HWOFFSET_IMM;
6737 inst.reloc.type = BFD_RELOC_ARM_HWLITERAL;
d8273442
NC
6738 inst.reloc.pc_rel = 1;
6739 inst.instruction |= (REG_PC << 16);
6740 pre_inc = 1;
b99bd4ef
NC
6741 }
6742 else
6743 {
6744 if (my_get_expression (&inst.reloc.exp, &str))
6745 return;
6746
90e4755a
RE
6747 inst.instruction |= HWOFFSET_IMM;
6748 inst.reloc.type = BFD_RELOC_ARM_OFFSET_IMM8;
b99bd4ef
NC
6749#ifndef TE_WINCE
6750 /* PC rel adjust. */
6751 inst.reloc.exp.X_add_number -= 8;
6752#endif
6753 inst.reloc.pc_rel = 1;
6754 inst.instruction |= (REG_PC << 16);
6755 pre_inc = 1;
6756 }
6757
90e4755a 6758 inst.instruction |= (pre_inc ? PRE_INDEX : 0);
b99bd4ef 6759 end_of_line (str);
b99bd4ef
NC
6760}
6761
b05fe5cf
ZW
6762static void
6763do_ldsttv4 (char * str)
6764{
6765 int conflict_reg;
6766
6767 skip_whitespace (str);
6768
6769 if ((conflict_reg = reg_required_here (& str, 12)) == FAIL)
6770 {
6771 if (!inst.error)
6772 inst.error = BAD_ARGS;
6773 return;
6774 }
6775
6776 if (skip_past_comma (& str) == FAIL)
6777 {
6778 inst.error = _("address expected");
6779 return;
6780 }
6781
6782 if (*str == '[')
6783 {
6784 int reg;
6785
6786 str++;
6787
6788 skip_whitespace (str);
6789
6790 if ((reg = reg_required_here (&str, 16)) == FAIL)
6791 return;
6792
6793 /* ldrt/strt always use post-indexed addressing, so if the base is
6794 the same as Rd, we warn. */
6795 if (conflict_reg == reg)
6796 as_warn (_("%s register same as write-back base"),
6797 ((inst.instruction & LOAD_BIT)
6798 ? _("destination") : _("source")));
6799
6800 skip_whitespace (str);
6801
6802 if (*str == ']')
6803 {
6804 str ++;
6805
6806 if (skip_past_comma (&str) == SUCCESS)
6807 {
6808 /* [Rn],... (post inc) */
6809 if (ldst_extend_v4 (&str) == FAIL)
6810 return;
6811 }
6812 else
6813 {
6814 /* [Rn] */
6815 skip_whitespace (str);
6816
6817 /* Skip a write-back '!'. */
6818 if (*str == '!')
6819 str++;
6820
6821 inst.instruction |= (INDEX_UP|HWOFFSET_IMM);
6822 }
6823 }
6824 else
6825 {
6826 inst.error = _("post-indexed expression expected");
6827 return;
6828 }
6829 }
6830 else
6831 {
6832 inst.error = _("post-indexed expression expected");
6833 return;
6834 }
6835
6836 end_of_line (str);
6837}
6838
6839
b99bd4ef 6840static long
a737bd4d 6841reg_list (char ** strp)
b99bd4ef
NC
6842{
6843 char * str = * strp;
6844 long range = 0;
6845 int another_range;
6846
6847 /* We come back here if we get ranges concatenated by '+' or '|'. */
6848 do
6849 {
6850 another_range = 0;
6851
6852 if (*str == '{')
6853 {
6854 int in_range = 0;
6855 int cur_reg = -1;
6856
6857 str++;
6858 do
6859 {
6860 int reg;
6861
6862 skip_whitespace (str);
6863
6864 if ((reg = reg_required_here (& str, -1)) == FAIL)
6865 return FAIL;
6866
6867 if (in_range)
6868 {
6869 int i;
6870
6871 if (reg <= cur_reg)
6872 {
f03698e6 6873 inst.error = _("bad range in register list");
b99bd4ef
NC
6874 return FAIL;
6875 }
6876
6877 for (i = cur_reg + 1; i < reg; i++)
6878 {
6879 if (range & (1 << i))
6880 as_tsktsk
f03698e6 6881 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6882 i);
6883 else
6884 range |= 1 << i;
6885 }
6886 in_range = 0;
6887 }
6888
6889 if (range & (1 << reg))
f03698e6 6890 as_tsktsk (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6891 reg);
6892 else if (reg <= cur_reg)
f03698e6 6893 as_tsktsk (_("Warning: register range not in ascending order"));
b99bd4ef
NC
6894
6895 range |= 1 << reg;
6896 cur_reg = reg;
6897 }
6898 while (skip_past_comma (&str) != FAIL
6899 || (in_range = 1, *str++ == '-'));
6900 str--;
6901 skip_whitespace (str);
6902
6903 if (*str++ != '}')
6904 {
f03698e6 6905 inst.error = _("missing `}'");
b99bd4ef
NC
6906 return FAIL;
6907 }
6908 }
6909 else
6910 {
6911 expressionS expr;
6912
6913 if (my_get_expression (&expr, &str))
6914 return FAIL;
6915
6916 if (expr.X_op == O_constant)
6917 {
6918 if (expr.X_add_number
6919 != (expr.X_add_number & 0x0000ffff))
6920 {
6921 inst.error = _("invalid register mask");
6922 return FAIL;
6923 }
6924
6925 if ((range & expr.X_add_number) != 0)
6926 {
6927 int regno = range & expr.X_add_number;
6928
6929 regno &= -regno;
6930 regno = (1 << regno) - 1;
6931 as_tsktsk
f03698e6 6932 (_("Warning: duplicated register (r%d) in register list"),
b99bd4ef
NC
6933 regno);
6934 }
6935
6936 range |= expr.X_add_number;
6937 }
6938 else
6939 {
6940 if (inst.reloc.type != 0)
6941 {
6942 inst.error = _("expression too complex");
6943 return FAIL;
6944 }
6945
6946 memcpy (&inst.reloc.exp, &expr, sizeof (expressionS));
6947 inst.reloc.type = BFD_RELOC_ARM_MULTI;
6948 inst.reloc.pc_rel = 0;
6949 }
6950 }
6951
6952 skip_whitespace (str);
6953
6954 if (*str == '|' || *str == '+')
6955 {
6956 str++;
6957 another_range = 1;
6958 }
6959 }
6960 while (another_range);
6961
6962 *strp = str;
6963 return range;
6964}
6965
6966static void
a737bd4d 6967do_ldmstm (char * str)
b99bd4ef
NC
6968{
6969 int base_reg;
6970 long range;
6971
6972 skip_whitespace (str);
6973
6974 if ((base_reg = reg_required_here (&str, 16)) == FAIL)
6975 return;
6976
6977 if (base_reg == REG_PC)
6978 {
6979 inst.error = _("r15 not allowed as base register");
6980 return;
6981 }
6982
6983 skip_whitespace (str);
6984
6985 if (*str == '!')
6986 {
90e4755a 6987 inst.instruction |= WRITE_BACK;
b99bd4ef
NC
6988 str++;
6989 }
6990
6991 if (skip_past_comma (&str) == FAIL
6992 || (range = reg_list (&str)) == FAIL)
6993 {
6994 if (! inst.error)
6995 inst.error = BAD_ARGS;
6996 return;
6997 }
6998
6999 if (*str == '^')
7000 {
7001 str++;
90e4755a 7002 inst.instruction |= LDM_TYPE_2_OR_3;
b99bd4ef
NC
7003 }
7004
6189168b
NC
7005 if (inst.instruction & WRITE_BACK)
7006 {
7007 /* Check for unpredictable uses of writeback. */
7008 if (inst.instruction & LOAD_BIT)
7009 {
7010 /* Not allowed in LDM type 2. */
7011 if ((inst.instruction & LDM_TYPE_2_OR_3)
7012 && ((range & (1 << REG_PC)) == 0))
7013 as_warn (_("writeback of base register is UNPREDICTABLE"));
7014 /* Only allowed if base reg not in list for other types. */
7015 else if (range & (1 << base_reg))
7016 as_warn (_("writeback of base register when in register list is UNPREDICTABLE"));
7017 }
7018 else /* STM. */
7019 {
7020 /* Not allowed for type 2. */
7021 if (inst.instruction & LDM_TYPE_2_OR_3)
7022 as_warn (_("writeback of base register is UNPREDICTABLE"));
7023 /* Only allowed if base reg not in list, or first in list. */
7024 else if ((range & (1 << base_reg))
7025 && (range & ((1 << base_reg) - 1)))
7026 as_warn (_("if writeback register is in list, it must be the lowest reg in the list"));
7027 }
7028 }
61b5f74b 7029
f2b7cb0a 7030 inst.instruction |= range;
b99bd4ef 7031 end_of_line (str);
b99bd4ef
NC
7032}
7033
0dd132b6
NC
7034static void
7035do_smi (char * str)
7036{
7037 skip_whitespace (str);
7038
7039 /* Allow optional leading '#'. */
7040 if (is_immediate_prefix (*str))
7041 str++;
7042
7043 if (my_get_expression (& inst.reloc.exp, & str))
7044 return;
7045
7046 inst.reloc.type = BFD_RELOC_ARM_SMI;
7047 inst.reloc.pc_rel = 0;
7048 end_of_line (str);
7049}
7050
b99bd4ef 7051static void
a737bd4d 7052do_swi (char * str)
b99bd4ef
NC
7053{
7054 skip_whitespace (str);
7055
7056 /* Allow optional leading '#'. */
7057 if (is_immediate_prefix (*str))
7058 str++;
7059
7060 if (my_get_expression (& inst.reloc.exp, & str))
7061 return;
7062
7063 inst.reloc.type = BFD_RELOC_ARM_SWI;
7064 inst.reloc.pc_rel = 0;
b99bd4ef 7065 end_of_line (str);
b99bd4ef
NC
7066}
7067
7068static void
a737bd4d 7069do_swap (char * str)
b99bd4ef
NC
7070{
7071 int reg;
7072
7073 skip_whitespace (str);
7074
7075 if ((reg = reg_required_here (&str, 12)) == FAIL)
7076 return;
7077
7078 if (reg == REG_PC)
7079 {
7080 inst.error = _("r15 not allowed in swap");
7081 return;
7082 }
7083
7084 if (skip_past_comma (&str) == FAIL
7085 || (reg = reg_required_here (&str, 0)) == FAIL)
7086 {
7087 if (!inst.error)
7088 inst.error = BAD_ARGS;
7089 return;
7090 }
7091
7092 if (reg == REG_PC)
7093 {
7094 inst.error = _("r15 not allowed in swap");
7095 return;
7096 }
7097
7098 if (skip_past_comma (&str) == FAIL
7099 || *str++ != '[')
7100 {
7101 inst.error = BAD_ARGS;
7102 return;
7103 }
7104
7105 skip_whitespace (str);
7106
7107 if ((reg = reg_required_here (&str, 16)) == FAIL)
7108 return;
7109
7110 if (reg == REG_PC)
7111 {
7112 inst.error = BAD_PC;
7113 return;
7114 }
7115
7116 skip_whitespace (str);
7117
7118 if (*str++ != ']')
7119 {
7120 inst.error = _("missing ]");
7121 return;
7122 }
7123
b99bd4ef 7124 end_of_line (str);
b99bd4ef
NC
7125}
7126
7127static void
a737bd4d 7128do_branch (char * str)
b99bd4ef
NC
7129{
7130 if (my_get_expression (&inst.reloc.exp, &str))
7131 return;
7132
7133#ifdef OBJ_ELF
7134 {
7135 char * save_in;
7136
7137 /* ScottB: February 5, 1998 - Check to see of PLT32 reloc
7138 required for the instruction. */
7139
7140 /* arm_parse_reloc () works on input_line_pointer.
7141 We actually want to parse the operands to the branch instruction
7142 passed in 'str'. Save the input pointer and restore it later. */
7143 save_in = input_line_pointer;
7144 input_line_pointer = str;
7145 if (inst.reloc.exp.X_op == O_symbol
7146 && *str == '('
7147 && arm_parse_reloc () == BFD_RELOC_ARM_PLT32)
7148 {
7149 inst.reloc.type = BFD_RELOC_ARM_PLT32;
7150 inst.reloc.pc_rel = 0;
7151 /* Modify str to point to after parsed operands, otherwise
7152 end_of_line() will complain about the (PLT) left in str. */
7153 str = input_line_pointer;
7154 }
7155 else
7156 {
7157 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
7158 inst.reloc.pc_rel = 1;
7159 }
7160 input_line_pointer = save_in;
7161 }
7162#else
7163 inst.reloc.type = BFD_RELOC_ARM_PCREL_BRANCH;
7164 inst.reloc.pc_rel = 1;
7165#endif /* OBJ_ELF */
7166
7167 end_of_line (str);
b99bd4ef
NC
7168}
7169
7170static void
a737bd4d 7171do_cdp (char * str)
b99bd4ef
NC
7172{
7173 /* Co-processor data operation.
7174 Format: CDP{cond} CP#,<expr>,CRd,CRn,CRm{,<expr>} */
7175 skip_whitespace (str);
7176
7177 if (co_proc_number (&str) == FAIL)
7178 {
7179 if (!inst.error)
7180 inst.error = BAD_ARGS;
7181 return;
7182 }
7183
7184 if (skip_past_comma (&str) == FAIL
7185 || cp_opc_expr (&str, 20,4) == FAIL)
7186 {
7187 if (!inst.error)
7188 inst.error = BAD_ARGS;
7189 return;
7190 }
7191
7192 if (skip_past_comma (&str) == FAIL
7193 || cp_reg_required_here (&str, 12) == FAIL)
7194 {
7195 if (!inst.error)
7196 inst.error = BAD_ARGS;
7197 return;
7198 }
7199
7200 if (skip_past_comma (&str) == FAIL
7201 || cp_reg_required_here (&str, 16) == FAIL)
7202 {
7203 if (!inst.error)
7204 inst.error = BAD_ARGS;
7205 return;
7206 }
7207
7208 if (skip_past_comma (&str) == FAIL
7209 || cp_reg_required_here (&str, 0) == FAIL)
7210 {
7211 if (!inst.error)
7212 inst.error = BAD_ARGS;
7213 return;
7214 }
7215
7216 if (skip_past_comma (&str) == SUCCESS)
7217 {
7218 if (cp_opc_expr (&str, 5, 3) == FAIL)
7219 {
7220 if (!inst.error)
7221 inst.error = BAD_ARGS;
7222 return;
7223 }
7224 }
7225
7226 end_of_line (str);
b99bd4ef
NC
7227}
7228
7229static void
a737bd4d 7230do_lstc (char * str)
b99bd4ef
NC
7231{
7232 /* Co-processor register load/store.
7233 Format: <LDC|STC{cond}[L] CP#,CRd,<address> */
7234
7235 skip_whitespace (str);
7236
7237 if (co_proc_number (&str) == FAIL)
7238 {
7239 if (!inst.error)
7240 inst.error = BAD_ARGS;
7241 return;
7242 }
7243
7244 if (skip_past_comma (&str) == FAIL
7245 || cp_reg_required_here (&str, 12) == FAIL)
7246 {
7247 if (!inst.error)
7248 inst.error = BAD_ARGS;
7249 return;
7250 }
7251
7252 if (skip_past_comma (&str) == FAIL
bfae80f2 7253 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7254 {
7255 if (! inst.error)
7256 inst.error = BAD_ARGS;
7257 return;
7258 }
7259
b99bd4ef 7260 end_of_line (str);
b99bd4ef
NC
7261}
7262
7263static void
a737bd4d 7264do_co_reg (char * str)
b99bd4ef
NC
7265{
7266 /* Co-processor register transfer.
7267 Format: <MCR|MRC>{cond} CP#,<expr1>,Rd,CRn,CRm{,<expr2>} */
7268
7269 skip_whitespace (str);
7270
7271 if (co_proc_number (&str) == FAIL)
7272 {
7273 if (!inst.error)
7274 inst.error = BAD_ARGS;
7275 return;
7276 }
7277
7278 if (skip_past_comma (&str) == FAIL
7279 || cp_opc_expr (&str, 21, 3) == FAIL)
7280 {
7281 if (!inst.error)
7282 inst.error = BAD_ARGS;
7283 return;
7284 }
7285
7286 if (skip_past_comma (&str) == FAIL
7287 || reg_required_here (&str, 12) == FAIL)
7288 {
7289 if (!inst.error)
7290 inst.error = BAD_ARGS;
7291 return;
7292 }
7293
7294 if (skip_past_comma (&str) == FAIL
7295 || cp_reg_required_here (&str, 16) == FAIL)
7296 {
7297 if (!inst.error)
7298 inst.error = BAD_ARGS;
7299 return;
7300 }
7301
7302 if (skip_past_comma (&str) == FAIL
7303 || cp_reg_required_here (&str, 0) == FAIL)
7304 {
7305 if (!inst.error)
7306 inst.error = BAD_ARGS;
7307 return;
7308 }
7309
7310 if (skip_past_comma (&str) == SUCCESS)
7311 {
7312 if (cp_opc_expr (&str, 5, 3) == FAIL)
7313 {
7314 if (!inst.error)
7315 inst.error = BAD_ARGS;
7316 return;
7317 }
7318 }
b99bd4ef
NC
7319
7320 end_of_line (str);
b99bd4ef
NC
7321}
7322
7323static void
a737bd4d 7324do_fpa_ctrl (char * str)
b99bd4ef
NC
7325{
7326 /* FP control registers.
7327 Format: <WFS|RFS|WFC|RFC>{cond} Rn */
7328
7329 skip_whitespace (str);
7330
7331 if (reg_required_here (&str, 12) == FAIL)
7332 {
7333 if (!inst.error)
7334 inst.error = BAD_ARGS;
7335 return;
7336 }
7337
7338 end_of_line (str);
b99bd4ef
NC
7339}
7340
7341static void
a737bd4d 7342do_fpa_ldst (char * str)
b99bd4ef
NC
7343{
7344 skip_whitespace (str);
7345
b99bd4ef
NC
7346 if (fp_reg_required_here (&str, 12) == FAIL)
7347 {
7348 if (!inst.error)
7349 inst.error = BAD_ARGS;
7350 return;
7351 }
7352
7353 if (skip_past_comma (&str) == FAIL
bfae80f2 7354 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7355 {
7356 if (!inst.error)
7357 inst.error = BAD_ARGS;
7358 return;
7359 }
7360
7361 end_of_line (str);
7362}
7363
7364static void
a737bd4d 7365do_fpa_ldmstm (char * str)
b99bd4ef
NC
7366{
7367 int num_regs;
7368
7369 skip_whitespace (str);
7370
7371 if (fp_reg_required_here (&str, 12) == FAIL)
7372 {
7373 if (! inst.error)
7374 inst.error = BAD_ARGS;
7375 return;
7376 }
7377
7378 /* Get Number of registers to transfer. */
7379 if (skip_past_comma (&str) == FAIL
7380 || my_get_expression (&inst.reloc.exp, &str))
7381 {
7382 if (! inst.error)
7383 inst.error = _("constant expression expected");
7384 return;
7385 }
7386
7387 if (inst.reloc.exp.X_op != O_constant)
7388 {
f03698e6 7389 inst.error = _("constant value required for number of registers");
b99bd4ef
NC
7390 return;
7391 }
7392
7393 num_regs = inst.reloc.exp.X_add_number;
7394
7395 if (num_regs < 1 || num_regs > 4)
7396 {
7397 inst.error = _("number of registers must be in the range [1:4]");
7398 return;
7399 }
7400
7401 switch (num_regs)
7402 {
7403 case 1:
7404 inst.instruction |= CP_T_X;
7405 break;
7406 case 2:
7407 inst.instruction |= CP_T_Y;
7408 break;
7409 case 3:
7410 inst.instruction |= CP_T_Y | CP_T_X;
7411 break;
7412 case 4:
7413 break;
7414 default:
7415 abort ();
7416 }
7417
e28cd48c 7418 if (inst.instruction & (CP_T_Pre | CP_T_UD)) /* ea/fd format. */
b99bd4ef
NC
7419 {
7420 int reg;
7421 int write_back;
7422 int offset;
7423
7424 /* The instruction specified "ea" or "fd", so we can only accept
7425 [Rn]{!}. The instruction does not really support stacking or
7426 unstacking, so we have to emulate these by setting appropriate
7427 bits and offsets. */
7428 if (skip_past_comma (&str) == FAIL
7429 || *str != '[')
7430 {
7431 if (! inst.error)
7432 inst.error = BAD_ARGS;
7433 return;
7434 }
7435
7436 str++;
7437 skip_whitespace (str);
7438
7439 if ((reg = reg_required_here (&str, 16)) == FAIL)
7440 return;
7441
7442 skip_whitespace (str);
7443
7444 if (*str != ']')
7445 {
7446 inst.error = BAD_ARGS;
7447 return;
7448 }
7449
7450 str++;
7451 if (*str == '!')
7452 {
7453 write_back = 1;
7454 str++;
7455 if (reg == REG_PC)
7456 {
7457 inst.error =
f03698e6 7458 _("r15 not allowed as base register with write-back");
b99bd4ef
NC
7459 return;
7460 }
7461 }
7462 else
7463 write_back = 0;
7464
90e4755a 7465 if (inst.instruction & CP_T_Pre)
b99bd4ef
NC
7466 {
7467 /* Pre-decrement. */
7468 offset = 3 * num_regs;
7469 if (write_back)
90e4755a 7470 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7471 }
7472 else
7473 {
7474 /* Post-increment. */
7475 if (write_back)
7476 {
90e4755a 7477 inst.instruction |= CP_T_WB;
b99bd4ef
NC
7478 offset = 3 * num_regs;
7479 }
7480 else
7481 {
7482 /* No write-back, so convert this into a standard pre-increment
7483 instruction -- aesthetically more pleasing. */
90e4755a 7484 inst.instruction |= CP_T_Pre | CP_T_UD;
b99bd4ef
NC
7485 offset = 0;
7486 }
7487 }
7488
f2b7cb0a 7489 inst.instruction |= offset;
b99bd4ef
NC
7490 }
7491 else if (skip_past_comma (&str) == FAIL
bfae80f2 7492 || cp_address_required_here (&str, CP_WB_OK) == FAIL)
b99bd4ef
NC
7493 {
7494 if (! inst.error)
7495 inst.error = BAD_ARGS;
7496 return;
7497 }
7498
7499 end_of_line (str);
7500}
7501
7502static void
a737bd4d 7503do_fpa_dyadic (char * str)
b99bd4ef
NC
7504{
7505 skip_whitespace (str);
7506
b99bd4ef
NC
7507 if (fp_reg_required_here (&str, 12) == FAIL)
7508 {
7509 if (! inst.error)
7510 inst.error = BAD_ARGS;
7511 return;
7512 }
7513
7514 if (skip_past_comma (&str) == FAIL
7515 || fp_reg_required_here (&str, 16) == FAIL)
7516 {
7517 if (! inst.error)
7518 inst.error = BAD_ARGS;
7519 return;
7520 }
7521
7522 if (skip_past_comma (&str) == FAIL
7523 || fp_op2 (&str) == FAIL)
7524 {
7525 if (! inst.error)
7526 inst.error = BAD_ARGS;
7527 return;
7528 }
7529
b99bd4ef 7530 end_of_line (str);
b99bd4ef
NC
7531}
7532
7533static void
a737bd4d 7534do_fpa_monadic (char * str)
b99bd4ef
NC
7535{
7536 skip_whitespace (str);
7537
b99bd4ef
NC
7538 if (fp_reg_required_here (&str, 12) == FAIL)
7539 {
7540 if (! inst.error)
7541 inst.error = BAD_ARGS;
7542 return;
7543 }
7544
7545 if (skip_past_comma (&str) == FAIL
7546 || fp_op2 (&str) == FAIL)
7547 {
7548 if (! inst.error)
7549 inst.error = BAD_ARGS;
7550 return;
7551 }
7552
b99bd4ef 7553 end_of_line (str);
b99bd4ef
NC
7554}
7555
7556static void
a737bd4d 7557do_fpa_cmp (char * str)
b99bd4ef
NC
7558{
7559 skip_whitespace (str);
7560
7561 if (fp_reg_required_here (&str, 16) == FAIL)
7562 {
7563 if (! inst.error)
7564 inst.error = BAD_ARGS;
7565 return;
7566 }
7567
7568 if (skip_past_comma (&str) == FAIL
7569 || fp_op2 (&str) == FAIL)
7570 {
7571 if (! inst.error)
7572 inst.error = BAD_ARGS;
7573 return;
7574 }
7575
b99bd4ef 7576 end_of_line (str);
b99bd4ef
NC
7577}
7578
7579static void
a737bd4d 7580do_fpa_from_reg (char * str)
b99bd4ef
NC
7581{
7582 skip_whitespace (str);
7583
b99bd4ef
NC
7584 if (fp_reg_required_here (&str, 16) == FAIL)
7585 {
7586 if (! inst.error)
7587 inst.error = BAD_ARGS;
7588 return;
7589 }
7590
7591 if (skip_past_comma (&str) == FAIL
7592 || reg_required_here (&str, 12) == FAIL)
7593 {
7594 if (! inst.error)
7595 inst.error = BAD_ARGS;
7596 return;
7597 }
7598
b99bd4ef 7599 end_of_line (str);
b99bd4ef
NC
7600}
7601
7602static void
a737bd4d 7603do_fpa_to_reg (char * str)
b99bd4ef
NC
7604{
7605 skip_whitespace (str);
7606
7607 if (reg_required_here (&str, 12) == FAIL)
7608 return;
7609
7610 if (skip_past_comma (&str) == FAIL
7611 || fp_reg_required_here (&str, 0) == FAIL)
7612 {
7613 if (! inst.error)
7614 inst.error = BAD_ARGS;
7615 return;
7616 }
7617
b99bd4ef 7618 end_of_line (str);
b99bd4ef
NC
7619}
7620
7ed4c4c5
NC
7621/* Encode a VFP SP register number. */
7622
7623static void
7624vfp_sp_encode_reg (int reg, enum vfp_sp_reg_pos pos)
7625{
7626 switch (pos)
7627 {
7628 case VFP_REG_Sd:
7629 inst.instruction |= ((reg >> 1) << 12) | ((reg & 1) << 22);
7630 break;
7631
7632 case VFP_REG_Sn:
7633 inst.instruction |= ((reg >> 1) << 16) | ((reg & 1) << 7);
7634 break;
7635
7636 case VFP_REG_Sm:
7637 inst.instruction |= ((reg >> 1) << 0) | ((reg & 1) << 5);
7638 break;
7639
7640 default:
7641 abort ();
7642 }
7643}
7644
b99bd4ef 7645static int
a737bd4d
NC
7646vfp_sp_reg_required_here (char ** str,
7647 enum vfp_sp_reg_pos pos)
b99bd4ef 7648{
bfae80f2 7649 int reg;
7ed4c4c5 7650 char * start = *str;
b99bd4ef 7651
bfae80f2 7652 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_SN].htab)) != FAIL)
b99bd4ef 7653 {
7ed4c4c5 7654 vfp_sp_encode_reg (reg, pos);
bfae80f2
RE
7655 return reg;
7656 }
b99bd4ef 7657
bfae80f2
RE
7658 /* In the few cases where we might be able to accept something else
7659 this error can be overridden. */
7660 inst.error = _(all_reg_maps[REG_TYPE_SN].expected);
7661
7662 /* Restore the start point. */
7663 *str = start;
7664 return FAIL;
7665}
7666
7667static int
a737bd4d
NC
7668vfp_dp_reg_required_here (char ** str,
7669 enum vfp_dp_reg_pos pos)
bfae80f2 7670{
a737bd4d
NC
7671 int reg;
7672 char * start = *str;
bfae80f2
RE
7673
7674 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_DN].htab)) != FAIL)
7675 {
7676 switch (pos)
b99bd4ef 7677 {
bfae80f2
RE
7678 case VFP_REG_Dd:
7679 inst.instruction |= reg << 12;
7680 break;
b99bd4ef 7681
bfae80f2
RE
7682 case VFP_REG_Dn:
7683 inst.instruction |= reg << 16;
7684 break;
7685
7686 case VFP_REG_Dm:
7687 inst.instruction |= reg << 0;
7688 break;
7689
7690 default:
7691 abort ();
7692 }
7693 return reg;
b99bd4ef
NC
7694 }
7695
bfae80f2
RE
7696 /* In the few cases where we might be able to accept something else
7697 this error can be overridden. */
7698 inst.error = _(all_reg_maps[REG_TYPE_DN].expected);
b99bd4ef 7699
bfae80f2
RE
7700 /* Restore the start point. */
7701 *str = start;
7702 return FAIL;
7703}
b99bd4ef
NC
7704
7705static void
a737bd4d 7706do_vfp_sp_monadic (char * str)
b99bd4ef 7707{
b99bd4ef
NC
7708 skip_whitespace (str);
7709
bfae80f2
RE
7710 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7711 return;
7712
7713 if (skip_past_comma (&str) == FAIL
7714 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef
NC
7715 {
7716 if (! inst.error)
7717 inst.error = BAD_ARGS;
7718 return;
7719 }
7720
bfae80f2 7721 end_of_line (str);
bfae80f2
RE
7722}
7723
7724static void
a737bd4d 7725do_vfp_dp_monadic (char * str)
bfae80f2
RE
7726{
7727 skip_whitespace (str);
7728
7729 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7730 return;
7731
7732 if (skip_past_comma (&str) == FAIL
7733 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
b99bd4ef 7734 {
bfae80f2
RE
7735 if (! inst.error)
7736 inst.error = BAD_ARGS;
7737 return;
b99bd4ef 7738 }
b99bd4ef 7739
bfae80f2 7740 end_of_line (str);
bfae80f2 7741}
b99bd4ef 7742
bfae80f2 7743static void
a737bd4d 7744do_vfp_sp_dyadic (char * str)
bfae80f2
RE
7745{
7746 skip_whitespace (str);
b99bd4ef 7747
bfae80f2
RE
7748 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
7749 return;
b99bd4ef 7750
bfae80f2
RE
7751 if (skip_past_comma (&str) == FAIL
7752 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL
7753 || skip_past_comma (&str) == FAIL
7754 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
b99bd4ef 7755 {
bfae80f2
RE
7756 if (! inst.error)
7757 inst.error = BAD_ARGS;
7758 return;
7759 }
b99bd4ef 7760
bfae80f2 7761 end_of_line (str);
bfae80f2 7762}
b99bd4ef 7763
bfae80f2 7764static void
a737bd4d 7765do_vfp_dp_dyadic (char * str)
bfae80f2
RE
7766{
7767 skip_whitespace (str);
b99bd4ef 7768
bfae80f2
RE
7769 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
7770 return;
b99bd4ef 7771
bfae80f2
RE
7772 if (skip_past_comma (&str) == FAIL
7773 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL
7774 || skip_past_comma (&str) == FAIL
7775 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
7776 {
7777 if (! inst.error)
7778 inst.error = BAD_ARGS;
7779 return;
7780 }
b99bd4ef 7781
bfae80f2 7782 end_of_line (str);
bfae80f2 7783}
b99bd4ef 7784
bfae80f2 7785static void
a737bd4d 7786do_vfp_reg_from_sp (char * str)
bfae80f2
RE
7787{
7788 skip_whitespace (str);
7789
7790 if (reg_required_here (&str, 12) == FAIL)
7791 return;
7792
7793 if (skip_past_comma (&str) == FAIL
7794 || vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7795 {
7796 if (! inst.error)
7797 inst.error = BAD_ARGS;
7798 return;
7799 }
7800
7801 end_of_line (str);
bfae80f2
RE
7802}
7803
7ed4c4c5
NC
7804/* Parse a VFP register list. If the string is invalid return FAIL.
7805 Otherwise return the number of registers, and set PBASE to the first
7806 register. Double precision registers are matched if DP is nonzero. */
a737bd4d 7807
7ed4c4c5
NC
7808static int
7809vfp_parse_reg_list (char **str, int *pbase, int dp)
a737bd4d 7810{
7ed4c4c5 7811 int base_reg;
a737bd4d 7812 int new_base;
7ed4c4c5
NC
7813 int regtype;
7814 int max_regs;
a737bd4d 7815 int count = 0;
a737bd4d 7816 int warned = 0;
7ed4c4c5
NC
7817 unsigned long mask = 0;
7818 int i;
a737bd4d
NC
7819
7820 if (**str != '{')
7821 return FAIL;
7822
7823 (*str)++;
7824 skip_whitespace (*str);
7825
7ed4c4c5 7826 if (dp)
a737bd4d 7827 {
7ed4c4c5
NC
7828 regtype = REG_TYPE_DN;
7829 max_regs = 16;
7830 }
7831 else
7832 {
7833 regtype = REG_TYPE_SN;
7834 max_regs = 32;
7835 }
a737bd4d 7836
7ed4c4c5 7837 base_reg = max_regs;
a737bd4d 7838
7ed4c4c5
NC
7839 do
7840 {
7841 new_base = arm_reg_parse (str, all_reg_maps[regtype].htab);
7842 if (new_base == FAIL)
a737bd4d 7843 {
7ed4c4c5
NC
7844 inst.error = _(all_reg_maps[regtype].expected);
7845 return FAIL;
a737bd4d
NC
7846 }
7847
7ed4c4c5
NC
7848 if (new_base < base_reg)
7849 base_reg = new_base;
7850
a737bd4d
NC
7851 if (mask & (1 << new_base))
7852 {
7853 inst.error = _("invalid register list");
7854 return FAIL;
7855 }
7856
7857 if ((mask >> new_base) != 0 && ! warned)
7858 {
7859 as_tsktsk (_("register list not in ascending order"));
7860 warned = 1;
7861 }
7862
7863 mask |= 1 << new_base;
7864 count++;
7865
7866 skip_whitespace (*str);
7867
7868 if (**str == '-') /* We have the start of a range expression */
7869 {
7870 int high_range;
7871
7872 (*str)++;
7873
7874 if ((high_range
7ed4c4c5 7875 = arm_reg_parse (str, all_reg_maps[regtype].htab))
a737bd4d
NC
7876 == FAIL)
7877 {
7ed4c4c5 7878 inst.error = _(all_reg_maps[regtype].expected);
a737bd4d
NC
7879 return FAIL;
7880 }
7881
7882 if (high_range <= new_base)
7883 {
7884 inst.error = _("register range not in ascending order");
7885 return FAIL;
7886 }
7887
7888 for (new_base++; new_base <= high_range; new_base++)
7889 {
7890 if (mask & (1 << new_base))
7891 {
7892 inst.error = _("invalid register list");
7893 return FAIL;
7894 }
7895
7896 mask |= 1 << new_base;
7897 count++;
7898 }
7899 }
7900 }
7901 while (skip_past_comma (str) != FAIL);
7902
a737bd4d
NC
7903 (*str)++;
7904
a737bd4d 7905 /* Sanity check -- should have raised a parse error above. */
7ed4c4c5 7906 if (count == 0 || count > max_regs)
a737bd4d
NC
7907 abort ();
7908
7ed4c4c5
NC
7909 *pbase = base_reg;
7910
a737bd4d 7911 /* Final test -- the registers must be consecutive. */
7ed4c4c5
NC
7912 mask >>= base_reg;
7913 for (i = 0; i < count; i++)
a737bd4d 7914 {
7ed4c4c5 7915 if ((mask & (1u << i)) == 0)
a737bd4d
NC
7916 {
7917 inst.error = _("non-contiguous register range");
7918 return FAIL;
7919 }
7920 }
7921
7ed4c4c5 7922 return count;
a737bd4d
NC
7923}
7924
bfae80f2 7925static void
a737bd4d 7926do_vfp_reg2_from_sp2 (char * str)
bfae80f2 7927{
7ed4c4c5
NC
7928 int reg;
7929
bfae80f2
RE
7930 skip_whitespace (str);
7931
e45d0630
PB
7932 if (reg_required_here (&str, 12) == FAIL
7933 || skip_past_comma (&str) == FAIL
bfae80f2
RE
7934 || reg_required_here (&str, 16) == FAIL
7935 || skip_past_comma (&str) == FAIL)
7936 {
7937 if (! inst.error)
7938 inst.error = BAD_ARGS;
7939 return;
7940 }
7941
7942 /* We require exactly two consecutive SP registers. */
7ed4c4c5 7943 if (vfp_parse_reg_list (&str, &reg, 0) != 2)
bfae80f2
RE
7944 {
7945 if (! inst.error)
7946 inst.error = _("only two consecutive VFP SP registers allowed here");
7947 }
7ed4c4c5 7948 vfp_sp_encode_reg (reg, VFP_REG_Sm);
bfae80f2
RE
7949
7950 end_of_line (str);
bfae80f2
RE
7951}
7952
7953static void
a737bd4d 7954do_vfp_sp_from_reg (char * str)
bfae80f2
RE
7955{
7956 skip_whitespace (str);
7957
7958 if (vfp_sp_reg_required_here (&str, VFP_REG_Sn) == FAIL)
7959 return;
7960
7961 if (skip_past_comma (&str) == FAIL
7962 || reg_required_here (&str, 12) == FAIL)
7963 {
7964 if (! inst.error)
7965 inst.error = BAD_ARGS;
7966 return;
7967 }
7968
7969 end_of_line (str);
bfae80f2
RE
7970}
7971
e45d0630 7972static void
a737bd4d 7973do_vfp_sp2_from_reg2 (char * str)
e45d0630 7974{
7ed4c4c5
NC
7975 int reg;
7976
e45d0630
PB
7977 skip_whitespace (str);
7978
7979 /* We require exactly two consecutive SP registers. */
7ed4c4c5 7980 if (vfp_parse_reg_list (&str, &reg, 0) != 2)
e45d0630
PB
7981 {
7982 if (! inst.error)
7983 inst.error = _("only two consecutive VFP SP registers allowed here");
7984 }
7ed4c4c5 7985 vfp_sp_encode_reg (reg, VFP_REG_Sm);
e45d0630
PB
7986
7987 if (skip_past_comma (&str) == FAIL
7988 || reg_required_here (&str, 12) == FAIL
7989 || skip_past_comma (&str) == FAIL
7990 || reg_required_here (&str, 16) == FAIL)
7991 {
7992 if (! inst.error)
7993 inst.error = BAD_ARGS;
7994 return;
7995 }
7996
7997 end_of_line (str);
7998}
7999
bfae80f2 8000static void
a737bd4d 8001do_vfp_reg_from_dp (char * str)
bfae80f2
RE
8002{
8003 skip_whitespace (str);
8004
8005 if (reg_required_here (&str, 12) == FAIL)
8006 return;
8007
8008 if (skip_past_comma (&str) == FAIL
8009 || vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
8010 {
8011 if (! inst.error)
8012 inst.error = BAD_ARGS;
8013 return;
8014 }
8015
8016 end_of_line (str);
bfae80f2
RE
8017}
8018
8019static void
a737bd4d 8020do_vfp_reg2_from_dp (char * str)
bfae80f2
RE
8021{
8022 skip_whitespace (str);
8023
8024 if (reg_required_here (&str, 12) == FAIL)
8025 return;
8026
8027 if (skip_past_comma (&str) == FAIL
8028 || reg_required_here (&str, 16) == FAIL
8029 || skip_past_comma (&str) == FAIL
8030 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8031 {
8032 if (! inst.error)
8033 inst.error = BAD_ARGS;
8034 return;
8035 }
8036
8037 end_of_line (str);
bfae80f2
RE
8038}
8039
8040static void
a737bd4d 8041do_vfp_dp_from_reg (char * str)
bfae80f2
RE
8042{
8043 skip_whitespace (str);
8044
8045 if (vfp_dp_reg_required_here (&str, VFP_REG_Dn) == FAIL)
8046 return;
8047
8048 if (skip_past_comma (&str) == FAIL
8049 || reg_required_here (&str, 12) == FAIL)
8050 {
8051 if (! inst.error)
8052 inst.error = BAD_ARGS;
8053 return;
8054 }
8055
8056 end_of_line (str);
bfae80f2
RE
8057}
8058
8059static void
a737bd4d 8060do_vfp_dp_from_reg2 (char * str)
bfae80f2
RE
8061{
8062 skip_whitespace (str);
8063
8064 if (vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8065 return;
8066
8067 if (skip_past_comma (&str) == FAIL
8068 || reg_required_here (&str, 12) == FAIL
8069 || skip_past_comma (&str) == FAIL
e45d0630 8070 || reg_required_here (&str, 16) == FAIL)
bfae80f2
RE
8071 {
8072 if (! inst.error)
8073 inst.error = BAD_ARGS;
8074 return;
8075 }
8076
8077 end_of_line (str);
bfae80f2
RE
8078}
8079
8080static const struct vfp_reg *
a737bd4d 8081vfp_psr_parse (char ** str)
bfae80f2
RE
8082{
8083 char *start = *str;
8084 char c;
8085 char *p;
8086 const struct vfp_reg *vreg;
8087
8088 p = start;
8089
8090 /* Find the end of the current token. */
8091 do
8092 {
8093 c = *p++;
8094 }
8095 while (ISALPHA (c));
8096
8097 /* Mark it. */
8098 *--p = 0;
8099
cc8a6dd0 8100 for (vreg = vfp_regs + 0;
bfae80f2
RE
8101 vreg < vfp_regs + sizeof (vfp_regs) / sizeof (struct vfp_reg);
8102 vreg++)
8103 {
a737bd4d 8104 if (streq (start, vreg->name))
bfae80f2
RE
8105 {
8106 *p = c;
8107 *str = p;
8108 return vreg;
8109 }
8110 }
8111
8112 *p = c;
8113 return NULL;
8114}
8115
8116static int
a737bd4d 8117vfp_psr_required_here (char ** str)
bfae80f2
RE
8118{
8119 char *start = *str;
8120 const struct vfp_reg *vreg;
8121
8122 vreg = vfp_psr_parse (str);
8123
8124 if (vreg)
8125 {
8126 inst.instruction |= vreg->regno;
8127 return SUCCESS;
8128 }
8129
8130 inst.error = _("VFP system register expected");
8131
8132 *str = start;
8133 return FAIL;
8134}
8135
8136static void
a737bd4d 8137do_vfp_reg_from_ctrl (char * str)
bfae80f2
RE
8138{
8139 skip_whitespace (str);
8140
8141 if (reg_required_here (&str, 12) == FAIL)
8142 return;
8143
8144 if (skip_past_comma (&str) == FAIL
8145 || vfp_psr_required_here (&str) == FAIL)
8146 {
8147 if (! inst.error)
8148 inst.error = BAD_ARGS;
8149 return;
8150 }
8151
8152 end_of_line (str);
bfae80f2
RE
8153}
8154
8155static void
a737bd4d 8156do_vfp_ctrl_from_reg (char * str)
bfae80f2
RE
8157{
8158 skip_whitespace (str);
8159
8160 if (vfp_psr_required_here (&str) == FAIL)
8161 return;
8162
8163 if (skip_past_comma (&str) == FAIL
8164 || reg_required_here (&str, 12) == FAIL)
8165 {
8166 if (! inst.error)
8167 inst.error = BAD_ARGS;
8168 return;
8169 }
8170
8171 end_of_line (str);
bfae80f2
RE
8172}
8173
8174static void
a737bd4d 8175do_vfp_sp_ldst (char * str)
bfae80f2
RE
8176{
8177 skip_whitespace (str);
8178
8179 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8180 {
8181 if (!inst.error)
8182 inst.error = BAD_ARGS;
8183 return;
8184 }
8185
8186 if (skip_past_comma (&str) == FAIL
8187 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
8188 {
8189 if (!inst.error)
8190 inst.error = BAD_ARGS;
8191 return;
8192 }
8193
8194 end_of_line (str);
bfae80f2
RE
8195}
8196
8197static void
a737bd4d 8198do_vfp_dp_ldst (char * str)
bfae80f2
RE
8199{
8200 skip_whitespace (str);
8201
8202 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8203 {
8204 if (!inst.error)
8205 inst.error = BAD_ARGS;
8206 return;
8207 }
8208
8209 if (skip_past_comma (&str) == FAIL
8210 || cp_address_required_here (&str, CP_NO_WB) == FAIL)
8211 {
8212 if (!inst.error)
a737bd4d
NC
8213 inst.error = BAD_ARGS;
8214 return;
bfae80f2
RE
8215 }
8216
a737bd4d 8217 end_of_line (str);
bfae80f2
RE
8218}
8219
bfae80f2
RE
8220
8221static void
a737bd4d 8222vfp_sp_ldstm (char * str, enum vfp_ldstm_type ldstm_type)
bfae80f2 8223{
7ed4c4c5
NC
8224 int count;
8225 int reg;
bfae80f2
RE
8226
8227 skip_whitespace (str);
8228
8229 if (reg_required_here (&str, 16) == FAIL)
8230 return;
8231
8232 skip_whitespace (str);
8233
8234 if (*str == '!')
8235 {
8236 inst.instruction |= WRITE_BACK;
8237 str++;
8238 }
8239 else if (ldstm_type != VFP_LDSTMIA)
8240 {
8241 inst.error = _("this addressing mode requires base-register writeback");
8242 return;
8243 }
8244
8245 if (skip_past_comma (&str) == FAIL
7ed4c4c5 8246 || (count = vfp_parse_reg_list (&str, &reg, 0)) == FAIL)
bfae80f2
RE
8247 {
8248 if (!inst.error)
8249 inst.error = BAD_ARGS;
8250 return;
8251 }
7ed4c4c5 8252 vfp_sp_encode_reg (reg, VFP_REG_Sd);
bfae80f2 8253
7ed4c4c5 8254 inst.instruction |= count;
bfae80f2
RE
8255 end_of_line (str);
8256}
8257
8258static void
a737bd4d 8259vfp_dp_ldstm (char * str, enum vfp_ldstm_type ldstm_type)
bfae80f2 8260{
7ed4c4c5
NC
8261 int count;
8262 int reg;
bfae80f2
RE
8263
8264 skip_whitespace (str);
8265
8266 if (reg_required_here (&str, 16) == FAIL)
8267 return;
8268
8269 skip_whitespace (str);
8270
8271 if (*str == '!')
8272 {
8273 inst.instruction |= WRITE_BACK;
8274 str++;
8275 }
8276 else if (ldstm_type != VFP_LDSTMIA && ldstm_type != VFP_LDSTMIAX)
8277 {
8278 inst.error = _("this addressing mode requires base-register writeback");
8279 return;
8280 }
8281
8282 if (skip_past_comma (&str) == FAIL
7ed4c4c5 8283 || (count = vfp_parse_reg_list (&str, &reg, 1)) == FAIL)
bfae80f2
RE
8284 {
8285 if (!inst.error)
8286 inst.error = BAD_ARGS;
8287 return;
8288 }
8289
7ed4c4c5 8290 count <<= 1;
bfae80f2 8291 if (ldstm_type == VFP_LDSTMIAX || ldstm_type == VFP_LDSTMDBX)
7ed4c4c5 8292 count += 1;
bfae80f2 8293
7ed4c4c5 8294 inst.instruction |= (reg << 12) | count;
bfae80f2
RE
8295 end_of_line (str);
8296}
8297
8298static void
a737bd4d 8299do_vfp_sp_ldstmia (char * str)
bfae80f2
RE
8300{
8301 vfp_sp_ldstm (str, VFP_LDSTMIA);
8302}
8303
8304static void
a737bd4d 8305do_vfp_sp_ldstmdb (char * str)
bfae80f2
RE
8306{
8307 vfp_sp_ldstm (str, VFP_LDSTMDB);
8308}
8309
8310static void
a737bd4d 8311do_vfp_dp_ldstmia (char * str)
bfae80f2
RE
8312{
8313 vfp_dp_ldstm (str, VFP_LDSTMIA);
8314}
8315
8316static void
a737bd4d 8317do_vfp_dp_ldstmdb (char * str)
bfae80f2
RE
8318{
8319 vfp_dp_ldstm (str, VFP_LDSTMDB);
8320}
8321
8322static void
a737bd4d 8323do_vfp_xp_ldstmia (char *str)
bfae80f2
RE
8324{
8325 vfp_dp_ldstm (str, VFP_LDSTMIAX);
8326}
8327
8328static void
a737bd4d 8329do_vfp_xp_ldstmdb (char * str)
bfae80f2
RE
8330{
8331 vfp_dp_ldstm (str, VFP_LDSTMDBX);
8332}
8333
8334static void
a737bd4d 8335do_vfp_sp_compare_z (char * str)
bfae80f2
RE
8336{
8337 skip_whitespace (str);
8338
8339 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8340 {
8341 if (!inst.error)
8342 inst.error = BAD_ARGS;
8343 return;
8344 }
8345
8346 end_of_line (str);
bfae80f2
RE
8347}
8348
8349static void
a737bd4d 8350do_vfp_dp_compare_z (char * str)
bfae80f2
RE
8351{
8352 skip_whitespace (str);
8353
8354 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8355 {
8356 if (!inst.error)
8357 inst.error = BAD_ARGS;
8358 return;
8359 }
8360
8361 end_of_line (str);
bfae80f2
RE
8362}
8363
8364static void
a737bd4d 8365do_vfp_dp_sp_cvt (char * str)
bfae80f2
RE
8366{
8367 skip_whitespace (str);
8368
8369 if (vfp_dp_reg_required_here (&str, VFP_REG_Dd) == FAIL)
8370 return;
8371
8372 if (skip_past_comma (&str) == FAIL
8373 || vfp_sp_reg_required_here (&str, VFP_REG_Sm) == FAIL)
8374 {
8375 if (! inst.error)
8376 inst.error = BAD_ARGS;
8377 return;
8378 }
8379
8380 end_of_line (str);
bfae80f2
RE
8381}
8382
8383static void
a737bd4d 8384do_vfp_sp_dp_cvt (char * str)
bfae80f2
RE
8385{
8386 skip_whitespace (str);
8387
8388 if (vfp_sp_reg_required_here (&str, VFP_REG_Sd) == FAIL)
8389 return;
8390
8391 if (skip_past_comma (&str) == FAIL
8392 || vfp_dp_reg_required_here (&str, VFP_REG_Dm) == FAIL)
8393 {
8394 if (! inst.error)
8395 inst.error = BAD_ARGS;
8396 return;
8397 }
8398
8399 end_of_line (str);
bfae80f2
RE
8400}
8401
8402/* Thumb specific routines. */
8403
bfae80f2
RE
8404/* Parse an add or subtract instruction, SUBTRACT is non-zero if the opcode
8405 was SUB. */
8406
8407static void
a737bd4d 8408thumb_add_sub (char * str, int subtract)
bfae80f2
RE
8409{
8410 int Rd, Rs, Rn = FAIL;
8411
8412 skip_whitespace (str);
8413
8414 if ((Rd = thumb_reg (&str, THUMB_REG_ANY)) == FAIL
8415 || skip_past_comma (&str) == FAIL)
8416 {
8417 if (! inst.error)
8418 inst.error = BAD_ARGS;
8419 return;
8420 }
8421
8422 if (is_immediate_prefix (*str))
8423 {
8424 Rs = Rd;
8425 str++;
8426 if (my_get_expression (&inst.reloc.exp, &str))
8427 return;
8428 }
8429 else
8430 {
8431 if ((Rs = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8432 return;
8433
8434 if (skip_past_comma (&str) == FAIL)
8435 {
8436 /* Two operand format, shuffle the registers
8437 and pretend there are 3. */
8438 Rn = Rs;
8439 Rs = Rd;
8440 }
8441 else if (is_immediate_prefix (*str))
8442 {
8443 str++;
8444 if (my_get_expression (&inst.reloc.exp, &str))
8445 return;
8446 }
8447 else if ((Rn = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8448 return;
8449 }
8450
8451 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8452 for the latter case, EXPR contains the immediate that was found. */
8453 if (Rn != FAIL)
8454 {
8455 /* All register format. */
8456 if (Rd > 7 || Rs > 7 || Rn > 7)
8457 {
8458 if (Rs != Rd)
8459 {
8460 inst.error = _("dest and source1 must be the same register");
8461 return;
8462 }
8463
8464 /* Can't do this for SUB. */
8465 if (subtract)
8466 {
8467 inst.error = _("subtract valid only on lo regs");
8468 return;
8469 }
8470
8471 inst.instruction = (T_OPCODE_ADD_HI
8472 | (Rd > 7 ? THUMB_H1 : 0)
8473 | (Rn > 7 ? THUMB_H2 : 0));
8474 inst.instruction |= (Rd & 7) | ((Rn & 7) << 3);
8475 }
8476 else
8477 {
8478 inst.instruction = subtract ? T_OPCODE_SUB_R3 : T_OPCODE_ADD_R3;
8479 inst.instruction |= Rd | (Rs << 3) | (Rn << 6);
8480 }
8481 }
8482 else
8483 {
8484 /* Immediate expression, now things start to get nasty. */
8485
8486 /* First deal with HI regs, only very restricted cases allowed:
8487 Adjusting SP, and using PC or SP to get an address. */
8488 if ((Rd > 7 && (Rd != REG_SP || Rs != REG_SP))
8489 || (Rs > 7 && Rs != REG_SP && Rs != REG_PC))
8490 {
8491 inst.error = _("invalid Hi register with immediate");
8492 return;
8493 }
8494
8495 if (inst.reloc.exp.X_op != O_constant)
8496 {
8497 /* Value isn't known yet, all we can do is store all the fragments
8498 we know about in the instruction and let the reloc hacking
8499 work it all out. */
8500 inst.instruction = (subtract ? 0x8000 : 0) | (Rd << 4) | Rs;
8501 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
8502 }
8503 else
8504 {
8505 int offset = inst.reloc.exp.X_add_number;
8506
8507 if (subtract)
358b94bd 8508 offset = - offset;
bfae80f2
RE
8509
8510 if (offset < 0)
8511 {
358b94bd 8512 offset = - offset;
bfae80f2
RE
8513 subtract = 1;
8514
8515 /* Quick check, in case offset is MIN_INT. */
8516 if (offset < 0)
8517 {
8518 inst.error = _("immediate value out of range");
8519 return;
8520 }
8521 }
358b94bd
NC
8522 /* Note - you cannot convert a subtract of 0 into an
8523 add of 0 because the carry flag is set differently. */
8524 else if (offset > 0)
bfae80f2
RE
8525 subtract = 0;
8526
8527 if (Rd == REG_SP)
8528 {
8529 if (offset & ~0x1fc)
8530 {
8531 inst.error = _("invalid immediate value for stack adjust");
8532 return;
b99bd4ef
NC
8533 }
8534 inst.instruction = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
8535 inst.instruction |= offset >> 2;
8536 }
8537 else if (Rs == REG_PC || Rs == REG_SP)
8538 {
8539 if (subtract
8540 || (offset & ~0x3fc))
8541 {
8542 inst.error = _("invalid immediate for address calculation");
8543 return;
8544 }
8545 inst.instruction = (Rs == REG_PC ? T_OPCODE_ADD_PC
8546 : T_OPCODE_ADD_SP);
8547 inst.instruction |= (Rd << 8) | (offset >> 2);
8548 }
8549 else if (Rs == Rd)
8550 {
8551 if (offset & ~0xff)
8552 {
8553 inst.error = _("immediate value out of range");
8554 return;
8555 }
8556 inst.instruction = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
8557 inst.instruction |= (Rd << 8) | offset;
8558 }
8559 else
8560 {
8561 if (offset & ~0x7)
8562 {
8563 inst.error = _("immediate value out of range");
8564 return;
8565 }
8566 inst.instruction = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
8567 inst.instruction |= Rd | (Rs << 3) | (offset << 6);
8568 }
8569 }
8570 }
8571
8572 end_of_line (str);
8573}
8574
8575static void
a737bd4d 8576thumb_shift (char * str, int shift)
b99bd4ef
NC
8577{
8578 int Rd, Rs, Rn = FAIL;
8579
8580 skip_whitespace (str);
8581
8582 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8583 || skip_past_comma (&str) == FAIL)
8584 {
8585 if (! inst.error)
8586 inst.error = BAD_ARGS;
8587 return;
8588 }
8589
8590 if (is_immediate_prefix (*str))
8591 {
8592 /* Two operand immediate format, set Rs to Rd. */
8593 Rs = Rd;
8594 str ++;
8595 if (my_get_expression (&inst.reloc.exp, &str))
8596 return;
8597 }
8598 else
8599 {
8600 if ((Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8601 return;
8602
8603 if (skip_past_comma (&str) == FAIL)
8604 {
8605 /* Two operand format, shuffle the registers
8606 and pretend there are 3. */
8607 Rn = Rs;
8608 Rs = Rd;
8609 }
8610 else if (is_immediate_prefix (*str))
8611 {
8612 str++;
8613 if (my_get_expression (&inst.reloc.exp, &str))
8614 return;
8615 }
8616 else if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8617 return;
8618 }
8619
8620 /* We now have Rd and Rs set to registers, and Rn set to a register or FAIL;
8621 for the latter case, EXPR contains the immediate that was found. */
8622
8623 if (Rn != FAIL)
8624 {
8625 if (Rs != Rd)
8626 {
8627 inst.error = _("source1 and dest must be same register");
8628 return;
8629 }
8630
8631 switch (shift)
8632 {
8633 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_R; break;
8634 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_R; break;
8635 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_R; break;
8636 }
8637
8638 inst.instruction |= Rd | (Rn << 3);
8639 }
8640 else
8641 {
8642 switch (shift)
8643 {
8644 case THUMB_ASR: inst.instruction = T_OPCODE_ASR_I; break;
8645 case THUMB_LSL: inst.instruction = T_OPCODE_LSL_I; break;
8646 case THUMB_LSR: inst.instruction = T_OPCODE_LSR_I; break;
8647 }
8648
8649 if (inst.reloc.exp.X_op != O_constant)
8650 {
8651 /* Value isn't known yet, create a dummy reloc and let reloc
8652 hacking fix it up. */
8653 inst.reloc.type = BFD_RELOC_ARM_THUMB_SHIFT;
8654 }
8655 else
8656 {
8657 unsigned shift_value = inst.reloc.exp.X_add_number;
8658
8659 if (shift_value > 32 || (shift_value == 32 && shift == THUMB_LSL))
8660 {
f03698e6 8661 inst.error = _("invalid immediate for shift");
b99bd4ef
NC
8662 return;
8663 }
8664
8665 /* Shifts of zero are handled by converting to LSL. */
8666 if (shift_value == 0)
8667 inst.instruction = T_OPCODE_LSL_I;
8668
8669 /* Shifts of 32 are encoded as a shift of zero. */
8670 if (shift_value == 32)
8671 shift_value = 0;
8672
8673 inst.instruction |= shift_value << 6;
8674 }
8675
8676 inst.instruction |= Rd | (Rs << 3);
8677 }
8678
8679 end_of_line (str);
8680}
8681
8682static void
a737bd4d 8683thumb_load_store (char * str, int load_store, int size)
b99bd4ef
NC
8684{
8685 int Rd, Rb, Ro = FAIL;
8686
8687 skip_whitespace (str);
8688
8689 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
8690 || skip_past_comma (&str) == FAIL)
8691 {
8692 if (! inst.error)
8693 inst.error = BAD_ARGS;
8694 return;
8695 }
8696
8697 if (*str == '[')
8698 {
8699 str++;
8700 if ((Rb = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
8701 return;
8702
8703 if (skip_past_comma (&str) != FAIL)
8704 {
8705 if (is_immediate_prefix (*str))
8706 {
8707 str++;
8708 if (my_get_expression (&inst.reloc.exp, &str))
8709 return;
8710 }
8711 else if ((Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
8712 return;
8713 }
8714 else
8715 {
8716 inst.reloc.exp.X_op = O_constant;
8717 inst.reloc.exp.X_add_number = 0;
8718 }
8719
8720 if (*str != ']')
8721 {
8722 inst.error = _("expected ']'");
8723 return;
8724 }
8725 str++;
8726 }
8727 else if (*str == '=')
8728 {
f03698e6
RE
8729 if (load_store != THUMB_LOAD)
8730 {
8731 inst.error = _("invalid pseudo operation");
8732 return;
8733 }
8734
b99bd4ef
NC
8735 /* Parse an "ldr Rd, =expr" instruction; this is another pseudo op. */
8736 str++;
8737
8738 skip_whitespace (str);
8739
8740 if (my_get_expression (& inst.reloc.exp, & str))
8741 return;
8742
8743 end_of_line (str);
8744
8745 if ( inst.reloc.exp.X_op != O_constant
8746 && inst.reloc.exp.X_op != O_symbol)
8747 {
8748 inst.error = "Constant expression expected";
8749 return;
8750 }
8751
8752 if (inst.reloc.exp.X_op == O_constant
8753 && ((inst.reloc.exp.X_add_number & ~0xFF) == 0))
8754 {
8755 /* This can be done with a mov instruction. */
8756
8757 inst.instruction = T_OPCODE_MOV_I8 | (Rd << 8);
8758 inst.instruction |= inst.reloc.exp.X_add_number;
8759 return;
8760 }
8761
8762 /* Insert into literal pool. */
8763 if (add_to_lit_pool () == FAIL)
8764 {
8765 if (!inst.error)
8766 inst.error = "literal pool insertion failed";
8767 return;
8768 }
8769
8770 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8771 inst.reloc.pc_rel = 1;
8772 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8773 /* Adjust ARM pipeline offset to Thumb. */
8774 inst.reloc.exp.X_add_number += 4;
8775
8776 return;
8777 }
8778 else
8779 {
8780 if (my_get_expression (&inst.reloc.exp, &str))
8781 return;
8782
8783 inst.instruction = T_OPCODE_LDR_PC | (Rd << 8);
8784 inst.reloc.pc_rel = 1;
8785 inst.reloc.exp.X_add_number -= 4; /* Pipeline offset. */
8786 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8787 end_of_line (str);
8788 return;
8789 }
8790
8791 if (Rb == REG_PC || Rb == REG_SP)
8792 {
8793 if (size != THUMB_WORD)
8794 {
8795 inst.error = _("byte or halfword not valid for base register");
8796 return;
8797 }
8798 else if (Rb == REG_PC && load_store != THUMB_LOAD)
8799 {
f03698e6 8800 inst.error = _("r15 based store not allowed");
b99bd4ef
NC
8801 return;
8802 }
8803 else if (Ro != FAIL)
8804 {
f03698e6 8805 inst.error = _("invalid base register for register offset");
b99bd4ef
NC
8806 return;
8807 }
8808
8809 if (Rb == REG_PC)
8810 inst.instruction = T_OPCODE_LDR_PC;
8811 else if (load_store == THUMB_LOAD)
8812 inst.instruction = T_OPCODE_LDR_SP;
8813 else
8814 inst.instruction = T_OPCODE_STR_SP;
8815
8816 inst.instruction |= Rd << 8;
8817 if (inst.reloc.exp.X_op == O_constant)
8818 {
8819 unsigned offset = inst.reloc.exp.X_add_number;
8820
8821 if (offset & ~0x3fc)
8822 {
8823 inst.error = _("invalid offset");
8824 return;
8825 }
8826
8827 inst.instruction |= offset >> 2;
8828 }
8829 else
8830 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8831 }
8832 else if (Rb > 7)
8833 {
8834 inst.error = _("invalid base register in load/store");
8835 return;
8836 }
8837 else if (Ro == FAIL)
8838 {
8839 /* Immediate offset. */
8840 if (size == THUMB_WORD)
8841 inst.instruction = (load_store == THUMB_LOAD
8842 ? T_OPCODE_LDR_IW : T_OPCODE_STR_IW);
8843 else if (size == THUMB_HALFWORD)
8844 inst.instruction = (load_store == THUMB_LOAD
8845 ? T_OPCODE_LDR_IH : T_OPCODE_STR_IH);
8846 else
8847 inst.instruction = (load_store == THUMB_LOAD
8848 ? T_OPCODE_LDR_IB : T_OPCODE_STR_IB);
8849
8850 inst.instruction |= Rd | (Rb << 3);
8851
8852 if (inst.reloc.exp.X_op == O_constant)
8853 {
8854 unsigned offset = inst.reloc.exp.X_add_number;
8855
8856 if (offset & ~(0x1f << size))
8857 {
f03698e6 8858 inst.error = _("invalid offset");
b99bd4ef
NC
8859 return;
8860 }
8861 inst.instruction |= (offset >> size) << 6;
8862 }
8863 else
8864 inst.reloc.type = BFD_RELOC_ARM_THUMB_OFFSET;
8865 }
8866 else
8867 {
8868 /* Register offset. */
8869 if (size == THUMB_WORD)
8870 inst.instruction = (load_store == THUMB_LOAD
8871 ? T_OPCODE_LDR_RW : T_OPCODE_STR_RW);
8872 else if (size == THUMB_HALFWORD)
8873 inst.instruction = (load_store == THUMB_LOAD
8874 ? T_OPCODE_LDR_RH : T_OPCODE_STR_RH);
8875 else
8876 inst.instruction = (load_store == THUMB_LOAD
8877 ? T_OPCODE_LDR_RB : T_OPCODE_STR_RB);
8878
8879 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
8880 }
8881
8882 end_of_line (str);
8883}
8884
404ff6b5
AH
8885/* A register must be given at this point.
8886
404ff6b5
AH
8887 Shift is the place to put it in inst.instruction.
8888
404ff6b5
AH
8889 Restores input start point on err.
8890 Returns the reg#, or FAIL. */
8891
8892static int
a737bd4d 8893mav_reg_required_here (char ** str, int shift, enum arm_reg_type regtype)
404ff6b5 8894{
6c43fab6
RE
8895 int reg;
8896 char *start = *str;
404ff6b5 8897
6c43fab6 8898 if ((reg = arm_reg_parse (str, all_reg_maps[regtype].htab)) != FAIL)
404ff6b5 8899 {
404ff6b5
AH
8900 if (shift >= 0)
8901 inst.instruction |= reg << shift;
8902
6c43fab6 8903 return reg;
404ff6b5
AH
8904 }
8905
6c43fab6 8906 /* Restore the start point. */
404ff6b5 8907 *str = start;
cc8a6dd0 8908
3631a3c8
NC
8909 /* Try generic coprocessor name if applicable. */
8910 if (regtype == REG_TYPE_MVF ||
8911 regtype == REG_TYPE_MVD ||
8912 regtype == REG_TYPE_MVFX ||
8913 regtype == REG_TYPE_MVDX)
8914 {
8915 if ((reg = arm_reg_parse (str, all_reg_maps[REG_TYPE_CN].htab)) != FAIL)
8916 {
8917 if (shift >= 0)
8918 inst.instruction |= reg << shift;
8919
8920 return reg;
8921 }
8922
8923 /* Restore the start point. */
8924 *str = start;
8925 }
8926
404ff6b5
AH
8927 /* In the few cases where we might be able to accept something else
8928 this error can be overridden. */
6c43fab6 8929 inst.error = _(all_reg_maps[regtype].expected);
cc8a6dd0 8930
404ff6b5
AH
8931 return FAIL;
8932}
8933
a737bd4d
NC
8934/* Cirrus Maverick Instructions. */
8935
8936/* Isnsn like "foo X,Y". */
8937
8938static void
8939do_mav_binops (char * str,
8940 int mode,
8941 enum arm_reg_type reg0,
8942 enum arm_reg_type reg1)
8943{
8944 int shift0, shift1;
8945
8946 shift0 = mode & 0xff;
8947 shift1 = (mode >> 8) & 0xff;
8948
8949 skip_whitespace (str);
8950
8951 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
8952 || skip_past_comma (&str) == FAIL
8953 || mav_reg_required_here (&str, shift1, reg1) == FAIL)
8954 {
8955 if (!inst.error)
8956 inst.error = BAD_ARGS;
8957 }
8958 else
8959 end_of_line (str);
8960}
8961
8962/* Isnsn like "foo X,Y,Z". */
8963
8964static void
8965do_mav_triple (char * str,
8966 int mode,
8967 enum arm_reg_type reg0,
8968 enum arm_reg_type reg1,
8969 enum arm_reg_type reg2)
8970{
8971 int shift0, shift1, shift2;
8972
8973 shift0 = mode & 0xff;
8974 shift1 = (mode >> 8) & 0xff;
8975 shift2 = (mode >> 16) & 0xff;
8976
8977 skip_whitespace (str);
8978
8979 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
8980 || skip_past_comma (&str) == FAIL
8981 || mav_reg_required_here (&str, shift1, reg1) == FAIL
8982 || skip_past_comma (&str) == FAIL
8983 || mav_reg_required_here (&str, shift2, reg2) == FAIL)
8984 {
8985 if (!inst.error)
8986 inst.error = BAD_ARGS;
8987 }
8988 else
8989 end_of_line (str);
8990}
8991
8992/* Wrapper functions. */
8993
8994static void
8995do_mav_binops_1a (char * str)
8996{
8997 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVF);
8998}
8999
9000static void
9001do_mav_binops_1b (char * str)
9002{
9003 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVD);
9004}
9005
9006static void
9007do_mav_binops_1c (char * str)
9008{
9009 do_mav_binops (str, MAV_MODE1, REG_TYPE_RN, REG_TYPE_MVDX);
9010}
9011
9012static void
9013do_mav_binops_1d (char * str)
9014{
9015 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVF);
9016}
9017
9018static void
9019do_mav_binops_1e (char * str)
9020{
9021 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVD);
9022}
9023
9024static void
9025do_mav_binops_1f (char * str)
9026{
9027 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVF);
9028}
9029
9030static void
9031do_mav_binops_1g (char * str)
9032{
9033 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVD);
9034}
9035
9036static void
9037do_mav_binops_1h (char * str)
9038{
9039 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVFX);
9040}
9041
9042static void
9043do_mav_binops_1i (char * str)
9044{
9045 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVFX);
9046}
9047
9048static void
9049do_mav_binops_1j (char * str)
9050{
9051 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVF, REG_TYPE_MVDX);
9052}
9053
9054static void
9055do_mav_binops_1k (char * str)
9056{
9057 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVD, REG_TYPE_MVDX);
9058}
9059
9060static void
9061do_mav_binops_1l (char * str)
9062{
9063 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVF);
9064}
9065
9066static void
9067do_mav_binops_1m (char * str)
9068{
9069 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVD);
9070}
9071
9072static void
9073do_mav_binops_1n (char * str)
9074{
9075 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVFX, REG_TYPE_MVFX);
9076}
9077
9078static void
9079do_mav_binops_1o (char * str)
9080{
9081 do_mav_binops (str, MAV_MODE1, REG_TYPE_MVDX, REG_TYPE_MVDX);
9082}
9083
9084static void
9085do_mav_binops_2a (char * str)
9086{
9087 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVF, REG_TYPE_RN);
9088}
9089
9090static void
9091do_mav_binops_2b (char * str)
9092{
9093 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVD, REG_TYPE_RN);
9094}
404ff6b5 9095
a737bd4d
NC
9096static void
9097do_mav_binops_2c (char * str)
9098{
9099 do_mav_binops (str, MAV_MODE2, REG_TYPE_MVDX, REG_TYPE_RN);
9100}
404ff6b5
AH
9101
9102static void
a737bd4d 9103do_mav_binops_3a (char * str)
6c43fab6 9104{
a737bd4d 9105 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVFX);
6c43fab6
RE
9106}
9107
9108static void
a737bd4d 9109do_mav_binops_3b (char * str)
6c43fab6 9110{
a737bd4d 9111 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVFX, REG_TYPE_MVAX);
6c43fab6
RE
9112}
9113
9114static void
a737bd4d 9115do_mav_binops_3c (char * str)
404ff6b5 9116{
a737bd4d 9117 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVAX, REG_TYPE_MVDX);
404ff6b5
AH
9118}
9119
9120static void
a737bd4d 9121do_mav_binops_3d (char * str)
404ff6b5 9122{
a737bd4d 9123 do_mav_binops (str, MAV_MODE3, REG_TYPE_MVDX, REG_TYPE_MVAX);
404ff6b5
AH
9124}
9125
9126static void
a737bd4d 9127do_mav_triple_4a (char * str)
404ff6b5 9128{
a737bd4d 9129 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_RN);
404ff6b5
AH
9130}
9131
9132static void
a737bd4d 9133do_mav_triple_4b (char * str)
404ff6b5 9134{
a737bd4d 9135 do_mav_triple (str, MAV_MODE4, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_RN);
404ff6b5
AH
9136}
9137
9138static void
a737bd4d 9139do_mav_triple_5a (char * str)
404ff6b5 9140{
a737bd4d 9141 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVF, REG_TYPE_MVF);
404ff6b5
AH
9142}
9143
9144static void
a737bd4d 9145do_mav_triple_5b (char * str)
404ff6b5 9146{
a737bd4d 9147 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVD, REG_TYPE_MVD);
404ff6b5
AH
9148}
9149
6c43fab6 9150static void
a737bd4d 9151do_mav_triple_5c (char * str)
6c43fab6 9152{
a737bd4d 9153 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9154}
9155
9156static void
a737bd4d 9157do_mav_triple_5d (char * str)
6c43fab6 9158{
a737bd4d 9159 do_mav_triple (str, MAV_MODE5, REG_TYPE_RN, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9160}
9161
9162static void
a737bd4d 9163do_mav_triple_5e (char * str)
6c43fab6 9164{
a737bd4d 9165 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVF, REG_TYPE_MVF, REG_TYPE_MVF);
6c43fab6
RE
9166}
9167
9168static void
a737bd4d 9169do_mav_triple_5f (char * str)
6c43fab6 9170{
a737bd4d 9171 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVD, REG_TYPE_MVD, REG_TYPE_MVD);
6c43fab6
RE
9172}
9173
9174static void
a737bd4d 9175do_mav_triple_5g (char * str)
6c43fab6 9176{
a737bd4d 9177 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVFX, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9178}
9179
9180static void
a737bd4d 9181do_mav_triple_5h (char * str)
6c43fab6 9182{
a737bd4d 9183 do_mav_triple (str, MAV_MODE5, REG_TYPE_MVDX, REG_TYPE_MVDX, REG_TYPE_MVDX);
6c43fab6
RE
9184}
9185
a737bd4d
NC
9186/* Isnsn like "foo W,X,Y,Z".
9187 where W=MVAX[0:3] and X,Y,Z=MVFX[0:15]. */
9188
6c43fab6 9189static void
a737bd4d
NC
9190do_mav_quad (char * str,
9191 int mode,
9192 enum arm_reg_type reg0,
9193 enum arm_reg_type reg1,
9194 enum arm_reg_type reg2,
9195 enum arm_reg_type reg3)
6c43fab6 9196{
a737bd4d
NC
9197 int shift0, shift1, shift2, shift3;
9198
9199 shift0= mode & 0xff;
9200 shift1 = (mode >> 8) & 0xff;
9201 shift2 = (mode >> 16) & 0xff;
9202 shift3 = (mode >> 24) & 0xff;
9203
9204 skip_whitespace (str);
9205
9206 if (mav_reg_required_here (&str, shift0, reg0) == FAIL
9207 || skip_past_comma (&str) == FAIL
9208 || mav_reg_required_here (&str, shift1, reg1) == FAIL
9209 || skip_past_comma (&str) == FAIL
9210 || mav_reg_required_here (&str, shift2, reg2) == FAIL
9211 || skip_past_comma (&str) == FAIL
9212 || mav_reg_required_here (&str, shift3, reg3) == FAIL)
9213 {
9214 if (!inst.error)
9215 inst.error = BAD_ARGS;
9216 }
9217 else
9218 end_of_line (str);
6c43fab6
RE
9219}
9220
9221static void
a737bd4d 9222do_mav_quad_6a (char * str)
6c43fab6 9223{
a737bd4d
NC
9224 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVFX, REG_TYPE_MVFX,
9225 REG_TYPE_MVFX);
6c43fab6
RE
9226}
9227
9228static void
a737bd4d 9229do_mav_quad_6b (char * str)
6c43fab6 9230{
a737bd4d
NC
9231 do_mav_quad (str, MAV_MODE6, REG_TYPE_MVAX, REG_TYPE_MVAX, REG_TYPE_MVFX,
9232 REG_TYPE_MVFX);
6c43fab6
RE
9233}
9234
a737bd4d 9235/* cfmvsc32<cond> DSPSC,MVDX[15:0]. */
6c43fab6 9236static void
a737bd4d 9237do_mav_dspsc_1 (char * str)
6c43fab6 9238{
a737bd4d
NC
9239 skip_whitespace (str);
9240
9241 /* cfmvsc32. */
9242 if (mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL
9243 || skip_past_comma (&str) == FAIL
9244 || mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL)
9245 {
9246 if (!inst.error)
9247 inst.error = BAD_ARGS;
9248
9249 return;
9250 }
9251
9252 end_of_line (str);
6c43fab6
RE
9253}
9254
a737bd4d 9255/* cfmv32sc<cond> MVDX[15:0],DSPSC. */
6c43fab6 9256static void
a737bd4d 9257do_mav_dspsc_2 (char * str)
6c43fab6 9258{
a737bd4d
NC
9259 skip_whitespace (str);
9260
9261 /* cfmv32sc. */
9262 if (mav_reg_required_here (&str, 12, REG_TYPE_MVDX) == FAIL
9263 || skip_past_comma (&str) == FAIL
9264 || mav_reg_required_here (&str, -1, REG_TYPE_DSPSC) == FAIL)
9265 {
9266 if (!inst.error)
9267 inst.error = BAD_ARGS;
9268
9269 return;
9270 }
9271
9272 end_of_line (str);
6c43fab6
RE
9273}
9274
a737bd4d
NC
9275/* Maverick shift immediate instructions.
9276 cfsh32<cond> MVFX[15:0],MVFX[15:0],Shift[6:0].
9277 cfsh64<cond> MVDX[15:0],MVDX[15:0],Shift[6:0]. */
9278
6c43fab6 9279static void
a737bd4d
NC
9280do_mav_shift (char * str,
9281 enum arm_reg_type reg0,
9282 enum arm_reg_type reg1)
6c43fab6 9283{
a737bd4d
NC
9284 int error;
9285 int imm, neg = 0;
9286
9287 skip_whitespace (str);
9288
9289 error = 0;
9290
9291 if (mav_reg_required_here (&str, 12, reg0) == FAIL
9292 || skip_past_comma (&str) == FAIL
9293 || mav_reg_required_here (&str, 16, reg1) == FAIL
9294 || skip_past_comma (&str) == FAIL)
9295 {
9296 if (!inst.error)
9297 inst.error = BAD_ARGS;
9298 return;
9299 }
9300
9301 /* Calculate the immediate operand.
9302 The operand is a 7bit signed number. */
9303 skip_whitespace (str);
9304
9305 if (*str == '#')
9306 ++str;
9307
9308 if (!ISDIGIT (*str) && *str != '-')
9309 {
9310 inst.error = _("expecting immediate, 7bit operand");
9311 return;
9312 }
9313
9314 if (*str == '-')
9315 {
9316 neg = 1;
9317 ++str;
9318 }
9319
9320 for (imm = 0; *str && ISDIGIT (*str); ++str)
9321 imm = imm * 10 + *str - '0';
9322
9323 if (imm > 64)
9324 {
9325 inst.error = _("immediate out of range");
9326 return;
9327 }
9328
9329 /* Make negative imm's into 7bit signed numbers. */
9330 if (neg)
9331 {
9332 imm = -imm;
9333 imm &= 0x0000007f;
9334 }
9335
9336 /* Bits 0-3 of the insn should have bits 0-3 of the immediate.
9337 Bits 5-7 of the insn should have bits 4-6 of the immediate.
9338 Bit 4 should be 0. */
9339 imm = (imm & 0xf) | ((imm & 0x70) << 1);
9340
9341 inst.instruction |= imm;
9342 end_of_line (str);
6c43fab6
RE
9343}
9344
9345static void
a737bd4d 9346do_mav_shift_1 (char * str)
6c43fab6 9347{
a737bd4d 9348 do_mav_shift (str, REG_TYPE_MVFX, REG_TYPE_MVFX);
6c43fab6
RE
9349}
9350
9351static void
a737bd4d 9352do_mav_shift_2 (char * str)
6c43fab6 9353{
a737bd4d
NC
9354 do_mav_shift (str, REG_TYPE_MVDX, REG_TYPE_MVDX);
9355}
9356
9357static int
9358mav_parse_offset (char ** str, int * negative)
9359{
9360 char * p = *str;
9361 int offset;
9362
9363 *negative = 0;
9364
9365 skip_whitespace (p);
9366
9367 if (*p == '#')
9368 ++p;
9369
9370 if (*p == '-')
9371 {
9372 *negative = 1;
9373 ++p;
9374 }
9375
9376 if (!ISDIGIT (*p))
9377 {
9378 inst.error = _("offset expected");
9379 return 0;
9380 }
9381
9382 for (offset = 0; *p && ISDIGIT (*p); ++p)
9383 offset = offset * 10 + *p - '0';
9384
9385 if (offset > 0x3fc)
9386 {
9387 inst.error = _("offset out of range");
9388 return 0;
9389 }
9390 if (offset & 0x3)
9391 {
9392 inst.error = _("offset not a multiple of 4");
9393 return 0;
9394 }
9395
9396 *str = p;
9397
9398 return *negative ? -offset : offset;
6c43fab6
RE
9399}
9400
a737bd4d
NC
9401/* Maverick load/store instructions.
9402 <insn><cond> CRd,[Rn,<offset>]{!}.
9403 <insn><cond> CRd,[Rn],<offset>. */
9404
9405static void
9406do_mav_ldst (char * str, enum arm_reg_type reg0)
9407{
9408 int offset, negative;
9409
9410 skip_whitespace (str);
9411
9412 if (mav_reg_required_here (&str, 12, reg0) == FAIL
9413 || skip_past_comma (&str) == FAIL
9414 || *str++ != '['
9415 || reg_required_here (&str, 16) == FAIL)
9416 goto fail_ldst;
9417
9418 if (skip_past_comma (&str) == SUCCESS)
9419 {
9420 /* You are here: "<offset>]{!}". */
9421 inst.instruction |= PRE_INDEX;
9422
9423 offset = mav_parse_offset (&str, &negative);
9424
9425 if (inst.error)
9426 return;
9427
9428 if (*str++ != ']')
9429 {
9430 inst.error = _("missing ]");
9431 return;
9432 }
9433
9434 if (*str == '!')
9435 {
9436 inst.instruction |= WRITE_BACK;
9437 ++str;
9438 }
9439 }
9440 else
9441 {
9442 /* You are here: "], <offset>". */
9443 if (*str++ != ']')
9444 {
9445 inst.error = _("missing ]");
9446 return;
9447 }
9448
9449 if (skip_past_comma (&str) == FAIL
9450 || (offset = mav_parse_offset (&str, &negative), inst.error))
9451 goto fail_ldst;
6c43fab6 9452
a737bd4d
NC
9453 inst.instruction |= CP_T_WB; /* Post indexed, set bit W. */
9454 }
6c43fab6 9455
a737bd4d
NC
9456 if (negative)
9457 offset = -offset;
9458 else
9459 inst.instruction |= CP_T_UD; /* Positive, so set bit U. */
6c43fab6 9460
a737bd4d
NC
9461 inst.instruction |= offset >> 2;
9462 end_of_line (str);
9463 return;
6c43fab6 9464
a737bd4d
NC
9465fail_ldst:
9466 if (!inst.error)
9467 inst.error = BAD_ARGS;
6c43fab6
RE
9468}
9469
9470static void
a737bd4d 9471do_mav_ldst_1 (char * str)
6c43fab6 9472{
a737bd4d 9473 do_mav_ldst (str, REG_TYPE_MVF);
6c43fab6
RE
9474}
9475
9476static void
a737bd4d 9477do_mav_ldst_2 (char * str)
6c43fab6 9478{
a737bd4d 9479 do_mav_ldst (str, REG_TYPE_MVD);
6c43fab6
RE
9480}
9481
9482static void
a737bd4d 9483do_mav_ldst_3 (char * str)
6c43fab6 9484{
a737bd4d 9485 do_mav_ldst (str, REG_TYPE_MVFX);
6c43fab6
RE
9486}
9487
9488static void
a737bd4d 9489do_mav_ldst_4 (char * str)
6c43fab6 9490{
a737bd4d 9491 do_mav_ldst (str, REG_TYPE_MVDX);
6c43fab6
RE
9492}
9493
9494static void
a737bd4d 9495do_t_nop (char * str)
6c43fab6 9496{
a737bd4d
NC
9497 /* Do nothing. */
9498 end_of_line (str);
6c43fab6
RE
9499}
9500
a737bd4d
NC
9501/* Handle the Format 4 instructions that do not have equivalents in other
9502 formats. That is, ADC, AND, EOR, SBC, ROR, TST, NEG, CMN, ORR, MUL,
9503 BIC and MVN. */
6c43fab6
RE
9504
9505static void
a737bd4d 9506do_t_arit (char * str)
6c43fab6 9507{
a737bd4d 9508 int Rd, Rs, Rn;
6c43fab6 9509
6c43fab6
RE
9510 skip_whitespace (str);
9511
a737bd4d 9512 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
6c43fab6 9513 || skip_past_comma (&str) == FAIL
a737bd4d 9514 || (Rs = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
6c43fab6 9515 {
a737bd4d 9516 inst.error = BAD_ARGS;
6c43fab6
RE
9517 return;
9518 }
9519
a737bd4d 9520 if (skip_past_comma (&str) != FAIL)
6c43fab6 9521 {
a737bd4d
NC
9522 /* Three operand format not allowed for TST, CMN, NEG and MVN.
9523 (It isn't allowed for CMP either, but that isn't handled by this
9524 function.) */
9525 if (inst.instruction == T_OPCODE_TST
9526 || inst.instruction == T_OPCODE_CMN
9527 || inst.instruction == T_OPCODE_NEG
9528 || inst.instruction == T_OPCODE_MVN)
9529 {
9530 inst.error = BAD_ARGS;
9531 return;
9532 }
6c43fab6 9533
a737bd4d
NC
9534 if ((Rn = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9535 return;
9536
9537 if (Rs != Rd)
9538 {
9539 inst.error = _("dest and source1 must be the same register");
9540 return;
9541 }
9542 Rs = Rn;
6c43fab6
RE
9543 }
9544
a737bd4d
NC
9545 if (inst.instruction == T_OPCODE_MUL
9546 && Rs == Rd)
9547 as_tsktsk (_("Rs and Rd must be different in MUL"));
9548
9549 inst.instruction |= Rd | (Rs << 3);
6c43fab6 9550 end_of_line (str);
404ff6b5
AH
9551}
9552
9553static void
a737bd4d 9554do_t_add (char * str)
404ff6b5 9555{
a737bd4d 9556 thumb_add_sub (str, 0);
404ff6b5
AH
9557}
9558
9559static void
a737bd4d 9560do_t_asr (char * str)
404ff6b5 9561{
a737bd4d 9562 thumb_shift (str, THUMB_ASR);
404ff6b5
AH
9563}
9564
9565static void
a737bd4d 9566do_t_branch9 (char * str)
404ff6b5 9567{
a737bd4d
NC
9568 if (my_get_expression (&inst.reloc.exp, &str))
9569 return;
9570 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH9;
9571 inst.reloc.pc_rel = 1;
9572 end_of_line (str);
404ff6b5
AH
9573}
9574
9575static void
a737bd4d 9576do_t_branch12 (char * str)
404ff6b5 9577{
a737bd4d
NC
9578 if (my_get_expression (&inst.reloc.exp, &str))
9579 return;
9580 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH12;
9581 inst.reloc.pc_rel = 1;
9582 end_of_line (str);
404ff6b5
AH
9583}
9584
a737bd4d 9585/* Find the real, Thumb encoded start of a Thumb function. */
404ff6b5 9586
a737bd4d
NC
9587static symbolS *
9588find_real_start (symbolS * symbolP)
404ff6b5 9589{
a737bd4d
NC
9590 char * real_start;
9591 const char * name = S_GET_NAME (symbolP);
9592 symbolS * new_target;
404ff6b5 9593
a737bd4d
NC
9594 /* This definition must agree with the one in gcc/config/arm/thumb.c. */
9595#define STUB_NAME ".real_start_of"
404ff6b5 9596
a737bd4d
NC
9597 if (name == NULL)
9598 abort ();
404ff6b5 9599
a737bd4d
NC
9600 /* Names that start with '.' are local labels, not function entry points.
9601 The compiler may generate BL instructions to these labels because it
9602 needs to perform a branch to a far away location. */
9603 if (name[0] == '.')
9604 return symbolP;
404ff6b5 9605
a737bd4d
NC
9606 real_start = malloc (strlen (name) + strlen (STUB_NAME) + 1);
9607 sprintf (real_start, "%s%s", STUB_NAME, name);
404ff6b5 9608
a737bd4d
NC
9609 new_target = symbol_find (real_start);
9610
9611 if (new_target == NULL)
404ff6b5 9612 {
a737bd4d
NC
9613 as_warn ("Failed to find real start of function: %s\n", name);
9614 new_target = symbolP;
404ff6b5 9615 }
404ff6b5 9616
a737bd4d
NC
9617 free (real_start);
9618
9619 return new_target;
9620}
404ff6b5
AH
9621
9622static void
a737bd4d 9623do_t_branch23 (char * str)
404ff6b5 9624{
a737bd4d
NC
9625 if (my_get_expression (& inst.reloc.exp, & str))
9626 return;
404ff6b5 9627
a737bd4d
NC
9628 inst.reloc.type = BFD_RELOC_THUMB_PCREL_BRANCH23;
9629 inst.reloc.pc_rel = 1;
9630 end_of_line (str);
404ff6b5 9631
a737bd4d
NC
9632 /* If the destination of the branch is a defined symbol which does not have
9633 the THUMB_FUNC attribute, then we must be calling a function which has
9634 the (interfacearm) attribute. We look for the Thumb entry point to that
9635 function and change the branch to refer to that function instead. */
9636 if ( inst.reloc.exp.X_op == O_symbol
9637 && inst.reloc.exp.X_add_symbol != NULL
9638 && S_IS_DEFINED (inst.reloc.exp.X_add_symbol)
9639 && ! THUMB_IS_FUNC (inst.reloc.exp.X_add_symbol))
9640 inst.reloc.exp.X_add_symbol =
9641 find_real_start (inst.reloc.exp.X_add_symbol);
404ff6b5
AH
9642}
9643
404ff6b5 9644static void
a737bd4d 9645do_t_bx (char * str)
404ff6b5 9646{
a737bd4d 9647 int reg;
404ff6b5
AH
9648
9649 skip_whitespace (str);
9650
a737bd4d
NC
9651 if ((reg = thumb_reg (&str, THUMB_REG_ANY)) == FAIL)
9652 return;
9653
9654 /* This sets THUMB_H2 from the top bit of reg. */
9655 inst.instruction |= reg << 3;
9656
9657 /* ??? FIXME: Should add a hacky reloc here if reg is REG_PC. The reloc
9658 should cause the alignment to be checked once it is known. This is
9659 because BX PC only works if the instruction is word aligned. */
9660
9661 end_of_line (str);
404ff6b5
AH
9662}
9663
a737bd4d
NC
9664static void
9665do_t_compare (char * str)
9666{
9667 thumb_mov_compare (str, THUMB_COMPARE);
9668}
404ff6b5
AH
9669
9670static void
a737bd4d 9671do_t_ldmstm (char * str)
404ff6b5 9672{
a737bd4d
NC
9673 int Rb;
9674 long range;
404ff6b5
AH
9675
9676 skip_whitespace (str);
9677
a737bd4d
NC
9678 if ((Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL)
9679 return;
404ff6b5 9680
a737bd4d
NC
9681 if (*str != '!')
9682 as_warn (_("inserted missing '!': load/store multiple always writes back base register"));
9683 else
9684 str++;
9685
9686 if (skip_past_comma (&str) == FAIL
9687 || (range = reg_list (&str)) == FAIL)
404ff6b5 9688 {
a737bd4d 9689 if (! inst.error)
404ff6b5
AH
9690 inst.error = BAD_ARGS;
9691 return;
9692 }
9693
620b81c1 9694 if (inst.reloc.type != BFD_RELOC_UNUSED)
404ff6b5 9695 {
a737bd4d 9696 /* This really doesn't seem worth it. */
620b81c1 9697 inst.reloc.type = BFD_RELOC_UNUSED;
a737bd4d 9698 inst.error = _("expression too complex");
404ff6b5
AH
9699 return;
9700 }
9701
a737bd4d 9702 if (range & ~0xff)
404ff6b5 9703 {
a737bd4d 9704 inst.error = _("only lo-regs valid in load/store multiple");
404ff6b5
AH
9705 return;
9706 }
9707
a737bd4d 9708 inst.instruction |= (Rb << 8) | range;
404ff6b5 9709 end_of_line (str);
404ff6b5
AH
9710}
9711
a737bd4d
NC
9712static void
9713do_t_ldr (char * str)
404ff6b5 9714{
a737bd4d
NC
9715 thumb_load_store (str, THUMB_LOAD, THUMB_WORD);
9716}
404ff6b5 9717
a737bd4d
NC
9718static void
9719do_t_ldrb (char * str)
9720{
9721 thumb_load_store (str, THUMB_LOAD, THUMB_BYTE);
9722}
404ff6b5 9723
a737bd4d
NC
9724static void
9725do_t_ldrh (char * str)
9726{
9727 thumb_load_store (str, THUMB_LOAD, THUMB_HALFWORD);
9728}
404ff6b5 9729
a737bd4d
NC
9730static void
9731do_t_lds (char * str)
9732{
9733 int Rd, Rb, Ro;
404ff6b5 9734
a737bd4d 9735 skip_whitespace (str);
404ff6b5 9736
a737bd4d
NC
9737 if ((Rd = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9738 || skip_past_comma (&str) == FAIL
9739 || *str++ != '['
9740 || (Rb = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9741 || skip_past_comma (&str) == FAIL
9742 || (Ro = thumb_reg (&str, THUMB_REG_LO)) == FAIL
9743 || *str++ != ']')
404ff6b5 9744 {
a737bd4d
NC
9745 if (! inst.error)
9746 inst.error = _("syntax: ldrs[b] Rd, [Rb, Ro]");
9747 return;
404ff6b5
AH
9748 }
9749
a737bd4d
NC
9750 inst.instruction |= Rd | (Rb << 3) | (Ro << 6);
9751 end_of_line (str);
9752}
404ff6b5 9753
a737bd4d
NC
9754static void
9755do_t_lsl (char * str)
9756{
9757 thumb_shift (str, THUMB_LSL);
9758}
404ff6b5 9759
a737bd4d
NC
9760static void
9761do_t_lsr (char * str)
9762{
9763 thumb_shift (str, THUMB_LSR);
404ff6b5
AH
9764}
9765
a737bd4d
NC
9766static void
9767do_t_mov (char * str)
9768{
9769 thumb_mov_compare (str, THUMB_MOVE);
9770}
404ff6b5
AH
9771
9772static void
a737bd4d 9773do_t_push_pop (char * str)
404ff6b5 9774{
a737bd4d 9775 long range;
404ff6b5
AH
9776
9777 skip_whitespace (str);
9778
a737bd4d 9779 if ((range = reg_list (&str)) == FAIL)
404ff6b5 9780 {
a737bd4d
NC
9781 if (! inst.error)
9782 inst.error = BAD_ARGS;
9783 return;
9784 }
404ff6b5 9785
620b81c1 9786 if (inst.reloc.type != BFD_RELOC_UNUSED)
a737bd4d
NC
9787 {
9788 /* This really doesn't seem worth it. */
620b81c1 9789 inst.reloc.type = BFD_RELOC_UNUSED;
a737bd4d
NC
9790 inst.error = _("expression too complex");
9791 return;
9792 }
404ff6b5 9793
a737bd4d
NC
9794 if (range & ~0xff)
9795 {
9796 if ((inst.instruction == T_OPCODE_PUSH
9797 && (range & ~0xff) == 1 << REG_LR)
9798 || (inst.instruction == T_OPCODE_POP
9799 && (range & ~0xff) == 1 << REG_PC))
404ff6b5 9800 {
a737bd4d
NC
9801 inst.instruction |= THUMB_PP_PC_LR;
9802 range &= 0xff;
404ff6b5 9803 }
a737bd4d 9804 else
404ff6b5 9805 {
a737bd4d 9806 inst.error = _("invalid register list to push/pop instruction");
404ff6b5
AH
9807 return;
9808 }
404ff6b5
AH
9809 }
9810
a737bd4d 9811 inst.instruction |= range;
404ff6b5 9812 end_of_line (str);
a737bd4d 9813}
404ff6b5 9814
a737bd4d
NC
9815static void
9816do_t_str (char * str)
9817{
9818 thumb_load_store (str, THUMB_STORE, THUMB_WORD);
404ff6b5
AH
9819}
9820
b99bd4ef 9821static void
a737bd4d 9822do_t_strb (char * str)
b99bd4ef 9823{
a737bd4d 9824 thumb_load_store (str, THUMB_STORE, THUMB_BYTE);
b99bd4ef
NC
9825}
9826
a737bd4d
NC
9827static void
9828do_t_strh (char * str)
9829{
9830 thumb_load_store (str, THUMB_STORE, THUMB_HALFWORD);
9831}
b99bd4ef
NC
9832
9833static void
a737bd4d 9834do_t_sub (char * str)
b99bd4ef 9835{
a737bd4d
NC
9836 thumb_add_sub (str, 1);
9837}
b99bd4ef 9838
a737bd4d
NC
9839static void
9840do_t_swi (char * str)
9841{
b99bd4ef
NC
9842 skip_whitespace (str);
9843
a737bd4d
NC
9844 if (my_get_expression (&inst.reloc.exp, &str))
9845 return;
b99bd4ef 9846
a737bd4d
NC
9847 inst.reloc.type = BFD_RELOC_ARM_SWI;
9848 end_of_line (str);
9849}
b99bd4ef 9850
a737bd4d
NC
9851static void
9852do_t_adr (char * str)
9853{
9854 int reg;
b99bd4ef 9855
a737bd4d
NC
9856 /* This is a pseudo-op of the form "adr rd, label" to be converted
9857 into a relative address of the form "add rd, pc, #label-.-4". */
9858 skip_whitespace (str);
9859
9860 /* Store Rd in temporary location inside instruction. */
9861 if ((reg = reg_required_here (&str, 4)) == FAIL
9862 || (reg > 7) /* For Thumb reg must be r0..r7. */
9863 || skip_past_comma (&str) == FAIL
9864 || my_get_expression (&inst.reloc.exp, &str))
9865 {
9866 if (!inst.error)
9867 inst.error = BAD_ARGS;
9868 return;
b99bd4ef
NC
9869 }
9870
a737bd4d
NC
9871 inst.reloc.type = BFD_RELOC_ARM_THUMB_ADD;
9872 inst.reloc.exp.X_add_number -= 4; /* PC relative adjust. */
9873 inst.reloc.pc_rel = 1;
9874 inst.instruction |= REG_PC; /* Rd is already placed into the instruction. */
b99bd4ef 9875
b99bd4ef
NC
9876 end_of_line (str);
9877}
9878
9879static void
a737bd4d
NC
9880insert_reg (const struct reg_entry * r,
9881 struct hash_control * htab)
b99bd4ef 9882{
a737bd4d
NC
9883 int len = strlen (r->name) + 2;
9884 char * buf = xmalloc (len);
9885 char * buf2 = xmalloc (len);
9886 int i = 0;
b99bd4ef 9887
a737bd4d
NC
9888#ifdef REGISTER_PREFIX
9889 buf[i++] = REGISTER_PREFIX;
9890#endif
9891
9892 strcpy (buf + i, r->name);
9893
9894 for (i = 0; buf[i]; i++)
9895 buf2[i] = TOUPPER (buf[i]);
9896
9897 buf2[i] = '\0';
9898
9899 hash_insert (htab, buf, (PTR) r);
9900 hash_insert (htab, buf2, (PTR) r);
b99bd4ef
NC
9901}
9902
9903static void
a737bd4d 9904build_reg_hsh (struct reg_map * map)
b99bd4ef 9905{
a737bd4d
NC
9906 const struct reg_entry *r;
9907
9908 if ((map->htab = hash_new ()) == NULL)
9909 as_fatal (_("virtual memory exhausted"));
9910
9911 for (r = map->names; r->name != NULL; r++)
9912 insert_reg (r, map->htab);
b99bd4ef
NC
9913}
9914
9915static void
a737bd4d
NC
9916insert_reg_alias (char * str,
9917 int regnum,
9918 struct hash_control *htab)
b99bd4ef 9919{
a737bd4d
NC
9920 const char * error;
9921 struct reg_entry * new = xmalloc (sizeof (struct reg_entry));
9922 const char * name = xmalloc (strlen (str) + 1);
9923
9924 strcpy ((char *) name, str);
9925
9926 new->name = name;
9927 new->number = regnum;
9928 new->builtin = FALSE;
9929
9930 error = hash_insert (htab, name, (PTR) new);
9931 if (error)
9932 {
9933 as_bad (_("failed to create an alias for %s, reason: %s"),
9934 str, error);
9935 free ((char *) name);
9936 free (new);
9937 }
b99bd4ef
NC
9938}
9939
a737bd4d 9940/* Look for the .req directive. This is of the form:
b99bd4ef 9941
a737bd4d
NC
9942 new_register_name .req existing_register_name
9943
9944 If we find one, or if it looks sufficiently like one that we want to
9945 handle any error here, return non-zero. Otherwise return zero. */
9946
9947static int
9948create_register_alias (char * newname, char * p)
b99bd4ef 9949{
a737bd4d
NC
9950 char * q;
9951 char c;
b99bd4ef 9952
a737bd4d
NC
9953 q = p;
9954 skip_whitespace (q);
b99bd4ef 9955
a737bd4d
NC
9956 c = *p;
9957 *p = '\0';
b99bd4ef 9958
a737bd4d
NC
9959 if (*q && !strncmp (q, ".req ", 5))
9960 {
9961 char *copy_of_str;
9962 char *r;
b99bd4ef 9963
a737bd4d
NC
9964#ifndef IGNORE_OPCODE_CASE
9965 newname = original_case_string;
9966#endif
9967 copy_of_str = newname;
b99bd4ef 9968
a737bd4d
NC
9969 q += 4;
9970 skip_whitespace (q);
b99bd4ef 9971
a737bd4d
NC
9972 for (r = q; *r != '\0'; r++)
9973 if (*r == ' ')
9974 break;
b99bd4ef 9975
a737bd4d
NC
9976 if (r != q)
9977 {
9978 enum arm_reg_type new_type, old_type;
9979 int old_regno;
9980 char d = *r;
b99bd4ef 9981
a737bd4d
NC
9982 *r = '\0';
9983 old_type = arm_reg_parse_any (q);
9984 *r = d;
9985
9986 new_type = arm_reg_parse_any (newname);
9987
9988 if (new_type == REG_TYPE_MAX)
9989 {
9990 if (old_type != REG_TYPE_MAX)
9991 {
9992 old_regno = arm_reg_parse (&q, all_reg_maps[old_type].htab);
9993 insert_reg_alias (newname, old_regno,
9994 all_reg_maps[old_type].htab);
9995 }
9996 else
9997 as_warn (_("register '%s' does not exist\n"), q);
9998 }
9999 else if (old_type == REG_TYPE_MAX)
10000 {
10001 as_warn (_("ignoring redefinition of register alias '%s' to non-existant register '%s'"),
10002 copy_of_str, q);
10003 }
10004 else
10005 {
10006 /* Do not warn about redefinitions to the same alias. */
10007 if (new_type != old_type
10008 || (arm_reg_parse (&q, all_reg_maps[old_type].htab)
10009 != arm_reg_parse (&q, all_reg_maps[new_type].htab)))
10010 as_warn (_("ignoring redefinition of register alias '%s'"),
10011 copy_of_str);
10012
10013 }
10014 }
10015 else
10016 as_warn (_("ignoring incomplete .req pseuso op"));
10017
10018 *p = c;
10019 return 1;
10020 }
10021
10022 *p = c;
10023 return 0;
b99bd4ef
NC
10024}
10025
10026static void
a737bd4d 10027set_constant_flonums (void)
b99bd4ef 10028{
a737bd4d 10029 int i;
b99bd4ef 10030
a737bd4d
NC
10031 for (i = 0; i < NUM_FLOAT_VALS; i++)
10032 if (atof_ieee ((char *) fp_const[i], 'x', fp_values[i]) == NULL)
10033 abort ();
b99bd4ef
NC
10034}
10035
a737bd4d
NC
10036\f
10037static const struct asm_opcode insns[] =
b99bd4ef 10038{
a737bd4d
NC
10039 /* Core ARM Instructions. */
10040 {"and", 0xe0000000, 3, ARM_EXT_V1, do_arit},
10041 {"ands", 0xe0100000, 3, ARM_EXT_V1, do_arit},
10042 {"eor", 0xe0200000, 3, ARM_EXT_V1, do_arit},
10043 {"eors", 0xe0300000, 3, ARM_EXT_V1, do_arit},
10044 {"sub", 0xe0400000, 3, ARM_EXT_V1, do_arit},
10045 {"subs", 0xe0500000, 3, ARM_EXT_V1, do_arit},
10046 {"rsb", 0xe0600000, 3, ARM_EXT_V1, do_arit},
10047 {"rsbs", 0xe0700000, 3, ARM_EXT_V1, do_arit},
10048 {"add", 0xe0800000, 3, ARM_EXT_V1, do_arit},
10049 {"adds", 0xe0900000, 3, ARM_EXT_V1, do_arit},
10050 {"adc", 0xe0a00000, 3, ARM_EXT_V1, do_arit},
10051 {"adcs", 0xe0b00000, 3, ARM_EXT_V1, do_arit},
10052 {"sbc", 0xe0c00000, 3, ARM_EXT_V1, do_arit},
10053 {"sbcs", 0xe0d00000, 3, ARM_EXT_V1, do_arit},
10054 {"rsc", 0xe0e00000, 3, ARM_EXT_V1, do_arit},
10055 {"rscs", 0xe0f00000, 3, ARM_EXT_V1, do_arit},
10056 {"orr", 0xe1800000, 3, ARM_EXT_V1, do_arit},
10057 {"orrs", 0xe1900000, 3, ARM_EXT_V1, do_arit},
10058 {"bic", 0xe1c00000, 3, ARM_EXT_V1, do_arit},
10059 {"bics", 0xe1d00000, 3, ARM_EXT_V1, do_arit},
10060
10061 {"tst", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
10062 {"tsts", 0xe1100000, 3, ARM_EXT_V1, do_cmp},
10063 {"tstp", 0xe110f000, 3, ARM_EXT_V1, do_cmp},
10064 {"teq", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
10065 {"teqs", 0xe1300000, 3, ARM_EXT_V1, do_cmp},
10066 {"teqp", 0xe130f000, 3, ARM_EXT_V1, do_cmp},
10067 {"cmp", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
10068 {"cmps", 0xe1500000, 3, ARM_EXT_V1, do_cmp},
10069 {"cmpp", 0xe150f000, 3, ARM_EXT_V1, do_cmp},
10070 {"cmn", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
10071 {"cmns", 0xe1700000, 3, ARM_EXT_V1, do_cmp},
10072 {"cmnp", 0xe170f000, 3, ARM_EXT_V1, do_cmp},
10073
10074 {"mov", 0xe1a00000, 3, ARM_EXT_V1, do_mov},
10075 {"movs", 0xe1b00000, 3, ARM_EXT_V1, do_mov},
10076 {"mvn", 0xe1e00000, 3, ARM_EXT_V1, do_mov},
10077 {"mvns", 0xe1f00000, 3, ARM_EXT_V1, do_mov},
10078
10079 {"ldr", 0xe4100000, 3, ARM_EXT_V1, do_ldst},
10080 {"ldrb", 0xe4500000, 3, ARM_EXT_V1, do_ldst},
10081 {"ldrt", 0xe4300000, 3, ARM_EXT_V1, do_ldstt},
10082 {"ldrbt", 0xe4700000, 3, ARM_EXT_V1, do_ldstt},
10083 {"str", 0xe4000000, 3, ARM_EXT_V1, do_ldst},
10084 {"strb", 0xe4400000, 3, ARM_EXT_V1, do_ldst},
10085 {"strt", 0xe4200000, 3, ARM_EXT_V1, do_ldstt},
10086 {"strbt", 0xe4600000, 3, ARM_EXT_V1, do_ldstt},
10087
10088 {"stmia", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
10089 {"stmib", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
10090 {"stmda", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
10091 {"stmdb", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
10092 {"stmfd", 0xe9000000, 3, ARM_EXT_V1, do_ldmstm},
10093 {"stmfa", 0xe9800000, 3, ARM_EXT_V1, do_ldmstm},
10094 {"stmea", 0xe8800000, 3, ARM_EXT_V1, do_ldmstm},
10095 {"stmed", 0xe8000000, 3, ARM_EXT_V1, do_ldmstm},
10096
10097 {"ldmia", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
10098 {"ldmib", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
10099 {"ldmda", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
10100 {"ldmdb", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
10101 {"ldmfd", 0xe8900000, 3, ARM_EXT_V1, do_ldmstm},
10102 {"ldmfa", 0xe8100000, 3, ARM_EXT_V1, do_ldmstm},
10103 {"ldmea", 0xe9100000, 3, ARM_EXT_V1, do_ldmstm},
10104 {"ldmed", 0xe9900000, 3, ARM_EXT_V1, do_ldmstm},
b99bd4ef 10105
a737bd4d
NC
10106 {"swi", 0xef000000, 3, ARM_EXT_V1, do_swi},
10107#ifdef TE_WINCE
10108 /* XXX This is the wrong place to do this. Think multi-arch. */
10109 {"bl", 0xeb000000, 2, ARM_EXT_V1, do_branch},
10110 {"b", 0xea000000, 1, ARM_EXT_V1, do_branch},
10111#else
10112 {"bl", 0xebfffffe, 2, ARM_EXT_V1, do_branch},
10113 {"b", 0xeafffffe, 1, ARM_EXT_V1, do_branch},
10114#endif
b99bd4ef 10115
a737bd4d
NC
10116 /* Pseudo ops. */
10117 {"adr", 0xe28f0000, 3, ARM_EXT_V1, do_adr},
10118 {"adrl", 0xe28f0000, 3, ARM_EXT_V1, do_adrl},
0dd132b6 10119 {"nop", 0xe1a00000, 3, ARM_EXT_V1, do_nop},
b99bd4ef 10120
a737bd4d
NC
10121 /* ARM 2 multiplies. */
10122 {"mul", 0xe0000090, 3, ARM_EXT_V2, do_mul},
10123 {"muls", 0xe0100090, 3, ARM_EXT_V2, do_mul},
10124 {"mla", 0xe0200090, 3, ARM_EXT_V2, do_mla},
10125 {"mlas", 0xe0300090, 3, ARM_EXT_V2, do_mla},
b99bd4ef 10126
a737bd4d
NC
10127 /* Generic coprocessor instructions. */
10128 {"cdp", 0xee000000, 3, ARM_EXT_V2, do_cdp},
10129 {"ldc", 0xec100000, 3, ARM_EXT_V2, do_lstc},
10130 {"ldcl", 0xec500000, 3, ARM_EXT_V2, do_lstc},
10131 {"stc", 0xec000000, 3, ARM_EXT_V2, do_lstc},
10132 {"stcl", 0xec400000, 3, ARM_EXT_V2, do_lstc},
10133 {"mcr", 0xee000010, 3, ARM_EXT_V2, do_co_reg},
10134 {"mrc", 0xee100010, 3, ARM_EXT_V2, do_co_reg},
b99bd4ef 10135
a737bd4d
NC
10136 /* ARM 3 - swp instructions. */
10137 {"swp", 0xe1000090, 3, ARM_EXT_V2S, do_swap},
10138 {"swpb", 0xe1400090, 3, ARM_EXT_V2S, do_swap},
b99bd4ef 10139
a737bd4d
NC
10140 /* ARM 6 Status register instructions. */
10141 {"mrs", 0xe10f0000, 3, ARM_EXT_V3, do_mrs},
10142 {"msr", 0xe120f000, 3, ARM_EXT_V3, do_msr},
10143 /* ScottB: our code uses 0xe128f000 for msr.
10144 NickC: but this is wrong because the bits 16 through 19 are
10145 handled by the PSR_xxx defines above. */
b99bd4ef 10146
a737bd4d
NC
10147 /* ARM 7M long multiplies. */
10148 {"smull", 0xe0c00090, 5, ARM_EXT_V3M, do_mull},
10149 {"smulls", 0xe0d00090, 5, ARM_EXT_V3M, do_mull},
10150 {"umull", 0xe0800090, 5, ARM_EXT_V3M, do_mull},
10151 {"umulls", 0xe0900090, 5, ARM_EXT_V3M, do_mull},
10152 {"smlal", 0xe0e00090, 5, ARM_EXT_V3M, do_mull},
10153 {"smlals", 0xe0f00090, 5, ARM_EXT_V3M, do_mull},
10154 {"umlal", 0xe0a00090, 5, ARM_EXT_V3M, do_mull},
10155 {"umlals", 0xe0b00090, 5, ARM_EXT_V3M, do_mull},
b99bd4ef 10156
a737bd4d
NC
10157 /* ARM Architecture 4. */
10158 {"ldrh", 0xe01000b0, 3, ARM_EXT_V4, do_ldstv4},
10159 {"ldrsh", 0xe01000f0, 3, ARM_EXT_V4, do_ldstv4},
10160 {"ldrsb", 0xe01000d0, 3, ARM_EXT_V4, do_ldstv4},
10161 {"strh", 0xe00000b0, 3, ARM_EXT_V4, do_ldstv4},
b99bd4ef 10162
a737bd4d
NC
10163 /* ARM Architecture 4T. */
10164 /* Note: bx (and blx) are required on V5, even if the processor does
10165 not support Thumb. */
10166 {"bx", 0xe12fff10, 2, ARM_EXT_V4T | ARM_EXT_V5, do_bx},
b99bd4ef 10167
a737bd4d
NC
10168 /* ARM Architecture 5T. */
10169 /* Note: blx has 2 variants, so the .value is set dynamically.
10170 Only one of the variants has conditional execution. */
10171 {"blx", 0xe0000000, 3, ARM_EXT_V5, do_blx},
10172 {"clz", 0xe16f0f10, 3, ARM_EXT_V5, do_clz},
10173 {"bkpt", 0xe1200070, 0, ARM_EXT_V5, do_bkpt},
10174 {"ldc2", 0xfc100000, 0, ARM_EXT_V5, do_lstc2},
10175 {"ldc2l", 0xfc500000, 0, ARM_EXT_V5, do_lstc2},
10176 {"stc2", 0xfc000000, 0, ARM_EXT_V5, do_lstc2},
10177 {"stc2l", 0xfc400000, 0, ARM_EXT_V5, do_lstc2},
10178 {"cdp2", 0xfe000000, 0, ARM_EXT_V5, do_cdp2},
10179 {"mcr2", 0xfe000010, 0, ARM_EXT_V5, do_co_reg2},
10180 {"mrc2", 0xfe100010, 0, ARM_EXT_V5, do_co_reg2},
b99bd4ef 10181
a737bd4d
NC
10182 /* ARM Architecture 5TExP. */
10183 {"smlabb", 0xe1000080, 6, ARM_EXT_V5ExP, do_smla},
10184 {"smlatb", 0xe10000a0, 6, ARM_EXT_V5ExP, do_smla},
10185 {"smlabt", 0xe10000c0, 6, ARM_EXT_V5ExP, do_smla},
10186 {"smlatt", 0xe10000e0, 6, ARM_EXT_V5ExP, do_smla},
b99bd4ef 10187
a737bd4d
NC
10188 {"smlawb", 0xe1200080, 6, ARM_EXT_V5ExP, do_smla},
10189 {"smlawt", 0xe12000c0, 6, ARM_EXT_V5ExP, do_smla},
b99bd4ef 10190
a737bd4d
NC
10191 {"smlalbb", 0xe1400080, 7, ARM_EXT_V5ExP, do_smlal},
10192 {"smlaltb", 0xe14000a0, 7, ARM_EXT_V5ExP, do_smlal},
10193 {"smlalbt", 0xe14000c0, 7, ARM_EXT_V5ExP, do_smlal},
10194 {"smlaltt", 0xe14000e0, 7, ARM_EXT_V5ExP, do_smlal},
b99bd4ef 10195
a737bd4d
NC
10196 {"smulbb", 0xe1600080, 6, ARM_EXT_V5ExP, do_smul},
10197 {"smultb", 0xe16000a0, 6, ARM_EXT_V5ExP, do_smul},
10198 {"smulbt", 0xe16000c0, 6, ARM_EXT_V5ExP, do_smul},
10199 {"smultt", 0xe16000e0, 6, ARM_EXT_V5ExP, do_smul},
b99bd4ef 10200
a737bd4d
NC
10201 {"smulwb", 0xe12000a0, 6, ARM_EXT_V5ExP, do_smul},
10202 {"smulwt", 0xe12000e0, 6, ARM_EXT_V5ExP, do_smul},
b99bd4ef 10203
a737bd4d
NC
10204 {"qadd", 0xe1000050, 4, ARM_EXT_V5ExP, do_qadd},
10205 {"qdadd", 0xe1400050, 5, ARM_EXT_V5ExP, do_qadd},
10206 {"qsub", 0xe1200050, 4, ARM_EXT_V5ExP, do_qadd},
10207 {"qdsub", 0xe1600050, 5, ARM_EXT_V5ExP, do_qadd},
b99bd4ef 10208
a737bd4d
NC
10209 /* ARM Architecture 5TE. */
10210 {"pld", 0xf450f000, 0, ARM_EXT_V5E, do_pld},
10211 {"ldrd", 0xe00000d0, 3, ARM_EXT_V5E, do_ldrd},
10212 {"strd", 0xe00000f0, 3, ARM_EXT_V5E, do_ldrd},
b99bd4ef 10213
a737bd4d
NC
10214 {"mcrr", 0xec400000, 4, ARM_EXT_V5E, do_co_reg2c},
10215 {"mrrc", 0xec500000, 4, ARM_EXT_V5E, do_co_reg2c},
b99bd4ef 10216
a737bd4d
NC
10217 /* ARM Architecture 5TEJ. */
10218 {"bxj", 0xe12fff20, 3, ARM_EXT_V5J, do_bxj},
b99bd4ef 10219
a737bd4d
NC
10220 /* ARM V6. */
10221 { "cps", 0xf1020000, 0, ARM_EXT_V6, do_cps},
10222 { "cpsie", 0xf1080000, 0, ARM_EXT_V6, do_cpsi},
10223 { "cpsid", 0xf10C0000, 0, ARM_EXT_V6, do_cpsi},
10224 { "ldrex", 0xe1900f9f, 5, ARM_EXT_V6, do_ldrex},
10225 { "mcrr2", 0xfc400000, 0, ARM_EXT_V6, do_co_reg2c},
10226 { "mrrc2", 0xfc500000, 0, ARM_EXT_V6, do_co_reg2c},
10227 { "pkhbt", 0xe6800010, 5, ARM_EXT_V6, do_pkhbt},
10228 { "pkhtb", 0xe6800050, 5, ARM_EXT_V6, do_pkhtb},
10229 { "qadd16", 0xe6200f10, 6, ARM_EXT_V6, do_qadd16},
10230 { "qadd8", 0xe6200f90, 5, ARM_EXT_V6, do_qadd16},
10231 { "qaddsubx", 0xe6200f30, 8, ARM_EXT_V6, do_qadd16},
10232 { "qsub16", 0xe6200f70, 6, ARM_EXT_V6, do_qadd16},
10233 { "qsub8", 0xe6200ff0, 5, ARM_EXT_V6, do_qadd16},
10234 { "qsubaddx", 0xe6200f50, 8, ARM_EXT_V6, do_qadd16},
10235 { "sadd16", 0xe6100f10, 6, ARM_EXT_V6, do_qadd16},
10236 { "sadd8", 0xe6100f90, 5, ARM_EXT_V6, do_qadd16},
10237 { "saddsubx", 0xe6100f30, 8, ARM_EXT_V6, do_qadd16},
10238 { "shadd16", 0xe6300f10, 7, ARM_EXT_V6, do_qadd16},
10239 { "shadd8", 0xe6300f90, 6, ARM_EXT_V6, do_qadd16},
10240 { "shaddsubx", 0xe6300f30, 9, ARM_EXT_V6, do_qadd16},
10241 { "shsub16", 0xe6300f70, 7, ARM_EXT_V6, do_qadd16},
10242 { "shsub8", 0xe6300ff0, 6, ARM_EXT_V6, do_qadd16},
10243 { "shsubaddx", 0xe6300f50, 9, ARM_EXT_V6, do_qadd16},
10244 { "ssub16", 0xe6100f70, 6, ARM_EXT_V6, do_qadd16},
10245 { "ssub8", 0xe6100ff0, 5, ARM_EXT_V6, do_qadd16},
10246 { "ssubaddx", 0xe6100f50, 8, ARM_EXT_V6, do_qadd16},
10247 { "uadd16", 0xe6500f10, 6, ARM_EXT_V6, do_qadd16},
10248 { "uadd8", 0xe6500f90, 5, ARM_EXT_V6, do_qadd16},
10249 { "uaddsubx", 0xe6500f30, 8, ARM_EXT_V6, do_qadd16},
10250 { "uhadd16", 0xe6700f10, 7, ARM_EXT_V6, do_qadd16},
10251 { "uhadd8", 0xe6700f90, 6, ARM_EXT_V6, do_qadd16},
10252 { "uhaddsubx", 0xe6700f30, 9, ARM_EXT_V6, do_qadd16},
10253 { "uhsub16", 0xe6700f70, 7, ARM_EXT_V6, do_qadd16},
10254 { "uhsub8", 0xe6700ff0, 6, ARM_EXT_V6, do_qadd16},
10255 { "uhsubaddx", 0xe6700f50, 9, ARM_EXT_V6, do_qadd16},
10256 { "uqadd16", 0xe6600f10, 7, ARM_EXT_V6, do_qadd16},
10257 { "uqadd8", 0xe6600f90, 6, ARM_EXT_V6, do_qadd16},
10258 { "uqaddsubx", 0xe6600f30, 9, ARM_EXT_V6, do_qadd16},
10259 { "uqsub16", 0xe6600f70, 7, ARM_EXT_V6, do_qadd16},
10260 { "uqsub8", 0xe6600ff0, 6, ARM_EXT_V6, do_qadd16},
10261 { "uqsubaddx", 0xe6600f50, 9, ARM_EXT_V6, do_qadd16},
10262 { "usub16", 0xe6500f70, 6, ARM_EXT_V6, do_qadd16},
10263 { "usub8", 0xe6500ff0, 5, ARM_EXT_V6, do_qadd16},
10264 { "usubaddx", 0xe6500f50, 8, ARM_EXT_V6, do_qadd16},
10265 { "rev", 0xe6bf0f30, 3, ARM_EXT_V6, do_rev},
10266 { "rev16", 0xe6bf0fb0, 5, ARM_EXT_V6, do_rev},
10267 { "revsh", 0xe6ff0fb0, 5, ARM_EXT_V6, do_rev},
10268 { "rfeia", 0xf8900a00, 0, ARM_EXT_V6, do_rfe},
10269 { "rfeib", 0xf9900a00, 0, ARM_EXT_V6, do_rfe},
10270 { "rfeda", 0xf8100a00, 0, ARM_EXT_V6, do_rfe},
10271 { "rfedb", 0xf9100a00, 0, ARM_EXT_V6, do_rfe},
10272 { "rfefd", 0xf8900a00, 0, ARM_EXT_V6, do_rfe},
10273 { "rfefa", 0xf9900a00, 0, ARM_EXT_V6, do_rfe},
10274 { "rfeea", 0xf8100a00, 0, ARM_EXT_V6, do_rfe},
10275 { "rfeed", 0xf9100a00, 0, ARM_EXT_V6, do_rfe},
10276 { "sxtah", 0xe6b00070, 5, ARM_EXT_V6, do_sxtah},
10277 { "sxtab16", 0xe6800070, 7, ARM_EXT_V6, do_sxtah},
10278 { "sxtab", 0xe6a00070, 5, ARM_EXT_V6, do_sxtah},
10279 { "sxth", 0xe6bf0070, 4, ARM_EXT_V6, do_sxth},
10280 { "sxtb16", 0xe68f0070, 6, ARM_EXT_V6, do_sxth},
10281 { "sxtb", 0xe6af0070, 4, ARM_EXT_V6, do_sxth},
10282 { "uxtah", 0xe6f00070, 5, ARM_EXT_V6, do_sxtah},
10283 { "uxtab16", 0xe6c00070, 7, ARM_EXT_V6, do_sxtah},
10284 { "uxtab", 0xe6e00070, 5, ARM_EXT_V6, do_sxtah},
10285 { "uxth", 0xe6ff0070, 4, ARM_EXT_V6, do_sxth},
10286 { "uxtb16", 0xe6cf0070, 6, ARM_EXT_V6, do_sxth},
10287 { "uxtb", 0xe6ef0070, 4, ARM_EXT_V6, do_sxth},
10288 { "sel", 0xe68000b0, 3, ARM_EXT_V6, do_qadd16},
10289 { "setend", 0xf1010000, 0, ARM_EXT_V6, do_setend},
10290 { "smlad", 0xe7000010, 5, ARM_EXT_V6, do_smlad},
10291 { "smladx", 0xe7000030, 6, ARM_EXT_V6, do_smlad},
10292 { "smlald", 0xe7400010, 6, ARM_EXT_V6, do_smlald},
10293 { "smlaldx", 0xe7400030, 7, ARM_EXT_V6, do_smlald},
10294 { "smlsd", 0xe7000050, 5, ARM_EXT_V6, do_smlad},
10295 { "smlsdx", 0xe7000070, 6, ARM_EXT_V6, do_smlad},
10296 { "smlsld", 0xe7400050, 6, ARM_EXT_V6, do_smlald},
10297 { "smlsldx", 0xe7400070, 7, ARM_EXT_V6, do_smlald},
10298 { "smmla", 0xe7500010, 5, ARM_EXT_V6, do_smlad},
10299 { "smmlar", 0xe7500030, 6, ARM_EXT_V6, do_smlad},
10300 { "smmls", 0xe75000d0, 5, ARM_EXT_V6, do_smlad},
10301 { "smmlsr", 0xe75000f0, 6, ARM_EXT_V6, do_smlad},
10302 { "smmul", 0xe750f010, 5, ARM_EXT_V6, do_smmul},
10303 { "smmulr", 0xe750f030, 6, ARM_EXT_V6, do_smmul},
10304 { "smuad", 0xe700f010, 5, ARM_EXT_V6, do_smmul},
10305 { "smuadx", 0xe700f030, 6, ARM_EXT_V6, do_smmul},
10306 { "smusd", 0xe700f050, 5, ARM_EXT_V6, do_smmul},
10307 { "smusdx", 0xe700f070, 6, ARM_EXT_V6, do_smmul},
10308 { "srsia", 0xf8cd0500, 0, ARM_EXT_V6, do_srs},
10309 { "srsib", 0xf9cd0500, 0, ARM_EXT_V6, do_srs},
10310 { "srsda", 0xf84d0500, 0, ARM_EXT_V6, do_srs},
10311 { "srsdb", 0xf94d0500, 0, ARM_EXT_V6, do_srs},
10312 { "ssat", 0xe6a00010, 4, ARM_EXT_V6, do_ssat},
10313 { "ssat16", 0xe6a00f30, 6, ARM_EXT_V6, do_ssat16},
10314 { "strex", 0xe1800f90, 5, ARM_EXT_V6, do_strex},
10315 { "umaal", 0xe0400090, 5, ARM_EXT_V6, do_umaal},
10316 { "usad8", 0xe780f010, 5, ARM_EXT_V6, do_smmul},
10317 { "usada8", 0xe7800010, 6, ARM_EXT_V6, do_smlad},
10318 { "usat", 0xe6e00010, 4, ARM_EXT_V6, do_usat},
10319 { "usat16", 0xe6e00f30, 6, ARM_EXT_V6, do_usat16},
b99bd4ef 10320
0dd132b6
NC
10321 /* ARM V6K. */
10322 { "clrex", 0xf57ff01f, 0, ARM_EXT_V6K, do_empty},
10323 { "ldrexb", 0xe1d00f9f, 6, ARM_EXT_V6K, do_ldrex},
10324 { "ldrexd", 0xe1b00f9f, 6, ARM_EXT_V6K, do_ldrex},
10325 { "ldrexh", 0xe1f00f9f, 6, ARM_EXT_V6K, do_ldrex},
10326 { "sev", 0xe320f004, 3, ARM_EXT_V6K, do_empty},
10327 { "strexb", 0xe1c00f90, 6, ARM_EXT_V6K, do_strex},
10328 { "strexd", 0xe1a00f90, 6, ARM_EXT_V6K, do_strex},
10329 { "strexh", 0xe1e00f90, 6, ARM_EXT_V6K, do_strex},
10330 { "wfe", 0xe320f002, 3, ARM_EXT_V6K, do_empty},
10331 { "wfi", 0xe320f003, 3, ARM_EXT_V6K, do_empty},
10332 { "yield", 0xe320f001, 5, ARM_EXT_V6K, do_empty},
7ed4c4c5 10333
0dd132b6
NC
10334 /* ARM V6Z. */
10335 { "smi", 0xe1600070, 3, ARM_EXT_V6Z, do_smi},
10336
b05fe5cf
ZW
10337 /* ARM V6T2. */
10338 { "bfc", 0xe7c0001f, 3, ARM_EXT_V6T2, do_bfc},
10339 { "bfi", 0xe7c00010, 3, ARM_EXT_V6T2, do_bfi},
10340 { "mls", 0xe0600090, 3, ARM_EXT_V6T2, do_mls},
10341 { "movw", 0xe3000000, 4, ARM_EXT_V6T2, do_mov16},
10342 { "movt", 0xe3400000, 4, ARM_EXT_V6T2, do_mov16},
10343 { "rbit", 0xe3ff0f30, 4, ARM_EXT_V6T2, do_rbit},
10344 { "sbfx", 0xe7a00050, 4, ARM_EXT_V6T2, do_bfx},
10345 { "ubfx", 0xe7e00050, 4, ARM_EXT_V6T2, do_bfx},
10346
10347 { "ldrht", 0xe03000b0, 3, ARM_EXT_V6T2, do_ldsttv4},
10348 { "ldrsht", 0xe03000f0, 3, ARM_EXT_V6T2, do_ldsttv4},
10349 { "ldrsbt", 0xe03000d0, 3, ARM_EXT_V6T2, do_ldsttv4},
10350 { "strht", 0xe02000b0, 3, ARM_EXT_V6T2, do_ldsttv4},
10351
a737bd4d
NC
10352 /* Core FPA instruction set (V1). */
10353 {"wfs", 0xee200110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
10354 {"rfs", 0xee300110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
10355 {"wfc", 0xee400110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
10356 {"rfc", 0xee500110, 3, FPU_FPA_EXT_V1, do_fpa_ctrl},
b99bd4ef 10357
a737bd4d
NC
10358 {"ldfs", 0xec100100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10359 {"ldfd", 0xec108100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10360 {"ldfe", 0xec500100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10361 {"ldfp", 0xec508100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
b99bd4ef 10362
a737bd4d
NC
10363 {"stfs", 0xec000100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10364 {"stfd", 0xec008100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10365 {"stfe", 0xec400100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
10366 {"stfp", 0xec408100, 3, FPU_FPA_EXT_V1, do_fpa_ldst},
b99bd4ef 10367
a737bd4d
NC
10368 {"mvfs", 0xee008100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10369 {"mvfsp", 0xee008120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10370 {"mvfsm", 0xee008140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10371 {"mvfsz", 0xee008160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10372 {"mvfd", 0xee008180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10373 {"mvfdp", 0xee0081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10374 {"mvfdm", 0xee0081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10375 {"mvfdz", 0xee0081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10376 {"mvfe", 0xee088100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10377 {"mvfep", 0xee088120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10378 {"mvfem", 0xee088140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10379 {"mvfez", 0xee088160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10380
a737bd4d
NC
10381 {"mnfs", 0xee108100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10382 {"mnfsp", 0xee108120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10383 {"mnfsm", 0xee108140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10384 {"mnfsz", 0xee108160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10385 {"mnfd", 0xee108180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10386 {"mnfdp", 0xee1081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10387 {"mnfdm", 0xee1081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10388 {"mnfdz", 0xee1081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10389 {"mnfe", 0xee188100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10390 {"mnfep", 0xee188120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10391 {"mnfem", 0xee188140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10392 {"mnfez", 0xee188160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10393
a737bd4d
NC
10394 {"abss", 0xee208100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10395 {"abssp", 0xee208120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10396 {"abssm", 0xee208140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10397 {"abssz", 0xee208160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10398 {"absd", 0xee208180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10399 {"absdp", 0xee2081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10400 {"absdm", 0xee2081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10401 {"absdz", 0xee2081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10402 {"abse", 0xee288100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10403 {"absep", 0xee288120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10404 {"absem", 0xee288140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10405 {"absez", 0xee288160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10406
a737bd4d
NC
10407 {"rnds", 0xee308100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10408 {"rndsp", 0xee308120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10409 {"rndsm", 0xee308140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10410 {"rndsz", 0xee308160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10411 {"rndd", 0xee308180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10412 {"rnddp", 0xee3081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10413 {"rnddm", 0xee3081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10414 {"rnddz", 0xee3081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10415 {"rnde", 0xee388100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10416 {"rndep", 0xee388120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10417 {"rndem", 0xee388140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10418 {"rndez", 0xee388160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10419
a737bd4d
NC
10420 {"sqts", 0xee408100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10421 {"sqtsp", 0xee408120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10422 {"sqtsm", 0xee408140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10423 {"sqtsz", 0xee408160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10424 {"sqtd", 0xee408180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10425 {"sqtdp", 0xee4081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10426 {"sqtdm", 0xee4081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10427 {"sqtdz", 0xee4081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10428 {"sqte", 0xee488100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10429 {"sqtep", 0xee488120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10430 {"sqtem", 0xee488140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10431 {"sqtez", 0xee488160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10432
a737bd4d
NC
10433 {"logs", 0xee508100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10434 {"logsp", 0xee508120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10435 {"logsm", 0xee508140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10436 {"logsz", 0xee508160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10437 {"logd", 0xee508180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10438 {"logdp", 0xee5081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10439 {"logdm", 0xee5081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10440 {"logdz", 0xee5081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10441 {"loge", 0xee588100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10442 {"logep", 0xee588120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10443 {"logem", 0xee588140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10444 {"logez", 0xee588160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10445
a737bd4d
NC
10446 {"lgns", 0xee608100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10447 {"lgnsp", 0xee608120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10448 {"lgnsm", 0xee608140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10449 {"lgnsz", 0xee608160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10450 {"lgnd", 0xee608180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10451 {"lgndp", 0xee6081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10452 {"lgndm", 0xee6081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10453 {"lgndz", 0xee6081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10454 {"lgne", 0xee688100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10455 {"lgnep", 0xee688120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10456 {"lgnem", 0xee688140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10457 {"lgnez", 0xee688160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10458
a737bd4d
NC
10459 {"exps", 0xee708100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10460 {"expsp", 0xee708120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10461 {"expsm", 0xee708140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10462 {"expsz", 0xee708160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10463 {"expd", 0xee708180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10464 {"expdp", 0xee7081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10465 {"expdm", 0xee7081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10466 {"expdz", 0xee7081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10467 {"expe", 0xee788100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10468 {"expep", 0xee788120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10469 {"expem", 0xee788140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10470 {"expdz", 0xee788160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10471
a737bd4d
NC
10472 {"sins", 0xee808100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10473 {"sinsp", 0xee808120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10474 {"sinsm", 0xee808140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10475 {"sinsz", 0xee808160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10476 {"sind", 0xee808180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10477 {"sindp", 0xee8081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10478 {"sindm", 0xee8081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10479 {"sindz", 0xee8081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10480 {"sine", 0xee888100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10481 {"sinep", 0xee888120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10482 {"sinem", 0xee888140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10483 {"sinez", 0xee888160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10484
a737bd4d
NC
10485 {"coss", 0xee908100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10486 {"cossp", 0xee908120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10487 {"cossm", 0xee908140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10488 {"cossz", 0xee908160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10489 {"cosd", 0xee908180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10490 {"cosdp", 0xee9081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10491 {"cosdm", 0xee9081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10492 {"cosdz", 0xee9081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10493 {"cose", 0xee988100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10494 {"cosep", 0xee988120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10495 {"cosem", 0xee988140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10496 {"cosez", 0xee988160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10497
a737bd4d
NC
10498 {"tans", 0xeea08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10499 {"tansp", 0xeea08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10500 {"tansm", 0xeea08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10501 {"tansz", 0xeea08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10502 {"tand", 0xeea08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10503 {"tandp", 0xeea081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10504 {"tandm", 0xeea081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10505 {"tandz", 0xeea081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10506 {"tane", 0xeea88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10507 {"tanep", 0xeea88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10508 {"tanem", 0xeea88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10509 {"tanez", 0xeea88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10510
a737bd4d
NC
10511 {"asns", 0xeeb08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10512 {"asnsp", 0xeeb08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10513 {"asnsm", 0xeeb08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10514 {"asnsz", 0xeeb08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10515 {"asnd", 0xeeb08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10516 {"asndp", 0xeeb081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10517 {"asndm", 0xeeb081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10518 {"asndz", 0xeeb081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10519 {"asne", 0xeeb88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10520 {"asnep", 0xeeb88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10521 {"asnem", 0xeeb88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10522 {"asnez", 0xeeb88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10523
a737bd4d
NC
10524 {"acss", 0xeec08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10525 {"acssp", 0xeec08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10526 {"acssm", 0xeec08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10527 {"acssz", 0xeec08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10528 {"acsd", 0xeec08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10529 {"acsdp", 0xeec081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10530 {"acsdm", 0xeec081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10531 {"acsdz", 0xeec081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10532 {"acse", 0xeec88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10533 {"acsep", 0xeec88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10534 {"acsem", 0xeec88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10535 {"acsez", 0xeec88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10536
a737bd4d
NC
10537 {"atns", 0xeed08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10538 {"atnsp", 0xeed08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10539 {"atnsm", 0xeed08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10540 {"atnsz", 0xeed08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10541 {"atnd", 0xeed08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10542 {"atndp", 0xeed081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10543 {"atndm", 0xeed081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10544 {"atndz", 0xeed081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10545 {"atne", 0xeed88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10546 {"atnep", 0xeed88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10547 {"atnem", 0xeed88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10548 {"atnez", 0xeed88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10549
a737bd4d
NC
10550 {"urds", 0xeee08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10551 {"urdsp", 0xeee08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10552 {"urdsm", 0xeee08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10553 {"urdsz", 0xeee08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10554 {"urdd", 0xeee08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10555 {"urddp", 0xeee081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10556 {"urddm", 0xeee081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10557 {"urddz", 0xeee081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10558 {"urde", 0xeee88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10559 {"urdep", 0xeee88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10560 {"urdem", 0xeee88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10561 {"urdez", 0xeee88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10562
a737bd4d
NC
10563 {"nrms", 0xeef08100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10564 {"nrmsp", 0xeef08120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10565 {"nrmsm", 0xeef08140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10566 {"nrmsz", 0xeef08160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10567 {"nrmd", 0xeef08180, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10568 {"nrmdp", 0xeef081a0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10569 {"nrmdm", 0xeef081c0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10570 {"nrmdz", 0xeef081e0, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10571 {"nrme", 0xeef88100, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10572 {"nrmep", 0xeef88120, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10573 {"nrmem", 0xeef88140, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
10574 {"nrmez", 0xeef88160, 3, FPU_FPA_EXT_V1, do_fpa_monadic},
b99bd4ef 10575
a737bd4d
NC
10576 {"adfs", 0xee000100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10577 {"adfsp", 0xee000120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10578 {"adfsm", 0xee000140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10579 {"adfsz", 0xee000160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10580 {"adfd", 0xee000180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10581 {"adfdp", 0xee0001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10582 {"adfdm", 0xee0001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10583 {"adfdz", 0xee0001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10584 {"adfe", 0xee080100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10585 {"adfep", 0xee080120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10586 {"adfem", 0xee080140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10587 {"adfez", 0xee080160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10588
a737bd4d
NC
10589 {"sufs", 0xee200100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10590 {"sufsp", 0xee200120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10591 {"sufsm", 0xee200140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10592 {"sufsz", 0xee200160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10593 {"sufd", 0xee200180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10594 {"sufdp", 0xee2001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10595 {"sufdm", 0xee2001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10596 {"sufdz", 0xee2001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10597 {"sufe", 0xee280100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10598 {"sufep", 0xee280120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10599 {"sufem", 0xee280140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10600 {"sufez", 0xee280160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10601
a737bd4d
NC
10602 {"rsfs", 0xee300100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10603 {"rsfsp", 0xee300120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10604 {"rsfsm", 0xee300140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10605 {"rsfsz", 0xee300160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10606 {"rsfd", 0xee300180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10607 {"rsfdp", 0xee3001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10608 {"rsfdm", 0xee3001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10609 {"rsfdz", 0xee3001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10610 {"rsfe", 0xee380100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10611 {"rsfep", 0xee380120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10612 {"rsfem", 0xee380140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10613 {"rsfez", 0xee380160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10614
a737bd4d
NC
10615 {"mufs", 0xee100100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10616 {"mufsp", 0xee100120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10617 {"mufsm", 0xee100140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10618 {"mufsz", 0xee100160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10619 {"mufd", 0xee100180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10620 {"mufdp", 0xee1001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10621 {"mufdm", 0xee1001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10622 {"mufdz", 0xee1001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10623 {"mufe", 0xee180100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10624 {"mufep", 0xee180120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10625 {"mufem", 0xee180140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10626 {"mufez", 0xee180160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10627
a737bd4d
NC
10628 {"dvfs", 0xee400100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10629 {"dvfsp", 0xee400120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10630 {"dvfsm", 0xee400140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10631 {"dvfsz", 0xee400160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10632 {"dvfd", 0xee400180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10633 {"dvfdp", 0xee4001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10634 {"dvfdm", 0xee4001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10635 {"dvfdz", 0xee4001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10636 {"dvfe", 0xee480100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10637 {"dvfep", 0xee480120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10638 {"dvfem", 0xee480140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10639 {"dvfez", 0xee480160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10640
a737bd4d
NC
10641 {"rdfs", 0xee500100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10642 {"rdfsp", 0xee500120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10643 {"rdfsm", 0xee500140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10644 {"rdfsz", 0xee500160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10645 {"rdfd", 0xee500180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10646 {"rdfdp", 0xee5001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10647 {"rdfdm", 0xee5001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10648 {"rdfdz", 0xee5001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10649 {"rdfe", 0xee580100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10650 {"rdfep", 0xee580120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10651 {"rdfem", 0xee580140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10652 {"rdfez", 0xee580160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10653
a737bd4d
NC
10654 {"pows", 0xee600100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10655 {"powsp", 0xee600120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10656 {"powsm", 0xee600140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10657 {"powsz", 0xee600160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10658 {"powd", 0xee600180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10659 {"powdp", 0xee6001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10660 {"powdm", 0xee6001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10661 {"powdz", 0xee6001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10662 {"powe", 0xee680100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10663 {"powep", 0xee680120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10664 {"powem", 0xee680140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10665 {"powez", 0xee680160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10666
a737bd4d
NC
10667 {"rpws", 0xee700100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10668 {"rpwsp", 0xee700120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10669 {"rpwsm", 0xee700140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10670 {"rpwsz", 0xee700160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10671 {"rpwd", 0xee700180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10672 {"rpwdp", 0xee7001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10673 {"rpwdm", 0xee7001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10674 {"rpwdz", 0xee7001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10675 {"rpwe", 0xee780100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10676 {"rpwep", 0xee780120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10677 {"rpwem", 0xee780140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10678 {"rpwez", 0xee780160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10679
a737bd4d
NC
10680 {"rmfs", 0xee800100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10681 {"rmfsp", 0xee800120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10682 {"rmfsm", 0xee800140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10683 {"rmfsz", 0xee800160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10684 {"rmfd", 0xee800180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10685 {"rmfdp", 0xee8001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10686 {"rmfdm", 0xee8001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10687 {"rmfdz", 0xee8001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10688 {"rmfe", 0xee880100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10689 {"rmfep", 0xee880120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10690 {"rmfem", 0xee880140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10691 {"rmfez", 0xee880160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10692
a737bd4d
NC
10693 {"fmls", 0xee900100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10694 {"fmlsp", 0xee900120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10695 {"fmlsm", 0xee900140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10696 {"fmlsz", 0xee900160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10697 {"fmld", 0xee900180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10698 {"fmldp", 0xee9001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10699 {"fmldm", 0xee9001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10700 {"fmldz", 0xee9001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10701 {"fmle", 0xee980100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10702 {"fmlep", 0xee980120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10703 {"fmlem", 0xee980140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10704 {"fmlez", 0xee980160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
6c43fab6 10705
a737bd4d
NC
10706 {"fdvs", 0xeea00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10707 {"fdvsp", 0xeea00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10708 {"fdvsm", 0xeea00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10709 {"fdvsz", 0xeea00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10710 {"fdvd", 0xeea00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10711 {"fdvdp", 0xeea001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10712 {"fdvdm", 0xeea001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10713 {"fdvdz", 0xeea001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10714 {"fdve", 0xeea80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10715 {"fdvep", 0xeea80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10716 {"fdvem", 0xeea80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10717 {"fdvez", 0xeea80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
6c43fab6 10718
a737bd4d
NC
10719 {"frds", 0xeeb00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10720 {"frdsp", 0xeeb00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10721 {"frdsm", 0xeeb00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10722 {"frdsz", 0xeeb00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10723 {"frdd", 0xeeb00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10724 {"frddp", 0xeeb001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10725 {"frddm", 0xeeb001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10726 {"frddz", 0xeeb001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10727 {"frde", 0xeeb80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10728 {"frdep", 0xeeb80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10729 {"frdem", 0xeeb80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10730 {"frdez", 0xeeb80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
6c43fab6 10731
a737bd4d
NC
10732 {"pols", 0xeec00100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10733 {"polsp", 0xeec00120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10734 {"polsm", 0xeec00140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10735 {"polsz", 0xeec00160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10736 {"pold", 0xeec00180, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10737 {"poldp", 0xeec001a0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10738 {"poldm", 0xeec001c0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10739 {"poldz", 0xeec001e0, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10740 {"pole", 0xeec80100, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10741 {"polep", 0xeec80120, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10742 {"polem", 0xeec80140, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
10743 {"polez", 0xeec80160, 3, FPU_FPA_EXT_V1, do_fpa_dyadic},
b99bd4ef 10744
a737bd4d
NC
10745 {"cmf", 0xee90f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10746 {"cmfe", 0xeed0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10747 {"cnf", 0xeeb0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10748 {"cnfe", 0xeef0f110, 3, FPU_FPA_EXT_V1, do_fpa_cmp},
10749 /* The FPA10 data sheet suggests that the 'E' of cmfe/cnfe should
10750 not be an optional suffix, but part of the instruction. To be
10751 compatible, we accept either. */
10752 {"cmfe", 0xeed0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
10753 {"cnfe", 0xeef0f110, 4, FPU_FPA_EXT_V1, do_fpa_cmp},
b99bd4ef 10754
a737bd4d
NC
10755 {"flts", 0xee000110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10756 {"fltsp", 0xee000130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10757 {"fltsm", 0xee000150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10758 {"fltsz", 0xee000170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10759 {"fltd", 0xee000190, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10760 {"fltdp", 0xee0001b0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10761 {"fltdm", 0xee0001d0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10762 {"fltdz", 0xee0001f0, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10763 {"flte", 0xee080110, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10764 {"fltep", 0xee080130, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10765 {"fltem", 0xee080150, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
10766 {"fltez", 0xee080170, 3, FPU_FPA_EXT_V1, do_fpa_from_reg},
6c43fab6 10767
a737bd4d
NC
10768 /* The implementation of the FIX instruction is broken on some
10769 assemblers, in that it accepts a precision specifier as well as a
10770 rounding specifier, despite the fact that this is meaningless.
10771 To be more compatible, we accept it as well, though of course it
10772 does not set any bits. */
10773 {"fix", 0xee100110, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10774 {"fixp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10775 {"fixm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10776 {"fixz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10777 {"fixsp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10778 {"fixsm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10779 {"fixsz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10780 {"fixdp", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10781 {"fixdm", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10782 {"fixdz", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10783 {"fixep", 0xee100130, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10784 {"fixem", 0xee100150, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
10785 {"fixez", 0xee100170, 3, FPU_FPA_EXT_V1, do_fpa_to_reg},
6c43fab6 10786
a737bd4d
NC
10787 /* Instructions that were new with the real FPA, call them V2. */
10788 {"lfm", 0xec100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10789 {"lfmfd", 0xec900200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10790 {"lfmea", 0xed100200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10791 {"sfm", 0xec000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10792 {"sfmfd", 0xed000200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
10793 {"sfmea", 0xec800200, 3, FPU_FPA_EXT_V2, do_fpa_ldmstm},
6c43fab6 10794
a737bd4d
NC
10795 /* VFP V1xD (single precision). */
10796 /* Moves and type conversions. */
10797 {"fcpys", 0xeeb00a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10798 {"fmrs", 0xee100a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_sp},
10799 {"fmsr", 0xee000a10, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_from_reg},
10800 {"fmstat", 0xeef1fa10, 6, FPU_VFP_EXT_V1xD, do_empty},
10801 {"fsitos", 0xeeb80ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10802 {"fuitos", 0xeeb80a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10803 {"ftosis", 0xeebd0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10804 {"ftosizs", 0xeebd0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10805 {"ftouis", 0xeebc0a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10806 {"ftouizs", 0xeebc0ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10807 {"fmrx", 0xeef00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_reg_from_ctrl},
10808 {"fmxr", 0xeee00a10, 4, FPU_VFP_EXT_V1xD, do_vfp_ctrl_from_reg},
6c43fab6 10809
a737bd4d
NC
10810 /* Memory operations. */
10811 {"flds", 0xed100a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
10812 {"fsts", 0xed000a00, 4, FPU_VFP_EXT_V1xD, do_vfp_sp_ldst},
10813 {"fldmias", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10814 {"fldmfds", 0xec900a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10815 {"fldmdbs", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10816 {"fldmeas", 0xed300a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10817 {"fldmiax", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10818 {"fldmfdx", 0xec900b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10819 {"fldmdbx", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
10820 {"fldmeax", 0xed300b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
10821 {"fstmias", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10822 {"fstmeas", 0xec800a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmia},
10823 {"fstmdbs", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10824 {"fstmfds", 0xed200a00, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_ldstmdb},
10825 {"fstmiax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10826 {"fstmeax", 0xec800b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmia},
10827 {"fstmdbx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
10828 {"fstmfdx", 0xed200b00, 7, FPU_VFP_EXT_V1xD, do_vfp_xp_ldstmdb},
6c43fab6 10829
a737bd4d
NC
10830 /* Monadic operations. */
10831 {"fabss", 0xeeb00ac0, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10832 {"fnegs", 0xeeb10a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10833 {"fsqrts", 0xeeb10ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
6c43fab6 10834
a737bd4d
NC
10835 /* Dyadic operations. */
10836 {"fadds", 0xee300a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10837 {"fsubs", 0xee300a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10838 {"fmuls", 0xee200a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10839 {"fdivs", 0xee800a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10840 {"fmacs", 0xee000a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10841 {"fmscs", 0xee100a00, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10842 {"fnmuls", 0xee200a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10843 {"fnmacs", 0xee000a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
10844 {"fnmscs", 0xee100a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_dyadic},
6c43fab6 10845
a737bd4d
NC
10846 /* Comparisons. */
10847 {"fcmps", 0xeeb40a40, 5, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10848 {"fcmpzs", 0xeeb50a40, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
10849 {"fcmpes", 0xeeb40ac0, 6, FPU_VFP_EXT_V1xD, do_vfp_sp_monadic},
10850 {"fcmpezs", 0xeeb50ac0, 7, FPU_VFP_EXT_V1xD, do_vfp_sp_compare_z},
6c43fab6 10851
a737bd4d
NC
10852 /* VFP V1 (Double precision). */
10853 /* Moves and type conversions. */
10854 {"fcpyd", 0xeeb00b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10855 {"fcvtds", 0xeeb70ac0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
10856 {"fcvtsd", 0xeeb70bc0, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10857 {"fmdhr", 0xee200b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
10858 {"fmdlr", 0xee000b10, 5, FPU_VFP_EXT_V1, do_vfp_dp_from_reg},
10859 {"fmrdh", 0xee300b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
10860 {"fmrdl", 0xee100b10, 5, FPU_VFP_EXT_V1, do_vfp_reg_from_dp},
10861 {"fsitod", 0xeeb80bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
10862 {"fuitod", 0xeeb80b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_sp_cvt},
10863 {"ftosid", 0xeebd0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10864 {"ftosizd", 0xeebd0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10865 {"ftouid", 0xeebc0b40, 6, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
10866 {"ftouizd", 0xeebc0bc0, 7, FPU_VFP_EXT_V1, do_vfp_sp_dp_cvt},
6c43fab6 10867
a737bd4d
NC
10868 /* Memory operations. */
10869 {"fldd", 0xed100b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
10870 {"fstd", 0xed000b00, 4, FPU_VFP_EXT_V1, do_vfp_dp_ldst},
10871 {"fldmiad", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10872 {"fldmfdd", 0xec900b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10873 {"fldmdbd", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
10874 {"fldmead", 0xed300b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
10875 {"fstmiad", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10876 {"fstmead", 0xec800b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmia},
10877 {"fstmdbd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
10878 {"fstmfdd", 0xed200b00, 7, FPU_VFP_EXT_V1, do_vfp_dp_ldstmdb},
6c43fab6 10879
a737bd4d
NC
10880 /* Monadic operations. */
10881 {"fabsd", 0xeeb00bc0, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10882 {"fnegd", 0xeeb10b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10883 {"fsqrtd", 0xeeb10bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
6c43fab6 10884
a737bd4d
NC
10885 /* Dyadic operations. */
10886 {"faddd", 0xee300b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10887 {"fsubd", 0xee300b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10888 {"fmuld", 0xee200b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10889 {"fdivd", 0xee800b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10890 {"fmacd", 0xee000b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10891 {"fmscd", 0xee100b00, 5, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10892 {"fnmuld", 0xee200b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10893 {"fnmacd", 0xee000b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
10894 {"fnmscd", 0xee100b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_dyadic},
6c43fab6 10895
a737bd4d
NC
10896 /* Comparisons. */
10897 {"fcmpd", 0xeeb40b40, 5, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10898 {"fcmpzd", 0xeeb50b40, 6, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
10899 {"fcmped", 0xeeb40bc0, 6, FPU_VFP_EXT_V1, do_vfp_dp_monadic},
10900 {"fcmpezd", 0xeeb50bc0, 7, FPU_VFP_EXT_V1, do_vfp_dp_compare_z},
6c43fab6 10901
a737bd4d
NC
10902 /* VFP V2. */
10903 {"fmsrr", 0xec400a10, 5, FPU_VFP_EXT_V2, do_vfp_sp2_from_reg2},
10904 {"fmrrs", 0xec500a10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_sp2},
10905 {"fmdrr", 0xec400b10, 5, FPU_VFP_EXT_V2, do_vfp_dp_from_reg2},
10906 {"fmrrd", 0xec500b10, 5, FPU_VFP_EXT_V2, do_vfp_reg2_from_dp},
6c43fab6 10907
a737bd4d
NC
10908 /* Intel XScale extensions to ARM V5 ISA. (All use CP0). */
10909 {"mia", 0xee200010, 3, ARM_CEXT_XSCALE, do_xsc_mia},
10910 {"miaph", 0xee280010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10911 {"miabb", 0xee2c0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10912 {"miabt", 0xee2d0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10913 {"miatb", 0xee2e0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10914 {"miatt", 0xee2f0010, 5, ARM_CEXT_XSCALE, do_xsc_mia},
10915 {"mar", 0xec400000, 3, ARM_CEXT_XSCALE, do_xsc_mar},
10916 {"mra", 0xec500000, 3, ARM_CEXT_XSCALE, do_xsc_mra},
cc8a6dd0 10917
a737bd4d
NC
10918 /* Intel Wireless MMX technology instructions. */
10919 {"tandcb", 0xee130130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
10920 {"tandch", 0xee530130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
10921 {"tandcw", 0xee930130, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tandc},
10922 {"tbcstb", 0xee400010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
10923 {"tbcsth", 0xee400050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
10924 {"tbcstw", 0xee400090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tbcst},
10925 {"textrcb", 0xee130170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
10926 {"textrch", 0xee530170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
10927 {"textrcw", 0xee930170, 7, ARM_CEXT_IWMMXT, do_iwmmxt_textrc},
10928 {"textrmub", 0xee100070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10929 {"textrmuh", 0xee500070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10930 {"textrmuw", 0xee900070, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10931 {"textrmsb", 0xee100078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10932 {"textrmsh", 0xee500078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10933 {"textrmsw", 0xee900078, 8, ARM_CEXT_IWMMXT, do_iwmmxt_textrm},
10934 {"tinsrb", 0xee600010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
10935 {"tinsrh", 0xee600050, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
10936 {"tinsrw", 0xee600090, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tinsr},
10937 {"tmcr", 0xee000110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmcr},
10938 {"tmcrr", 0xec400000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmcrr},
10939 {"tmia", 0xee200010, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10940 {"tmiaph", 0xee280010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10941 {"tmiabb", 0xee2c0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10942 {"tmiabt", 0xee2d0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10943 {"tmiatb", 0xee2e0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10944 {"tmiatt", 0xee2f0010, 6, ARM_CEXT_IWMMXT, do_iwmmxt_tmia},
10945 {"tmovmskb", 0xee100030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
10946 {"tmovmskh", 0xee500030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
10947 {"tmovmskw", 0xee900030, 8, ARM_CEXT_IWMMXT, do_iwmmxt_tmovmsk},
10948 {"tmrc", 0xee100110, 4, ARM_CEXT_IWMMXT, do_iwmmxt_tmrc},
10949 {"tmrrc", 0xec500000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_tmrrc},
10950 {"torcb", 0xee130150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
10951 {"torch", 0xee530150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
10952 {"torcw", 0xee930150, 5, ARM_CEXT_IWMMXT, do_iwmmxt_torc},
10953 {"waccb", 0xee0001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
10954 {"wacch", 0xee4001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
10955 {"waccw", 0xee8001c0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
10956 {"waddbss", 0xee300180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10957 {"waddb", 0xee000180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10958 {"waddbus", 0xee100180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10959 {"waddhss", 0xee700180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10960 {"waddh", 0xee400180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10961 {"waddhus", 0xee500180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10962 {"waddwss", 0xeeb00180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10963 {"waddw", 0xee800180, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10964 {"waddwus", 0xee900180, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10965 {"waligni", 0xee000020, 7, ARM_CEXT_IWMMXT, do_iwmmxt_waligni},
10966 {"walignr0", 0xee800020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10967 {"walignr1", 0xee900020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10968 {"walignr2", 0xeea00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10969 {"walignr3", 0xeeb00020, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10970 {"wand", 0xee200000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10971 {"wandn", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10972 {"wavg2b", 0xee800000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10973 {"wavg2br", 0xee900000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10974 {"wavg2h", 0xeec00000, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10975 {"wavg2hr", 0xeed00000, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10976 {"wcmpeqb", 0xee000060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10977 {"wcmpeqh", 0xee400060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10978 {"wcmpeqw", 0xee800060, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10979 {"wcmpgtub", 0xee100060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10980 {"wcmpgtuh", 0xee500060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10981 {"wcmpgtuw", 0xee900060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10982 {"wcmpgtsb", 0xee300060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10983 {"wcmpgtsh", 0xee700060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10984 {"wcmpgtsw", 0xeeb00060, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10985 {"wldrb", 0xec100000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
10986 {"wldrh", 0xec100100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
10987 {"wldrw", 0xec100200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
10988 {"wldrd", 0xec100300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
10989 {"wmacs", 0xee600100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10990 {"wmacsz", 0xee700100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10991 {"wmacu", 0xee400100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10992 {"wmacuz", 0xee500100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10993 {"wmadds", 0xeea00100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10994 {"wmaddu", 0xee800100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10995 {"wmaxsb", 0xee200160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10996 {"wmaxsh", 0xee600160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10997 {"wmaxsw", 0xeea00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10998 {"wmaxub", 0xee000160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
10999 {"wmaxuh", 0xee400160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11000 {"wmaxuw", 0xee800160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11001 {"wminsb", 0xee300160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11002 {"wminsh", 0xee700160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11003 {"wminsw", 0xeeb00160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11004 {"wminub", 0xee100160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11005 {"wminuh", 0xee500160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11006 {"wminuw", 0xee900160, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11007 {"wmov", 0xee000000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wmov},
11008 {"wmulsm", 0xee300100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11009 {"wmulsl", 0xee200100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11010 {"wmulum", 0xee100100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11011 {"wmulul", 0xee000100, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11012 {"wor", 0xee000000, 3, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11013 {"wpackhss", 0xee700080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11014 {"wpackhus", 0xee500080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11015 {"wpackwss", 0xeeb00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11016 {"wpackwus", 0xee900080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11017 {"wpackdss", 0xeef00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11018 {"wpackdus", 0xeed00080, 8, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11019 {"wrorh", 0xee700040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11020 {"wrorhg", 0xee700148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11021 {"wrorw", 0xeeb00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11022 {"wrorwg", 0xeeb00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11023 {"wrord", 0xeef00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11024 {"wrordg", 0xeef00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11025 {"wsadb", 0xee000120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11026 {"wsadbz", 0xee100120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11027 {"wsadh", 0xee400120, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11028 {"wsadhz", 0xee500120, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11029 {"wshufh", 0xee0001e0, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wshufh},
11030 {"wsllh", 0xee500040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11031 {"wsllhg", 0xee500148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11032 {"wsllw", 0xee900040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11033 {"wsllwg", 0xee900148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11034 {"wslld", 0xeed00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11035 {"wslldg", 0xeed00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11036 {"wsrah", 0xee400040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11037 {"wsrahg", 0xee400148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11038 {"wsraw", 0xee800040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11039 {"wsrawg", 0xee800148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11040 {"wsrad", 0xeec00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11041 {"wsradg", 0xeec00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11042 {"wsrlh", 0xee600040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11043 {"wsrlhg", 0xee600148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11044 {"wsrlw", 0xeea00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11045 {"wsrlwg", 0xeea00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11046 {"wsrld", 0xeee00040, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11047 {"wsrldg", 0xeee00148, 6, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwcg},
11048 {"wstrb", 0xec000000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
11049 {"wstrh", 0xec000100, 5, ARM_CEXT_IWMMXT, do_iwmmxt_byte_addr},
11050 {"wstrw", 0xec000200, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
11051 {"wstrd", 0xec000300, 5, ARM_CEXT_IWMMXT, do_iwmmxt_word_addr},
11052 {"wsubbss", 0xee3001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11053 {"wsubb", 0xee0001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11054 {"wsubbus", 0xee1001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11055 {"wsubhss", 0xee7001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11056 {"wsubh", 0xee4001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11057 {"wsubhus", 0xee5001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11058 {"wsubwss", 0xeeb001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11059 {"wsubw", 0xee8001a0, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11060 {"wsubwus", 0xee9001a0, 7, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11061 {"wunpckehub", 0xee0000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11062 {"wunpckehuh", 0xee4000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11063 {"wunpckehuw", 0xee8000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11064 {"wunpckehsb", 0xee2000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11065 {"wunpckehsh", 0xee6000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11066 {"wunpckehsw", 0xeea000c0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11067 {"wunpckihb", 0xee1000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11068 {"wunpckihh", 0xee5000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11069 {"wunpckihw", 0xee9000c0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11070 {"wunpckelub", 0xee0000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11071 {"wunpckeluh", 0xee4000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11072 {"wunpckeluw", 0xee8000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11073 {"wunpckelsb", 0xee2000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11074 {"wunpckelsh", 0xee6000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11075 {"wunpckelsw", 0xeea000e0, 10, ARM_CEXT_IWMMXT, do_iwmmxt_wrwr},
11076 {"wunpckilb", 0xee1000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11077 {"wunpckilh", 0xee5000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11078 {"wunpckilw", 0xee9000e0, 9, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11079 {"wxor", 0xee100000, 4, ARM_CEXT_IWMMXT, do_iwmmxt_wrwrwr},
11080 {"wzero", 0xee300000, 5, ARM_CEXT_IWMMXT, do_iwmmxt_wzero},
b99bd4ef 11081
a737bd4d
NC
11082 /* Cirrus Maverick instructions. */
11083 {"cfldrs", 0xec100400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
11084 {"cfldrd", 0xec500400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
11085 {"cfldr32", 0xec100500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
11086 {"cfldr64", 0xec500500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
11087 {"cfstrs", 0xec000400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_1},
11088 {"cfstrd", 0xec400400, 6, ARM_CEXT_MAVERICK, do_mav_ldst_2},
11089 {"cfstr32", 0xec000500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_3},
11090 {"cfstr64", 0xec400500, 7, ARM_CEXT_MAVERICK, do_mav_ldst_4},
11091 {"cfmvsr", 0xee000450, 6, ARM_CEXT_MAVERICK, do_mav_binops_2a},
11092 {"cfmvrs", 0xee100450, 6, ARM_CEXT_MAVERICK, do_mav_binops_1a},
11093 {"cfmvdlr", 0xee000410, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
11094 {"cfmvrdl", 0xee100410, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
11095 {"cfmvdhr", 0xee000430, 7, ARM_CEXT_MAVERICK, do_mav_binops_2b},
11096 {"cfmvrdh", 0xee100430, 7, ARM_CEXT_MAVERICK, do_mav_binops_1b},
11097 {"cfmv64lr", 0xee000510, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
11098 {"cfmvr64l", 0xee100510, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
11099 {"cfmv64hr", 0xee000530, 8, ARM_CEXT_MAVERICK, do_mav_binops_2c},
11100 {"cfmvr64h", 0xee100530, 8, ARM_CEXT_MAVERICK, do_mav_binops_1c},
11101 {"cfmval32", 0xee200440, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11102 {"cfmv32al", 0xee100440, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11103 {"cfmvam32", 0xee200460, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11104 {"cfmv32am", 0xee100460, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11105 {"cfmvah32", 0xee200480, 8, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11106 {"cfmv32ah", 0xee100480, 8, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11107 {"cfmva32", 0xee2004a0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3a},
11108 {"cfmv32a", 0xee1004a0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3b},
11109 {"cfmva64", 0xee2004c0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3c},
11110 {"cfmv64a", 0xee1004c0, 7, ARM_CEXT_MAVERICK, do_mav_binops_3d},
11111 {"cfmvsc32", 0xee2004e0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_1},
11112 {"cfmv32sc", 0xee1004e0, 8, ARM_CEXT_MAVERICK, do_mav_dspsc_2},
11113 {"cfcpys", 0xee000400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
11114 {"cfcpyd", 0xee000420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
11115 {"cfcvtsd", 0xee000460, 7, ARM_CEXT_MAVERICK, do_mav_binops_1f},
11116 {"cfcvtds", 0xee000440, 7, ARM_CEXT_MAVERICK, do_mav_binops_1g},
11117 {"cfcvt32s", 0xee000480, 8, ARM_CEXT_MAVERICK, do_mav_binops_1h},
11118 {"cfcvt32d", 0xee0004a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1i},
11119 {"cfcvt64s", 0xee0004c0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1j},
11120 {"cfcvt64d", 0xee0004e0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1k},
11121 {"cfcvts32", 0xee100580, 8, ARM_CEXT_MAVERICK, do_mav_binops_1l},
11122 {"cfcvtd32", 0xee1005a0, 8, ARM_CEXT_MAVERICK, do_mav_binops_1m},
11123 {"cftruncs32", 0xee1005c0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1l},
11124 {"cftruncd32", 0xee1005e0, 10, ARM_CEXT_MAVERICK, do_mav_binops_1m},
11125 {"cfrshl32", 0xee000550, 8, ARM_CEXT_MAVERICK, do_mav_triple_4a},
11126 {"cfrshl64", 0xee000570, 8, ARM_CEXT_MAVERICK, do_mav_triple_4b},
11127 {"cfsh32", 0xee000500, 6, ARM_CEXT_MAVERICK, do_mav_shift_1},
11128 {"cfsh64", 0xee200500, 6, ARM_CEXT_MAVERICK, do_mav_shift_2},
11129 {"cfcmps", 0xee100490, 6, ARM_CEXT_MAVERICK, do_mav_triple_5a},
11130 {"cfcmpd", 0xee1004b0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5b},
11131 {"cfcmp32", 0xee100590, 7, ARM_CEXT_MAVERICK, do_mav_triple_5c},
11132 {"cfcmp64", 0xee1005b0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5d},
11133 {"cfabss", 0xee300400, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
11134 {"cfabsd", 0xee300420, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
11135 {"cfnegs", 0xee300440, 6, ARM_CEXT_MAVERICK, do_mav_binops_1d},
11136 {"cfnegd", 0xee300460, 6, ARM_CEXT_MAVERICK, do_mav_binops_1e},
11137 {"cfadds", 0xee300480, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
11138 {"cfaddd", 0xee3004a0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
11139 {"cfsubs", 0xee3004c0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
11140 {"cfsubd", 0xee3004e0, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
11141 {"cfmuls", 0xee100400, 6, ARM_CEXT_MAVERICK, do_mav_triple_5e},
11142 {"cfmuld", 0xee100420, 6, ARM_CEXT_MAVERICK, do_mav_triple_5f},
11143 {"cfabs32", 0xee300500, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
11144 {"cfabs64", 0xee300520, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
11145 {"cfneg32", 0xee300540, 7, ARM_CEXT_MAVERICK, do_mav_binops_1n},
11146 {"cfneg64", 0xee300560, 7, ARM_CEXT_MAVERICK, do_mav_binops_1o},
11147 {"cfadd32", 0xee300580, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11148 {"cfadd64", 0xee3005a0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
11149 {"cfsub32", 0xee3005c0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11150 {"cfsub64", 0xee3005e0, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
11151 {"cfmul32", 0xee100500, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11152 {"cfmul64", 0xee100520, 7, ARM_CEXT_MAVERICK, do_mav_triple_5h},
11153 {"cfmac32", 0xee100540, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11154 {"cfmsc32", 0xee100560, 7, ARM_CEXT_MAVERICK, do_mav_triple_5g},
11155 {"cfmadd32", 0xee000600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
11156 {"cfmsub32", 0xee100600, 8, ARM_CEXT_MAVERICK, do_mav_quad_6a},
11157 {"cfmadda32", 0xee200600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
11158 {"cfmsuba32", 0xee300600, 9, ARM_CEXT_MAVERICK, do_mav_quad_6b},
11159};
b99bd4ef 11160
90e4755a 11161/* Iterate over the base tables to create the instruction patterns. */
a737bd4d 11162
90e4755a 11163static void
a737bd4d 11164build_arm_ops_hsh (void)
90e4755a
RE
11165{
11166 unsigned int i;
11167 unsigned int j;
11168 static struct obstack insn_obstack;
11169
11170 obstack_begin (&insn_obstack, 4000);
11171
11172 for (i = 0; i < sizeof (insns) / sizeof (struct asm_opcode); i++)
11173 {
6c43fab6 11174 const struct asm_opcode *insn = insns + i;
90e4755a
RE
11175
11176 if (insn->cond_offset != 0)
11177 {
11178 /* Insn supports conditional execution. Build the varaints
11179 and insert them in the hash table. */
11180 for (j = 0; j < sizeof (conds) / sizeof (struct asm_cond); j++)
11181 {
11182 unsigned len = strlen (insn->template);
11183 struct asm_opcode *new;
11184 char *template;
11185
11186 new = obstack_alloc (&insn_obstack, sizeof (struct asm_opcode));
11187 /* All condition codes are two characters. */
11188 template = obstack_alloc (&insn_obstack, len + 3);
11189
11190 strncpy (template, insn->template, insn->cond_offset);
11191 strcpy (template + insn->cond_offset, conds[j].template);
11192 if (len > insn->cond_offset)
11193 strcpy (template + insn->cond_offset + 2,
11194 insn->template + insn->cond_offset);
11195 new->template = template;
11196 new->cond_offset = 0;
11197 new->variant = insn->variant;
11198 new->parms = insn->parms;
11199 new->value = (insn->value & ~COND_MASK) | conds[j].value;
11200
11201 hash_insert (arm_ops_hsh, new->template, (PTR) new);
11202 }
11203 }
11204 /* Finally, insert the unconditional insn in the table directly;
11205 no need to build a copy. */
11206 hash_insert (arm_ops_hsh, insn->template, (PTR) insn);
11207 }
11208}
11209
a737bd4d
NC
11210\f
11211static const struct thumb_opcode tinsns[] =
11212{
11213 /* Thumb v1 (ARMv4T). */
11214 {"adc", 0x4140, 2, ARM_EXT_V4T, do_t_arit},
11215 {"add", 0x0000, 2, ARM_EXT_V4T, do_t_add},
11216 {"and", 0x4000, 2, ARM_EXT_V4T, do_t_arit},
11217 {"asr", 0x0000, 2, ARM_EXT_V4T, do_t_asr},
11218 {"b", T_OPCODE_BRANCH, 2, ARM_EXT_V4T, do_t_branch12},
11219 {"beq", 0xd0fe, 2, ARM_EXT_V4T, do_t_branch9},
11220 {"bne", 0xd1fe, 2, ARM_EXT_V4T, do_t_branch9},
11221 {"bcs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
11222 {"bhs", 0xd2fe, 2, ARM_EXT_V4T, do_t_branch9},
11223 {"bcc", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
11224 {"bul", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
11225 {"blo", 0xd3fe, 2, ARM_EXT_V4T, do_t_branch9},
11226 {"bmi", 0xd4fe, 2, ARM_EXT_V4T, do_t_branch9},
11227 {"bpl", 0xd5fe, 2, ARM_EXT_V4T, do_t_branch9},
11228 {"bvs", 0xd6fe, 2, ARM_EXT_V4T, do_t_branch9},
11229 {"bvc", 0xd7fe, 2, ARM_EXT_V4T, do_t_branch9},
11230 {"bhi", 0xd8fe, 2, ARM_EXT_V4T, do_t_branch9},
11231 {"bls", 0xd9fe, 2, ARM_EXT_V4T, do_t_branch9},
11232 {"bge", 0xdafe, 2, ARM_EXT_V4T, do_t_branch9},
11233 {"blt", 0xdbfe, 2, ARM_EXT_V4T, do_t_branch9},
11234 {"bgt", 0xdcfe, 2, ARM_EXT_V4T, do_t_branch9},
11235 {"ble", 0xddfe, 2, ARM_EXT_V4T, do_t_branch9},
11236 {"bal", 0xdefe, 2, ARM_EXT_V4T, do_t_branch9},
11237 {"bic", 0x4380, 2, ARM_EXT_V4T, do_t_arit},
11238 {"bl", 0xf7fffffe, 4, ARM_EXT_V4T, do_t_branch23},
11239 {"bx", 0x4700, 2, ARM_EXT_V4T, do_t_bx},
11240 {"cmn", T_OPCODE_CMN, 2, ARM_EXT_V4T, do_t_arit},
11241 {"cmp", 0x0000, 2, ARM_EXT_V4T, do_t_compare},
11242 {"eor", 0x4040, 2, ARM_EXT_V4T, do_t_arit},
11243 {"ldmia", 0xc800, 2, ARM_EXT_V4T, do_t_ldmstm},
11244 {"ldr", 0x0000, 2, ARM_EXT_V4T, do_t_ldr},
11245 {"ldrb", 0x0000, 2, ARM_EXT_V4T, do_t_ldrb},
11246 {"ldrh", 0x0000, 2, ARM_EXT_V4T, do_t_ldrh},
11247 {"ldrsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
11248 {"ldrsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
11249 {"ldsb", 0x5600, 2, ARM_EXT_V4T, do_t_lds},
11250 {"ldsh", 0x5e00, 2, ARM_EXT_V4T, do_t_lds},
11251 {"lsl", 0x0000, 2, ARM_EXT_V4T, do_t_lsl},
11252 {"lsr", 0x0000, 2, ARM_EXT_V4T, do_t_lsr},
11253 {"mov", 0x0000, 2, ARM_EXT_V4T, do_t_mov},
11254 {"mul", T_OPCODE_MUL, 2, ARM_EXT_V4T, do_t_arit},
11255 {"mvn", T_OPCODE_MVN, 2, ARM_EXT_V4T, do_t_arit},
11256 {"neg", T_OPCODE_NEG, 2, ARM_EXT_V4T, do_t_arit},
11257 {"orr", 0x4300, 2, ARM_EXT_V4T, do_t_arit},
11258 {"pop", 0xbc00, 2, ARM_EXT_V4T, do_t_push_pop},
11259 {"push", 0xb400, 2, ARM_EXT_V4T, do_t_push_pop},
11260 {"ror", 0x41c0, 2, ARM_EXT_V4T, do_t_arit},
11261 {"sbc", 0x4180, 2, ARM_EXT_V4T, do_t_arit},
11262 {"stmia", 0xc000, 2, ARM_EXT_V4T, do_t_ldmstm},
11263 {"str", 0x0000, 2, ARM_EXT_V4T, do_t_str},
11264 {"strb", 0x0000, 2, ARM_EXT_V4T, do_t_strb},
11265 {"strh", 0x0000, 2, ARM_EXT_V4T, do_t_strh},
11266 {"swi", 0xdf00, 2, ARM_EXT_V4T, do_t_swi},
11267 {"sub", 0x0000, 2, ARM_EXT_V4T, do_t_sub},
11268 {"tst", T_OPCODE_TST, 2, ARM_EXT_V4T, do_t_arit},
11269 /* Pseudo ops: */
11270 {"adr", 0x0000, 2, ARM_EXT_V4T, do_t_adr},
11271 {"nop", 0x46C0, 2, ARM_EXT_V4T, do_t_nop}, /* mov r8,r8 */
11272 /* Thumb v2 (ARMv5T). */
11273 {"blx", 0, 0, ARM_EXT_V5T, do_t_blx},
11274 {"bkpt", 0xbe00, 2, ARM_EXT_V5T, do_t_bkpt},
11275
11276 /* ARM V6. */
11277 {"cpsie", 0xb660, 2, ARM_EXT_V6, do_t_cps},
11278 {"cpsid", 0xb670, 2, ARM_EXT_V6, do_t_cps},
11279 {"cpy", 0x4600, 2, ARM_EXT_V6, do_t_cpy},
11280 {"rev", 0xba00, 2, ARM_EXT_V6, do_t_arit},
11281 {"rev16", 0xba40, 2, ARM_EXT_V6, do_t_arit},
11282 {"revsh", 0xbac0, 2, ARM_EXT_V6, do_t_arit},
11283 {"setend", 0xb650, 2, ARM_EXT_V6, do_t_setend},
11284 {"sxth", 0xb200, 2, ARM_EXT_V6, do_t_arit},
11285 {"sxtb", 0xb240, 2, ARM_EXT_V6, do_t_arit},
11286 {"uxth", 0xb280, 2, ARM_EXT_V6, do_t_arit},
11287 {"uxtb", 0xb2c0, 2, ARM_EXT_V6, do_t_arit},
885fc257
ZW
11288
11289 /* ARM V6K. */
11290 {"sev", 0xbf40, 2, ARM_EXT_V6K, do_empty},
11291 {"wfe", 0xbf20, 2, ARM_EXT_V6K, do_empty},
11292 {"wfi", 0xbf30, 2, ARM_EXT_V6K, do_empty},
11293 {"yield", 0xbf10, 2, ARM_EXT_V6K, do_empty},
a737bd4d 11294};
5a6c6817 11295
b99bd4ef 11296void
a737bd4d 11297md_begin (void)
b99bd4ef
NC
11298{
11299 unsigned mach;
11300 unsigned int i;
11301
11302 if ( (arm_ops_hsh = hash_new ()) == NULL
11303 || (arm_tops_hsh = hash_new ()) == NULL
11304 || (arm_cond_hsh = hash_new ()) == NULL
11305 || (arm_shift_hsh = hash_new ()) == NULL
b99bd4ef 11306 || (arm_psr_hsh = hash_new ()) == NULL)
f03698e6 11307 as_fatal (_("virtual memory exhausted"));
b99bd4ef 11308
90e4755a 11309 build_arm_ops_hsh ();
b99bd4ef
NC
11310 for (i = 0; i < sizeof (tinsns) / sizeof (struct thumb_opcode); i++)
11311 hash_insert (arm_tops_hsh, tinsns[i].template, (PTR) (tinsns + i));
11312 for (i = 0; i < sizeof (conds) / sizeof (struct asm_cond); i++)
11313 hash_insert (arm_cond_hsh, conds[i].template, (PTR) (conds + i));
11314 for (i = 0; i < sizeof (shift_names) / sizeof (struct asm_shift_name); i++)
11315 hash_insert (arm_shift_hsh, shift_names[i].name, (PTR) (shift_names + i));
11316 for (i = 0; i < sizeof (psrs) / sizeof (struct asm_psr); i++)
11317 hash_insert (arm_psr_hsh, psrs[i].template, (PTR) (psrs + i));
11318
6c43fab6
RE
11319 for (i = (int) REG_TYPE_FIRST; i < (int) REG_TYPE_MAX; i++)
11320 build_reg_hsh (all_reg_maps + i);
b99bd4ef
NC
11321
11322 set_constant_flonums ();
11323
03b1477f
RE
11324 /* Set the cpu variant based on the command-line options. We prefer
11325 -mcpu= over -march= if both are set (as for GCC); and we prefer
11326 -mfpu= over any other way of setting the floating point unit.
11327 Use of legacy options with new options are faulted. */
11328 if (legacy_cpu != -1)
11329 {
11330 if (mcpu_cpu_opt != -1 || march_cpu_opt != -1)
11331 as_bad (_("use of old and new-style options to set CPU type"));
11332
11333 mcpu_cpu_opt = legacy_cpu;
11334 }
11335 else if (mcpu_cpu_opt == -1)
11336 mcpu_cpu_opt = march_cpu_opt;
11337
11338 if (legacy_fpu != -1)
11339 {
11340 if (mfpu_opt != -1)
11341 as_bad (_("use of old and new-style options to set FPU type"));
11342
11343 mfpu_opt = legacy_fpu;
11344 }
11345 else if (mfpu_opt == -1)
11346 {
4e7fd91e 11347#if !(defined (TE_LINUX) || defined (TE_NetBSD) || defined (TE_VXWORKS))
39c2da32
RE
11348 /* Some environments specify a default FPU. If they don't, infer it
11349 from the processor. */
03b1477f
RE
11350 if (mcpu_fpu_opt != -1)
11351 mfpu_opt = mcpu_fpu_opt;
11352 else
11353 mfpu_opt = march_fpu_opt;
39c2da32
RE
11354#else
11355 mfpu_opt = FPU_DEFAULT;
11356#endif
03b1477f
RE
11357 }
11358
11359 if (mfpu_opt == -1)
11360 {
11361 if (mcpu_cpu_opt == -1)
11362 mfpu_opt = FPU_DEFAULT;
11363 else if (mcpu_cpu_opt & ARM_EXT_V5)
11364 mfpu_opt = FPU_ARCH_VFP_V2;
11365 else
11366 mfpu_opt = FPU_ARCH_FPA;
11367 }
11368
11369 if (mcpu_cpu_opt == -1)
11370 mcpu_cpu_opt = CPU_DEFAULT;
11371
11372 cpu_variant = mcpu_cpu_opt | mfpu_opt;
11373
f17c130b 11374#if defined OBJ_COFF || defined OBJ_ELF
b99bd4ef 11375 {
7cc69913
NC
11376 unsigned int flags = 0;
11377
11378#if defined OBJ_ELF
11379 flags = meabi_flags;
d507cf36
PB
11380
11381 switch (meabi_flags)
33a392fb 11382 {
d507cf36 11383 case EF_ARM_EABI_UNKNOWN:
7cc69913 11384#endif
d507cf36
PB
11385 /* Set the flags in the private structure. */
11386 if (uses_apcs_26) flags |= F_APCS26;
11387 if (support_interwork) flags |= F_INTERWORK;
11388 if (uses_apcs_float) flags |= F_APCS_FLOAT;
11389 if (pic_code) flags |= F_PIC;
11390 if ((cpu_variant & FPU_ANY) == FPU_NONE
11391 || (cpu_variant & FPU_ANY) == FPU_ARCH_VFP) /* VFP layout only. */
7cc69913
NC
11392 flags |= F_SOFT_FLOAT;
11393
d507cf36
PB
11394 switch (mfloat_abi_opt)
11395 {
11396 case ARM_FLOAT_ABI_SOFT:
11397 case ARM_FLOAT_ABI_SOFTFP:
11398 flags |= F_SOFT_FLOAT;
11399 break;
33a392fb 11400
d507cf36
PB
11401 case ARM_FLOAT_ABI_HARD:
11402 if (flags & F_SOFT_FLOAT)
11403 as_bad (_("hard-float conflicts with specified fpu"));
11404 break;
11405 }
03b1477f 11406
7cc69913
NC
11407 /* Using VFP conventions (even if soft-float). */
11408 if (cpu_variant & FPU_VFP_EXT_NONE)
11409 flags |= F_VFP_FLOAT;
f17c130b 11410
fde78edd 11411#if defined OBJ_ELF
d507cf36
PB
11412 if (cpu_variant & FPU_ARCH_MAVERICK)
11413 flags |= EF_ARM_MAVERICK_FLOAT;
d507cf36
PB
11414 break;
11415
8cb51566 11416 case EF_ARM_EABI_VER4:
d507cf36
PB
11417 /* No additional flags to set. */
11418 break;
11419
11420 default:
11421 abort ();
11422 }
7cc69913 11423#endif
b99bd4ef
NC
11424 bfd_set_private_flags (stdoutput, flags);
11425
11426 /* We have run out flags in the COFF header to encode the
11427 status of ATPCS support, so instead we create a dummy,
11428 empty, debug section called .arm.atpcs. */
11429 if (atpcs)
11430 {
11431 asection * sec;
11432
11433 sec = bfd_make_section (stdoutput, ".arm.atpcs");
11434
11435 if (sec != NULL)
11436 {
11437 bfd_set_section_flags
11438 (stdoutput, sec, SEC_READONLY | SEC_DEBUGGING /* | SEC_HAS_CONTENTS */);
11439 bfd_set_section_size (stdoutput, sec, 0);
11440 bfd_set_section_contents (stdoutput, sec, NULL, 0, 0);
11441 }
11442 }
7cc69913 11443 }
f17c130b 11444#endif
b99bd4ef
NC
11445
11446 /* Record the CPU type as well. */
11447 switch (cpu_variant & ARM_CPU_MASK)
11448 {
11449 case ARM_2:
11450 mach = bfd_mach_arm_2;
11451 break;
11452
11453 case ARM_3: /* Also ARM_250. */
11454 mach = bfd_mach_arm_2a;
11455 break;
11456
b89dddec
RE
11457 case ARM_6: /* Also ARM_7. */
11458 mach = bfd_mach_arm_3;
11459 break;
11460
b99bd4ef 11461 default:
5a6c6817 11462 mach = bfd_mach_arm_unknown;
b99bd4ef 11463 break;
b99bd4ef
NC
11464 }
11465
11466 /* Catch special cases. */
e16bb312
NC
11467 if (cpu_variant & ARM_CEXT_IWMMXT)
11468 mach = bfd_mach_arm_iWMMXt;
11469 else if (cpu_variant & ARM_CEXT_XSCALE)
b99bd4ef 11470 mach = bfd_mach_arm_XScale;
fde78edd
NC
11471 else if (cpu_variant & ARM_CEXT_MAVERICK)
11472 mach = bfd_mach_arm_ep9312;
b99bd4ef
NC
11473 else if (cpu_variant & ARM_EXT_V5E)
11474 mach = bfd_mach_arm_5TE;
11475 else if (cpu_variant & ARM_EXT_V5)
11476 {
b89dddec 11477 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
11478 mach = bfd_mach_arm_5T;
11479 else
11480 mach = bfd_mach_arm_5;
11481 }
b89dddec 11482 else if (cpu_variant & ARM_EXT_V4)
b99bd4ef 11483 {
b89dddec 11484 if (cpu_variant & ARM_EXT_V4T)
b99bd4ef
NC
11485 mach = bfd_mach_arm_4T;
11486 else
11487 mach = bfd_mach_arm_4;
11488 }
b89dddec 11489 else if (cpu_variant & ARM_EXT_V3M)
b99bd4ef
NC
11490 mach = bfd_mach_arm_3M;
11491
11492 bfd_set_arch_mach (stdoutput, TARGET_ARCH, mach);
11493}
11494
11495/* Turn an integer of n bytes (in val) into a stream of bytes appropriate
11496 for use in the a.out file, and stores them in the array pointed to by buf.
11497 This knows about the endian-ness of the target machine and does
11498 THE RIGHT THING, whatever it is. Possible values for n are 1 (byte)
11499 2 (short) and 4 (long) Floating numbers are put out as a series of
11500 LITTLENUMS (shorts, here at least). */
11501
11502void
a737bd4d 11503md_number_to_chars (char * buf, valueT val, int n)
b99bd4ef
NC
11504{
11505 if (target_big_endian)
11506 number_to_chars_bigendian (buf, val, n);
11507 else
11508 number_to_chars_littleendian (buf, val, n);
11509}
11510
11511static valueT
a737bd4d 11512md_chars_to_number (char * buf, int n)
b99bd4ef
NC
11513{
11514 valueT result = 0;
11515 unsigned char * where = (unsigned char *) buf;
11516
11517 if (target_big_endian)
11518 {
11519 while (n--)
11520 {
11521 result <<= 8;
11522 result |= (*where++ & 255);
11523 }
11524 }
11525 else
11526 {
11527 while (n--)
11528 {
11529 result <<= 8;
11530 result |= (where[n] & 255);
11531 }
11532 }
11533
11534 return result;
11535}
11536
11537/* Turn a string in input_line_pointer into a floating point constant
11538 of type TYPE, and store the appropriate bytes in *LITP. The number
11539 of LITTLENUMS emitted is stored in *SIZEP. An error message is
11540 returned, or NULL on OK.
11541
11542 Note that fp constants aren't represent in the normal way on the ARM.
11543 In big endian mode, things are as expected. However, in little endian
11544 mode fp constants are big-endian word-wise, and little-endian byte-wise
11545 within the words. For example, (double) 1.1 in big endian mode is
11546 the byte sequence 3f f1 99 99 99 99 99 9a, and in little endian mode is
11547 the byte sequence 99 99 f1 3f 9a 99 99 99.
11548
11549 ??? The format of 12 byte floats is uncertain according to gcc's arm.h. */
11550
11551char *
a737bd4d 11552md_atof (int type, char * litP, int * sizeP)
b99bd4ef
NC
11553{
11554 int prec;
11555 LITTLENUM_TYPE words[MAX_LITTLENUMS];
11556 char *t;
11557 int i;
11558
11559 switch (type)
11560 {
11561 case 'f':
11562 case 'F':
11563 case 's':
11564 case 'S':
11565 prec = 2;
11566 break;
11567
11568 case 'd':
11569 case 'D':
11570 case 'r':
11571 case 'R':
11572 prec = 4;
11573 break;
11574
11575 case 'x':
11576 case 'X':
11577 prec = 6;
11578 break;
11579
11580 case 'p':
11581 case 'P':
11582 prec = 6;
11583 break;
11584
11585 default:
11586 *sizeP = 0;
f03698e6 11587 return _("bad call to MD_ATOF()");
b99bd4ef
NC
11588 }
11589
11590 t = atof_ieee (input_line_pointer, type, words);
11591 if (t)
11592 input_line_pointer = t;
11593 *sizeP = prec * 2;
11594
11595 if (target_big_endian)
11596 {
11597 for (i = 0; i < prec; i++)
11598 {
11599 md_number_to_chars (litP, (valueT) words[i], 2);
11600 litP += 2;
11601 }
11602 }
11603 else
11604 {
bfae80f2
RE
11605 if (cpu_variant & FPU_ARCH_VFP)
11606 for (i = prec - 1; i >= 0; i--)
11607 {
11608 md_number_to_chars (litP, (valueT) words[i], 2);
11609 litP += 2;
11610 }
11611 else
11612 /* For a 4 byte float the order of elements in `words' is 1 0.
11613 For an 8 byte float the order is 1 0 3 2. */
11614 for (i = 0; i < prec; i += 2)
11615 {
11616 md_number_to_chars (litP, (valueT) words[i + 1], 2);
11617 md_number_to_chars (litP + 2, (valueT) words[i], 2);
11618 litP += 4;
11619 }
b99bd4ef
NC
11620 }
11621
11622 return 0;
11623}
11624
11625/* The knowledge of the PC's pipeline offset is built into the insns
11626 themselves. */
11627
11628long
a737bd4d 11629md_pcrel_from (fixS * fixP)
b99bd4ef
NC
11630{
11631 if (fixP->fx_addsy
11632 && S_GET_SEGMENT (fixP->fx_addsy) == undefined_section
11633 && fixP->fx_subsy == NULL)
11634 return 0;
11635
11636 if (fixP->fx_pcrel && (fixP->fx_r_type == BFD_RELOC_ARM_THUMB_ADD))
11637 {
11638 /* PC relative addressing on the Thumb is slightly odd
11639 as the bottom two bits of the PC are forced to zero
11640 for the calculation. */
11641 return (fixP->fx_where + fixP->fx_frag->fr_address) & ~3;
11642 }
11643
11644#ifdef TE_WINCE
2d2255b5
KH
11645 /* The pattern was adjusted to accommodate CE's off-by-one fixups,
11646 so we un-adjust here to compensate for the accommodation. */
b99bd4ef
NC
11647 return fixP->fx_where + fixP->fx_frag->fr_address + 8;
11648#else
11649 return fixP->fx_where + fixP->fx_frag->fr_address;
11650#endif
11651}
11652
11653/* Round up a section size to the appropriate boundary. */
11654
11655valueT
a737bd4d
NC
11656md_section_align (segT segment ATTRIBUTE_UNUSED,
11657 valueT size)
b99bd4ef
NC
11658{
11659#ifdef OBJ_ELF
11660 return size;
11661#else
11662 /* Round all sects to multiple of 4. */
11663 return (size + 3) & ~3;
11664#endif
11665}
11666
11667/* Under ELF we need to default _GLOBAL_OFFSET_TABLE.
11668 Otherwise we have no need to default values of symbols. */
11669
11670symbolS *
a737bd4d 11671md_undefined_symbol (char * name ATTRIBUTE_UNUSED)
b99bd4ef
NC
11672{
11673#ifdef OBJ_ELF
11674 if (name[0] == '_' && name[1] == 'G'
11675 && streq (name, GLOBAL_OFFSET_TABLE_NAME))
11676 {
11677 if (!GOT_symbol)
11678 {
11679 if (symbol_find (name))
11680 as_bad ("GOT already in the symbol table");
11681
11682 GOT_symbol = symbol_new (name, undefined_section,
11683 (valueT) 0, & zero_address_frag);
11684 }
11685
11686 return GOT_symbol;
11687 }
11688#endif
11689
11690 return 0;
11691}
11692
94f592af 11693void
a737bd4d
NC
11694md_apply_fix3 (fixS * fixP,
11695 valueT * valP,
11696 segT seg)
b99bd4ef 11697{
94f592af 11698 offsetT value = * valP;
b99bd4ef
NC
11699 offsetT newval;
11700 unsigned int newimm;
11701 unsigned long temp;
11702 int sign;
11703 char * buf = fixP->fx_where + fixP->fx_frag->fr_literal;
11704 arm_fix_data * arm_data = (arm_fix_data *) fixP->tc_fix_data;
11705
620b81c1 11706 assert (fixP->fx_r_type <= BFD_RELOC_UNUSED);
b99bd4ef
NC
11707
11708 /* Note whether this will delete the relocation. */
b99bd4ef 11709 if (fixP->fx_addsy == 0 && !fixP->fx_pcrel)
b99bd4ef
NC
11710 fixP->fx_done = 1;
11711
11712 /* If this symbol is in a different section then we need to leave it for
11713 the linker to deal with. Unfortunately, md_pcrel_from can't tell,
11714 so we have to undo it's effects here. */
11715 if (fixP->fx_pcrel)
11716 {
11717 if (fixP->fx_addsy != NULL
11718 && S_IS_DEFINED (fixP->fx_addsy)
11719 && S_GET_SEGMENT (fixP->fx_addsy) != seg)
7f266840 11720 value += md_pcrel_from (fixP);
b99bd4ef
NC
11721 }
11722
11723 /* Remember value for emit_reloc. */
11724 fixP->fx_addnumber = value;
11725
11726 switch (fixP->fx_r_type)
11727 {
620b81c1
JB
11728 case BFD_RELOC_NONE:
11729 /* This will need to go in the object file. */
11730 fixP->fx_done = 0;
11731 break;
11732
b99bd4ef 11733 case BFD_RELOC_ARM_IMMEDIATE:
310ea308
NC
11734 /* We claim that this fixup has been processed here,
11735 even if in fact we generate an error because we do
11736 not have a reloc for it, so tc_gen_reloc will reject it. */
11737 fixP->fx_done = 1;
11738
11739 if (fixP->fx_addsy
11740 && ! S_IS_DEFINED (fixP->fx_addsy))
11741 {
11742 as_bad_where (fixP->fx_file, fixP->fx_line,
11743 _("undefined symbol %s used as an immediate value"),
11744 S_GET_NAME (fixP->fx_addsy));
11745 break;
11746 }
11747
b99bd4ef
NC
11748 newimm = validate_immediate (value);
11749 temp = md_chars_to_number (buf, INSN_SIZE);
11750
11751 /* If the instruction will fail, see if we can fix things up by
11752 changing the opcode. */
11753 if (newimm == (unsigned int) FAIL
11754 && (newimm = negate_data_op (&temp, value)) == (unsigned int) FAIL)
11755 {
11756 as_bad_where (fixP->fx_file, fixP->fx_line,
11757 _("invalid constant (%lx) after fixup"),
11758 (unsigned long) value);
11759 break;
11760 }
11761
11762 newimm |= (temp & 0xfffff000);
11763 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
11764 break;
11765
11766 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
11767 {
11768 unsigned int highpart = 0;
11769 unsigned int newinsn = 0xe1a00000; /* nop. */
6189168b 11770
b99bd4ef
NC
11771 newimm = validate_immediate (value);
11772 temp = md_chars_to_number (buf, INSN_SIZE);
11773
11774 /* If the instruction will fail, see if we can fix things up by
11775 changing the opcode. */
11776 if (newimm == (unsigned int) FAIL
11777 && (newimm = negate_data_op (& temp, value)) == (unsigned int) FAIL)
11778 {
11779 /* No ? OK - try using two ADD instructions to generate
11780 the value. */
11781 newimm = validate_immediate_twopart (value, & highpart);
11782
11783 /* Yes - then make sure that the second instruction is
11784 also an add. */
11785 if (newimm != (unsigned int) FAIL)
11786 newinsn = temp;
11787 /* Still No ? Try using a negated value. */
11788 else if ((newimm = validate_immediate_twopart (- value, & highpart)) != (unsigned int) FAIL)
11789 temp = newinsn = (temp & OPCODE_MASK) | OPCODE_SUB << DATA_OP_SHIFT;
11790 /* Otherwise - give up. */
11791 else
11792 {
11793 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11794 _("unable to compute ADRL instructions for PC offset of 0x%lx"),
08df2379 11795 (long) value);
b99bd4ef
NC
11796 break;
11797 }
11798
11799 /* Replace the first operand in the 2nd instruction (which
11800 is the PC) with the destination register. We have
11801 already added in the PC in the first instruction and we
11802 do not want to do it again. */
11803 newinsn &= ~ 0xf0000;
11804 newinsn |= ((newinsn & 0x0f000) << 4);
11805 }
11806
11807 newimm |= (temp & 0xfffff000);
11808 md_number_to_chars (buf, (valueT) newimm, INSN_SIZE);
11809
11810 highpart |= (newinsn & 0xfffff000);
11811 md_number_to_chars (buf + INSN_SIZE, (valueT) highpart, INSN_SIZE);
11812 }
11813 break;
11814
11815 case BFD_RELOC_ARM_OFFSET_IMM:
11816 sign = value >= 0;
11817
11818 if (value < 0)
11819 value = - value;
11820
11821 if (validate_offset_imm (value, 0) == FAIL)
11822 {
11823 as_bad_where (fixP->fx_file, fixP->fx_line,
11824 _("bad immediate value for offset (%ld)"),
11825 (long) value);
11826 break;
11827 }
11828
11829 newval = md_chars_to_number (buf, INSN_SIZE);
11830 newval &= 0xff7ff000;
11831 newval |= value | (sign ? INDEX_UP : 0);
11832 md_number_to_chars (buf, newval, INSN_SIZE);
11833 break;
11834
11835 case BFD_RELOC_ARM_OFFSET_IMM8:
11836 case BFD_RELOC_ARM_HWLITERAL:
11837 sign = value >= 0;
11838
11839 if (value < 0)
11840 value = - value;
11841
11842 if (validate_offset_imm (value, 1) == FAIL)
11843 {
11844 if (fixP->fx_r_type == BFD_RELOC_ARM_HWLITERAL)
11845 as_bad_where (fixP->fx_file, fixP->fx_line,
11846 _("invalid literal constant: pool needs to be closer"));
11847 else
11848 as_bad (_("bad immediate value for half-word offset (%ld)"),
11849 (long) value);
11850 break;
11851 }
11852
11853 newval = md_chars_to_number (buf, INSN_SIZE);
11854 newval &= 0xff7ff0f0;
11855 newval |= ((value >> 4) << 8) | (value & 0xf) | (sign ? INDEX_UP : 0);
11856 md_number_to_chars (buf, newval, INSN_SIZE);
11857 break;
11858
11859 case BFD_RELOC_ARM_LITERAL:
11860 sign = value >= 0;
11861
11862 if (value < 0)
11863 value = - value;
11864
11865 if (validate_offset_imm (value, 0) == FAIL)
11866 {
11867 as_bad_where (fixP->fx_file, fixP->fx_line,
11868 _("invalid literal constant: pool needs to be closer"));
11869 break;
11870 }
11871
11872 newval = md_chars_to_number (buf, INSN_SIZE);
11873 newval &= 0xff7ff000;
11874 newval |= value | (sign ? INDEX_UP : 0);
11875 md_number_to_chars (buf, newval, INSN_SIZE);
11876 break;
11877
11878 case BFD_RELOC_ARM_SHIFT_IMM:
11879 newval = md_chars_to_number (buf, INSN_SIZE);
11880 if (((unsigned long) value) > 32
11881 || (value == 32
11882 && (((newval & 0x60) == 0) || (newval & 0x60) == 0x60)))
11883 {
11884 as_bad_where (fixP->fx_file, fixP->fx_line,
11885 _("shift expression is too large"));
11886 break;
11887 }
11888
11889 if (value == 0)
11890 /* Shifts of zero must be done as lsl. */
11891 newval &= ~0x60;
11892 else if (value == 32)
11893 value = 0;
11894 newval &= 0xfffff07f;
11895 newval |= (value & 0x1f) << 7;
11896 md_number_to_chars (buf, newval, INSN_SIZE);
11897 break;
11898
0dd132b6
NC
11899 case BFD_RELOC_ARM_SMI:
11900 if (((unsigned long) value) > 0xffff)
11901 as_bad_where (fixP->fx_file, fixP->fx_line,
11902 _("invalid smi expression"));
11903 newval = md_chars_to_number (buf, INSN_SIZE) & 0xfff000f0;
11904 newval |= (value & 0xf) | ((value & 0xfff0) << 4);
11905 md_number_to_chars (buf, newval, INSN_SIZE);
11906 break;
11907
b99bd4ef
NC
11908 case BFD_RELOC_ARM_SWI:
11909 if (arm_data->thumb_mode)
11910 {
11911 if (((unsigned long) value) > 0xff)
11912 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11913 _("invalid swi expression"));
b99bd4ef
NC
11914 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xff00;
11915 newval |= value;
11916 md_number_to_chars (buf, newval, THUMB_SIZE);
11917 }
11918 else
11919 {
11920 if (((unsigned long) value) > 0x00ffffff)
11921 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11922 _("invalid swi expression"));
b99bd4ef
NC
11923 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff000000;
11924 newval |= value;
11925 md_number_to_chars (buf, newval, INSN_SIZE);
11926 }
11927 break;
11928
11929 case BFD_RELOC_ARM_MULTI:
11930 if (((unsigned long) value) > 0xffff)
11931 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11932 _("invalid expression in load/store multiple"));
b99bd4ef
NC
11933 newval = value | md_chars_to_number (buf, INSN_SIZE);
11934 md_number_to_chars (buf, newval, INSN_SIZE);
11935 break;
11936
11937 case BFD_RELOC_ARM_PCREL_BRANCH:
11938 newval = md_chars_to_number (buf, INSN_SIZE);
11939
11940 /* Sign-extend a 24-bit number. */
11941#define SEXT24(x) ((((x) & 0xffffff) ^ (~ 0x7fffff)) + 0x800000)
11942
11943#ifdef OBJ_ELF
7f266840 11944 value = fixP->fx_offset;
b99bd4ef
NC
11945#endif
11946
11947 /* We are going to store value (shifted right by two) in the
11948 instruction, in a 24 bit, signed field. Thus we need to check
11949 that none of the top 8 bits of the shifted value (top 7 bits of
11950 the unshifted, unsigned value) are set, or that they are all set. */
11951 if ((value & ~ ((offsetT) 0x1ffffff)) != 0
11952 && ((value & ~ ((offsetT) 0x1ffffff)) != ~ ((offsetT) 0x1ffffff)))
11953 {
11954#ifdef OBJ_ELF
11955 /* Normally we would be stuck at this point, since we cannot store
11956 the absolute address that is the destination of the branch in the
11957 24 bits of the branch instruction. If however, we happen to know
11958 that the destination of the branch is in the same section as the
2d2255b5 11959 branch instruction itself, then we can compute the relocation for
b99bd4ef
NC
11960 ourselves and not have to bother the linker with it.
11961
7f266840
DJ
11962 FIXME: The test for OBJ_ELF is only here because I have not
11963 worked out how to do this for OBJ_COFF. */
11964 if (fixP->fx_addsy != NULL
b99bd4ef
NC
11965 && S_IS_DEFINED (fixP->fx_addsy)
11966 && S_GET_SEGMENT (fixP->fx_addsy) == seg)
11967 {
11968 /* Get pc relative value to go into the branch. */
94f592af 11969 value = * valP;
b99bd4ef
NC
11970
11971 /* Permit a backward branch provided that enough bits
11972 are set. Allow a forwards branch, provided that
11973 enough bits are clear. */
11974 if ( (value & ~ ((offsetT) 0x1ffffff)) == ~ ((offsetT) 0x1ffffff)
11975 || (value & ~ ((offsetT) 0x1ffffff)) == 0)
11976 fixP->fx_done = 1;
11977 }
11978
11979 if (! fixP->fx_done)
11980#endif
11981 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 11982 _("GAS can't handle same-section branch dest >= 0x04000000"));
b99bd4ef
NC
11983 }
11984
11985 value >>= 2;
11986 value += SEXT24 (newval);
11987
11988 if ( (value & ~ ((offsetT) 0xffffff)) != 0
11989 && ((value & ~ ((offsetT) 0xffffff)) != ~ ((offsetT) 0xffffff)))
11990 as_bad_where (fixP->fx_file, fixP->fx_line,
11991 _("out of range branch"));
11992
4e7fd91e
PB
11993 if (seg->use_rela_p && !fixP->fx_done)
11994 {
11995 /* Must unshift the value before storing it in the addend. */
11996 value <<= 2;
11997#ifdef OBJ_ELF
11998 fixP->fx_offset = value;
11999#endif
12000 fixP->fx_addnumber = value;
12001 newval = newval & 0xff000000;
12002 }
12003 else
12004 newval = (value & 0x00ffffff) | (newval & 0xff000000);
b99bd4ef
NC
12005 md_number_to_chars (buf, newval, INSN_SIZE);
12006 break;
12007
12008 case BFD_RELOC_ARM_PCREL_BLX:
12009 {
12010 offsetT hbit;
12011 newval = md_chars_to_number (buf, INSN_SIZE);
12012
12013#ifdef OBJ_ELF
7f266840 12014 value = fixP->fx_offset;
b99bd4ef
NC
12015#endif
12016 hbit = (value >> 1) & 1;
12017 value = (value >> 2) & 0x00ffffff;
12018 value = (value + (newval & 0x00ffffff)) & 0x00ffffff;
4e7fd91e
PB
12019
12020 if (seg->use_rela_p && !fixP->fx_done)
12021 {
12022 /* Must sign-extend and unshift the value before storing
12023 it in the addend. */
12024 value = SEXT24 (value);
12025 value = (value << 2) | hbit;
12026#ifdef OBJ_ELF
12027 fixP->fx_offset = value;
12028#endif
12029 fixP->fx_addnumber = value;
12030 newval = newval & 0xfe000000;
12031 }
12032 else
12033 newval = value | (newval & 0xfe000000) | (hbit << 24);
b99bd4ef
NC
12034 md_number_to_chars (buf, newval, INSN_SIZE);
12035 }
12036 break;
12037
12038 case BFD_RELOC_THUMB_PCREL_BRANCH9: /* Conditional branch. */
12039 newval = md_chars_to_number (buf, THUMB_SIZE);
12040 {
12041 addressT diff = (newval & 0xff) << 1;
12042 if (diff & 0x100)
12043 diff |= ~0xff;
12044
12045 value += diff;
12046 if ((value & ~0xff) && ((value & ~0xff) != ~0xff))
12047 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12048 _("branch out of range"));
4e7fd91e
PB
12049 if (seg->use_rela_p && !fixP->fx_done)
12050 {
12051#ifdef OBJ_ELF
12052 fixP->fx_offset = value;
12053#endif
12054 fixP->fx_addnumber = value;
12055 newval = newval & 0xff00;
12056 }
12057 else
12058 newval = (newval & 0xff00) | ((value & 0x1ff) >> 1);
b99bd4ef
NC
12059 }
12060 md_number_to_chars (buf, newval, THUMB_SIZE);
12061 break;
12062
12063 case BFD_RELOC_THUMB_PCREL_BRANCH12: /* Unconditional branch. */
12064 newval = md_chars_to_number (buf, THUMB_SIZE);
12065 {
12066 addressT diff = (newval & 0x7ff) << 1;
12067 if (diff & 0x800)
12068 diff |= ~0x7ff;
12069
12070 value += diff;
12071 if ((value & ~0x7ff) && ((value & ~0x7ff) != ~0x7ff))
12072 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12073 _("branch out of range"));
4e7fd91e
PB
12074 if (seg->use_rela_p && !fixP->fx_done)
12075 {
12076#ifdef OBJ_ELF
12077 fixP->fx_offset = value;
12078#endif
12079 fixP->fx_addnumber = value;
12080 newval = newval & 0xf800;
12081 }
12082 else
12083 newval = (newval & 0xf800) | ((value & 0xfff) >> 1);
b99bd4ef
NC
12084 }
12085 md_number_to_chars (buf, newval, THUMB_SIZE);
12086 break;
12087
12088 case BFD_RELOC_THUMB_PCREL_BLX:
12089 case BFD_RELOC_THUMB_PCREL_BRANCH23:
12090 {
12091 offsetT newval2;
12092 addressT diff;
12093
12094 newval = md_chars_to_number (buf, THUMB_SIZE);
12095 newval2 = md_chars_to_number (buf + THUMB_SIZE, THUMB_SIZE);
12096 diff = ((newval & 0x7ff) << 12) | ((newval2 & 0x7ff) << 1);
12097 if (diff & 0x400000)
12098 diff |= ~0x3fffff;
12099#ifdef OBJ_ELF
12100 value = fixP->fx_offset;
12101#endif
12102 value += diff;
c62e1cc3 12103
b99bd4ef
NC
12104 if ((value & ~0x3fffff) && ((value & ~0x3fffff) != ~0x3fffff))
12105 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12106 _("branch with link out of range"));
b99bd4ef 12107
b99bd4ef 12108 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX)
c62e1cc3
NC
12109 /* For a BLX instruction, make sure that the relocation is rounded up
12110 to a word boundary. This follows the semantics of the instruction
12111 which specifies that bit 1 of the target address will come from bit
12112 1 of the base address. */
4e7fd91e
PB
12113 value = (value + 1) & ~ 1;
12114
12115 if (seg->use_rela_p && !fixP->fx_done)
12116 {
12117#ifdef OBJ_ELF
12118 fixP->fx_offset = value;
12119#endif
12120 fixP->fx_addnumber = value;
12121 newval = newval & 0xf800;
12122 newval2 = newval2 & 0xf800;
12123 }
12124 else
12125 {
12126 newval = (newval & 0xf800) | ((value & 0x7fffff) >> 12);
12127 newval2 = (newval2 & 0xf800) | ((value & 0xfff) >> 1);
12128 }
b99bd4ef
NC
12129 md_number_to_chars (buf, newval, THUMB_SIZE);
12130 md_number_to_chars (buf + THUMB_SIZE, newval2, THUMB_SIZE);
12131 }
12132 break;
12133
12134 case BFD_RELOC_8:
4e7fd91e
PB
12135 if (seg->use_rela_p && !fixP->fx_done)
12136 break;
b99bd4ef
NC
12137 if (fixP->fx_done || fixP->fx_pcrel)
12138 md_number_to_chars (buf, value, 1);
12139#ifdef OBJ_ELF
7f266840 12140 else
b99bd4ef
NC
12141 {
12142 value = fixP->fx_offset;
12143 md_number_to_chars (buf, value, 1);
12144 }
12145#endif
12146 break;
12147
12148 case BFD_RELOC_16:
4e7fd91e
PB
12149 if (seg->use_rela_p && !fixP->fx_done)
12150 break;
b99bd4ef
NC
12151 if (fixP->fx_done || fixP->fx_pcrel)
12152 md_number_to_chars (buf, value, 2);
12153#ifdef OBJ_ELF
7f266840 12154 else
b99bd4ef
NC
12155 {
12156 value = fixP->fx_offset;
12157 md_number_to_chars (buf, value, 2);
12158 }
12159#endif
12160 break;
12161
12162#ifdef OBJ_ELF
ba93b8ac
DJ
12163 case BFD_RELOC_ARM_TLS_GD32:
12164 case BFD_RELOC_ARM_TLS_LE32:
12165 case BFD_RELOC_ARM_TLS_IE32:
12166 case BFD_RELOC_ARM_TLS_LDM32:
12167 case BFD_RELOC_ARM_TLS_LDO32:
12168 S_SET_THREAD_LOCAL (fixP->fx_addsy);
12169 /* fall through */
12170
b99bd4ef
NC
12171 case BFD_RELOC_ARM_GOT32:
12172 case BFD_RELOC_ARM_GOTOFF:
eb043451 12173 case BFD_RELOC_ARM_TARGET2:
4e7fd91e
PB
12174 if (seg->use_rela_p && !fixP->fx_done)
12175 break;
b99bd4ef
NC
12176 md_number_to_chars (buf, 0, 4);
12177 break;
12178#endif
12179
12180 case BFD_RELOC_RVA:
12181 case BFD_RELOC_32:
9c504268 12182 case BFD_RELOC_ARM_TARGET1:
db6579d4
PB
12183 case BFD_RELOC_ARM_ROSEGREL32:
12184 case BFD_RELOC_ARM_SBREL32:
eb043451 12185 case BFD_RELOC_32_PCREL:
4e7fd91e
PB
12186 if (seg->use_rela_p && !fixP->fx_done)
12187 break;
b99bd4ef
NC
12188 if (fixP->fx_done || fixP->fx_pcrel)
12189 md_number_to_chars (buf, value, 4);
12190#ifdef OBJ_ELF
7f266840 12191 else
b99bd4ef
NC
12192 {
12193 value = fixP->fx_offset;
12194 md_number_to_chars (buf, value, 4);
12195 }
12196#endif
12197 break;
12198
12199#ifdef OBJ_ELF
eb043451
PB
12200 case BFD_RELOC_ARM_PREL31:
12201 if (fixP->fx_done || fixP->fx_pcrel)
12202 {
12203 newval = md_chars_to_number (buf, 4) & 0x80000000;
12204 if ((value ^ (value >> 1)) & 0x40000000)
12205 {
12206 as_bad_where (fixP->fx_file, fixP->fx_line,
12207 _("rel31 relocation overflow"));
12208 }
12209 newval |= value & 0x7fffffff;
12210 md_number_to_chars (buf, newval, 4);
12211 }
12212 break;
12213
b99bd4ef
NC
12214 case BFD_RELOC_ARM_PLT32:
12215 /* It appears the instruction is fully prepared at this point. */
12216 break;
12217#endif
12218
b99bd4ef
NC
12219 case BFD_RELOC_ARM_CP_OFF_IMM:
12220 sign = value >= 0;
12221 if (value < -1023 || value > 1023 || (value & 3))
12222 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12223 _("illegal value for co-processor offset"));
b99bd4ef
NC
12224 if (value < 0)
12225 value = -value;
12226 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
12227 newval |= (value >> 2) | (sign ? INDEX_UP : 0);
12228 md_number_to_chars (buf, newval, INSN_SIZE);
12229 break;
12230
e16bb312
NC
12231 case BFD_RELOC_ARM_CP_OFF_IMM_S2:
12232 sign = value >= 0;
12233 if (value < -255 || value > 255)
12234 as_bad_where (fixP->fx_file, fixP->fx_line,
12235 _("Illegal value for co-processor offset"));
12236 if (value < 0)
12237 value = -value;
12238 newval = md_chars_to_number (buf, INSN_SIZE) & 0xff7fff00;
12239 newval |= value | (sign ? INDEX_UP : 0);
12240 md_number_to_chars (buf, newval , INSN_SIZE);
12241 break;
12242
b99bd4ef
NC
12243 case BFD_RELOC_ARM_THUMB_OFFSET:
12244 newval = md_chars_to_number (buf, THUMB_SIZE);
12245 /* Exactly what ranges, and where the offset is inserted depends
12246 on the type of instruction, we can establish this from the
12247 top 4 bits. */
12248 switch (newval >> 12)
12249 {
12250 case 4: /* PC load. */
12251 /* Thumb PC loads are somewhat odd, bit 1 of the PC is
12252 forced to zero for these loads, so we will need to round
12253 up the offset if the instruction address is not word
12254 aligned (since the final address produced must be, and
12255 we can only describe word-aligned immediate offsets). */
12256
12257 if ((fixP->fx_frag->fr_address + fixP->fx_where + value) & 3)
12258 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12259 _("invalid offset, target not word aligned (0x%08X)"),
b99bd4ef
NC
12260 (unsigned int) (fixP->fx_frag->fr_address
12261 + fixP->fx_where + value));
12262
12263 if ((value + 2) & ~0x3fe)
12264 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12265 _("invalid offset, value too big (0x%08lX)"),
12266 (long) value);
b99bd4ef
NC
12267
12268 /* Round up, since pc will be rounded down. */
12269 newval |= (value + 2) >> 2;
12270 break;
12271
12272 case 9: /* SP load/store. */
12273 if (value & ~0x3fc)
12274 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12275 _("invalid offset, value too big (0x%08lX)"),
12276 (long) value);
b99bd4ef
NC
12277 newval |= value >> 2;
12278 break;
12279
12280 case 6: /* Word load/store. */
12281 if (value & ~0x7c)
12282 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12283 _("invalid offset, value too big (0x%08lX)"),
12284 (long) value);
b99bd4ef
NC
12285 newval |= value << 4; /* 6 - 2. */
12286 break;
12287
12288 case 7: /* Byte load/store. */
12289 if (value & ~0x1f)
12290 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12291 _("invalid offset, value too big (0x%08lX)"),
12292 (long) value);
b99bd4ef
NC
12293 newval |= value << 6;
12294 break;
12295
12296 case 8: /* Halfword load/store. */
12297 if (value & ~0x3e)
12298 as_bad_where (fixP->fx_file, fixP->fx_line,
08df2379
NC
12299 _("invalid offset, value too big (0x%08lX)"),
12300 (long) value);
b99bd4ef
NC
12301 newval |= value << 5; /* 6 - 1. */
12302 break;
12303
12304 default:
12305 as_bad_where (fixP->fx_file, fixP->fx_line,
12306 "Unable to process relocation for thumb opcode: %lx",
12307 (unsigned long) newval);
12308 break;
12309 }
12310 md_number_to_chars (buf, newval, THUMB_SIZE);
12311 break;
12312
12313 case BFD_RELOC_ARM_THUMB_ADD:
12314 /* This is a complicated relocation, since we use it for all of
12315 the following immediate relocations:
12316
12317 3bit ADD/SUB
12318 8bit ADD/SUB
12319 9bit ADD/SUB SP word-aligned
12320 10bit ADD PC/SP word-aligned
12321
12322 The type of instruction being processed is encoded in the
12323 instruction field:
12324
12325 0x8000 SUB
12326 0x00F0 Rd
12327 0x000F Rs
12328 */
12329 newval = md_chars_to_number (buf, THUMB_SIZE);
12330 {
12331 int rd = (newval >> 4) & 0xf;
12332 int rs = newval & 0xf;
12333 int subtract = newval & 0x8000;
12334
12335 if (rd == REG_SP)
12336 {
12337 if (value & ~0x1fc)
12338 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12339 _("invalid immediate for stack address calculation"));
b99bd4ef
NC
12340 newval = subtract ? T_OPCODE_SUB_ST : T_OPCODE_ADD_ST;
12341 newval |= value >> 2;
12342 }
12343 else if (rs == REG_PC || rs == REG_SP)
12344 {
12345 if (subtract ||
12346 value & ~0x3fc)
12347 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12348 _("invalid immediate for address calculation (value = 0x%08lX)"),
b99bd4ef
NC
12349 (unsigned long) value);
12350 newval = (rs == REG_PC ? T_OPCODE_ADD_PC : T_OPCODE_ADD_SP);
12351 newval |= rd << 8;
12352 newval |= value >> 2;
12353 }
12354 else if (rs == rd)
12355 {
12356 if (value & ~0xff)
12357 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12358 _("invalid 8bit immediate"));
b99bd4ef
NC
12359 newval = subtract ? T_OPCODE_SUB_I8 : T_OPCODE_ADD_I8;
12360 newval |= (rd << 8) | value;
12361 }
12362 else
12363 {
12364 if (value & ~0x7)
12365 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12366 _("invalid 3bit immediate"));
b99bd4ef
NC
12367 newval = subtract ? T_OPCODE_SUB_I3 : T_OPCODE_ADD_I3;
12368 newval |= rd | (rs << 3) | (value << 6);
12369 }
12370 }
12371 md_number_to_chars (buf, newval, THUMB_SIZE);
12372 break;
12373
12374 case BFD_RELOC_ARM_THUMB_IMM:
12375 newval = md_chars_to_number (buf, THUMB_SIZE);
12376 switch (newval >> 11)
12377 {
12378 case 0x04: /* 8bit immediate MOV. */
12379 case 0x05: /* 8bit immediate CMP. */
12380 if (value < 0 || value > 255)
12381 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12382 _("invalid immediate: %ld is too large"),
b99bd4ef
NC
12383 (long) value);
12384 newval |= value;
12385 break;
12386
12387 default:
12388 abort ();
12389 }
12390 md_number_to_chars (buf, newval, THUMB_SIZE);
12391 break;
12392
12393 case BFD_RELOC_ARM_THUMB_SHIFT:
12394 /* 5bit shift value (0..31). */
12395 if (value < 0 || value > 31)
12396 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12397 _("illegal Thumb shift value: %ld"), (long) value);
b99bd4ef
NC
12398 newval = md_chars_to_number (buf, THUMB_SIZE) & 0xf03f;
12399 newval |= value << 6;
12400 md_number_to_chars (buf, newval, THUMB_SIZE);
12401 break;
12402
12403 case BFD_RELOC_VTABLE_INHERIT:
12404 case BFD_RELOC_VTABLE_ENTRY:
12405 fixP->fx_done = 0;
94f592af 12406 return;
b99bd4ef 12407
620b81c1 12408 case BFD_RELOC_UNUSED:
b99bd4ef
NC
12409 default:
12410 as_bad_where (fixP->fx_file, fixP->fx_line,
f03698e6 12411 _("bad relocation fixup type (%d)"), fixP->fx_r_type);
b99bd4ef 12412 }
b99bd4ef
NC
12413}
12414
12415/* Translate internal representation of relocation info to BFD target
12416 format. */
12417
12418arelent *
a737bd4d
NC
12419tc_gen_reloc (asection * section ATTRIBUTE_UNUSED,
12420 fixS * fixp)
b99bd4ef
NC
12421{
12422 arelent * reloc;
12423 bfd_reloc_code_real_type code;
12424
a737bd4d 12425 reloc = xmalloc (sizeof (arelent));
b99bd4ef 12426
a737bd4d 12427 reloc->sym_ptr_ptr = xmalloc (sizeof (asymbol *));
b99bd4ef
NC
12428 *reloc->sym_ptr_ptr = symbol_get_bfdsym (fixp->fx_addsy);
12429 reloc->address = fixp->fx_frag->fr_address + fixp->fx_where;
12430
12431 /* @@ Why fx_addnumber sometimes and fx_offset other times? */
12432#ifndef OBJ_ELF
12433 if (fixp->fx_pcrel == 0)
12434 reloc->addend = fixp->fx_offset;
12435 else
12436 reloc->addend = fixp->fx_offset = reloc->address;
12437#else /* OBJ_ELF */
12438 reloc->addend = fixp->fx_offset;
12439#endif
12440
12441 switch (fixp->fx_r_type)
12442 {
12443 case BFD_RELOC_8:
12444 if (fixp->fx_pcrel)
12445 {
12446 code = BFD_RELOC_8_PCREL;
12447 break;
12448 }
12449
12450 case BFD_RELOC_16:
12451 if (fixp->fx_pcrel)
12452 {
12453 code = BFD_RELOC_16_PCREL;
12454 break;
12455 }
12456
12457 case BFD_RELOC_32:
12458 if (fixp->fx_pcrel)
12459 {
12460 code = BFD_RELOC_32_PCREL;
12461 break;
12462 }
12463
620b81c1 12464 case BFD_RELOC_NONE:
b99bd4ef
NC
12465 case BFD_RELOC_ARM_PCREL_BRANCH:
12466 case BFD_RELOC_ARM_PCREL_BLX:
12467 case BFD_RELOC_RVA:
12468 case BFD_RELOC_THUMB_PCREL_BRANCH9:
12469 case BFD_RELOC_THUMB_PCREL_BRANCH12:
12470 case BFD_RELOC_THUMB_PCREL_BRANCH23:
12471 case BFD_RELOC_THUMB_PCREL_BLX:
12472 case BFD_RELOC_VTABLE_ENTRY:
12473 case BFD_RELOC_VTABLE_INHERIT:
12474 code = fixp->fx_r_type;
12475 break;
12476
12477 case BFD_RELOC_ARM_LITERAL:
12478 case BFD_RELOC_ARM_HWLITERAL:
3d0c9500
NC
12479 /* If this is called then the a literal has
12480 been referenced across a section boundary. */
b99bd4ef 12481 as_bad_where (fixp->fx_file, fixp->fx_line,
61b5f74b 12482 _("literal referenced across section boundary"));
b99bd4ef
NC
12483 return NULL;
12484
12485#ifdef OBJ_ELF
12486 case BFD_RELOC_ARM_GOT32:
12487 case BFD_RELOC_ARM_GOTOFF:
12488 case BFD_RELOC_ARM_PLT32:
9c504268 12489 case BFD_RELOC_ARM_TARGET1:
db6579d4
PB
12490 case BFD_RELOC_ARM_ROSEGREL32:
12491 case BFD_RELOC_ARM_SBREL32:
eb043451
PB
12492 case BFD_RELOC_ARM_PREL31:
12493 case BFD_RELOC_ARM_TARGET2:
ba93b8ac
DJ
12494 case BFD_RELOC_ARM_TLS_LE32:
12495 case BFD_RELOC_ARM_TLS_LDO32:
12496 code = fixp->fx_r_type;
12497 break;
12498
12499 case BFD_RELOC_ARM_TLS_GD32:
12500 case BFD_RELOC_ARM_TLS_IE32:
12501 case BFD_RELOC_ARM_TLS_LDM32:
12502 /* BFD will include the symbol's address in the addend.
12503 But we don't want that, so subtract it out again here. */
12504 if (!S_IS_COMMON (fixp->fx_addsy))
12505 reloc->addend -= (*reloc->sym_ptr_ptr)->value;
b99bd4ef
NC
12506 code = fixp->fx_r_type;
12507 break;
12508#endif
12509
12510 case BFD_RELOC_ARM_IMMEDIATE:
12511 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 12512 _("internal relocation (type: IMMEDIATE) not fixed up"));
b99bd4ef
NC
12513 return NULL;
12514
12515 case BFD_RELOC_ARM_ADRL_IMMEDIATE:
12516 as_bad_where (fixp->fx_file, fixp->fx_line,
12517 _("ADRL used for a symbol not defined in the same file"));
12518 return NULL;
12519
12520 case BFD_RELOC_ARM_OFFSET_IMM:
c3ba240c
DJ
12521 if (fixp->fx_addsy != NULL
12522 && !S_IS_DEFINED (fixp->fx_addsy)
12523 && S_IS_LOCAL (fixp->fx_addsy))
12524 {
12525 as_bad_where (fixp->fx_file, fixp->fx_line,
12526 _("undefined local label `%s'"),
12527 S_GET_NAME (fixp->fx_addsy));
12528 return NULL;
12529 }
12530
b99bd4ef 12531 as_bad_where (fixp->fx_file, fixp->fx_line,
6189168b 12532 _("internal_relocation (type: OFFSET_IMM) not fixed up"));
b99bd4ef
NC
12533 return NULL;
12534
12535 default:
12536 {
12537 char * type;
12538
12539 switch (fixp->fx_r_type)
12540 {
620b81c1 12541 case BFD_RELOC_NONE: type = "NONE"; break;
b99bd4ef
NC
12542 case BFD_RELOC_ARM_OFFSET_IMM8: type = "OFFSET_IMM8"; break;
12543 case BFD_RELOC_ARM_SHIFT_IMM: type = "SHIFT_IMM"; break;
0dd132b6 12544 case BFD_RELOC_ARM_SMI: type = "SMI"; break;
b99bd4ef
NC
12545 case BFD_RELOC_ARM_SWI: type = "SWI"; break;
12546 case BFD_RELOC_ARM_MULTI: type = "MULTI"; break;
12547 case BFD_RELOC_ARM_CP_OFF_IMM: type = "CP_OFF_IMM"; break;
12548 case BFD_RELOC_ARM_THUMB_ADD: type = "THUMB_ADD"; break;
12549 case BFD_RELOC_ARM_THUMB_SHIFT: type = "THUMB_SHIFT"; break;
12550 case BFD_RELOC_ARM_THUMB_IMM: type = "THUMB_IMM"; break;
12551 case BFD_RELOC_ARM_THUMB_OFFSET: type = "THUMB_OFFSET"; break;
12552 default: type = _("<unknown>"); break;
12553 }
12554 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 12555 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
12556 type);
12557 return NULL;
12558 }
12559 }
12560
12561#ifdef OBJ_ELF
8df7094c 12562 if ((code == BFD_RELOC_32_PCREL || code == BFD_RELOC_32)
b99bd4ef
NC
12563 && GOT_symbol
12564 && fixp->fx_addsy == GOT_symbol)
12565 {
12566 code = BFD_RELOC_ARM_GOTPC;
12567 reloc->addend = fixp->fx_offset = reloc->address;
12568 }
12569#endif
12570
12571 reloc->howto = bfd_reloc_type_lookup (stdoutput, code);
12572
12573 if (reloc->howto == NULL)
12574 {
12575 as_bad_where (fixp->fx_file, fixp->fx_line,
f03698e6 12576 _("cannot represent %s relocation in this object file format"),
b99bd4ef
NC
12577 bfd_get_reloc_code_name (code));
12578 return NULL;
12579 }
12580
12581 /* HACK: Since arm ELF uses Rel instead of Rela, encode the
12582 vtable entry to be used in the relocation's section offset. */
12583 if (fixp->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
12584 reloc->address = fixp->fx_offset;
12585
12586 return reloc;
12587}
12588
12589int
a737bd4d
NC
12590md_estimate_size_before_relax (fragS * fragP ATTRIBUTE_UNUSED,
12591 segT segtype ATTRIBUTE_UNUSED)
b99bd4ef
NC
12592{
12593 as_fatal (_("md_estimate_size_before_relax\n"));
12594 return 1;
12595}
12596
a737bd4d
NC
12597/* We need to be able to fix up arbitrary expressions in some statements.
12598 This is so that we can handle symbols that are an arbitrary distance from
12599 the pc. The most common cases are of the form ((+/-sym -/+ . - 8) & mask),
12600 which returns part of an address in a form which will be valid for
12601 a data instruction. We do this by pushing the expression into a symbol
12602 in the expr_section, and creating a fix for that. */
12603
12604static void
12605fix_new_arm (fragS * frag,
12606 int where,
12607 short int size,
12608 expressionS * exp,
12609 int pc_rel,
12610 int reloc)
12611{
12612 fixS * new_fix;
12613 arm_fix_data * arm_data;
12614
12615 switch (exp->X_op)
12616 {
12617 case O_constant:
12618 case O_symbol:
12619 case O_add:
12620 case O_subtract:
12621 new_fix = fix_new_exp (frag, where, size, exp, pc_rel, reloc);
12622 break;
12623
12624 default:
12625 new_fix = fix_new (frag, where, size, make_expr_symbol (exp), 0,
12626 pc_rel, reloc);
12627 break;
12628 }
12629
12630 /* Mark whether the fix is to a THUMB instruction, or an ARM
12631 instruction. */
12632 arm_data = obstack_alloc (& notes, sizeof (arm_fix_data));
12633 new_fix->tc_fix_data = (PTR) arm_data;
12634 arm_data->thumb_mode = thumb_mode;
12635}
12636
b99bd4ef 12637static void
a737bd4d 12638output_inst (const char * str)
b99bd4ef
NC
12639{
12640 char * to = NULL;
12641
12642 if (inst.error)
12643 {
f03698e6 12644 as_bad ("%s -- `%s'", inst.error, str);
b99bd4ef
NC
12645 return;
12646 }
12647
12648 to = frag_more (inst.size);
12649
12650 if (thumb_mode && (inst.size > THUMB_SIZE))
12651 {
12652 assert (inst.size == (2 * THUMB_SIZE));
12653 md_number_to_chars (to, inst.instruction >> 16, THUMB_SIZE);
12654 md_number_to_chars (to + THUMB_SIZE, inst.instruction, THUMB_SIZE);
12655 }
12656 else if (inst.size > INSN_SIZE)
12657 {
12658 assert (inst.size == (2 * INSN_SIZE));
12659 md_number_to_chars (to, inst.instruction, INSN_SIZE);
12660 md_number_to_chars (to + INSN_SIZE, inst.instruction, INSN_SIZE);
12661 }
12662 else
12663 md_number_to_chars (to, inst.instruction, inst.size);
12664
620b81c1 12665 if (inst.reloc.type != BFD_RELOC_UNUSED)
b99bd4ef
NC
12666 fix_new_arm (frag_now, to - frag_now->fr_literal,
12667 inst.size, & inst.reloc.exp, inst.reloc.pc_rel,
12668 inst.reloc.type);
12669
12670#ifdef OBJ_ELF
12671 dwarf2_emit_insn (inst.size);
12672#endif
12673}
12674
12675void
a737bd4d 12676md_assemble (char * str)
b99bd4ef 12677{
6c43fab6
RE
12678 char c;
12679 char *p;
12680 char *start;
b99bd4ef 12681
b99bd4ef
NC
12682 /* Align the previous label if needed. */
12683 if (last_label_seen != NULL)
12684 {
12685 symbol_set_frag (last_label_seen, frag_now);
12686 S_SET_VALUE (last_label_seen, (valueT) frag_now_fix ());
12687 S_SET_SEGMENT (last_label_seen, now_seg);
12688 }
12689
12690 memset (&inst, '\0', sizeof (inst));
620b81c1 12691 inst.reloc.type = BFD_RELOC_UNUSED;
b99bd4ef
NC
12692
12693 skip_whitespace (str);
12694
12695 /* Scan up to the end of the op-code, which must end in white space or
12696 end of string. */
12697 for (start = p = str; *p != '\0'; p++)
12698 if (*p == ' ')
12699 break;
12700
12701 if (p == str)
12702 {
f03698e6 12703 as_bad (_("no operator -- statement `%s'\n"), str);
b99bd4ef
NC
12704 return;
12705 }
12706
12707 if (thumb_mode)
12708 {
05d2d07e 12709 const struct thumb_opcode * opcode;
b99bd4ef
NC
12710
12711 c = *p;
12712 *p = '\0';
05d2d07e 12713 opcode = (const struct thumb_opcode *) hash_find (arm_tops_hsh, str);
b99bd4ef
NC
12714 *p = c;
12715
12716 if (opcode)
12717 {
12718 /* Check that this instruction is supported for this CPU. */
90e4755a 12719 if (thumb_mode == 1 && (opcode->variant & cpu_variant) == 0)
b99bd4ef 12720 {
f03698e6 12721 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
12722 return;
12723 }
12724
6057a28f 12725 mapping_state (MAP_THUMB);
b99bd4ef
NC
12726 inst.instruction = opcode->value;
12727 inst.size = opcode->size;
a737bd4d 12728 opcode->parms (p);
f03698e6 12729 output_inst (str);
b99bd4ef
NC
12730 return;
12731 }
12732 }
12733 else
12734 {
05d2d07e 12735 const struct asm_opcode * opcode;
b99bd4ef 12736
90e4755a
RE
12737 c = *p;
12738 *p = '\0';
6c43fab6 12739 opcode = (const struct asm_opcode *) hash_find (arm_ops_hsh, str);
90e4755a 12740 *p = c;
b99bd4ef 12741
90e4755a 12742 if (opcode)
b99bd4ef 12743 {
90e4755a
RE
12744 /* Check that this instruction is supported for this CPU. */
12745 if ((opcode->variant & cpu_variant) == 0)
b99bd4ef 12746 {
f03698e6 12747 as_bad (_("selected processor does not support `%s'"), str);
b99bd4ef
NC
12748 return;
12749 }
12750
6057a28f 12751 mapping_state (MAP_ARM);
90e4755a
RE
12752 inst.instruction = opcode->value;
12753 inst.size = INSN_SIZE;
a737bd4d 12754 opcode->parms (p);
f03698e6 12755 output_inst (str);
90e4755a 12756 return;
b99bd4ef
NC
12757 }
12758 }
12759
12760 /* It wasn't an instruction, but it might be a register alias of the form
12761 alias .req reg. */
6c43fab6
RE
12762 if (create_register_alias (str, p))
12763 return;
b99bd4ef 12764
b99bd4ef
NC
12765 as_bad (_("bad instruction `%s'"), start);
12766}
12767
12768/* md_parse_option
12769 Invocation line includes a switch not recognized by the base assembler.
cc8a6dd0 12770 See if it's a processor-specific option.
03b1477f
RE
12771
12772 This routine is somewhat complicated by the need for backwards
12773 compatibility (since older releases of gcc can't be changed).
12774 The new options try to make the interface as compatible as
12775 possible with GCC.
12776
12777 New options (supported) are:
12778
12779 -mcpu=<cpu name> Assemble for selected processor
12780 -march=<architecture name> Assemble for selected architecture
12781 -mfpu=<fpu architecture> Assemble for selected FPU.
12782 -EB/-mbig-endian Big-endian
12783 -EL/-mlittle-endian Little-endian
12784 -k Generate PIC code
12785 -mthumb Start in Thumb mode
12786 -mthumb-interwork Code supports ARM/Thumb interworking
12787
3d0c9500 12788 For now we will also provide support for:
03b1477f
RE
12789
12790 -mapcs-32 32-bit Program counter
12791 -mapcs-26 26-bit Program counter
12792 -macps-float Floats passed in FP registers
12793 -mapcs-reentrant Reentrant code
12794 -matpcs
12795 (sometime these will probably be replaced with -mapcs=<list of options>
12796 and -matpcs=<list of options>)
12797
12798 The remaining options are only supported for back-wards compatibility.
b99bd4ef
NC
12799 Cpu variants, the arm part is optional:
12800 -m[arm]1 Currently not supported.
12801 -m[arm]2, -m[arm]250 Arm 2 and Arm 250 processor
12802 -m[arm]3 Arm 3 processor
12803 -m[arm]6[xx], Arm 6 processors
12804 -m[arm]7[xx][t][[d]m] Arm 7 processors
12805 -m[arm]8[10] Arm 8 processors
12806 -m[arm]9[20][tdmi] Arm 9 processors
12807 -mstrongarm[110[0]] StrongARM processors
12808 -mxscale XScale processors
12809 -m[arm]v[2345[t[e]]] Arm architectures
12810 -mall All (except the ARM1)
12811 FP variants:
12812 -mfpa10, -mfpa11 FPA10 and 11 co-processor instructions
12813 -mfpe-old (No float load/store multiples)
bfae80f2
RE
12814 -mvfpxd VFP Single precision
12815 -mvfp All VFP
b99bd4ef 12816 -mno-fpu Disable all floating point instructions
b99bd4ef 12817
03b1477f
RE
12818 The following CPU names are recognized:
12819 arm1, arm2, arm250, arm3, arm6, arm600, arm610, arm620,
12820 arm7, arm7m, arm7d, arm7dm, arm7di, arm7dmi, arm70, arm700,
12821 arm700i, arm710 arm710t, arm720, arm720t, arm740t, arm710c,
12822 arm7100, arm7500, arm7500fe, arm7tdmi, arm8, arm810, arm9,
12823 arm920, arm920t, arm940t, arm946, arm966, arm9tdmi, arm9e,
12824 arm10t arm10e, arm1020t, arm1020e, arm10200e,
12825 strongarm, strongarm110, strongarm1100, strongarm1110, xscale.
12826
12827 */
12828
5a38dc70 12829const char * md_shortopts = "m:k";
03b1477f 12830
b99bd4ef
NC
12831#ifdef ARM_BI_ENDIAN
12832#define OPTION_EB (OPTION_MD_BASE + 0)
b99bd4ef 12833#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 12834#else
21f0f23a
RE
12835#if TARGET_BYTES_BIG_ENDIAN
12836#define OPTION_EB (OPTION_MD_BASE + 0)
21f0f23a
RE
12837#else
12838#define OPTION_EL (OPTION_MD_BASE + 1)
21f0f23a 12839#endif
ce058b6c 12840#endif
03b1477f
RE
12841
12842struct option md_longopts[] =
12843{
12844#ifdef OPTION_EB
12845 {"EB", no_argument, NULL, OPTION_EB},
12846#endif
12847#ifdef OPTION_EL
12848 {"EL", no_argument, NULL, OPTION_EL},
b99bd4ef
NC
12849#endif
12850 {NULL, no_argument, NULL, 0}
12851};
12852
12853size_t md_longopts_size = sizeof (md_longopts);
12854
03b1477f 12855struct arm_option_table
b99bd4ef 12856{
03b1477f
RE
12857 char *option; /* Option name to match. */
12858 char *help; /* Help information. */
12859 int *var; /* Variable to change. */
12860 int value; /* What to change it to. */
12861 char *deprecated; /* If non-null, print this message. */
12862};
b99bd4ef 12863
cc8a6dd0 12864struct arm_option_table arm_opts[] =
03b1477f
RE
12865{
12866 {"k", N_("generate PIC code"), &pic_code, 1, NULL},
12867 {"mthumb", N_("assemble Thumb code"), &thumb_mode, 1, NULL},
12868 {"mthumb-interwork", N_("support ARM/Thumb interworking"),
12869 &support_interwork, 1, NULL},
03b1477f
RE
12870 {"mapcs-32", N_("code uses 32-bit program counter"), &uses_apcs_26, 0, NULL},
12871 {"mapcs-26", N_("code uses 26-bit program counter"), &uses_apcs_26, 1, NULL},
12872 {"mapcs-float", N_("floating point args are in fp regs"), &uses_apcs_float,
12873 1, NULL},
12874 {"mapcs-reentrant", N_("re-entrant code"), &pic_code, 1, NULL},
12875 {"matpcs", N_("code is ATPCS conformant"), &atpcs, 1, NULL},
12876 {"mbig-endian", N_("assemble for big-endian"), &target_big_endian, 1, NULL},
12877 {"mlittle-endian", N_("assemble for little-endian"), &target_big_endian, 1,
12878 NULL},
12879
12880 /* These are recognized by the assembler, but have no affect on code. */
12881 {"mapcs-frame", N_("use frame pointer"), NULL, 0, NULL},
12882 {"mapcs-stack-check", N_("use stack size checking"), NULL, 0, NULL},
12883
12884 /* DON'T add any new processors to this list -- we want the whole list
12885 to go away... Add them to the processors table instead. */
12886 {"marm1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
12887 {"m1", NULL, &legacy_cpu, ARM_ARCH_V1, N_("use -mcpu=arm1")},
12888 {"marm2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
12889 {"m2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -mcpu=arm2")},
12890 {"marm250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
12891 {"m250", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm250")},
12892 {"marm3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
12893 {"m3", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -mcpu=arm3")},
12894 {"marm6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
12895 {"m6", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm6")},
12896 {"marm600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
12897 {"m600", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm600")},
12898 {"marm610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
12899 {"m610", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm610")},
12900 {"marm620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
12901 {"m620", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm620")},
12902 {"marm7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
12903 {"m7", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7")},
12904 {"marm70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
12905 {"m70", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm70")},
12906 {"marm700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
12907 {"m700", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700")},
12908 {"marm700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
12909 {"m700i", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm700i")},
12910 {"marm710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
12911 {"m710", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710")},
12912 {"marm710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
12913 {"m710c", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm710c")},
12914 {"marm720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
12915 {"m720", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm720")},
12916 {"marm7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
12917 {"m7d", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7d")},
12918 {"marm7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
12919 {"m7di", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7di")},
12920 {"marm7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
12921 {"m7m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7m")},
12922 {"marm7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
12923 {"m7dm", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dm")},
12924 {"marm7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
12925 {"m7dmi", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -mcpu=arm7dmi")},
12926 {"marm7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
12927 {"m7100", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7100")},
12928 {"marm7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
12929 {"m7500", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500")},
12930 {"marm7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
12931 {"m7500fe", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -mcpu=arm7500fe")},
12932 {"marm7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12933 {"m7t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12934 {"marm7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12935 {"m7tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm7tdmi")},
12936 {"marm710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
12937 {"m710t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm710t")},
12938 {"marm720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
12939 {"m720t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm720t")},
12940 {"marm740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
12941 {"m740t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm740t")},
12942 {"marm8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
12943 {"m8", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm8")},
12944 {"marm810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
12945 {"m810", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=arm810")},
12946 {"marm9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
12947 {"m9", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9")},
12948 {"marm9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
12949 {"m9tdmi", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm9tdmi")},
12950 {"marm920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
12951 {"m920", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm920")},
12952 {"marm940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
12953 {"m940", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -mcpu=arm940")},
12954 {"mstrongarm", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -mcpu=strongarm")},
12955 {"mstrongarm110", NULL, &legacy_cpu, ARM_ARCH_V4,
12956 N_("use -mcpu=strongarm110")},
12957 {"mstrongarm1100", NULL, &legacy_cpu, ARM_ARCH_V4,
12958 N_("use -mcpu=strongarm1100")},
12959 {"mstrongarm1110", NULL, &legacy_cpu, ARM_ARCH_V4,
12960 N_("use -mcpu=strongarm1110")},
12961 {"mxscale", NULL, &legacy_cpu, ARM_ARCH_XSCALE, N_("use -mcpu=xscale")},
e16bb312 12962 {"miwmmxt", NULL, &legacy_cpu, ARM_ARCH_IWMMXT, N_("use -mcpu=iwmmxt")},
03b1477f
RE
12963 {"mall", NULL, &legacy_cpu, ARM_ANY, N_("use -mcpu=all")},
12964
12965 /* Architecture variants -- don't add any more to this list either. */
12966 {"mv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
12967 {"marmv2", NULL, &legacy_cpu, ARM_ARCH_V2, N_("use -march=armv2")},
12968 {"mv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
12969 {"marmv2a", NULL, &legacy_cpu, ARM_ARCH_V2S, N_("use -march=armv2a")},
12970 {"mv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
12971 {"marmv3", NULL, &legacy_cpu, ARM_ARCH_V3, N_("use -march=armv3")},
12972 {"mv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
12973 {"marmv3m", NULL, &legacy_cpu, ARM_ARCH_V3M, N_("use -march=armv3m")},
12974 {"mv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
12975 {"marmv4", NULL, &legacy_cpu, ARM_ARCH_V4, N_("use -march=armv4")},
12976 {"mv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
12977 {"marmv4t", NULL, &legacy_cpu, ARM_ARCH_V4T, N_("use -march=armv4t")},
12978 {"mv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
12979 {"marmv5", NULL, &legacy_cpu, ARM_ARCH_V5, N_("use -march=armv5")},
12980 {"mv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
12981 {"marmv5t", NULL, &legacy_cpu, ARM_ARCH_V5T, N_("use -march=armv5t")},
12982 {"mv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
12983 {"marmv5e", NULL, &legacy_cpu, ARM_ARCH_V5TE, N_("use -march=armv5te")},
12984
12985 /* Floating point variants -- don't add any more to this list either. */
12986 {"mfpe-old", NULL, &legacy_fpu, FPU_ARCH_FPE, N_("use -mfpu=fpe")},
12987 {"mfpa10", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa10")},
12988 {"mfpa11", NULL, &legacy_fpu, FPU_ARCH_FPA, N_("use -mfpu=fpa11")},
12989 {"mno-fpu", NULL, &legacy_fpu, 0,
12990 N_("use either -mfpu=softfpa or -mfpu=softvfp")},
12991
12992 {NULL, NULL, NULL, 0, NULL}
12993};
21f0f23a 12994
03b1477f
RE
12995struct arm_cpu_option_table
12996{
12997 char *name;
12998 int value;
12999 /* For some CPUs we assume an FPU unless the user explicitly sets
13000 -mfpu=... */
13001 int default_fpu;
13002};
13003
13004/* This list should, at a minimum, contain all the cpu names
13005 recognized by GCC. */
13006static struct arm_cpu_option_table arm_cpus[] =
13007{
13008 {"all", ARM_ANY, FPU_ARCH_FPA},
13009 {"arm1", ARM_ARCH_V1, FPU_ARCH_FPA},
13010 {"arm2", ARM_ARCH_V2, FPU_ARCH_FPA},
13011 {"arm250", ARM_ARCH_V2S, FPU_ARCH_FPA},
13012 {"arm3", ARM_ARCH_V2S, FPU_ARCH_FPA},
13013 {"arm6", ARM_ARCH_V3, FPU_ARCH_FPA},
13014 {"arm60", ARM_ARCH_V3, FPU_ARCH_FPA},
13015 {"arm600", ARM_ARCH_V3, FPU_ARCH_FPA},
13016 {"arm610", ARM_ARCH_V3, FPU_ARCH_FPA},
13017 {"arm620", ARM_ARCH_V3, FPU_ARCH_FPA},
13018 {"arm7", ARM_ARCH_V3, FPU_ARCH_FPA},
13019 {"arm7m", ARM_ARCH_V3M, FPU_ARCH_FPA},
13020 {"arm7d", ARM_ARCH_V3, FPU_ARCH_FPA},
13021 {"arm7dm", ARM_ARCH_V3M, FPU_ARCH_FPA},
13022 {"arm7di", ARM_ARCH_V3, FPU_ARCH_FPA},
13023 {"arm7dmi", ARM_ARCH_V3M, FPU_ARCH_FPA},
13024 {"arm70", ARM_ARCH_V3, FPU_ARCH_FPA},
13025 {"arm700", ARM_ARCH_V3, FPU_ARCH_FPA},
13026 {"arm700i", ARM_ARCH_V3, FPU_ARCH_FPA},
13027 {"arm710", ARM_ARCH_V3, FPU_ARCH_FPA},
13028 {"arm710t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13029 {"arm720", ARM_ARCH_V3, FPU_ARCH_FPA},
13030 {"arm720t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13031 {"arm740t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13032 {"arm710c", ARM_ARCH_V3, FPU_ARCH_FPA},
13033 {"arm7100", ARM_ARCH_V3, FPU_ARCH_FPA},
13034 {"arm7500", ARM_ARCH_V3, FPU_ARCH_FPA},
13035 {"arm7500fe", ARM_ARCH_V3, FPU_ARCH_FPA},
13036 {"arm7t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13037 {"arm7tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
8783612f 13038 {"arm7tdmi-s", ARM_ARCH_V4T, FPU_ARCH_FPA},
03b1477f
RE
13039 {"arm8", ARM_ARCH_V4, FPU_ARCH_FPA},
13040 {"arm810", ARM_ARCH_V4, FPU_ARCH_FPA},
13041 {"strongarm", ARM_ARCH_V4, FPU_ARCH_FPA},
13042 {"strongarm1", ARM_ARCH_V4, FPU_ARCH_FPA},
13043 {"strongarm110", ARM_ARCH_V4, FPU_ARCH_FPA},
13044 {"strongarm1100", ARM_ARCH_V4, FPU_ARCH_FPA},
13045 {"strongarm1110", ARM_ARCH_V4, FPU_ARCH_FPA},
13046 {"arm9", ARM_ARCH_V4T, FPU_ARCH_FPA},
13047 {"arm920", ARM_ARCH_V4T, FPU_ARCH_FPA},
13048 {"arm920t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13049 {"arm922t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13050 {"arm940t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13051 {"arm9tdmi", ARM_ARCH_V4T, FPU_ARCH_FPA},
13052 /* For V5 or later processors we default to using VFP; but the user
13053 should really set the FPU type explicitly. */
13054 {"arm9e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
13055 {"arm9e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
ea6ef066 13056 {"arm926ej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
7de9afa2 13057 {"arm926ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
8783612f 13058 {"arm926ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
03b1477f
RE
13059 {"arm946e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
13060 {"arm946e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13061 {"arm966e-r0", ARM_ARCH_V5TExP, FPU_ARCH_VFP_V2},
13062 {"arm966e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13063 {"arm10t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
13064 {"arm10e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13065 {"arm1020", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
13066 {"arm1020t", ARM_ARCH_V5T, FPU_ARCH_VFP_V1},
13067 {"arm1020e", ARM_ARCH_V5TE, FPU_ARCH_VFP_V2},
5dc1606f
PB
13068 {"arm1026ejs", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
13069 {"arm1026ej-s", ARM_ARCH_V5TEJ, FPU_ARCH_VFP_V2},
09d92015 13070 {"arm1136js", ARM_ARCH_V6, FPU_NONE},
9166bcd7 13071 {"arm1136j-s", ARM_ARCH_V6, FPU_NONE},
09d92015 13072 {"arm1136jfs", ARM_ARCH_V6, FPU_ARCH_VFP_V2},
8783612f 13073 {"arm1136jf-s", ARM_ARCH_V6, FPU_ARCH_VFP_V2},
0dd132b6
NC
13074 {"mpcore", ARM_ARCH_V6K, FPU_ARCH_VFP_V2},
13075 {"mpcorenovfp", ARM_ARCH_V6K, FPU_NONE},
13076 {"arm1176jz-s", ARM_ARCH_V6ZK, FPU_NONE},
13077 {"arm1176jzf-s", ARM_ARCH_V6ZK, FPU_ARCH_VFP_V2},
03b1477f
RE
13078 /* ??? XSCALE is really an architecture. */
13079 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
5a6c6817 13080 /* ??? iwmmxt is not a processor. */
e16bb312 13081 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP_V2},
03b1477f
RE
13082 {"i80200", ARM_ARCH_XSCALE, FPU_ARCH_VFP_V2},
13083 /* Maverick */
33a392fb 13084 {"ep9312", ARM_ARCH_V4T | ARM_CEXT_MAVERICK, FPU_ARCH_MAVERICK},
03b1477f
RE
13085 {NULL, 0, 0}
13086};
cc8a6dd0 13087
03b1477f
RE
13088struct arm_arch_option_table
13089{
13090 char *name;
13091 int value;
13092 int default_fpu;
13093};
13094
13095/* This list should, at a minimum, contain all the architecture names
13096 recognized by GCC. */
13097static struct arm_arch_option_table arm_archs[] =
13098{
13099 {"all", ARM_ANY, FPU_ARCH_FPA},
13100 {"armv1", ARM_ARCH_V1, FPU_ARCH_FPA},
13101 {"armv2", ARM_ARCH_V2, FPU_ARCH_FPA},
13102 {"armv2a", ARM_ARCH_V2S, FPU_ARCH_FPA},
13103 {"armv2s", ARM_ARCH_V2S, FPU_ARCH_FPA},
13104 {"armv3", ARM_ARCH_V3, FPU_ARCH_FPA},
13105 {"armv3m", ARM_ARCH_V3M, FPU_ARCH_FPA},
13106 {"armv4", ARM_ARCH_V4, FPU_ARCH_FPA},
13107 {"armv4xm", ARM_ARCH_V4xM, FPU_ARCH_FPA},
13108 {"armv4t", ARM_ARCH_V4T, FPU_ARCH_FPA},
13109 {"armv4txm", ARM_ARCH_V4TxM, FPU_ARCH_FPA},
13110 {"armv5", ARM_ARCH_V5, FPU_ARCH_VFP},
13111 {"armv5t", ARM_ARCH_V5T, FPU_ARCH_VFP},
13112 {"armv5txm", ARM_ARCH_V5TxM, FPU_ARCH_VFP},
13113 {"armv5te", ARM_ARCH_V5TE, FPU_ARCH_VFP},
13114 {"armv5texp", ARM_ARCH_V5TExP, FPU_ARCH_VFP},
ea6ef066 13115 {"armv5tej", ARM_ARCH_V5TEJ, FPU_ARCH_VFP},
84255574 13116 {"armv6", ARM_ARCH_V6, FPU_ARCH_VFP},
1ddd7f43 13117 {"armv6j", ARM_ARCH_V6, FPU_ARCH_VFP},
0dd132b6
NC
13118 {"armv6k", ARM_ARCH_V6K, FPU_ARCH_VFP},
13119 {"armv6z", ARM_ARCH_V6Z, FPU_ARCH_VFP},
13120 {"armv6zk", ARM_ARCH_V6ZK, FPU_ARCH_VFP},
b05fe5cf
ZW
13121 {"armv6t2", ARM_ARCH_V6T2, FPU_ARCH_VFP},
13122 {"armv6kt2", ARM_ARCH_V6KT2, FPU_ARCH_VFP},
13123 {"armv6zt2", ARM_ARCH_V6ZT2, FPU_ARCH_VFP},
13124 {"armv6zkt2", ARM_ARCH_V6ZKT2, FPU_ARCH_VFP},
03b1477f 13125 {"xscale", ARM_ARCH_XSCALE, FPU_ARCH_VFP},
8266886e 13126 {"iwmmxt", ARM_ARCH_IWMMXT, FPU_ARCH_VFP},
03b1477f
RE
13127 {NULL, 0, 0}
13128};
13129
13130/* ISA extensions in the co-processor space. */
13131struct arm_arch_extension_table
13132{
13133 char *name;
13134 int value;
13135};
13136
13137static struct arm_arch_extension_table arm_extensions[] =
13138{
13139 {"maverick", ARM_CEXT_MAVERICK},
13140 {"xscale", ARM_CEXT_XSCALE},
e16bb312 13141 {"iwmmxt", ARM_CEXT_IWMMXT},
03b1477f
RE
13142 {NULL, 0}
13143};
b99bd4ef 13144
03b1477f
RE
13145struct arm_fpu_option_table
13146{
13147 char *name;
13148 int value;
13149};
13150
13151/* This list should, at a minimum, contain all the fpu names
13152 recognized by GCC. */
13153static struct arm_fpu_option_table arm_fpus[] =
13154{
13155 {"softfpa", FPU_NONE},
13156 {"fpe", FPU_ARCH_FPE},
d193a22a
RE
13157 {"fpe2", FPU_ARCH_FPE},
13158 {"fpe3", FPU_ARCH_FPA}, /* Third release supports LFM/SFM. */
03b1477f
RE
13159 {"fpa", FPU_ARCH_FPA},
13160 {"fpa10", FPU_ARCH_FPA},
13161 {"fpa11", FPU_ARCH_FPA},
13162 {"arm7500fe", FPU_ARCH_FPA},
13163 {"softvfp", FPU_ARCH_VFP},
13164 {"softvfp+vfp", FPU_ARCH_VFP_V2},
13165 {"vfp", FPU_ARCH_VFP_V2},
13166 {"vfp9", FPU_ARCH_VFP_V2},
13167 {"vfp10", FPU_ARCH_VFP_V2},
13168 {"vfp10-r0", FPU_ARCH_VFP_V1},
13169 {"vfpxd", FPU_ARCH_VFP_V1xD},
13170 {"arm1020t", FPU_ARCH_VFP_V1},
13171 {"arm1020e", FPU_ARCH_VFP_V2},
09d92015 13172 {"arm1136jfs", FPU_ARCH_VFP_V2},
8783612f 13173 {"arm1136jf-s", FPU_ARCH_VFP_V2},
33a392fb
PB
13174 {"maverick", FPU_ARCH_MAVERICK},
13175 {NULL, 0}
13176};
13177
13178struct arm_float_abi_option_table
13179{
13180 char *name;
13181 int value;
13182};
13183
13184static struct arm_float_abi_option_table arm_float_abis[] =
13185{
13186 {"hard", ARM_FLOAT_ABI_HARD},
13187 {"softfp", ARM_FLOAT_ABI_SOFTFP},
13188 {"soft", ARM_FLOAT_ABI_SOFT},
03b1477f
RE
13189 {NULL, 0}
13190};
13191
d507cf36
PB
13192struct arm_eabi_option_table
13193{
13194 char *name;
13195 unsigned int value;
13196};
13197
7cc69913 13198#ifdef OBJ_ELF
8cb51566 13199/* We only know how to output GNU and ver 4 (AAELF) formats. */
d507cf36
PB
13200static struct arm_eabi_option_table arm_eabis[] =
13201{
13202 {"gnu", EF_ARM_EABI_UNKNOWN},
8cb51566 13203 {"4", EF_ARM_EABI_VER4},
d507cf36
PB
13204 {NULL, 0}
13205};
7cc69913 13206#endif
d507cf36 13207
03b1477f
RE
13208struct arm_long_option_table
13209{
a737bd4d
NC
13210 char * option; /* Substring to match. */
13211 char * help; /* Help information. */
13212 int (* func) (char * subopt); /* Function to decode sub-option. */
13213 char * deprecated; /* If non-null, print this message. */
03b1477f
RE
13214};
13215
13216static int
a737bd4d 13217arm_parse_extension (char * str, int * opt_p)
03b1477f
RE
13218{
13219 while (str != NULL && *str != 0)
13220 {
a737bd4d
NC
13221 struct arm_arch_extension_table * opt;
13222 char * ext;
03b1477f
RE
13223 int optlen;
13224
13225 if (*str != '+')
b99bd4ef 13226 {
03b1477f
RE
13227 as_bad (_("invalid architectural extension"));
13228 return 0;
13229 }
b99bd4ef 13230
03b1477f
RE
13231 str++;
13232 ext = strchr (str, '+');
b99bd4ef 13233
03b1477f
RE
13234 if (ext != NULL)
13235 optlen = ext - str;
13236 else
13237 optlen = strlen (str);
b99bd4ef 13238
03b1477f
RE
13239 if (optlen == 0)
13240 {
13241 as_bad (_("missing architectural extension"));
13242 return 0;
13243 }
b99bd4ef 13244
03b1477f
RE
13245 for (opt = arm_extensions; opt->name != NULL; opt++)
13246 if (strncmp (opt->name, str, optlen) == 0)
13247 {
13248 *opt_p |= opt->value;
13249 break;
13250 }
bfae80f2 13251
03b1477f
RE
13252 if (opt->name == NULL)
13253 {
13254 as_bad (_("unknown architectural extnsion `%s'"), str);
13255 return 0;
13256 }
b99bd4ef 13257
03b1477f
RE
13258 str = ext;
13259 };
b99bd4ef 13260
03b1477f
RE
13261 return 1;
13262}
b99bd4ef 13263
03b1477f 13264static int
a737bd4d 13265arm_parse_cpu (char * str)
03b1477f 13266{
a737bd4d
NC
13267 struct arm_cpu_option_table * opt;
13268 char * ext = strchr (str, '+');
03b1477f 13269 int optlen;
b99bd4ef 13270
03b1477f
RE
13271 if (ext != NULL)
13272 optlen = ext - str;
13273 else
13274 optlen = strlen (str);
b99bd4ef 13275
03b1477f
RE
13276 if (optlen == 0)
13277 {
13278 as_bad (_("missing cpu name `%s'"), str);
13279 return 0;
13280 }
b99bd4ef 13281
03b1477f
RE
13282 for (opt = arm_cpus; opt->name != NULL; opt++)
13283 if (strncmp (opt->name, str, optlen) == 0)
13284 {
13285 mcpu_cpu_opt = opt->value;
13286 mcpu_fpu_opt = opt->default_fpu;
b99bd4ef 13287
03b1477f
RE
13288 if (ext != NULL)
13289 return arm_parse_extension (ext, &mcpu_cpu_opt);
b99bd4ef 13290
03b1477f
RE
13291 return 1;
13292 }
b99bd4ef 13293
03b1477f
RE
13294 as_bad (_("unknown cpu `%s'"), str);
13295 return 0;
13296}
b99bd4ef 13297
03b1477f 13298static int
a737bd4d 13299arm_parse_arch (char * str)
03b1477f
RE
13300{
13301 struct arm_arch_option_table *opt;
13302 char *ext = strchr (str, '+');
13303 int optlen;
b99bd4ef 13304
03b1477f
RE
13305 if (ext != NULL)
13306 optlen = ext - str;
13307 else
13308 optlen = strlen (str);
b99bd4ef 13309
03b1477f
RE
13310 if (optlen == 0)
13311 {
13312 as_bad (_("missing architecture name `%s'"), str);
13313 return 0;
13314 }
b99bd4ef 13315
b99bd4ef 13316
03b1477f 13317 for (opt = arm_archs; opt->name != NULL; opt++)
a737bd4d 13318 if (streq (opt->name, str))
03b1477f
RE
13319 {
13320 march_cpu_opt = opt->value;
13321 march_fpu_opt = opt->default_fpu;
b99bd4ef 13322
03b1477f
RE
13323 if (ext != NULL)
13324 return arm_parse_extension (ext, &march_cpu_opt);
b99bd4ef 13325
03b1477f
RE
13326 return 1;
13327 }
b99bd4ef 13328
03b1477f
RE
13329 as_bad (_("unknown architecture `%s'\n"), str);
13330 return 0;
13331}
13332
13333static int
a737bd4d 13334arm_parse_fpu (char * str)
03b1477f 13335{
a737bd4d 13336 struct arm_fpu_option_table * opt;
b99bd4ef 13337
03b1477f 13338 for (opt = arm_fpus; opt->name != NULL; opt++)
a737bd4d 13339 if (streq (opt->name, str))
03b1477f
RE
13340 {
13341 mfpu_opt = opt->value;
13342 return 1;
13343 }
b99bd4ef 13344
03b1477f
RE
13345 as_bad (_("unknown floating point format `%s'\n"), str);
13346 return 0;
13347}
b99bd4ef 13348
33a392fb 13349static int
a737bd4d 13350arm_parse_float_abi (char * str)
33a392fb 13351{
a737bd4d 13352 struct arm_float_abi_option_table * opt;
33a392fb
PB
13353
13354 for (opt = arm_float_abis; opt->name != NULL; opt++)
a737bd4d 13355 if (streq (opt->name, str))
33a392fb
PB
13356 {
13357 mfloat_abi_opt = opt->value;
13358 return 1;
13359 }
13360
13361 as_bad (_("unknown floating point abi `%s'\n"), str);
13362 return 0;
13363}
13364
7cc69913 13365#ifdef OBJ_ELF
d507cf36 13366static int
a737bd4d 13367arm_parse_eabi (char * str)
d507cf36
PB
13368{
13369 struct arm_eabi_option_table *opt;
13370
13371 for (opt = arm_eabis; opt->name != NULL; opt++)
a737bd4d 13372 if (streq (opt->name, str))
d507cf36
PB
13373 {
13374 meabi_flags = opt->value;
13375 return 1;
13376 }
13377 as_bad (_("unknown EABI `%s'\n"), str);
13378 return 0;
13379}
7cc69913 13380#endif
d507cf36 13381
03b1477f
RE
13382struct arm_long_option_table arm_long_opts[] =
13383{
13384 {"mcpu=", N_("<cpu name>\t assemble for CPU <cpu name>"),
13385 arm_parse_cpu, NULL},
13386 {"march=", N_("<arch name>\t assemble for architecture <arch name>"),
13387 arm_parse_arch, NULL},
13388 {"mfpu=", N_("<fpu name>\t assemble for FPU architecture <fpu name>"),
13389 arm_parse_fpu, NULL},
33a392fb
PB
13390 {"mfloat-abi=", N_("<abi>\t assemble for floating point ABI <abi>"),
13391 arm_parse_float_abi, NULL},
7cc69913 13392#ifdef OBJ_ELF
d507cf36
PB
13393 {"meabi=", N_("<ver>\t assemble for eabi version <ver>"),
13394 arm_parse_eabi, NULL},
7cc69913 13395#endif
03b1477f
RE
13396 {NULL, NULL, 0, NULL}
13397};
b99bd4ef 13398
03b1477f 13399int
a737bd4d 13400md_parse_option (int c, char * arg)
03b1477f
RE
13401{
13402 struct arm_option_table *opt;
13403 struct arm_long_option_table *lopt;
b99bd4ef 13404
03b1477f
RE
13405 switch (c)
13406 {
13407#ifdef OPTION_EB
13408 case OPTION_EB:
13409 target_big_endian = 1;
b99bd4ef 13410 break;
03b1477f 13411#endif
b99bd4ef 13412
03b1477f
RE
13413#ifdef OPTION_EL
13414 case OPTION_EL:
13415 target_big_endian = 0;
b99bd4ef
NC
13416 break;
13417#endif
13418
03b1477f 13419 case 'a':
cc8a6dd0 13420 /* Listing option. Just ignore these, we don't support additional
03b1477f
RE
13421 ones. */
13422 return 0;
13423
b99bd4ef 13424 default:
03b1477f
RE
13425 for (opt = arm_opts; opt->option != NULL; opt++)
13426 {
13427 if (c == opt->option[0]
13428 && ((arg == NULL && opt->option[1] == 0)
a737bd4d 13429 || streq (arg, opt->option + 1)))
03b1477f
RE
13430 {
13431#if WARN_DEPRECATED
13432 /* If the option is deprecated, tell the user. */
13433 if (opt->deprecated != NULL)
13434 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c,
13435 arg ? arg : "", _(opt->deprecated));
13436#endif
13437
13438 if (opt->var != NULL)
13439 *opt->var = opt->value;
13440
13441 return 1;
13442 }
13443 }
13444
13445 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
13446 {
cc8a6dd0 13447 /* These options are expected to have an argument. */
03b1477f
RE
13448 if (c == lopt->option[0]
13449 && arg != NULL
cc8a6dd0 13450 && strncmp (arg, lopt->option + 1,
03b1477f
RE
13451 strlen (lopt->option + 1)) == 0)
13452 {
13453#if WARN_DEPRECATED
13454 /* If the option is deprecated, tell the user. */
13455 if (lopt->deprecated != NULL)
13456 as_tsktsk (_("option `-%c%s' is deprecated: %s"), c, arg,
13457 _(lopt->deprecated));
13458#endif
13459
13460 /* Call the sup-option parser. */
a737bd4d 13461 return lopt->func (arg + strlen (lopt->option) - 1);
03b1477f
RE
13462 }
13463 }
13464
b99bd4ef
NC
13465 return 0;
13466 }
13467
13468 return 1;
13469}
13470
13471void
a737bd4d 13472md_show_usage (FILE * fp)
b99bd4ef 13473{
03b1477f
RE
13474 struct arm_option_table *opt;
13475 struct arm_long_option_table *lopt;
13476
13477 fprintf (fp, _(" ARM-specific assembler options:\n"));
13478
13479 for (opt = arm_opts; opt->option != NULL; opt++)
13480 if (opt->help != NULL)
13481 fprintf (fp, " -%-23s%s\n", opt->option, _(opt->help));
13482
13483 for (lopt = arm_long_opts; lopt->option != NULL; lopt++)
13484 if (lopt->help != NULL)
13485 fprintf (fp, " -%s%s\n", lopt->option, _(lopt->help));
13486
13487#ifdef OPTION_EB
b99bd4ef 13488 fprintf (fp, _("\
03b1477f 13489 -EB assemble code for a big-endian cpu\n"));
b99bd4ef 13490#endif
03b1477f
RE
13491
13492#ifdef OPTION_EL
b99bd4ef 13493 fprintf (fp, _("\
03b1477f 13494 -EL assemble code for a little-endian cpu\n"));
b99bd4ef
NC
13495#endif
13496}
13497
b99bd4ef
NC
13498/* This fix_new is called by cons via TC_CONS_FIX_NEW. */
13499
13500void
a737bd4d
NC
13501cons_fix_new_arm (fragS * frag,
13502 int where,
13503 int size,
13504 expressionS * exp)
b99bd4ef
NC
13505{
13506 bfd_reloc_code_real_type type;
13507 int pcrel = 0;
13508
13509 /* Pick a reloc.
13510 FIXME: @@ Should look at CPU word size. */
13511 switch (size)
13512 {
13513 case 1:
13514 type = BFD_RELOC_8;
13515 break;
13516 case 2:
13517 type = BFD_RELOC_16;
13518 break;
13519 case 4:
13520 default:
13521 type = BFD_RELOC_32;
13522 break;
13523 case 8:
13524 type = BFD_RELOC_64;
13525 break;
13526 }
13527
13528 fix_new_exp (frag, where, (int) size, exp, pcrel, type);
13529}
13530
13531/* A good place to do this, although this was probably not intended
13532 for this kind of use. We need to dump the literal pool before
13533 references are made to a null symbol pointer. */
13534
13535void
a737bd4d 13536arm_cleanup (void)
b99bd4ef 13537{
3d0c9500 13538 literal_pool * pool;
b99bd4ef 13539
3d0c9500
NC
13540 for (pool = list_of_pools; pool; pool = pool->next)
13541 {
13542 /* Put it at the end of the relevent section. */
13543 subseg_set (pool->section, pool->sub_section);
69b97547
NC
13544#ifdef OBJ_ELF
13545 arm_elf_change_section ();
13546#endif
3d0c9500
NC
13547 s_ltorg (0);
13548 }
b99bd4ef
NC
13549}
13550
13551void
a737bd4d 13552arm_start_line_hook (void)
b99bd4ef
NC
13553{
13554 last_label_seen = NULL;
13555}
13556
13557void
a737bd4d 13558arm_frob_label (symbolS * sym)
b99bd4ef
NC
13559{
13560 last_label_seen = sym;
13561
13562 ARM_SET_THUMB (sym, thumb_mode);
13563
13564#if defined OBJ_COFF || defined OBJ_ELF
13565 ARM_SET_INTERWORK (sym, support_interwork);
13566#endif
13567
13568 /* Note - do not allow local symbols (.Lxxx) to be labeled
13569 as Thumb functions. This is because these labels, whilst
13570 they exist inside Thumb code, are not the entry points for
13571 possible ARM->Thumb calls. Also, these labels can be used
13572 as part of a computed goto or switch statement. eg gcc
13573 can generate code that looks like this:
13574
13575 ldr r2, [pc, .Laaa]
13576 lsl r3, r3, #2
13577 ldr r2, [r3, r2]
13578 mov pc, r2
cc8a6dd0 13579
b99bd4ef
NC
13580 .Lbbb: .word .Lxxx
13581 .Lccc: .word .Lyyy
13582 ..etc...
13583 .Laaa: .word Lbbb
13584
13585 The first instruction loads the address of the jump table.
13586 The second instruction converts a table index into a byte offset.
13587 The third instruction gets the jump address out of the table.
13588 The fourth instruction performs the jump.
cc8a6dd0 13589
b99bd4ef
NC
13590 If the address stored at .Laaa is that of a symbol which has the
13591 Thumb_Func bit set, then the linker will arrange for this address
13592 to have the bottom bit set, which in turn would mean that the
13593 address computation performed by the third instruction would end
13594 up with the bottom bit set. Since the ARM is capable of unaligned
13595 word loads, the instruction would then load the incorrect address
13596 out of the jump table, and chaos would ensue. */
13597 if (label_is_thumb_function_name
13598 && (S_GET_NAME (sym)[0] != '.' || S_GET_NAME (sym)[1] != 'L')
13599 && (bfd_get_section_flags (stdoutput, now_seg) & SEC_CODE) != 0)
13600 {
13601 /* When the address of a Thumb function is taken the bottom
13602 bit of that address should be set. This will allow
13603 interworking between Arm and Thumb functions to work
13604 correctly. */
13605
13606 THUMB_SET_FUNC (sym, 1);
13607
b34976b6 13608 label_is_thumb_function_name = FALSE;
b99bd4ef
NC
13609 }
13610}
13611
13612/* Adjust the symbol table. This marks Thumb symbols as distinct from
13613 ARM ones. */
13614
13615void
a737bd4d 13616arm_adjust_symtab (void)
b99bd4ef
NC
13617{
13618#ifdef OBJ_COFF
13619 symbolS * sym;
13620
13621 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
13622 {
13623 if (ARM_IS_THUMB (sym))
13624 {
13625 if (THUMB_IS_FUNC (sym))
13626 {
13627 /* Mark the symbol as a Thumb function. */
13628 if ( S_GET_STORAGE_CLASS (sym) == C_STAT
13629 || S_GET_STORAGE_CLASS (sym) == C_LABEL) /* This can happen! */
13630 S_SET_STORAGE_CLASS (sym, C_THUMBSTATFUNC);
13631
13632 else if (S_GET_STORAGE_CLASS (sym) == C_EXT)
13633 S_SET_STORAGE_CLASS (sym, C_THUMBEXTFUNC);
13634 else
13635 as_bad (_("%s: unexpected function type: %d"),
13636 S_GET_NAME (sym), S_GET_STORAGE_CLASS (sym));
13637 }
cc8a6dd0 13638 else switch (S_GET_STORAGE_CLASS (sym))
b99bd4ef
NC
13639 {
13640 case C_EXT:
13641 S_SET_STORAGE_CLASS (sym, C_THUMBEXT);
13642 break;
13643 case C_STAT:
13644 S_SET_STORAGE_CLASS (sym, C_THUMBSTAT);
13645 break;
13646 case C_LABEL:
13647 S_SET_STORAGE_CLASS (sym, C_THUMBLABEL);
13648 break;
13649 default:
13650 /* Do nothing. */
13651 break;
13652 }
13653 }
13654
13655 if (ARM_IS_INTERWORK (sym))
13656 coffsymbol (symbol_get_bfdsym (sym))->native->u.syment.n_flags = 0xFF;
13657 }
13658#endif
13659#ifdef OBJ_ELF
13660 symbolS * sym;
13661 char bind;
13662
13663 for (sym = symbol_rootP; sym != NULL; sym = symbol_next (sym))
13664 {
13665 if (ARM_IS_THUMB (sym))
13666 {
13667 elf_symbol_type * elf_sym;
13668
13669 elf_sym = elf_symbol (symbol_get_bfdsym (sym));
d110d6a2 13670 bind = ELF_ST_BIND (elf_sym->internal_elf_sym.st_info);
b99bd4ef 13671
05ea83ed 13672 if (! bfd_is_arm_mapping_symbol_name (elf_sym->symbol.name))
9d2da7ca
JB
13673 {
13674 /* If it's a .thumb_func, declare it as so,
13675 otherwise tag label as .code 16. */
13676 if (THUMB_IS_FUNC (sym))
13677 elf_sym->internal_elf_sym.st_info =
13678 ELF_ST_INFO (bind, STT_ARM_TFUNC);
13679 else
13680 elf_sym->internal_elf_sym.st_info =
13681 ELF_ST_INFO (bind, STT_ARM_16BIT);
13682 }
b99bd4ef
NC
13683 }
13684 }
13685#endif
13686}
13687
13688int
a737bd4d 13689arm_data_in_code (void)
b99bd4ef
NC
13690{
13691 if (thumb_mode && ! strncmp (input_line_pointer + 1, "data:", 5))
13692 {
13693 *input_line_pointer = '/';
13694 input_line_pointer += 5;
13695 *input_line_pointer = 0;
13696 return 1;
13697 }
13698
13699 return 0;
13700}
13701
13702char *
a737bd4d 13703arm_canonicalize_symbol_name (char * name)
b99bd4ef
NC
13704{
13705 int len;
13706
13707 if (thumb_mode && (len = strlen (name)) > 5
13708 && streq (name + len - 5, "/data"))
13709 *(name + len - 5) = 0;
13710
13711 return name;
13712}
13713
bfc866a6 13714#if defined OBJ_COFF || defined OBJ_ELF
a161fe53 13715void
a737bd4d 13716arm_validate_fix (fixS * fixP)
b99bd4ef
NC
13717{
13718 /* If the destination of the branch is a defined symbol which does not have
13719 the THUMB_FUNC attribute, then we must be calling a function which has
13720 the (interfacearm) attribute. We look for the Thumb entry point to that
13721 function and change the branch to refer to that function instead. */
13722 if (fixP->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23
13723 && fixP->fx_addsy != NULL
13724 && S_IS_DEFINED (fixP->fx_addsy)
13725 && ! THUMB_IS_FUNC (fixP->fx_addsy))
13726 {
13727 fixP->fx_addsy = find_real_start (fixP->fx_addsy);
b99bd4ef 13728 }
b99bd4ef 13729}
bfc866a6 13730#endif
b99bd4ef 13731
114424c6 13732int
a737bd4d 13733arm_force_relocation (struct fix * fixp)
114424c6
AM
13734{
13735#if defined (OBJ_COFF) && defined (TE_PE)
13736 if (fixp->fx_r_type == BFD_RELOC_RVA)
13737 return 1;
13738#endif
13739#ifdef OBJ_ELF
ae6063d4 13740 if (fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BRANCH
114424c6
AM
13741 || fixp->fx_r_type == BFD_RELOC_ARM_PCREL_BLX
13742 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BLX
13743 || fixp->fx_r_type == BFD_RELOC_THUMB_PCREL_BRANCH23)
13744 return 1;
13745#endif
13746
13747 /* Resolve these relocations even if the symbol is extern or weak. */
13748 if (fixp->fx_r_type == BFD_RELOC_ARM_IMMEDIATE
47281638 13749 || fixp->fx_r_type == BFD_RELOC_ARM_OFFSET_IMM
114424c6
AM
13750 || fixp->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
13751 return 0;
13752
ae6063d4 13753 return generic_force_reloc (fixp);
114424c6
AM
13754}
13755
b99bd4ef
NC
13756#ifdef OBJ_COFF
13757/* This is a little hack to help the gas/arm/adrl.s test. It prevents
13758 local labels from being added to the output symbol table when they
13759 are used with the ADRL pseudo op. The ADRL relocation should always
13760 be resolved before the binbary is emitted, so it is safe to say that
13761 it is adjustable. */
13762
b34976b6 13763bfd_boolean
a737bd4d 13764arm_fix_adjustable (fixS * fixP)
b99bd4ef
NC
13765{
13766 if (fixP->fx_r_type == BFD_RELOC_ARM_ADRL_IMMEDIATE)
13767 return 1;
13768 return 0;
13769}
13770#endif
114424c6 13771
b99bd4ef
NC
13772#ifdef OBJ_ELF
13773/* Relocations against Thumb function names must be left unadjusted,
13774 so that the linker can use this information to correctly set the
13775 bottom bit of their addresses. The MIPS version of this function
13776 also prevents relocations that are mips-16 specific, but I do not
13777 know why it does this.
13778
13779 FIXME:
13780 There is one other problem that ought to be addressed here, but
13781 which currently is not: Taking the address of a label (rather
13782 than a function) and then later jumping to that address. Such
13783 addresses also ought to have their bottom bit set (assuming that
13784 they reside in Thumb code), but at the moment they will not. */
13785
b34976b6 13786bfd_boolean
a737bd4d 13787arm_fix_adjustable (fixS * fixP)
b99bd4ef
NC
13788{
13789 if (fixP->fx_addsy == NULL)
13790 return 1;
13791
b99bd4ef
NC
13792 if (THUMB_IS_FUNC (fixP->fx_addsy)
13793 && fixP->fx_subsy == NULL)
13794 return 0;
13795
13796 /* We need the symbol name for the VTABLE entries. */
13797 if ( fixP->fx_r_type == BFD_RELOC_VTABLE_INHERIT
13798 || fixP->fx_r_type == BFD_RELOC_VTABLE_ENTRY)
13799 return 0;
13800
a161fe53
AM
13801 /* Don't allow symbols to be discarded on GOT related relocs. */
13802 if (fixP->fx_r_type == BFD_RELOC_ARM_PLT32
13803 || fixP->fx_r_type == BFD_RELOC_ARM_GOT32
eb043451 13804 || fixP->fx_r_type == BFD_RELOC_ARM_GOTOFF
ba93b8ac
DJ
13805 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_GD32
13806 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LE32
13807 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_IE32
13808 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDM32
13809 || fixP->fx_r_type == BFD_RELOC_ARM_TLS_LDO32
eb043451 13810 || fixP->fx_r_type == BFD_RELOC_ARM_TARGET2)
a161fe53
AM
13811 return 0;
13812
b99bd4ef
NC
13813 return 1;
13814}
13815
13816const char *
a737bd4d 13817elf32_arm_target_format (void)
b99bd4ef 13818{
e5a52504
MM
13819#ifdef TE_SYMBIAN
13820 return (target_big_endian
13821 ? "elf32-bigarm-symbian"
13822 : "elf32-littlearm-symbian");
4e7fd91e
PB
13823#elif defined (TE_VXWORKS)
13824 return (target_big_endian
13825 ? "elf32-bigarm-vxworks"
13826 : "elf32-littlearm-vxworks");
a737bd4d 13827#else
b99bd4ef 13828 if (target_big_endian)
7f266840 13829 return "elf32-bigarm";
b99bd4ef 13830 else
7f266840 13831 return "elf32-littlearm";
e5a52504 13832#endif
b99bd4ef
NC
13833}
13834
13835void
a737bd4d
NC
13836armelf_frob_symbol (symbolS * symp,
13837 int * puntp)
b99bd4ef
NC
13838{
13839 elf_frob_symbol (symp, puntp);
13840}
13841
b99bd4ef 13842static void
a737bd4d 13843s_arm_elf_cons (int nbytes)
b99bd4ef
NC
13844{
13845 expressionS exp;
13846
13847#ifdef md_flush_pending_output
13848 md_flush_pending_output ();
13849#endif
13850
13851 if (is_it_end_of_statement ())
13852 {
13853 demand_empty_rest_of_line ();
13854 return;
13855 }
13856
13857#ifdef md_cons_align
13858 md_cons_align (nbytes);
13859#endif
13860
6057a28f 13861 mapping_state (MAP_DATA);
b99bd4ef
NC
13862 do
13863 {
13864 bfd_reloc_code_real_type reloc;
ba93b8ac
DJ
13865 char *sym_start;
13866 int sym_len;
b99bd4ef 13867
ba93b8ac 13868 sym_start = input_line_pointer;
b99bd4ef 13869 expression (& exp);
ba93b8ac 13870 sym_len = input_line_pointer - sym_start;
b99bd4ef
NC
13871
13872 if (exp.X_op == O_symbol
13873 && * input_line_pointer == '('
13874 && (reloc = arm_parse_reloc ()) != BFD_RELOC_UNUSED)
13875 {
13876 reloc_howto_type *howto = bfd_reloc_type_lookup (stdoutput, reloc);
13877 int size = bfd_get_reloc_size (howto);
13878
13879 if (size > nbytes)
13880 as_bad ("%s relocations do not fit in %d bytes",
13881 howto->name, nbytes);
13882 else
13883 {
ba93b8ac 13884 char *p;
b99bd4ef 13885 int offset = nbytes - size;
ba93b8ac
DJ
13886 char *saved_buf = alloca (sym_len), *saved_input;
13887
13888 /* We've parsed an expression stopping at O_symbol. But there
13889 may be more expression left now that we have parsed the
13890 relocation marker. Parse it again. */
13891 saved_input = input_line_pointer - sym_len;
13892 memcpy (saved_buf, saved_input, sym_len);
13893 memmove (saved_input, sym_start, sym_len);
13894 input_line_pointer = saved_input;
13895 expression (& exp);
13896 memcpy (saved_input, saved_buf, sym_len);
13897 assert (input_line_pointer >= saved_input + sym_len);
13898
13899 p = frag_more ((int) nbytes);
b99bd4ef
NC
13900 fix_new_exp (frag_now, p - frag_now->fr_literal + offset, size,
13901 &exp, 0, reloc);
13902 }
13903 }
13904 else
13905 emit_expr (&exp, (unsigned int) nbytes);
13906 }
13907 while (*input_line_pointer++ == ',');
13908
13909 /* Put terminator back into stream. */
13910 input_line_pointer --;
13911 demand_empty_rest_of_line ();
13912}
13913
eb043451
PB
13914
13915/* Parse a .rel31 directive. */
13916
13917static void
13918s_arm_rel31 (int ignored ATTRIBUTE_UNUSED)
13919{
13920 expressionS exp;
13921 char *p;
13922 valueT highbit;
a737bd4d 13923
eb043451
PB
13924 SKIP_WHITESPACE ();
13925
13926 highbit = 0;
13927 if (*input_line_pointer == '1')
13928 highbit = 0x80000000;
13929 else if (*input_line_pointer != '0')
13930 as_bad (_("expected 0 or 1"));
13931
13932 input_line_pointer++;
13933 SKIP_WHITESPACE ();
13934 if (*input_line_pointer != ',')
13935 as_bad (_("missing comma"));
13936 input_line_pointer++;
13937
13938#ifdef md_flush_pending_output
13939 md_flush_pending_output ();
13940#endif
13941
13942#ifdef md_cons_align
13943 md_cons_align (4);
13944#endif
13945
13946 mapping_state (MAP_DATA);
13947
13948 expression (&exp);
13949
13950 p = frag_more (4);
13951 md_number_to_chars (p, highbit, 4);
13952 fix_new_arm (frag_now, p - frag_now->fr_literal, 4, &exp, 1,
13953 BFD_RELOC_ARM_PREL31);
13954
13955 demand_empty_rest_of_line ();
13956}
7ed4c4c5
NC
13957\f
13958/* Code to deal with unwinding tables. */
13959
13960static void add_unwind_adjustsp (offsetT);
13961
13962/* Switch to section NAME and create section if necessary. It's
13963 rather ugly that we have to manipulate input_line_pointer but I
13964 don't see any other way to accomplish the same thing without
13965 changing obj-elf.c (which may be the Right Thing, in the end).
13966 Copied from tc-ia64.c. */
13967
13968static void
13969set_section (char *name)
13970{
13971 char *saved_input_line_pointer;
13972
13973 saved_input_line_pointer = input_line_pointer;
13974 input_line_pointer = name;
13975 obj_elf_section (0);
13976 input_line_pointer = saved_input_line_pointer;
13977}
13978
13979/* Cenerate and deferred unwind frame offset. */
13980
13981static void
13982flush_pending_unwind (void)
13983{
13984 offsetT offset;
13985
13986 offset = unwind.pending_offset;
13987 unwind.pending_offset = 0;
13988 if (offset != 0)
13989 add_unwind_adjustsp (offset);
13990}
13991
13992/* Add an opcode to this list for this function. Two-byte opcodes should
13993 be passed as op[0] << 8 | op[1]. The list of opcodes is built in reverse
13994 order. */
13995
13996static void
13997add_unwind_opcode (valueT op, int length)
13998{
13999 /* Add any deferred stack adjustment. */
14000 if (unwind.pending_offset)
14001 flush_pending_unwind ();
14002
14003 unwind.sp_restored = 0;
14004
14005 if (unwind.opcode_count + length > unwind.opcode_alloc)
14006 {
14007 unwind.opcode_alloc += ARM_OPCODE_CHUNK_SIZE;
14008 if (unwind.opcodes)
14009 unwind.opcodes = xrealloc (unwind.opcodes,
14010 unwind.opcode_alloc);
14011 else
14012 unwind.opcodes = xmalloc (unwind.opcode_alloc);
14013 }
14014 while (length > 0)
14015 {
14016 length--;
14017 unwind.opcodes[unwind.opcode_count] = op & 0xff;
14018 op >>= 8;
14019 unwind.opcode_count++;
14020 }
14021}
14022
14023/* Add unwind opcodes to adjust the stack pointer. */
14024
14025static void
14026add_unwind_adjustsp (offsetT offset)
14027{
14028 valueT op;
14029
14030 if (offset > 0x200)
14031 {
14032 /* We need at most 5 bytes to hold a 32-bit value in a uleb128. */
14033 char bytes[5];
14034 int n;
14035 valueT o;
14036
14037 /* Long form: 0xb2, uleb128. */
14038 /* This might not fit in a word so add the individual bytes,
14039 remembering the list is built in reverse order. */
14040 o = (valueT) ((offset - 0x204) >> 2);
14041 if (o == 0)
14042 add_unwind_opcode (0, 1);
14043
14044 /* Calculate the uleb128 encoding of the offset. */
14045 n = 0;
14046 while (o)
14047 {
14048 bytes[n] = o & 0x7f;
14049 o >>= 7;
14050 if (o)
14051 bytes[n] |= 0x80;
14052 n++;
14053 }
14054 /* Add the insn. */
14055 for (; n; n--)
14056 add_unwind_opcode (bytes[n - 1], 1);
14057 add_unwind_opcode (0xb2, 1);
14058 }
14059 else if (offset > 0x100)
14060 {
14061 /* Two short opcodes. */
14062 add_unwind_opcode (0x3f, 1);
14063 op = (offset - 0x104) >> 2;
14064 add_unwind_opcode (op, 1);
14065 }
14066 else if (offset > 0)
14067 {
14068 /* Short opcode. */
14069 op = (offset - 4) >> 2;
14070 add_unwind_opcode (op, 1);
14071 }
14072 else if (offset < 0)
14073 {
14074 offset = -offset;
14075 while (offset > 0x100)
14076 {
14077 add_unwind_opcode (0x7f, 1);
14078 offset -= 0x100;
14079 }
14080 op = ((offset - 4) >> 2) | 0x40;
14081 add_unwind_opcode (op, 1);
14082 }
14083}
14084
14085/* Finish the list of unwind opcodes for this function. */
14086static void
14087finish_unwind_opcodes (void)
14088{
14089 valueT op;
14090
14091 if (unwind.fp_used)
14092 {
14093 /* Adjust sp as neccessary. */
14094 unwind.pending_offset += unwind.fp_offset - unwind.frame_size;
14095 flush_pending_unwind ();
14096
14097 /* After restoring sp from the frame pointer. */
14098 op = 0x90 | unwind.fp_reg;
14099 add_unwind_opcode (op, 1);
14100 }
14101 else
14102 flush_pending_unwind ();
14103}
14104
14105
14106/* Start an exception table entry. If idx is nonzero this is an index table
14107 entry. */
14108
14109static void
14110start_unwind_section (const segT text_seg, int idx)
14111{
14112 const char * text_name;
14113 const char * prefix;
14114 const char * prefix_once;
14115 size_t prefix_len;
14116 size_t text_len;
14117 char * sec_name;
14118 size_t sec_name_len;
14119
14120 if (idx)
14121 {
14122 prefix = ELF_STRING_ARM_unwind;
14123 prefix_once = ELF_STRING_ARM_unwind_once;
14124 }
14125 else
14126 {
14127 prefix = ELF_STRING_ARM_unwind_info;
14128 prefix_once = ELF_STRING_ARM_unwind_info_once;
14129 }
14130
14131 text_name = segment_name (text_seg);
14132 if (streq (text_name, ".text"))
14133 text_name = "";
14134
14135 if (strncmp (text_name, ".gnu.linkonce.t.",
14136 strlen (".gnu.linkonce.t.")) == 0)
14137 {
14138 prefix = prefix_once;
14139 text_name += strlen (".gnu.linkonce.t.");
14140 }
14141
14142 prefix_len = strlen (prefix);
14143 text_len = strlen (text_name);
14144 sec_name_len = prefix_len + text_len;
14145 sec_name = alloca (sec_name_len + 1);
14146 memcpy (sec_name, prefix, prefix_len);
14147 memcpy (sec_name + prefix_len, text_name, text_len);
14148 sec_name[prefix_len + text_len] = '\0';
14149
14150 /* Handle COMDAT group. */
14151 if (prefix != prefix_once && (text_seg->flags & SEC_LINK_ONCE) != 0)
14152 {
14153 char *section;
14154 size_t len, group_name_len;
14155 const char *group_name = elf_group_name (text_seg);
14156
14157 if (group_name == NULL)
14158 {
14159 as_bad ("Group section `%s' has no group signature",
14160 segment_name (text_seg));
14161 ignore_rest_of_line ();
14162 return;
14163 }
14164 /* We have to construct a fake section directive. */
14165 group_name_len = strlen (group_name);
14166 if (idx)
14167 prefix_len = 13;
14168 else
14169 prefix_len = 16;
14170
14171 len = (sec_name_len
14172 + prefix_len /* ,"aG",%sectiontype, */
14173 + group_name_len /* ,group_name */
14174 + 7); /* ,comdat */
14175
14176 section = alloca (len + 1);
14177 memcpy (section, sec_name, sec_name_len);
14178 if (idx)
14179 memcpy (section + sec_name_len, ",\"aG\",%exidx,", 13);
14180 else
14181 memcpy (section + sec_name_len, ",\"aG\",%progbits,", 16);
14182 memcpy (section + sec_name_len + prefix_len, group_name, group_name_len);
14183 memcpy (section + len - 7, ",comdat", 7);
14184 section [len] = '\0';
14185 set_section (section);
14186 }
14187 else
14188 {
14189 set_section (sec_name);
14190 bfd_set_section_flags (stdoutput, now_seg,
14191 SEC_LOAD | SEC_ALLOC | SEC_READONLY);
14192 }
14193
14194 /* Set the setion link for index tables. */
14195 if (idx)
14196 elf_linked_to_section (now_seg) = text_seg;
14197}
14198
14199
14200/* Start an unwind table entry. HAVE_DATA is nonzero if we have additional
14201 personality routine data. Returns zero, or the index table value for
14202 and inline entry. */
14203
14204static valueT
14205create_unwind_entry (int have_data)
14206{
14207 int size;
14208 addressT where;
2132e3a3 14209 char *ptr;
7ed4c4c5
NC
14210 /* The current word of data. */
14211 valueT data;
14212 /* The number of bytes left in this word. */
14213 int n;
14214
14215 finish_unwind_opcodes ();
14216
14217 /* Remember the current text section. */
14218 unwind.saved_seg = now_seg;
14219 unwind.saved_subseg = now_subseg;
14220
14221 start_unwind_section (now_seg, 0);
14222
14223 if (unwind.personality_routine == NULL)
14224 {
14225 if (unwind.personality_index == -2)
14226 {
14227 if (have_data)
14228 as_bad (_("handerdata in cantunwind frame"));
14229 return 1; /* EXIDX_CANTUNWIND. */
14230 }
14231
14232 /* Use a default personality routine if none is specified. */
14233 if (unwind.personality_index == -1)
14234 {
14235 if (unwind.opcode_count > 3)
14236 unwind.personality_index = 1;
14237 else
14238 unwind.personality_index = 0;
14239 }
14240
14241 /* Space for the personality routine entry. */
14242 if (unwind.personality_index == 0)
14243 {
14244 if (unwind.opcode_count > 3)
14245 as_bad (_("too many unwind opcodes for personality routine 0"));
14246
14247 if (!have_data)
14248 {
14249 /* All the data is inline in the index table. */
14250 data = 0x80;
14251 n = 3;
14252 while (unwind.opcode_count > 0)
14253 {
14254 unwind.opcode_count--;
14255 data = (data << 8) | unwind.opcodes[unwind.opcode_count];
14256 n--;
14257 }
14258
14259 /* Pad with "finish" opcodes. */
14260 while (n--)
14261 data = (data << 8) | 0xb0;
14262
14263 return data;
14264 }
14265 size = 0;
14266 }
14267 else
14268 /* We get two opcodes "free" in the first word. */
14269 size = unwind.opcode_count - 2;
14270 }
14271 else
14272 /* An extra byte is required for the opcode count. */
14273 size = unwind.opcode_count + 1;
14274
14275 size = (size + 3) >> 2;
14276 if (size > 0xff)
14277 as_bad (_("too many unwind opcodes"));
14278
14279 frag_align (2, 0, 0);
14280 record_alignment (now_seg, 2);
14281 unwind.table_entry = expr_build_dot ();
14282
14283 /* Allocate the table entry. */
14284 ptr = frag_more ((size << 2) + 4);
14285 where = frag_now_fix () - ((size << 2) + 4);
14286
14287 switch (unwind.personality_index)
14288 {
14289 case -1:
14290 /* ??? Should this be a PLT generating relocation? */
14291 /* Custom personality routine. */
14292 fix_new (frag_now, where, 4, unwind.personality_routine, 0, 1,
14293 BFD_RELOC_ARM_PREL31);
620b81c1 14294
7ed4c4c5
NC
14295 where += 4;
14296 ptr += 4;
14297
14298 /* Set the first byte to the number of additional words. */
14299 data = size - 1;
14300 n = 3;
14301 break;
14302
14303 /* ABI defined personality routines. */
7ed4c4c5
NC
14304 case 0:
14305 /* Three opcodes bytes are packed into the first word. */
14306 data = 0x80;
14307 n = 3;
84798bd6 14308 break;
7ed4c4c5
NC
14309
14310 case 1:
14311 case 2:
14312 /* The size and first two opcode bytes go in the first word. */
14313 data = ((0x80 + unwind.personality_index) << 8) | size;
14314 n = 2;
14315 break;
14316
14317 default:
14318 /* Should never happen. */
14319 abort ();
14320 }
14321
14322 /* Pack the opcodes into words (MSB first), reversing the list at the same
14323 time. */
14324 while (unwind.opcode_count > 0)
14325 {
14326 if (n == 0)
14327 {
14328 md_number_to_chars (ptr, data, 4);
14329 ptr += 4;
14330 n = 4;
14331 data = 0;
14332 }
14333 unwind.opcode_count--;
14334 n--;
14335 data = (data << 8) | unwind.opcodes[unwind.opcode_count];
14336 }
14337
14338 /* Finish off the last word. */
14339 if (n < 4)
14340 {
14341 /* Pad with "finish" opcodes. */
14342 while (n--)
14343 data = (data << 8) | 0xb0;
14344
14345 md_number_to_chars (ptr, data, 4);
14346 }
14347
14348 if (!have_data)
14349 {
14350 /* Add an empty descriptor if there is no user-specified data. */
14351 ptr = frag_more (4);
14352 md_number_to_chars (ptr, 0, 4);
14353 }
14354
14355 return 0;
14356}
14357
14358
14359/* Parse an unwind_fnstart directive. Simply records the current location. */
14360
14361static void
14362s_arm_unwind_fnstart (int ignored ATTRIBUTE_UNUSED)
14363{
14364 demand_empty_rest_of_line ();
14365 /* Mark the start of the function. */
14366 unwind.proc_start = expr_build_dot ();
14367
14368 /* Reset the rest of the unwind info. */
14369 unwind.opcode_count = 0;
14370 unwind.table_entry = NULL;
14371 unwind.personality_routine = NULL;
14372 unwind.personality_index = -1;
14373 unwind.frame_size = 0;
14374 unwind.fp_offset = 0;
14375 unwind.fp_reg = 13;
14376 unwind.fp_used = 0;
14377 unwind.sp_restored = 0;
14378}
14379
14380
14381/* Parse a handlerdata directive. Creates the exception handling table entry
14382 for the function. */
14383
14384static void
14385s_arm_unwind_handlerdata (int ignored ATTRIBUTE_UNUSED)
14386{
14387 demand_empty_rest_of_line ();
14388 if (unwind.table_entry)
14389 as_bad (_("dupicate .handlerdata directive"));
14390
14391 create_unwind_entry (1);
14392}
14393
14394/* Parse an unwind_fnend directive. Generates the index table entry. */
14395
14396static void
14397s_arm_unwind_fnend (int ignored ATTRIBUTE_UNUSED)
14398{
14399 long where;
2132e3a3 14400 char *ptr;
7ed4c4c5
NC
14401 valueT val;
14402
14403 demand_empty_rest_of_line ();
14404
14405 /* Add eh table entry. */
14406 if (unwind.table_entry == NULL)
14407 val = create_unwind_entry (0);
14408 else
14409 val = 0;
14410
14411 /* Add index table entry. This is two words. */
14412 start_unwind_section (unwind.saved_seg, 1);
14413 frag_align (2, 0, 0);
14414 record_alignment (now_seg, 2);
14415
14416 ptr = frag_more (8);
14417 where = frag_now_fix () - 8;
14418
14419 /* Self relative offset of the function start. */
14420 fix_new (frag_now, where, 4, unwind.proc_start, 0, 1,
be1b2b4b 14421 BFD_RELOC_ARM_PREL31);
7ed4c4c5 14422
84798bd6
JB
14423 /* Indicate dependency on EHABI-defined personality routines to the
14424 linker, if it hasn't been done already. */
14425 if (unwind.personality_index >= 0 && unwind.personality_index < 3)
14426 {
14427 char *name[] = { "__aeabi_unwind_cpp_pr0",
14428 "__aeabi_unwind_cpp_pr1",
14429 "__aeabi_unwind_cpp_pr2" };
14430 if (!(marked_pr_dependency & (1 << unwind.personality_index)))
14431 {
14432 symbolS *pr = symbol_find_or_make (name[unwind.personality_index]);
14433 fix_new (frag_now, where, 0, pr, 0, 1, BFD_RELOC_NONE);
14434 marked_pr_dependency |= 1 << unwind.personality_index;
14435 seg_info (now_seg)->tc_segment_info_data.marked_pr_dependency
14436 = marked_pr_dependency;
14437 }
14438 }
14439
7ed4c4c5
NC
14440 if (val)
14441 /* Inline exception table entry. */
14442 md_number_to_chars (ptr + 4, val, 4);
14443 else
14444 /* Self relative offset of the table entry. */
14445 fix_new (frag_now, where + 4, 4, unwind.table_entry, 0, 1,
14446 BFD_RELOC_ARM_PREL31);
14447
14448 /* Restore the original section. */
14449 subseg_set (unwind.saved_seg, unwind.saved_subseg);
14450}
14451
14452
14453/* Parse an unwind_cantunwind directive. */
14454
14455static void
14456s_arm_unwind_cantunwind (int ignored ATTRIBUTE_UNUSED)
14457{
14458 demand_empty_rest_of_line ();
14459 if (unwind.personality_routine || unwind.personality_index != -1)
14460 as_bad (_("personality routine specified for cantunwind frame"));
14461
14462 unwind.personality_index = -2;
14463}
14464
14465
14466/* Parse a personalityindex directive. */
14467
14468static void
14469s_arm_unwind_personalityindex (int ignored ATTRIBUTE_UNUSED)
14470{
14471 expressionS exp;
14472
14473 if (unwind.personality_routine || unwind.personality_index != -1)
14474 as_bad (_("duplicate .personalityindex directive"));
14475
14476 SKIP_WHITESPACE ();
14477
14478 expression (&exp);
14479
14480 if (exp.X_op != O_constant
14481 || exp.X_add_number < 0 || exp.X_add_number > 15)
14482 {
14483 as_bad (_("bad personality routine number"));
14484 ignore_rest_of_line ();
14485 return;
14486 }
14487
14488 unwind.personality_index = exp.X_add_number;
14489
14490 demand_empty_rest_of_line ();
14491}
14492
14493
14494/* Parse a personality directive. */
14495
14496static void
14497s_arm_unwind_personality (int ignored ATTRIBUTE_UNUSED)
14498{
14499 char *name, *p, c;
14500
14501 if (unwind.personality_routine || unwind.personality_index != -1)
14502 as_bad (_("duplicate .personality directive"));
14503
14504 SKIP_WHITESPACE ();
14505 name = input_line_pointer;
14506 c = get_symbol_end ();
14507 p = input_line_pointer;
14508 unwind.personality_routine = symbol_find_or_make (name);
14509 *p = c;
14510 SKIP_WHITESPACE ();
14511 demand_empty_rest_of_line ();
14512}
14513
14514
14515/* Parse a directive saving core registers. */
14516
14517static void
14518s_arm_unwind_save_core (void)
14519{
14520 valueT op;
14521 long range;
14522 int n;
14523
14524 SKIP_WHITESPACE ();
14525 range = reg_list (&input_line_pointer);
14526 if (range == FAIL)
14527 {
14528 as_bad (_("expected register list"));
14529 ignore_rest_of_line ();
14530 return;
14531 }
14532
14533 demand_empty_rest_of_line ();
14534
14535 /* Turn .unwind_movsp ip followed by .unwind_save {..., ip, ...}
14536 into .unwind_save {..., sp...}. We aren't bothered about the value of
14537 ip because it is clobbered by calls. */
14538 if (unwind.sp_restored && unwind.fp_reg == 12
14539 && (range & 0x3000) == 0x1000)
14540 {
14541 unwind.opcode_count--;
14542 unwind.sp_restored = 0;
14543 range = (range | 0x2000) & ~0x1000;
14544 unwind.pending_offset = 0;
14545 }
14546
14547 /* See if we can use the short opcodes. These pop a block of upto 8
14548 registers starting with r4, plus maybe r14. */
14549 for (n = 0; n < 8; n++)
14550 {
14551 /* Break at the first non-saved register. */
14552 if ((range & (1 << (n + 4))) == 0)
14553 break;
14554 }
14555 /* See if there are any other bits set. */
14556 if (n == 0 || (range & (0xfff0 << n) & 0xbff0) != 0)
14557 {
14558 /* Use the long form. */
14559 op = 0x8000 | ((range >> 4) & 0xfff);
14560 add_unwind_opcode (op, 2);
14561 }
14562 else
14563 {
14564 /* Use the short form. */
14565 if (range & 0x4000)
14566 op = 0xa8; /* Pop r14. */
14567 else
14568 op = 0xa0; /* Do not pop r14. */
14569 op |= (n - 1);
14570 add_unwind_opcode (op, 1);
14571 }
14572
14573 /* Pop r0-r3. */
14574 if (range & 0xf)
14575 {
14576 op = 0xb100 | (range & 0xf);
14577 add_unwind_opcode (op, 2);
14578 }
14579
14580 /* Record the number of bytes pushed. */
14581 for (n = 0; n < 16; n++)
14582 {
14583 if (range & (1 << n))
14584 unwind.frame_size += 4;
14585 }
14586}
14587
14588
14589/* Parse a directive saving FPA registers. */
14590
14591static void
14592s_arm_unwind_save_fpa (int reg)
14593{
14594 expressionS exp;
14595 int num_regs;
14596 valueT op;
14597
14598 /* Get Number of registers to transfer. */
14599 if (skip_past_comma (&input_line_pointer) != FAIL)
14600 expression (&exp);
14601 else
14602 exp.X_op = O_illegal;
14603
14604 if (exp.X_op != O_constant)
14605 {
14606 as_bad (_("expected , <constant>"));
14607 ignore_rest_of_line ();
14608 return;
14609 }
14610
14611 num_regs = exp.X_add_number;
14612
14613 if (num_regs < 1 || num_regs > 4)
14614 {
14615 as_bad (_("number of registers must be in the range [1:4]"));
14616 ignore_rest_of_line ();
14617 return;
14618 }
14619
14620 demand_empty_rest_of_line ();
14621
14622 if (reg == 4)
14623 {
14624 /* Short form. */
14625 op = 0xb4 | (num_regs - 1);
14626 add_unwind_opcode (op, 1);
14627 }
14628 else
14629 {
14630 /* Long form. */
14631 op = 0xc800 | (reg << 4) | (num_regs - 1);
14632 add_unwind_opcode (op, 2);
14633 }
14634 unwind.frame_size += num_regs * 12;
14635}
14636
14637
14638/* Parse a directive saving VFP registers. */
14639
14640static void
14641s_arm_unwind_save_vfp (void)
14642{
14643 int count;
14644 int reg;
14645 valueT op;
14646
14647 count = vfp_parse_reg_list (&input_line_pointer, &reg, 1);
14648 if (count == FAIL)
14649 {
14650 as_bad (_("expected register list"));
14651 ignore_rest_of_line ();
14652 return;
14653 }
14654
14655 demand_empty_rest_of_line ();
14656
14657 if (reg == 8)
14658 {
14659 /* Short form. */
14660 op = 0xb8 | (count - 1);
14661 add_unwind_opcode (op, 1);
14662 }
14663 else
14664 {
14665 /* Long form. */
14666 op = 0xb300 | (reg << 4) | (count - 1);
14667 add_unwind_opcode (op, 2);
14668 }
14669 unwind.frame_size += count * 8 + 4;
14670}
14671
14672
14673/* Parse a directive saving iWMMXt registers. */
14674
14675static void
14676s_arm_unwind_save_wmmx (void)
14677{
14678 int reg;
14679 int hi_reg;
14680 int i;
14681 unsigned wcg_mask;
14682 unsigned wr_mask;
14683 valueT op;
14684
14685 if (*input_line_pointer == '{')
14686 input_line_pointer++;
14687
14688 wcg_mask = 0;
14689 wr_mask = 0;
14690 do
14691 {
14692 reg = arm_reg_parse (&input_line_pointer,
14693 all_reg_maps[REG_TYPE_IWMMXT].htab);
14694
14695 if (wr_register (reg))
14696 {
14697 i = reg & ~WR_PREFIX;
14698 if (wr_mask >> i)
14699 as_tsktsk (_("register list not in ascending order"));
14700 wr_mask |= 1 << i;
14701 }
14702 else if (wcg_register (reg))
14703 {
14704 i = (reg & ~WC_PREFIX) - 8;
14705 if (wcg_mask >> i)
14706 as_tsktsk (_("register list not in ascending order"));
14707 wcg_mask |= 1 << i;
14708 }
14709 else
14710 {
14711 as_bad (_("expected wr or wcgr"));
14712 goto error;
14713 }
14714
14715 SKIP_WHITESPACE ();
14716 if (*input_line_pointer == '-')
14717 {
14718 hi_reg = arm_reg_parse (&input_line_pointer,
14719 all_reg_maps[REG_TYPE_IWMMXT].htab);
14720 if (wr_register (reg) && wr_register (hi_reg))
14721 {
14722 for (; reg < hi_reg; reg++)
14723 wr_mask |= 1 << (reg & ~WR_PREFIX);
14724 }
14725 else if (wcg_register (reg) && wcg_register (hi_reg))
14726 {
14727 for (; reg < hi_reg; reg++)
14728 wcg_mask |= 1 << ((reg & ~WC_PREFIX) - 8);
14729 }
14730 else
14731 {
14732 as_bad (_("bad register range"));
14733 goto error;
14734 }
14735 }
14736 }
14737 while (skip_past_comma (&input_line_pointer) != FAIL);
14738
14739 SKIP_WHITESPACE ();
14740 if (*input_line_pointer == '}')
14741 input_line_pointer++;
14742
14743 demand_empty_rest_of_line ();
14744
14745 if (wr_mask && wcg_mask)
14746 {
14747 as_bad (_("inconsistent register types"));
14748 goto error;
14749 }
14750
14751 /* Generate any deferred opcodes becuuse we're going to be looking at
14752 the list. */
14753 flush_pending_unwind ();
14754
14755 if (wcg_mask)
14756 {
14757 for (i = 0; i < 16; i++)
14758 {
14759 if (wcg_mask & (1 << i))
14760 unwind.frame_size += 4;
14761 }
14762 op = 0xc700 | wcg_mask;
14763 add_unwind_opcode (op, 2);
14764 }
14765 else
14766 {
14767 for (i = 0; i < 16; i++)
14768 {
14769 if (wr_mask & (1 << i))
14770 unwind.frame_size += 8;
14771 }
14772 /* Attempt to combine with a previous opcode. We do this because gcc
14773 likes to output separate unwind directives for a single block of
14774 registers. */
14775 if (unwind.opcode_count > 0)
14776 {
14777 i = unwind.opcodes[unwind.opcode_count - 1];
14778 if ((i & 0xf8) == 0xc0)
14779 {
14780 i &= 7;
14781 /* Only merge if the blocks are contiguous. */
14782 if (i < 6)
14783 {
14784 if ((wr_mask & 0xfe00) == (1 << 9))
14785 {
14786 wr_mask |= ((1 << (i + 11)) - 1) & 0xfc00;
14787 unwind.opcode_count--;
14788 }
14789 }
14790 else if (i == 6 && unwind.opcode_count >= 2)
14791 {
14792 i = unwind.opcodes[unwind.opcode_count - 2];
14793 reg = i >> 4;
14794 i &= 0xf;
14795
14796 op = 0xffff << (reg - 1);
14797 if (reg > 0
14798 || ((wr_mask & op) == (1u << (reg - 1))))
14799 {
14800 op = (1 << (reg + i + 1)) - 1;
14801 op &= ~((1 << reg) - 1);
14802 wr_mask |= op;
14803 unwind.opcode_count -= 2;
14804 }
14805 }
14806 }
14807 }
14808
14809 hi_reg = 15;
14810 /* We want to generate opcodes in the order the registers have been
14811 saved, ie. descending order. */
14812 for (reg = 15; reg >= -1; reg--)
14813 {
14814 /* Save registers in blocks. */
14815 if (reg < 0
14816 || !(wr_mask & (1 << reg)))
14817 {
14818 /* We found an unsaved reg. Generate opcodes to save the
14819 preceeding block. */
14820 if (reg != hi_reg)
14821 {
14822 if (reg == 9)
14823 {
14824 /* Short form. */
14825 op = 0xc0 | (hi_reg - 10);
14826 add_unwind_opcode (op, 1);
14827 }
14828 else
14829 {
14830 /* Long form. */
14831 op = 0xc600 | ((reg + 1) << 4) | ((hi_reg - reg) - 1);
14832 add_unwind_opcode (op, 2);
14833 }
14834 }
14835 hi_reg = reg - 1;
14836 }
14837 }
14838 }
14839 return;
14840error:
14841 ignore_rest_of_line ();
14842}
14843
14844
14845/* Parse an unwind_save directive. */
14846
14847static void
14848s_arm_unwind_save (int ignored ATTRIBUTE_UNUSED)
14849{
14850 char *saved_ptr;
14851 int reg;
14852
14853 /* Figure out what sort of save we have. */
14854 SKIP_WHITESPACE ();
14855 saved_ptr = input_line_pointer;
14856
14857 reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_FN].htab);
14858 if (reg != FAIL)
14859 {
14860 s_arm_unwind_save_fpa (reg);
14861 return;
14862 }
14863
14864 if (*input_line_pointer == '{')
14865 input_line_pointer++;
14866
14867 SKIP_WHITESPACE ();
14868
14869 reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_RN].htab);
14870 if (reg != FAIL)
14871 {
14872 input_line_pointer = saved_ptr;
14873 s_arm_unwind_save_core ();
14874 return;
14875 }
14876
14877 reg = arm_reg_parse (&input_line_pointer, all_reg_maps[REG_TYPE_DN].htab);
14878 if (reg != FAIL)
14879 {
14880 input_line_pointer = saved_ptr;
14881 s_arm_unwind_save_vfp ();
14882 return;
14883 }
14884
14885 reg = arm_reg_parse (&input_line_pointer,
14886 all_reg_maps[REG_TYPE_IWMMXT].htab);
14887 if (reg != FAIL)
14888 {
14889 input_line_pointer = saved_ptr;
14890 s_arm_unwind_save_wmmx ();
14891 return;
14892 }
14893
14894 /* TODO: Maverick registers. */
14895 as_bad (_("unrecognised register"));
14896}
14897
14898
14899/* Parse an unwind_movsp directive. */
14900
14901static void
14902s_arm_unwind_movsp (int ignored ATTRIBUTE_UNUSED)
14903{
14904 int reg;
14905 valueT op;
14906
14907 SKIP_WHITESPACE ();
14908 reg = reg_required_here (&input_line_pointer, -1);
14909 if (reg == FAIL)
14910 {
14911 as_bad (_("ARM register expected"));
14912 ignore_rest_of_line ();
14913 return;
14914 }
14915
14916 if (reg == 13 || reg == 15)
14917 {
14918 as_bad (_("r%d not permitted in .unwind_movsp directive"), reg);
14919 ignore_rest_of_line ();
14920 return;
14921 }
14922
14923 if (unwind.fp_reg != 13)
14924 as_bad (_("unexpected .unwind_movsp directive"));
14925
14926 /* Generate opcode to restore the value. */
14927 op = 0x90 | reg;
14928 add_unwind_opcode (op, 1);
14929
14930 /* Record the information for later. */
14931 unwind.fp_reg = reg;
14932 unwind.fp_offset = unwind.frame_size;
14933 unwind.sp_restored = 1;
14934 demand_empty_rest_of_line ();
14935}
14936
14937
14938/* Parse #<number>. */
14939
14940static int
14941require_hashconst (int * val)
14942{
14943 expressionS exp;
14944
14945 SKIP_WHITESPACE ();
14946 if (*input_line_pointer == '#')
14947 {
14948 input_line_pointer++;
14949 expression (&exp);
14950 }
14951 else
14952 exp.X_op = O_illegal;
14953
14954 if (exp.X_op != O_constant)
14955 {
14956 as_bad (_("expected #constant"));
14957 ignore_rest_of_line ();
14958 return FAIL;
14959 }
14960 *val = exp.X_add_number;
14961 return SUCCESS;
14962}
14963
14964/* Parse an unwind_pad directive. */
14965
14966static void
14967s_arm_unwind_pad (int ignored ATTRIBUTE_UNUSED)
14968{
14969 int offset;
14970
14971 if (require_hashconst (&offset) == FAIL)
14972 return;
14973
14974 if (offset & 3)
14975 {
14976 as_bad (_("stack increment must be multiple of 4"));
14977 ignore_rest_of_line ();
14978 return;
14979 }
14980
14981 /* Don't generate any opcodes, just record the details for later. */
14982 unwind.frame_size += offset;
14983 unwind.pending_offset += offset;
14984
14985 demand_empty_rest_of_line ();
14986}
14987
14988/* Parse an unwind_setfp directive. */
14989
14990static void
14991s_arm_unwind_setfp (int ignored ATTRIBUTE_UNUSED)
14992{
14993 int sp_reg;
14994 int fp_reg;
14995 int offset;
14996
14997 fp_reg = reg_required_here (&input_line_pointer, -1);
14998 if (skip_past_comma (&input_line_pointer) == FAIL)
14999 sp_reg = FAIL;
15000 else
15001 sp_reg = reg_required_here (&input_line_pointer, -1);
15002
15003 if (fp_reg == FAIL || sp_reg == FAIL)
15004 {
15005 as_bad (_("expected <reg>, <reg>"));
15006 ignore_rest_of_line ();
15007 return;
15008 }
15009
15010 /* Optonal constant. */
15011 if (skip_past_comma (&input_line_pointer) != FAIL)
15012 {
15013 if (require_hashconst (&offset) == FAIL)
15014 return;
15015 }
15016 else
15017 offset = 0;
15018
15019 demand_empty_rest_of_line ();
15020
15021 if (sp_reg != 13 && sp_reg != unwind.fp_reg)
15022 {
15023 as_bad (_("register must be either sp or set by a previous"
15024 "unwind_movsp directive"));
15025 return;
15026 }
15027
15028 /* Don't generate any opcodes, just record the information for later. */
15029 unwind.fp_reg = fp_reg;
15030 unwind.fp_used = 1;
15031 if (sp_reg == 13)
15032 unwind.fp_offset = unwind.frame_size - offset;
15033 else
15034 unwind.fp_offset -= offset;
15035}
15036
15037/* Parse an unwind_raw directive. */
15038
15039static void
15040s_arm_unwind_raw (int ignored ATTRIBUTE_UNUSED)
15041{
15042 expressionS exp;
15043 /* This is an arbitary limit. */
15044 unsigned char op[16];
15045 int count;
15046
15047 SKIP_WHITESPACE ();
15048 expression (&exp);
15049 if (exp.X_op == O_constant
15050 && skip_past_comma (&input_line_pointer) != FAIL)
15051 {
15052 unwind.frame_size += exp.X_add_number;
15053 expression (&exp);
15054 }
15055 else
15056 exp.X_op = O_illegal;
15057
15058 if (exp.X_op != O_constant)
15059 {
15060 as_bad (_("expected <offset>, <opcode>"));
15061 ignore_rest_of_line ();
15062 return;
15063 }
15064
15065 count = 0;
15066
15067 /* Parse the opcode. */
15068 for (;;)
15069 {
15070 if (count >= 16)
15071 {
15072 as_bad (_("unwind opcode too long"));
15073 ignore_rest_of_line ();
15074 }
15075 if (exp.X_op != O_constant || exp.X_add_number & ~0xff)
15076 {
15077 as_bad (_("invalid unwind opcode"));
15078 ignore_rest_of_line ();
15079 return;
15080 }
15081 op[count++] = exp.X_add_number;
15082
15083 /* Parse the next byte. */
15084 if (skip_past_comma (&input_line_pointer) == FAIL)
15085 break;
15086
15087 expression (&exp);
15088 }
15089
15090 /* Add the opcode bytes in reverse order. */
15091 while (count--)
15092 add_unwind_opcode (op[count], 1);
15093
15094 demand_empty_rest_of_line ();
15095}
eb043451 15096
b99bd4ef
NC
15097#endif /* OBJ_ELF */
15098
15099/* This is called from HANDLE_ALIGN in write.c. Fill in the contents
15100 of an rs_align_code fragment. */
15101
15102void
a737bd4d 15103arm_handle_align (fragS * fragP)
b99bd4ef
NC
15104{
15105 static char const arm_noop[4] = { 0x00, 0x00, 0xa0, 0xe1 };
15106 static char const thumb_noop[2] = { 0xc0, 0x46 };
15107 static char const arm_bigend_noop[4] = { 0xe1, 0xa0, 0x00, 0x00 };
15108 static char const thumb_bigend_noop[2] = { 0x46, 0xc0 };
15109
15110 int bytes, fix, noop_size;
15111 char * p;
15112 const char * noop;
cc8a6dd0 15113
b99bd4ef
NC
15114 if (fragP->fr_type != rs_align_code)
15115 return;
15116
15117 bytes = fragP->fr_next->fr_address - fragP->fr_address - fragP->fr_fix;
15118 p = fragP->fr_literal + fragP->fr_fix;
15119 fix = 0;
cc8a6dd0 15120
b99bd4ef
NC
15121 if (bytes > MAX_MEM_FOR_RS_ALIGN_CODE)
15122 bytes &= MAX_MEM_FOR_RS_ALIGN_CODE;
cc8a6dd0 15123
b99bd4ef
NC
15124 if (fragP->tc_frag_data)
15125 {
15126 if (target_big_endian)
15127 noop = thumb_bigend_noop;
15128 else
15129 noop = thumb_noop;
15130 noop_size = sizeof (thumb_noop);
15131 }
15132 else
15133 {
15134 if (target_big_endian)
15135 noop = arm_bigend_noop;
15136 else
15137 noop = arm_noop;
15138 noop_size = sizeof (arm_noop);
15139 }
cc8a6dd0 15140
b99bd4ef
NC
15141 if (bytes & (noop_size - 1))
15142 {
15143 fix = bytes & (noop_size - 1);
15144 memset (p, 0, fix);
15145 p += fix;
15146 bytes -= fix;
15147 }
15148
15149 while (bytes >= noop_size)
15150 {
15151 memcpy (p, noop, noop_size);
15152 p += noop_size;
15153 bytes -= noop_size;
15154 fix += noop_size;
15155 }
cc8a6dd0 15156
b99bd4ef
NC
15157 fragP->fr_fix += fix;
15158 fragP->fr_var = noop_size;
15159}
15160
15161/* Called from md_do_align. Used to create an alignment
15162 frag in a code section. */
15163
15164void
a737bd4d 15165arm_frag_align_code (int n, int max)
b99bd4ef
NC
15166{
15167 char * p;
15168
2d2255b5 15169 /* We assume that there will never be a requirement
b99bd4ef
NC
15170 to support alignments greater than 32 bytes. */
15171 if (max > MAX_MEM_FOR_RS_ALIGN_CODE)
15172 as_fatal (_("alignments greater than 32 bytes not supported in .text sections."));
cc8a6dd0 15173
b99bd4ef
NC
15174 p = frag_var (rs_align_code,
15175 MAX_MEM_FOR_RS_ALIGN_CODE,
15176 1,
15177 (relax_substateT) max,
15178 (symbolS *) NULL,
15179 (offsetT) n,
15180 (char *) NULL);
15181 *p = 0;
b99bd4ef
NC
15182}
15183
15184/* Perform target specific initialisation of a frag. */
15185
15186void
a737bd4d 15187arm_init_frag (fragS * fragP)
b99bd4ef
NC
15188{
15189 /* Record whether this frag is in an ARM or a THUMB area. */
15190 fragP->tc_frag_data = thumb_mode;
15191}
a737bd4d 15192
a394c00f
NC
15193#ifdef OBJ_ELF
15194
15195/* Convert REGNAME to a DWARF-2 register number. */
15196
15197int
15198tc_arm_regname_to_dw2regnum (const char *regname)
15199{
15200 unsigned int i;
15201
15202 for (i = 0; rn_table[i].name; i++)
15203 if (streq (regname, rn_table[i].name))
15204 return rn_table[i].number;
15205
15206 return -1;
15207}
15208
15209/* Initialize the DWARF-2 unwind information for this procedure. */
15210
15211void
15212tc_arm_frame_initial_instructions (void)
15213{
15214 cfi_add_CFA_def_cfa (REG_SP, 0);
15215}
15216#endif
15217
a737bd4d
NC
15218/* This table describes all the machine specific pseudo-ops the assembler
15219 has to support. The fields are:
15220 pseudo-op name without dot
15221 function to call to execute this pseudo-op
15222 Integer arg to pass to the function. */
15223
15224const pseudo_typeS md_pseudo_table[] =
15225{
15226 /* Never called because '.req' does not start a line. */
15227 { "req", s_req, 0 },
15228 { "unreq", s_unreq, 0 },
15229 { "bss", s_bss, 0 },
15230 { "align", s_align, 0 },
15231 { "arm", s_arm, 0 },
15232 { "thumb", s_thumb, 0 },
15233 { "code", s_code, 0 },
15234 { "force_thumb", s_force_thumb, 0 },
15235 { "thumb_func", s_thumb_func, 0 },
15236 { "thumb_set", s_thumb_set, 0 },
15237 { "even", s_even, 0 },
15238 { "ltorg", s_ltorg, 0 },
15239 { "pool", s_ltorg, 0 },
15240#ifdef OBJ_ELF
15241 { "word", s_arm_elf_cons, 4 },
15242 { "long", s_arm_elf_cons, 4 },
15243 { "rel31", s_arm_rel31, 0 },
7ed4c4c5
NC
15244 { "fnstart", s_arm_unwind_fnstart, 0 },
15245 { "fnend", s_arm_unwind_fnend, 0 },
15246 { "cantunwind", s_arm_unwind_cantunwind, 0 },
15247 { "personality", s_arm_unwind_personality, 0 },
15248 { "personalityindex", s_arm_unwind_personalityindex, 0 },
15249 { "handlerdata", s_arm_unwind_handlerdata, 0 },
15250 { "save", s_arm_unwind_save, 0 },
15251 { "movsp", s_arm_unwind_movsp, 0 },
15252 { "pad", s_arm_unwind_pad, 0 },
15253 { "setfp", s_arm_unwind_setfp, 0 },
15254 { "unwind_raw", s_arm_unwind_raw, 0 },
a737bd4d
NC
15255#else
15256 { "word", cons, 4},
15257#endif
15258 { "extend", float_cons, 'x' },
15259 { "ldouble", float_cons, 'x' },
15260 { "packed", float_cons, 'p' },
15261 { 0, 0, 0 }
15262};
This page took 1.158316 seconds and 4 git commands to generate.